CtrlK
BlogDocsLog inGet started
Tessl Logo

new-target-backend

Add a new target backend skeleton to LLVM 22. Covers CMake registration, TargetInfo, TargetMachine, MCTargetDesc, minimal TableGen register/instruction defs, and wiring into the LLVM build.

67

Quality

80%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Fix and improve this skill with Tessl

tessl review fix ./tiles/tessl-llvm/skills/new-target/SKILL.md
SKILL.md
Quality
Evals
Security

Skill: Add a New Target Backend Skeleton (LLVM 22)

Use this skill when the user wants to add a brand-new ISA target to LLVM 22. This produces a compilable, registered skeleton — not a production backend. Extend each layer incrementally after the skeleton builds.


Step 0 — Choose a name

Pick a short, capitalized name: MyISA. This will be used as:

  • Directory: llvm/lib/Target/MyISA/
  • Namespace: llvm (all LLVM code lives here)
  • CMake component: MyISACodeGen, MyISADesc, MyISAInfo, MyISAAsmParser
  • Triple arch string: myisa (lower-case, used in target triples)
  • Register call: LLVMInitializeMyISATarget()

Step 1 — Register the target in root CMakeLists.txt

# llvm/CMakeLists.txt — add to LLVM_ALL_TARGETS list
set(LLVM_ALL_TARGETS
  ...
  MyISA
  ...
)

And in llvm/include/llvm/Config/llvm-config.h.cmake (auto-generated, handled by cmake) — no manual edit needed; cmake regenerates it.


Step 2 — Create the target directory structure

llvm/lib/Target/MyISA/
├── CMakeLists.txt
├── MyISA.h                   # Forward declarations, target init prototype
├── MyISA.td                  # Top-level TableGen file
├── MyISARegisterInfo.td      # Register definitions
├── MyISAInstrInfo.td         # Instruction definitions (stub)
├── MyISATargetMachine.h
├── MyISATargetMachine.cpp
├── MyISARegisterInfo.h
├── MyISARegisterInfo.cpp
├── MyISAInstrInfo.h
├── MyISAInstrInfo.cpp
├── MyISAFrameLowering.h
├── MyISAFrameLowering.cpp
├── MyISAISelLowering.h
├── MyISAISelLowering.cpp
├── MyISASubtarget.h
├── MyISASubtarget.cpp
└── MCTargetDesc/
    ├── CMakeLists.txt
    ├── MyISAMCAsmInfo.h
    ├── MyISAMCAsmInfo.cpp
    ├── MyISAMCTargetDesc.h
    └── MyISAMCTargetDesc.cpp

Step 3 — TableGen: register and instruction stubs

MyISARegisterInfo.td

class MyISAReg<bits<5> num, string name> : Register<name> {
  let HWEncoding{4-0} = num;
  let Namespace = "MyISA";
}

// General purpose registers
def R0  : MyISAReg<0,  "r0">;
def R1  : MyISAReg<1,  "r1">;
// ... add R2-R31 as needed

def GPR : RegisterClass<"MyISA", [i32], 32, (add R0, R1)>;

MyISAInstrInfo.td

// Minimal — just enough to compile
class MyISAInst<dag outs, dag ins, string asmstr, list<dag> pattern>
    : Instruction {
  let Namespace = "MyISA";
  let OutOperandList = outs;
  let InOperandList  = ins;
  let AsmString      = asmstr;
  let Pattern        = pattern;
}

// Example: NOP
def NOP : MyISAInst<(outs), (ins), "nop", []>;

MyISA.td (top-level)

include "llvm/Target/Target.td"
include "MyISARegisterInfo.td"
include "MyISAInstrInfo.td"

def MyISAInstrInfo : InstrInfo;

def MyISA : Target {
  let InstructionSet = MyISAInstrInfo;
}

Step 4 — MCTargetDesc

MyISAMCTargetDesc.h

#ifndef LLVM_LIB_TARGET_MYISA_MCTARGETDESC_MYISAMCTARGETDESC_H
#define LLVM_LIB_TARGET_MYISA_MCTARGETDESC_MYISAMCTARGETDESC_H

#include "llvm/Support/DataTypes.h"
#include <memory>

