Files
TheRock/rocm-libraries/shared/stinkytofu/docs/user/asm-emitter.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

6.7 KiB

StinkyAsmEmitter User Guide

Overview

'StinkyAsmEmitter' converts StinkyTofu IR (MLIR-style intermediate representation) into actual GPU assembly code that can be processed by assemblers and compilers.

Basic Usage

Simple Assembly Emission

'''cpp #include "stinkytofu/serialization/asm/StinkyAsmEmitter.hpp" #include "stinkytofu/core/stinkytofu.hpp"

using namespace stinkytofu;

// Assuming you have an IRList populated with instructions IRList irlist; // ... populate irlist ...

// Create an emitter with default options StinkyAsmEmitter emitter;

// Emit assembly code as a string std::string assembly = emitter.emit(irlist); std::cout << assembly << std::endl; '''

Emit to Stream

'''cpp // Emit directly to a stream (e.g., file) std::ofstream outFile("output.s"); StinkyAsmEmitter emitter; emitter.emit(outFile, irlist); outFile.close(); '''

Using the Utility Function

'''cpp // Quick conversion using the toAssembly() utility std::string assembly = toAssembly(irlist); '''

Configuration Options

The 'AsmEmitterOptions' struct allows you to customize the assembly output:

'''cpp struct AsmEmitterOptions { bool emitComments = true; // Include header comments bool emitCycleInfo = true; // Emit cycle count information int indent = 4; // Instruction indentation (spaces) bool emitBlankLines = false; // Add blank lines between instruction groups }; '''

Example: Custom Configuration

'''cpp AsmEmitterOptions options; options.emitComments = false; // No header comments options.emitCycleInfo = true; // Show cycle counts options.indent = 8; // Use 8-space indentation

StinkyAsmEmitter emitter(options); std::string assembly = emitter.emit(irlist); '''

Complete Example

Here's a complete example showing how to create instructions and emit them as assembly:

'''cpp #include "stinkytofu/serialization/asm/StinkyAsmEmitter.hpp" #include "stinkytofu/core/stinkytofu.hpp" #include

using namespace stinkytofu;

int main() { // Create a PassContext (manages IR and builders) auto ctx = PassContext::create(GfxArchID::gfx1250);

// Get the IRList and builder
IRList& irlist = ctx->getIRList();
AsmIRBuilder* builder = ctx->getIRBuilder();

// Create a label (builder must be bound to a block, e.g. via setInsertionPoint)
builder->createLabel("loop_start");

// Create a ds_read instruction
StinkyInstruction* inst1 = builder->createStinkyInstruction(
    "ds_read_b128", irlist.end());
inst1->destRegs.push_back(StinkyRegister("v", 0, 4));   // v[0:3]
inst1->srcRegs.push_back(StinkyRegister("v", 40, 1));   // v[40]
inst1->issueCycles   = 4;
inst1->latencyCycles = 52;

// Create another ds_read instruction
StinkyInstruction* inst2 = builder->createStinkyInstruction(
    "ds_read_b128", irlist.end());
inst2->destRegs.push_back(StinkyRegister("v", 4, 4));   // v[4:7]
inst2->srcRegs.push_back(StinkyRegister("v", 40, 1));   // v[40]
inst2->issueCycles   = 4;
inst2->latencyCycles = 52;

// Configure emission options
AsmEmitterOptions options;
options.emitComments  = true;
options.emitCycleInfo = true;
options.indent        = 4;

// Emit assembly
StinkyAsmEmitter emitter(options);
std::string assembly = emitter.emit(irlist);

// Print the result
std::cout << assembly << std::endl;

return 0;

} '''

Expected Output

'''assembly // ================================================== // StinkyTofu Assembly Output // Instructions: 3 // ==================================================

loop_start: ds_read_b128 v[0:3], v[40] // issue=4 latency=52 ds_read_b128 v[4:7], v[40] // issue=4 latency=52 '''

Without Cycle Information

If you don't want cycle count comments:

'''cpp AsmEmitterOptions options; options.emitCycleInfo = false;

StinkyAsmEmitter emitter(options); std::string assembly = emitter.emit(irlist); '''

Output

'''assembly // ================================================== // StinkyTofu Assembly Output // Instructions: 3 // ==================================================

loop_start: ds_read_b128 v[0:3], v[40] ds_read_b128 v[4:7], v[40] '''

Minimal Output (No Comments)

For production assembly without any comments:

'''cpp AsmEmitterOptions options; options.emitComments = false; options.emitCycleInfo = false;

StinkyAsmEmitter emitter(options); std::string assembly = emitter.emit(irlist); '''

Output

'''assembly loop_start: ds_read_b128 v[0:3], v[40] ds_read_b128 v[4:7], v[40] '''

Emitting Single Instructions

You can also emit individual instructions:

'''cpp StinkyInstruction* inst = /* ... get instruction ... */;

AsmEmitterOptions options; options.emitCycleInfo = true;

StinkyAsmEmitter emitter(options); std::string assembly = emitter.emit(*inst); // Output: " ds_read_b128 v[0:3], v[40] // issue=4 latency=52\n" '''

Common Use Cases

1. Debug Output

Use default options with comments and cycle info to understand instruction timing: '''cpp std::cout << toAssembly(irlist) << std::endl; '''

2. Assembly File Generation

Generate clean assembly for the assembler: '''cpp AsmEmitterOptions options; options.emitComments = false; options.emitCycleInfo = false;

std::ofstream asmFile("kernel.s"); StinkyAsmEmitter emitter(options); emitter.emit(asmFile, irlist); asmFile.close(); '''

3. Annotated Assembly for Analysis

Include cycle information for performance analysis: '''cpp AsmEmitterOptions options; options.emitComments = true; options.emitCycleInfo = true;

std::ofstream annotated("kernel_annotated.s"); StinkyAsmEmitter emitter(options); emitter.emit(annotated, irlist); annotated.close(); '''

Register Formats

The emitter handles different register types correctly:

Register Type Example Assembly Output
Vector (single) 'StinkyRegister("v", 5, 1)' 'v[5]'
Vector (range) 'StinkyRegister("v", 0, 4)' 'v[0:3]'
Accumulator 'StinkyRegister("acc", 0, 16)' 'acc[0:15]'
Scalar 'StinkyRegister("s", 10, 1)' 's10'
Literal int 'StinkyRegister(0)' '0'

Integration with Pass Pipeline

The emitter works seamlessly with the pass manager:

'''cpp // Create context and run optimization passes auto ctx = PassContext::create(GfxArchID::gfx1250); IRList& irlist = ctx->getIRList();

// ... populate irlist and run passes ...

PassManager pm; pm.addPass(std::make_unique()); pm.run(*ctx);

// Emit optimized assembly AsmEmitterOptions options; options.emitComments = true; std::string assembly = toAssembly(irlist, options); std::cout << assembly << std::endl; '''

See Also