nx_wgsl_rung2_gate.nx source
↩ module page · 330 lines · 26241 B
1// nx_wgsl_rung2_gate.nx -- IS THE FRONT HALF REAL? Rung 2 is the claim that a shader is an
2// ORDINARY NISHILANG FUNCTION compiled by the SAME front-end as every other program, with GLSL
3// and WGSL as two backends over the shared nx_ir SSA. This gate measures that claim.
4//
5// WHY A SEPARATE GATE FROM nx_wgsl_gate: that one covers the rung-1 BUILDER path (a module
6// assembled by sir_* calls). The path shipped in rung 2 -- real source -> expand_imports ->
7// lex_source -> parse_module -> opt_run -> lowering -> two dialects -- was UNGATED, and an
8// ungated rung is one this estate does not ship.
9//
10// SUBJECT: ./nx_wgsl.elf forked per fixture (e2e; an in-process gate would prove the source
11// compiles, never that the SHIPPED artifact behaves).
12//
13// EVERY EXPECTED VALUE BELOW WAS MEASURED FIRST by running the fixtures, never guessed -- teeth
14// written against assumed output are the vacuous-test defect wearing a gate's clothes.
15//
16// SCOPE, STATED SO IT CANNOT BE MISREAD: not one tooth renders a frame. GREEN means the two
17// dialects are emitted from one NishiLang source and agree structurally. It does NOT mean a GPU
18// drew the same pixels from both -- that is nx_wgsl_pixel_gate, and it is OWED.
19
20import "nx_syscalls.nx"
21import "nx_gate_verdict.nx"
22import "nx_gatekit_lib.nx"
23
24const R2_ELF: *u8 = "./nx_wgsl.elf"
25// The subject prints two shader texts plus a summary; the measured worst fixture is under 700
26// bytes. 64 KiB is a refusal bound two orders above that, and gk_run_capture reports the byte
27// count so the teeth bind to what was actually read.
28const R2_CAP: i64 = 65536
29
30// SELF-FIXTURING (2026-09-04). These TEN shader sources were read from knowledge/nxsh_*.nx, which
31// exists ONLY on the NAS -- so on any other host this gate reported a missing-fixture RED that is
32// indistinguishable from a real backend failure. MEASURED on the laptop that day with the older
33// six-fixture copy: 2/22 with the files absent, 21/22 with them staged by hand -- two different
34// verdicts about the SAME subject, neither of them evidence. A GATE THAT CANNOT FIND ITS FIXTURE
35// MEASURES NOTHING, and it fails in the alarming direction, so the next reader pays for the whole
36// investigation. The gate now writes its own fixtures via gatekit into a per-RUN /tmp/<gate>_<us>/:
37// self-contained on every host, unshareable with any production beat, and safe against two
38// concurrent runs. The TEXTS are byte-identical to the files they replace -- only their LOCATION
39// changed -- so every tooth below still measures exactly what it measured before.
40const R2_GATE_NAME: *u8 = "nx_wgsl_rung2_gate"
41// A fixture path is /tmp/ + gate name + _ + a microsecond stamp + / + a file name: under 80 bytes
42// measured. 512 bounds it two orders above, and every write is checked by the setup tooth.
43const R2_PATHCAP: i64 = 512
44// The denominator the setup tooth binds to. One place to change when a fixture is added, so the
45// count and the writes cannot disagree.
46const R2_FIXTURES: i64 = 10
47
48const R2_FN_CLIP: *u8 = "nxsh_clip.nx"
49const R2_FN_CLIP2: *u8 = "nxsh_clip2.nx"
50const R2_FN_BRANCH: *u8 = "nxsh_branch.nx"
51const R2_FN_I64: *u8 = "nxsh_i64.nx"
52const R2_FN_REM: *u8 = "nxsh_rem.nx"
53const R2_FN_LOOP: *u8 = "nxsh_loop.nx"
54const R2_FN_SKIN: *u8 = "nxsh_skin.nx"
55const R2_FN_LAYERS: *u8 = "nxsh_layers.nx"
56const R2_FN_IFELSE: *u8 = "nxsh_ifelse.nx"
57const R2_FN_LITCTL: *u8 = "nxsh_litctl.nx"
58
59const R2_TX_CLIP: *u8 = "// nxsh_clip.nx -- A SHADER, WRITTEN AS AN ORDINARY NISHILANG FUNCTION.\n//\n// There is no GLSL and no WGSL in this file. It is compiled by the SAME lexer, the SAME parser\n// and the SAME optimiser as every other NishiLang program (nx_tokenizer -> nx_parse -> nx_opt),\n// and nx_wgsl's two backends emit both dialects from the resulting nx_ir SSA. That is rung 2:\n// the shader IS the language, not a string literal written in another one.\n//\n// Deliberately straight-line: GLSL and WGSL have no goto, so a branchy function needs structured\n// control-flow recovery, which nx_wgsl REFUSES BY NAME today rather than guessing at (rung 2b).\n\nfunc shader_main(vi: i32) -> i32 {\n let a: i32 = vi * 2\n let b: i32 = a - 1\n return b\n}\n"
60const R2_TX_CLIP2: *u8 = "// FIXTURE for nx_wgsl_gate: the CORRUPTION NEG-CONTROL. Identical to nxsh_clip.nx except for one\n// extra statement. Trace identity across the two dialects would be satisfied by two backends that\n// both emitted NOTHING, so it is only evidence if a CHANGED SOURCE produces a CHANGED trace --\n// this fixture is what makes that tooth load-bearing instead of decorative.\nfunc shader_main(vi: i32) -> i32 {\n let a: i32 = vi * 2\n let b: i32 = a - 1\n let c: i32 = b + 7\n return c\n}\n"
61const R2_TX_BRANCH: *u8 = "// FIXTURE for nx_wgsl_gate: a BRANCHY shader function. GLSL and WGSL have no goto, so lowering\n// a multi-block CFG needs structured control-flow recovery (rung 2b -- the problem WebAssembly\n// had to solve). The backend must REFUSE THIS BY NAME rather than emit something plausible.\nfunc shader_main(vi: i32) -> i32 {\n var r: i32 = vi\n if vi > 0 { r = vi - 1 }\n return r\n}\n"
62const R2_TX_I64: *u8 = "// FIXTURE for nx_wgsl_gate: an i64 shader function. GLSL ES 3.00 HAS NO 64-BIT INTEGER, so the\n// only honest answers are refuse or narrow -- and narrowing is the exact silent mistranslation\n// this backend exists to prevent (it would compile, link, run, and compute the wrong number).\n// The backend must REFUSE THIS BY NAME.\nfunc shader_main(vi: i64) -> i64 {\n let a: i64 = vi * 2\n return a\n}\n"
63const R2_TX_REM: *u8 = "// FIXTURE for nx_wgsl_gate: an opcode OUTSIDE the covered subset (remainder). The refusal must\n// name the opcode NUMBER -- a refusal truncated before its actionable field costs the reader the\n// investigation it exists to save them (measured on this backend's own first run).\nfunc shader_main(vi: i32) -> i32 {\n let a: i32 = vi % 3\n return a\n}\n"
64const R2_TX_LOOP: *u8 = "// FIXTURE for nx_wgsl_rung2_gate: a LOOP. A back edge is the case the if-diamond recogniser\n// cannot handle and must never guess at -- the general answer is a relooper-class algorithm\n// (node duplication or a dispatch loop over a state variable), which is rung 2b-general.\n// The backend must REFUSE THIS BY NAME.\nfunc shader_main(vi: i32) -> i32 {\n var r: i32 = vi\n while r > 0 { r = r - 1 }\n return r\n}\n"
65const R2_TX_SKIN: *u8 = "// FIXTURE for nx_wgsl rung 2b: the SKINNING shape the character pass ACTUALLY produces --\n// a bounded loop over bone influences with a conditional skip for zero-weight slots.\n// This is loop-CONTAINING-if: the COMPOSITION a FLAT shape recogniser cannot match even\n// though it already handles each shape ALONE.\n//\n// TWO DELIBERATE RESTRICTIONS so that any refusal here is attributable to CONTROL FLOW alone:\n// (1) operators limited to + - < >, all of them already proven by earlier rungs;\n// (2) NO integer-literal initialiser. A bare literal types as i64 and `var a: i32 = 0` is\n// refused by shl_blk as 'stored value type has no GLSL ES 3.00 counterpart'. That is a\n// SCALAR-LITERAL TYPING gap, NOT a control-flow one, and knowledge/nxsh_litctl.nx is the\n// one-block control that proves it (ir_blocks=1, same refusal, no branch and no loop).\n// Literal OPERANDS are fine, which is why `i > 0` and `i - 1` appear freely below.\nfunc shader_main(vi: i32) -> i32 {\n var acc: i32 = vi\n var i: i32 = vi\n while i > 0 {\n let w: i32 = vi - i\n if w > 0 { acc = acc + w }\n i = i - 1\n }\n return acc\n}\n"
66const R2_TX_LAYERS: *u8 = "// FIXTURE for nx_wgsl rung 2b: the PAINT-LAYER shape -- NESTED bounded loops (layer x channel).\n// Nesting is the SECOND composition a flat recogniser cannot match. Same two restrictions as\n// nxsh_skin.nx (proven operators only; no integer-literal initialiser, see nxsh_litctl.nx) so\n// that a refusal here is attributable to control-flow recovery and to nothing else.\nfunc shader_main(vi: i32) -> i32 {\n var out: i32 = vi\n var l: i32 = vi\n while l > 0 {\n var c: i32 = vi\n while c > 0 {\n out = out + l\n c = c - 1\n }\n l = l - 1\n }\n return out\n}\n"
67const R2_TX_IFELSE: *u8 = "// NEGATIVE CONTROL for nx_wgsl rung 2b -- and a NAMED capability gap in the same file.\n//\n// Structured NishiLang source cannot express an irreducible CFG (there is no goto), so the\n// reducer's multi-entry and irreducible refusals cannot be fired from source at all. This is the\n// refusal that CAN be fired: an if/ELSE. Both arms are non-empty, so the entry's two successors\n// are then-block and else-block, and the then-block falls through to a JOIN that is neither of\n// them -- which is not the if-diamond shape the reducer recognises.\n//\n// It must REFUSE BY NAME. A reducer whose refusals have never fired is unverified, and this is\n// the one that keeps it honest. It also names the next rung: if/else lowering is NOT implemented,\n// and that is a real gap rather than a hypothetical one -- shaders use else constantly.\nfunc shader_main(vi: i32) -> i32 {\n var r: i32 = vi\n if vi > 0 { r = vi - 1 } else { r = vi + 1 }\n return r\n}\n"
68const R2_TX_LITCTL: *u8 = "// CONTROL for nx_wgsl rung 2b. ONE block, no branch, no loop -- the ONLY thing it exercises that\n// the earlier fixtures did not is an integer LITERAL initialiser for an i32 local. If this refuses\n// with the same 'stored value type' message that nxsh_skin.nx hit, then that refusal is a TYPE\n// gap and has nothing to do with control-flow recovery. A control is the cheapest way to stop a\n// failure being attributed to the rung that happened to be under test when it appeared.\nfunc shader_main(vi: i32) -> i32 {\n var a: i32 = 0\n return a\n}\n"
69// RUNG 2b-GENERAL fixtures. skin and layers are the shapes the CHARACTER PASS actually produces
70// (bone-influence accumulation, layer x channel paint), measured before the reducer was designed.
71
72func r2_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
73
74func r2_has(buf: *u8, n: i64, ned: *u8) -> i64 {
75 let m: i64 = r2_slen(ned)
76 if m == 0 { return 0 }
77 var i: i64 = 0
78 while i + m <= n {
79 var j: i64 = 0
80 var ok: i64 = 1
81 while j < m { if buf[i+j] != ned[j] { ok = 0; j = m } else { j = j + 1 } }
82 if ok == 1 { return 1 }
83 i = i + 1
84 }
85 return 0
86}
87
88// anchored on the key, taking the LAST occurrence, so a value printed in the prose above can
89// never be read as the answer
90func r2_num(buf: *u8, n: i64, key: *u8) -> i64 {
91 let m: i64 = r2_slen(key)
92 var at: i64 = 0 - 1
93 var i: i64 = 0
94 while i + m <= n {
95 var j: i64 = 0
96 var ok: i64 = 1
97 while j < m { if buf[i+j] != key[j] { ok = 0; j = m } else { j = j + 1 } }
98 if ok == 1 { at = i + m }
99 i = i + 1
100 }
101 if at < 0 { return 0 - 1 }
102 var v: i64 = 0
103 var seen: i64 = 0
104 var neg: i64 = 0
105 if at < n { if buf[at] == (45 as u8) { neg = 1; at = at + 1 } }
106 while at < n {
107 let c: i64 = buf[at] as i64
108 if c >= 48 { if c <= 57 { v = v*10 + (c - 48); seen = 1; at = at + 1 } else { at = n } } else { at = n }
109 }
110 if seen == 0 { return 0 - 1 }
111 if neg == 1 { return 0 - v }
112 return v
113}
114
115func r2_run(src: *u8, buf: *u8, bl: *i64) -> i64 {
116 bl[0] = 0
117 // COMPOSE the proven subprocess primitive: a hand-rolled pipe/fork/wait deadlocked a sibling
118 // gate in production today (50+ min in pipe_wait). Fixtures and subprocess come from gatekit.
119 return gk_run_capture(R2_ELF, src, 0 as *u8, 0 as *u8, 0 as *u8, buf, R2_CAP, bl)
120}
121
122func main() -> i64 {
123 let ctr: *i64 = gv_ctr()
124 gv_puts("nx_wgsl_rung2_gate -- a shader is an ORDINARY NishiLang function, and the front-end is SHARED\n\n" as *u8)
125
126 let buf: *u8 = sys_mmap(R2_CAP)
127 let bl: *i64 = sys_mmap(16) as *i64
128
129 // SETUP -- this gate writes its OWN fixtures (see the SELF-FIXTURING note at the top).
130 let fxdir: *u8 = sys_mmap(R2_PATHCAP)
131 gk_fixture_dir(R2_GATE_NAME, fxdir)
132 let pclip: *u8 = sys_mmap(R2_PATHCAP)
133 let pclip2: *u8 = sys_mmap(R2_PATHCAP)
134 let pbranch: *u8 = sys_mmap(R2_PATHCAP)
135 let pi64: *u8 = sys_mmap(R2_PATHCAP)
136 let prem: *u8 = sys_mmap(R2_PATHCAP)
137 let ploop: *u8 = sys_mmap(R2_PATHCAP)
138 let pskin: *u8 = sys_mmap(R2_PATHCAP)
139 let players: *u8 = sys_mmap(R2_PATHCAP)
140 let pifelse: *u8 = sys_mmap(R2_PATHCAP)
141 let plitctl: *u8 = sys_mmap(R2_PATHCAP)
142 gk_join(pclip, fxdir, R2_FN_CLIP)
143 gk_join(pclip2, fxdir, R2_FN_CLIP2)
144 gk_join(pbranch, fxdir, R2_FN_BRANCH)
145 gk_join(pi64, fxdir, R2_FN_I64)
146 gk_join(prem, fxdir, R2_FN_REM)
147 gk_join(ploop, fxdir, R2_FN_LOOP)
148 gk_join(pskin, fxdir, R2_FN_SKIN)
149 gk_join(players, fxdir, R2_FN_LAYERS)
150 gk_join(pifelse, fxdir, R2_FN_IFELSE)
151 gk_join(plitctl, fxdir, R2_FN_LITCTL)
152 var wrote: i64 = 0
153 if gk_write(pclip, R2_TX_CLIP) > 0 { wrote = wrote + 1 }
154 if gk_write(pclip2, R2_TX_CLIP2) > 0 { wrote = wrote + 1 }
155 if gk_write(pbranch, R2_TX_BRANCH) > 0 { wrote = wrote + 1 }
156 if gk_write(pi64, R2_TX_I64) > 0 { wrote = wrote + 1 }
157 if gk_write(prem, R2_TX_REM) > 0 { wrote = wrote + 1 }
158 if gk_write(ploop, R2_TX_LOOP) > 0 { wrote = wrote + 1 }
159 if gk_write(pskin, R2_TX_SKIN) > 0 { wrote = wrote + 1 }
160 if gk_write(players, R2_TX_LAYERS) > 0 { wrote = wrote + 1 }
161 if gk_write(pifelse, R2_TX_IFELSE) > 0 { wrote = wrote + 1 }
162 if gk_write(plitctl, R2_TX_LITCTL) > 0 { wrote = wrote + 1 }
163 gv_puts(" [setup] fixtures written=" as *u8); gv_num(wrote); gv_puts(" of " as *u8); gv_num(R2_FIXTURES); gv_puts(" in " as *u8); gv_puts(fxdir); gv_puts("\n" as *u8)
164 // FIXTURE-REACHED-THE-CONDITION for the WHOLE gate: every tooth below reads one of these ten
165 // files, so a partial setup must fail HERE and BY NAME, never as ten mysterious subject REDs.
166 gv_check("setup-wrote-every-fixture (a gate that cannot write its fixtures measures nothing)" as *u8, wrote == R2_FIXTURES, ctr)
167
168 // ---- the good source: real front-end, both dialects -----------------------------------
169 let rc: i64 = r2_run(pclip, buf, bl)
170 var n: i64 = bl[0]
171 gv_puts(" [clip] rc=" as *u8); gv_num(rc); gv_puts(" bytes=" as *u8); gv_num(n); gv_puts("\n" as *u8)
172 gv_check("subject-ran (127 = elf absent, the stale-offc tell)" as *u8, rc == 0, ctr)
173 var got: i64 = 0
174 if n > 0 { got = 1 }
175 gv_check("subject-emitted-bytes (a silent subject proves nothing)" as *u8, got, ctr)
176 if got == 0 { return gv_verdict("NX-WGSL-RUNG2" as *u8, ctr, "the backend produced no output at all" as *u8) }
177
178 let lrc: i64 = r2_num(buf, n, "lower_rc=" as *u8)
179 gv_check("good-source-LOWERS (lower_rc=0)" as *u8, lrc == 0, ctr)
180 gv_check("the-front-end-actually-parsed-it (one function, one block)" as *u8, r2_has(buf, n, "ir_functions=1 ir_blocks=1" as *u8), ctr)
181 gv_check("glsl-emitted-in-GLSL-spelling (int, #version 300 es)" as *u8, r2_has(buf, n, "int shader_main(int p0)" as *u8), ctr)
182 gv_check("wgsl-emitted-in-WGSL-spelling (fn, i32, arrow return)" as *u8, r2_has(buf, n, "fn shader_main(p0:i32)->i32" as *u8), ctr)
183
184 // ---- THE PROOF THAT THIS IS A BACKEND AND NOT A TRANSLATOR -----------------------------
185 // The SOURCE says `vi * 2`. The emitted dialects say `<<1`. Nothing in this backend performs
186 // strength reduction -- opt_run did it on the shared IR BEFORE the backend saw a single node.
187 // Every optimisation the language gains, shaders inherit with nobody porting anything. A
188 // translator reading GLSL text could never show this.
189 gv_check("THE SHARED OPTIMISER RAN FIRST: source says *2, emitted says <<1" as *u8, r2_has(buf, n, "(p0<<1)" as *u8), ctr)
190
191 let g1: i64 = r2_num(buf, n, "glsl_nodes=" as *u8)
192 let w1: i64 = r2_num(buf, n, "wgsl_nodes=" as *u8)
193 let te: i64 = r2_num(buf, n, "trace_equal=" as *u8)
194 gv_puts(" glsl_nodes=" as *u8); gv_num(g1); gv_puts(" wgsl_nodes=" as *u8); gv_num(w1); gv_puts(" trace_equal=" as *u8); gv_num(te); gv_puts("\n" as *u8)
195 // bound IN the condition: a gate that only asked 'are they equal?' would pass on 0 == 0
196 var same: i64 = 0
197 if g1 > 0 { if g1 == w1 { same = 1 } }
198 gv_check("both-backends-consumed-the-same-source (counts equal AND positive)" as *u8, same, ctr)
199 gv_check("trace-identity-element-wise (same node ids, same order)" as *u8, te == 1, ctr)
200 gv_check("no-refusal-fired-on-the-GOOD-source" as *u8, r2_has(buf, n, "REFUSED" as *u8) == 0, ctr)
201
202 // ---- NEG-CONTROL 1: a CHANGED SOURCE must produce a CHANGED trace ----------------------
203 r2_run(pclip2, buf, bl)
204 n = bl[0]
205 let g2: i64 = r2_num(buf, n, "glsl_nodes=" as *u8)
206 gv_puts(" [clip2 perturbed] glsl_nodes=" as *u8); gv_num(g2); gv_puts(" (clip was " as *u8); gv_num(g1); gv_puts(")\n" as *u8)
207 var moved: i64 = 0
208 if g2 > 0 { if g2 != g1 { moved = 1 } }
209 gv_check("neg-control-one-extra-statement-CHANGES-the-trace (equality is not vacuous)" as *u8, moved, ctr)
210
211 // ---- RUNG 2b: THE IF-DIAMOND IS RECOVERED, NOT REFUSED --------------------------------
212 // This tooth REPLACED a refusal tooth. Until rung 2b the branch fixture refused by name; the
213 // gate caught that capability change on the very next run, which is what a gate is for.
214 r2_run(pbranch, buf, bl)
215 n = bl[0]
216 let lb: i64 = r2_num(buf, n, "lower_rc=" as *u8)
217 let bblk: i64 = r2_num(buf, n, "ir_blocks=" as *u8)
218 let bte: i64 = r2_num(buf, n, "trace_equal=" as *u8)
219 gv_puts(" [branch] lower_rc=" as *u8); gv_num(lb); gv_puts(" ir_blocks=" as *u8); gv_num(bblk); gv_puts(" trace_equal=" as *u8); gv_num(bte); gv_puts("\n" as *u8)
220 // FIXTURE-REACHED-THE-CONDITION, and it is load-bearing in BOTH directions now: without it,
221 // "recovers a branch" could pass on a fixture that never branched.
222 gv_check("the-branch-fixture-really-was-branchy (ir_blocks>1)" as *u8, bblk > 1, ctr)
223 gv_check("if-diamond-LOWERS (rung 2b first shape; it refused before this rung)" as *u8, lb == 0, ctr)
224 gv_check("glsl-emits-a-STRUCTURED-if (no goto exists to emit instead)" as *u8, r2_has(buf, n, "if(t" as *u8), ctr)
225 gv_check("the-then-arm-assigns-the-shader-local (the branch body actually lowered)" as *u8, r2_has(buf, n, "a3=t9;" as *u8), ctr)
226 gv_check("branch-trace-identity-holds-across-dialects-too" as *u8, bte == 1, ctr)
227
228 // ---- RUNG 2b-GENERAL: A BACK EDGE IS RECOVERED, NOT REFUSED ---------------------------
229 // For the SECOND time a refusal tooth here became a recovery tooth. The loop fixture refused
230 // by name until this rung; the gate caught the capability change on the very next run, which
231 // is a gate maintaining its own discrimination as its subject grows.
232 r2_run(ploop, buf, bl)
233 n = bl[0]
234 let ll: i64 = r2_num(buf, n, "lower_rc=" as *u8)
235 let lblk: i64 = r2_num(buf, n, "ir_blocks=" as *u8)
236 let lte: i64 = r2_num(buf, n, "trace_equal=" as *u8)
237 gv_puts(" [loop] lower_rc=" as *u8); gv_num(ll); gv_puts(" ir_blocks=" as *u8); gv_num(lblk); gv_puts(" trace_equal=" as *u8); gv_num(lte); gv_puts("\n" as *u8)
238 gv_check("the-loop-fixture-really-had-a-back-edge (ir_blocks>3 -- fixture reached the condition)" as *u8, lblk > 3, ctr)
239 gv_check("while-loop-LOWERS (rung 2b-general; it refused before this rung)" as *u8, ll == 0, ctr)
240 gv_check("glsl-emits-a-STRUCTURED-loop (while(true) -- there is no goto to emit instead)" as *u8, r2_has(buf, n, "while(true){" as *u8), ctr)
241 gv_check("wgsl-emits-ITS-OWN-loop-spelling (loop{}, not a copy of the GLSL text)" as *u8, r2_has(buf, n, "loop{" as *u8), ctr)
242 gv_check("the-exit-is-an-explicit-BREAK (the Relooper's conditional break)" as *u8, r2_has(buf, n, "break;" as *u8), ctr)
243 gv_check("loop-trace-identity-holds-across-dialects" as *u8, lte == 1, ctr)
244
245 // ---- COMPOSITION 1: a loop CONTAINING an if -- the SKINNING shape ----------------------
246 // Measured from the character pass before the reducer was designed: bone-influence
247 // accumulation with a conditional skip. A FLAT shape recogniser cannot match this even
248 // though it handles each shape alone, which is why the reducer is recursive.
249 r2_run(pskin, buf, bl)
250 n = bl[0]
251 let sl: i64 = r2_num(buf, n, "lower_rc=" as *u8)
252 let sblk: i64 = r2_num(buf, n, "ir_blocks=" as *u8)
253 let ste: i64 = r2_num(buf, n, "trace_equal=" as *u8)
254 gv_puts(" [skin loop-contains-if] lower_rc=" as *u8); gv_num(sl); gv_puts(" ir_blocks=" as *u8); gv_num(sblk); gv_puts(" trace_equal=" as *u8); gv_num(ste); gv_puts("\n" as *u8)
255 gv_check("the-skin-fixture-really-was-a-composition (ir_blocks>5)" as *u8, sblk > 5, ctr)
256 gv_check("loop-CONTAINING-if-LOWERS (the composition, not just the parts)" as *u8, sl == 0, ctr)
257 gv_check("the-inner-if-is-NESTED-inside-the-loop-body (both constructs emitted)" as *u8, r2_has(buf, n, "while(true){" as *u8), ctr)
258 gv_check("skin-trace-identity-holds" as *u8, ste == 1, ctr)
259
260 // ---- COMPOSITION 2: NESTED loops -- the PAINT-LAYER shape ------------------------------
261 r2_run(players, buf, bl)
262 n = bl[0]
263 let yl: i64 = r2_num(buf, n, "lower_rc=" as *u8)
264 let yblk: i64 = r2_num(buf, n, "ir_blocks=" as *u8)
265 let yte: i64 = r2_num(buf, n, "trace_equal=" as *u8)
266 gv_puts(" [layers nested-loops] lower_rc=" as *u8); gv_num(yl); gv_puts(" ir_blocks=" as *u8); gv_num(yblk); gv_puts(" trace_equal=" as *u8); gv_num(yte); gv_puts("\n" as *u8)
267 gv_check("the-layers-fixture-really-had-TWO-loop-headers (ir_blocks>6)" as *u8, yblk > 6, ctr)
268 gv_check("NESTED-loops-LOWER (the region reducer actually recursed)" as *u8, yl == 0, ctr)
269 gv_check("layers-trace-identity-holds" as *u8, yte == 1, ctr)
270
271 // ---- COMPOSITION 3: if/ELSE -----------------------------------------------------------
272 // This shape was FOUND BY ITS OWN NEGATIVE CONTROL: nxsh_ifelse.nx was written to prove the
273 // reducer's two-way refusal could fire, it fired by name, and in doing so it named a real
274 // gap -- shaders use else constantly. The refusal earned the feature.
275 r2_run(pifelse, buf, bl)
276 n = bl[0]
277 let el: i64 = r2_num(buf, n, "lower_rc=" as *u8)
278 let eblk: i64 = r2_num(buf, n, "ir_blocks=" as *u8)
279 gv_puts(" [ifelse] lower_rc=" as *u8); gv_num(el); gv_puts(" ir_blocks=" as *u8); gv_num(eblk); gv_puts("\n" as *u8)
280 gv_check("the-ifelse-fixture-really-had-BOTH-arms (ir_blocks>3, a four-block diamond)" as *u8, eblk > 3, ctr)
281 gv_check("if-ELSE-LOWERS (both arms joining at a common third block)" as *u8, el == 0, ctr)
282 gv_check("an-ELSE-ARM-IS-ACTUALLY-EMITTED (not silently dropped, which would compute wrongly)" as *u8, r2_has(buf, n, "else{" as *u8), ctr)
283
284 // ---- WHERE THE REDUCER'S OWN REFUSALS WENT, STATED RATHER THAN PAPERED OVER ------------
285 // Structured NishiLang has no goto, so an IRREDUCIBLE or MULTI-ENTRY CFG cannot be written
286 // in source at all. Every shape the front-end can emit is now recovered, which means the
287 // reducer's remaining refusals are fail-closed guards with NO source-level fixture that can
288 // fire them. That is declared here instead of being hidden: they are verified by MUTATION
289 // (nx_gate_bite), never by a fixture, and this gate does NOT claim otherwise.
290 // What IS still firable is a type refusal, and it is a REAL blocking gap: a bare integer
291 // literal types as i64, so `var a: i32 = 0` cannot lower. One block, no branch, no loop --
292 // which is exactly what makes it attributable to typing rather than to control flow.
293 r2_run(plitctl, buf, bl)
294 n = bl[0]
295 let cl: i64 = r2_num(buf, n, "lower_rc=" as *u8)
296 let cblk: i64 = r2_num(buf, n, "ir_blocks=" as *u8)
297 gv_puts(" [litctl] lower_rc=" as *u8); gv_num(cl); gv_puts(" ir_blocks=" as *u8); gv_num(cblk); gv_puts("\n" as *u8)
298 gv_check("the-literal-control-has-NO-control-flow (ir_blocks=1 -- attribution is unambiguous)" as *u8, cblk == 1, ctr)
299 var litok: i64 = 0
300 if cl == (0 - 1) { litok = r2_has(buf, n, "stored value type" as *u8) }
301 gv_check("neg-control-integer-LITERAL-store-REFUSES (a TYPE gap, NOT a control-flow one)" as *u8, litok, ctr)
302
303 // ---- NEG-CONTROL 3: i64 REFUSES rather than narrowing ----------------------------------
304 // The most important tooth in this backend. GLSL ES 3.00 has no 64-bit integer, so a backend
305 // that narrows produces a program which compiles, links, runs and computes the wrong number.
306 r2_run(pi64, buf, bl)
307 n = bl[0]
308 let li: i64 = r2_num(buf, n, "lower_rc=" as *u8)
309 gv_puts(" [i64] lower_rc=" as *u8); gv_num(li); gv_puts("\n" as *u8)
310 var i64ok: i64 = 0
311 if li == (0 - 1) { i64ok = r2_has(buf, n, "refused rather than narrowed" as *u8) }
312 gv_check("neg-control-i64-REFUSES-RATHER-THAN-NARROWS (the silent-mistranslation guard)" as *u8, i64ok, ctr)
313 gv_check("the-i64-refusal-names-the-standard-it-is-bound-by (GLSL ES 3.00)" as *u8, r2_has(buf, n, "GLSL ES 3.00" as *u8), ctr)
314
315 // ---- NEG-CONTROL 4: an uncovered opcode refuses WITH ITS NUMBER ------------------------
316 r2_run(prem, buf, bl)
317 n = bl[0]
318 let lr: i64 = r2_num(buf, n, "lower_rc=" as *u8)
319 let opn: i64 = r2_num(buf, n, "op=" as *u8)
320 gv_puts(" [rem] lower_rc=" as *u8); gv_num(lr); gv_puts(" refused op=" as *u8); gv_num(opn); gv_puts("\n" as *u8)
321 var remok: i64 = 0
322 if lr == (0 - 1) { remok = r2_has(buf, n, "opcode outside the covered subset" as *u8) }
323 gv_check("neg-control-uncovered-opcode-REFUSES" as *u8, remok, ctr)
324 // A refusal truncated before its actionable field costs the reader the investigation it
325 // exists to save them -- measured on this backend's own first run, where the opcode number
326 // fell off the end of a buffer named for decimal digits. This tooth is that scar.
327 gv_check("the-refusal-CARRIES-ITS-OPCODE-NUMBER (not truncated before the actionable field)" as *u8, opn > 0, ctr)
328
329 return gv_verdict("NX-WGSL-RUNG2" as *u8, ctr, "a NishiLang function compiles through the SHARED front-end to both dialects; equivalence is measured at the IR level and the pixel level is declared unproven" as *u8)
330}