4.6 KiB
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.
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 BasicBlocks 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 |
InsertClusterBarrierPass |
Inserts cluster-barrier (s_barrier_signal/wait -3) handshakes at five rules covering the main and tail loops. See Insert Cluster Barrier Pass |
LoopRegionRemarkPass |
Emits optimization remarks about loop health: region count, boundary causes, s_nop waste, branch count. Enabled by StinkyTofuEnableRemarks. See Global Parameters |
RemoveInstructionPass |
Removes instructions matching configured unified opcodes from all basic blocks. Optional last pass on gfx1250; disabled when ModuleOptions.RemoveInstructions is empty. See RemoveInstructionPass |
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.
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.