Reference: LLVM Code Generator
SelectionDAG
.MachineInstr
s;To work on any of the above components, it is necessary to be familiar with the two classes:
include/llvm/Target/
. Defines the Target Description classes. They capture important properties about various aspects of the machine, independently of how they will be used.
include/llvm/CodeGen/
: Define Machine Code Description classes used to represent the code being generated for a target, both SSA form and Non-SSA form representation for machine code. These classes are intended to be abstract enough to represent the machine code for any target machine.
At this level, concepts like “constant pool entries” and “jump tables” are explicitly exposed.
include/llvm/MC/
: define classes and algorithms used to represent code at the object file level, the MC layer. These classes represent assembly level contructs like labels, sections, and instructions. At this level, concepts like “constant pool entries” and “jump tables” don’t exist.
lib/CodeGen/
: Define the target-independent algorithms used to implement various phases of native code generation.
lib/Target/
: Implement the abstract target description interfaces for particular targets. These machine descriptions make use of the components provided by LLVM, and can optionally provide custom target-specific passes, to build complete code generators for a specific target.
lib/ExecutionEngine/JIT
: defines the target independent JIT components. The LLVM JIT is completely target independent. It uses the TargetJITInfo structure to interface for target-specific issues.
Note: need to focus on the following parts:
code emission
prolog/epilog code insertion
.Two pieces: high-level interface to the code generator & set of reusable components that can be used to build target-specific backends.
Two most important interfaces, TargetMachine and DataLayout, are the only ones that are required to be defined for a backend to fit into the LLVM system, but the others must be defined if the reusable code generator components are going to be used.
This design allows to implement radically different code generator that do not make use of any of the built-in components. This could be required for radically different target that do not fit into the LLVM machine description model: FPGAs for example.
Located in include/llvm/Target/
. Provides an abstract description of the target machine independent of any particular client. Designed to capture the abstract properties of the target, such as the instructions and registers it has. It does not incorporate any particular pieces of code generation algorithms.
TargetMachine
DataLayout
TargetLowering
TargetRegisterInfo
TargetInstrInfo
TargetFrameLowering
TargetSubtarget
TargetJITInfo
LLVM code is translated to a machine specific representation formed out of instances of the following classes:
MachineFunction
.MachineBasicBlock
.MachineInstr
.However, this reprentation is completely target agnostic, representing instructions in their most abstract form: an opcode and a series of operands. The representation is designed to support both an SSA form for machine code, as well as a register allocated, non-SSA form.
Used to represent target machine instructions. Only keep track of an opcode number and a set of operands.
TargetInstrInfo
class.MachineInstr
’s are initially selected in SSA-form, and are maintained in SSA-form until register allocation happens.To create a MachineInstr
, use BuildMI
functions (in include/llvm/CodeGen/MachineInstrBuilder.h
):
// Create a 'DestReg = mov 42' (rendered in X86 assembly as 'mov DestReg, 42')
// instruction and insert it at the end of the given MachineBasicBlock.
const TargetInstrInfo &TII = ...
MachineBasicBlock &MBB = ...
DebugLoc DL;
MachineInstr *MI = BuildMI(MBB, DL, TII.get(X86::MOV32ri), DestReg).addImm(42);
// Create the same instr, but insert it before a specified iterator point.
MachineBasicBlock::iterator MBBI = ...
BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32ri), DestReg).addImm(42);
// Create a 'cmp Reg, 0' instruction, no destination reg.
MI = BuildMI(MBB, DL, TII.get(X86::CMP32ri8)).addReg(Reg).addImm(42);
// Create an 'sahf' instruction which takes no operands and stores nothing.
MI = BuildMI(MBB, DL, TII.get(X86::SAHF));
// Create a self looping branch instruction.
BuildMI(MBB, DL, TII.get(X86::JNE)).addMBB(&MBB);
Contains a list of MachineInstr
instances.
Roughly corresponds to the LLVM IR basic block, but there can be one to many mapping: one LLVM basic block map to multiple machine basic blocks.
Has a getBasicBlock
method, which returns the LLVM basic block that it comes from.
Contains:
MachineBasicBlocks
instances,MachineConstantPool
MachineFrameInfo
, represents an abstract stack frame until prolog/epilog is inserted.MachineFunctionInfo
MachineRegisterInfo
Corresponds one-to-one with the LLVM IR function input.
MachineFunctionPass
:
~ 265 passes lives in llvm/include/llvm/CodeGen
and llvm/lib/Target/*
Initialization code in llvm/lib/CodeGen/CodeGen.cpp
// llvm/lib/CodeGen/CodeGen.cpp
/// initializeCodeGen - Initialize all passes linked into the CodeGen library.
void llvm::initializeCodeGen(PassRegistry &Registry) {
initializeAtomicExpandPass(Registry);
initializeBranchFolderPassPass(Registry);
initializeBranchRelaxationPass(Registry);
initializeCFIInstrInserterPass(Registry);
initializeCheriBoundAllocasPass(Registry);
initializeCodeGenPreparePass(Registry);
initializeDeadMachineInstructionElimPass(Registry);
initializeDetectDeadLanesPass(Registry);
initializeDwarfEHPreparePass(Registry);
initializeEarlyIfConverterPass(Registry);
initializeEarlyIfPredicatorPass(Registry);
initializeEarlyMachineLICMPass(Registry);
initializeEarlyTailDuplicatePass(Registry);
initializeExpandMemCmpPassPass(Registry);
initializeExpandPostRAPass(Registry);
initializeFEntryInserterPass(Registry);
initializeFinalizeISelPass(Registry);
initializeFinalizeMachineBundlesPass(Registry);
initializeFuncletLayoutPass(Registry);
initializeGCMachineCodeAnalysisPass(Registry);
initializeGCModuleInfoPass(Registry);
initializeHardwareLoopsPass(Registry);
initializeIfConverterPass(Registry);
initializeImplicitNullChecksPass(Registry);
initializeIndirectBrExpandPassPass(Registry);
initializeInterleavedLoadCombinePass(Registry);
initializeInterleavedAccessPass(Registry);
initializeLiveDebugValuesPass(Registry);
initializeLiveDebugVariablesPass(Registry);
initializeLiveIntervalsPass(Registry);
initializeLiveRangeShrinkPass(Registry);
initializeLiveStacksPass(Registry);
initializeLiveVariablesPass(Registry);
initializeLocalStackSlotPassPass(Registry);
initializeLowerIntrinsicsPass(Registry);
initializeMIRCanonicalizerPass(Registry);
initializeMIRNamerPass(Registry);
initializeMachineBlockFrequencyInfoPass(Registry);
initializeMachineBlockPlacementPass(Registry);
initializeMachineBlockPlacementStatsPass(Registry);
initializeMachineCSEPass(Registry);
initializeMachineCombinerPass(Registry);
initializeMachineCopyPropagationPass(Registry);
initializeMachineDominatorTreePass(Registry);
initializeMachineFunctionPrinterPassPass(Registry);
initializeMachineLICMPass(Registry);
initializeMachineLoopInfoPass(Registry);
initializeMachineModuleInfoPass(Registry);
initializeMachineOptimizationRemarkEmitterPassPass(Registry);
initializeMachineOutlinerPass(Registry);
initializeMachinePipelinerPass(Registry);
initializeModuloScheduleTestPass(Registry);
initializeMachinePostDominatorTreePass(Registry);
initializeMachineRegionInfoPassPass(Registry);
initializeMachineSchedulerPass(Registry);
initializeMachineSinkingPass(Registry);
initializeMachineVerifierPassPass(Registry);
initializeOptimizePHIsPass(Registry);
initializePEIPass(Registry);
initializePHIEliminationPass(Registry);
initializePatchableFunctionPass(Registry);
initializePeepholeOptimizerPass(Registry);
initializePostMachineSchedulerPass(Registry);
initializePostRAHazardRecognizerPass(Registry);
initializePostRAMachineSinkingPass(Registry);
initializePostRASchedulerPass(Registry);
initializePreISelIntrinsicLoweringLegacyPassPass(Registry);
initializeProcessImplicitDefsPass(Registry);
initializeRABasicPass(Registry);
initializeRAGreedyPass(Registry);
initializeRegAllocFastPass(Registry);
initializeRegUsageInfoCollectorPass(Registry);
initializeRegUsageInfoPropagationPass(Registry);
initializeRegisterCoalescerPass(Registry);
initializeRenameIndependentSubregsPass(Registry);
initializeSafeStackLegacyPassPass(Registry);
initializeScalarizeMaskedMemIntrinPass(Registry);
initializeShrinkWrapPass(Registry);
initializeSlotIndexesPass(Registry);
initializeStackColoringPass(Registry);
initializeStackMapLivenessPass(Registry);
initializeStackProtectorPass(Registry);
initializeStackSlotColoringPass(Registry);
initializeTailDuplicatePass(Registry);
initializeTargetPassConfigPass(Registry);
initializeTwoAddressInstructionPassPass(Registry);
initializeUnpackMachineBundlesPass(Registry);
initializeUnreachableBlockElimLegacyPassPass(Registry);
initializeUnreachableMachineBlockElimPass(Registry);
initializeVirtRegMapPass(Registry);
initializeVirtRegRewriterPass(Registry);
initializeWasmEHPreparePass(Registry);
initializeWinEHPreparePass(Registry);
initializeXRayInstrumentationPass(Registry);
}
void LLVMInitializeCodeGen(LLVMPassRegistryRef R) {
initializeCodeGen(*unwrap(R));
}
reference LLVM CodeGen - Code Emission
Code emission is responsible for lowering from code generator abstractions (MachineFunction
, MachineInstr
, etc) down the the abstractions used by the MC Layer (MCInst
, MCStreamer
, etc). This is done by the following classes:
AsmPrinter
class.
AsmPrinter
, such as SparcAsmPrinter
, MipsAsmPrinter
.td
files used to generate instruction printer automatically.
add $dst, $src, $src2
<target>MCInstLower.cpp
: code that lowers a MachineInstr
to an MCInst
TargetLoweringObjectFile
classMC layer works at the level of abstraction of object files, it does not have a notion of functions, global variables, etc. Instead, it thinks about labels, directives, and instructions.
More info at MC Layer
CodeGen [MachineInstr
] –> MC [MCInst
] –> Object [ISA]
Target.td
TargetSelectionDAT.td
XXXInstrFormats.td
XXXInstrInfo.td
XXX.td
References: [](#) Relocation basics Relocation Sections in ELF Relocation during Linking in LLD ELFRelocationEntry // llvm/include/llvm/MC/MCELFObjectWriter.h struct ELFRelocationEntry { uint64_t Offset; // Where is the relocation. const MCSymbolELF *Symbol; // The symbol to relocate with. unsigned Type; // The type of the relocation. uint64_t Addend; // The addend to use. const MCSymbolELF *OriginalSymbol; // The original value of Symbol if we changed it.
Reference [lld/ELF/Driver.cpp] lld/ELF/LinkerScript.cpp lld xxx.o -o xxx.exe lld –verbose How to determine which sections to write to exe LinkerDriver::link<ELFT> is the driving entry for the link to prepare different sections needed for the final executable. inputSecions hold a list of all sections from all object files. outputSections tracking sections in/out // lld/ELF/Driver.cpp // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed.
Q&A/Top Where is the return address being spilled? Where is the allocated stack frame being ‘destroyed’? Reference reference llvm/lib/CodeGen/PrologEpilogInserter.cpp Pass overview PEI (Prolog Epilog Inserter) pass creation: // void TargetPassConfig::addMachinePasses() { //... // Insert prolog/epilog code. Eliminate abstract frame index references... if (getOptLevel() != CodeGenOpt::None) { addPass(&PostRAMachineSinkingID); // sink COPY instructions which should be handled after RA. addPass(&ShrinkWrapID); // determine where the safe point to insert the prologue and epilogue.
References: llvm/lib/CodeGen/TargetPassConfig.cpp TargetPassConfig::addCoreISelPasses() will create the core passes needed for instruction selection in LLVM. It will choose one of three instruction selectors (FastISel, SelectionDAG, or GlobalISel) for the compilation, whichever is available or meets the configuration options. add finalization pass addPass(&FinalizeISelID); to expand pseudo-instructions emitted by ISel. print and verify the instructions selected machine code: printAndVerify("After Instruction Selection");. code TargetPassConfig::addCoreISelPasses() ```C++
References: Target Code Generation Class of variables: Temporary variables: Local variables: Global variables: Stack Frame Layout Frame pointer (FP): ptr to beginning of stack frame (fixed) Stack pointer (SP): ptr to end of stack (can move). Stack frame hold space for: formals local variables return addresses (maybe) dynamic link (ptr to calling stack frame) (maybe) static link (ptr to lexically-enclosing stack frame) other run-time data (e.
References: ELF specification ELF Tutorial (i386). 目的档格式(ELF). two ELF views: linking and execution. a list of widely used sections in ELF. Linker and Libraries Guide – Object File Format CTOR/DTOR CFI (Call Frame Information) directives .cfi_personality directives, etc. Exception Frames .eh_frame section. Format is similar to .debug_frame section specified by DWARF standard. The .eh_frame and .eh_framehdr describes the call frames
References: LLVM Language Reference – Calling Conventions Writing an llvm backend – Calling Convention TableGen for Calling Convention TargetCallingConv.td Calling convention from writing an llvm backend: To support target-specific calling conventions, _XXX_GenCallingConv.td uses interfaces (such as CCIfType and CCAssignToReg) that are defined in lib/Target/TargetCallingConv.td. TableGen uses the target descriptor file _XXX_GenCallingConv.td to generate the header file _XXX_GenCallingConv.inc, which is typically included in _XXX_ISelLowering.cpp. The inferfaces in _XXX_GenCalllingConv.
References: Assemblers, Linkers, and Loaders, slides from Hakim Weatherspoon, Cornell, 2013. linkers and loaders, blog post. How to add a new target to LLD, slides from Peter Smith, Linaro, 2016. a figure of calling dynamic libraries over PLT/GOT Linker/Loader: binds more abstract names to more concrete names. Example: getline –> “the location 612 bytes from the beginning of the executable code in module iosys”. “the location 450 bytes beyond the beginning of the static data from this module” –> numberic address.
Q & A Where is the symbol table section being composed and written to the object file? References: llvm-mc LLVM the x86 disassembler LLVM CodeGen The LLVM MC Project This section is mostly from: llvm-mc, with partial info from LLVM CodeGen. Instruction Printer. MCInstPrint: MCInst -> textual representation. Not aware of sections/directives, so independent of object file format. A new lowering pass: MachineInstr -> MCInst.
Q&A How does it handle .got addressing? References: Machine IR Language Reference Welcome to the back end: the LLVM Machine Representation Tasks for LLVM Machine Representation: Resource Allocation: registers, stack space, … Lowering: ABI, Exception Handling, Debug Info, … Optimization: Peephole, Instruction/Block Scheduling, .. Basics Pass Manage Setup Pass manager pipeline is setup in TargetPassConfig. Target overrides methods to add, remove or replace passes.
Reference 1 https://web.stanford.edu/class/archive/cs/cs143/cs143.1128/lectures/17/Slides17.pdf Silhouette: https://github.com/jzhou76/Silhouette/blob/silhouette_llvm9/lib/Target/ARM/ARMSilhouetteLabelCFI.cpp#L59 https://github.com/jzhou76/Silhouette/blob/silhouette_llvm9/lib/Target/ARM/ARMSilhouetteSFI.cpp#L148 https://github.com/jzhou76/Silhouette/blob/silhouette_llvm9/lib/Target/ARM/ARMSilhouetteSTR2STRT.cpp#L65 reference ↩
Assembler Directives Reference: GNU AS - assembler directives Pseudo Op-Codes .cpload directives, etc. CFI (Call Frame Information) directives .cfi_personality directives, etc. Exception Frames .eh_frame section. TI - MSP430 - Assembler Directives Assembler directives supply data to the program and control the assembly process. Directives are commands that are part of the assmbler syntax but are not related to the processor ISA. Assembler directives enable you to do the following:
Q&A How to create a new section and store instruction and data’s metadata? like a new symbol table section? how to implement a new calling convention? Intrinsics? what is tablegen .td file? How it is used in LLVM infra? A domain specific language that describes functional modules and can be used to generate C++ code autotmatically. In LLVM, current usage of TableGen is to generate LLVM code generation code, and clang diagnostics and attributes; Instrinsics; Calling conventions; Register set, instruction set; More at TableGen what is regression test and how does it work?
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?