Adding register and instruction information – Instruction Selection-1
By Peggy Johnston / October 9, 2023 / No Comments / Emitting machine instructions, Exams of IT, Implementing the assembler parser, ITCertification Exams
The target description captures most information about registers and instructions. To access that information, we must implement the M88kRegisterInfo and M88kInstrInfo classes. These classes also contain hooks that we can override to accomplish tasks that are too complex to express in the target description. Let’s begin with the M88kRegisterInfo class, which is declared in the M88kRegisterInfo.h file:
- The header file begins by including the code generated from the target description:
define GET_REGINFO_HEADER
include “M88kGenRegisterInfo.inc”
- After that, we must declare the M88kRegisterInfo class in the llvm namespace. We only override a couple of methods:
namespace llvm {
struct M88kRegisterInfo : public M88kGenRegisterInfo {
M88kRegisterInfo();
const MCPhysReg *getCalleeSavedRegs(
const MachineFunction *MF) const override;
BitVector getReservedRegs(
const MachineFunction &MF) const override;
bool eliminateFrameIndex(
MachineBasicBlock::iterator II, int SPAdj,
unsigned FIOperandNum,
RegScavenger *RS = nullptr) const override;
Register getFrameRegister(
const MachineFunction &MF) const override;
};
} // end namespace llvm
The definition of the class is stored in the M88kRegisterInfo.cpp file:
- Again, the film begins with including the code generated from the target description:
define GET_REGINFO_TARGET_DESC
include “M88kGenRegisterInfo.inc”
- The constructor initializes the superclass, passing the register holding the return address as a parameter:
M88kRegisterInfo::M88kRegisterInfo()
: M88kGenRegisterInfo(M88k::R1) {}
- Then, we implement the method that returns the list of callee-saved registers. We defined the list in the target description, and we only return that list:
const MCPhysReg *M88kRegisterInfo::getCalleeSavedRegs(
const MachineFunction *MF) const {
return CSR_M88k_SaveList;
}
- After, we deal with the reserved registers. The reserved registers depend on the platform and the hardware. The r0 register contains a constant value of 0, so we treat it as a reserved register. The r28 and r29 registers are always reserved for use by a linker. Lastly, the r31 register is used as a stack pointer. This list may depend on the function, and it cannot be generated due to this dynamic behavior:
BitVector M88kRegisterInfo::getReservedRegs(
const MachineFunction &MF) const {
BitVector Reserved(getNumRegs());
Reserved.set(M88k::R0);
Reserved.set(M88k::R28);
Reserved.set(M88k::R29);
Reserved.set(M88k::R31);
return Reserved;
}
- If a frame register is required, then r30 is used. Please note that our code does not support creating a frame yet. If the function requires a frame, then r30 must also be marked as reserved in the getReservedRegs() method. However, we must implement this method because it is declared pure virtual in the superclass:
Register M88kRegisterInfo::getFrameRegister(
const MachineFunction &MF) const {
return M88k::R30;
}
- Similarly, we need to implement the eliminateFrameIndex() method because it is declared pure virtual. It is called to replace a frame index in an operand with the correct value to use to address the value on the stack:
bool M88kRegisterInfo::eliminateFrameIndex(
MachineBasicBlock::iterator MI, int SPAdj,
unsigned FIOperandNum, RegScavenger *RS) const {
return false;
}