The code emission phase lowers the code from code generator abstractions (such as MachineFunction
class, MachineInstr
class, and so on) to machine code layer abstractions (MCInst
class, MCStreamer
class, and so on). The important classes in this phase are the target-independent AsmPrinter
class, target-specific subclasses of AsmPrinter
, and the TargetLoweringObjectFile
class.
The MC layer is responsible for emitting object files, which consist of labels, directives, and instructions; while the CodeGen
layer consists of MachineFunctions
, MachineBasicBlock
and MachineInstructions
. A key class used at this point in time is the MCStreamer
class, which consists of assembler APIs. The MCStreamer
class has functions such as EmitLabel
, EmitSymbolAttribute
, SwitchSection
, and so on, which directly correspond to the aforementioned assembly-level directives.
There are four important things that need to be implemented for the target in order to emit code:
AsmPrinter
class for the target. This class implements the general lowering process, converting the MachineFunctions
functions into MC label constructs. The AsmPrinter
base class methods and routines help implement a target-specific AsmPrinter
class. The TargetLoweringObjectFile
class implements much of the common logic for the ELF
, COFF
, or MachO
targets.MCInst
class and renders it into a raw_ostream
class as text. Most of this is automatically generated from the .td
file (when you specify something like add $dst
, $src1
, $src2
in the instructions), but you need to implement routines to print operands.MachineInstr
class to an MCInst
class
, usually implemented in <target>MCInstLower.cpp
. This lowering process is often target-specific, and is responsible for turning jump table entries, constant pool indices, global variable addresses, and so on into MCLabels
, as appropriate. The instruction printer or the encoder takes the MCInsts
that are generated.MCCodeEmitter
that lowers MCInsts
to machine code bytes and relocations. This is important if you want to support direct .o
file emission, or want to implement an assembler for your target.Let's visit some important functions in the AsmPrinter
base class in the lib/CodeGen/AsmPrinter/AsmPrinter.cpp
file:
EmitLinkage()
: This emits the linkage of the given variables or functions:void AsmPrinter::EmitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const ;
EmitGlobalVariable()
: This emits the specified global variable to the .s
file:void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV);
EmitFunctionHeader()
: This emits the header of the current function:void AsmPrinter::EmitFunctionHeader();
EmitFunctionBody()
: This method emits the body and trailer of a function:void AsmPrinter::EmitFunctionBody();
EmitJumpTableInfo()
: This prints assembly representations of the jump tables used by the current function to the current output stream:void AsmPrinter::EmitJumpTableInfo();
EmitJumpTableEntry()
: This emits a jump table entry for the specified MachineBasicBlock
class to the current stream:void AsmPrinter::EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, const MachineBasicBlock *MBB, unsigned UID) const;
void AsmPrinter::EmitInt8(int Value) const { OutStreamer.EmitIntValue(Value, 1); } void AsmPrinter::EmitInt16(int Value) const { OutStreamer.EmitIntValue(Value, 2); } void AsmPrinter::EmitInt32(int Value) const { OutStreamer.EmitIntValue(Value, 4); }
For detailed implementation on code emission, see the lib/CodeGen/AsmPrinter/AsmPrinter.cpp
file. One important thing to note is that this class uses the OutStreamer
class object to output assembly instructions. The details of target-specific code emission will be covered in later chapters.
18.216.77.153