---
generated: true
model: claude-opus-4.8
generated_at: 2026-06-29T15:32:39Z
source_commit: c21ead2690b5b9fa4a582f6b51a4cd5fb34d29d8
watched_paths_digest: e27926ca78614bca20d3b57a5268d5884f642e04074ed66afbbed157eadbfdd7
warning: "Auto-generated. May drift from source. Do not edit by hand."
---

# Structure

This page is the per-opcode reference for IR opcodes that organize
the module: the module itself, functions and generics, global
variables and constants, struct / class / interface containers, and
the witness-table machinery that connects them.

The intended reader is a compiler engineer reading IR around a
function or type definition, or writing an IR pass that walks the
top-level structure of a module.

## Source

The structural opcodes live in two clusters of
[slang-ir-insts.lua](../../../../source/slang/slang-ir-insts.lua):

- The `GlobalValueWithCode` group (around lines 797-826) plus the
  `key` / `StructKey`, `builtinRequirementKey`, `witness_table`,
  `thisTypeWitness`, `TypeEqualityWitness`,
  `global_hashed_string_literals`, `module`, and `SymbolAlias`
  opcodes occupy lines ~797-863 (and overlap conceptually with the
  type-side `StructType` / `InterfaceType` / `ClassType` declarations
  earlier in the file).
- The `param`, `field`, `call`, `witness_table_entry`,
  `interface_req_entry` opcodes, plus the structural body of a
  function, occupy lines ~1060-1075.

C++ wrappers are declared in
[slang-ir-insts.h](../../../../source/slang/slang-ir-insts.h). The
infrastructure (`IRInst`, `IRBuilder::createFunc`,
`IRBuilder::createGeneric`, `IRBuilder::createModule`, ...) is in
[slang-ir.h](../../../../source/slang/slang-ir.h) and
[slang-ir.cpp](../../../../source/slang/slang-ir.cpp).

Lowering from the AST is in
[slang-lower-to-ir.cpp](../../../../source/slang/slang-lower-to-ir.cpp):
`lowerFuncDecl` (functions), `visitGenericDecl` (generics),
`visitAggTypeDecl` (struct / class types, via `createStructType`),
`visitInterfaceDecl` (interface types), `visitInheritanceDecl`
(witness tables), and `lowerGlobalVarDecl` (global variables). The
module itself is created in `generateIRForTranslationUnit`, whose
member declarations are lowered through `ensureAllDeclsRec`.

Requirement keys are produced by `getInterfaceRequirementKey`, which
returns an `IRInst*` (not strictly an `IRStructKey*`): an ordinary
requirement lowers to a `StructKey`, but a recognized built-in
requirement lowers to the hoistable `BuiltinRequirementKey` instead.

## Family hierarchy

```mermaid
flowchart TD
  IRInst --> Structure
  Structure --> moduleNode["module / ModuleInst"]
  Structure --> GlobalValueWithCode
  Structure --> GlobalState["global_param / globalConstant / global_generic_param / global_hashed_string_literals"]
  Structure --> StructInternals["StructType internals"]
  Structure --> InterfaceInternals["InterfaceType internals"]
  Structure --> WitnessTables
  Structure --> SymbolAliasNode["SymbolAlias"]
  GlobalValueWithCode --> GlobalValueWithParams
  GlobalValueWithCode --> global_var
  GlobalValueWithParams --> funcNode[func]
  GlobalValueWithParams --> genericNode[generic]
  StructInternals --> structFieldNode["field / StructField"]
  StructInternals --> structKeyNode["key / StructKey"]
  StructInternals --> builtinReqKeyNode["builtinRequirementKey / BuiltinRequirementKey"]
  StructInternals --> indexedFieldKeyNode[indexedFieldKey]
  InterfaceInternals --> interfaceReqEntryNode["interface_req_entry / InterfaceRequirementEntry"]
  WitnessTables --> witness_tableNode[witness_table]
  WitnessTables --> witness_table_entryNode[witness_table_entry]
  WitnessTables --> thisTypeWitnessNode[thisTypeWitness]
  WitnessTables --> TypeEqualityWitnessNode[TypeEqualityWitness]
```

## Opcodes

### Module

| Opcode | C++ wrapper | Operands | Flags | AST origin | Summary |
| --- | --- | --- | --- | --- | --- |
| `module` | `ModuleInst` | (variadic) | P | `ModuleDecl` lowering in `slang-lower-to-ir.cpp` | Top-level container; children are every other top-level instruction. |

