1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
EQUIV_DIR="$SCRIPT_DIR/equivalence"
DIAG_DIR="$SCRIPT_DIR/diagnostics"
LUMA="${TMPDIR:-/tmp}/gpu_shader_bin"
if [[ ! -f "$LUMA" ]] || [[ "$PROJECT_DIR/main.odin" -nt "$LUMA" ]] || \
find "$PROJECT_DIR" -name '*.odin' -newer "$LUMA" 2>/dev/null | grep -q .; then
echo "Building shader compiler..."
(cd "$PROJECT_DIR/.." && odin build tools/shader -out:"$LUMA") || { echo "FAIL: build failed"; exit 1; }
fi
PASS=0
FAIL=0
ERRORS=""
compare_ir() {
name="$1"
old="$EQUIV_DIR/${name}_old.luma"
new="$EQUIV_DIR/${name}_new.luma"
old_ir="$(mktemp /tmp/luma_${name}_old_XXXXXX.ir)"
new_ir="$(mktemp /tmp/luma_${name}_new_XXXXXX.ir)"
old_norm="$(mktemp /tmp/luma_${name}_old_XXXXXX.norm)"
new_norm="$(mktemp /tmp/luma_${name}_new_XXXXXX.norm)"
"$LUMA" dump-ir "$old" > "$old_ir"
"$LUMA" dump-ir "$new" > "$new_ir"
normalize_ir "$old_ir" "$old_norm"
normalize_ir "$new_ir" "$new_norm"
if diff_output=$(diff -u "$old_norm" "$new_norm" 2>&1); then
PASS=$((PASS + 1))
else
FAIL=$((FAIL + 1))
ERRORS="${ERRORS}FAIL: ${name} old/new IR mismatch\n${diff_output}\n\n"
fi
rm -f "$old_ir" "$new_ir" "$old_norm" "$new_norm"
}
normalize_ir() {
input="$1"
output="$2"
python3 - "$input" "$output" <<'PY'
import sys
src, dst = sys.argv[1], sys.argv[2]
lines = open(src, encoding="utf-8").read().splitlines()
structs = []
other = []
i = 0
while i < len(lines):
line = lines[i]
if line.startswith("struct "):
block = [line]
i += 1
while i < len(lines):
block.append(lines[i])
if lines[i] == "end":
i += 1
break
i += 1
structs.append("\n".join(block))
continue
other.append(line)
i += 1
with open(dst, "w", encoding="utf-8") as f:
for block in sorted(structs):
f.write(block)
f.write("\n\n")
for line in other:
f.write(line)
f.write("\n")
PY
}
expect_diag() {
file="$1"
pattern="$2"
output="$("$LUMA" check "$DIAG_DIR/$file" 2>&1 || true)"
if printf '%s\n' "$output" | grep -Fq "$pattern"; then
PASS=$((PASS + 1))
else
FAIL=$((FAIL + 1))
ERRORS="${ERRORS}FAIL: ${file} missing diagnostic: ${pattern}\n${output}\n\n"
fi
}
compare_ir fragment
compare_ir vertex
compare_ir group
expect_diag missing_branch_output.luma "out slot 'color' is not definitely assigned on every path"
expect_diag mixed_return_out.luma "cannot mix explicit out writes with fragment return sugar"
expect_diag nested_return.luma "workflow stage return sugar is only supported as a top-level"
expect_diag wrong_stage_builtin.luma "builtin 'work.global_id' is only valid in compute stages"
if [[ $FAIL -gt 0 ]]; then
echo -e "$ERRORS"
fi
echo "Workflow equivalence results: $PASS passed, $FAIL failed"
[[ $FAIL -eq 0 ]] || exit 1