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

224 lines
4.9 KiB
Markdown

# Adding Intrinsics
This guide shows you how to add new intrinsics to StinkyTofu.
## What is an Intrinsic?
An intrinsic is a high-level operation that expands into multiple instructions. Examples:
- `ReluF32`: Implements ReLU activation (max(x, 0))
- `ClampF32`: Clamps values to a range [min, max]
- `SigmoidF32`: Applies sigmoid activation function
Intrinsics are automatically available throughout StinkyTofu via the `IntrinsicRegistry`.
## Quick Start
### Step 1: Define Your Intrinsic
Edit `src/ir/logical/Intrinsics.intrinsic`:
```
intrinsic ReluF32 {
arguments {
dest: vgpr_f32
src: vgpr_f32
temp: vgpr_f32
}
body {
v[temp] = v_cmp_gt_f32(v[src], 0.0)
v[dest] = v_cndmask_b32(0.0, v[src], v[temp])
}
comment "ReLU F32 activation"
python_binding true
}
```
### Step 2: Rebuild
```bash
cd build
ninja
```
The build system automatically:
1. Parses `Intrinsics.intrinsic`
2. Compiles it to `intrinsics.st.bc` (binary format)
3. Makes it available to the runtime
### Step 3: Use Your Intrinsic
In TensileLite or any code generator:
```cpp
#include "stinkytofu/ir/logical/IntrinsicRegistry.hpp"
auto& intrinsics = IntrinsicRegistry::instance();
if (intrinsics.hasIntrinsic("ReluF32")) {
auto pattern = intrinsics.lookup("ReluF32");
// Use pattern to generate code
}
```
## Intrinsic Definition Syntax
### Basic Structure
```
intrinsic <Name> {
arguments { ... }
body { ... }
comment "..."
python_binding true/false
}
```
### Arguments Block
List all registers needed, including temporaries:
```
arguments {
dest: vgpr_f32 // Output register
src: vgpr_f32 // Input register
temp: vgpr_f32 // Temporary register
min_val: vgpr_f32 // Another input
}
```
**Important:** You must explicitly list temporary registers. StinkyTofu does not use SSA form, so register allocation happens before intrinsic expansion.
### Body Block
Define the instruction sequence using high-level IR operations:
```
body {
v[temp] = v_max_f32(v[src], v[min_val])
v[dest] = v_min_f32(v[temp], v[max_val])
}
```
**Syntax:**
- Register reference: `v[name]` for VGPR, `s[name]` for SGPR
- Operation: `operation(operands...)`
- Assignment: `dest = operation(...)`
### Metadata
```
comment "Brief description of what this intrinsic does"
python_binding true // Generate Python API (future feature)
```
## Examples
### Simple Intrinsic (ReLU)
```
intrinsic ReluF32 {
arguments {
dest: vgpr_f32
src: vgpr_f32
temp: vgpr_f32
}
body {
v[temp] = v_cmp_gt_f32(v[src], 0.0)
v[dest] = v_cndmask_b32(0.0, v[src], v[temp])
}
comment "ReLU F32 activation"
python_binding true
}
```
### Complex Intrinsic (Clamp)
```
intrinsic ClampF32 {
arguments {
dest: vgpr_f32
src: vgpr_f32
min_val: vgpr_f32
max_val: vgpr_f32
temp: vgpr_f32
}
body {
v[temp] = v_max_f32(v[src], v[min_val])
v[dest] = v_min_f32(v[temp], v[max_val])
}
comment "Clamp F32 to range [min, max]"
python_binding true
}
```
## Testing Your Intrinsic
### Verify Compilation
```bash
cd build
./tools/intrinsic-compiler/intrinsic-compiler
# Should output: Compiled 5 intrinsics to intrinsics.st.bc (1117 bytes)
```
### Test Loading
```bash
./tools/intrinsic-compiler/demo_auto_load
# Should show your intrinsic in the list
```
### Add Unit Test
Edit `tests/unit/IntrinsicFlowTest.cpp`:
```cpp
TEST_F(IntrinsicFlowTest, MyNewIntrinsic) {
auto& registry = IntrinsicRegistry::instance();
ASSERT_TRUE(registry.hasIntrinsic("MyNewIntrinsic"));
auto pattern = registry.lookup("MyNewIntrinsic");
ASSERT_NE(pattern, nullptr);
EXPECT_EQ(pattern->arguments.size(), 3);
EXPECT_EQ(pattern->body.size(), 2);
}
```
## Tips
? **DO:**
- Use clear, descriptive names (`ReluF32`, not `r32`)
- List all temporaries in `arguments`
- Keep intrinsics focused (single operation)
- Add comments explaining what it does
? **DON'T:**
- Use SSA form (StinkyTofu isn't SSA-based)
- Assume register allocation happens during expansion
- Create very large intrinsics (consider breaking them up)
- Use assembly syntax (use high-level IR operations)
## Troubleshooting
**Intrinsic not found at runtime:**
- Rebuild: `ninja` in the build directory
- Check `intrinsics.st.bc` was generated
- Verify syntax in `Intrinsics.intrinsic`
**Parse errors:**
- Check matching braces `{ }`
- Ensure `arguments` and `body` are present
- Verify register syntax: `v[name]` or `s[name]`
**Build errors:**
- Run `ninja clean && ninja` to rebuild from scratch
- Check the TableGen output for syntax errors
## See Also
- [Architecture Overview](architecture.md) - System architecture and intrinsic system overview
- [IntrinsicRegistry API](../../include/stinkytofu/ir/logical/IntrinsicRegistry.hpp) - Runtime API
- Example intrinsics: `src/ir/logical/Intrinsics.intrinsic`