### Functions and generics

| Opcode | C++ wrapper | Operands | Flags | AST origin | Summary |
| --- | --- | --- | --- | --- | --- |
| `func` | `IRFunc` | (variadic) | P | `FuncDecl`, `AccessorDecl`, lambda lowering in `slang-lower-to-ir.cpp` | Function; children are blocks. The first block's `Param`s are the function parameters; the function signature is on the `func` itself via its type. |
| `generic` | `IRGeneric` | (variadic) | P | `GenericDecl` in `slang-lower-to-ir.cpp` | Function-shaped instruction whose single block computes a type-level value; ends with `return_val` / `IRReturn`. |
| `param` | `IRParam` | (variadic) | | `ParamDecl`, block-parameter introduction | Function or block parameter declared inside a `func`/`generic` or `block` parent. Documented in detail in [control-flow.md](control-flow.md). |
| `call` | `IRCall` | `callee, args...` | | `InvokeExpr` in `slang-lower-to-ir.cpp` | Calls `callee` with the remaining operands as arguments; result type is the callee's return type. |

### Global state

| Opcode | C++ wrapper | Operands | Flags | AST origin | Summary |
| --- | --- | --- | --- | --- | --- |
| `global_var` | `IRGlobalVar` | (variadic) | G | `VarDecl` at module scope in `slang-lower-to-ir.cpp` | Module-scope mutable variable. |
| `global_param` | `IRGlobalParam` | (variadic) | G | Entry-point and module-scope parameter declarations | Module-scope parameter (shader uniform, push-constant, ...). |
| `globalConstant` | `IRGlobalConstant` | (variadic) | G | `VarDecl` with `const`/`static const` at module scope | Module-scope constant value. |
| `global_generic_param` | `IRGlobalGenericParam` | — | G | `GenericTypeParamDecl` at module scope | Declares a generic parameter at module level. |
| `global_hashed_string_literals` | `IRGlobalHashedStringLiterals` | (variadic) | | (synthesized) | Container for the module's hashed-string-literal pool; a module is expected to hold at most one. |

### Struct internals

The `StructType` *type* opcode is documented as a type in
[types.md](types.md); here we describe its role as a parent
container that owns `field` and `key` children.

| Opcode | C++ wrapper | Operands | Flags | AST origin | Summary |
| --- | --- | --- | --- | --- | --- |
| `struct` (parent) | `IRStructType` | (children: `field`, `key`) | P | `StructDecl` in `slang-lower-to-ir.cpp` | Owns the struct's field and key children. See [types.md](types.md) for its type-side semantics. |
| `class` (parent) | `IRClassType` | (children: `field`, `key`) | P | `ClassDecl` in `slang-lower-to-ir.cpp` | Owns the class's field and key children; cross-linked to [types.md](types.md). |
| `field` | `StructField` | `key, fieldType` | | (synthesized as part of `StructDecl` lowering) | Declares one named member of a `StructType` parent. |
| `key` | `StructKey` | — | G | Member-name lowering in `slang-lower-to-ir.cpp` | Identity for a field or interface requirement; carries linkage so the field is addressable across compilation units. |
| `builtinRequirementKey` | `BuiltinRequirementKey` | `kindOperand` | H | `getInterfaceRequirementKey` for a `BuiltinRequirementModifier`-tagged requirement | Key for a recognized built-in interface requirement (e.g. an `IDifferentiable` member); deduplicated by construction from its `BuiltinRequirementKind` operand. |
| `indexedFieldKey` | `IRIndexedFieldKey` | `baseType, index` | H | (synthesized) | Synthetic key for the *n*-th field of a tuple-like type when no named key exists. |

### Interface internals

The `InterfaceType` *type* opcode is documented in
[types.md](types.md); here we describe its role as the carrier of
`interface_req_entry` operands.

| Opcode | C++ wrapper | Operands | Flags | AST origin | Summary |
| --- | --- | --- | --- | --- | --- |
| `interface` | `IRInterfaceType` | (operands: `interface_req_entry`) | G | `InterfaceDecl` in `slang-lower-to-ir.cpp` | Interface declaration; its operands are the requirement entries. |
| `interface_req_entry` | `InterfaceRequirementEntry` | `requirementKey, requirementVal` | G | (synthesized as part of `InterfaceDecl` lowering) | One requirement slot of an interface; `requirementKey` is an `IRStructKey` or a hoistable `IRBuiltinRequirementKey`. Cross-link to [generics-and-existentials.md](generics-and-existentials.md). |