namespace llvm {
class MCAsmInfo;
class MCContext;
class MCInstrInfo;
class MCRegisterInfo;
class MCSubtargetInfo;
class MCTargetOptions;
class Target;

Target &getTheMyISATarget();

} // namespace llvm

// Generated by TableGen:
#define GET_REGINFO_ENUM
#include "MyISAGenRegisterInfo.inc"
#define GET_INSTRINFO_ENUM
#include "MyISAGenInstrInfo.inc"

#endif

MyISAMCTargetDesc.cpp

#include "MyISAMCTargetDesc.h"
#include "MyISAMCAsmInfo.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/FormattedStream.h"

using namespace llvm;

#define GET_INSTRINFO_MC_DESC
#include "MyISAGenInstrInfo.inc"
#define GET_REGINFO_MC_DESC
#include "MyISAGenRegisterInfo.inc"
#define GET_SUBTARGETINFO_MC_DESC
#include "MyISAGenSubtargetInfo.inc"

static MCInstrInfo *createMyISAMCInstrInfo() {
  MCInstrInfo *X = new MCInstrInfo();
  InitMyISAMCInstrInfo(X);
  return X;
}

static MCRegisterInfo *createMyISAMCRegisterInfo(const Triple &TT) {
  MCRegisterInfo *X = new MCRegisterInfo();
  InitMyISAMCRegisterInfo(X, MyISA::R0); // return address register
  return X;
}

static MCSubtargetInfo *
createMyISAMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) {
  return createMyISAMCSubtargetInfoImpl(TT, CPU, /*TuneCPU=*/CPU, FS);
}

extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMyISATargetMC() {
  TargetRegistry::RegisterMCInstrInfo(getTheMyISATarget(),
                                      createMyISAMCInstrInfo);
  TargetRegistry::RegisterMCRegInfo(getTheMyISATarget(),
                                    createMyISAMCRegisterInfo);
  TargetRegistry::RegisterMCSubtargetInfo(getTheMyISATarget(),
                                          createMyISAMCSubtargetInfo);
}

MCTargetDesc/CMakeLists.txt

add_llvm_component_library(LLVMMyISADesc
  MyISAMCAsmInfo.cpp
  MyISAMCTargetDesc.cpp

  LINK_COMPONENTS
  MC
  Support
  TargetParser

  ADD_TO_COMPONENT MyISA
)

Step 5 — TargetMachine

MyISATargetMachine.h

#ifndef LLVM_LIB_TARGET_MYISA_MYISATARGETMACHINE_H
#define LLVM_LIB_TARGET_MYISA_MYISATARGETMACHINE_H

#include "MyISASubtarget.h"
#include "llvm/Target/TargetMachine.h"

namespace llvm {

class MyISATargetMachine : public LLVMTargetMachine {
  MyISASubtarget Subtarget;
public:
  MyISATargetMachine(const Target &T, const Triple &TT, StringRef CPU,
                     StringRef FS, const TargetOptions &Options,
                     std::optional<Reloc::Model> RM,
                     std::optional<CodeModel::Model> CM,
                     CodeGenOptLevel OL, bool JIT);

  const MyISASubtarget *getSubtargetImpl(const Function &) const override {
    return &Subtarget;
  }

  TargetPassConfig *createPassConfig(PassManagerBase &PM) override;
};

} // namespace llvm
#endif

MyISATargetMachine.cpp

#include "MyISATargetMachine.h"
#include "MCTargetDesc/MyISAMCTargetDesc.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/PassRegistry.h"

using namespace llvm;

extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMyISATarget() {
  RegisterTargetMachine<MyISATargetMachine> X(getTheMyISATarget());
}

static const char *MyISADataLayout =
    "e-m:e-p:32:32-i64:64-n32-S128"; // adjust for your ISA

MyISATargetMachine::MyISATargetMachine(
    const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
    const TargetOptions &Options, std::optional<Reloc::Model> RM,
    std::optional<CodeModel::Model> CM, CodeGenOptLevel OL, bool JIT)
    : LLVMTargetMachine(T, MyISADataLayout, TT, CPU, FS, Options,
                        RM.value_or(Reloc::Static),
                        CM.value_or(CodeModel::Small), OL),
      Subtarget(TT, CPU, FS, *this) {}

