Files
TheRock/rocm-libraries/shared/stinkytofu/docs/developer/adding-peephole-patterns.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

488 lines
9.5 KiB
Markdown

# How to Add Peephole Optimization Patterns
This guide shows you how to add new optimization patterns to the StinkyTofu compiler.
## Quick Start
**Three steps:**
1. Write pattern in '.pattern' file
2. Run 'make'
3. Done!
## Example: Adding a Multiply-Add Fusion
### Step 1: Write the Pattern
Edit 'src/transforms/asm/PeepholePatterns.pattern':
'''
//===----------------------------------------------------------------------===//
// Pattern: Multiply-Add Fusion (F32)
//
// Transforms:
// v_mul_f32 v0, a, b
// v_add_f32 v2, v0, c
// Into:
// v_fma_f32 v2, a, b, c
//===----------------------------------------------------------------------===//
pattern MulAddFusion_F32 {
match {
$mul = v_mul_f32 $tmp, $a, $b
$add = v_add_f32 $dst, $tmp, $c
}
constraints {
HasOneUse($tmp)
}
rewrite {
$new_const = AddConstants($fma_const, $add_const)
// Pattern system automatically handles the transformation
}
}
'''
### Step 2: Build
'''bash
cd build
make -j$(nproc)
'''
**What happens:**
- [x] Pattern is parsed
- [x] C++ matcher code is generated
- [x] Pattern is automatically registered
- [x] Pass will try your pattern on every instruction
### Step 3: Test
Your pattern is now active! It will match and transform automatically.
'''
[PeepholePass] Loaded 3 pattern(s)
[Peephole] Applied MulAddFusion_F32
'''
---
## Pattern Syntax
### Basic Structure
'''
pattern PatternName {
match {
// Instructions to match
}
constraints {
// Conditions that must be true
}
rewrite {
// How to transform (currently automatic)
}
}
'''
### Match Section
**Syntax:**
'''
$instruction_var = opcode $dest, $src1, $src2, ...
'''
**Rules:**
- First operand is **always** the destination register
- Pattern variables start with '$'
- Instructions are matched in temporal order (first executed first)
**Example:**
'''
match {
// First: FMA instruction
$fma = v_fma_f32 $result, $a, $b, $const1
// Second: ADD instruction using FMA result
$add = v_add_f32 $output, $const2, $result
}
'''
### Constraints Section
Available constraints:
| Constraint | Meaning | Example |
|------------|---------|---------|
| 'HasOneUse($reg)' | Register used exactly once | 'HasOneUse($tmp)' |
| 'IsConstant($reg)' | Register is a literal | 'IsConstant($const)' |
| 'SameValue($r1, $r2)' | Registers have same value | 'SameValue($a, $b)' |
| 'DifferentValue($r1, $r2)' | Registers differ | 'DifferentValue($x, $y)' |
**Example:**
'''
constraints {
HasOneUse($tmp) // $tmp only used by next instruction
IsConstant($c1) // $c1 must be a literal value
IsConstant($c2) // $c2 must be a literal value
}
'''
### Rewrite Section
Currently, rewrites are **automatic** for fusion patterns:
- Constants are folded
- Instructions are modified in-place
- Dead instructions are removed
**Built-in constant folding:**
'''
rewrite {
$new = AddConstants($c1, $c2) // c1 + c2
$new = SubConstants($c1, $c2) // c1 - c2
$new = MulConstants($c1, $c2) // c1 * c2
$new = NegateConstant($c) // -c
}
'''
---
## Complete Examples
### Example 1: Add+FMA Fusion (F32)
**Before:**
'''asm
v_fma_f32 v0, a, b, 1.0
v_add_f32 v2, 1.0, v0
'''
**After:**
'''asm
v_fma_f32 v2, a, b, 2.0 # v0 eliminated!
'''
**Pattern:**
'''
pattern AddFMAFusion_F32 {
match {
$fma = v_fma_f32 $fma_result, $a, $b, $fma_const
$add = v_add_f32 $add_dst, $add_const, $fma_result
}
constraints {
HasOneUse($fma_result)
IsConstant($fma_const)
IsConstant($add_const)
}
rewrite {
$new_const = AddConstants($fma_const, $add_const)
}
}
'''
### Example 2: Add+FMA Fusion (F16)
**Before:**
'''asm
v_fma_f16 v0, a, b, 0.5
v_add_f16 v1, 0.5, v0
'''
**After:**
'''asm
v_fma_f16 v1, a, b, 1.0
'''
**Pattern:**
'''
pattern AddFMAFusion_F16 {
match {
$fma = v_fma_f16 $fma_result, $a, $b, $fma_const
$add = v_add_f16 $add_dst, $add_const, $fma_result
}
constraints {
HasOneUse($fma_result)
IsConstant($fma_const)
IsConstant($add_const)
}
rewrite {
$new_const = AddConstants($fma_const, $add_const)
}
}
'''
---
## Tips & Best Practices
### 1. Always Use 'HasOneUse' for Intermediate Values
'''
[x] Good:
constraints {
HasOneUse($tmp) // Safe to eliminate $tmp
}
[ ] Bad:
// Missing HasOneUse - might eliminate value that's used elsewhere!
'''
### 2. Check for Constants When Folding
'''
[x] Good:
constraints {
IsConstant($c1)
IsConstant($c2)
}
rewrite {
$result = AddConstants($c1, $c2)
}
[ ] Bad:
// Missing IsConstant - can't fold non-constant values!
'''
### 3. Name Variables Descriptively
'''
[x] Good:
$fma_inst = v_fma_f32 $fma_result, $a, $b, $const
[ ] Bad:
$i1 = v_fma_f32 $r1, $r2, $r3, $r4
'''
### 4. Add Comments Explaining the Optimization
'''
//===----------------------------------------------------------------------===//
// Pattern: NegateNegate
//
// Eliminates double negation: -(-x) => x
// Benefit: Eliminates 2 instructions, frees registers
//===----------------------------------------------------------------------===//
'''
### 5. Order Patterns by Specificity
More specific patterns should come before general ones:
'''
// Specific: mul by constant 1.0
pattern MulByOne { ... }
// General: any multiplication
pattern MulFusion { ... }
'''
### 6. Patterns Work Across Non-Consecutive Instructions
The pattern system uses **def-use analysis**, so patterns don't require strict consecutiveness:
'''
[x] This works fine:
v_fma_f32 v0, v1, v2, 1.0
v_mul_f32 v5, v6, v7 // Intervening instruction
v_add_f32 v0, 1.0, v0 // Still matches and fuses!
'''
The pattern matcher automatically verifies that:
- Dependencies are correct (FMA comes before ADD)
- Intermediate registers haven't been overwritten
'''
[ ] This correctly doesn't match:
v_fma_f32 v0, v1, v2, 1.0
v_mul_f32 v0, v6, v7 // Overwrites v0!
v_add_f32 v3, 1.0, v0 // Uses v0 from v_mul, not v_fma
'''
### 7. In-Place Operations Are Handled Correctly
Patterns work even when destination == source:
'''
[x] In-place fusion works:
v_fma_f32 v0, v1, v2, 1.0 // Defines v0
v_add_f32 v0, 1.0, v0 // Uses v0, writes v0
=> v_fma_f32 v0, v1, v2, 2.0 // Correctly fused!
'''
The pattern system uses **position-aware def-use analysis** to find the correct previous definition.
---
## Testing Your Pattern
### 1. Write Test IR
Create test input:
'''asm
v_fma_f32 v0, a, b, 1.0
v_add_f32 v2, 1.0, v0
'''
### 2. Run the Pass
'''cpp
auto pass = createPeepholeOptimizationPass();
pass->run(module);
'''
### 3. Check Output
Expected output:
'''asm
v_fma_f32 v2, a, b, 2.0
'''
Console should show:
'''
[PeepholePass] Loaded N pattern(s)
[Peephole] Applied YourPatternName
'''
---
## Troubleshooting
### Pattern Not Matching?
**Check:**
1. [x] Instruction opcodes are correct (e.g., 'v_fma_f32', not 'v_fma')
2. [x] Operand order is correct (destination first)
3. [x] Constraints are satisfied
4. [x] Instructions appear in the right order
**Debug:**
'''bash
# Check generated code
cat build/PeepholePatterns.inc | grep "YourPatternName"
# Verbose build
make VERBOSE=1 | grep pattern
'''
### Build Errors?
**Common issues:**
- Syntax error in '.pattern' file -> Check pattern grammar
- Undefined opcode -> Verify opcode exists in GFX ISA
- Missing constraint -> Add required constraints
**Fix:**
'''bash
# Clean rebuild
cd build
rm PeepholePatterns.inc
make tablegen
make
'''
---
## What's Automatic
You **don't** need to:
- [ ] Write C++ matcher code
- [ ] Write C++ rewrite code
- [ ] Register patterns manually
- [ ] Update the pass
- [ ] Handle def-use analysis
- [ ] Remove dead instructions
The system handles all of this automatically! [x]
---
## What You Control
You **do** control:
- [x] Which instructions to match
- [x] What constraints to check
- [x] How constants are folded
- [x] Pattern priority (order in file)
---
## Advanced: Pattern Variants
### Same Pattern for Multiple Types
Create separate patterns for each type:
'''
pattern AddFMAFusion_F32 { ... v_fma_f32 ... }
pattern AddFMAFusion_F16 { ... v_fma_f16 ... }
pattern AddFMAFusion_F64 { ... v_fma_f64 ... }
'''
### Pattern Families
Group related patterns:
'''
//===----------------------------------------------------------------------===//
// FMA Fusion Family
//===----------------------------------------------------------------------===//
pattern AddFMAFusion_F32 { ... }
pattern MulAddFusion_F32 { ... }
pattern SubFMAFusion_F32 { ... }
'''
---
## File Locations
| File | Purpose |
|------|---------|
| 'src/transforms/asm/PeepholePatterns.pattern' | **Your patterns go here** |
| 'build/PeepholePatterns.inc' | Generated C++ code (auto) |
| 'src/transforms/asm/PeepholeOptimizationPass.cpp' | Generic pass (never edit) |
| 'tools/tablegen/GenPatterns.cpp' | Code generator (rarely edit) |
---
## Summary
**To add a pattern:**
1. Edit 'PeepholePatterns.pattern'
2. Run 'make'
3. Done!
**Pattern structure:**
'''
pattern Name {
match { ... } // Instructions to find
constraints { ... } // Conditions to check
rewrite { ... } // How to transform
}
'''
**The system automatically:**
- Parses your pattern
- Generates efficient C++ code
- Registers your pattern
- Applies it during compilation
**You just write the pattern!** !
---
## Next Steps
- See [Architecture Overview](architecture.md) for system architecture
- See [Pattern Grammar Reference](pattern-grammar.md) for complete syntax reference
- See 'src/transforms/asm/PeepholePatterns.pattern' for real examples
---
## Questions?
Common patterns are already implemented. Just copy and modify them for your needs!