---
generated: true
model: claude-opus-4-7
generated_at: 2026-05-22T00:00:00+00:00
source_commit: 6e923e2c0fe3cae4e7cf40e25a96569df5b9f009
watched_paths_digest: 4cd2b0ab91da080eb6a16ece95070e661cf2096b991cd6d164bfccb383236671
source_doc: docs/generated/design/ir-reference/values.md
source_doc_digest: 0bd66a543db2abee42ed03fc4534c5483860e577fe816355ee527d444cedd80b
warning: "Auto-generated. May drift from source. Do not edit by hand."
---

# Tests for ir-reference/values

## Intent
Tests verify the per-opcode catalog of the IR value-producing family
described in
[`docs/generated/design/ir-reference/values.md`](../../../design/ir-reference/values.md):
that each documented IR value opcode (literal payloads inline on
`IRInst` for `integer_constant`/`float_constant`/`boolConst`/`void_constant`;
arithmetic and bitwise `irem`/`frem`/`neg`/`shl`/`shr`/`and`/`or`/`xor`/`bitnot`/`not`;
the branch-free `select`; comparisons
`cmpEQ`/`cmpNE`/`cmpLT`/`cmpLE`/`cmpGE`;
conversions `intCast`/`floatCast`/`castIntToFloat`/`castFloatToInt`/`bitCast`/`castToVoid`;
memory `get_field` (rvalue), `getElement` (rvalue), `getElementPtr`
(lvalue), `globalConstant`, `swizzle` (multi-component) and
`swizzledStore`;
aggregate constructors `makeVector`/`makeMatrix`/`makeTuple`;
the optional helpers
`makeOptionalValue`/`makeOptionalNone`/`optionalHasValue`/`getOptionalValue`;
the bitfield builtins `bitfieldExtract`/`bitfieldInsert`;
the `out` parameter form `OutParam(<T>)`;
and `return_val(void_constant)` for `void`-returning functions)
appears in `-dump-ir` output for the obvious surface construct that
produces it, and that target-divergent emit lowerings (vector
swizzle, integer/float literals) emit the documented per-target
text on the text-emit backends.

The primary observation mechanism is `-target spirv-asm -dump-ir -o
/dev/null` followed by a FileCheck against the IR dump. Anchors are
user-named functions, user struct fields, and user
`global_param`s — the IR dump's preamble is large and any unanchored
pattern risks false positives. For target-divergent lowerings
(vector swizzle, literal emission) the test carries one SIMPLE
directive per feasible text-emit target with a distinct CHECK
prefix, because the doc does not claim cross-target uniformity for
these lowerings.

Catalog rows that the `cross-cutting/ir-instructions` bundle already
covers at a sample level (`add`/`sub`/`mul`/`div` for `int`, `cmpGT`,
`intCast` from `uint`, the `var`+`load`+`store`+`get_field_addr`
quartet on a struct local, single-component `swizzle`,
`rwstructuredBufferGetElementPtr`) are not duplicated here; this
bundle drills into the rest of the catalog without repeating those.


