0% found this document useful (0 votes)
217 views65 pages

Building An LLVM Backend

This document provides an overview of how to build an LLVM backend by creating a target called LEG. It discusses the necessary background knowledge, the overall pipeline of an LLVM backend from IR to machine instructions, and how to describe the key components of a target like registers, calling conventions, and instructions using TableGen. The document is intended as a crash course for beginners on getting started with their own LLVM backend. It uses a simple example RISC-like target called LEG to demonstrate the concepts.

Uploaded by

fran
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
217 views65 pages

Building An LLVM Backend

This document provides an overview of how to build an LLVM backend by creating a target called LEG. It discusses the necessary background knowledge, the overall pipeline of an LLVM backend from IR to machine instructions, and how to describe the key components of a target like registers, calling conventions, and instructions using TableGen. The document is intended as a crash course for beginners on getting started with their own LLVM backend. It uses a simple example RISC-like target called LEG to demonstrate the concepts.

Uploaded by

fran
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 65

Building an LLVM Backend

Fraser Cormack
Pierre-Andre Saulais

Codeplay Software
@codeplaysoft

1
Introduction
● Yet another talk about creating a LLVM target?
● LLVM backend crash course, for beginners
– How-tos and tips
– Solution to common problems
● Example target created for this tutorial
– Can be used to see how LLVM works
– Can be used as a skeleton to bootstrap new target

2
Overview
● Part 1: Background
● Part 2: Creating your own target
● Part 3: How-tos for specific tasks
● Part 4: Troubleshooting and tips

3
Part 1

Background

4
What you need to start
● Know a little bit about LLVM IR:
llvm.org/docs/LangRef.html
● xdot.py to visualize graphs when debugging:
github.com/jrfonseca/xdot.py
● Check out and build our LLVM repo from GitHub:
github.com/frasercrmck/llvm-leg
● This informative and well-presented talk!

5
Example target: LEG
● Simple, RISC-like architecture
– Very small subset of ARM
● 12 integer registers (32-bit)
– r0, r1, …, r9, sp (stack pointer), lr (return address)
● Instructions:
– 32-bit arithmetic (add, subtract, multiply, mad)
– 32-bit register move, 16-bit constant moves
– load, store, branch, branch and link

6
Calling convention for LEG
● How values are passed to/from a function
● Arguments in r0 (1st), r1 (2nd), …, r3 (4th)
– Further arguments passed on the stack
● Return value in r0
int foo(int a, int b) {
int result = a + b; // r0 + r1
return result; // r0
} ex1.c

.foo:
add r0, r0, r1
b lr ex1.s

7
The big picture
● Pipeline structure of the backend:
IR → SelectionDAG → MachineDAG → MachineInstr → MCInst
● Transforms your program many times
– Same program, few different representations
– Different instruction namespaces
– Check it out (IR and MI only):
● llc foo.ll -print-after-all 2>&1 > foo.log

8
A look at an IR module
● High-level, linear representation
● Typed values, no registers
● Target-agnostic
– Exceptions: data layout, triple, intrinsics
target datalayout = "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-
i64:32-f64:32-a:0:32-n32"
target triple = "leg"

define i32 @foo(i32 %a, i32 %b) {


%c = add nsw i32 %a, %b
ret i32 %c
} ex1.ll

IR → SelectionDAG → MachineDAG → MachineInstr → MCInst 9


A look at a SelectionDAG graph
● Graph representation
● Operations as nodes
– Mostly target-agnostic
– LEGISD (ISD) namespace
● Dependencies as edges
– Data
– Order (“chain”)
– Scheduling (“glue”)
● Typed values
IR → SelectionDAG → MachineDAG → MachineInstr → MCInst 10
A look at a MachineDAG graph
● Very similar to
SelectionDAG
● Instructions as nodes
– Result of instruction
selection
– LEG namespace
● Similar dependencies
● Similar types

IR → SelectionDAG → MachineDAG → MachineInstr → MCInst 11


Before and after ISel

IR → SelectionDAG → MachineDAG → MachineInstr → MCInst 12


A look at a MachineInstr block
● Untyped, uses register classes instead
● Target-specific instructions (LEG namespace)
– Few exceptions (TargetOpcode namespace)
BB#0: derived from LLVM BB %entry
Live Ins: %R0 %R1

