Skip to content

[Frontend] bilinear interpolate emits invalid MLIR: gather value used across sibling loop regions (and its scratchpad is overwritten) #296

Description

@YWHyuk

Summary

On feature/togsim-cpp-trace, a bilinear F.interpolate emits invalid MLIR: a value defined
inside one gather's affine.for body is referenced from a later, sibling affine.for body.
Codegen aborts while the Python passes re-parse the kernel:

mlir._mlir_libs._site_initialize.<locals>.MLIRError: Unable to parse module assembly:
error: "-":186:42: use of undeclared SSA value name

Minimal repro

import torch
import torch.nn.functional as F

x = torch.randn(1, 8, 8, 8).to("npu:0")
f = torch.compile(dynamic=False)(
    lambda t: F.interpolate(t, scale_factor=2, mode="bilinear", align_corners=False)
)
f(x)   # -> MLIRError: use of undeclared SSA value name

What does and does not trigger it

case result
x[i] (single gather) OK
x[i0] - x[i1] (two gathers + sub) OK
x[i0] + x[i1] OK
F.interpolate(..., mode="nearest") OK
F.interpolate(..., mode="bilinear") FAIL

So two indirect gathers alone are fine. It needs the bilinear pattern, where several gathers of the
same tensor are blended and one gather's loaded value is consumed after a later gather has run.

Mechanism

Two things are broken at once. From the generated kernel:

119:  "togsim.transfer"(%in_ptr0, ..., %spad4, ..., %spad3) {indirect = true}   // gather #1 -> spad4
120:  affine.for %compute_idx = 0 to 64 step 16 {
122:      %tmp57  = affine.vector_load %spad4[...]                              // value A
        ...
      }                                                                        // <- scope closes

182:  "togsim.transfer"(%in_ptr0, ..., %spad4, ..., %spad7) {indirect = true}   // gather #2 -> SAME spad4
183:  affine.for %compute_idx = 0 to 64 step 16 {
185:      %tmp113 = affine.vector_load %spad4[...]                              // value B
186:      %tmp114 = arith.subf %tmp57, %tmp113                                  // A - B
      }
  1. SSA scope violation. %tmp57 is defined in the first loop's region and used in a sibling
    region, so the module does not parse.
  2. Even with scoping fixed, the data would be wrong. Both indirect MVINs target the same
    %spad4 (only the index buffer differs: %spad3 vs %spad7), so value A has already been
    overwritten by gather Scalar #2 by the time arith.subf runs.

A correct lowering has to either give each gather its own scratchpad buffer (and hoist the loaded
value so it stays live), or fuse the gather loops so both loads happen in one region.

Impact

Blocks HuggingFace SegFormer (issue #254). Running SegFormer on this branch, 10 of 1170 generated
kernels fail to parse; every one of them has >= 2 indirect MVINs writing the same scratchpad. The
decode head's bilinear upsample is the source.

Note this is not the error originally reported in #254 (NotImplementedError: Not supporting format),
which no longer reproduces. SegFormer now clears codegen for 145 kernels and all their gem5 runs
(~197 s with the functional Spike pass off), then dies here.

Related but distinct: #284 (the trace path does not model indirect access). This issue is about the
frontend emitting unparseable MLIR in the first place.

Environment

  • branch feature/togsim-cpp-trace
  • fails at PyTorchSimFrontend/mlir/passes/__init__.py:78 (Module.parse) via
    extension_codecache.load -> run_python_passes, i.e. before gem5/Spike, so it is pure frontend
    codegen and independent of the simulator binaries.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions