| //===-- LanaiFrameLowering.cpp - Lanai Frame Information ------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file contains the Lanai implementation of TargetFrameLowering class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "LanaiFrameLowering.h" |
| |
| #include "LanaiAluCode.h" |
| #include "LanaiInstrInfo.h" |
| #include "LanaiSubtarget.h" |
| #include "llvm/CodeGen/MachineFrameInfo.h" |
| #include "llvm/CodeGen/MachineFunction.h" |
| #include "llvm/CodeGen/MachineInstrBuilder.h" |
| #include "llvm/CodeGen/MachineRegisterInfo.h" |
| #include "llvm/IR/Function.h" |
| |
| using namespace llvm; |
| |
| // Determines the size of the frame and maximum call frame size. |
| void LanaiFrameLowering::determineFrameLayout(MachineFunction &MF) const { |
| MachineFrameInfo &MFI = MF.getFrameInfo(); |
| const LanaiRegisterInfo *LRI = STI.getRegisterInfo(); |
| |
| // Get the number of bytes to allocate from the FrameInfo. |
| unsigned FrameSize = MFI.getStackSize(); |
| |
| // Get the alignment. |
| Align StackAlign = |
| LRI->hasStackRealignment(MF) ? MFI.getMaxAlign() : getStackAlign(); |
| |
| // Get the maximum call frame size of all the calls. |
| unsigned MaxCallFrameSize = MFI.getMaxCallFrameSize(); |
| |
| // If we have dynamic alloca then MaxCallFrameSize needs to be aligned so |
| // that allocations will be aligned. |
| if (MFI.hasVarSizedObjects()) |
| MaxCallFrameSize = alignTo(MaxCallFrameSize, StackAlign); |
| |
| // Update maximum call frame size. |
| MFI.setMaxCallFrameSize(MaxCallFrameSize); |
| |
| // Include call frame size in total. |
| if (!(hasReservedCallFrame(MF) && MFI.adjustsStack())) |
| FrameSize += MaxCallFrameSize; |
| |
| // Make sure the frame is aligned. |
| FrameSize = alignTo(FrameSize, StackAlign); |
| |
| // Update frame info. |
| MFI.setStackSize(FrameSize); |
| } |
| |
| // Iterates through each basic block in a machine function and replaces |
| // ADJDYNALLOC pseudo instructions with a Lanai:ADDI with the |
| // maximum call frame size as the immediate. |
| void LanaiFrameLowering::replaceAdjDynAllocPseudo(MachineFunction &MF) const { |
| const LanaiInstrInfo &LII = |
| *static_cast<const LanaiInstrInfo *>(STI.getInstrInfo()); |
| unsigned MaxCallFrameSize = MF.getFrameInfo().getMaxCallFrameSize(); |
| |
| for (MachineBasicBlock &MBB : MF) { |
| for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) { |
| if (MI.getOpcode() == Lanai::ADJDYNALLOC) { |
| DebugLoc DL = MI.getDebugLoc(); |
| Register Dst = MI.getOperand(0).getReg(); |
| Register Src = MI.getOperand(1).getReg(); |
| |
| BuildMI(MBB, MI, DL, LII.get(Lanai::ADD_I_LO), Dst) |
| .addReg(Src) |
| .addImm(MaxCallFrameSize); |
| MI.eraseFromParent(); |
| } |
| } |
| } |
| } |
| |
| // Generates the following sequence for function entry: |
| // st %fp,-4[*%sp] !push old FP |
| // add %sp,8,%fp !generate new FP |
| // sub %sp,0x4,%sp !allocate stack space (as needed) |
| void LanaiFrameLowering::emitPrologue(MachineFunction &MF, |
| MachineBasicBlock &MBB) const { |
| assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); |
| |
| MachineFrameInfo &MFI = MF.getFrameInfo(); |
| const LanaiInstrInfo &LII = |
| *static_cast<const LanaiInstrInfo *>(STI.getInstrInfo()); |
| MachineBasicBlock::iterator MBBI = MBB.begin(); |
| |
| // Debug location must be unknown since the first debug location is used |
| // to determine the end of the prologue. |
| DebugLoc DL; |
| |
| // Determine the correct frame layout |
| determineFrameLayout(MF); |
| |
| // FIXME: This appears to be overallocating. Needs investigation. |
| // Get the number of bytes to allocate from the FrameInfo. |
| unsigned StackSize = MFI.getStackSize(); |
| |
| // Push old FP |
| // st %fp,-4[*%sp] |
| BuildMI(MBB, MBBI, DL, LII.get(Lanai::SW_RI)) |
| .addReg(Lanai::FP) |
| .addReg(Lanai::SP) |
| .addImm(-4) |
| .addImm(LPAC::makePreOp(LPAC::ADD)) |
| .setMIFlag(MachineInstr::FrameSetup); |
| |
| // Generate new FP |
| // add %sp,8,%fp |
| BuildMI(MBB, MBBI, DL, LII.get(Lanai::ADD_I_LO), Lanai::FP) |
| .addReg(Lanai::SP) |
| .addImm(8) |
| .setMIFlag(MachineInstr::FrameSetup); |
| |
| // Allocate space on the stack if needed |
| // sub %sp,StackSize,%sp |
| if (StackSize != 0) { |
| BuildMI(MBB, MBBI, DL, LII.get(Lanai::SUB_I_LO), Lanai::SP) |
| .addReg(Lanai::SP) |
| .addImm(StackSize) |
| .setMIFlag(MachineInstr::FrameSetup); |
| } |
| |
| // Replace ADJDYNANALLOC |
| if (MFI.hasVarSizedObjects()) |
| replaceAdjDynAllocPseudo(MF); |
| } |
| |
| MachineBasicBlock::iterator LanaiFrameLowering::eliminateCallFramePseudoInstr( |
| MachineFunction & /*MF*/, MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator I) const { |
| // Discard ADJCALLSTACKDOWN, ADJCALLSTACKUP instructions. |
| return MBB.erase(I); |
| } |
| |
| // The function epilogue should not depend on the current stack pointer! |
| // It should use the frame pointer only. This is mandatory because |
| // of alloca; we also take advantage of it to omit stack adjustments |
| // before returning. |
| // |
| // Note that when we go to restore the preserved register values we must |
| // not try to address their slots by using offsets from the stack pointer. |
| // That's because the stack pointer may have been moved during the function |
| // execution due to a call to alloca(). Rather, we must restore all |
| // preserved registers via offsets from the frame pointer value. |
| // |
| // Note also that when the current frame is being "popped" (by adjusting |
| // the value of the stack pointer) on function exit, we must (for the |
| // sake of alloca) set the new value of the stack pointer based upon |
| // the current value of the frame pointer. We can't just add what we |
| // believe to be the (static) frame size to the stack pointer because |
| // if we did that, and alloca() had been called during this function, |
| // we would end up returning *without* having fully deallocated all of |
| // the space grabbed by alloca. If that happened, and a function |
| // containing one or more alloca() calls was called over and over again, |
| // then the stack would grow without limit! |
| // |
| // RET is lowered to |
| // ld -4[%fp],%pc # modify %pc (two delay slots) |
| // as the return address is in the stack frame and mov to pc is allowed. |
| // emitEpilogue emits |
| // mov %fp,%sp # restore the stack pointer |
| // ld -8[%fp],%fp # restore the caller's frame pointer |
| // before RET and the delay slot filler will move RET such that these |
| // instructions execute in the delay slots of the load to PC. |
| void LanaiFrameLowering::emitEpilogue(MachineFunction & /*MF*/, |
| MachineBasicBlock &MBB) const { |
| MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); |
| const LanaiInstrInfo &LII = |
| *static_cast<const LanaiInstrInfo *>(STI.getInstrInfo()); |
| DebugLoc DL = MBBI->getDebugLoc(); |
| |
| // Restore the stack pointer using the callee's frame pointer value. |
| BuildMI(MBB, MBBI, DL, LII.get(Lanai::ADD_I_LO), Lanai::SP) |
| .addReg(Lanai::FP) |
| .addImm(0); |
| |
| // Restore the frame pointer from the stack. |
| BuildMI(MBB, MBBI, DL, LII.get(Lanai::LDW_RI), Lanai::FP) |
| .addReg(Lanai::FP) |
| .addImm(-8) |
| .addImm(LPAC::ADD); |
| } |
| |
| void LanaiFrameLowering::determineCalleeSaves(MachineFunction &MF, |
| BitVector &SavedRegs, |
| RegScavenger *RS) const { |
| TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); |
| |
| MachineFrameInfo &MFI = MF.getFrameInfo(); |
| const LanaiRegisterInfo *LRI = |
| static_cast<const LanaiRegisterInfo *>(STI.getRegisterInfo()); |
| int Offset = -4; |
| |
| // Reserve 4 bytes for the saved RCA |
| MFI.CreateFixedObject(4, Offset, true); |
| Offset -= 4; |
| |
| // Reserve 4 bytes for the saved FP |
| MFI.CreateFixedObject(4, Offset, true); |
| Offset -= 4; |
| |
| if (LRI->hasBasePointer(MF)) { |
| MFI.CreateFixedObject(4, Offset, true); |
| SavedRegs.reset(LRI->getBaseRegister()); |
| } |
| } |