code wiki / (root) / nx_wgsl_rung2_gate.nx

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}