### Witness tables and witness facts

`witness_table` and its companion opcodes are also documented from
the dispatch side in
[generics-and-existentials.md](generics-and-existentials.md); the
rows below describe their structural role.

| Opcode | C++ wrapper | Operands | Flags | AST origin | Summary |
| --- | --- | --- | --- | --- | --- |
| `witness_table` | `IRWitnessTable` | `concreteType` (+ children: `witness_table_entry`) | H | `InheritanceDecl` lowering in `slang-lower-to-ir.cpp` | Conformance of `concreteType` (operand 0) to the interface carried in its result type; owns one `witness_table_entry` per requirement. Hoistable so identical conformances dedupe. |
| `witness_table_entry` | `IRWitnessTableEntry` | `requirementKey, satisfyingVal` | | (synthesized) | One row of a `witness_table`. |
| `thisTypeWitness` | `IRThisTypeWitness` | `type` | | (synthesized inside `InterfaceDecl` lowering) | Placeholder witness that `ThisType` implements the enclosing interface; only valid inside an interface definition. |
| `TypeEqualityWitness` | `IRTypeEqualityWitness` | `subType, superType` | H | (synthesized) | Witness certifying two types are equal. |

### Symbol aliasing

| Opcode | C++ wrapper | Operands | Flags | AST origin | Summary |
| --- | --- | --- | --- | --- | --- |
| `SymbolAlias` | `IRSymbolAlias` | `symbol` | | (synthesized as part of linking) | Module-level alias of another symbol under a different mangled name. Must be eliminated by the linker — every use is replaced with the canonical symbol. |

## Notable opcodes

### `func`

`func` is a parent opcode that owns the blocks of a function body
and (via its result type, a `FuncType` instance) carries the
function signature. The first block in the body is the entry
block; its `Param` children are the function parameters in
declaration order. Function-level decorations (`NameHintDecoration`,
`KeepAliveDecoration`, `TargetIntrinsicDecoration`, ...) attach to
the `func` inst itself rather than to its body. After IR passes
have finished, every `func` has a single entry block, exactly the
function's `Param`s as that block's parameters, and only ordinary
`call` and `return_val` plumbing connecting them to the body.

### `generic`

`generic` is structurally the same as `func` — a parent opcode
that owns blocks — but its body is interpreted as type-level
computation. In practice each `generic` holds a single block, and
that block ends with a `return_val` (`IRReturn`) whose operand is
the result of the type-level computation; `findGenericReturnVal`
in [slang-ir.cpp](../../../../source/slang/slang-ir.cpp) reads it
back as the terminator's value. `specialize` (see
[generics-and-existentials.md](generics-and-existentials.md))
applies arguments to a `generic` value; the specialization pass
replaces matched applications with the concrete result of the
generic's `return_val`.

### `module` / `ModuleInst`

`module` is the IR-level root. Every other top-level instruction —
`func`, `generic`, `global_var`, `global_param`, `globalConstant`,
`witness_table`, `StructType`, `InterfaceType`, ... — is a child
of a `module`. The module's decorations carry import / export
information used by the linker; the module is also the unit that
serialization writes and reads (see
[../cross-cutting/serialization.md](../cross-cutting/serialization.md)).

The `IRModule` owning the `module` inst (in
[slang-ir.h](../../../../source/slang/slang-ir.h)) can build a
`ModuleLinkingInfo` acceleration cache (`_getOrCreateLinkingInfo`)
that pre-indexes the module-scope structure the linker repeatedly
scans for: the `global_param` instructions (`getGlobalParams`),
`HLSLExportDecoration` globals, `KnownBuiltinDecoration` globals, and
the single `global_hashed_string_literals` aggregate
(`getGlobalHashedStringLiterals`). The cache assumes the module is
not mutated after it is built; callers that change module-scope state
must `_invalidateLinkingInfo`. The serialized module-version range
this layout participates in is `k_minSupportedModuleVersion` (4) ..
`k_maxSupportedModuleVersion` (22).

### `key` / `StructKey`

`StructKey` is the identity of a struct field or an interface
requirement. Unlike a string name, a `StructKey` is a globally
linkable IR value: two `StructKey` instances for the same source-
level name in two different modules compare equal after linking.
Field access opcodes (`FieldAddress`, `FieldExtract`, see
[values.md](values.md)) use the key as their selector, which
makes structural reorganization (e.g. struct splitting) a
key-rewriting task rather than a string-rewriting task.

