Skip to content

feat(parser): make authored expression gates work and show themselves - #124

Merged
zhen8838 merged 8 commits into
tile-ai:mainfrom
zhen8838:feat/parser-surfaces-and-hir-mma
Aug 26, 2026
Merged

feat(parser): make authored expression gates work and show themselves#124
zhen8838 merged 8 commits into
tile-ai:mainfrom
zhen8838:feat/parser-surfaces-and-hir-mma

Conversation

@zhen8838

@zhen8838 zhen8838 commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Why

  • Three authored-expression gates were broken or invisible. A Python float
    scalar never adopted its peer's dtype, so x + 1.0 on a bf16 tensor was
    rejected although hir §1.3 requires the authoring surface to adapt it. @
    was not a runtime operator at all, so x @ b could not be written. The
    generated grammar rendered binary-op as a placeholder, so the operator set
    the parser really accepts was unreadable.
  • A refused call reported runtime_expression: nested pattern failed. A choice
    synthesized a failure for every alternative that returned None, so a report
    listed one line per alternative tried and the reason had to be dug back out
    of the pile.
  • HIR carried per-shape CUDA MMA ops. A backend-bound construct in the
    reference side pulls HIR toward the imperative, and TIR already owns that
    surface.

What

  • _constant produces a dtype-less weak Constant for Python floats; it takes a
    typed floating-point peer's dtype before type inference. Unary minus keeps it
    weak. Python integers and tensor/tensor mismatches stay strict.
  • MatMulExpressionPattern builds MatMul from ast.MatMult in runtime
    position only; the placement sugar 2 @ mesh.tile is untouched.
  • Matching gains a typed third outcome: a pattern that has established the node
    is its own refuses with a reason, every other combinator returns that refusal
    unchanged, and a choice records only the alternatives that claimed the node.
  • Refusals name what is wrong with a call, a mesh, a launch, or a static dict
    where those sites previously returned None.
  • The generated grammar expands the real operator set, adds
    matmul-expression, and states each loop iterator's argument count.
  • ir/hir/cuda/ is deleted along with its lowering refusal, cost evaluator,
    tests, and the isolated mma_tile fixture.

Contract

  • parser: match returns AstMatch, None, or a MatchFailure. A pattern
    MUST claim a node before refusing it with a reason; a pattern that has not
    claimed it returns None. The generated grammar and constraint table change
    with the patterns.
  • hir: the CUDA matrix multiply-accumulate family is removed; Mma leaves the
    symmetric multi-input list. passes: the CUDA HIR MMA refusal section is
    removed. code-organization: MMA is target-owned under ir/tir/cuda/nn/ only.
  • TIR's T.mma, its atom, and CUDA codegen are unchanged.

Risk

  • The claim discipline is per-pattern. A pattern that claims a shape another
    alternative owns produces a misleading report; the corpus check is that a
    valid program yields no refusal at all, which currently holds.

Weak Python float scalars now adopt a typed floating-point peer's dtype, `@`
builds a MatMul in runtime position, and a rejected call names the op it could
not resolve. The generated grammar expands the operator set it actually
accepts. HIR's per-shape CUDA MMA ops are removed: a backend-bound construct in
the reference side pulls HIR toward the imperative.
`tile` and `range` each match their own argument count, so the generated
grammar shows the accepted forms instead of an open repetition. A precheck
keeps naming the specific reason, which a shape mismatch alone would reduce to
a bare match failure.
Comment thread docs/spec/parser.md Outdated
Comment thread src/tilefoundry/ir/hir/math/binary.py Outdated
lhs_ty = ctx.type_of(call.args[0])
rhs_ty = ctx.type_of(call.args[1])
if lhs_ty.dtype != rhs_ty.dtype:
number = next(

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this solve what problems?

Comment thread src/tilefoundry/parser/ast_pattern.py Outdated
return type(pattern).__name__


def _runtime_expression_detail(node: object) -> str:

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong design

"""
roots = placed_fixture_roots()
assert len(roots) == 29
assert len(roots) == 28

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the meaning of this kind of test? remove it

Comment thread tests/parser/test_matmul_syntax.py Outdated
target=CudaTarget("nvidia.h200_sxm"),
topologies=(Topology("cta", 2),),
)
class PlacedMatMul:

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test writing method is wrong, and then merge it into the test call.

),
),
)
def test_unsupported_expression_names_its_shape(body: str, expected: str) -> None:

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete this file and merge the previous test files.

Comment thread tests/parser/test_scalar_dtype.py Outdated

def test_tensor_operands_do_not_promote() -> None:
with pytest.raises(VerifyError, match=r"bf16 vs f32.*never promoted"):
import_dsl(

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong test writing method

…lved

A call that resolves to no authored Op or Function now says so at the point of
resolution instead of having its shape described from the outside, and a binary
dtype mismatch states the two dtypes and the promotion rule instead of guessing
what the author wrote. Matmul reuses the shared call result rules. The parser
cases join the existing call and function suites.
…e node

A choice used to synthesize a failure for every alternative that returned
None, so a report listed one line per alternative tried and the reason had
to be dug back out of the pile. Give matching a typed third outcome instead:
a pattern that has established the node is its own refuses with a reason,
and every other combinator returns that refusal unchanged.

Refusals now name what is wrong with a call, a mesh, a launch, or a static
dict, where those sites previously returned None and left the report with
nothing to say.
A rule shared by several elements was rendered once per owner, so the four
call rules and the two layout rules each took four rows saying the same
sentence. Merge on the rule and list the elements it governs, the way the
situation column already lists situations.
…h no alternative left

A call pattern named a callee it could not resolve, so a valid `launch(...)`
produced a refusal that a choice then discarded. Deciding whether the spelling
was meant as an op call made one alternative reason about another's territory,
and it still missed the namespaces it did not know.

Being last in a choice is no better a claim, since that choice is itself an
alternative elsewhere. Describe an unclaimed node in `parse_node`, where no
alternative remains by construction, and let the call pattern stay silent about
callees it does not own.
The four spellings were interpolated into a source string and run through the
module-import harness, so none of them appeared as Python anywhere in the file
and a failure could come from any step of that import. Write each one out, the
way the rest of the file's negatives are written.
A Python float was parsed as a Constant with no type at all, then completed
later: adopted from a Binary peer where one was floating, and otherwise
defaulted to f32 on every argument of every call. Three construction sites had
to remember to run that completion, the marker was an Expr state the IR says
cannot exist, and a rule existed only to state the exception negation made.

Parse a float as an ordinary f32 Constant. A dtype mismatch is now reported
where every other mismatch is, and the message names the Cast the author writes
instead of guessing which dtype was meant.
@zhen8838
zhen8838 merged commit 7823b41 into tile-ai:main Aug 26, 2026
1 check passed
@zhen8838
zhen8838 deleted the feat/parser-surfaces-and-hir-mma branch August 26, 2026 13:32
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