---
generated: true
model: claude-opus-4-7
generated_at: 2026-05-21T20:00:00+00:00
source_commit: 690f6a3084801386b77186394e0f6e8c120824a4
watched_paths_digest: 3dbc65f6df020239a91b769be66fa5d3b9d250fac6a4422fc500ef569caf3235
source_doc: docs/generated/design/pipeline/04-ast-to-ir.md
source_doc_digest: 2786b3ac65f55d3fefdde03d0c432f013d0d8c9686304746f06a7f61fab79197
warning: "Auto-generated. May drift from source. Do not edit by hand."
---

# Tests for pipeline/04-ast-to-ir

## Intent
Tests verify the AST → IR lowering claims described in
[`docs/generated/design/pipeline/04-ast-to-ir.md`](../../../design/pipeline/04-ast-to-ir.md):
that each documented AST node family lowers to the IR construct the
doc names (`FuncDecl` → `IRFunc`, `VarDecl` → `IRVar`/`IRGlobalVar`,
`StructDecl` → `IRStructType` with `IRStructField` children,
`InterfaceDecl` → `IRInterfaceType` + per-method requirement insts,
`GenericDecl` → `IRGeneric`, `BlockStmt` → basic blocks, structured
branches `IfStmt`/`ForStmt`/`WhileStmt`/`SwitchStmt` → `ifElse` /
`loop` / `switch` terminators with explicit join operand,
`ReturnStmt` → `return_val`, `BinaryExpr` → pure value insts,
`InvokeExpr` → `call`, `MemberExpr` → `get_field` / `get_field_addr`
depending on rvalue/lvalue context, `LiteralExpr` → constant inst,
`WitnessTable` → `IRWitnessTable`), that phi-style joining is
encoded as block parameters rather than explicit `phi`, that
specialization is **deferred** to a later IR pass (a generic call
appears as `call specialize(%generic, <Type>)(...)`, not as an
inlined body), and that the lowering step excludes IR for `import`ed
modules (those flow through `[import("...")]` decorations and are
linked in later).

The primary observation mechanism is `-target spirv-asm -dump-ir -o
/dev/null` followed by a FileCheck against the IR dump, anchored on
the user-named function (`func %main` or a helper) to cut through the
preamble of capability sets, core-module imports, and
differentiation glue. All claims here are target-independent IR-shape
claims, so the bundle uses a single SPIR-V `-dump-ir` directive per
test rather than multi-target SIMPLE — the doc never asserts a
target-conditional lowering behavior.

