Skip to content

TileOP: eliminate scalar stack round-trips, fix SD-branch dim binding (SuperNPUBench#112) - #92

Merged
VV0003 merged 1 commit into
linxfrom
fix/scalar-stack-roundtrip-and-sd-binding
Sep 8, 2026
Merged

TileOP: eliminate scalar stack round-trips, fix SD-branch dim binding (SuperNPUBench#112)#92
VV0003 merged 1 commit into
linxfrom
fix/scalar-stack-roundtrip-and-sd-binding

Conversation

@VV0003

@VV0003 VV0003 commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Fixes the TileOP-side of SuperNPUBench#112 (plus a related binding bug found during verification).

Type A: keep_acc() zero-descriptor dead code

Analysis on current linx: already fixed by #71 — no sdi/ldi is emitted before B.FPATR for parameter-free options (verified by repro). This PR removes the residual hazard: the volatile descriptor references now live inside the if constexpr (IorMode != 0) guard so parameter-free options cannot resurrect the dead materialisation under any future optimisation level.

Type B: scalar constant stack round-trips (swi/lwi)

Confirmed and fixed. Root cause: the anti-fold idiom volatile T sv = s; (78 occurrences across TEXPANDS/TMULS/TADDS/TCMP/TQUANT/TDEQUANT/TCMP/TPREFETCH/...) forces the scalar through the stack:

lwi.u [const pool] -> x0
swi   x0, [sp, 204]      # redundant
lwi   [sp, 204], -> a4    # redundant

Replaced with an empty asm register tie asm("" : "+r"(sv)) — the value stays in a GPR (anti-fold preserved: B.IOR binds a real register, verified with the 0.0f worst case) and constants load directly from the pool into the asm input register:

lwi.u [const pool] -> a1     # direct

Bonus fix: SD-branch dim binding mixup

While auditing whether any static value still reaches B.DIM reg, 0, found three branches (static ValidCol / dynamic ValidRow: TMUL, TROWSUM, TROWEXPANDMUL) that bound [valid_col] "r"(GetValidCol()) into lb1 — the wrong dimension, and a compile-time constant into a register operand. This is exactly what produced "register fed by an immediate then B.DIM reg, 0". Fixed to bind GetValidRow(). After the fix: all 324 register-form B.DIM operands in the per-dimension sweep trace to genuine runtime defs (loads/parameters), zero immediate-fed.

Verification

  • Issue repro (TMATMUL+keep_acc / TEXPANDS constant / TMULS constant): zero stack round-trips, zero dead descriptors
  • B.IOR anti-fold preserved (constant 0.0 still binds [a1] via pool load, never [zero])
  • Full gate 64/74 — the 11 failures are identical on the unmodified baseline
  • unittest 40/40

Note: the reported ELF was built with the 0904 toolchain (1ae4ee39); the header-side fixes here apply to any toolchain version. Backend-side constant rematerialisation (c.movr direct move where a stack slot was used) is covered by the same header change — no backend edit needed.

Fixes the two codegen patterns from SuperNPUBench#112 and a binding
mixup found while auditing static-value B.DIM forms:

1. Scalar stack round-trips (issue type B): the anti-fold idiom
   'volatile T sv = s;' forced every scalar operand (TEXPANDS/TMULS/
   TADDS/TCMP/TPREFETCH/TQUANT/...) through a swi/lwi stack round-trip.
   Replaced all 78 occurrences with an empty asm register tie:
   'T sv = s; asm("" : "+r"(sv));' which keeps the value in a GPR
   (anti-fold preserved: B.IOR still binds a real register, never
   zero) without touching the stack. Constant scalels now load
   directly from the constant pool into the asm input register.

2. keep_acc dead descriptors (issue type A): the zero Quant/LRelu
   descriptors are only materialised when the IOR schema reads them
   (IorMode != 0); the volatile references moved inside the guarded
   branch so parameter-free options emit nothing. (Verified: no
   sdi/ldi before B.FPATR on current linx either, #71 already fixed
   the emission; this removes the residual hazard.)

3. SD-branch binding mixup (found via the static-value B.DIM audit):
   three branches with a static ValidCol and dynamic ValidRow
   (TMUL, TROWSUM, TROWEXPANDMUL) bound [valid_col] "r"(GetValidCol())
   into lb1 — the wrong dimension, and a compile-time constant into a
   register operand. Now binds GetValidRow(). This was the source of
   'B.DIM reg, 0' fed by an immediate: after the fix, all 324
   register-form B.DIM operands in the per-dimension sweep trace to
   genuine runtime defs (loads/parameters), zero immediate-fed.

Verification: issue repro compiles with zero stack round-trips and
zero dead descriptors; full gate 64/74 (11 pre-existing failures
identical on baseline); unittest 40/40; B.IOR zero-constant anti-fold
preserved (B.IOR [a1] with constant-pool load).
@VV0003
VV0003 merged commit c88ba58 into linx Sep 8, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant