agentleFS
mohitmishra786mohitmishra786/low-level-dev-skills/skills/compiler-internals/mlir/SKILL.md

mlir

Skill290 starsChanged 7 months agoMITView on GitHub

MLIR skill for multi-level intermediate representation. Use when writing custom dialects, defining ops with ODS, writing lowering passes, running mlir-opt, or building ML compilers with Torch-MLIR/IREE. Activates on queries about MLIR, dialect, ODS, mlir-opt, linalg, lowering pass, or Torch-MLIR.

The file

Files
SKILL.md

MLIR

Purpose

Guide agents through MLIR (Multi-Level IR): ops, regions, blocks, and values; built-in dialects (arith, func, memref, affine, linalg); writing custom dialects with ODS; lowering passes with ConversionPattern; mlir-opt CLI; and ML compiler use cases (Torch-MLIR, IREE).

When to Use

  • Building a domain-specific compiler IR (graphics, ML, hardware DSL)
  • Lowering high-level ops to LLVM or GPU dialects
  • Writing progressive lowering pipelines (linalg → loops → LLVM)
  • Integrating with IREE or Torch-MLIR for ML deployment
  • Creating reusable transformation passes across dialects
  • Prototyping compiler optimizations at the right abstraction level

Workflow

1. MLIR structure

Module
└── func.func @main()
    └── region
        └── block ^bb0:
            └── operations (ops) producing SSA values

Key concepts:

  • Operation — instruction-like node (arith.addi, memref.load)
  • Region — container of blocks (functions, control flow)
  • Block — CFG node with ordered ops
  • Value — SSA result of an op or block argument

2. Built-in dialects

DialectPurpose
arithInteger/float arithmetic
funcFunction definitions and calls
memrefBuffer abstraction with shapes/strides
affineAffine loop nests, map/set constraints
linalgStructured linear algebra ops
scfStructured control flow (for, if)
llvmLLVM IR dialect for final lowering
gpuGPU kernel launches
// example.mlir
func.func @add(%a: memref<4xf32>, %b: memref<4xf32>, %c: memref<4xf32>) {
  %c0 = arith.constant 0 : index
  %c4 = arith.constant 4 : index
  scf.for %i = %c0 to %c4 step %c1 {
    %av = memref.load %a[%i] : memref<4xf32>
    %bv = memref.load %b[%i] : memref<4xf32>
    %sum = arith.addf %av, %bv : f32
    memref.store %sum, %c[%i] : memref<4xf32>
  }
  return
}

3. mlir-opt CLI

# Parse and print
mlir-opt example.mlir

# Run canonicalization
mlir-opt example.mlir -canonicalize

# Lower affine to scf
mlir-opt affine.mlir -lower-affine

# Full pipeline toward LLVM
mlir-opt input.mlir \
  --linalg-bufferize \
  --convert-linalg-to-loops \
  --convert-scf-to-cf \
  --convert-arith-to-llvm \
  --convert-memref-to-llvm \
  --convert-func-to-llvm \
  -o llvm.mlir

4. ODS — Operation Definition Specification

// MyOps.td
include "mlir/IR/OpBase.td"

def My_Dialect : Dialect {
    let name = "my";
    let summary = "My custom dialect";
}

class My_Op<string mnemonic, list<Trait> traits = []> :
    Op<My_Dialect, mnemonic, traits>;

def AddOp : My_Op<"add", [Pure]> {
    let summary = "Add two values";
    let arguments = (ins AnyType:$lhs, AnyType:$rhs);
    let results = (outs AnyType:$result);
    let assemblyFormat = "$lhs `,` $rhs attr-dict `:` type($result)";
}
# Generate C++ from TableGen
mlir-tblgen -gen-op-defs MyOps.td -I include/ -o MyOps.cpp.inc

5. Custom dialect C++ implementation

#include "mlir/IR/DialectImplementation.h"
#include "MyDialect.h"

#include "MyOps.cpp.inc"

void MyDialect::initialize() {
    addOperations<
#define GET_OP_LIST
#include "MyOps.cpp.inc"
    >();
}

#define GET_OP_CLASSES
#include "MyOps.cpp.inc"

6. Lowering passes

#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
#include "mlir/Transforms/DialectConversion.h"

struct AddOpLowering : OpConversionPattern<my::AddOp> {
    using OpConversionPattern::OpConversionPattern;

    LogicalResult matchAndRewrite(my::AddOp op, OpAdaptor adaptor,
                                  ConversionPatternRewriter &rewriter) const override {
        rewriter.replaceOpWithNewOp<arith::AddIOp>(op, adaptor.getLhs(), adaptor.getRhs());
        return success();
    }
};

void populateLoweringPatterns(RewritePatternSet &patterns) {
    patterns.add<AddOpLowering>(patterns.getContext());
}

// In pass:
mlir::ConversionTarget target(*context);
target.addIllegalDialect<my::MyDialect>();
target.addLegalDialect<arith::ArithDialect>();

if (failed(applyPartialConversion(module, target, std::move(patterns))))
    signalPassFailure();

7. linalg for ML compilers

%0 = linalg.matmul ins(%A, %B : tensor<128x256xf32>, tensor<256x64xf32>)
                   outs(%C : tensor<128x64xf32>) -> tensor<128x64xf32>

Lowering path: linalg → scf loops → affine → llvm

8. Torch-MLIR and IREE

# Torch-MLIR: PyTorch → MLIR
python -m torch_mlir.tools.import-onnx --onnx-model model.onnx -o model.mlir

# IREE: MLIR → GPU/CPU executable
iree-compile --iree-hal-target-backends=llvm-cpu model.mlir -o model.vmfb
iree-run-module --module=model.vmfb --function=main

Common Problems

SymptomCauseFix
Dialect not registeredMissing registerDialectRegister in tool/pass init
ODS build failureTableGen include pathCheck -I for mlir/IR/OpBase.td
Lowering incompleteIllegal ops remainDebug with --mlir-print-ir-after-failure
Type mismatch in patternWrong adaptor typesUse OpAdaptor typed accessors
mlir-opt crashInvalid IRRun -verify-each
Empty function after loweringAll ops illegal, none convertedAdd missing patterns

Related Skills

  • skills/compiler-internals/llvm-passes — LLVM pass equivalents
  • skills/compiler-internals/compiler-frontend — AST to MLIR import
  • skills/compiler-internals/jit-compilation — JIT compiled MLIR→LLVM
  • skills/compilers/llvm — LLVM IR output target
  • skills/gpu/cuda — GPU dialect lowering targets
  • skills/gpu/triton-lang — alternative GPU kernel IR

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.