namespace {
class MyISAPassConfig : public TargetPassConfig {
public:
  MyISAPassConfig(MyISATargetMachine &TM, PassManagerBase &PM)
      : TargetPassConfig(TM, PM) {}

  bool addInstSelector() override {
    // TODO: addPass(createMyISAISelDag(...));
    return false;
  }
};
} // namespace

TargetPassConfig *MyISATargetMachine::createPassConfig(PassManagerBase &PM) {
  return new MyISAPassConfig(*this, PM);
}

Step 6 — Register target with TargetRegistry

In MyISA.h / MCTargetDesc/MyISAMCTargetDesc.cpp, expose getTheMyISATarget():

// MyISA.h
namespace llvm {
Target &getTheMyISATarget();
}

// MyISATargetInfo.cpp  (new file, add to CMakeLists.txt under TargetInfo/)
#include "llvm/MC/TargetRegistry.h"
namespace llvm {
Target &getTheMyISATarget() {
  static Target TheMyISATarget;
  return TheMyISATarget;
}
} // namespace llvm

extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMyISATargetInfo() {
  RegisterTarget<Triple::myisa, /*HasJIT=*/false> X(
      getTheMyISATarget(), "myisa", "MyISA (32-bit)", "MyISA");
}

Add the myisa arch to llvm/include/llvm/TargetParser/Triple.h (the ArchType enum) and the string mapping in Triple.cpp.


Step 7 — Root CMakeLists.txt for the target

# llvm/lib/Target/MyISA/CMakeLists.txt
add_llvm_component_group(MyISA)

set(LLVM_TARGET_DEFINITIONS MyISA.td)

tablegen(LLVM MyISAGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM MyISAGenInstrInfo.inc    -gen-instr-info)
tablegen(LLVM MyISAGenSubtargetInfo.inc -gen-subtarget)
tablegen(LLVM MyISAGenAsmWriter.inc    -gen-asm-writer)
add_public_tablegen_target(MyISACommonTableGen)

add_llvm_component_library(LLVMMyISACodeGen
  MyISAFrameLowering.cpp
  MyISAInstrInfo.cpp
  MyISAISelLowering.cpp
  MyISARegisterInfo.cpp
  MyISASubtarget.cpp
  MyISATargetMachine.cpp

  LINK_COMPONENTS
  Analysis
  AsmPrinter
  CodeGen
  CodeGenTypes
  Core
  MC
  MyISADesc
  MyISAInfo
  SelectionDAG
  Support
  Target
  TransformUtils

  ADD_TO_COMPONENT MyISA
)

add_subdirectory(MCTargetDesc)
add_subdirectory(TargetInfo)

Step 8 — Build and verify registration

cmake --build build --target LLVMMyISACodeGen -j$(nproc)

# Verify the target appears in llc/opt
llc --version | grep myisa
opt --version  | grep myisa  # opt doesn't list targets, but no crash = good

# Attempt codegen (will fail gracefully without an isel):
echo 'define void @f() { ret void }' | \
  llc -march=myisa -

What to build next (after skeleton)

  1. ISelLowering — lower LLVM IR SDNodes to MyISA SDNodes.
  2. Instruction selection — either SelectionDAG .td patterns or GlobalISel GISelCombiner + Legalizer.
  3. AsmPrinter — emit .s text output.
  4. ELF/object writer — emit relocatable object files.
  5. AsmParser — accept MyISA assembly text.

Common mistakes to avoid

  • Do NOT forget to add the arch to Triple.h and Triple.cpp — the target won't be found by llc -march=.
  • Do NOT omit LLVMInitializeMyISATargetInfo() / LLVMInitializeMyISATargetMC() — they must all be called for the target to be usable.
  • Do NOT use Reloc::PIC_ without implementing PIC support in ISelLowering — default to Reloc::Static in the skeleton.
  • ALWAYS add ADD_TO_COMPONENT MyISA in all sub-library CMakeLists.txt so llvm_map_components_to_libnames(MyISA) works for downstream users.
  • ALWAYS run tablegen targets before the main library target — the .inc files must exist at compile time.
Repository
hbarve1/tessl-llvm
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.