Implementing frame lowering

This recipe talks about frame lowering for target architecture. Frame lowering involves emitting the prologue and epilogue of the function call.

Getting ready

Note

Two functions need to be defined for frame lowering, namely TOYFrameLowering::emitPrologue() and TOYFrameLowering::emitEpilogue().

How to do it…

The following functions are defined in the TOYFrameLowering.cpp file in the lib/Target/TOY folder:

  1. The emitPrologue function can be defined as follows:
    void TOYFrameLowering::emitPrologue(MachineFunction &MF) const {
      const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
      MachineBasicBlock &MBB = MF.front();
      MachineBasicBlock::iterator MBBI = MBB.begin();
      DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
      uint64_t StackSize = computeStackSize(MF);
      if (!StackSize) {
        return;
      }
      unsigned StackReg = TOY::SP;
      unsigned OffsetReg = materializeOffset(MF, MBB, MBBI, (unsigned)StackSize);
      if (OffsetReg) {
        BuildMI(MBB, MBBI, dl, TII.get(TOY::SUBrr), StackReg)
            .addReg(StackReg)
            .addReg(OffsetReg)
            .setMIFlag(MachineInstr::FrameSetup);
      } else {
        BuildMI(MBB, MBBI, dl, TII.get(TOY::SUBri), StackReg)
            .addReg(StackReg)
            .addImm(StackSize)
            .setMIFlag(MachineInstr::FrameSetup);
      }
    }
  2. The emitEpilogue function can be defined like this:
    void TOYFrameLowering::emitEpilogue(MachineFunction &MF,
                                        MachineBasicBlock &MBB) const {
    
      const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
    MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
      DebugLoc dl = MBBI->getDebugLoc();
      uint64_t StackSize = computeStackSize(MF);
      if (!StackSize) {
        return;
      }
      unsigned StackReg = TOY::SP;
      unsigned OffsetReg = materializeOffset(MF, MBB, MBBI, (unsigned)StackSize);
      if (OffsetReg) {
        BuildMI(MBB, MBBI, dl, TII.get(TOY::ADDrr), StackReg)
            .addReg(StackReg)
            .addReg(OffsetReg)
            .setMIFlag(MachineInstr::FrameSetup);
      } else {
        BuildMI(MBB, MBBI, dl, TII.get(TOY::ADDri), StackReg)
            .addReg(StackReg)
            .addImm(StackSize)
            .setMIFlag(MachineInstr::FrameSetup);
      }
    }
  3. Here are some helper functions used to determine the offset for the ADD stack operation:
    static unsigned materializeOffset(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, unsigned Offset) {
      const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
      DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
      const uint64_t MaxSubImm = 0xfff;
      if (Offset <= MaxSubImm) {
        return 0;
      } else {
        unsigned OffsetReg = TOY::R2;
        unsigned OffsetLo = (unsigned)(Offset & 0xffff);
        unsigned OffsetHi = (unsigned)((Offset & 0xffff0000) >> 16);
        BuildMI(MBB, MBBI, dl, TII.get(TOY::MOVLOi16), OffsetReg)
            .addImm(OffsetLo)
            .setMIFlag(MachineInstr::FrameSetup);
        if (OffsetHi) {
          BuildMI(MBB, MBBI, dl, TII.get(TOY::MOVHIi16), OffsetReg)
              .addReg(OffsetReg)
              .addImm(OffsetHi)
              .setMIFlag(MachineInstr::FrameSetup);
        }
        return OffsetReg;
      }
    }
  4. The following are some more helper functions used to compute the stack size:
    uint64_t TOYFrameLowering::computeStackSize(MachineFunction &MF) const {
      MachineFrameInfo *MFI = MF.getFrameInfo();
      uint64_t StackSize = MFI->getStackSize();
      unsigned StackAlign = getStackAlignment();
      if (StackAlign > 0) {
        StackSize = RoundUpToAlignment(StackSize, StackAlign);
      }
      return StackSize;
    }

How it works…

The emitPrologue function first computes the stack size to determine whether the prologue is required at all. Then it adjusts the stack pointer by calculating the offset. For the epilogue, it first checks whether the epilogue is required or not. Then it restores the stack pointer to what it was at the beginning of the function.

For example, consider this input IR:

%p = alloca i32, align 4
store i32 2, i32* %p
%b = load i32* %p, align 4
%c = add nsw i32 %a, %b

The TOY assembly generated will look like this:

sub sp, sp, #4 ; prologue
movw r1, #2
str r1, [sp]
add r0, r0, #2
add sp, sp, #4 ; epilogue

See also

  • For advanced architecture frame lowering, such as in ARM, refer to the lib/Target/ARM/ARMFrameLowering.cpp file.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.240.196