%R0<def> = ADDrr %R0<kill>, %R1<kill> ; %R0, %R1, %R2: GRRegs

Successors according to CFG: BB#1 ex1-mi.txt

IR → SelectionDAG → MachineDAG → MachineInstr → MCInst 13


Part 2

Creating your own target

14
Bits of your ISA you need to describe
● Target machine
– Registers, register classes
– Calling conventions
● Instruction set
– Operands and patterns
– Assembly printing and/or instruction encoding
– Schedule (not part of this talk)
● …

15
TableGen
● C++-style syntax
● Different set of backends
– RegisterInfo, InstrInfo, AsmWriter, ...
● TableGen backends generate .inc files
– Included by your C++ files
● More information:
– llvm.org/docs/TableGen/index.html
– llvm.org/docs/TableGen/BackEnds.html

16
Describing registers with TableGen
● TableGen provides the 'Register' class
– Can use the 'HWEncoding' field for encodings
class LEGReg<bits<16> Enc, string n> : Register<n> {
Let HWEncoding = Enc;
let Namespace = “LEG”;
}

def R0 : LEGReg< 0, “r0” >;


...
def SP : LEGReg< 10, “sp” >;
LEGRegisterInfo.td

● Referenced as “LEG::R0” in C++

17
Describing registers with TableGen
● Can automate trivial definitions
foreach i = 0-9 in {
def R#i : R<i, “r”#i>;
} LEGRegisterInfo.td

● Group registers into register classes


def GRRegs : RegisterClass<”LEG”, [i32], 32,
(add SP, (sequence "R%i", 0, 9))>;
LEGRegisterInfo.td

18
Calling convention lowering:
TableGen
def CC_LEG : CallingConv<[
// Promote i8/i16 arguments to i32
CCIfType<[i8, i16], CCPromoteToType<i32>>,

// The first 4 arguments are passed in registers


CCIfType<[i32], CCAssignToReg<[R0, R1, R2, R3]>>,

// Fall-back, and use the stack


CCIfType<[i32], CCAssignToStack<4, 4>>
]>; LEGCallingConv.td

● Generates functions used in ISelLowering via


function pointers.

19
Calling convention lowering:
The big picture
a b

define i32 @foo(i32 %a, i32 %b) {


%c = add nsw i32 %a, %b
ret i32 %c
} ex1.ll c

● Two target hooks:


– LowerFormalArguments()
– LowerReturn()

20
Calling convention lowering:
The big picture
a b
LowerFormalArguments()
● Lowers incoming arguments into

the DAG
c

LowerReturn()
● Lowers outgoing

return values into


the DAG

21
Calling convention lowering:
LowerFormalArguments()
● Assigns locations to arguments, according to the
TableGen-defined calling convention
● Creates DAG nodes for each location:
– Registers: CopyFromReg nodes
– Stack: frame indices and stack loads
// LEGTargetLowering::LowerFormalArguments()
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(),
getTargetMachine(), ArgLocs,
*DAG.getContext());
CCInfo.AnalyzeFormalArguments(Ins, CC_LEG);
...
LEGISelLowering.cpp
22
Calling convention lowering:
LowerReturn()
● Similar to LowerFormalArguments(), but the other
way around
● Define another, 'RetCC_LEG', TableGen calling
convention
● Call 'AnalyzeReturn()' with it
● Walk the return value locations and issue DAG nodes
● Return LEGISD::RET instruction

23
Calling convention lowering:
LowerCall()
● Hybrid of LowerFormalArguments() and
LowerReturn()
● Not explicitly covered here

24
Describing instructions:
Overview
● Let's start with a simple instruction: ADDrr
● Define it in lib/Target/LEG/LEGInstrInfo.td
● What we need to specify:
– Operands
– Assembly string
– Instruction pattern

25
Describing instructions:
Operands
● List of definitions or outputs ('outs')
● List of uses or inputs ('ins')
● Operand class:
– Register class (e.g. GRRegs)
– Immediate (e.g. i32imm)
– More complex operands (e.g. reg + imm for load/store)
def ADDrr : InstLEG<(outs GRRegs:$dst),
(ins GRRegs:$src1, GRRegs:$src2),
"add $dst, $src1, $src2",
[(set i32:$dst, (add i32:$src1, i32:$src2))]>;
LEGInstrInfo.td

