# Architecture Overview StinkyTofu is an LLVM-inspired pass-based IR optimizer for AMD GPU assembly kernels, used by hipBLASLt/TensileLite via Python bindings. ## Two IR Levels **Logical IR** (`include/stinkytofu/ir/logical/`, `src/ir/logical/`) -- architecture-agnostic, high-level. Used before lowering to assembly. **Asm IR** (`include/stinkytofu/ir/asm/`, `src/ir/asm/`) -- concrete, architecture-specific. Core types: `StinkyInstruction`, `Function`, `BasicBlock`. This is what passes operate on. The text format (used by `stinkytofu-opt` and FileCheck tests): ``` st.func @name() { ^entry: v0 = "st.v_mul_f32"(v1, v2) { issueCycles = 1, latencyCycles = 5 } } ``` ## Build Dependency Chain ``` hardware/src/gfx/GfxXXX/ GfxXXXInstructions.def (DEF_T / DEF_BATCH definitions) GfxXXXFormats.def (format definitions) arch.cmake (ARCH_MAJOR, ARCH_WAVEFRONT, costs, register limits) | v tablegen hardware/generated/ GfxXXX_init.inc (instruction table) GfxXXX_costs.inc (non-default costs) GfxXXX_operands.inc (operand requirements) GfxXXX_block.inc (defineGfxXXXInsts() body) | v gfxisa library --> stinkytofu library --> tools / Python bindings ``` New architectures require only adding a `hardware/src/gfx/GfxXXX/` directory with `.def` files -- no C++ edits for instruction definitions. See [Adding an Architecture](adding-architecture.md). ## Pass Pipeline `PassManager` runs passes sequentially. `PassInstrumentation` callbacks fire before/after each pass (used for debug printing and JSON snapshot). `ScopeAdaptor` extracts instruction regions (identified by named groups like `loopWithPrefetch`) into temporary `Function` objects for isolated scheduling, then splices results back. `PassFeatureConfig` carries pass-tuning flags (barrier config, loop config, DAG features) through `PassContext`. ## Key Passes | Pass | Purpose | |------|---------| | `CFGBuilderPass` | Splits `BasicBlock`s at labels, builds CFG edges | | `StinkyDAGSchedulerPass` | DAG-based instruction scheduling. Calls `buildUseDefChain` (inserts pseudo-PHI nodes) before scheduling | | `StinkyWaitCntInsertionPass` | Def-use based wait count insertion for memory operations | | `DeadCodeEliminationPass` | Block-local forward scan: removes instructions whose destination is overwritten before use. Iterates to fixpoint. Preserves memory ops, barriers, side-effects, in-place ops, and dummy registers | | `RedundantMovEliminationPass` | Block-local backward search: removes duplicate mov-type instructions (same opcode + dest + src, source unmodified between occurrences) | | `PeepholeOptimizationPass` | Declarative pattern-based optimizations compiled from `.pattern` files. See [Adding Peephole Patterns](adding-peephole-patterns.md) | | `InsertClusterBarrierPass` | Inserts cluster-barrier (`s_barrier_signal/wait -3`) handshakes at five rules covering the main and tail loops. See [Insert Cluster Barrier Pass](cluster-barrier.md) | | `LoopRegionRemarkPass` | Emits optimization remarks about loop health: region count, boundary causes, s_nop waste, branch count. Enabled by `StinkyTofuEnableRemarks`. See [Global Parameters](../user/global-parameters.md) | | `RemoveInstructionPass` | Removes instructions matching configured unified opcodes from all basic blocks. Optional last pass on gfx1250; disabled when `ModuleOptions.RemoveInstructions` is empty. See [RemoveInstructionPass](../user/remove-instruction-pass.md) | ## Pseudo-PHI Nodes `buildUseDefChain()` inserts pseudo-PHI instructions at CFG join points for cross-block def-use tracking. PHIs are **never emitted to assembly** (AsmEmitter skips them). Code that snapshots or counts instructions must skip `GFX::PHI` opcodes. ## rocisa vs StinkyTofu TensileLite uses **rocisa** for older architectures and **StinkyTofu** for newer ones. The split is by architecture: gfx1250 and beyond use StinkyTofu. `src/conversion/rocisa/` bridges rocisa IR to StinkyTofu Asm IR. ## Intrinsic System Pre-defined high-level operations (e.g., ReLU, Clamp) are defined in `src/ir/logical/Intrinsics.intrinsic`, compiled to binary `intrinsics.st.bc` at build time, and loaded at runtime via `IntrinsicRegistry`. Two-stage build avoids circular dependencies with TableGen. See [Adding Intrinsics](adding-intrinsics.md). ## stinkytofu-opt `tools/stinkytofu-opt/` is the standalone IR driver for testing passes. Pass registry is in `stinkytofu-opt.hpp::availablePasses`. FileCheck tests use `stinkytofu-check` to run a `RUN:` command and verify stdout against `CHECK:` directives. See [stinkytofu-opt README](../../tools/stinkytofu-opt/README.md).