Implementing M88kTargetMachine – adding the implementation – Instruction Selection-1
By Peggy Johnston / April 16, 2024 / No Comments / Adding the M88k backend to LLVM, Global instruction selection, Implementing M88kSubtarget, Implementing the assembler parser, ITCertification Exams
The implementation of the class is stored in the M88kTargetMachine.cpp file. Please note that we created this file in Chapter 11. Now, we will replace this file with a complete implementation:
- First, we must register the target machine. In addition, we must initialize the DAG-to-DAG pass via the initialization function we defined earlier:
extern “C” LLVM_EXTERNAL_VISIBILITY void
LLVMInitializeM88kTarget() {
RegisterTargetMachine X(
getTheM88kTarget());
auto &PR = *PassRegistry::getPassRegistry();
initializeM88kDAGToDAGISelPass(PR);
}
- Next, we must define the support function, computeDataLayout(). We talked about the data layout string in Chapter 4, Basics of IR Code Generation. In this function, the data layout, as the backend, expects it to be defined. Since the data layout depends on hardware features, the triple, the name of the CPU, and the feature set string are passed to this function. We create the data layout string with the following components. The target is big-endian (E) and uses the ELF symbol mangling.
Pointers are 32-bit wide and 32-bit aligned. All scalar types are naturally aligned. The MC88110 CPU has an extended register set and supports 80-bit wide floating points. If we were to support this special feature, then we’d need to add a check of the CPU name here and extend the string with the floating-point values accordingly. Next, we must state that all globals have a preferred alignment of 16-bit and that the hardware has only 32-bit registers:
namespace {
std::string computeDataLayout(const Triple &TT,
StringRef CPU,
StringRef FS) {
std::string Ret;
Ret += “E”;
Ret += DataLayout::getManglingComponent(TT);
Ret += “-p:32:32:32”;
Ret += “-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64”;
Ret += “-f32:32:32-f64:64:64”;
Ret += “-a:8:16”;
Ret += “-n32”;
return Ret;
}
} // namespace
- Now, we can define the constructor and destructor. Many of the parameters are just passed to the superclass constructor. Note that our computeDataLayout() function is called here. In addition, the TLOF member is initialized with an instance of TargetLoweringObjectFileELF, since we are using the ELF file format. In the body of the constructor, we must call the initAsmInfo() method, which initializes many data members of the superclass:
M88kTargetMachine::M88kTargetMachine(
const Target &T, const Triple &TT, StringRef CPU,
StringRef FS, const TargetOptions &Options,
std::optional RM,
std::optional CM,
CodeGenOpt::Level OL, bool JIT)
: LLVMTargetMachine(
T, computeDataLayout(TT, CPU, FS), TT, CPU,
FS, Options, !RM ? Reloc::Static : *RM,
getEffectiveCodeModel(CM, CodeModel::Medium),
OL),
TLOF(std::make_unique< TargetLoweringObjectFileELF>()) {
initAsmInfo();
}
M88kTargetMachine::~M88kTargetMachine() {}