## Functional coverage
| Claim | Intent | Anchor | Tests |
| --- | --- | --- | --- |
| A `CoopVec<T, N>(args...)` cooperative-vector constructor call lowers — via the synthesized `CoopVec.$init` — to a `makeCoopVector(...)` IR opcode with one operand per element. | functional | [#aggregate-constructors](../../../design/ir-reference/values.md#aggregate-constructors) | [`aggregate-makecoopvector.slang`](aggregate-makecoopvector.slang) |
| A `floatN(...)` vector-constructor call with non-constant component values lowers to `makeVector(%a, %b, ...)` of type `Vec(Float, N : Int)`. | functional | [#aggregate-constructors](../../../design/ir-reference/values.md#aggregate-constructors) | [`aggregate-makevector.slang`](aggregate-makevector.slang) |
| A `floatRxC(...)` matrix-constructor call with non-constant component values lowers to `makeMatrix(...)` producing a `Mat(Float, R : Int, C : Int, L : Int)` value. | functional | [#aggregate-constructors](../../../design/ir-reference/values.md#aggregate-constructors) | [`aggregate-makematrix.slang`](aggregate-makematrix.slang) |
| A `makeTuple(...)` call lowers to the `makeTuple` IR opcode producing a `tuple_type(...)` value. | functional | [#aggregate-constructors](../../../design/ir-reference/values.md#aggregate-constructors) | [`aggregate-maketuple.slang`](aggregate-maketuple.slang) |
| Boundary: `float2(fa, fb)` (smallest documented vector dimension) lowers to `makeVector(%fa, %fb)` with result type `Vec(Float, 2 : Int)`. | boundary | [#aggregate-constructors](../../../design/ir-reference/values.md#aggregate-constructors) | [`makeVector-float2-smallest-vector.slang`](makeVector-float2-smallest-vector.slang) |
| Stress: a `float4x4(...)` constructor with sixteen `uniform` float operands lowers to a single `makeMatrix(...)` opcode with sixteen variadic operands — pattern-bloat probe for the largest documented matrix dimension. | stress | [#aggregate-constructors](../../../design/ir-reference/values.md#aggregate-constructors) | [`makeMatrix-float4x4-largest-documented.slang`](makeMatrix-float4x4-largest-documented.slang) |
| Stress: two distinct `float4(...)` constructions feeding a vector `add` lower to two `makeVector(...)` opcodes plus an `add(%a, %b)` on the vector type — pattern-bloat probe for componentwise vector arithmetic. | stress | [#aggregate-constructors](../../../design/ir-reference/values.md#aggregate-constructors) | [`_probe_diag.slang`](_probe_diag.slang) |
| The synthesized `__makeCoopVec<T, N>(expand each U)` variadic-pack core-module builtin (invoked by `CoopVec<T, N>(args...)` constructors) lowers to a `makeCoopVectorFromValuePack(...)` IR opcode in the generic-unspecialized form of `CoopVec.$init`. | functional | [#aggregate-constructors](../../../design/ir-reference/values.md#aggregate-constructors) | [`aggregate-makecoopvectorfromvaluepack.slang`](aggregate-makecoopvectorfromvaluepack.slang) |
| Bitwise `&` / `\|` / `^` lower to `and` / `or` / `xor`, and prefix `~` lowers to `bitnot`. | functional | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`arith-bitwise.slang`](arith-bitwise.slang) |
| Boundary: `a * 4294967295u` (multiplication by `uint` MAX) lowers to `mul(%a, 4294967295 : UInt)` with the MAX literal preserved as the inline payload. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`mul-uint-by-max-literal.slang`](mul-uint-by-max-literal.slang) |
| Boundary: `bitfieldExtract(a, 0, 0)` lowers to `bitfieldExtract(%a, 0 : UInt, 0 : UInt)` — the count=0 edge of the bitfield-width range. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`bitfieldExtract-count-zero.slang`](bitfieldExtract-count-zero.slang) |
| Boundary: `bitfieldExtract(a, 0, 32)` (full-width extract on a 32-bit `uint`) lowers to `bitfieldExtract(%a, 0 : UInt, 32 : UInt)` — the upper-edge of the bitfield-width range. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`bitfieldExtract-count-full-width.slang`](bitfieldExtract-count-full-width.slang) |
| Boundary: `bitfieldExtract(a, 31, 1)` (top-bit extract on a 32-bit `uint`) lowers to `bitfieldExtract(%a, 31 : UInt, 1 : UInt)` — the high-edge of the offset axis. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`bitfieldExtract-offset-high-edge.slang`](bitfieldExtract-offset-high-edge.slang) |
| Boundary: `bitfieldInsert(a, b, 0, 32)` (full-width replace on a 32-bit `uint`) lowers to `bitfieldInsert(%a, %b, 0 : UInt, 32 : UInt)` — the upper edge of the bitfield-width range. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`bitfieldInsert-count-full-width.slang`](bitfieldInsert-count-full-width.slang) |
| Boundary: arithmetic right-shift by 31 (`a >> 31`) on a 32-bit signed int lowers to `shr(%a, 31 : Int)` — the upper-edge valid amount; canonical "extract sign bit" idiom. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`shr-int-by-width-minus-one.slang`](shr-int-by-width-minus-one.slang) |
| Boundary: float divide by positive-zero literal (`fa / 0.0`) lowers to `div(%a, 0 : Float)` — the `div` opcode survives even when the divisor is the IEEE-754 +zero, where integer divide-by-zero is rejected as a diagnostic. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`div-float-by-positive-zero-uniform.slang`](div-float-by-positive-zero-uniform.slang) |
| Boundary: integer remainder by 1 (`a % 1`) lowers to `irem(%a, 1 : Int)` — the smallest non-zero divisor edge for the documented `irem` opcode. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`irem-int-by-one.slang`](irem-int-by-one.slang) |
| Boundary: prefix `-` on a `uniform float` lowers to `neg(%fa)` — the float-typed sibling of the integer `neg` exercised in the smoke test. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`neg-uniform-float.slang`](neg-uniform-float.slang) |
| Boundary: prefix `-` on a `uniform int` (whose value spans the full signed-32 range, including the documented MIN where unary negation overflows) lowers to `neg(%a)`. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`neg-uniform-int.slang`](neg-uniform-int.slang) |
| Boundary: right-shift by 0 (`a >> 0`) lowers to `shr(%a, 0 : Int)` — the lower edge of the shift-amount axis on the `shr` opcode. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`shr-int-by-zero.slang`](shr-int-by-zero.slang) |
| Boundary: shift by 0 (`a << 0`) lowers to `shl(%a, 0 : Int)` — the lower edge of the shift-amount axis. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`shl-uint-by-zero.slang`](shl-uint-by-zero.slang) |
| Boundary: shift by 31 (`a << 31`) on a 32-bit `uint` lowers to `shl(%a, 31 : Int)` — the documented "width minus one" valid edge. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`shl-uint-by-width-minus-one.slang`](shl-uint-by-width-minus-one.slang) |
| Boundary: shift by 32 (`a << 32`) on a 32-bit `uint` still lowers to `shl(%a, 32 : Int)` (one past the documented valid range) — the opcode appears in IR even though semantic-check emits a left-shift-overflow warning. Verifies that lowering proceeds past the warning, leaving the literal payload intact. | boundary | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`shl-uint-by-width-overflow.slang`](shl-uint-by-width-overflow.slang) |
| Integer `%` lowers to `irem`, floating-point `%` lowers to `frem`, and prefix `-` lowers to `neg`. | functional | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`arith-irem-frem-neg.slang`](arith-irem-frem-neg.slang) |
| Negative boundary: integer `a / 0` is rejected by semantic check with "divide by zero" — no `div` IR opcode is produced. (Float divide-by-zero is permitted; see `div-float-by-positive-zero-uniform.slang`.) | negative | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`int-divide-by-zero-literal-rejected.slang`](int-divide-by-zero-literal-rejected.slang) |
| Prefix `!` on a boolean lowers to the `not` opcode. | functional | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`logical-not.slang`](logical-not.slang) |
| The `<<` operator lowers to `shl` and `>>` lowers to `shr`; the doc notes the arithmetic-vs-logical choice is keyed by operand signedness. | functional | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`arith-shifts.slang`](arith-shifts.slang) |
| The `bitfieldExtract(v, off, count)` and `bitfieldInsert(b, ins, off, count)` builtins lower to the IR opcodes of the same names. | functional | [#arithmetic-and-bitwise](../../../design/ir-reference/values.md#arithmetic-and-bitwise) | [`bitfield-extract-insert.slang`](bitfield-extract-insert.slang) |
| Boundary: `<=` / `>=` on `uniform float` operands lower to `cmpLE` / `cmpGE` — verifying the ordered-comparison opcodes survive on the float type (existing smoke test covers integer ordering). | boundary | [#comparison](../../../design/ir-reference/values.md#comparison) | [`cmpLE-cmpGE-float-uniform.slang`](cmpLE-cmpGE-float-uniform.slang) |
| Boundary: `==` against the float literal `0.0` lowers to `cmpEQ(%fa, 0 : Float)`, preserving the literal payload on the comparison operand. | boundary | [#comparison](../../../design/ir-reference/values.md#comparison) | [`cmpEQ-float-pos-zero-literal.slang`](cmpEQ-float-pos-zero-literal.slang) |
| Boundary: `==` against the negative-zero literal `-0.0` lowers to `cmpEQ(%fa, -0 : Float)`, with the sign-distinct payload preserved on the operand. | boundary | [#comparison](../../../design/ir-reference/values.md#comparison) | [`cmpEQ-float-neg-zero-literal.slang`](cmpEQ-float-neg-zero-literal.slang) |
| Boundary: `fa != fa` on a `uniform float` surfaces `cmpNE(%fa, %fa)` — the NaN-detection idiom is preserved through IR lowering. | boundary | [#comparison](../../../design/ir-reference/values.md#comparison) | [`cmpNE-self-uniform-float.slang`](cmpNE-self-uniform-float.slang) |
| Boundary: `fa == fa` on a `uniform float` is not constant-folded away — both operands are the same SSA value, so the comparison surfaces `cmpEQ(%fa, %fa)`. This is the canonical NaN-detection idiom (NaN != NaN per IEEE-754). | boundary | [#comparison](../../../design/ir-reference/values.md#comparison) | [`cmpEQ-self-uniform-float.slang`](cmpEQ-self-uniform-float.slang) |
| Expansion: `double <= double` lowers to `cmpLE(%a, %b)` — the doc places the float ranks under the same `cmpLE` opcode as int. | expansion | [#comparison](../../../design/ir-reference/values.md#comparison) | [`cmple-double-uniform.slang`](cmple-double-uniform.slang) |
| Expansion: comparing two `int64_t` values lowers to `cmpLT(%a, %b)` — the doc places all integer ranks under one opcode. | expansion | [#comparison](../../../design/ir-reference/values.md#comparison) | [`cmplt-int64-uniform.slang`](cmplt-int64-uniform.slang) |
| Expansion: comparing two `int8_t` values lowers to `cmpEQ(%a, %b)` — verifies the opcode is the same shape at the small-int rank. | expansion | [#comparison](../../../design/ir-reference/values.md#comparison) | [`cmpeq-int8-uniform.slang`](cmpeq-int8-uniform.slang) |
| Expansion: comparing two `uint` (unsigned) values via `!=` lowers to `cmpNE(%a, %b)` — same opcode as signed-int and float operands. | expansion | [#comparison](../../../design/ir-reference/values.md#comparison) | [`cmpne-uint-uniform.slang`](cmpne-uint-uniform.slang) |
| The `<` / `<=` / `>=` operators lower to `cmpLT` / `cmpLE` / `cmpGE`. | functional | [#comparison](../../../design/ir-reference/values.md#comparison) | [`comparison-lt-le-ge.slang`](comparison-lt-le-ge.slang) |
| The `==` operator lowers to `cmpEQ` and `!=` lowers to `cmpNE`. | functional | [#comparison](../../../design/ir-reference/values.md#comparison) | [`comparison-eq-ne.slang`](comparison-eq-ne.slang) |
| A `(void)expr` cast discards the operand and lowers to the `castToVoid` IR opcode. | functional | [#conversions](../../../design/ir-reference/values.md#conversions) | [`conversion-cast-to-void.slang`](conversion-cast-to-void.slang) |
| A function with an `out T` parameter has IR type `OutParam(T)`; the callee writes through the parameter with `store`, and the caller passes a `Ptr(T)` from a local `var`. | functional | [#conversions](../../../design/ir-reference/values.md#conversions) | [`out-param-type.slang`](out-param-type.slang) |
| A precision-changing float-to-float cast lowers to `floatCast`. | functional | [#conversions](../../../design/ir-reference/values.md#conversions) | [`conversion-floatcast.slang`](conversion-floatcast.slang) |
| Boundary: `bit_cast<float>(uintVal)` lowers to `bitCast(%a)` with `Float` result type — reinterpret across the signed/unsigned + int/float boundary. | boundary | [#conversions](../../../design/ir-reference/values.md#conversions) | [`bitCast-uint-to-float-reinterpret.slang`](bitCast-uint-to-float-reinterpret.slang) |
| Boundary: maximum-narrowing `int(32-bit) -> uint8_t(8-bit)` lowers to `intCast(%a)` with result type `UInt8` — verifying the same opcode covers the widest narrowing step in the documented int ladder. | boundary | [#conversions](../../../design/ir-reference/values.md#conversions) | [`intCast-int-to-uint8-narrowing.slang`](intCast-int-to-uint8-narrowing.slang) |
| Boundary: precision-narrowing `float -> half` lowers to a single `floatCast(%fa)` opcode. | boundary | [#conversions](../../../design/ir-reference/values.md#conversions) | [`floatCast-float-to-half-narrowing.slang`](floatCast-float-to-half-narrowing.slang) |
| Boundary: same-width signed-to-unsigned `int -> uint` lowers to `intCast(%a)`, even though no bit-width change is involved — the `intCast` opcode covers the signedness-flip step. | boundary | [#conversions](../../../design/ir-reference/values.md#conversions) | [`intCast-int-to-uint-same-width.slang`](intCast-int-to-uint-same-width.slang) |
| Boundary: widest float-widening `half -> double` lowers to a `floatCast(%ha)` opcode. | boundary | [#conversions](../../../design/ir-reference/values.md#conversions) | [`floatCast-half-to-double-widening.slang`](floatCast-half-to-double-widening.slang) |
| Boundary: widest unsigned-widening `int -> uint64_t` lowers to `intCast(%a)` — the same opcode covers the maximum signed-to-unsigned widening step. | boundary | [#conversions](../../../design/ir-reference/values.md#conversions) | [`intCast-int-to-uint64-widening.slang`](intCast-int-to-uint64-widening.slang) |
| Constructor-style `float(intVal)` lowers to `castIntToFloat`; `int(floatVal)` lowers to `castFloatToInt`. | functional | [#conversions](../../../design/ir-reference/values.md#conversions) | [`conversion-int-float.slang`](conversion-int-float.slang) |
| Expansion: 16-bit same-width reinterpret `bit_cast<half>(uint16_t)` lowers to `bitCast(%u16a)` with `Half` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`bitcast-uint16-to-half-reinterpret.slang`](bitcast-uint16-to-half-reinterpret.slang) |
| Expansion: `bit_cast<double>(uint64_t)` 64-bit same-width reinterpret lowers to `bitCast(%u64a)` with `Double` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`bitcast-uint64-to-double-reinterpret.slang`](bitcast-uint64-to-double-reinterpret.slang) |
| Expansion: `bit_cast<float>(int)` signed-int-to-float reinterpret lowers to `bitCast(%a)` with `Float` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`bitcast-int32-to-float-reinterpret.slang`](bitcast-int32-to-float-reinterpret.slang) |
| Expansion: `bit_cast<uint>(float)` reverse-direction reinterpret lowers to `bitCast(%fa)` with `UInt` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`bitcast-float-to-uint32-reinterpret.slang`](bitcast-float-to-uint32-reinterpret.slang) |
| Expansion: `double -> float` precision-narrowing lowers to `floatCast(%da)` with `Float` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`floatcast-double-to-float-narrow.slang`](floatcast-double-to-float-narrow.slang) |
| Expansion: `double -> int64_t` truncation lowers to a single `castFloatToInt(%da)` with `Int64` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`castfloattoint-double-to-int64.slang`](castfloattoint-double-to-int64.slang) |
| Expansion: `double -> int8_t` truncation lowers to a single `castFloatToInt(%da)` with `Int8` result — combines precision loss and rank narrowing in one opcode. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`castfloattoint-double-to-int8-narrow.slang`](castfloattoint-double-to-int8-narrow.slang) |
| Expansion: `double -> int` truncation lowers to a single `castFloatToInt(%da)` with `Int` result — no intermediate `float` step. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`castfloattoint-double-to-int32.slang`](castfloattoint-double-to-int32.slang) |
| Expansion: `float -> int` truncation lowers to a single `castFloatToInt(%fa)` with `Int` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`castfloattoint-float-to-int32.slang`](castfloattoint-float-to-int32.slang) |
| Expansion: `float -> uint` truncation (signed-to-unsigned float-to-int) lowers to a single `castFloatToInt(%fa)` with `UInt` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`castfloattoint-float-to-uint32.slang`](castfloattoint-float-to-uint32.slang) |
| Expansion: `half -> uint` truncation lowers to a single `castFloatToInt(%ha)` with `UInt` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`castfloattoint-half-to-uint32.slang`](castfloattoint-half-to-uint32.slang) |
| Expansion: `int -> half` lowers directly to `castIntToFloat(%a)` with `Half` result — no intermediate `float` step at IR level. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`castinttofloat-int32-to-half.slang`](castinttofloat-int32-to-half.slang) |
| Expansion: `int == half` triggers `castIntToFloat` on the int operand (to `Half`), then `cmpEQ` — confirms the conversion opcode targets the common float type by result rank. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`cmpeq-int-vs-half-implicit-conversion.slang`](cmpeq-int-vs-half-implicit-conversion.slang) |
| Expansion: `int(32-bit) -> int8_t` narrowing across the full int ladder lowers to `intCast(%a)` with `Int8` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`intcast-int32-to-int8-narrow.slang`](intcast-int32-to-int8-narrow.slang) |
| Expansion: `int16_t -> uint8_t` narrowing across signedness lowers to a single `intCast(%i16a)` with `UInt8` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`intcast-int16-to-uint8-narrow-across-signedness.slang`](intcast-int16-to-uint8-narrow-across-signedness.slang) |
| Expansion: `int64_t -> uint16_t` narrowing across signedness lowers to a single `intCast(%i64a)` with `UInt16` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`intcast-int64-to-uint16-narrow-across-signedness.slang`](intcast-int64-to-uint16-narrow-across-signedness.slang) |
| Expansion: `int8_t + int16_t` promotes the int8 operand via `intCast` to int16 before `add` — surfaces the same `intCast` opcode used for explicit constructor casts. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`add-int8-plus-int16-promotes-via-intcast.slang`](add-int8-plus-int16-promotes-via-intcast.slang) |
| Expansion: `int8_t -> int16_t` one-step signed widening lowers to a single `intCast(%i8a)` with `Int16` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`intcast-int8-to-int16-widen.slang`](intcast-int8-to-int16-widen.slang) |
| Expansion: `select(c, intVal, floatVal)` implicitly converts the int arm via `castIntToFloat` so both arms meet a common float type; the `select` opcode then takes two `Float` operands. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`select-mixed-int-float-arms-implicit-conversion.slang`](select-mixed-int-float-arms-implicit-conversion.slang) |
| Expansion: `uint32 -> int8_t` narrowing across signedness lowers to a single `intCast(%a)` with `Int8` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`intcast-uint32-to-int8-narrow-across-signedness.slang`](intcast-uint32-to-int8-narrow-across-signedness.slang) |
| Expansion: `uint8_t -> int32` widening (zero-extend then re-interpret) lowers to a single `intCast(%u8a)` with `Int` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`intcast-uint8-to-int32-zero-extend.slang`](intcast-uint8-to-int32-zero-extend.slang) |
| Expansion: comparing `int < float` triggers an implicit `castIntToFloat` on the int operand before `cmpLT`; verifies the documented conversion opcode bridges the type mismatch. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`cmplt-int-vs-float-implicit-conversion.slang`](cmplt-int-vs-float-implicit-conversion.slang) |
| Expansion: middle-of-ladder float widening `float -> double` lowers to `floatCast(%fa)` with `Double` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`floatcast-float-to-double-widen.slang`](floatcast-float-to-double-widen.slang) |
| Expansion: one-rung float widening `half -> float` lowers to a single `floatCast(%ha)` with `Float` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`floatcast-half-to-float-widen.slang`](floatcast-half-to-float-widen.slang) |
| Expansion: reverse 16-bit reinterpret `bit_cast<uint16_t>(half)` lowers to `bitCast(%ha)` with `UInt16` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`bitcast-half-to-uint16-reinterpret.slang`](bitcast-half-to-uint16-reinterpret.slang) |
| Expansion: reverse 64-bit reinterpret `bit_cast<uint64_t>(double)` lowers to `bitCast(%da)` with `UInt64` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`bitcast-double-to-uint64-reinterpret.slang`](bitcast-double-to-uint64-reinterpret.slang) |
| Expansion: signed 64-to-32 truncation lowers to a single `intCast(%i64a)` with `Int` result — the reverse direction of the sign-extend widening case. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`intcast-int64-to-int32-truncate.slang`](intcast-int64-to-int32-truncate.slang) |
| Expansion: signed `int -> float` lowers to a single `castIntToFloat(%a)` with `Float` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`castinttofloat-int32-to-float.slang`](castinttofloat-int32-to-float.slang) |
| Expansion: signed widening `int32 -> int64_t` selects the sign-extend variant of `intCast`; lowers to `intCast(%a)` with `Int64` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`intcast-int32-to-int64-sign-extend.slang`](intcast-int32-to-int64-sign-extend.slang) |
| Expansion: small-int `uint8_t -> float` lowers to a single `castIntToFloat(%u8a)` with `Float` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`castinttofloat-uint8-to-float.slang`](castinttofloat-uint8-to-float.slang) |
| Expansion: small-signed-int to double `int16_t -> double` lowers to `castIntToFloat(%i16a)` with `Double` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`castinttofloat-int16-to-double.slang`](castinttofloat-int16-to-double.slang) |
| Expansion: smallest-rank float to small signed int `half -> int16_t` lowers to `castFloatToInt(%ha)` with `Int16` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`castfloattoint-half-to-int16.slang`](castfloattoint-half-to-int16.slang) |
| Expansion: unsigned `uint -> float` lowers to `castIntToFloat(%a)` with `Float` result — same opcode as the signed case, signedness encoded by operand type. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`castinttofloat-uint32-to-float.slang`](castinttofloat-uint32-to-float.slang) |
| Expansion: widest float-narrowing `double -> half` lowers to a single `floatCast(%da)` with `Half` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`floatcast-double-to-half-precision-loss.slang`](floatcast-double-to-half-precision-loss.slang) |
| Expansion: widest int-to-float `int64_t -> double` lowers to a single `castIntToFloat(%i64a)` with `Double` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`castinttofloat-int64-to-double.slang`](castinttofloat-int64-to-double.slang) |
| Expansion: widest signed widening `int8_t -> int64_t` (7 bits of extension) lowers to a single `intCast(%i8a)` with `Int64` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`intcast-int8-to-int64-widen-across-extend.slang`](intcast-int8-to-int64-widen-across-extend.slang) |
| Expansion: zero-width-change `uint64_t -> int64_t` signedness flip lowers to a single `intCast(%u64a)` with `Int64` result. | expansion | [#conversions](../../../design/ir-reference/values.md#conversions) | [`intcast-uint64-to-int64-same-width-flip.slang`](intcast-uint64-to-int64-same-width-flip.slang) |
| Negative: `bit_cast` between differently-sized types is rejected with `E41202: bit_cast size mismatch` — no `bitCast` IR opcode is produced. | negative | [#conversions](../../../design/ir-reference/values.md#conversions) | [`bitcast-different-width-rejected.slang`](bitcast-different-width-rejected.slang) |
| The `bit_cast<T>(...)` builtin lowers to the `bitCast` opcode (reinterpret bits without changing them). | functional | [#conversions](../../../design/ir-reference/values.md#conversions) | [`conversion-bitcast.slang`](conversion-bitcast.slang) |
| `intCast` is the integer-to-integer conversion opcode; both narrowing (int -> int16_t) and widening (int -> uint64_t) lower through it. | functional | [#conversions](../../../design/ir-reference/values.md#conversions) | [`conversion-intcast-narrow.slang`](conversion-intcast-narrow.slang) |
| A `MemberExpr` on a struct *value* (rvalue position) lowers to `get_field`, while the lvalue path uses `get_field_addr`. | functional | [#fieldaddress-vs-fieldextract](../../../design/ir-reference/values.md#fieldaddress-vs-fieldextract) | [`memory-get-field-rvalue.slang`](memory-get-field-rvalue.slang) |
| Array indexing in lvalue position lowers to `getElementPtr`; indexing into a struct-field array value lowers to `getElement`. | functional | [#getelementptr-vs-getelement](../../../design/ir-reference/values.md#getelementptr-vs-getelement) | [`memory-getelement-and-getelementptr.slang`](memory-getelement-and-getelementptr.slang) |
| An integer literal `42` and a float literal `3.5` emit as a recognizable numeric token on every text-emit target. | functional | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`literal-emit-multi-target.slang`](literal-emit-multi-target.slang) |
| Boundary: `uint8_t(256)` (one past unsigned-8 MAX) constant-folds to a `0 : UInt8` payload, demonstrating unsigned modular wrap on the narrowing path. | boundary | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`cast-uint8-max-plus-one-wraps.slang`](cast-uint8-max-plus-one-wraps.slang) |
| Boundary: a `double` literal at the edge of the documented finite range survives lowering and the IR formatter renders the upper-finite value as `inf : Double` when the literal would overflow double's normal range. | boundary | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`add-double-overflow-folds-to-inf.slang`](add-double-overflow-folds-to-inf.slang) |
| Boundary: documented `int16_t` MAX (32767) and MIN (-32768) survive lowering as `32767 : Int16` and `-32768 : Int16` on the `store` operands. | boundary | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`store-int16-max-literal.slang`](store-int16-max-literal.slang) |
| Boundary: documented `int64_t` MAX (9223372036854775807) survives lowering as `9223372036854775807 : Int64` on the `add` operand. | boundary | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`add-int64-max-literal.slang`](add-int64-max-literal.slang) |
| Boundary: documented `int8_t` MIN (-128) survives lowering as `-128 : Int8` on the `store` operand. | boundary | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`store-int8-min-literal.slang`](store-int8-min-literal.slang) |
| Boundary: documented `int` MAX (2147483647) survives lowering as a literal payload on the `add` operand of `add(%a, 2147483647 : Int)`. | boundary | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`add-int32-max-literal.slang`](add-int32-max-literal.slang) |
| Boundary: documented `int` MIN (-2147483648, expressed as `-2147483647 - 1` to avoid literal-overflow warning) survives lowering as `-2147483648 : Int` on the `add` operand. | boundary | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`add-int32-min-literal.slang`](add-int32-min-literal.slang) |
| Boundary: documented `uint8_t` MAX (255) and lower-edge (0) survive lowering as `255 : UInt8` and `0 : UInt8` on the `store` operands. | boundary | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`store-uint8-max-literal.slang`](store-uint8-max-literal.slang) |
| Boundary: documented `uint` MAX (4294967295) survives lowering as `4294967295 : UInt` on the `add` operand. | boundary | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`add-uint32-max-literal.slang`](add-uint32-max-literal.slang) |
| Boundary: largest-finite `float` literal (~3.40282e+38) survives lowering as `3.40282e+38 : Float` on an `add` operand. | boundary | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`add-float-max-literal.slang`](add-float-max-literal.slang) |
| Boundary: negative-zero `-0.0` literal survives as `-0 : Float` on a `mul` operand, distinct from positive `0` in the IR payload. | boundary | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`mul-float-neg-zero-literal.slang`](mul-float-neg-zero-literal.slang) |
| Boundary: positive `0.0` literal survives as `0 : Float` on a `mul` operand (the `add` identity collapses `+0`, so `mul` is used to keep the literal observable). | boundary | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`mul-float-pos-zero-literal.slang`](mul-float-pos-zero-literal.slang) |
| Boundary: smallest positive normal `float` (~1.17549e-38) survives lowering as `1.17549e-38 : Float` on an `add` operand. | boundary | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`add-float-smallest-normal-literal.slang`](add-float-smallest-normal-literal.slang) |
| Constant-family opcodes (IntLit / FloatLit / BoolLit / VoidLit) carry their value inline on the IRInst and appear as `<value> : <Type>` operands rather than as separately-named lines. | functional | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`literals-inline-payload.slang`](literals-inline-payload.slang) |
| Negative boundary: an integer literal larger than the documented `int64` MAX (99999999999999999999) is rejected with "integer literal is too large to be represented in any integer type" — the literal payload encoding has finite range. | negative | [#literal-payload-encoding](../../../design/ir-reference/values.md#literal-payload-encoding) | [`int-literal-overflow-any-type-rejected.slang`](int-literal-overflow-any-type-rejected.slang) |
| A `void`-returning function's terminator is `return_val(void_constant)`, surfacing the unique `void` value the doc lists as `VoidLit`. | functional | [#literals-constant-group](../../../design/ir-reference/values.md#literals-constant-group) | [`return-val-void-constant.slang`](return-val-void-constant.slang) |
| A module-scope `static const T K = value;` declaration lowers to `globalConstant(<value>)` in the IR. | functional | [#memory](../../../design/ir-reference/values.md#memory) | [`memory-global-constant.slang`](memory-global-constant.slang) |
| Boundary: `Optional<int> o = none;` (bare `none` literal at the construction site) lowers to `makeOptionalNone` — the empty-side edge of the Optional value space. | boundary | [#result-optional-conditional-helpers](../../../design/ir-reference/values.md#result-optional-conditional-helpers) | [`optional-always-none.slang`](optional-always-none.slang) |
| Boundary: a function that unconditionally returns `Optional<int>` from a value (no `none` branch) surfaces `makeOptionalValue(%x)` exactly once — the value-side edge of the Optional value space. | boundary | [#result-optional-conditional-helpers](../../../design/ir-reference/values.md#result-optional-conditional-helpers) | [`optional-always-value.slang`](optional-always-value.slang) |
| `Optional<T>` constructors (`return x;` and `return none;`) lower to `makeOptionalValue` / `makeOptionalNone`, and accessors `o.hasValue` / `o.value` lower to `optionalHasValue` / `getOptionalValue`. | functional | [#result-optional-conditional-helpers](../../../design/ir-reference/values.md#result-optional-conditional-helpers) | [`optional-make-has-value.slang`](optional-make-has-value.slang) |
| `Result<T, E>` helpers are observable through Slang's throwing-function surface: a `throws` function lowers `return x;` to `makeResultValue(x)` and `throw e;` to `makeResultError(e)`, while a `try` / `catch` site in the caller lowers to `isResultError`, `getResultValue`, and `getResultError` accessors. | functional | [#result-optional-conditional-helpers](../../../design/ir-reference/values.md#result-optional-conditional-helpers) | [`result-make-and-accessors.slang`](result-make-and-accessors.slang) |
| Boundary: `select(c, 1, 0)` with literal-integer true/false arms lowers to `select(%c, 1 : Int, 0 : Int)` with the BoolLit-equivalent literal payloads on the result operands. | boundary | [#select](../../../design/ir-reference/values.md#select) | [`select-true-literal-bool.slang`](select-true-literal-bool.slang) |
| Expansion: `select(c, vec3, vec3)` with vector operands lowers to a single `select(%c, %a, %b)` with `Vec(Float, 3)` result — verifies the opcode handles aggregate operand pairs. | expansion | [#select](../../../design/ir-reference/values.md#select) | [`select-vector-float3-arms.slang`](select-vector-float3-arms.slang) |
| Expansion: `select` with widest-rank float arms lowers to `select(%c, %a, %b)` with `Double` result. | expansion | [#select](../../../design/ir-reference/values.md#select) | [`select-double-arms.slang`](select-double-arms.slang) |
| Expansion: `select` with widest-rank integer arms lowers to `select(%c, %a, %b)` with `Int64` result. | expansion | [#select](../../../design/ir-reference/values.md#select) | [`select-int64-arms.slang`](select-int64-arms.slang) |
| The `select(condition, trueValue, falseValue)` builtin lowers to the branch-free `select` IR opcode. | functional | [#select](../../../design/ir-reference/values.md#select) | [`select-builtin.slang`](select-builtin.slang) |
| A multi-component swizzle (`v.xyz`) lowers to a `swizzle` opcode taking the source vector and one literal index per output lane. | functional | [#swizzle-swizzleset-swizzledstore](../../../design/ir-reference/values.md#swizzle-swizzleset-swizzledstore) | [`swizzle-multi-component.slang`](swizzle-multi-component.slang) |
| A multi-component vector swizzle (`v.xyz`) lowers to a recognizable `.x` / `.y` / `.z` member-access form on every text-emit target. | functional | [#swizzle-swizzleset-swizzledstore](../../../design/ir-reference/values.md#swizzle-swizzleset-swizzledstore) | [`swizzle-emit-multi-target.slang`](swizzle-emit-multi-target.slang) |
| A swizzle in lvalue position (`dst.xy = ...`) lowers to `swizzledStore` mutating memory in place. | functional | [#swizzle-swizzleset-swizzledstore](../../../design/ir-reference/values.md#swizzle-swizzleset-swizzledstore) | [`swizzle-store-lvalue.slang`](swizzle-store-lvalue.slang) |
| Boundary: M=4 swizzle from an N=2 source (`vec2.xxxy`) lowers to `swizzle(%v, 0, 0, 0, 1)` — M > N, mixed-repeat indices. | boundary | [#swizzle-swizzleset-swizzledstore](../../../design/ir-reference/values.md#swizzle-swizzleset-swizzledstore) | [`swizzle-mixed-xxxy-from-vec2.slang`](swizzle-mixed-xxxy-from-vec2.slang) |
| Boundary: full-length swizzle `.xyzw` on a `float4` lowers to `swizzle(%v, 0, 1, 2, 3)` — the M=N edge of the swizzle width. | boundary | [#swizzle-swizzleset-swizzledstore](../../../design/ir-reference/values.md#swizzle-swizzleset-swizzledstore) | [`swizzle-full-length-xyzw.slang`](swizzle-full-length-xyzw.slang) |
| Boundary: repeat-component swizzle (`v.xxxx`) lowers to `swizzle(%v, 0, 0, 0, 0)` — the same literal index repeated four times, exercising the duplicate-lane case of the doc's "M elements" claim. | boundary | [#swizzle-swizzleset-swizzledstore](../../../design/ir-reference/values.md#swizzle-swizzleset-swizzledstore) | [`swizzle-repeat-component-xxxx.slang`](swizzle-repeat-component-xxxx.slang) |
| Boundary: single-component swizzle from a `float4` (`v.x`) lowers to `swizzle(%v, 0 : Int)` with exactly one literal index — the M=1 edge of the doc's "M elements from an N-vector" claim. | boundary | [#swizzle-swizzleset-swizzledstore](../../../design/ir-reference/values.md#swizzle-swizzleset-swizzledstore) | [`swizzle-single-component-from-vec4.slang`](swizzle-single-component-from-vec4.slang) |
| Negative boundary: accessing the `.w` component of a `float3` (one past the N=3 edge) is rejected with "'w' is not a member of 'vector<float,3>'." — confirms the index-range check at every documented vector width. | negative | [#swizzle-swizzleset-swizzledstore](../../../design/ir-reference/values.md#swizzle-swizzleset-swizzledstore) | [`swizzle-w-on-vec3-rejected.slang`](swizzle-w-on-vec3-rejected.slang) |
| Negative boundary: accessing the `.z` component of a `float2` (out of the documented N-vector range) is rejected by semantic check with "'z' is not a member of 'vector<float,2>'." — no swizzle opcode is produced. | negative | [#swizzle-swizzleset-swizzledstore](../../../design/ir-reference/values.md#swizzle-swizzleset-swizzledstore) | [`swizzle-z-on-vec2-rejected.slang`](swizzle-z-on-vec2-rejected.slang) |


## Untested claims
| Claim | Reason | Anchor | Why untested |
| --- | --- | --- | --- |
| The **C++ wrapper struct** identity for each opcode (e.g. that `add` is `IRAdd` in C++, `boolConst` is `BoolLit`) — internal API visible only through `<inst>->getOp()` / `as<IRBoolLit>()`. | (unclassified) | [#add](../../../design/ir-reference/values.md#add) | Reason and explanation to be refined by the next regeneration. |
| **`alloca`** — no documented portable Slang surface produces it at LOWER-TO-IR. Runtime-size arrays use a different lowering on most targets. | (unclassified) | [#alloca](../../../design/ir-reference/values.md#alloca) | Reason and explanation to be refined by the next regeneration. |
| **`CastEnumToInt`, `CastIntToEnum`, `EnumCast`** — the doc lists them but does not name which surface produces which (Slang's enum-to-int may be implicit in arithmetic context, blurring the per-opcode boundary). | (unclassified) | [#castenumtoint](../../../design/ir-reference/values.md#castenumtoint) | Reason and explanation to be refined by the next regeneration. |
| **`CUDA_LDG`** — emitted by the CUDA backend's read-only buffer lowering, not by AST-to-IR lowering. The cross-cutting bundle notes the `__ldg` factoring as a CUDA emit consequence. | (unclassified) | [#cudaldg](../../../design/ir-reference/values.md#cudaldg) | Reason and explanation to be refined by the next regeneration. |
| **`extractTaggedUnionTag`/`extractTaggedUnionPayload`** — the doc itself cross-references `generics-and-existentials.md`; produced by existential elimination. | (unclassified) | [#extracttaggeduniontag](../../../design/ir-reference/values.md#extracttaggeduniontag) | Reason and explanation to be refined by the next regeneration. |
| **`LoadFromUninitializedMemory`** — same as `Poison`; the doc describes its semantics ("like LLVM's `freeze(undef)`") but no surface in the doc produces it at LOWER-TO-IR. | (unclassified) | [#loadfromuninitializedmemory](../../../design/ir-reference/values.md#loadfromuninitializedmemory) | Reason and explanation to be refined by the next regeneration. |
| **`makeMatrixFromScalar`, `MakeVectorFromScalar`, `makeArrayFromElement`** — implicit lowerings whose surface is not documented. `float3(x)` may or may not produce them; the observed lowering produces `makeVector(x, x, x)` instead. | (unclassified) | [#makematrixfromscalar](../../../design/ir-reference/values.md#makematrixfromscalar) | Reason and explanation to be refined by the next regeneration. |
| **`makeUInt64`** — produced during emit / late lowering, not at LOWER-TO-IR. | (unclassified) | [#makeuint64](../../../design/ir-reference/values.md#makeuint64) | Reason and explanation to be refined by the next regeneration. |
| **The `_debugUID`/`m_op` packed bit layout** — internal to `IRInst::m_op`. | (unclassified) | [#mop](../../../design/ir-reference/values.md#mop) | Reason and explanation to be refined by the next regeneration. |
| **`Poison`** as an active operand — the LOWER-TO-IR dump shows `Poison` only as a top-level sigil declaration, not as an active operand of any user instruction. A reading-an-uninitialized-local diagnostic is a frontend check, not a positive observation of an IR opcode. | (unclassified) | [#poison](../../../design/ir-reference/values.md#poison) | Reason and explanation to be refined by the next regeneration. |
| The **`IRBuilder` emitter** for each opcode (`emitAdd`, `emitLoad`, `emitMakeStruct`, ...) — internal C++ API. | needs-unit-test | [#irbuilder](../../../design/ir-reference/values.md#irbuilder) | No slangc CLI surface reaches this. A C++ unit test in `tools/slang-unit-test/` could exercise the relevant compiler internals directly. |
| **`makeString`, `getNativeStr`, `getNativePtr`, `getManagedPtrWriteRef`, `ManagedPtrAttach`, `ManagedPtrDetach`, `allocObj`** — host-side or COM-pointer machinery, not exercisable from a shader. | needs-unit-test | [#makestring](../../../design/ir-reference/values.md#makestring) | No slangc CLI surface reaches this. A C++ unit test in `tools/slang-unit-test/` could exercise the relevant compiler internals directly. |
| **`Constexpr*` family** (`constexprAdd`, `constexprMul`, ..., `constexprCastEnumToInt`) — produced by the IR's compile-time integer evaluator (`IntVal` lowering), not by AST-to-IR. | compile-time-toggle | [#constexpradd](../../../design/ir-reference/values.md#constexpradd) | Preprocessor define or build-time flag baked into the binary; not observable at runtime. |
| **Hoistable instruction deduplication** — observable only by comparing `IRInst*` identity, not visible in the dump. | implementation-detail | (unspecified) | Internal compiler choice (pass ordering, hoistability decisions, deduplication) with no test-directive that reveals it. |
| **Hoistability flags** (`H` in the doc's tables) — the IR dump shows the post-hoist result, not the decision. Two identical `IntLit 42` payloads collapsing to a single operand is observable in the dump's textual output, but the *reason* (hoisting via `IRBuilder` deduplication) is an internal mechanism. | implementation-detail | [#irbuilder](../../../design/ir-reference/values.md#irbuilder) | Internal compiler choice (pass ordering, hoistability decisions, deduplication) with no test-directive that reveals it. |
| **`copyLogical`, `assumeAddress`, `getAddr`, `getOffsetPtr`, `swizzleSet`, `matrixSwizzleStore`, `updateElement`** — "(synthesized)" per the doc; no portable Slang surface produces them at LOWER-TO-IR. | link-stage-only | [#copylogical](../../../design/ir-reference/values.md#copylogical) | Synthesized at a later IR pass than this bundle's `pipeline_stage` observes; the test belongs in the bundle whose pipeline stage matches. |
| **`makeConditionalValue`/`getConditionalValue`** — "(synthesized)" per the doc; no portable surface. | link-stage-only | [#makeconditionalvalue](../../../design/ir-reference/values.md#makeconditionalvalue) | Synthesized at a later IR pass than this bundle's `pipeline_stage` observes; the test belongs in the bundle whose pipeline stage matches. |
| **`makeTargetTuple`, `getTargetTupleElement`** — target-keyed tuple values used by `targetSwitch`; "(synthesized)" per the doc. | link-stage-only | [#maketargettuple](../../../design/ir-reference/values.md#maketargettuple) | Synthesized at a later IR pass than this bundle's `pipeline_stage` observes; the test belongs in the bundle whose pipeline stage matches. |
| **`ReinterpretOptional`, `unmodified`, `outImplicitCast`, `inOutImplicitCast`, `BuiltinCast`, `PtrCast`, `CastPtrToBool`, `CastPtrToInt`, `CastIntToPtr`, `CastUInt2ToDescriptorHandle`, `CastDescriptorHandleToUInt2`** — "(synthesized)" or host-side; no portable Slang surface in the doc names them. | link-stage-only | [#reinterpretoptional](../../../design/ir-reference/values.md#reinterpretoptional) | Synthesized at a later IR pass than this bundle's `pipeline_stage` observes; the test belongs in the bundle whose pipeline stage matches. |
| **`SumVectorElements`, `SumMatrixElements`, `matrixReshape`, `vectorReshape`** — all "(synthesized)" per the doc. | link-stage-only | [#sumvectorelements](../../../design/ir-reference/values.md#sumvectorelements) | Synthesized at a later IR pass than this bundle's `pipeline_stage` observes; the test belongs in the bundle whose pipeline stage matches. |


## Doc gaps observed
| Anchor | Kind | Gap | Suggested addition |
| --- | --- | --- | --- |
| [#logicaland](../../../design/ir-reference/values.md#logicaland) | drift-from-source | The doc's Logical table lists `logicalAnd` (`InfixExpr` `&&`) and `logicalOr` (`InfixExpr` `\|\|`), but the observed lowering of the short-circuit operators is a pair of `ifElse` terminator blocks joining at a `param` — the same shape the doc describes for the ternary `?:`. No portable surface in this bundle reliably produces a `logicalAnd` or `logicalOr` IR opcode on the LOWER-TO-IR stage. | Either the lowering should emit these opcodes (and the doc would be honoured) or the doc should be updated to note that the opcodes are reserved for future use / produced by an IR pass rather than lowering. |
| [#lowers-from-selectexpr-and-ternary-cond-a-b](../../../design/ir-reference/values.md#lowers-from-selectexpr-and-ternary-cond-a-b) | drift-from-source | The doc's `select` notable-opcode note says `select` "lowers from `SelectExpr` and ternary `cond ? a : b`", but the observed lowering of the ternary uses short-circuit `ifElse` + block `param`, not `select`. Only the `select(...)` builtin reliably surfaces the `select` opcode. | The doc should narrow the "AST origin" cell to "`SelectExpr` / `select(...)` builtin". |
| [#makestructexpr-aggregate-initializer-lowering](../../../design/ir-reference/values.md#makestructexpr-aggregate-initializer-lowering) | undocumented-behavior | The Aggregate constructors table lists `makeStruct` with AST origin "`MakeStructExpr`, aggregate-initializer lowering", but Slang's natural aggregate-initializer surface (`Foo f = { a, b, c };` or `Foo f = Foo();`) lowers to a synthesized `call %Foox5Fx24init(...)` rather than a `makeStruct(...)` IR opcode on the LOWER-TO-IR stage. | The doc should either describe the synthesized initializer path or name a surface that reliably surfaces `makeStruct`. |
| [#makearrayexpr](../../../design/ir-reference/values.md#makearrayexpr) | undocumented-behavior | The Aggregate constructors table lists `makeArray` with AST origin "`MakeArrayExpr`". The observed lowering of an array initializer (`int arr[3] = { a, b, c };`) streams the components straight into per-index `store` instructions on a local `var`, with no `makeArray` opcode in the dump. The same comment applies as for `makeStruct`. |  |
| [#memberexpr-on-a-tuple](../../../design/ir-reference/values.md#memberexpr-on-a-tuple) | undocumented-behavior | The Aggregate constructors table lists `getTupleElement` for "`MemberExpr` on a tuple". The observed lowering of `t._0` (where `t` is a `Tuple<int, float>`) is a `swizzle(%t, 0 : Int)` — using the same swizzle opcode that handles vector lanes — not `getTupleElement`. | The doc should clarify which surface produces `getTupleElement`. |
| [#function-arg-lowering-for-out-inout-parameters](../../../design/ir-reference/values.md#function-arg-lowering-for-out-inout-parameters) | ambiguous-claim | The Conversions table lists `outImplicitCast` and `inOutImplicitCast` for "Function-arg lowering for `out` / `inout` parameters". The observed lowering does not emit either opcode when the caller's argument type matches the parameter; an implicit-cast at the out-parameter boundary is rejected by semantic check (error `E30047` "argument must be l-value") rather than producing the cast. The opcodes appear to be reserved for an IR pass; a surface that produces them at LOWER-TO-IR is unclear from the doc. |  |
| [#synthesized](../../../design/ir-reference/values.md#synthesized) | missing-surface | The Conversions table lists `BuiltinCast`, `unmodified`, `reinterpret`, `ReinterpretOptional` and `PtrCast` with various "synthesized" or `BitCastExpr`-style origins, but does not name a portable shader-language surface that produces each. A one-sentence "surface" cell per row would let the agent test them. |  |
| [#castenumtoint](../../../design/ir-reference/values.md#castenumtoint) | undocumented-behavior | The Conversions table lists `CastEnumToInt`, `CastIntToEnum`, `EnumCast`. Slang enums do exist as a surface, but the doc does not name which assignment / cast triggers which of the three opcodes (Slang's `enum`-to-`int` conversion is typically implicit on arithmetic; explicit `int(myEnum)` is the natural surface for `CastEnumToInt`, but `EnumCast` between two distinct enums of the same underlying type has no documented surface). |  |
| [#defaultconstructexpr-and-synthesized-in-ir-passes](../../../design/ir-reference/values.md#defaultconstructexpr-and-synthesized-in-ir-passes) | undocumented-behavior | The Memory table lists `defaultConstruct` with AST origin "`DefaultConstructExpr` and synthesized in IR passes". Observed lowering of `Foo f = Foo();` or `Foo f = {};` produces a synthesized `call %Foox5Fx24init(0 : Int, 0 : Float)` — that is, the `$init` function call with zero literals — not a `defaultConstruct` opcode on the LOWER-TO-IR stage. | The doc should either name a surface that reliably produces `defaultConstruct` at lowering, or move the opcode to a list of IR-pass-introduced opcodes. |
| [#dynamically-sized-stack-allocation](../../../design/ir-reference/values.md#dynamically-sized-stack-allocation) | undocumented-behavior | The Memory table lists `alloca` for "Dynamically-sized stack allocation" with AST origin "`AllocaExpr` / dynamic-stack lowering". Slang's surface for dynamic-sized stack allocation is not documented; on most targets a runtime-size array uses a different lowering path entirely. |  |
| [#constexpradd](../../../design/ir-reference/values.md#constexpradd) | undocumented-behavior | The Constexpr arithmetic and casts table lists 28 opcodes (`constexprAdd`, `constexprMul`, ..., `constexprCastEnumToInt`) with the note "Hoistable variants ... used to lower compile-time integer expressions (`IntVal` subclasses such as `PolynomialIntVal`) so that identical compile-time values dedupe." These are produced by the IR's compile-time integer evaluator, not by AST-to-IR lowering. | The doc should clarify that they are not part of the LOWER-TO-IR catalog and direct the reader to the `pipeline/05-ir-passes` bundle (where they belong if anywhere). |
| [#constructs-a-64-bit-value-from-two-32-bit-halves](../../../design/ir-reference/values.md#constructs-a-64-bit-value-from-two-32-bit-halves) | undocumented-behavior | The `MakeUInt64` notable-opcode note says it "constructs a 64-bit value from two 32-bit halves" because "several targets do not have a direct `uint64` literal form". Observed lowering of a `uint64_t x = 0xDEADBEEF12345678uL;` and of `uint64_t(hi) << 32 \| uint64_t(lo)` compositions does not surface `makeUInt64` at LOWER-TO-IR — it appears to be produced later, during emit. |  |
| [#synthesized](../../../design/ir-reference/values.md#synthesized) | undocumented-behavior | The Strings and native pointers / Object and CUDA helpers families list `makeString`, `getNativeStr`, `getNativePtr`, `getManagedPtrWriteRef`, `ManagedPtrAttach`, `ManagedPtrDetach`, `allocObj`, `CUDA_LDG` — all marked "(synthesized)" or host-side. No portable shader-language surface in the doc produces them; per-opcode tests cannot be anchored. |  |
| [#asuint](../../../design/ir-reference/values.md#asuint) | undocumented-behavior | The Conversions table does **not** mention the HLSL-compatible reinterpret builtins `asuint`/`asint`/`asfloat`/`asdouble`. Probing reveals that on the LOWER-TO-IR stage these surface as `call %asuint(...)` etc. with `targetIntrinsic` decoration; they are not lowered to the `bitCast` opcode at lowering time. | The doc should either name the surface that lowers these intrinsics to `bitCast` (presumably an emit-side rewrite) or describe them as call-shaped throughout the value pipeline. |
| [#makematrixfromscalar](../../../design/ir-reference/values.md#makematrixfromscalar) | undocumented-behavior | The Aggregate constructors family lists `makeMatrixFromScalar`, `MakeVectorFromScalar`, `makeArrayFromElement`, `makeTargetTuple`, `matrixReshape`, `vectorReshape`, `SumVectorElements`, `SumMatrixElements`, `updateElement` — all with synthesized / implicit origins. | The doc should name the surface that produces each (e.g. is `float3(x)` the surface for `MakeVectorFromScalar` or is it lowered as `makeVector(x, x, x)`?). |
| [#makecoopmatrixfromscalar](../../../design/ir-reference/values.md#makecoopmatrixfromscalar) | drift-from-source | The Aggregate constructors table lists `makeCoopMatrixFromScalar` as "(synthesized)". The IR builder's `emitDefaultConstruct(CoopMatrixType)` is the only producer (`source/slang/slang-ir.cpp` ~L4105), but the `CoopMat` type in `hlsl.meta.slang` carries user-defined `__init()` / `__init(T t)` / `__init(int i)` constructors that short-circuit the default-construct path: probes of `CoopMat<T,...>()`, `CoopMat<T,...>(fa)`, `CoopMat<T,...> arr[2]`, and struct-of-`CoopMat` aggregate-initializers all lower to a `call %linalg.CoopMat.$init(...)` (which itself contains `LoadFromUninitializedMemory`) — no `makeCoopMatrixFromScalar` opcode appears at LOWER-TO-IR. | The doc should either name a portable Slang surface that bypasses the user `__init` to surface `makeCoopMatrixFromScalar`, or move the opcode to a list of opcodes only the IR builder produces internally (not part of the LOWER-TO-IR catalog). |
| [#makeresultvalue](../../../design/ir-reference/values.md#makeresultvalue) | drift-from-source | The Result / Optional / Conditional helpers table lists `makeResultValue`/`makeResultError`/`isResultError`/`getResultValue`/`getResultError` with AST origin "`Result<T, E>::makeValue` lowering" / "`Result<T, E>::isError`" / etc., suggesting a method-call surface on `Result<T, E>`. The actually observed surface is the error-handling syntax (`throws`, `throw`, `try`, `catch`): the LOWER-TO-IR error-handling pass rewrites `return val;` in a `throws` function to `makeResultValue(val)`, `throw e;` to `makeResultError(e)`, and a `try f()` call site introduces `isResultError` / `getResultValue` / `getResultError`. A direct `Result::makeValue(x)` member-call surface on `Result<T, E>` is not exposed in `core.meta.slang`. | The doc should narrow the "AST origin" cell to "synthesized by the error-handling lowering pass for `throws` / `throw` / `try` / `catch`" (and cross-reference the error-handling docs). |
| [#synthesized](../../../design/ir-reference/values.md#synthesized) | undocumented-behavior | The Undefined and default-construct family lists `Poison` and `LoadFromUninitializedMemory` as opcodes "synthesized". The observed IR dump shows a single `Poison` declaration at the top of the LOWER-TO-IR stage (as a sigil), but no surface in the doc produces it as an active operand. | The doc should clarify whether the top-of-dump `Poison` line is the entire surface or whether some construct yields an active `Poison`-typed value. |


## Housekeeping
- `_probe_diag.slang` is a real stress test (two `makeVector` calls
  feeding a vector `add`); the underscore-prefixed filename is a
  legacy artifact of the expansion pass and should be renamed to
  something like `makeVector-pair-feeding-add-stress.slang` on the
  next regeneration. The lint accepts it as-is.
