Adding the M88k backend to LLVM – The Target Description-1
By Peggy Johnston / October 5, 2021 / No Comments / Adding the M88k backend to LLVM, Emitting machine instructions, Implementing the assembler parser, ITCertification Exams
Creating the top-level file for the target description
So far, we created the M88kRegisterInfo.td, M88kInstrFormats.td, and M88kInstrInfo.td files. The target description is a single file, called M88k.td. This file includes the LLVM definitions first, and the files that we have implemented follow afterwards.:
include “llvm/Target/Target.td”
include “M88kRegisterInfo.td”
include “M88kInstrFormats.td”
include “M88kInstrInfo.td”
We will extend this include section later when we add more backend functionality.
The top-level file also defines some global instances. The first record named M88kInstrInfo holds the information about all instructions:
def M88kInstrInfo : InstrInfo;
We call the assembler class M88kAsmParser. To enable TableGen to identify hardcoded registers, we specify that register names are prefixed with a percent sign, and we need to define an assembler parser variant to specify this:
def M88kAsmParser : AsmParser;
def M88kAsmParserVariant : AsmParserVariant {
let RegisterPrefix = “%”;
}
And last, we need to define the target:
def M88k : Target {
let InstructionSet = M88kInstrInfo;
let AssemblyParsers = [M88kAsmParser];
let AssemblyParserVariants = [M88kAsmParserVariant];
}
We now have defined enough of the target so that we can code the first utility. In the next section, we add the M88k backend to LLVM.
Adding the M88k backend to LLVM
We have not yet discussed where to place the target description files. Each backend in LLVM has a subdirectory in llvm/lib/Target. We create the M88k directory here and copy the target description files into it.
Of course, just adding the TableGen files is not enough. LLVM uses a registry to look up instances of a target implementation, and it expects certain global functions to register those instances. And since some parts are generated, we can already provide an implementation.
All information about a target, like the target triple and factory function for the target machine, assembler, disassembler, and so on, are stored in an instance of the Target class. Each target holds a static instance of this class, and this instance is registered in the central registry:
- The implementation is in the M88kTargetInfo.cpp file in the TargetInfo subdirectory in our target. The single instance of the Target class is held inside the getTheM88kTarget() function:
using namespace llvm;
Target &llvm::getTheM88kTarget() {
static Target TheM88kTarget;
return TheM88kTarget;
}
- LLVM requires that each target provides a LLVMInitializeTargetInfo() function to register the target instance. That function must have a C linkage because it is also used in the LLVM C API:
extern “C” LLVM_EXTERNAL_VISIBILITY void
LLVMInitializeM88kTargetInfo() {
RegisterTargetHasJIT=/false> X(
getTheM88kTarget(), “m88k”, “M88k”, “M88k”);
}
- We also need to create an M88kTargetInfo.h header file in the same directory, which just contains a single declaration:
namespace llvm {
class Target;
Target &getTheM88kTarget();
}
- And last, we add a CMakeLists.txt file for building:
add_llvm_component_library(LLVMM88kInfo
M88kTargetInfo.cpp
LINK_COMPONENTS Support
ADD_TO_COMPONENT M88k)
Next, we partially populate the target instance with the information used at the machine-code (MC) level. Let’s get started:
- The implementation is in the M88kMCTargetDesc.cpp file in the MCTargetDesc subdirectory. TableGen turns the target description we created in the previous section into C++ source code fragments. Here, we include the parts for the register information, the instruction information, and the sub-target information:
using namespace llvm;
define GET_INSTRINFO_MC_DESC
include “M88kGenInstrInfo.inc”
define GET_SUBTARGETINFO_MC_DESC
include “M88kGenSubtargetInfo.inc”
define GET_REGINFO_MC_DESC
include “M88kGenRegisterInfo.inc”