Skip to content

[Bug] Regex parser mis-bounds functions in a multi-function module: body and grid come from a later function #202

Description

@WarningRan

In a module with more than one func.func, the parser bounds each function by a span that runs to
the end of the module rather than the end of that function. One root cause, four symptoms —
the loud one is that every function is parsed with the last function's body.

Repro

Plain arith.constant bodies are enough — no ktdp ops, memory spaces or pointer arithmetic.

from ktir_cpu.parser import KTIRParser

fns = KTIRParser().parse_module("""
module {
  func.func @f0(%a: index) {
    %0 = arith.constant 0 : index
    return
  }
  func.func @f1(%a: index) attributes {grid = [32]} {
    %0 = arith.constant 1 : index
    %1 = arith.constant 11 : index
    return
  }
}
""").functions

for n in ("f0", "f1"):
    print(n, [o.attributes.get("value") for o in fns[n].operations
              if o.op_type == "arith.constant"], fns[n].grid)

# actual:    f0 [1, 11] (32, 1, 1)      <- f1's body, and f1's grid
#            f1 [1, 11] (32, 1, 1)
# expected:  f0 [0]     (1, 1, 1)       <- @f0 declares no grid, so it should default
#            f1 [1, 11] (32, 1, 1)

Each IRFunction is a distinct object with the correct name — only the body and the grid come
from the wrong function.

Cause

_extract_brace_body (parser.py:149) is documented as "Extract the last top-level
brace-balanced block after start"
and terminates on the enclosing }. That is correct for a
single-function module — it skips attributes { ... } and the last remaining block is the body.
With several functions the scan runs past every later function to the module's closing brace.

func_header = mlir_text[match.start():body_end] (parser.py:121) inherits the same over-long
span, so the grid regex searches the whole module.

Symptoms

# symptom consequence visibility
1 every function gets the last function's body the wrong program runs loud
2 tensor_sizes cross-contaminated (ir_types.py:558 walks that same body) inferred parameter table is the last function's loud
3 grid leaks across functions: a function with no grid attribute inherits a later one's runs on the wrong core count, still produces numbers silent
4 use_counts (parser.py:135) built from the wrong body LX charge/release windows don't match the executing function silent

Symptom 3 also constrains the fix: the function span is what needs bounding, not just body
extraction
— taking the first brace-balanced block after the header that isn't
attributes { ... } fixes symptom 1 and leaves symptom 3 in place.

Relation to #151

That issue reports the same over-long func_header and concludes it is functionally harmless
because _parse_grid_attribute just scans for grid[...]. That holds for a single-function
module; in a multi-function module the scan reaches a later function's grid — symptom 3.

Relation to #187

Subsumed by it: a grammar-based parser takes each body from the AST rather than a brace heuristic.
This is filed as a concrete case with a repro, usable as a regression test for whichever
replacement lands — not as an argument for point-fixing instead.

Scope

  • Seen on the default regex KTIRParser. MLIRFrontendParser looks unaffected by inspection (it
    takes each body from func_op.regions[0].blocks[0]) but was not exercised — mlir_ktdp /
    tools_ktdp bindings unavailable locally.
  • No multi-function module exists under examples/ or tests/, consistent with this not having
    been hit.
  • Workaroundable by splitting a module into single-function modules before loading, so this is not
    blocking. Symptom 3 has no such workaround for anyone emitting multi-function modules without a
    grid on every function.
  • docs/gap_analysis.md row 36 reads "The parser can find func.func inside a module { ... }
    wrapper" — true for finding them, but the bodies are wrong. Worth correcting alongside the fix.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions