CtrlK
BlogDocsLog inGet started
Tessl Logo

himank-test/tessl-llvm

LLVM 22.x tile for building compilers, language runtimes, and out-of-tree tooling

88

1.23x
Quality

83%

Does it follow best practices?

Impact

96%

1.23x

Average score across 5 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

SKILL.mdskills/new-target/

name:
new-target-backend
description:
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.

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.

skills

new-target

AUDIT.md

tile.json