Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a245f12
test(inspection): lock canonical type and analysis goldens
zhen8838 Sep 13, 2026
d49f24a
refactor(inspection): print types through one inherited visitor
zhen8838 Sep 13, 2026
51c2365
revert(inspection): withdraw the footprint projection PR #166 added
zhen8838 Sep 13, 2026
9b2e776
feat(inspection,parser): make placement sugar the printed type surface
zhen8838 Sep 13, 2026
32639d7
test(analysis): lock the annotated analysis surface to the sugar fixture
zhen8838 Sep 13, 2026
bc688d4
fix(inspection): state a layout's strides in the sugar it prints
zhen8838 Sep 13, 2026
1ff589d
test(analysis): regenerate the analyze golden on main's per-level met…
zhen8838 Sep 13, 2026
439011a
docs(tutorial): re-render the showcase page on the sugar surface
zhen8838 Sep 13, 2026
ef6f0e5
test(inspection): hold the two placements sugar cannot state
zhen8838 Sep 13, 2026
2fb5a4c
test(inspection): pair a named layout across a bound and an unbound mesh
zhen8838 Sep 13, 2026
013dfe9
refactor(parser): let one pattern answer a whole placement
zhen8838 Sep 13, 2026
925ee10
refactor(inspection): finish render golden review fixes
zhen8838 Sep 14, 2026
0a506dd
fix(ci): align render and mma review contracts
zhen8838 Sep 14, 2026
17ee258
docs(tutorial): refresh showcase after printer refactor
zhen8838 Sep 14, 2026
e1e2fde
test(inspection): align mesh sugar fixture with review
zhen8838 Sep 14, 2026
5c5f396
Revert "test(inspection): align mesh sugar fixture with review"
zhen8838 Sep 14, 2026
56465bd
Revert "docs(tutorial): refresh showcase after printer refactor"
zhen8838 Sep 14, 2026
bcf8179
fix(inspection/parser): enforce lexical mesh placement bindings [M0-M2]
zhen8838 Sep 14, 2026
b6b7b33
fix(inspection): omit loop result type comments
zhen8838 Sep 14, 2026
d9cd3b2
fix(inspection): stabilize sliced mesh type annotations
zhen8838 Sep 14, 2026
deae3f6
docs(tutorial): refresh showcase analysis output
zhen8838 Sep 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 57 additions & 50 deletions docs/spec/inspection.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ explicit wrapper request. Module output computes imports from names actually
used by the rendered program and MUST remain lint-clean.

- constraints:
- Module input MUST emit every HIR Function and preserve shared `Mesh` and
`Topology` definitions before the class. Mixed HIR/TIR Modules MUST be
- Module input MUST emit every HIR Function. Meshes used by a function are
written at their scope boundary, and mixed HIR/TIR Modules MUST be
rejected.