Cross-cutting decoration / opcode catalog coverage (`entryPoint`,
`nameHint`, the per-opcode catalog shape) lives in
[`cross-cutting/ir-instructions`](../../cross-cutting/ir-instructions/);
this bundle anchors on the AST-side of the mapping ("which AST node
lowers to which IR construct").


## Functional coverage
| Claim | Intent | Anchor | Tests |
| --- | --- | --- | --- |
| A GenericDecl lowers to an `IRGeneric` (function-shaped IR inst whose body computes a type-level value); specialization is NOT performed at lowering. | functional | [#generics-and-existentials](../../../design/pipeline/04-ast-to-ir.md#generics-and-existentials) | [`genericdecl-lowers-to-irgeneric.slang`](genericdecl-lowers-to-irgeneric.slang) |
| A WitnessTable synthesized in checking lowers to an `IRWitnessTable` whose entries map interface requirements to concrete implementations. | functional | [#generics-and-existentials](../../../design/pipeline/04-ast-to-ir.md#generics-and-existentials) | [`witness-table-lowers-to-ir-witness-table.slang`](witness-table-lowers-to-ir-witness-table.slang) |
| A five-deep chain of generic-from-generic calls lowers to five `IRGeneric` wrappers; each generic body holds an unspecialized `call specialize(...)` to the inner generic — confirming that specialization is deferred recursively. | stress | [#generics-and-existentials](../../../design/pipeline/04-ast-to-ir.md#generics-and-existentials) | [`generic-recursive-depth-five-call-chain-specialize.slang`](generic-recursive-depth-five-call-chain-specialize.slang) |
| A generic function declaring two distinct type parameters lowers without specialization; the call site emits `call specialize(%g, Int, Float)(...)` carrying both type arguments in source order. | boundary | [#generics-and-existentials](../../../design/pipeline/04-ast-to-ir.md#generics-and-existentials) | [`generic-multi-typearg-call-specialize-two-types.slang`](generic-multi-typearg-call-specialize-two-types.slang) |
| A generic with one type parameter but four value arguments lowers to a `call specialize(%g, Int)(%a, %a, %a, %a)` — value arguments flow through the inner call operand list, the type list stays at length one. | boundary | [#generics-and-existentials](../../../design/pipeline/04-ast-to-ir.md#generics-and-existentials) | [`generic-multi-value-args-call-specialize-four-values.slang`](generic-multi-value-args-call-specialize-four-values.slang) |
| A single generic function called with three distinct type arguments lowers to a single `IRGeneric` and three independent `call specialize(%g, T_k)` sites — each specialization is deferred and emitted at the use site, not at the definition. | stress | [#generics-and-existentials](../../../design/pipeline/04-ast-to-ir.md#generics-and-existentials) | [`generic-call-three-distinct-specializations-each-deferred.slang`](generic-call-three-distinct-specializations-each-deferred.slang) |
| A two-method interface conformance lowers to an `IRWitnessTable` carrying two `witness_table_entry(req, impl)` rows — one per interface requirement. | boundary | [#generics-and-existentials](../../../design/pipeline/04-ast-to-ir.md#generics-and-existentials) | [`witness-table-two-methods-two-entries.slang`](witness-table-two-methods-two-entries.slang) |
| Lowering does not specialize generics; a generic call appears as `call specialize(%generic, <Type>)(...)`, not as an inlined body. | functional | [#generics-and-existentials](../../../design/pipeline/04-ast-to-ir.md#generics-and-existentials) | [`specialization-deferred-to-ir-pass.slang`](specialization-deferred-to-ir-pass.slang) |
| References to symbols defined in an imported module (e.g. the core module) appear in the lowered IR with `[import("...")]` decorations rather than as full function bodies; the doc says "The lowering step does NOT include the IR for imported modules". | functional | [#inputs-and-outputs](../../../design/pipeline/04-ast-to-ir.md#inputs-and-outputs) | [`import-not-lowered-into-translation-unit.slang`](import-not-lowered-into-translation-unit.slang) |
| A BinaryExpr `a != b` lowers to `cmpNE` — sibling of cmpEQ in the doc's comparison-Expr row. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`binaryexpr-ne-lowers-to-cmpne.slang`](binaryexpr-ne-lowers-to-cmpne.slang) |
| A BinaryExpr `a % b` on integers lowers to an `irem` IR opcode — the integer-remainder pure-value inst in the arithmetic row. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`binaryexpr-mod-lowers-to-irem.slang`](binaryexpr-mod-lowers-to-irem.slang) |
| A BinaryExpr `a & b` (bitwise AND) lowers to an `and` IR opcode — a pure-value inst in the doc's arithmetic/comparison Expr row. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`binaryexpr-bitand-lowers-to-and.slang`](binaryexpr-bitand-lowers-to-and.slang) |
| A BinaryExpr `a * b` lowers to a `mul` IR opcode, matching the doc's `IRMul` exemplar of the arithmetic Expr row. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`binaryexpr-mul-lowers-to-mul.slang`](binaryexpr-mul-lowers-to-mul.slang) |
| A BinaryExpr `a - b` lowers to a `sub` IR opcode in the doc's "BinaryExpr, arithmetic / comparison Expr -> pure value insts" row; the IRSub mirror of IRAdd. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`binaryexpr-sub-lowers-to-sub.slang`](binaryexpr-sub-lowers-to-sub.slang) |
| A BinaryExpr `a / b` lowers to a `div` IR opcode in the doc's arithmetic-pure-value-inst row. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`binaryexpr-div-lowers-to-div.slang`](binaryexpr-div-lowers-to-div.slang) |
| A BinaryExpr `a < b` lowers to `cmpLT` — sibling of cmpEQ/cmpGT in the doc's comparison-Expr row. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`binaryexpr-lt-lowers-to-cmplt.slang`](binaryexpr-lt-lowers-to-cmplt.slang) |
| A BinaryExpr `a << n` lowers to an `shl` IR opcode — a pure-value inst representing left-shift in the doc's arithmetic-Expr row. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`binaryexpr-shl-lowers-to-shl.slang`](binaryexpr-shl-lowers-to-shl.slang) |
| A BinaryExpr `a == b` lowers to `cmpEQ` — the doc's `IREq` exemplar of the comparison Expr row. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`binaryexpr-eq-lowers-to-cmpeq.slang`](binaryexpr-eq-lowers-to-cmpeq.slang) |
| A BinaryExpr arithmetic site (`a + b`) lowers to the corresponding pure-value IR opcode (`add`) — the doc's "Pure value insts (IRAdd, IRMul, ...)" claim. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`binaryexpr-arithmetic-lowers-to-add.slang`](binaryexpr-arithmetic-lowers-to-add.slang) |
| A BinaryExpr comparison site (`a > 0`) lowers to a comparison IR opcode (`cmpGT`) — the doc's row for arithmetic/comparison Expr. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`binaryexpr-comparison-lowers-to-cmpgt.slang`](binaryexpr-comparison-lowers-to-cmpgt.slang) |
| A BlockStmt containing a single statement (no control flow) lowers to a single entry IRBlock; lowering does not introduce extra blocks just because of the brace nesting. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`blockstmt-single-stmt-block-collapses.slang`](blockstmt-single-stmt-block-collapses.slang) |
| A BlockStmt lowers to a sequence of basic blocks; the function body has multiple `block %{{.*}}` regions when control flow branches. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`blockstmt-lowers-to-basic-blocks.slang`](blockstmt-lowers-to-basic-blocks.slang) |
| A ForStmt lowers to a `loop` terminator; the induction variable is carried as a block `param` (phi-style joining encoded as block parameters). | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`forstmt-lowers-to-loop-with-block-params.slang`](forstmt-lowers-to-loop-with-block-params.slang) |
| A FuncDecl lowers to an IRFunc whose body contains one or more IRBlocks; a callsite lowers to a `call` instruction. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`funcdecl-lowers-to-irfunc.slang`](funcdecl-lowers-to-irfunc.slang) |
| A FuncDecl that calls itself lowers to a single IRFunc whose body contains a `call %self(...)` instruction targeting the same IRFunc — the doc's `InvokeExpr -> IRCall` row applied to a self-reference. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`funcdecl-recursive-call-self-references-irfunc.slang`](funcdecl-recursive-call-self-references-irfunc.slang) |
| A FuncDecl that returns a multi-field struct lowers to an IRFunc whose function type names the struct as its return type; the body builds the struct in an IRVar and returns its loaded value. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`funcdecl-returns-struct-lowers-to-return-val-struct.slang`](funcdecl-returns-struct-lowers-to-return-val-struct.slang) |
| A FuncDecl with a default-valued parameter lowers normally; the omitted argument at the call site is materialized as a literal operand in the `call` instruction. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`funcdecl-default-arg-materialized-at-call-site.slang`](funcdecl-default-arg-materialized-at-call-site.slang) |
| A FuncDecl with an `out int y` parameter lowers to an IRFunc whose param has type `OutParam(Int)`; writes through `y` lower to `store(%y, ...)` and the call site passes the address of a local IRVar. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`funcdecl-out-param-lowers-to-outparam-pointer.slang`](funcdecl-out-param-lowers-to-outparam-pointer.slang) |
| A FuncDecl with eight parameters lowers to an IRFunc whose entry block carries eight `param` instructions in declaration order. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`funcdecl-many-params-eight-block-params.slang`](funcdecl-many-params-eight-block-params.slang) |
| A FuncDecl with zero parameters lowers to an IRFunc whose entry block has no `param` instructions; the function type carries only the return type. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`funcdecl-zero-params-no-block-params.slang`](funcdecl-zero-params-no-block-params.slang) |
| A LiteralExpr lowers to a constant IR instruction (IRIntLit / IRFloatLit) visible as the literal value inline. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`literalexpr-lowers-to-constant.slang`](literalexpr-lowers-to-constant.slang) |
| A MemberExpr in rvalue position lowers to `IRFieldExtract` (spelled `get_field` in the dump). | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`memberexpr-rvalue-lowers-to-get-field.slang`](memberexpr-rvalue-lowers-to-get-field.slang) |
| A MemberExpr used as an assignment target (lvalue) lowers to `IRFieldAddress` (spelled `get_field_addr` in the dump). | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`memberexpr-lvalue-lowers-to-get-field-addr.slang`](memberexpr-lvalue-lowers-to-get-field-addr.slang) |
| A ReturnStmt lowers to an `IRReturn` terminator (spelled `return_val(...)` in the IR dump). | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`returnstmt-lowers-to-return-val.slang`](returnstmt-lowers-to-return-val.slang) |
| A ReturnStmt nested inside a ForStmt lowers to a `return_val(...)` terminator in a block reached from the loop body, alongside the `loop(...)` structured-branch terminator — the doc's "ReturnStmt -> IRReturn" claim is unaffected by enclosing control flow. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`return-from-inside-loop-emits-return-val-in-loop-block.slang`](return-from-inside-loop-emits-return-val-in-loop-block.slang) |
| A StructDecl containing another StructDecl as a field lowers to an outer IRStructType whose `field(...)` row names the inner IRStructType; a nested member assignment lowers to chained `get_field_addr` instructions. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`structdecl-nested-struct-field-lowers-to-field-of-struct-type.slang`](structdecl-nested-struct-field-lowers-to-field-of-struct-type.slang) |
| A StructDecl lowers to an `IRStructType` parent instruction containing `IRStructField` children. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`structdecl-lowers-to-struct-with-fields.slang`](structdecl-lowers-to-struct-with-fields.slang) |
| A StructDecl whose field is `int16_t` lowers with that field's IR type as `Int16` inside the `field(...)` row. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-int16-struct-field.slang`](lower-int16-struct-field.slang) |
| A StructDecl whose field is `uint8_t` lowers with the field IR type `UInt8`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-uint8-struct-field.slang`](lower-uint8-struct-field.slang) |
| A StructDecl with eight scalar fields lowers to an IRStructType carrying eight `field(...)` children in source order. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`structdecl-many-fields-eight-fields.slang`](structdecl-many-fields-eight-fields.slang) |
| A StructDecl with exactly one scalar field lowers to an IRStructType carrying exactly one `field(...)` child — sibling of the empty (zero-field is not tested) and the eight-field boundary cases. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`structdecl-single-field-lowers-to-one-field.slang`](structdecl-single-field-lowers-to-one-field.slang) |
| A SwitchStmt lowers to a `switch` structured-branch terminator with case-value/case-block operand pairs. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`switchstmt-lowers-to-switch.slang`](switchstmt-lowers-to-switch.slang) |
| A SwitchStmt with a default and a single explicit case lowers to a `switch(scrutinee, merge, default, k, block)` — minimum non-trivial case count. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`switchstmt-default-only-single-default-arm.slang`](switchstmt-default-only-single-default-arm.slang) |
| A SwitchStmt with five explicit cases lowers to a single `switch(...)` terminator carrying five case-value / case-block operand pairs in source order. | stress | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`switchstmt-five-cases-five-pairs.slang`](switchstmt-five-cases-five-pairs.slang) |
| A WhileStmt lowers to a `loop` structured-branch terminator (sibling of for; doc lists `WhileStmt` in the same row as `ForStmt`). | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`whilestmt-lowers-to-loop.slang`](whilestmt-lowers-to-loop.slang) |
| A `BinaryExpr` on `double` operands lowers to `mul` whose result IR type is `Double`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-double-arithmetic.slang`](lower-double-arithmetic.slang) |
| A `BinaryExpr` on `half` operands lowers to `add` whose result IR type is `Half`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-half-arithmetic.slang`](lower-half-arithmetic.slang) |
| A `BinaryExpr` on `int16_t` operands lowers to `add` whose result type carries through the narrow `Int16` IR type. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-int8-arithmetic.slang`](lower-int8-arithmetic.slang) |
| A `BinaryExpr` on `uint64_t` operands lowers to `add` whose result IR type is `UInt64`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-uint64-arithmetic.slang`](lower-uint64-arithmetic.slang) |
| A `ParameterBlock<Narrow>` over a struct of narrow types lowers to a `global_param` whose IR type is `ParameterBlock(%Narrow)`; the inner struct's `field(...)` rows preserve each narrow type. | expansion | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-parameter-block-narrow-struct.slang`](lower-parameter-block-narrow-struct.slang) |
| A `RWStructuredBuffer<Narrow>` over a struct with narrow integer fields lowers so the per-element `Ptr(%Narrow)` is returned by `rwstructuredBufferGetElementPtr`, and the struct's narrow-typed `field(...)` rows survive. | expansion | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-buffer-of-struct-with-narrow-types.slang`](lower-buffer-of-struct-with-narrow-types.slang) |
| A `RWStructuredBuffer<int64_t>` lowers so the element pointer returned by `rwstructuredBufferGetElementPtr` is `Ptr(Int64)`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-int64-buffer-element.slang`](lower-int64-buffer-element.slang) |
| A `Tuple<half, uint16_t>` lowers to `tuple_type(Half, UInt16)` — narrow-precision pair carries through tuple IR type. | expansion | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-tuple-narrow-pair.slang`](lower-tuple-narrow-pair.slang) |
| A `Tuple<int8_t, float, bool>` constructor lowers to a `makeTuple(...)` whose result IR type is `tuple_type(Int8, Float, Bool)` carrying each element's lowered IR type. | expansion | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-tuple-heterogeneous.slang`](lower-tuple-heterogeneous.slang) |
| A `matrix<double, 2, 4>` rectangular matrix lowers with IR type `Mat(Double, 2 : Int, 4 : Int, 0 : Int)`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-mat-double-rectangular.slang`](lower-mat-double-rectangular.slang) |
| A `matrix<double, 4, 4>` global lowers with IR type `Mat(Double, 4 : Int, 4 : Int, 0 : Int)`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-double-matrix.slang`](lower-double-matrix.slang) |
| A `matrix<half, 3, 2>` rectangular matrix lowers with IR type `Mat(Half, 3 : Int, 2 : Int, 0 : Int)`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-mat-half-rectangular.slang`](lower-mat-half-rectangular.slang) |
| A `matrix<half, 3, 3>` global lowers with IR type `Mat(Half, 3 : Int, 3 : Int, 0 : Int)`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-half-matrix.slang`](lower-half-matrix.slang) |
| A `return` from a void-returning function lowers to `return_val(void_constant)` — the doc's "ReturnStmt → IRReturn terminator" claim, void variant. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`return-void-uses-void-constant.slang`](return-void-uses-void-constant.slang) |
| A `uniform double` lowers with IR type `Double`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-double-scalar.slang`](lower-double-scalar.slang) |
| A `uniform half` lowers with IR type `Half`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-half-scalar.slang`](lower-half-scalar.slang) |
| A `vector<double, 3>` global lowers with IR type `Vec(Double, 3 : Int)`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-double3-vector.slang`](lower-double3-vector.slang) |
| A `vector<half, 3>` global lowers with IR type `Vec(Half, 3 : Int)`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-half3-vector.slang`](lower-half3-vector.slang) |
| A `vector<int64_t, 3>` global lowers with IR type `Vec(Int64, 3 : Int)`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-int64-vector.slang`](lower-int64-vector.slang) |
| A `vector<int8_t, 4>` global lowers with IR type `Vec(Int8, 4 : Int)` — narrow-int element inside the vector storage form. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-int8-vector.slang`](lower-int8-vector.slang) |
| A `vector<uint16_t, 2>` global lowers with IR type `Vec(UInt16, 2 : Int)`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-uint16-vector.slang`](lower-uint16-vector.slang) |
| A fixed-size array of `double` global lowers with IR type `Array(Double, N : Int)`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-double-array.slang`](lower-double-array.slang) |
| A fixed-size array of `half` global lowers with IR type `Array(Half, N : Int)`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-half-array.slang`](lower-half-array.slang) |
| A fixed-size array of `int8_t` global lowers with IR type `Array(Int8, N : Int)`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-int8-array.slang`](lower-int8-array.slang) |
| A fixed-size array of `uint64_t` global lowers with IR type `Array(UInt64, N : Int)`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-uint64-array.slang`](lower-uint64-array.slang) |
| A float LiteralExpr lowers to an IRFloatLit constant inst spelled as `<value> : Float` inline in its operand position — the float-side of the doc's "LiteralExpr -> constant inst (IRIntLit, IRFloatLit, ...)" row. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`literalexpr-float-literal-lowers-to-float-constant.slang`](literalexpr-float-literal-lowers-to-float-constant.slang) |
| A function with five-deep nested IfStmts lowers each level to its own `ifElse(...)` terminator; the body grows into many basic blocks (then / else / merge per level). | stress | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`blockstmt-nested-five-deep-multiple-blocks.slang`](blockstmt-nested-five-deep-multiple-blocks.slang) |
| A global fixed-size array of struct elements lowers with IR type `Array(%Struct, N : Int)`; subscripting the array uses `getElement` to recover the struct element value. | expansion | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-array-of-structs.slang`](lower-array-of-structs.slang) |
| A local VarDecl whose address is taken (struct field access) lowers to an `IRVar` allocated inside the enclosing block. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`vardecl-local-struct-lowers-to-irvar.slang`](vardecl-local-struct-lowers-to-irvar.slang) |
| A method-call InvokeExpr `s.act(v)` on a struct lowers to a `call %S_act(...)` (the same `IRCall` family the doc lists) with the struct-typed receiver passed as the first argument. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`invokeexpr-method-call-on-struct-lowers-to-call.slang`](invokeexpr-method-call-on-struct-lowers-to-call.slang) |
| A module-scope `static const int N = 42;` lowers to a `globalConstant(42 : Int)` IR value bound to a named global; reads of `N` in `main` reference the named global, not the inline literal. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`static-const-lowers-to-global-constant.slang`](static-const-lowers-to-global-constant.slang) |
| A module-scope `uniform int16_t` lowers with IR type `Int16`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-int16-scalar.slang`](lower-int16-scalar.slang) |
| A module-scope `uniform int64_t` lowers with IR type `Int64`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-int64-scalar.slang`](lower-int64-scalar.slang) |
| A module-scope `uniform int8_t` lowers with IR type `Int8`; the doc's "VarDecl(global) -> IRGlobalVar" row at the narrow-integer end of the type axis. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-int8-scalar.slang`](lower-int8-scalar.slang) |
| A module-scope `uniform uint16_t` lowers with IR type `UInt16`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-uint16-scalar.slang`](lower-uint16-scalar.slang) |
| A module-scope `uniform uint64_t` lowers with IR type `UInt64`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-uint64-scalar.slang`](lower-uint64-scalar.slang) |
| A module-scope `uniform uint8_t` lowers with IR type `UInt8`; the doc's "VarDecl(global) -> IRGlobalVar" row at the unsigned narrow-integer end of the type axis. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-uint8-scalar.slang`](lower-uint8-scalar.slang) |
| A module-scope uniform VarDecl lowers to an `IRGlobalVar` (spelled `global_param` in the IR dump). | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`vardecl-global-uniform-lowers-to-global-param.slang`](vardecl-global-uniform-lowers-to-global-param.slang) |
| A non-square `float2x4` matrix lowers with IR type `Mat(Float, 2 : Int, 4 : Int, 0 : Int)`; the row/column operands appear in source order. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-mat2x4-rectangular.slang`](lower-mat2x4-rectangular.slang) |
| A non-square `float4x2` matrix lowers with IR type `Mat(Float, 4 : Int, 2 : Int, 0 : Int)` — the row/column dimensions are not confused with `float2x4`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-mat4x2-rectangular.slang`](lower-mat4x2-rectangular.slang) |
| A short-circuit `(a > b) && (c < d)` lowers to an `ifElse(...)` terminator whose true/false blocks unconditionally branch to a merge block carrying the joined Bool as a block parameter — the doc's phi-as-block-param encoding applied to short-circuit logic. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`shortcircuit-and-encodes-as-ifelse-with-block-param.slang`](shortcircuit-and-encodes-as-ifelse-with-block-param.slang) |
| A struct mixing narrow integer, half, float, double, and uint16 fields lowers so each `field(...)` row carries its element's lowered IR type verbatim. | expansion | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-struct-of-mixed-precision.slang`](lower-struct-of-mixed-precision.slang) |
| A struct whose field is `double` lowers with that field's IR type as `Double` inside the `field(...)` row. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-double-struct-field.slang`](lower-double-struct-field.slang) |
| A struct whose field is `half` lowers with that field's IR type as `Half` inside the `field(...)` row. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-half-struct-field.slang`](lower-half-struct-field.slang) |
| A struct whose fields are fixed-size arrays lowers so each `field(...)` row carries an `Array(...)` IR type — composition of StructDecl + Array rows. | expansion | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-struct-of-arrays.slang`](lower-struct-of-arrays.slang) |
| A subscript-assignment on an `RWStructuredBuffer<T>` lowers to `rwstructuredBufferGetElementPtr` followed by `store`. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`rwbuffer-write-lowers-to-getelementptr-store.slang`](rwbuffer-write-lowers-to-getelementptr-store.slang) |
| A unary `~a` (bitwise NOT) lowers to a `bitnot` IR opcode — pure-value inst in the doc's arithmetic-Expr row. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`unaryexpr-bitnot-lowers-to-bitnot.slang`](unaryexpr-bitnot-lowers-to-bitnot.slang) |
| A unary minus `-a` lowers to a `neg` IR opcode in the doc's pure-value-inst row; the row's "arithmetic Expr" wording covers unary as well as binary arithmetic. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`unaryexpr-neg-lowers-to-neg.slang`](unaryexpr-neg-lowers-to-neg.slang) |
| A uniform `uint` plus the literal `1u` lowers to a runtime `add(%a, 1 : UInt)` instruction; lowering does not pre-compute the sum because one operand is non-constant. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`literalexpr-uint-max-runtime-add-one-not-folded.slang`](literalexpr-uint-max-runtime-add-one-not-folded.slang) |
| A void-returning FuncDecl with an empty body lowers to an IRFunc whose sole block is a single `return_val(void_constant)` terminator. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`funcdecl-empty-body-lowers-to-return-val-void.slang`](funcdecl-empty-body-lowers-to-return-val-void.slang) |
| An IfStmt lowers to an `ifElse` structured-branch terminator whose merge / join point is an explicit operand. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`ifstmt-lowers-to-ifelse.slang`](ifstmt-lowers-to-ifelse.slang) |
| An IfStmt with no `else` clause still lowers to an `ifElse(...)` terminator carrying an explicit merge operand; the missing else-branch is represented by an empty/false-block jumping directly to the merge. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`ifstmt-no-else-lowers-to-ifelse-merge.slang`](ifstmt-no-else-lowers-to-ifelse-merge.slang) |
| An InterfaceDecl lowers to an `IRInterfaceType` plus per-method `interface_req_entry` instructions. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`interfacedecl-lowers-to-interface-with-req-entries.slang`](interfacedecl-lowers-to-interface-with-req-entries.slang) |
| An InterfaceDecl with exactly one method lowers to one `interface_req_entry(...)` row plus an `interface(...)` declaration with that single requirement. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`interfacedecl-single-method-one-req-entry.slang`](interfacedecl-single-method-one-req-entry.slang) |
| An InterfaceDecl with five methods lowers to five `interface_req_entry(...)` rows referenced by a single `interface(%1, %2, %3, %4, %5)` declaration, scaling the "InterfaceDecl -> IRInterfaceType plus per-method requirement insts" claim. | stress | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`interfacedecl-five-methods-five-req-entries.slang`](interfacedecl-five-methods-five-req-entries.slang) |
| An InterfaceDecl with three methods lowers to one `interface_req_entry(...)` instruction per method; the interface type aggregates them into a single `interface(...)` operand list. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`interfacedecl-three-methods-three-req-entries.slang`](interfacedecl-three-methods-three-req-entries.slang) |
| An InterfaceDecl with zero methods lowers to an `IRInterfaceType` carrying no method requirement entries — the witness table for a conforming type still exists but is empty. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`interfacedecl-empty-no-req-entry.slang`](interfacedecl-empty-no-req-entry.slang) |
| An InvokeExpr (function call) lowers to an `IRCall` (spelled `call %<callee>(...)` in the dump). | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`invokeexpr-lowers-to-call.slang`](invokeexpr-lowers-to-call.slang) |
| An assignment to a struct field lowers to a `store(%addr, %value)`; reading the field back lowers to a `load(%addr)`. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`load-store-from-local-pointer.slang`](load-store-from-local-pointer.slang) |
| An explicit `float(doubleValue)` cast lowers to `floatCast(%double)` — double-to-float narrowing in the float-to-float family. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-cast-double-to-float.slang`](lower-cast-double-to-float.slang) |
| An explicit `float(halfValue)` constructor-style cast lowers to `floatCast(%half)` — float-to-float family. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-cast-half-to-float.slang`](lower-cast-half-to-float.slang) |
| An explicit `int(int64Value)` cast lowers to `intCast(%int64)` — wide-to-narrow signed integer conversion in the int-to-int family. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-cast-int64-to-int.slang`](lower-cast-int64-to-int.slang) |
| An explicit `int(int8Value)` cast lowers to `intCast(%int8)` — narrow-to-wide signed integer conversion in the int-to-int family. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-cast-int8-to-int.slang`](lower-cast-int8-to-int.slang) |
| An explicit constructor-style cast `int(x)` between primitive numeric types lowers to a dedicated conversion IR opcode (`castFloatToInt` / `castIntToFloat`), produced from a `TypeCastExpr` AST node. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`conversion-explicit-cast-lowers-to-castfloattoint.slang`](conversion-explicit-cast-lowers-to-castfloattoint.slang) |
| An explicit constructor-style cast between two integer widths/signednesses (`uint(intValue)`) lowers to an `intCast` IR opcode — the integer-to-integer counterpart of `castFloatToInt`. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`cast-uint-from-int-lowers-to-intcast.slang`](cast-uint-from-int-lowers-to-intcast.slang) |
| Multiple ReturnStmts in a single FuncDecl each lower to their own `return_val(...)` terminator inside distinct basic blocks, all of which terminate the same IRFunc. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`returnstmt-early-return-emits-multiple-return-val.slang`](returnstmt-early-return-emits-multiple-return-val.slang) |
| Multiple module-scope `uniform VarDecl`s each lower to a `global_param` IR value, preserving source order and each carrying its declared type. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`vardecl-multiple-global-uniforms-each-lowers-to-global-param.slang`](vardecl-multiple-global-uniforms-each-lowers-to-global-param.slang) |
| Phi-style joining is encoded as block parameters (IRParam at the start of a block); branches to a block carry the parameter values as arguments — not via an explicit `phi` opcode. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`block-param-replaces-phi.slang`](block-param-replaces-phi.slang) |
| Structured branches (`ifElse`) encode the join (merge) point as an explicit operand on the terminator; the two branches reach it via `unconditionalBranch`. | functional | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`ifelse-merge-block-is-explicit-operand.slang`](ifelse-merge-block-is-explicit-operand.slang) |
| Two nested ForStmts lower to two distinct `loop(...)` terminators inside `func %main`, each with its own induction-variable block parameter — sibling stress to the deep-if test. | stress | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`loop-nested-two-deep-emits-two-loop-instructions.slang`](loop-nested-two-deep-emits-two-loop-instructions.slang) |
| When both operands of `+` are compile-time integer literals (uint MAX and `1u`), the IRBuilder constant-folds at lowering and the body emits `store(..., 0 : UInt)` directly — no `add` instruction survives. | boundary | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`literalexpr-uint-max-literal-add-one-constant-folds.slang`](literalexpr-uint-max-literal-add-one-constant-folds.slang) |
| `Optional<int>` composes through lowering as `Optional(Int)`; the nested-type axis on a scalar inner type. | expansion | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-optional-int.slang`](lower-optional-int.slang) |
| `Optional<vector<half, 3>>` composes through lowering as `Optional(Vec(Half, 3 : Int))` — generic specialization of `Optional` over a narrow-precision vector element is deferred, but the storage IR type is observable. | expansion | [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | [`lower-optional-half3.slang`](lower-optional-half3.slang) |
| A FuncDecl registered as an entry point ends up in the lowered module with an `entryPoint(...)` decoration on its IRFunc. | functional | [#module-level-outputs](../../../design/pipeline/04-ast-to-ir.md#module-level-outputs) | [`entry-point-funcdecl-carries-entry-point-decoration.slang`](entry-point-funcdecl-carries-entry-point-decoration.slang) |
| A cbuffer containing a single scalar lowers to a `ConstantBuffer<...>` global parameter whose payload struct carries exactly one `field(...)` row. | boundary | [#module-level-outputs](../../../design/pipeline/04-ast-to-ir.md#module-level-outputs) | [`cbuffer-single-scalar-lowers-to-one-field-struct.slang`](cbuffer-single-scalar-lowers-to-one-field-struct.slang) |
| A cbuffer mixing scalar, vector, and matrix fields lowers to a `ConstantBuffer<...>` payload struct whose `field(...)` rows carry each member's IR type verbatim (Int, Vec, Mat). | boundary | [#module-level-outputs](../../../design/pipeline/04-ast-to-ir.md#module-level-outputs) | [`cbuffer-mixed-types-lowers-to-struct-with-mixed-fields.slang`](cbuffer-mixed-types-lowers-to-struct-with-mixed-fields.slang) |
| An empty `cbuffer CB {}` lowers to a `ConstantBuffer(%SLANG_ParameterGroup_CB, ...)` global parameter and a body-less struct type; layout-intent annotation appears later in the pipeline. | boundary | [#module-level-outputs](../../../design/pipeline/04-ast-to-ir.md#module-level-outputs) | [`cbuffer-empty-lowers-to-empty-struct.slang`](cbuffer-empty-lowers-to-empty-struct.slang) |
| Only FuncDecls registered as entry points carry an `entryPoint(...)` decoration; a sibling non-entry helper function in the same translation unit is lowered without that decoration. | boundary | [#module-level-outputs](../../../design/pipeline/04-ast-to-ir.md#module-level-outputs) | [`non-entry-funcdecl-lacks-entry-point-decoration.slang`](non-entry-funcdecl-lacks-entry-point-decoration.slang) |
| Requesting an entry-point name that does not exist in the translation unit fires a "no function found matching entry point name 'main'" diagnostic before any IR module can be produced. | negative | [#module-level-outputs](../../../design/pipeline/04-ast-to-ir.md#module-level-outputs) | [`entry-missing-name-fires-no-function-found.slang`](entry-missing-name-fires-no-function-found.slang) |
| When two FuncDecls are registered as entry points in one translation unit, each lowered IRFunc carries its own `entryPoint(...)` decoration; the module-level entry-point list contains both. | boundary | [#module-level-outputs](../../../design/pipeline/04-ast-to-ir.md#module-level-outputs) | [`entry-point-multiple-each-gets-entry-point-decoration.slang`](entry-point-multiple-each-gets-entry-point-decoration.slang) |


## Untested claims
| Claim | Reason | Anchor | Why untested |
| --- | --- | --- | --- |
| `generateIRForSpecializedComponentType` and `generateIRForTypeConformance` — component-type API entry points invoked through the `Session`, not through the command line. A C++ unit test would exercise them. | (unclassified) | [#generateirforspecializedcomponenttype](../../../design/pipeline/04-ast-to-ir.md#generateirforspecializedcomponenttype) | Reason and explanation to be refined by the next regeneration. |
| `IRBuilder` hash-consing decisions — the dump shows the post- dedup result, not the decision path. | (unclassified) | [#irbuilder](../../../design/pipeline/04-ast-to-ir.md#irbuilder) | Reason and explanation to be refined by the next regeneration. |
| `kIROpFlag_Hoistable` / `kIROpFlag_Global` flag bits — internal to `IRInst`, not in the dump. | (unclassified) | [#kiropflaghoistable](../../../design/pipeline/04-ast-to-ir.md#kiropflaghoistable) | Reason and explanation to be refined by the next regeneration. |
| Order of pass invocation inside `linkAndOptimizeIR` — belongs to `pipeline/05-ir-passes`. | (unclassified) | [#linkandoptimizeir](../../../design/pipeline/04-ast-to-ir.md#linkandoptimizeir) | Reason and explanation to be refined by the next regeneration. |
| "Lowering errors flow through DiagnosticSink" — true, but the doc does not name a specific construct that produces a lowering-only diagnostic, so no `.slang` test can probe it here. Diagnostic claims belong to `pipeline/03-semantic-check`. | (unclassified) | [#lowering-errors-flow-through-diagnosticsink](../../../design/pipeline/04-ast-to-ir.md#lowering-errors-flow-through-diagnosticsink) | Reason and explanation to be refined by the next regeneration. |
| Side artefacts on the surrounding `Module` (entry-point list, type-conformance bookkeeping, layout-intent markers) — these are C++ container contents, not observable through slangc CLI. | (unclassified) | [#module](../../../design/pipeline/04-ast-to-ir.md#module) | Reason and explanation to be refined by the next regeneration. |
| The `slang-ir-insts-enum.h` FIDDLE-generated `IROp` enum — a build-time artefact. | compile-time-toggle | [#irop](../../../design/pipeline/04-ast-to-ir.md#irop) | Preprocessor define or build-time flag baked into the binary; not observable at runtime. |
| Internal lowering visitor structure (which C++ visitor method handles which AST node) — implementation detail of `slang-lower-to-ir.cpp`, not surface-visible. | internal-source-fact | (unspecified) | Implementation detail (C++ class hierarchy, field names, parser-callback names) with no user-observable consequence. |


## Doc gaps observed
| Anchor | Kind | Gap | Suggested addition |
| --- | --- | --- | --- |
| [#mapping-ast-constructs-to-ir](../../../design/pipeline/04-ast-to-ir.md#mapping-ast-constructs-to-ir) | undocumented-behavior | The doc's "Mapping AST constructs to IR" table is explicitly "illustrative, not exhaustive" — a number of AST families that appear in practice are absent: `IndexExpr` (resource subscript / array element access), `AssignExpr` (the assignment itself, vs. the lvalue-side `get_field_addr` + `store`), `TypeCastExpr` (cast lowering — only mentioned implicitly through the arithmetic/comparison row), `BreakStmt` / `ContinueStmt` (loop exit / continue terminators), `ConditionalExpr` (ternary). A single-line addition per row would let agents anchor tests for each. The bundle covers explicit casts and buffer indexing under the existing rows but with a stretched citation. |  |
| [#structured-branches-whose-join-point-is-an-explicit-operand-on-the-terminator](../../../design/pipeline/04-ast-to-ir.md#structured-branches-whose-join-point-is-an-explicit-operand-on-the-terminator) | undocumented-behavior | The doc says "structured branches whose join point is an explicit operand on the terminator" but does not say which operand position is the merge block for each terminator. The `cross-cutting/ir-instructions` doc has more detail on this; an explicit cross-reference would help. |  |
| [#the-lowering-visitor-descends-the-ast-top-down](../../../design/pipeline/04-ast-to-ir.md#the-lowering-visitor-descends-the-ast-top-down) | undocumented-behavior | "The lowering visitor descends the AST top-down" — the doc names the algorithmic style but does not list any user-observable consequence (e.g. ordering of nameHint decoration emission). An observability hook would let an agent test it. |  |
| [#pipeline03-semantic-check](../../../design/pipeline/04-ast-to-ir.md#pipeline03-semantic-check) | undocumented-behavior | The doc says "Lowering errors flow through the same DiagnosticSink used by the rest of the front-end" but lists no specific construct that produces a lowering-only diagnostic. A single example (e.g. "interface conformance with a missing witness that semantic check could not detect") would unlock diagnostic tests for this stage; without one, all rejection-style tests belong to `pipeline/03-semantic-check`. |  |
| [#generateirforspecializedcomponenttype](../../../design/pipeline/04-ast-to-ir.md#generateirforspecializedcomponenttype) | undocumented-behavior | `generateIRForSpecializedComponentType` and `generateIRForTypeConformance` are described as entry points but the doc does not name a `.slang`-observable surface that triggers each path. They are reachable only through C++ API. |  |
| [#lower-to-ir](../../../design/pipeline/04-ast-to-ir.md#lower-to-ir) | undocumented-behavior | The doc says global parameters carry "layout intent" markers, but does not state what those markers look like in the `### LOWER-TO-IR:` stage (the layout decoration appears in later stages). A row of the form "global params carry decoration X at lowering" would let an agent test it; otherwise the topic belongs to `pipeline/04c-layout-ir`. |  |
| [#element-types-and-storage-shapes](../../../design/pipeline/04-ast-to-ir.md#element-types-and-storage-shapes) | undocumented-behavior | **Type-lowering claims are implicit rather than enumerated.** The doc's table only names which AST-family produces which IR-family (e.g. `StructDecl -> IRStructType`). It does not enumerate the per-scalar-type IR-side spellings that lowering must preserve — `Int8`/`UInt8`/`Int16`/`UInt16`/`Int64`/`UInt64`/`Half`/`Double`, vector/array/matrix composition with each, and the rectangular matrix `Mat(<elem>, R : Int, C : Int, 0 : Int)` shape with row/col order. A "Element types and storage shapes" subsection under "Mapping AST constructs to IR" — or a cross-reference to `cross-cutting/ir-instructions.md` — would let agents anchor tests for these without stretching the existing rows. |  |
| [#optionalt](../../../design/pipeline/04-ast-to-ir.md#optionalt) | undocumented-behavior | **`Optional<T>` and `Tuple<...>` are not in the AST-family table.** Optional lowers to `Optional(<T>)` and Tuple to `tuple_type(...)`; both are observable through `-dump-ir`. The doc references the hash-consing rules in `design/ir.md` but no row in the lowering table names these generic-composite types, even though their syntax is part of the documented surface in `pipeline/03-semantic-check`. |  |
| [#parameterblockt-vardecl---irglobalparam-of-type-parameterblockt](../../../design/pipeline/04-ast-to-ir.md#parameterblockt-vardecl---irglobalparam-of-type-parameterblockt) | undocumented-behavior | **`ParameterBlock<T>` lowering is not mentioned by name.** The doc says global VarDecls become `IRGlobalVar`, but `ParameterBlock(%T)` is a distinct IR type, not a plain global. A row "ParameterBlock<T> VarDecl -> IRGlobalParam of type `ParameterBlock(%T)`" would close this gap. |  |
| [#typecastexpr---family-of-cast-pure-value-insts](../../../design/pipeline/04-ast-to-ir.md#typecastexpr---family-of-cast-pure-value-insts) | undocumented-behavior | **Cast lowering is illustrated by name but not by family.** The doc table mentions `BinaryExpr -> IRAdd/IRMul/IREq, ...`. Explicit type-cast lowering follows a parallel family — `floatCast`, `intCast`, `castFloatToInt`, `castIntToFloat` — with one opcode per source/dest type family. A row "TypeCastExpr -> family of cast pure-value insts" would tie these to the doc directly; the bundle currently anchors them under the more general "Mapping AST constructs to IR" header. |  |
