Implementing M88kSubtarget – Instruction Selection
By Peggy Johnston / February 26, 2024 / No Comments / Adding the M88k backend to LLVM, Creating the disassembler, Emitting machine instructions, Implementing the assembler parser, ITCertification Exams
Creating the target machine and the sub-target
So far, we’ve implemented the instruction selection classes and a couple of other classes. Now, we need to set up how our backend will work. Like the optimization pipeline, a backend is divided into passes. Configuring those passes is the main task of the M88kTargetMachine class. In addition, we need to specify which features are available for instruction selection. Usually, a platform is a family of CPUs, which all have a common set of instructions but differ by specific extensions. For example, some CPUs have vector instructions, while others do not. In LLVM IR, a function can have attributes attached that specify for which CPU this function should be compiled, or what features are available. In other words, each function could have a different configuration, which is captured in the M88kSubTarget class.
Implementing M88kSubtarget
Let’s implement the M88kSubtarget class first. The declaration is stored in the M88kSubtarget.h class:
- Parts of the sub-target are generated from the target description, and we include those codes first:
define GET_SUBTARGETINFO_HEADER
include “M88kGenSubtargetInfo.inc”
- Then, we declare the class, deriving it from the generated M88kGenSubtargetInfo class. The class owns a couple of previously defined classes – the instruction information, the target lowering class, and the frame lowering class:
namespace llvm {
class StringRef;
class TargetMachine;
class M88kSubtarget : public M88kGenSubtargetInfo {
virtual void anchor();
Triple TargetTriple;
M88kInstrInfo InstrInfo;
M88kTargetLowering TLInfo;
M88kFrameLowering FrameLowering;
- The sub-target is initialized with the target triple, the name of the CPU, and a feature string, as well as with the target machine. All these parameters describe the hardware for which our backend will generate code:
public:
M88kSubtarget(const Triple &TT,
const std::string &CPU,
const std::string &FS,
const TargetMachine &TM);
- Next, we include the generated file again, this time for automatically defining getter methods for features defined in the target description:
define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, \
GETTER) \
bool GETTER() const { return ATTRIBUTE; }
include “M88kGenSubtargetInfo.inc”
- In addition, we need to declare the ParseSubtargetFeatures() method. The method itself is generated from the target description: void ParseSubtargetFeatures(StringRef CPU,
StringRef TuneCPU,
StringRef FS);
- Next, we must add getter methods for the member variables: const TargetFrameLowering *
getFrameLowering() const override {
return &FrameLowering;
}
const M88kInstrInfo *getInstrInfo() const override {
return &InstrInfo;
}
const M88kTargetLowering *
getTargetLowering() const override {
return &TLInfo;
}
- Finally, we must add a getter method for the register information, which is owned by the instruction information class. This finishes the declaration: const M88kRegisterInfo *
getRegisterInfo() const override {
return &InstrInfo.getRegisterInfo();
}
};
} // end namespace llvm
Next, we must implement the actual subtarget class. The implementation is stored in the M88kSubtarget.cpp file:
- Again, we begin the file by including the generated source:
define GET_SUBTARGETINFO_TARGET_DESC
define GET_SUBTARGETINFO_CTOR
include “M88kGenSubtargetInfo.inc”
- Then, we define the anchor method, which pins the vtable to this file:
void M88kSubtarget::anchor() {}
- Finally, we define the constructor. Note that the generated class expected two CPU parameters: the first one for the instruction set, and the second one for scheduling. The use case here is that you want to optimize the code for the latest CPU but still be able to run the code on an older CPU. We do not support this feature and use the same CPU name for both parameters:
M88kSubtarget::M88kSubtarget(const Triple &TT,
const std::string &CPU,
const std::string &FS,
const TargetMachine &TM)
: M88kGenSubtargetInfo(TT, CPU, /TuneCPU/ CPU, FS),
TargetTriple(TT), InstrInfo(*this),
TLInfo(TM, *this), FrameLowering() {}