IR and XIR Pipeline
Two IRs, both starting from AST (src/ast/), feeding into backend codegen:
|
IR (Legacy) |
XIR (Preferred) |
| Location |
src/ir/, include/luisa/ir/ |
src/xir/, include/luisa/xir/ |
| Impl |
Rust (src/rust/) |
Pure C++ |
| Serialization |
ast2json → Rust IR |
xir2json/json2xir (yyjson) |
| SSA |
Yes |
Yes (mem2reg) |
| Status |
Maintained (compat) |
Active development |
| Basic Blocks |
Yes |
Yes |
Pipeline Flow
DSL Tracing (src/dsl/) → AST (src/ast/)
│
┌─────────┴─────────┐
▼ ▼
XIR (ast2xir) IR (ast2ir → JSON → Rust FFI)
│ │
└─────────┬─────────┘
▼
Backend Codegen (src/backends/<name>/)
│
▼
GPU Execution (src/runtime/)
Rust IR path: src/rust/luisa_compute_ir/ does autodiff, DCE, SSA, vectorize.
XIR path: Pure C++ with ast2xir translator, xir2ast round-trip, and optimization passes.
AST → IR Translation (Legacy)
File: src/ir/ast2ir.cpp
AST Function → to_json() → JSON string → Rust FFI → CArc<KernelModule/CallableModule>
FFI: luisa_compute_ir_ast_json_to_ir_kernel(), ..._callable(), ..._type().
Key IR classes (Rust, via C FFI): KernelModule, CallableModule, Node, Instruction (Local, Call, Phi, Loop, If, Switch, RayQuery, AdScope), Type, BasicBlock.
AST → XIR Translation
Files: src/xir/translators/ast2xir.cpp, xir2ast.cpp. AST2XIRContext maps AST variables to XIR Values, tracks break/continue targets, handles autodiff adjoints, caches constants.
Expression Mapping
| AST |
XIR |
UnaryExpr |
ArithmeticOp (UNARY_MINUS, UNARY_BIT_NOT); +x is elided |
BinaryExpr |
ArithmeticOp (BINARY_ADD, etc.); matrix-aware; logic ops cast to bool |
MemberExpr |
EXTRACT/SHUFFLE or GEP |
AccessExpr |
GEP + LOAD |
LiteralExpr |
Constant |
ConstantExpr |
Constant |
RefExpr |
Variable lookup or SpecialRegister |
CallExpr |
CallInst, ArithmeticOp, AtomicOp, Resource*Op, ThreadGroupOp, RayQuery*Op, Assert/Assume/Unreachable/RasterDiscard |
CastExpr |
CastInst (STATIC_CAST, BITWISE_CAST) |
TypeIdExpr/StringIdExpr/FuncRefExpr |
Not implemented |
Statement Mapping
| AST |
XIR |
IfStmt |
IfInst + true/false/merge |
SwitchStmt |
SwitchInst + case/default/merge |
ForStmt |
LoopInst (prepare/body/update/merge) |
LoopStmt |
SimpleLoopInst (do-while) |
BreakStmt |
BreakInst |
ContinueStmt |
ContinueInst |
ReturnStmt |
ReturnInst |
AssignStmt |
StoreInst |
ExprStmt |
Expression (terminator-aware, e.g. Unreachable) |
AutoDiffStmt |
AutodiffScopeInst |
RayQueryStmt |
RayQueryLoopInst + RayQueryDispatchInst |
PrintStmt |
PrintInst |
DebugBreakStmt |
DebugBreakInst |
CommentStmt |
Collected as comment metadata on following instruction |
XIR Core Architecture
Value Hierarchy
Value
├── GlobalValue
│ ├── Function → FunctionDefinition → KernelFunction (entry+block size), CallableFunction, ExternalFunction
│ ├── Constant (literals)
│ ├── Undefined
│ └── SpecialRegister (SPR_ThreadID, SPR_BlockID, SPR_DispatchID, SPR_WarpLaneID, SPR_KernelID, SPR_BlockSize, SPR_WarpSize, SPR_DispatchSize, SPR_ObjectID, SPR_Barycentrics, ...)
├── FunctionScopeValue
│ ├── BasicBlock (instruction container)
│ └── Argument → ValueArgument / ReferenceArgument / ResourceArgument
└── BlockScopeValue → Instruction
├── TerminatorInstruction: BranchInst, ConditionalBranchInst, IfInst, SwitchInst,
│ LoopInst, SimpleLoopInst, ReturnInst, BreakInst, ContinueInst, UnreachableInst, RasterDiscardInst
└── Non-terminator instructions
Key Classes
- Module (
include/luisa/xir/module.h): container for globals, unique constants via hash
- Function / FunctionDefinition (
include/luisa/xir/function.h): ArgumentList, BasicBlockList, body_block(), traversal orders (PRE_ORDER, POST_ORDER, ...). Traversal: traverse_basic_blocks(), traverse_instructions()
- Argument (
include/luisa/xir/argument.h): ValueArgument, ReferenceArgument, ResourceArgument
- BasicBlock (
include/luisa/xir/basic_block.h): InstructionList, is_terminated(), terminator(), traverse_predecessors(), traverse_successors()
- Instruction (
include/luisa/xir/instruction.h): DerivedInstruction<>, is_terminator(), control_flow_merge(), clone(), intrinsic_identifier()
- Value & Use (
include/luisa/xir/value.h, use.h): SSA UseList, replace_all_uses_with(), is_lvalue() for alloca/gep/reference args
XIR Instruction Set
Control Flow
| Instruction |
Blocks |
IfInst |
true, false, merge |
SwitchInst |
cases, default, merge |
LoopInst |
prepare, body, update, merge |
SimpleLoopInst |
body, merge |
BranchInst |
target |
ConditionalBranchInst |
true, false |
ReturnInst |
— |
BreakInst / ContinueInst |
target (lowered before codegen) |
UnreachableInst |
— |
Memory
AllocaInst (LOCAL/SHARED), LoadInst, StoreInst, GEPInst
SSA
PhiInst — (block, value) pairs
Call / Cast
CallInst (user/external functions), CastInst (STATIC_CAST, BITWISE_CAST)
Arithmetic (ArithmeticOp)
- Unary: UNARY_MINUS, UNARY_BIT_NOT
- Binary: ADD, SUB, MUL, DIV, MOD, BIT_AND, BIT_OR, BIT_XOR, SHIFT_LEFT/RIGHT, ROTATE_LEFT/RIGHT, comparisons
- Logic/Selection: ALL, ANY, SELECT, STEP
- Math: ABS, MIN, MAX, CLAMP, SATURATE, LERP, SMOOTHSTEP, trig (SIN/COS/TAN/ASIN/ACOS/ATAN/ATAN2 and hyperbolic variants), exp/log families (EXP/EXP2/EXP10/LOG/LOG2/LOG10), POW, SQRT, RSQRT, FMA, COPYSIGN, CLZ, CTZ, POPCOUNT, REVERSE, ISINF, ISNAN, CEIL, FLOOR, FRACT, TRUNC, ROUND, RINT
- Vector: DOT, CROSS, LENGTH, LENGTH_SQUARED, NORMALIZE, FACEFORWARD, REFLECT, REDUCE_SUM/PRODUCT/MIN/MAX, OUTER_PRODUCT
- Matrix: MATRIX_COMP_NEG/ADD/SUB/MUL/DIV, MATRIX_LINALG_MUL, MATRIX_DETERMINANT, MATRIX_TRANSPOSE, MATRIX_INVERSE
- Aggregate: AGGREGATE, SHUFFLE, EXTRACT, INSERT
Resource
ResourceQueryOp, ResourceReadOp, ResourceWriteOp — buffer/texture/bindless ops, ray-tracing queries, indirect dispatch, device-address loads/stores
Atomic (AtomicOp)
EXCHANGE, COMPARE_EXCHANGE, FETCH_ADD/SUB/AND/OR/XOR/MIN/MAX
Thread Group & Ray Query & Autodiff
ThreadGroupOp (warp, sync, SER, quad derivatives), RayQueryLoopInst, RayQueryDispatchInst, RayQueryObjectReadInst, RayQueryObjectWriteInst, RayQueryPipelineInst, AutodiffScopeInst, AutodiffIntrinsicInst (requires_gradient, gradient, gradient_marker, accumulate_gradient, backward, detach)
Debug / Utility
PrintInst, ClockInst, DebugBreakInst, AssertInst, AssumeInst, OutlineInst, RasterDiscardInst
XIR Optimization Passes
Location: src/xir/passes/ (headers in include/luisa/xir/passes/)
Core / SSA / CFG
| Pass |
File |
Purpose |
| DCE |
dce.cpp |
Dead instructions, unreachable blocks, dead allocas, static branch eval |
| Mem2Reg |
mem2reg.cpp |
Alloca→SSA via dominance tree/frontiers, PHI insertion |
| Dominance Tree |
dom_tree.cpp |
Immediate dominators + frontiers |
| Post-Dominance Tree |
post_dom_tree.cpp |
Post-dominance analysis |
| Early Return Elim |
early_return_elimination.cpp |
Early returns → structured control flow |
| Lower Break/Continue |
lower_break_continue.cpp |
Lower break/continue to explicit branches |
| Lower Ray Query Loop |
lower_ray_query_loop.cpp |
Ray query loop lowering |
| Lower Ray Query Loop → Loop |
lower_ray_query_loop_to_loop.cpp |
Convert ray query loops to plain loops |
| Destructure CFG |
destructure_cfg.cpp |
Flatten structured CFG to basic branches |
| Restructure CFG |
restructure_cfg.cpp |
Recover structured control flow |
| Outline |
outline.cpp |
Function outlining |
| Phi Cleanup |
phi_cleanup.cpp |
Remove trivial/duplicate PHI nodes |
| Fix Self-Referential |
fix_self_referential.cpp |
Break self-referential PHI/value cycles |
| If Conversion |
if_conversion.cpp |
Convert simple diamonds to select/min/max |
Analysis
| Pass |
File |
Purpose |
| Call Graph |
call_graph.cpp |
Call-graph construction |
| Pointer Usage |
pointer_usage.cpp |
Per-field kill/touch/live analysis for pointers |
| Lexical Scope |
lex_scope_analysis.cpp |
Scope region analysis |
| Aggregate Field Bitmask |
aggregate_field_bitmask.cpp |
Bitmask tracking for aggregate fields |
| Alias Analysis |
alias_analysis.cpp |
May-/must-alias queries for memory instructions |
| Convergence Region |
convergence_region.cpp |
Divergence/convergence region analysis |
| CVP |
cvp.cpp |
Correlated value propagation via structured branches |
| Scalar Evolution |
scalar_evolution.cpp |
SCEV for loop induction variables |
| Uniformity Analysis |
uniformity_analysis.cpp |
Uniform/divergent value analysis |
Scalar / Peephole / Global
| Pass |
File |
Purpose |
| Algebraic Simplify |
algebraic_simplify.cpp |
Algebraic identities (with optional fast-math) |
| Const Fold |
const_fold.cpp |
Constant folding |
| Early CSE |
early_cse.cpp |
Early common subexpression elimination |
| GVN |
gvn.cpp |
Global value numbering |
| Reassociate |
reassociate.cpp |
Reassociate expressions for CSE/folding |
| SCCP |
sccp.cpp |
Sparse conditional constant propagation |
| Simplify CFG |
simplify_cfg.cpp |
Remove empty/trivial blocks |
| Simplify Libcalls |
simplify_libcalls.cpp |
Simplify known builtin calls |
| Scalarizer |
scalarizer.cpp |
Break vector ops into scalar ops |
| Div-Rem Pairs |
div_rem_pairs.cpp |
Combine division/remainder pairs |
| Dead Arg Elim |
dead_arg_elim.cpp |
Remove unused arguments |
Loop
| Pass |
File |
Purpose |
| IndVar Simplify |
indvar_simplify.cpp |
Simplify induction variables |
| LICM |
licm.cpp |
Loop-invariant code motion |
| Loop Rotation |
loop_rotation.cpp |
Rotate loops for simpler CFG |
Memory / Local
| Pass |
File |
Purpose |
| SROA |
sroa.cpp |
Scalar replacement of aggregates |
| Reg2Mem |
reg2mem.cpp |
Register → memory conversion |
| Promote Ref Arg |
promote_ref_arg.cpp |
Reference argument promotion |
| Transpose GEP |
transpose_gep.cpp |
Transpose GEP through loads/stores |
| Trace GEP |
trace_gep.cpp |
GEP analysis & tracing |
| Local Load Elimination |
local_load_elimination.cpp |
Redundant load elimination |
| Local Store Forward |
local_store_forward.cpp |
Store-to-load forwarding |
| Dead Store Elimination |
dead_store_elimination.cpp |
Remove dead stores |
AD / Interprocedural
| Pass |
File |
Purpose |
| Autodiff |
autodiff.cpp |
Autodiff transformations |
| Inline |
inline.cpp |
Function inlining |
| Unused Callable Removal |
unused_callable_removal.cpp |
Dead function elimination |
Pass Pipeline Helpers
pass_pipeline.cpp / include/luisa/xir/passes/pass_pipeline.h provides PassPipeline, PassReport, and factory functions:
create_basic_optimization_pipeline()
create_post_inline_cleanup_pipeline()
create_ssa_optimization_pipeline()
create_post_restructure_cleanup_pipeline()
Control Flow Representation
XIR uses structured control flow with explicit merge blocks:
IfInst: condition, true_block, false_block, merge_block
LoopInst: prepare_block, body_block, update_block, merge_block
Design: maintains SSA, enables structured transforms, maps well to GPU shaders,
and supports PHI nodes at merges. SwitchInst is a first-class structured
terminator. Only the explicit destructure_cfg boundary maps it to raw
IndexedBranchInst; restructure_cfg reconstructs the switch and its merge.
There is no generic switch-lowering or XIR loop-unroll pass. Autodiff's private
bounded semantic expansion and SPIRV-Tools loop unrolling are separate
mechanisms with separate contracts.
Metadata
Headers: include/luisa/xir/metadata.h plus include/luisa/xir/metadata/{name,location,comment,curve_basis}.h. Types: NAME, LOCATION, COMMENT, CURVE_BASIS. Applied via MetadataListMixin.
JSON Serialization / Translators
- IR (legacy):
ast2json → Rust IR, C API luisa_compute_ir_ast_json_to_ir_*
- XIR:
src/xir/translators/xir2json.cpp, json2xir.cpp, xir2ast.cpp, xir2text.cpp — yyjson-based module serialization and AST round-tripping, useful for cross-process transport and debugging
Key Design Patterns
- Intrusive Lists —
ManagedIntrusiveList for node management
- CRTP —
DerivedValue<>, DerivedInstruction<>, DerivedFunction<>, DerivedArgument<>
- Visitor —
traverse_basic_blocks(), traverse_instructions()
- Builder —
XIRBuilder for instruction creation
- Mixin —
MetadataListMixin, ControlFlowMergeMixin, InstructionOpMixin, PrintMessageMixin
- Use-Def Chains —
Use objects track value users for SSA
Adding a New XIR Pass
- Create
src/xir/passes/<name>.cpp + header include/luisa/xir/passes/<name>.h
- Register in
src/xir/CMakeLists.txt
- Convention: accept
Module & or Function &, return an info struct (often with *_pass_run_on_module(Module *, PassReport *report = nullptr)), use XIRBuilder, call replace_all_uses_with() for substitution
1---2name: ir-pipeline3description: Legacy IR and XIR compiler pipeline, AST lowering, SSA IR, and optimization passes.4---56# IR and XIR Pipeline78Two IRs, both starting from AST (`src/ast/`), feeding into backend codegen:910| | IR (Legacy) | XIR (Preferred) |11|---|---|---|12| **Location** | `src/ir/`, `include/luisa/ir/` | `src/xir/`, `include/luisa/xir/` |13| **Impl** | Rust (`src/rust/`) | Pure C++ |14| **Serialization** | `ast2json` → Rust IR | `xir2json`/`json2xir` (yyjson) |15| **SSA** | Yes | Yes (mem2reg) |16| **Status** | Maintained (compat) | Active development |17| **Basic Blocks** | Yes | Yes |1819## Pipeline Flow2021```22DSL Tracing (src/dsl/) → AST (src/ast/)23 │24 ┌─────────┴─────────┐25 ▼ ▼26 XIR (ast2xir) IR (ast2ir → JSON → Rust FFI)27 │ │28 └─────────┬─────────┘29 ▼30 Backend Codegen (src/backends/<name>/)31 │32 ▼33 GPU Execution (src/runtime/)34```3536**Rust IR path**: `src/rust/luisa_compute_ir/` does autodiff, DCE, SSA, vectorize.37**XIR path**: Pure C++ with `ast2xir` translator, `xir2ast` round-trip, and optimization passes.3839## AST → IR Translation (Legacy)4041**File**: `src/ir/ast2ir.cpp`4243```44AST Function → to_json() → JSON string → Rust FFI → CArc<KernelModule/CallableModule>45```4647FFI: `luisa_compute_ir_ast_json_to_ir_kernel()`, `..._callable()`, `..._type()`.4849Key IR classes (Rust, via C FFI): `KernelModule`, `CallableModule`, `Node`, `Instruction` (Local, Call, Phi, Loop, If, Switch, RayQuery, AdScope), `Type`, `BasicBlock`.5051## AST → XIR Translation5253**Files**: `src/xir/translators/ast2xir.cpp`, `xir2ast.cpp`. `AST2XIRContext` maps AST variables to XIR Values, tracks break/continue targets, handles autodiff adjoints, caches constants.5455### Expression Mapping56| AST | XIR |57|---|---|58| `UnaryExpr` | `ArithmeticOp` (UNARY_MINUS, UNARY_BIT_NOT); `+x` is elided |59| `BinaryExpr` | `ArithmeticOp` (BINARY_ADD, etc.); matrix-aware; logic ops cast to bool |60| `MemberExpr` | `EXTRACT`/`SHUFFLE` or `GEP` |61| `AccessExpr` | `GEP` + `LOAD` |62| `LiteralExpr` | `Constant` |63| `ConstantExpr` | `Constant` |64| `RefExpr` | Variable lookup or `SpecialRegister` |65| `CallExpr` | `CallInst`, `ArithmeticOp`, `AtomicOp`, `Resource*Op`, `ThreadGroupOp`, `RayQuery*Op`, `Assert`/`Assume`/`Unreachable`/`RasterDiscard` |66| `CastExpr` | `CastInst` (STATIC_CAST, BITWISE_CAST) |67| `TypeIdExpr`/`StringIdExpr`/`FuncRefExpr` | Not implemented |6869### Statement Mapping70| AST | XIR |71|---|---|72| `IfStmt` | `IfInst` + true/false/merge |73| `SwitchStmt` | `SwitchInst` + case/default/merge |74| `ForStmt` | `LoopInst` (prepare/body/update/merge) |75| `LoopStmt` | `SimpleLoopInst` (do-while) |76| `BreakStmt` | `BreakInst` |77| `ContinueStmt` | `ContinueInst` |78| `ReturnStmt` | `ReturnInst` |79| `AssignStmt` | `StoreInst` |80| `ExprStmt` | Expression (terminator-aware, e.g. `Unreachable`) |81| `AutoDiffStmt` | `AutodiffScopeInst` |82| `RayQueryStmt` | `RayQueryLoopInst` + `RayQueryDispatchInst` |83| `PrintStmt` | `PrintInst` |84| `DebugBreakStmt` | `DebugBreakInst` |85| `CommentStmt` | Collected as comment metadata on following instruction |8687## XIR Core Architecture8889### Value Hierarchy90```91Value92├── GlobalValue93│ ├── Function → FunctionDefinition → KernelFunction (entry+block size), CallableFunction, ExternalFunction94│ ├── Constant (literals)95│ ├── Undefined96│ └── SpecialRegister (SPR_ThreadID, SPR_BlockID, SPR_DispatchID, SPR_WarpLaneID, SPR_KernelID, SPR_BlockSize, SPR_WarpSize, SPR_DispatchSize, SPR_ObjectID, SPR_Barycentrics, ...)97├── FunctionScopeValue98│ ├── BasicBlock (instruction container)99│ └── Argument → ValueArgument / ReferenceArgument / ResourceArgument100└── BlockScopeValue → Instruction101 ├── TerminatorInstruction: BranchInst, ConditionalBranchInst, IfInst, SwitchInst,102 │ LoopInst, SimpleLoopInst, ReturnInst, BreakInst, ContinueInst, UnreachableInst, RasterDiscardInst103 └── Non-terminator instructions104```105106### Key Classes107- **Module** (`include/luisa/xir/module.h`): container for globals, unique constants via hash108- **Function / FunctionDefinition** (`include/luisa/xir/function.h`): `ArgumentList`, `BasicBlockList`, `body_block()`, traversal orders (`PRE_ORDER`, `POST_ORDER`, ...). Traversal: `traverse_basic_blocks()`, `traverse_instructions()`109- **Argument** (`include/luisa/xir/argument.h`): `ValueArgument`, `ReferenceArgument`, `ResourceArgument`110- **BasicBlock** (`include/luisa/xir/basic_block.h`): `InstructionList`, `is_terminated()`, `terminator()`, `traverse_predecessors()`, `traverse_successors()`111- **Instruction** (`include/luisa/xir/instruction.h`): `DerivedInstruction<>`, `is_terminator()`, `control_flow_merge()`, `clone()`, `intrinsic_identifier()`112- **Value & Use** (`include/luisa/xir/value.h`, `use.h`): SSA `UseList`, `replace_all_uses_with()`, `is_lvalue()` for alloca/gep/reference args113114## XIR Instruction Set115116### Control Flow117| Instruction | Blocks |118|---|---|119| `IfInst` | true, false, merge |120| `SwitchInst` | cases, default, merge |121| `LoopInst` | prepare, body, update, merge |122| `SimpleLoopInst` | body, merge |123| `BranchInst` | target |124| `ConditionalBranchInst` | true, false |125| `ReturnInst` | — |126| `BreakInst` / `ContinueInst` | target (lowered before codegen) |127| `UnreachableInst` | — |128129### Memory130`AllocaInst` (LOCAL/SHARED), `LoadInst`, `StoreInst`, `GEPInst`131132### SSA133`PhiInst` — (block, value) pairs134135### Call / Cast136`CallInst` (user/external functions), `CastInst` (`STATIC_CAST`, `BITWISE_CAST`)137138### Arithmetic (`ArithmeticOp`)139- **Unary**: UNARY_MINUS, UNARY_BIT_NOT140- **Binary**: ADD, SUB, MUL, DIV, MOD, BIT_AND, BIT_OR, BIT_XOR, SHIFT_LEFT/RIGHT, ROTATE_LEFT/RIGHT, comparisons141- **Logic/Selection**: ALL, ANY, SELECT, STEP142- **Math**: ABS, MIN, MAX, CLAMP, SATURATE, LERP, SMOOTHSTEP, trig (SIN/COS/TAN/ASIN/ACOS/ATAN/ATAN2 and hyperbolic variants), exp/log families (EXP/EXP2/EXP10/LOG/LOG2/LOG10), POW, SQRT, RSQRT, FMA, COPYSIGN, CLZ, CTZ, POPCOUNT, REVERSE, ISINF, ISNAN, CEIL, FLOOR, FRACT, TRUNC, ROUND, RINT143- **Vector**: DOT, CROSS, LENGTH, LENGTH_SQUARED, NORMALIZE, FACEFORWARD, REFLECT, REDUCE_SUM/PRODUCT/MIN/MAX, OUTER_PRODUCT144- **Matrix**: MATRIX_COMP_NEG/ADD/SUB/MUL/DIV, MATRIX_LINALG_MUL, MATRIX_DETERMINANT, MATRIX_TRANSPOSE, MATRIX_INVERSE145- **Aggregate**: AGGREGATE, SHUFFLE, EXTRACT, INSERT146147### Resource148`ResourceQueryOp`, `ResourceReadOp`, `ResourceWriteOp` — buffer/texture/bindless ops, ray-tracing queries, indirect dispatch, device-address loads/stores149150### Atomic (`AtomicOp`)151EXCHANGE, COMPARE_EXCHANGE, FETCH_ADD/SUB/AND/OR/XOR/MIN/MAX152153### Thread Group & Ray Query & Autodiff154`ThreadGroupOp` (warp, sync, SER, quad derivatives), `RayQueryLoopInst`, `RayQueryDispatchInst`, `RayQueryObjectReadInst`, `RayQueryObjectWriteInst`, `RayQueryPipelineInst`, `AutodiffScopeInst`, `AutodiffIntrinsicInst` (requires_gradient, gradient, gradient_marker, accumulate_gradient, backward, detach)155156### Debug / Utility157`PrintInst`, `ClockInst`, `DebugBreakInst`, `AssertInst`, `AssumeInst`, `OutlineInst`, `RasterDiscardInst`158159## XIR Optimization Passes160161**Location**: `src/xir/passes/` (headers in `include/luisa/xir/passes/`)162163### Core / SSA / CFG164| Pass | File | Purpose |165|---|---|---|166| DCE | `dce.cpp` | Dead instructions, unreachable blocks, dead allocas, static branch eval |167| Mem2Reg | `mem2reg.cpp` | Alloca→SSA via dominance tree/frontiers, PHI insertion |168| Dominance Tree | `dom_tree.cpp` | Immediate dominators + frontiers |169| Post-Dominance Tree | `post_dom_tree.cpp` | Post-dominance analysis |170| Early Return Elim | `early_return_elimination.cpp` | Early returns → structured control flow |171| Lower Break/Continue | `lower_break_continue.cpp` | Lower break/continue to explicit branches |172| Lower Ray Query Loop | `lower_ray_query_loop.cpp` | Ray query loop lowering |173| Lower Ray Query Loop → Loop | `lower_ray_query_loop_to_loop.cpp` | Convert ray query loops to plain loops |174| Destructure CFG | `destructure_cfg.cpp` | Flatten structured CFG to basic branches |175| Restructure CFG | `restructure_cfg.cpp` | Recover structured control flow |176| Outline | `outline.cpp` | Function outlining |177| Phi Cleanup | `phi_cleanup.cpp` | Remove trivial/duplicate PHI nodes |178| Fix Self-Referential | `fix_self_referential.cpp` | Break self-referential PHI/value cycles |179| If Conversion | `if_conversion.cpp` | Convert simple diamonds to select/min/max |180181### Analysis182| Pass | File | Purpose |183|---|---|---|184| Call Graph | `call_graph.cpp` | Call-graph construction |185| Pointer Usage | `pointer_usage.cpp` | Per-field kill/touch/live analysis for pointers |186| Lexical Scope | `lex_scope_analysis.cpp` | Scope region analysis |187| Aggregate Field Bitmask | `aggregate_field_bitmask.cpp` | Bitmask tracking for aggregate fields |188| Alias Analysis | `alias_analysis.cpp` | May-/must-alias queries for memory instructions |189| Convergence Region | `convergence_region.cpp` | Divergence/convergence region analysis |190| CVP | `cvp.cpp` | Correlated value propagation via structured branches |191| Scalar Evolution | `scalar_evolution.cpp` | SCEV for loop induction variables |192| Uniformity Analysis | `uniformity_analysis.cpp` | Uniform/divergent value analysis |193194### Scalar / Peephole / Global195| Pass | File | Purpose |196|---|---|---|197| Algebraic Simplify | `algebraic_simplify.cpp` | Algebraic identities (with optional fast-math) |198| Const Fold | `const_fold.cpp` | Constant folding |199| Early CSE | `early_cse.cpp` | Early common subexpression elimination |200| GVN | `gvn.cpp` | Global value numbering |201| Reassociate | `reassociate.cpp` | Reassociate expressions for CSE/folding |202| SCCP | `sccp.cpp` | Sparse conditional constant propagation |203| Simplify CFG | `simplify_cfg.cpp` | Remove empty/trivial blocks |204| Simplify Libcalls | `simplify_libcalls.cpp` | Simplify known builtin calls |205| Scalarizer | `scalarizer.cpp` | Break vector ops into scalar ops |206| Div-Rem Pairs | `div_rem_pairs.cpp` | Combine division/remainder pairs |207| Dead Arg Elim | `dead_arg_elim.cpp` | Remove unused arguments |208209### Loop210| Pass | File | Purpose |211|---|---|---|212| IndVar Simplify | `indvar_simplify.cpp` | Simplify induction variables |213| LICM | `licm.cpp` | Loop-invariant code motion |214| Loop Rotation | `loop_rotation.cpp` | Rotate loops for simpler CFG |215216### Memory / Local217| Pass | File | Purpose |218|---|---|---|219| SROA | `sroa.cpp` | Scalar replacement of aggregates |220| Reg2Mem | `reg2mem.cpp` | Register → memory conversion |221| Promote Ref Arg | `promote_ref_arg.cpp` | Reference argument promotion |222| Transpose GEP | `transpose_gep.cpp` | Transpose GEP through loads/stores |223| Trace GEP | `trace_gep.cpp` | GEP analysis & tracing |224| Local Load Elimination | `local_load_elimination.cpp` | Redundant load elimination |225| Local Store Forward | `local_store_forward.cpp` | Store-to-load forwarding |226| Dead Store Elimination | `dead_store_elimination.cpp` | Remove dead stores |227228### AD / Interprocedural229| Pass | File | Purpose |230|---|---|---|231| Autodiff | `autodiff.cpp` | Autodiff transformations |232| Inline | `inline.cpp` | Function inlining |233| Unused Callable Removal | `unused_callable_removal.cpp` | Dead function elimination |234235### Pass Pipeline Helpers236`pass_pipeline.cpp` / `include/luisa/xir/passes/pass_pipeline.h` provides `PassPipeline`, `PassReport`, and factory functions:237- `create_basic_optimization_pipeline()`238- `create_post_inline_cleanup_pipeline()`239- `create_ssa_optimization_pipeline()`240- `create_post_restructure_cleanup_pipeline()`241242## Control Flow Representation243244XIR uses **structured control flow** with explicit merge blocks:245246```247IfInst: condition, true_block, false_block, merge_block248LoopInst: prepare_block, body_block, update_block, merge_block249```250251Design: maintains SSA, enables structured transforms, maps well to GPU shaders,252and supports PHI nodes at merges. `SwitchInst` is a first-class structured253terminator. Only the explicit `destructure_cfg` boundary maps it to raw254`IndexedBranchInst`; `restructure_cfg` reconstructs the switch and its merge.255There is no generic switch-lowering or XIR loop-unroll pass. Autodiff's private256bounded semantic expansion and SPIRV-Tools loop unrolling are separate257mechanisms with separate contracts.258259## Metadata260261**Headers**: `include/luisa/xir/metadata.h` plus `include/luisa/xir/metadata/{name,location,comment,curve_basis}.h`. Types: `NAME`, `LOCATION`, `COMMENT`, `CURVE_BASIS`. Applied via `MetadataListMixin`.262263## JSON Serialization / Translators264265- **IR (legacy)**: `ast2json` → Rust IR, C API `luisa_compute_ir_ast_json_to_ir_*`266- **XIR**: `src/xir/translators/xir2json.cpp`, `json2xir.cpp`, `xir2ast.cpp`, `xir2text.cpp` — yyjson-based module serialization and AST round-tripping, useful for cross-process transport and debugging267268## Key Design Patterns2692701. **Intrusive Lists** — `ManagedIntrusiveList` for node management2712. **CRTP** — `DerivedValue<>`, `DerivedInstruction<>`, `DerivedFunction<>`, `DerivedArgument<>`2723. **Visitor** — `traverse_basic_blocks()`, `traverse_instructions()`2734. **Builder** — `XIRBuilder` for instruction creation2745. **Mixin** — `MetadataListMixin`, `ControlFlowMergeMixin`, `InstructionOpMixin`, `PrintMessageMixin`2756. **Use-Def Chains** — `Use` objects track value users for SSA276277## Adding a New XIR Pass2782791. Create `src/xir/passes/<name>.cpp` + header `include/luisa/xir/passes/<name>.h`2802. Register in `src/xir/CMakeLists.txt`2813. Convention: accept `Module &` or `Function &`, return an info struct (often with `*_pass_run_on_module(Module *, PassReport *report = nullptr)`), use `XIRBuilder`, call `replace_all_uses_with()` for substitution