### `builtinRequirementKey` / `BuiltinRequirementKey`

`BuiltinRequirementKey` is the requirement-key variant for a
recognized built-in interface requirement — for example the
`Differential` associated type, `dzero`, or `dadd` of
`IDifferentiable`. Unlike a `StructKey`, which is a distinct
`global` symbol per requirement decl unified across modules by its
`key_<mangled>` linkage name, a `BuiltinRequirementKey` is
hoistable: its identity is its single `kindOperand` (an `IRIntLit`
holding a `BuiltinRequirementKind` value), so it is deduplicated by
construction and the same logical built-in requirement always
resolves to one key inst — even across decls and the
precompiled-core-module boundary. `getInterfaceRequirementKey` in
[slang-lower-to-ir.cpp](../../../../source/slang/slang-lower-to-ir.cpp)
emits it via `IRBuilder::getBuiltinRequirementKey` and tags it with
an `IRBuiltinRequirementDecoration` (see
[decorations.md](decorations.md)) so role-scanning consumers (e.g.
autodiff) can find the requirement by role rather than by entry
order. Because either key kind can appear, the `lookupKey` operand
of `lookupWitness`-style dispatch is typed `IRInst`, not
`IRStructKey`.

### `witness_table`

`witness_table` records that one concrete type conforms to one
interface. Operand 0 is the `concreteType` (read back via
`getConcreteType()`); the interface it satisfies is *not* an operand
but is carried in the instruction's result type — a
`WitnessTableType` whose conformance interface is read back via
`getConformanceType()`. Its children are the `witness_table_entry`
instructions, one per interface requirement, that map each
`requirementKey` to the satisfying function or value. The opcode is
hoistable, so the same type-and-interface pair shares a single
witness table across all uses.

### `witness_table_entry` vs `interface_req_entry`

`interface_req_entry` is an operand of an `InterfaceType` and
declares one requirement — the `requirementKey` (a `StructKey`, or
a `BuiltinRequirementKey` for a built-in requirement) plus the
requirement's type (`requirementVal`).
`witness_table_entry` lives inside a `witness_table` parent and
*satisfies* a requirement — pairing the same `requirementKey` with
the concrete implementing function or value. The two opcodes are
the interface-side and implementation-side halves of the same
key-driven dispatch table.

### `SymbolAlias`

`SymbolAlias` records that one symbol should be linked as if it
were another — typically used when a module exports a value
under multiple mangled names. The linking pass walks every
`SymbolAlias`, replaces each use of the alias with a reference to
its `symbol` operand, and then deletes the alias. No
`SymbolAlias` should survive past linking; if one does, downstream
passes will assert.

## See also

- [../cross-cutting/ir-instructions.md](../cross-cutting/ir-instructions.md)
  — schema, op flags (notably `Parent` for `func` / `generic` /
  `module` / `StructType` / `InterfaceType`), and the hoistable /
  global conventions that determine which opcodes here are
  deduplicated.
- [types.md](types.md) — `StructType`, `ClassType`,
  `InterfaceType` as type opcodes (their type-system role
  complements the parent-container role documented here).
- [control-flow.md](control-flow.md) — `block`, `Param`, and the
  terminator family that populate a `func`'s body.
- [generics-and-existentials.md](generics-and-existentials.md) —
  `specialize`, `lookupWitness`, and the existential-extract
  opcodes that consume the witness tables documented here.
- [values.md](values.md) — `FieldAddress`, `FieldExtract`,
  `GetElementPtr`, and other opcodes that consume `StructField`
  and `StructKey`.
- [../pipeline/04-ast-to-ir.md](../pipeline/04-ast-to-ir.md) — how
  declarations lower into `func` / `generic` / `StructType` /
  `InterfaceType` / `witness_table`.
- [../pipeline/05-ir-passes.md](../pipeline/05-ir-passes.md) —
  linking, specialization, and the passes that eliminate
  `SymbolAlias` and inline `generic` bodies.
- [../../../design/decl-refs.md](../../../design/decl-refs.md) —
  rationale for keying members by `StructKey` rather than by name.
- [../glossary.md](../glossary.md) — definitions of `parent
  instruction`, `linkage`, `module`, `witness table`,
  `decl-ref`.