The printer MUST emit a Module's whole tree: each nested Module prints as a
Expand All @@ -143,9 +143,9 @@ Target prints as the `@module(target=...)` argument and a declared hierarchy
as the `@module(topologies=...)` argument
([parser §3](./parser.md#3-implementation-overview)).
Every dimension referenced only by a declared topology expression MUST still
be emitted in the dimension prelude. A topology `ShapeDim` MUST use the same
DSL expression text as tensor and Mesh geometry, including public constructors
such as `ceildiv`, so importing restores the same expression tree.
be emitted in the file header. A topology `ShapeDim` MUST use the same DSL
expression text as tensor and Mesh geometry, including public constructors such
as `ceildiv`, so importing restores the same expression tree.

- constraints:
- The decorator MUST print in its called form, `@module()` included. A bare
Expand Down Expand Up @@ -178,42 +178,41 @@ executed. A Target subclass with a different constructor customizes ordinary
DSL text forms for tensor / layout / shard annotations are owned by
[parser](./parser.md). The printer reuses those forms only when they
round-trip without losing mesh / layout / storage information;
otherwise it falls back to the verbose `ShardLayout(...)`. Printer
output supports two modes derived from the same pretty-print core:

- `canonical` — round-trippable text used by `as_script()`, pass
dumps, and viewer detail `code` blocks: the `Tensor[...]` form of
[parser §2.1](./parser.md#21-syntax) (storage as the string
slot, `gmem` omitted).
- `compact` — abbreviated, **display-only / non-round-trip** text for
summaries / labels: `dtype[shape] {value-state?} @storage`. It inlines
what it can (a split into the shape, a `Partial` into the `{...}`
suffix) and falls back to the canonical form when a layout cannot be
rendered compactly.

Both modes MUST agree on semantics; only the level of detail differs.
otherwise it falls back to the verbose `ShardLayout(...)`.

A `ShardLayout` over a plain `Layout` whose `Mesh` has named axes MUST use the
placement sugar of [parser §2.1](./parser.md#21-syntax), in both type slots and
op-attribute slots, when every mesh identifier in that sugar has an explicit
scope binding. A binding is either a `with <mesh> as <name>` region or the
function's own execution domain. A mesh merely restated in another expression
is not a binding. Without such a binding, the printer MUST use the verbose
`ShardLayout(...)` form rather than inventing a name.

Placement sugar states the layout's own dimensions with each `Split` written on
the dimension it divides, adds the stride tuple whenever the layout has one,
and states the remaining mesh axes in a `{axis @ ...}` set. Because the parser
reads an unstated mesh axis as `Broadcast`, the set carries every `Partial` and
carries `Broadcast` only when no `Split` or `Partial` would otherwise name the
mesh.

The printer has one type-text surface: the canonical `Tensor[...]` form of
[parser §2.1](./parser.md#21-syntax), used by `as_script()`, comments, DOT,
the viewer graph, and viewer detail panels. Comments may flatten this text onto
one physical line, but MUST NOT change its syntax or semantics. The same
printer visitor supplies type, dimension, layout, and shard-attribute text;
there is no separate compact, display-only type language.

The meaning of `Split` / `Partial` / `Broadcast` is owned by
[shard](./shard.md); these forms define only render syntax.

The same-line type annotation `show_types` appends is the `canonical` form on
one physical line, rendered through the same mesh name map
([§2.5](#25-mesh-name-map)) as the signature and the prelude: an annotated
layout MUST name the hoisted mesh rather than restate it, and a `Tuple[...]`
annotation MUST name it in every field. The verbose `ShardLayout(...)` fallback
is unchanged — a mesh with no named axes, or a layout the sugar cannot express,
still renders verbose, so no annotation loses information. The annotation is
**display-only** ([§2.7](#27-round-trip-contract)); what round-trips is the
emitted code, not its comments.

Canonical DType text is the descriptor's `name`. Tensor annotations and DType
op attributes MUST emit that name as a quoted DSL string. Compact labels MAY
omit the quotes, but MUST NOT use the descriptor's raw `repr()`.
[shard](./shard.md); these forms define only render syntax. Canonical DType text
is the descriptor's `name`. Tensor annotations and DType op attributes MUST
emit that name as a quoted DSL string.

### 2.4 Pretty-print / debug display contract

Pretty print is the core presentation layer. Sugar, debug dumps, and
viewer type/value text reuse the same DSL text forms in [§2.3](#23-dsl-text-forms). That keeps
round-trippable source, labels, and detail panes semantically aligned.
Pretty print is the core presentation layer. Sugar, debug dumps, DOT, and
viewer type/value text reuse the same canonical DSL text forms in
[§2.3](#23-dsl-text-forms). That keeps round-trippable source, labels, and
detail panes semantically aligned.

- op attributes that are `DType`, `TensorType`, `Layout`, or `ShardLayout` are
rendered through the [§2.3](#23-dsl-text-forms) printer; `DType` uses its canonical name and these
Expand All @@ -225,12 +224,24 @@ printing (for example, choosing stable mesh names across a whole function)
must use an explicit pretty-printer API rather than relying on no-argument
`repr()`.

### 2.5 Mesh name map
### 2.5 Mesh bindings and file header

The print context records imports and declarations while the printer visits the
program. After the body has been visited, the context emits the file header;
it MUST contain only imports and `DimVar` declarations reached by the output.
There is no module-level mesh hoist or global mesh name map.

A mesh identifier in placement sugar MUST be a lexical binding visible at the
point represented by the text: a `with <mesh> as <name>` region, or the
function's own execution domain. The function execution domain is represented
as `@func(mesh=...)`, so its name is available to signature annotations. A
nested region writes its mesh expression at the `with` boundary and uses that
binding in its body. A named constant or an out-of-scope mesh does not create a
binding; types that refer to one use the verbose form.

The printer collects unique `Mesh` objects from all `ShardLayout`
references in the function (params, return type, body `Reshard` ops)
and assigns variable names from the first declared topology's name. Mesh
definitions are emitted in the module prelude / standalone header.
Analysis annotations use the same type text for value-producing statements, but
a structural `LoopRegion` or `MeshRegion` line MUST NOT restate the aggregate
type of its body. The region may still carry selected analysis metadata.

### 2.6 Specialization printing

Expand Down Expand Up @@ -460,14 +471,10 @@ graph; an id that was collapsed away returns 404.
elements); `Tuple` bundles its elements. Op attributes that are
constants / types render through the [§2.4](#24-pretty-print--debug-display-contract) pretty-print, never raw
`repr`.
- **Type text.** Graph labels use the [§2.3](#23-dsl-text-forms) **compact** pretty mode
(`bf16[4 @ trd.l, 64] {trd.t @ P("sum")} @smem`) with inline split /
DimVar / storage colour; the detail panel uses the [§2.3](#23-dsl-text-forms) **canonical**
mode (`Tensor[(4, 64), "f32", ((4 @ trd.l, 64), {trd.t @ P("sum")}),
"smem"]`). `Reshard` / layout attrs render through the same core (never
raw `repr`). DimVar is a single token-class colour;
storage classes draw from an ordered pool, and an unknown memory level
hashes stably into the pool's spare slots rather than going colourless.
- **Type text.** Graph labels and detail panels use the canonical type text from
[§2.3](#23-dsl-text-forms), including `Tensor[...]` and placement sugar when
a scope binding is available. `Reshard` / layout attrs render through the
same visitor (never raw `repr`).

### 3.4 Interaction contract

Expand Down
38 changes: 26 additions & 12 deletions docs/spec/parser.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,20 @@ dim-expr ::= integer-literal
| dim-expr ('+' | '-' | '*' | '//' | '%') dim-expr
| (identifier | primary '.' identifier) '(' (dim-expr (',' dim-expr)*)?
')'
placed-shape ::= '(' ((expression '@' ('(' mesh-axis (',' mesh-axis)* ')' | mesh-axis) |
layout-dims ::= '(' ((expression '@' ('(' mesh-axis (',' mesh-axis)* ')' | mesh-axis) |
dim-expr) (',' (expression '@' ('(' mesh-axis (',' mesh-axis)* ')' |
mesh-axis) | dim-expr))*)? ')'
layout-strides ::= '(' (dim-expr (',' dim-expr)*)? ')'
value-states ::= '{' mesh-axis '@' ('B' '(' ')' | 'P' '(' string-literal ')') (','
mesh-axis '@' ('B' '(' ')' | 'P' '(' string-literal ')'))* '}'
placed-layout ::= '(' layout-dims ',' layout-strides ',' value-states ')'
| '(' layout-dims ',' layout-strides ')'
| '(' layout-dims ',' value-states ')'
| layout-dims
shape ::= '(' (dim-expr (',' dim-expr)*)? ')'
| identifier
| primary '.' identifier
tensor-shape-layout ::= placed-shape
tensor-shape-layout ::= placed-layout
| shape
dtype ::= string-literal
| primary
Expand Down Expand Up @@ -133,15 +140,10 @@ expression ::= literal
| subscript
call ::= expression '(' ((expression | keyword-name '=' expression) (','
(expression | keyword-name '=' expression))*)? ')'
explicit-layout ::= '(' (tensor-shape-layout | shape) ',' shape ')'
placed-layout ::= '(' ((expression '@' ('(' mesh-axis (',' mesh-axis)* ')' | mesh-axis) |
dim-expr) (',' (expression '@' ('(' mesh-axis (',' mesh-axis)* ')' |
mesh-axis) | dim-expr))*)? ')'
plain-layout ::= '(' (dim-expr (',' dim-expr)*)? ')'
layout ::= None
| primary
| call
| explicit-layout
| placed-layout
| plain-layout
storage ::= string-literal
Expand Down Expand Up @@ -242,28 +244,40 @@ function ::= 'def' name '(' signature ')' ('->' return-type)? ':' b
| --- | --- | --- | --- | --- |
| binary_expression, matmul_expression, op_call, unary_expression | expression, slice_endpoint, subscript_index | CallBindingRule | A call must bind its arguments into a Call tuple. | src/tilefoundry/parser/pattern_nodes.py |
| binary_expression, matmul_expression, op_call, unary_expression | expression, slice_endpoint, subscript_index | CallTypeInferenceRule | A call's result type must be inferred from its binding. | src/tilefoundry/parser/pattern_nodes.py |
| dim_expr | dim_expr, layout_extent, layout_shape, tensor_dim_expr, tensor_optional_slot, tensor_shape | ShapeDimRule | A shape dimension must be an integer, DimVar, or expression. | src/tilefoundry/parser/ast_pattern.py |
| dim_expr | dim_expr, layout_extent, tensor_dim_expr, tensor_optional_slot, tensor_shape | ShapeDimRule | A shape dimension must be an integer, DimVar, or expression. | src/tilefoundry/parser/ast_pattern.py |
| dtype | tensor_dtype | CanonicalDTypeRule | A dtype must resolve to a canonical DType. | src/tilefoundry/parser/ast_pattern.py |
| explicit_layout, layout, placed_layout, plain_layout | tensor_optional_slot | LayoutPositionRule | A layout must be legal for its parser position. | src/tilefoundry/parser/ast_pattern.py |
| explicit_layout, layout, placed_layout, plain_layout | tensor_optional_slot | LayoutShapeRule | A layout must have a valid non-boolean shape. | src/tilefoundry/parser/ast_pattern.py |
| function | function | FunctionDialectRule | A function kind and constructed value must agree with the active dialect. | src/tilefoundry/parser/pattern_nodes.py |
| function | function | FunctionRegistrationRule | A validated function must be registered exactly once in its owning scope. | src/tilefoundry/parser/pattern_nodes.py |
| function | function | FunctionReturnCompatibilityRule | A HIR body with a return annotation must satisfy that annotation; a dispatch prototype must declare one, and each variant body must satisfy the prototype return contract. | src/tilefoundry/parser/pattern_nodes.py |
| function | function | FunctionRoleValidationRule | A root, variant, or converter must satisfy its role before registration. | src/tilefoundry/parser/pattern_nodes.py |
| function | function | FunctionSignatureRule | A function must construct an ordered parameter tuple. | src/tilefoundry/parser/pattern_nodes.py |
| if, while | loop_statement, statement | TirOnlyStatementRule | A TIR-only statement must appear in a prim_func. | src/tilefoundry/parser/pattern_nodes.py |
| index_slice | subscript_index | TileWindowSliceBoundRule | A tile window cannot be used as a slice bound. | src/tilefoundry/parser/pattern_nodes.py |
| layout, plain_layout | tensor_optional_slot | LayoutPositionRule | A layout must be legal for its parser position. | src/tilefoundry/parser/ast_pattern.py |
| layout, plain_layout | tensor_optional_slot | LayoutShapeRule | A layout must have a valid non-boolean shape. | src/tilefoundry/parser/ast_pattern.py |
| module | module_finalization | ModuleFinalizationRule | A module declaration must contain valid unique members and a resolvable entry. | src/tilefoundry/parser/ast_pattern.py |
| module | module_function | ModuleFunctionRegistrationRule | A validated module function must be recorded in declaration order. | src/tilefoundry/parser/ast_pattern.py |
| module | module_function | ModuleFunctionValidationRule | A module function must satisfy its root, variant, or converter role before mutation. | src/tilefoundry/parser/ast_pattern.py |
| op_call | expression, slice_endpoint, subscript_index | CallVariadicInputFormRule | A variadic call must use one explicit list, tuple, or supported static list comprehension. | src/tilefoundry/parser/pattern_nodes.py |
| placed_shape | layout_shape, tensor_shape | PlacedShapeRule | Placement sugar in a shape slot states both a shape and a layout. | src/tilefoundry/parser/ast_pattern.py |
| shape | layout_shape, layout_strides, tensor_shape | ShapeTupleRule | A shape must construct a tuple of dimensions. | src/tilefoundry/parser/ast_pattern.py |
| placed_layout | tensor_optional_slot, tensor_shape | LayoutStrideRankRule | A stated stride tuple must have the rank of the layout it addresses. | src/tilefoundry/parser/pattern_nodes.py |
| placed_layout | tensor_optional_slot, tensor_shape | MeshAxisBoundOnceRule | A placement binds each mesh axis at most once. | src/tilefoundry/parser/pattern_nodes.py |
| placed_layout | tensor_optional_slot, tensor_shape | PlacementAnswerRule | Placement sugar states both the shape as written and the layout it implies. | src/tilefoundry/parser/pattern_nodes.py |
| placed_layout | tensor_optional_slot, tensor_shape | PlacementConstructionRule | A placement must construct a valid shard layout. | src/tilefoundry/parser/pattern_nodes.py |
| placed_layout | tensor_optional_slot, tensor_shape | PlacementLevelRule | A placement's meshes cannot name the same topology level. | src/tilefoundry/parser/pattern_nodes.py |
| placed_layout | tensor_optional_slot, tensor_shape | PlacementMeshResolutionRule | A placement's mesh must be a lexical mesh binding. | src/tilefoundry/parser/pattern_nodes.py |
| shape | tensor_shape | ShapeTupleRule | A shape must construct a tuple of dimensions. | src/tilefoundry/parser/ast_pattern.py |
| storage | tensor_optional_slot | StorageValueRule | Storage must resolve to a StorageKind. | src/tilefoundry/parser/ast_pattern.py |
| tensor | annotation, expression, slice_endpoint, subscript_index, type_annotation | TensorLayoutStorageRule | A tensor type must contain compatible layout and storage values. | src/tilefoundry/parser/ast_pattern.py |
| tensor | annotation, expression, slice_endpoint, subscript_index, type_annotation | TensorPositionRule | A tensor type's storage must be legal for its dialect and position. | src/tilefoundry/parser/ast_pattern.py |
<!-- parser-constraints:end -->

A `mesh-axis` used by placement sugar MUST resolve to a mesh binding in the
current lexical scope. A module or closure name that resolves to a `Mesh` does
not become a placement binding. Such an external value remains valid as the
context expression of `with ... as ...` or as the value supplied to
`@func(mesh=...)`; the resulting lexical binding is the name placement sugar
may use.

## 3. Implementation Overview

| Component | Responsibility |
Expand Down
Loading
Loading