Files
TheRock/rocm-libraries/shared/stinkytofu/tools/stinkytofu-opt/README.md
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

386 lines
14 KiB
Markdown

# stinkytofu-opt
`stinkytofu-opt` is a command-line tool for parsing, analyzing, and optimizing StinkyTofu IR (Intermediate Representation).
---
## Table of Contents
- [Build](#build)
- [Quick Start](#quick-start)
- [User Guide](#user-guide)
- [Basic Usage](#basic-usage)
- [Available Passes](#available-passes)
- [Examples](#examples)
- [Developer Guide](#developer-guide)
- [Architecture Overview](#architecture-overview)
- [Configuration Components](#configuration-components)
- [IR Format](#ir-format)
---
## Build
Then, navigate to the `rocm-libraries/shared/stinkytofu` directory:
```bash
cmake -B build .
cmake --build build --target stinkytofu-opt -j
```
The binary will be located at: `build/tools/stinkytofu-opt/stinkytofu-opt`
---
## Quick Start
```bash
# List all available passes
./build/tools/stinkytofu-opt/stinkytofu-opt --list-passes
# Parse and deserialize IR (no optimization)
./build/tools/stinkytofu-opt/stinkytofu-opt --arch gfx1250 func.arch-gfx1250.stir
# Apply optimization passes
./build/tools/stinkytofu-opt/stinkytofu-opt \
--arch gfx1250 func.arch-gfx1250.stir \
--StinkyDAGSchedulerPass
```
---
## User Guide
### Basic Usage
```bash
stinkytofu-opt [options] <ir_file> [--pass1] [--pass2] ...
```
**Arguments:**
- `<ir_file>`: Path to the StinkyTofu IR file to process
- `--passN`: Optional pass names to apply (use `--` prefix)
**Options:**
- `--arch <arch>`: Target GPU architecture (default: gfx1250). Supported: `gfx1250`
- `--remarks`: Enable optimization remarks on stderr (e.g. loop region diagnostics)
- `--list-passes`: Display all available optimization passes
- `--help`: Show usage information
**Output flags:**
- `--print-output`: Emit optimized IR (StinkyTofu text format)
- `--emit-asm`: Emit optimized GPU assembly (always on for `.s` input)
- `-o <file>`: Write output to file instead of stdout
**Region selection (asm input only):**
- `--from-label <label>`: Start processing at the given label
- `--to-label <label>`: Stop processing at the given label (labels are any identifier defined in the assembly file)
**Round-trip fidelity flags (asm input only):**
- `--preserve-symbolic-regs`: Preserve and re-emit symbolic register names (e.g.
`v[vgprSerialPersist-768]`) instead of resolving them to the numeric form
(`v255`). Best used with no optimization passes, since passes operate on
numeric indices and can leave the symbolic names stale.
- `--preserve-comments`: Preserve and re-emit trailing source comments (`// ...`
or `; ...`) attached to each instruction, label, or `.set` directive. Best
used with no optimization passes, since passes can move or rewrite the
instructions the comments were attached to.
Both flags are off by default — `stinkytofu-opt` resolves symbolic register
names and strips comments unless the flag is set.
### Available Passes
```bash
./stinkytofu-opt --list-passes
```
Output (illustrative — the authoritative, up-to-date list is whatever the tool
prints, sourced from `availablePasses` in `tools/stinkytofu-opt/stinkytofu-opt.hpp`):
```
Available passes:
=================
--StinkyDAGSchedulerPass
--StinkyWaitCntInsertionPass
--DeadCodeEliminationPass
...
```
**Note:** Passes are applied in the order they appear on the command line, after the initial deserialization pass.
### Examples
#### Example 1: Parse and Validate IR
Simply parse the IR file without applying any optimization passes:
```bash
./build/tools/stinkytofu-opt/stinkytofu-opt \
--arch gfx1250 tools/stinkytofu-opt/tests/func.arch-gfx1250.stir
```
This will:
- Parse the IR file
- Display parsed instruction count
- Generate debug output files (`before.txt`, `after.txt`)
#### Example 2: Apply DAG Scheduling
Apply the DAG scheduler to optimize instruction ordering:
```bash
./build/tools/stinkytofu-opt/stinkytofu-opt \
--arch gfx1250 tools/stinkytofu-opt/tests/func.arch-gfx1250.stir \
--StinkyDAGSchedulerPass
```
#### Example 3: Multiple Passes
Apply multiple optimization passes in sequence:
```bash
./build/tools/stinkytofu-opt/stinkytofu-opt \
--arch gfx1250 tools/stinkytofu-opt/tests/func.arch-gfx1250.stir \
--StinkyDAGSchedulerPass \
--StinkyWaitCntInsertionPass
```
#### Example 4: Remove selected instructions
`RemoveInstructionPass` deletes every instruction whose unified opcode matches
one of the comma-separated mnemonics. See
[RemoveInstructionPass](../../docs/user/remove-instruction-pass.md) for gfx1250
pipeline integration and Tensile `ModuleOptions.RemoveInstructions`.
```bash
# Remove tensor_load_to_lds only
./build/tools/stinkytofu-opt/stinkytofu-opt \
--arch gfx1250 input.stir \
--RemoveInstructionPass=tensor_load_to_lds \
--print-output
# Remove tensor_load, ds_load, and wmma in one pass
./build/tools/stinkytofu-opt/stinkytofu-opt \
--arch gfx1250 input.stir \
--RemoveInstructionPass=tensor_load_to_lds,ds_load_b128,v_wmma_f32_16x16x16_bf16 \
--print-output
```
#### Example 5: Round-Trip Raw Assembly
When the input is a `.s` file (raw GPU assembly), `--emit-asm` is implied and
the tool can be used as a parse → IR → emit round-trip. By default, symbolic
register names are resolved to numeric indices and source comments are
stripped. Use the round-trip fidelity flags to preserve them:
```bash
# Resolve symbolic regs and strip comments (default)
./build/tools/stinkytofu-opt/stinkytofu-opt --arch gfx1250 kernel.s
# Preserve symbolic register names (e.g. v[vgprSerialPersist-768] survives
# instead of becoming v255).
./build/tools/stinkytofu-opt/stinkytofu-opt --arch gfx1250 kernel.s \
--preserve-symbolic-regs
# Preserve trailing // and ; comments on each instruction, label, and .set.
./build/tools/stinkytofu-opt/stinkytofu-opt --arch gfx1250 kernel.s \
--preserve-comments
# Both — closest to byte-for-byte round-trip:
./build/tools/stinkytofu-opt/stinkytofu-opt --arch gfx1250 kernel.s \
--preserve-symbolic-regs --preserve-comments
```
**Caveat:** both flags are designed for round-trip workflows, *not* for
running optimization passes. Optimization passes operate on numeric
register indices and can move or rewrite instructions, which leaves stale
symbolic names and orphaned comments. If you need to combine round-trip
with passes, expect manual review of the output.
### Output Files
The tool generates debug output files in the same directory as the input:
- `before.txt`: IR state before each pass
- `after.txt`: IR state after each pass
---
## Developer Guide
### Architecture Overview
`stinkytofu-opt` is built using a modular pass-based architecture inspired by LLVM:
1. **IRLexer**: Tokenizes the input IR text into a token stream (`stinkytofu/serialization/asm/`, impl in `src/serialization/asm/IRLexer.cpp`)
2. **IRParser**: Parses tokens into `StinkyInstruction` objects (`stinkytofu/serialization/asm/IRParser.hpp`, impl in `src/serialization/asm/IRParser.cpp`)
3. **PassManager**: Orchestrates the execution of optimization passes
4. **Passes**: Individual optimization transformations on the IR
#### Component Flow
```
IR File → IRLexer → Tokens → IRParser → Instructions → PassManager → Optimized IR
↓
Pass Pipeline
├─ DeserializePass
├─ Pass 1
├─ Pass 2
└─ Pass N
```
### Configuration Components
The tool uses several configuration components defined in `stinkytofu-opt.hpp`:
#### 1. Available Passes (`availablePasses`)
A vector of `PassInfo` structures that register all available optimization passes:
```cpp
struct PassInfo
{
const char* name; // Pass identifier (e.g., "StinkyDAGSchedulerPass")
std::function<std::unique_ptr<Pass>()> creator; // Factory function to create the pass
};
// Illustrative — see the actual, up-to-date registry in stinkytofu-opt.hpp.
const std::vector<PassInfo> availablePasses = {
{ "StinkyDAGSchedulerPass", [](const auto&) { return createStinkyDAGSchedulerPass(); } },
{ "StinkyWaitCntInsertionPass", [](const auto&) { return createStinkyWaitCntInsertionPass(); } },
// ...
};
```
**Purpose:** This registry allows dynamic pass creation based on command-line
arguments. The authoritative list lives in
`tools/stinkytofu-opt/stinkytofu-opt.hpp::availablePasses`.
#### 2. Debug Print Instrumentation (`createDebugPrintInstrumentation()`)
Controls debug output and logging during pass execution via the PassInstrumentation callback interface:
```cpp
std::shared_ptr<stinkytofu::PassInstrumentation> createDebugPrintInstrumentation()
{
auto debugConfig = std::make_unique<stinkytofu::PassManagerDebugConfig>();
debugConfig->setPrintBeforeAll(true); // Print IR before each pass
debugConfig->setPrintAfterAll(true); // Print IR after each pass
debugConfig->setDumpToFileInBefore("before.txt"); // Save pre-pass state
debugConfig->setDumpToFileInAfter("after.txt"); // Save post-pass state
return std::make_shared<stinkytofu::DebugPrintInstrumentation>(std::move(debugConfig));
}
```
**Use Case:** Enable detailed debugging when developing or troubleshooting passes.
#### 3. StinkyOptInfo (`getStinkyOptInfo()`)
Global optimization settings that control pass behavior:
```cpp
stinkytofu::StinkyOptInfo getStinkyOptInfo()
{
stinkytofu::StinkyOptInfo optInfo;
optInfo.unrollGemmMovableBarrier = true;
optInfo.unrollGemm = true;
optInfo.distributeGlobalRead = true;
return optInfo;
}
```
**Use Case:** Tune optimization aggressiveness for different workloads.
#### 4. Kernel Configuration (`setKernelConfig()`)
Hardware-specific configuration for the target GPU architecture:
```cpp
void setKernelConfig(stinkytofu::PassManager& passManager)
{
passManager.setKernelConfig(
{12, 5, 0}, // arch: GPU architecture version (e.g., gfx1250)
0, // ta0: TileA0
0, // tb0: TileB0
0, // tm0: TileM0
0, // nGRA: NumGRA
0, // nGRB: NumGRB
0, // nGRM: NumGRM
0 // numWaves: Number of waves per workgroup
// Note: wavefrontSz is automatically determined from architecture
);
}
```
**Use Case:** Configure passes for specific GPU architectures and kernel characteristics.
---
## IR Format
StinkyTofu IR uses an MLIR-style text format. Each instruction has the form:
```
[destRegs =] "st.<mnemonic>"(srcRegs) { issueCycles = N, latencyCycles = N [, mod.X = { ... }, ...] }
```
### Field Descriptions
- **destRegs** (optional): Destination register(s), e.g. `v[0]`, `v[34:37]`, `acc[0:3]`. Omit for instructions with no destination. Follow with `=`.
- **"st.\<mnemonic>"**: Quoted operation name with `st.` namespace (e.g. `"st.ds_read_b128"`, `"st.v_mfma_f32_16x16x16_f16"`).
- **srcRegs**: Comma-separated source operands in parentheses (registers, immediates, BARRIER[0], etc.).
- **attributes** (in braces): Required **issueCycles** and **latencyCycles** (integer values). Optional modifier attributes: **mod.X = { field = value, ... }** for each modifier type (e.g. `mod.ds`, `mod.flat`, `mod.mfma`). Use `-1` for default cycle values when appropriate.
### Modifier Attributes
Modifiers are serialized as attribute keys `mod.<type>` with a dict value. Examples:
- **mod.ds**: `mod.ds = { na = 1, offset = 0, offset0 = 0, offset1 = 0, gds = false }`
- **mod.flat**: `mod.flat = { offset12 = 0, glc = false, slc = false, lds = false }`
- **mod.mfma**: `mod.mfma = { reuseA = false, reuseB = false, negLo = [0,0,0], negHi = [0,0,0], numNegSrcs = 3 }` (negLo/negHi/numNegSrcs only emitted when neg bits are set)
- **mod.matrix_fmt**: `mod.matrix_fmt = { fmtA = "MATRIX_FMT_FP8", fmtB = "MATRIX_FMT_FP8", scaleFmtA = "MATRIX_SCALE_FMT_E4M3", scaleFmtB = "MATRIX_SCALE_FMT_E4M3" }` (fields only emitted when not NONE; `MatrixFmt` ∈ {FP8, BF8, FP6, BF6, FP4}; `MatrixScaleFmt` ∈ {E8, E5M3, E4M3})
- **mod.dpp** (DPP16): `mod.dpp = { dppCtrl = 273, rowMask = 15, bankMask = 15, boundCtrl = 0, fi = 0 }` (dppCtrl is the numeric DppCtrl enum value)
- **mod.dpp** (DPP8): `mod.dpp = { isDPP8 = true, dpp8 = [7,6,5,4,3,2,1,0], boundCtrl = 0, fi = 0 }`
Other modifier types (e.g. `mod.vop3`, `mod.swaitcnt`, `mod.delayalu`) follow the same pattern. The serializer emits only fields that apply to the modifier instance.
### Example IR
```
v[34:37] = "st.ds_read_b128"(v[5]) { issueCycles = 4, latencyCycles = 52, mod.ds = { na = 1, offset = 0, gds = false } }
acc[0:3] = "st.v_mfma_f32_16x16x16_f16"(v[6:7], v[22:23], acc[0:3]) { issueCycles = 4, latencyCycles = 16 }
```
Hierarchical format with functions and blocks:
```
st.func @kernel() {
^entry:
v[0] = "st.v_add_f32"(v[1], v[2]) { issueCycles = 4, latencyCycles = 8 }
Successors: ^next
^next:
...
}
```
See `tests/unit/asm/IRParserTest.cpp` and the serialization layer (`StinkyAsmPrinter`, `IRParser`) for more examples.
---
## Optimization Remarks
Use `--remarks` to enable optimization remarks on stderr. Remarks report code quality diagnostics (loop region count, s_nop waste, etc.) without requiring `PASS_DEBUG`.
```bash
# Run the full gfx1250 pipeline with remarks
./build/tools/stinkytofu-opt/stinkytofu-opt \
--arch gfx1250 kernel.s -O2 --remarks --emit-asm
# Run individual passes with remarks
./build/tools/stinkytofu-opt/stinkytofu-opt \
--arch gfx1250 input.stir \
--from-label loop_start --to-label loop_end \
--StinkyDAGSchedulerPass --InsertDelayAluPass --LoopRegionRemarkPass \
--remarks --print-output
```
See [Global Parameters](../../docs/user/global-parameters.md) for the `StinkyTofuEnableRemarks` equivalent in the Tensile/KernelWriter path.