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
4.9 KiB
4.9 KiB
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
cd build
ninja
The build system automatically:
- Parses
Intrinsics.intrinsic - Compiles it to
intrinsics.st.bc(binary format) - Makes it available to the runtime
Step 3: Use Your Intrinsic
In TensileLite or any code generator:
#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
cd build
./tools/intrinsic-compiler/intrinsic-compiler
# Should output: Compiled 5 intrinsics to intrinsics.st.bc (1117 bytes)
Test Loading
./tools/intrinsic-compiler/demo_auto_load
# Should show your intrinsic in the list
Add Unit Test
Edit tests/unit/IntrinsicFlowTest.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, notr32) - 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:
ninjain the build directory - Check
intrinsics.st.bcwas generated - Verify syntax in
Intrinsics.intrinsic
Parse errors:
- Check matching braces
{ } - Ensure
argumentsandbodyare present - Verify register syntax:
v[name]ors[name]
Build errors:
- Run
ninja clean && ninjato rebuild from scratch - Check the TableGen output for syntax errors
See Also
- Architecture Overview - System architecture and intrinsic system overview
- IntrinsicRegistry API - Runtime API
- Example intrinsics:
src/ir/logical/Intrinsics.intrinsic