26
Describing instructions:
Selection Patterns
● Matches nodes in the SelectionDAG
– Nodes get turned into MachineInstrs during ISel
– If pattern is omitted, selection needs to be done in C++
● Syntax:
– One pair of parenthesis defines one node
– Nodes have DAG operands, with 'MVT' type (e.g. i32)
– Map DAG operands to MI operands
def ADDrr : InstLEG<(outs GRRegs:$dst),
(ins GRRegs:$src1, GRRegs:$src2),
"add $dst, $src1, $src2",
[(set i32:$dst, (add i32:$src1, i32:$src2))]>;
LEGInstrInfo.td
27
Describing instructions:
Result
● This is what we get after defining the pattern:
● Assembly was generated by the instruction printer
– More on this later

# BB#0: # %entry
add r0, r0, r1
ex1.s

def ADDrr : InstLEG<(outs GRRegs:$dst),


(ins GRRegs:$src1, GRRegs:$src2),
"add $dst, $src1, $src2",
[(set i32:$dst, (add i32:$src1, i32:$src2))]>;
LEGInstrInfo.td

28
Constants
● Compiling this IR produces the following error:
%2 = add nsw i32 %1, 2
ex2.ll

LLVM ERROR: Cannot select: 0x29d4350: i32 = Constant<2> [ID=2]


In function: main

● Specify how to generate ('materialize') constants


● For example, with a 'move' instruction
– E.g. MOVW on ARM for 16-bit constants

29
Constants
● Let's define this move instruction:
def MOVWi16 : InstLEG<(outs GRRegs:$dst),
(ins i32imm:$src),
"movw $dst, $src",
[(set i32:$dst, i32imm:$src)]> {
let isMoveImm = 1;
} LEGInstrInfo.td

● The previous example translates to:


movw r1, #2
add r0, r0, r1
ex2-ADDrr-MOVW.s

30
Constants
● What if instructions take immediates?
def LEGimm8 : Operand<i32>, ImmLeaf<i32, [{
return Imm >= 0 && Imm < 256;
}]>;

def ADDri : InstLEG<(outs GRRegs:$dst),


(ins GRRegs:$src1, i32imm:$src2),
"add $dst, $src1, $src2",
[(set i32:$dst, (add i32:$src1,
LEGimm8:$src2))]>;
LEGInstrInfo.td

add r0, r0, #2


ex2-ADDri.s

31
Matching multiple DAG nodes
● DAG nodes can be nested inside selection patterns
– The output of one node is the input of another
● Allows operations to be combined
– Reduces the number of generated instructions
– Possibly improves performance or power consumption
● Example: multiply and add instruction (ex3.ll)
def MLA : InstLEG<(outs GRRegs:$dst),
(ins GRRegs:$src1, GRRegs:$src2, GRRegs:$src3),
"mla $dst, $src1, $src2, $src3",
[(set i32:$dst,
(add (mul i32:$src1, i32:$src2), i32:$src3))]>;
LEGInstrInfo.td

32
Matching multiple DAG nodes

mul r0, r0, r1


add r0, r0, r2

Without MLA
pattern

With MLA pattern


mla r0, r0, r1, r2
33
Frame lowering
● Hooks invoked when values are stored on the stack
– In debug builds (-O0), but not only
● Adjust the stack at the beginning ('prologue') and
end ('epilogue') of functions
– LEGFrameLowering::emitPrologue()
– LEGFrameLowering::emitEpilogue()
● Usually by increasing or decreasing the stack pointer
● May need to align the stack pointer too

34
Frame lowering
● Example that uses the stack:
%p = alloca i32, align 4
store i32 2, i32* %p
%b = load i32* %p, align 4
%c = add nsw i32 %a, %b
ex4.ll

● Output when compiled with -O2:


sub sp, sp, #4 ; prologue
movw r1, #2
str r1, [sp]
add r0, r0, #2
add sp, sp, #4 ; epilogue
ex4-O2.s

