Now that the implementation in the M88k target machine is completed, the next step will be to develop the machine function pass itself. The implementation is contained within the new file, llvm/lib/Target/M88k/M88kDivInstr.cpp:
- The necessary headers for our machine function pass are added first. This includes headers that give us access to the M88k target information and headers that allow us to operate on machine functions and machine instructions:
include “M88k.h”
include “M88kInstrInfo.h”
include “M88kTargetMachine.h”
include “MCTargetDesc/M88kMCTargetDesc.h”
include “llvm/ADT/Statistic.h”
include “llvm/CodeGen/MachineFunction.h”
include “llvm/CodeGen/MachineFunctionPass.h”
include “llvm/CodeGen/MachineInstrBuilder.h”
include “llvm/CodeGen/MachineRegisterInfo.h”
include “llvm/IR/Instructions.h”
include “llvm/Support/Debug.h”
- After that, we will add some code to prepare for our machine function pass. The first is a DEBUG_TYPE definition that is named m88k-div-instr, which is used for fine-grained control when debugging. Specifically, defining this DEBUG_TYPE allows users to specify the machine function pass name and view any debugging information that is pertinent to the pass when debug information is enabled:
define DEBUG_TYPE “m88k-div-instr”
- We also specify that the llvm namespace is being used, and a STATISTIC value for our machine function is also declared. This statistic, called InsertedChecks, keeps track of how many division-by-zero checks are inserted by the compiler. Finally, an anonymous namespace is declared to encapsulate the subsequent machine function pass implementation:
using namespace llvm;
STATISTIC(InsertedChecks, “Number of inserted checks for division by zero”);
namespace {
- As mentioned previously, this machine function pass aims to check for division by zero cases and inserts instructions that will cause the CPU to trap. These instructions require condition codes, so an enum value that we call CC0 is defined with condition codes that are valid for the M88k target, along with their encodings:
enum class CC0 : unsigned {
EQ0 = 0x2,
NE0 = 0xd,
GT0 = 0x1,
LT0 = 0xc,
GE0 = 0x3,
LE0 = 0xe
};
- Let’s create the actual class for our machine function pass next, called M88kDivInstr. Firstly, we create it as an instance that inherits and is of the MachineFunctionPass type. Next, we declare various necessary instances that our M88kDivInstr pass will require. This includes M88kBuilder, which we will create and elaborate on later, and M88kTargetMachine, which contains target instruction and register information. Furthermore, we also require the register bank information and the machine register information when emitting instructions. An AddZeroDivCheck Boolean is also added to represent the previous command-line option, which turns our pass on or off:
class M88kDivInstr : public MachineFunctionPass {
friend class M88kBuilder;
const M88kTargetMachine *TM;
const TargetInstrInfo *TII;
const TargetRegisterInfo *TRI;
const RegisterBankInfo *RBI;
MachineRegisterInfo *MRI;
bool AddZeroDivCheck;
- For the public variables and methods of the M88kDivInstr class, we declare an identification number that LLVM will use to identify our pass, as well as the M88kDivInstr constructor, which takes in M88kTargetMachine. Next, we override the getRequiredProperties() method, which represents the properties that MachineFunction may have at any time during the optimization, and we also override the runOnMachineFunction() method, which will be one of the primary methods that our pass will run when checking for any division by zero. The second important function that is publicly declared is the runOnMachineBasicBlock() function, which will be executed from inside runOnMachineFunction():
public:
static char ID;
M88kDivInstr(const M88kTargetMachine *TM = nullptr);
MachineFunctionProperties getRequiredProperties() const override;
bool runOnMachineFunction(MachineFunction &MF) override;
bool runOnMachineBasicBlock(MachineBasicBlock &MBB);