# How to Use LLVM TableGen for Defining Instruction Sets: A Complete Guide

> Learn to use LLVM TableGen to define instruction sets in .td files and generate C++ backend code with the llvm-tblgen tool. Master this essential LLVM feature today.

- Repository: [LLVM/llvm-project](https://github.com/llvm/llvm-project)
- Tags: how-to-guide
- Published: 2026-09-11

---

**LLVM TableGen is a domain-specific language that lets you define instruction sets in `.td` files and automatically generate C++ backend code via the `llvm-tblgen` tool.**

LLVM TableGen is the code-generation engine at the heart of the `llvm/llvm-project` repository, enabling compiler developers to describe target architectures declaratively. Instead of manually writing repetitive C++ boilerplate for instruction opcodes, operand types, and register classes, you define records in TableGen files that the build system transforms into optimized header files. This approach powers production backends like X86 and RISC-V, making it essential for anyone building a new LLVM target.

## Understanding the LLVM TableGen Architecture

TableGen operates as a two-stage pipeline: a frontend parser that reads `.td` files into an in-memory record database, and a backend code generator that emits C++ source. The frontend implementation lives in `llvm/utils/TableGen/`, while the backend API is exposed through [`llvm/include/llvm/TableGen/TableGenBackend.h`](https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/TableGen/TableGenBackend.h). Common backends such as `-gen-instr-info` and `-gen-asm-writer` reside in `llvm/lib/TableGen/`, each translating specific record types into compiler infrastructure.

## Defining Instruction Sets in TableGen Files

TableGen uses a class-based inheritance system where abstract `class` definitions capture common properties and concrete `def` records instantiate specific instructions.

### Declaring Register Classes

Start by including the core target definitions and defining your register classes. In `llvm/lib/Target/Target.td`, the base `RegisterClass` template establishes the contract for register sets.

```tablegen
//===- MyTargetInstrInfo.td - MyTarget instruction definitions -----*- tablegen -*-===//

include "llvm/Target/Target.td"
include "llvm/Target/InstrInfo.td"
include "llvm/Target/RegInfo.td"

// Define a simple register class
def GPR : RegisterClass<"MyTarget", [i32], 32, (add GPR0, GPR1, GPR2, GPR3)>;

```

The `def GPR` statement creates a register class named **GPR** containing four 32-bit general-purpose registers. The `include` statements pull in generic target definitions from the LLVM core that define the base `Instruction` and `RegisterClass` templates.

### Abstracting Common Instruction Behavior

Create a base class to capture shared properties across your instruction set. This pattern appears throughout production code, such as in `llvm/lib/Target/X86/X86InstrInfo.td`.

```tablegen
// Abstract instruction class – all instructions inherit from this
class InstBase<string InstrName, list<Operand> Ops> : Instruction {
  let Name = InstrName;
  let OperandList = Ops;
}

```

The `InstBase` class inherits from the core `Instruction` class defined in `InstrInfo.td` and parameterizes the instruction name and operand list. The `let` statements override default field values in the parent class.

### Instantiating Concrete Instructions

Concrete instructions use `def` to inherit from your abstract class and provide specific opcodes and operand layouts.

```tablegen
// Concrete instruction definitions
def ADD : InstBase<"ADD", (outs GPR:$dst, ins GPR:$src1, ins GPR:$src2)> {
  let InstCode = 0x01;
}

def SUB : InstBase<"SUB", (outs GPR:$dst, ins GPR:$src1, ins GPR:$src2)> {
  let InstCode = 0x02;
}

```

Here, `def ADD` and `def SUB` instantiate records that TableGen will emit into the generated code. The `(outs ...)` and `(ins ...)` syntax defines the operand constraints, while `InstCode` assigns the binary opcode encoding.

## Generating C++ Headers with llvm-tblgen

Once your `.td` files are complete, invoke the appropriate backend to generate include files. The `llvm-tblgen` binary processes your definitions and emits tables, enumerations, and helper functions.

```bash
llvm-tblgen -gen-instr-info -o MyTargetGenInstrInfo.inc MyTargetInstrInfo.td

```

The `-gen-instr-info` flag selects the instruction information backend. The generated `MyTargetGenInstrInfo.inc` contains an enumeration mapping opcodes to names (`enum MyTargetInstOpcode { ADD = 0, SUB = 1, ... }`), operand descriptor tables, and register class mappings that the backend consumes directly. Other common flags include `-gen-asm-writer` for assembly printers and `-gen-subtarget-info` for processor feature flags.

## Consuming Generated Code in Your Backend

Include the generated file in your target's implementation to access auto-generated definitions. This eliminates manual synchronization between your instruction definitions and C++ logic.

```cpp
#include "MyTargetGenInstrInfo.inc"

bool MyTargetInstrInfo::isBranch(MachineInstr &MI) const {
  switch (MI.getOpcode()) {
  case MyTarget::BR:
  case MyTarget::BRCOND:
    return true;
  default:
    return false;
  }
}

```

The `#include` statement inserts the TableGen-generated enumerations and tables directly into your compilation unit. The `MyTarget::` namespace contains the opcode constants generated from your `def` statements, ensuring type-safe access to instruction identifiers.

## Automating the Build with CMake

Modern LLVM development integrates TableGen through CMake macros defined in `llvm/cmake/modules/TableGen.cmake`. The `add_tablegen_target` function creates custom commands that invoke `llvm-tblgen` with the correct generator flags and dependency tracking.

```cmake
add_tablegen_target(MyTargetTableGen
  SOURCE MyTargetInstrInfo.td
  TARGETS InstrInfo
)
add_dependencies(MyTargetBackend MyTargetTableGen)

```

This CMake configuration ensures that modifying `MyTargetInstrInfo.td` automatically triggers regeneration of `MyTargetGenInstrInfo.inc` before compiling the backend source. The `TableGen.cmake` module handles include paths, generator selection, and dependency management across the build tree.

## Summary

- **LLVM TableGen** uses `.td` files to declaratively define instruction sets, registers, and target metadata without manual C++ coding.
- The `llvm-tblgen` tool processes these files through backends like `-gen-instr-info` to produce optimized C++ headers containing enumerations and lookup tables.
- Generated files reside in `llvm/lib/TableGen/` and provide the instruction descriptors, assembly strings, and encoding information consumed by backend code in `llvm/lib/Target/`.
- Production targets like X86 (`X86InstrInfo.td`) and RISC-V (`RISCVInstrInfo.td`) demonstrate scalable patterns for complex instruction set architectures.
- CMake integration via `TableGen.cmake` automates the generation pipeline during the build process, ensuring headers stay synchronized with TableGen definitions.

## Frequently Asked Questions

### What is the difference between a class and a def in TableGen?

A `class` in TableGen defines an abstract record template with parameters and default values that cannot be instantiated directly in generated code. A `def` creates a concrete, fully instantiated record that appears in the output. Only `def` records are emitted into the C++ headers; `class` definitions serve as reusable blueprints. This distinction is handled by the record database implementation in [`llvm/include/llvm/TableGen/TableGenBackend.h`](https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/TableGen/TableGenBackend.h).

### How do I add a new instruction to an existing LLVM target?

Locate the target's instruction definition file, such as `llvm/lib/Target/X86/X86InstrInfo.td` for X86 or `llvm/lib/Target/RISCV/RISCVInstrInfo.td` for RISC-V. Create a new `def` that inherits from the target's base instruction class (often `Instruction` or a target-specific subclass), specifying the opcode encoding, operand list with register classes, and assembly format string. Rebuild the target to regenerate the instruction info tables via the `-gen-instr-info` backend.

### Where is the llvm-tblgen source code located?

The frontend parser and main driver for `llvm-tblgen` reside in `llvm/utils/TableGen/`. The backend implementation classes and generator logic are located in `llvm/lib/TableGen/`. Header files defining the C++ API for writing custom backends, such as `Record` and `CGRecord`, are found in [`llvm/include/llvm/TableGen/TableGenBackend.h`](https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/TableGen/TableGenBackend.h).

### Can I use TableGen without building all of LLVM?

Yes. While TableGen is part of the `llvm/llvm-project` monorepo, you can build only the `llvm-tblgen` target by running `cmake --build . --target llvm-tblgen` after configuring the LLVM build with CMake. This produces the standalone tool needed to process `.td` files for external projects, independent of the full compiler infrastructure.