35
Frame lowering
● When compiling with -O0, hooks need to be defined
● Emit load/store instructions with frame indices
● Minimal implementation:
// LEGInstrInfo::storeRegToStackSlot() LEGFrameLowering.cpp
BuildMI(MBB, I, I->getDebugLoc(), get(LEG::STR))
.addReg(SrcReg, getKillRegState(KillSrc))
.addFrameIndex(FrameIndex).addImm(0);

// LEGInstrInfo::loadRegFromStackSlot()
BuildMI(MBB, I, I->getDebugLoc(), get(LEG::LDR), DestReg)
.addFrameIndex(FrameIndex).addImm(0);

// LEGInstrInfo::copyPhysReg()
BuildMI(MBB, I, I->getDebugLoc(), get(LEG::MOVrr), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
36
Instruction printer
● New classes:
– LEGAsmPrinter
– LEGMCInstLower
– An MCAsmStreamer (usually stock)
– LEGInstPrinter
● LEGAsmPrinter works as a gateway to the streamers
● This stages works with MCInsts, lowered from
MachineInstrs by LEGMCInstLower

37
Instruction printer
● TableGen provides the 'AsmString' field:
class InstLEG<... , string asmstr> : Instruction {
let AsmString = asmstr;
...
} LEGInstrFormats.td

def ADDrr : InstLEG<(outs GRRegs:$dst),


(ins GRRegs:$src1, GRRegs:$src2),
“add $dst, $src1, $src2”> {
...
} LEGInstrInfo.td

● LEGInstPrinter::printOperand will be called on each


operand

38
Instruction printer
● LEGInstPrinter::printOperand is given the stream to
print to.
void LEGInstPrinter::printOperand(const MCInst *MI, unsigned No,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(No);
if (Op.isReg()) {
// TableGen generates this function for us from
// LEGRegisterInfo.td
O << getRegisterName(Op.getReg());
return;
}
if (Op.isImm()) {
O << '#' << Op.getImm();
return;
}

} LEGInstPrinter.cpp39
Instruction printer
.text
.file "foo.ll"
.globl foo
.type foo,@function
foo: # @foo
# BB#0: # %entry
add r0, r0, r1
b lr
.Ltmp0:
.size foo, .Ltmp0-foo
ex1.s

● That's it!
● Directives & labels handled for us
– Can emit target-specific syntax if we wish

40
Part 3

How-to for specific tasks

41
Instruction encoding
● A few new classes:
– LEGAsmBackend
– LEGMCCodeEmitter
– LEGObjectWriter
– An MCObjectStreamer (again, stock)
● You will also need your LEGAsmPrinter

42
Instruction encoding
def ADDrr : InstLEG<(outs GRRegs:$dst),
(ins GRRegs:$src1, GRRegs:$src2),
"add $dst, $src1, $src2",
[(set i32:$dst, (add i32:$src1, i32:$src2))]>;
LEGInstrInfo.td

● Example encoding:
31 … 28 27 … 25 24 …21 20 19 … 16 15 … 12 11 ... 4 3…0
1110 000 opcode 0 src1 dst 00000000 src2

● How can we achieve this?

43
Instruction encoding
● TableGen recognises the 'Inst' field:
class InstLEG< ... > : Instruction {
field bits<32> Inst;
...
} LEGInstrFormats.td

● Used to define the binary encoding of each


instruction in TableGen:
def ADDrr : InstLEG< ... > {
let Inst{31-25} = 0b110000;
let Inst{24-21} = 0b1100; // Opcode
let Inst{20} = 0b0;
let Inst{11-4} = 0b00000000;
} LEGInstrInfo.td
44
Instruction encoding
● For operand-based encoding, need bit fields with
the same names as the operands:
def ADDrr : InstLEG<(outs GRRegs:$dst),
(ins GRRegs:$src1, GRRegs:$src2) ... > {
bits<4> src1; bits<4> src2; bits<4> dst;
let Inst{31-25} = 0b110000;
let Inst{24-21} = 0b1100; // Opcode
let Inst{20} = 0b0;
let Inst{19-16} = src1; // Operand 1
let Inst{15-12} = dst; // Destination
let Inst{11-4} = 0b00000000;
let Inst{3-0} = src2; // Operand 2 LEGInstrInfo.td

● LEGMCCodeEmitter::getMachineOpValue() will be
called on each operand
45
Instruction encoding
● Returns the encoding of each operand...
unsigned LEGMCCodeEmitter::
getMachineOpValue(const MCInst &MI, const MCOperand MO,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
if (MO.isReg()) {
return
CTX.getRegisterInfo()->getEncodingValue(MO.getReg());
} if (MO.isImm()) {
return static_cast<unsigned>(MO.getImm());
}

} LEGMCCodeEmitter.cpp

…placed, masked, and shifted into position

46
Relocations and fixups
● For values that require fixing up, record the
relocation into Fixups and return zero.
unsigned LEGMCCodeEmitter::
getMachineOpValue(const MCInst &MI, const MCOperand MO,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
...

assert(MO.isExpr()); // MO must be an expression

const MCExpr *Expr = MO.getExpr();


const MCExpr::ExprKind Kind = Expr->getFixupKind();

Fixups.push_back(MCFixup::Create(0, Expr, Kind));


return 0;
} LEGMCCodeEmitter.cpp

47
Relocations and fixups
● Defining a target-specific fixup:
enum Fixups { LEGFixups.h
fixup_leg_pcrel = FirstTargetFixupKind,

LastTargetFixupKind,
NumTargetFixupKinds = LastTargetFixupKind – FirstTargetFixupKind
};

const MCFixupKindInfo& getFixupKindInfo(MCFixupKind K) const {


const static MCFixupKindInfo I[LEG::NumTargetFixupKinds] = {
// Name Offset Size Flags
{ “fixup_leg_pcrel”, 0, 32, MCFixupKindInfo::FKF_IsPCRel },
};
...
return I[K – FirstTargetFixupKind];
} LEGAsmBackend.cpp
48
Relocations and fixups
● We must then implement some hooks
● These are called at the end once the section layouts
have been finalized
● LEGAsmBackend::processFixupValue()
– Adjusts the fixup value, e.g., splitting the value
across non-contiguous fields
● LEGAsmBackend::applyFixup()
– Patches the fixed-up value into the binary stream

49
Custom SelectionDAG nodes
● To represent target-specific operations in the DAG
– Example: 32-bit immediate move on ARM
● Add a value in the LEGISD enum
● Add to LEGTargetLowering::getTargetNodeName()
● Add TableGen node definition:
def MoveImm32Ty : SDTypeProfile<1, 1, [
SDTCisSameAs<0, 1>, SDTCisInt<0>
]>;

def movei32 : SDNode<"LEGISD::MOVi32", MoveImm32Ty>;


LEGOperators.td

50
Custom DAG lowering
● To implement an operation in a more efficient way
– E.g. by replacing it with a custom DAG node
● To work around target limitations
– E.g. by replacing it with multiple DAG nodes
● Add support to LEGISelLowering::LowerOperation
● Set the operation action to 'custom' on given type:
LEGISelLowering::LEGISelLowering(...) {
(...)
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
}
LEGISelLowering.cpp

51
Creating SelectionDAG nodes
● Simply call DAG.getNode() with these arguments:
– Node ID (e.g. LEGISD::MOVi32), type, operand(s)
● Nodes are target-independent (ISD) or not (LEGISD)
● Use DAG.getMachineNode() in LEGISelDAGToDAG
SDValue LEGTargetLowering::LowerConstant(SDValue Op,
SelectionDAG &DAG) const {
EVT VT = Op.getValueType();
ConstantSDNode *Val = cast<ConstantSDNode>(Op.getNode());
SDValue TargetVal = DAG.getTargetConstant(Val->getZExtVaue(),
MVT::i32);
return DAG.getNode(LEGISD::MOVi32, VT, TargetVal);
}
LEGISelLowering.cpp
52
Lowering to multiple instructions
● Example: implement 32-bit immediate load with
high/low pairs:
– MOVW: load 16-bit 'low' immediate and clear high 16
bits
– MOVT: load 16-bit 'high' immediate
● The final value is defined by the second instruction
● Different ways to implement this:
– At the DAG level, in LEGISelDAGToDAG.cpp
– Using a pseudo-instruction (placeholder)

53
Lowering to multiple instructions
● The two instructions must be ordered:
– Because MOVW clears the high 16 bits
– Achieved by having MOVT reading MOVW's output
● Source and destination registers must be the same
– Use 'Constraints' in Tablegen (unless using pseudo)

def MOVTi16 : InstLEG<(outs GRRegs:$dst),


(ins GRRegs:$src1, i32imm:$src2),
"movw $dst, $src2",
[/* No pattern */]> {
let Constraints = "$src1 = $dst";
} LEGInstrInfo.td

54
Lowering to multiple instructions
● Define a pseudo instruction, can be selected from
the custom DAG node we previously defined
● The pseudo is lowered by a target hook
def MOVi32 : InstLEG<(outs GRRegs:$dst), (ins i32imm:$src), “”,
[(set i32:$dst, (movei32 i32imm:$src))]> {
let isPseudo = 1;
}
LEGInstrInfo.td

bool LEGInstrInfo::expandPostRAPseudo(MI) {
if (MI->getOpcode() != LEG::MOVi32) return false;
BuildMI(..., get(LEG::MOVWi16), Dst).addImm(Lo);
BuildMI(..., get(LEG::MOVTi16), Dst).addReg(Dst).addImm(Hi);
MBB.erase(MI);
return true;
} LEGInstrInfo.cpp
55
Lowering to multiple instructions
● Example IR:
define i32 @foo(i32 %a) #0 {
%c = add nsw i32 %a, 65537 ; 0x00010001
ret i32 %c
}
ex5.ll

; We want to write 0x00010001 to the register.


; Each instruction writes half of the value (16 bits)
movw r1, #1 ; Write 0x00000001 (write low bits, clear high bits)
movt r1, #1 ; Write 0x0001XXXX (write high bits, don't touch low bits)
add r0, r0, r1
b lr ex5.s

56
Part 4

Troubleshooting and resources

57
When something goes wrong
● Find which pass introduces the issue:
– llc -print-after-all
● Find the LLVM source file and category for this pass:
– #define DEBUG_TYPE "codegen-dce"
● Dump the log:
– llc foo.ll -debug-only codegen-dce 2>&1 > foo.log
● Compare (diff) the '-print-after-all' or '-debug-only'
good and bad outputs to see where it goes wrong

58
Debugging LLVM
● MIs, BBs, functions, almost anything → call X.dump()
● DAGs, CFGs → call X.viewGraph() (pops up xdot)
● Or from the terminal: llc foo.ll -view-isel-dags
– Try -view-dag1-combine-dags, -view-legalize-dags, -view-
sched-dags, etc.
● To view graphs, make sure you build LLVM in debug
mode!
– Turn on LLVM_ENABLE_ASSERTIONS (i.e. NDEBUG should
not be defined)

59
“Cannot select”
● When LLVM doesn't know how to map ('lower') a
DAG node to an actual instruction
– Missing pattern in LEGInstrInfo.td?
– Without a pattern, lowering needs to be done in
LEGISelDAGToDag::Select()
● Check the graph!

60
The dog ate my homework
● Why did my code disappear?
– Missing chain/glue in the DAG
– Dead code elimination may have removed it
● DCE does not touch instructions whose value is used
by other instructions:
– Root your use/def chains using a MI that has side-effects
● DCE does not touch instructions with side-effects:
– mayLoad, mayStore, isTerminator, hasSideEffects

61
Useful in-tree resources
● include/llvm/Target/Target*.h
– Shows all target-specific hooks that can be overridden,
with useful comments
● include/llvm/Target/Target*.td
– Shows all TableGen fields you can use in your target files
● include/llvm/CodeGen/ISDOpcodes.h
– Lists all SelectionDAG nodes and descriptions of what
they mean

62
You're not alone!
● "Writing an LLVM Backend" at
llvm.org/docs/WritingAnLLVMBackend.html
● Other backends
● TableGen backend documentation
● LLVM-Dev mailing lists
● Anton Korobeynikov's 2009 and 2012 "Building a
backend in 24 hours" tutorials

63
Summary
● Should be enough to create a very simple target!
● Many things were not covered in this talk:
– Using different types and legalization
– Scheduling
– Intrinsics
– …
● Introduced resources to go further

64
Thank you!
● Q&A
● Happy to answer questions by email too:
[email protected]
[email protected]
● Check out our code from GitHub:
– github.com/frasercrmck/llvm-leg

65

You might also like