1*0b57cec5SDimitry Andric //===-- MSP430FrameLowering.cpp - MSP430 Frame Information ----------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file contains the MSP430 implementation of TargetFrameLowering class. 10*0b57cec5SDimitry Andric // 11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 12*0b57cec5SDimitry Andric 13*0b57cec5SDimitry Andric #include "MSP430FrameLowering.h" 14*0b57cec5SDimitry Andric #include "MSP430InstrInfo.h" 15*0b57cec5SDimitry Andric #include "MSP430MachineFunctionInfo.h" 16*0b57cec5SDimitry Andric #include "MSP430Subtarget.h" 17*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 18*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 19*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 20*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 22*0b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 23*0b57cec5SDimitry Andric #include "llvm/IR/Function.h" 24*0b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h" 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric using namespace llvm; 27*0b57cec5SDimitry Andric 28*0b57cec5SDimitry Andric bool MSP430FrameLowering::hasFP(const MachineFunction &MF) const { 29*0b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 30*0b57cec5SDimitry Andric 31*0b57cec5SDimitry Andric return (MF.getTarget().Options.DisableFramePointerElim(MF) || 32*0b57cec5SDimitry Andric MF.getFrameInfo().hasVarSizedObjects() || 33*0b57cec5SDimitry Andric MFI.isFrameAddressTaken()); 34*0b57cec5SDimitry Andric } 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric bool MSP430FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { 37*0b57cec5SDimitry Andric return !MF.getFrameInfo().hasVarSizedObjects(); 38*0b57cec5SDimitry Andric } 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric void MSP430FrameLowering::emitPrologue(MachineFunction &MF, 41*0b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 42*0b57cec5SDimitry Andric assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); 43*0b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 44*0b57cec5SDimitry Andric MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>(); 45*0b57cec5SDimitry Andric const MSP430InstrInfo &TII = 46*0b57cec5SDimitry Andric *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo()); 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(); 49*0b57cec5SDimitry Andric DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric // Get the number of bytes to allocate from the FrameInfo. 52*0b57cec5SDimitry Andric uint64_t StackSize = MFI.getStackSize(); 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric uint64_t NumBytes = 0; 55*0b57cec5SDimitry Andric if (hasFP(MF)) { 56*0b57cec5SDimitry Andric // Calculate required stack adjustment 57*0b57cec5SDimitry Andric uint64_t FrameSize = StackSize - 2; 58*0b57cec5SDimitry Andric NumBytes = FrameSize - MSP430FI->getCalleeSavedFrameSize(); 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric // Get the offset of the stack slot for the EBP register... which is 61*0b57cec5SDimitry Andric // guaranteed to be the last slot by processFunctionBeforeFrameFinalized. 62*0b57cec5SDimitry Andric // Update the frame offset adjustment. 63*0b57cec5SDimitry Andric MFI.setOffsetAdjustment(-NumBytes); 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric // Save FP into the appropriate stack slot... 66*0b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::PUSH16r)) 67*0b57cec5SDimitry Andric .addReg(MSP430::FP, RegState::Kill); 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric // Update FP with the new base value... 70*0b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::MOV16rr), MSP430::FP) 71*0b57cec5SDimitry Andric .addReg(MSP430::SP); 72*0b57cec5SDimitry Andric 73*0b57cec5SDimitry Andric // Mark the FramePtr as live-in in every block except the entry. 74*0b57cec5SDimitry Andric for (MachineFunction::iterator I = std::next(MF.begin()), E = MF.end(); 75*0b57cec5SDimitry Andric I != E; ++I) 76*0b57cec5SDimitry Andric I->addLiveIn(MSP430::FP); 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric } else 79*0b57cec5SDimitry Andric NumBytes = StackSize - MSP430FI->getCalleeSavedFrameSize(); 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric // Skip the callee-saved push instructions. 82*0b57cec5SDimitry Andric while (MBBI != MBB.end() && (MBBI->getOpcode() == MSP430::PUSH16r)) 83*0b57cec5SDimitry Andric ++MBBI; 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric if (MBBI != MBB.end()) 86*0b57cec5SDimitry Andric DL = MBBI->getDebugLoc(); 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric if (NumBytes) { // adjust stack pointer: SP -= numbytes 89*0b57cec5SDimitry Andric // If there is an SUB16ri of SP immediately before this instruction, merge 90*0b57cec5SDimitry Andric // the two. 91*0b57cec5SDimitry Andric //NumBytes -= mergeSPUpdates(MBB, MBBI, true); 92*0b57cec5SDimitry Andric // If there is an ADD16ri or SUB16ri of SP immediately after this 93*0b57cec5SDimitry Andric // instruction, merge the two instructions. 94*0b57cec5SDimitry Andric // mergeSPUpdatesDown(MBB, MBBI, &NumBytes); 95*0b57cec5SDimitry Andric 96*0b57cec5SDimitry Andric if (NumBytes) { 97*0b57cec5SDimitry Andric MachineInstr *MI = 98*0b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::SUB16ri), MSP430::SP) 99*0b57cec5SDimitry Andric .addReg(MSP430::SP).addImm(NumBytes); 100*0b57cec5SDimitry Andric // The SRW implicit def is dead. 101*0b57cec5SDimitry Andric MI->getOperand(3).setIsDead(); 102*0b57cec5SDimitry Andric } 103*0b57cec5SDimitry Andric } 104*0b57cec5SDimitry Andric } 105*0b57cec5SDimitry Andric 106*0b57cec5SDimitry Andric void MSP430FrameLowering::emitEpilogue(MachineFunction &MF, 107*0b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 108*0b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 109*0b57cec5SDimitry Andric MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>(); 110*0b57cec5SDimitry Andric const MSP430InstrInfo &TII = 111*0b57cec5SDimitry Andric *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo()); 112*0b57cec5SDimitry Andric 113*0b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); 114*0b57cec5SDimitry Andric unsigned RetOpcode = MBBI->getOpcode(); 115*0b57cec5SDimitry Andric DebugLoc DL = MBBI->getDebugLoc(); 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric switch (RetOpcode) { 118*0b57cec5SDimitry Andric case MSP430::RET: 119*0b57cec5SDimitry Andric case MSP430::RETI: break; // These are ok 120*0b57cec5SDimitry Andric default: 121*0b57cec5SDimitry Andric llvm_unreachable("Can only insert epilog into returning blocks"); 122*0b57cec5SDimitry Andric } 123*0b57cec5SDimitry Andric 124*0b57cec5SDimitry Andric // Get the number of bytes to allocate from the FrameInfo 125*0b57cec5SDimitry Andric uint64_t StackSize = MFI.getStackSize(); 126*0b57cec5SDimitry Andric unsigned CSSize = MSP430FI->getCalleeSavedFrameSize(); 127*0b57cec5SDimitry Andric uint64_t NumBytes = 0; 128*0b57cec5SDimitry Andric 129*0b57cec5SDimitry Andric if (hasFP(MF)) { 130*0b57cec5SDimitry Andric // Calculate required stack adjustment 131*0b57cec5SDimitry Andric uint64_t FrameSize = StackSize - 2; 132*0b57cec5SDimitry Andric NumBytes = FrameSize - CSSize; 133*0b57cec5SDimitry Andric 134*0b57cec5SDimitry Andric // pop FP. 135*0b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::POP16r), MSP430::FP); 136*0b57cec5SDimitry Andric } else 137*0b57cec5SDimitry Andric NumBytes = StackSize - CSSize; 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric // Skip the callee-saved pop instructions. 140*0b57cec5SDimitry Andric while (MBBI != MBB.begin()) { 141*0b57cec5SDimitry Andric MachineBasicBlock::iterator PI = std::prev(MBBI); 142*0b57cec5SDimitry Andric unsigned Opc = PI->getOpcode(); 143*0b57cec5SDimitry Andric if (Opc != MSP430::POP16r && !PI->isTerminator()) 144*0b57cec5SDimitry Andric break; 145*0b57cec5SDimitry Andric --MBBI; 146*0b57cec5SDimitry Andric } 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric DL = MBBI->getDebugLoc(); 149*0b57cec5SDimitry Andric 150*0b57cec5SDimitry Andric // If there is an ADD16ri or SUB16ri of SP immediately before this 151*0b57cec5SDimitry Andric // instruction, merge the two instructions. 152*0b57cec5SDimitry Andric //if (NumBytes || MFI.hasVarSizedObjects()) 153*0b57cec5SDimitry Andric // mergeSPUpdatesUp(MBB, MBBI, StackPtr, &NumBytes); 154*0b57cec5SDimitry Andric 155*0b57cec5SDimitry Andric if (MFI.hasVarSizedObjects()) { 156*0b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, 157*0b57cec5SDimitry Andric TII.get(MSP430::MOV16rr), MSP430::SP).addReg(MSP430::FP); 158*0b57cec5SDimitry Andric if (CSSize) { 159*0b57cec5SDimitry Andric MachineInstr *MI = 160*0b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, 161*0b57cec5SDimitry Andric TII.get(MSP430::SUB16ri), MSP430::SP) 162*0b57cec5SDimitry Andric .addReg(MSP430::SP).addImm(CSSize); 163*0b57cec5SDimitry Andric // The SRW implicit def is dead. 164*0b57cec5SDimitry Andric MI->getOperand(3).setIsDead(); 165*0b57cec5SDimitry Andric } 166*0b57cec5SDimitry Andric } else { 167*0b57cec5SDimitry Andric // adjust stack pointer back: SP += numbytes 168*0b57cec5SDimitry Andric if (NumBytes) { 169*0b57cec5SDimitry Andric MachineInstr *MI = 170*0b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::ADD16ri), MSP430::SP) 171*0b57cec5SDimitry Andric .addReg(MSP430::SP).addImm(NumBytes); 172*0b57cec5SDimitry Andric // The SRW implicit def is dead. 173*0b57cec5SDimitry Andric MI->getOperand(3).setIsDead(); 174*0b57cec5SDimitry Andric } 175*0b57cec5SDimitry Andric } 176*0b57cec5SDimitry Andric } 177*0b57cec5SDimitry Andric 178*0b57cec5SDimitry Andric // FIXME: Can we eleminate these in favour of generic code? 179*0b57cec5SDimitry Andric bool 180*0b57cec5SDimitry Andric MSP430FrameLowering::spillCalleeSavedRegisters(MachineBasicBlock &MBB, 181*0b57cec5SDimitry Andric MachineBasicBlock::iterator MI, 182*0b57cec5SDimitry Andric const std::vector<CalleeSavedInfo> &CSI, 183*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI) const { 184*0b57cec5SDimitry Andric if (CSI.empty()) 185*0b57cec5SDimitry Andric return false; 186*0b57cec5SDimitry Andric 187*0b57cec5SDimitry Andric DebugLoc DL; 188*0b57cec5SDimitry Andric if (MI != MBB.end()) DL = MI->getDebugLoc(); 189*0b57cec5SDimitry Andric 190*0b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 191*0b57cec5SDimitry Andric const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); 192*0b57cec5SDimitry Andric MSP430MachineFunctionInfo *MFI = MF.getInfo<MSP430MachineFunctionInfo>(); 193*0b57cec5SDimitry Andric MFI->setCalleeSavedFrameSize(CSI.size() * 2); 194*0b57cec5SDimitry Andric 195*0b57cec5SDimitry Andric for (unsigned i = CSI.size(); i != 0; --i) { 196*0b57cec5SDimitry Andric unsigned Reg = CSI[i-1].getReg(); 197*0b57cec5SDimitry Andric // Add the callee-saved register as live-in. It's killed at the spill. 198*0b57cec5SDimitry Andric MBB.addLiveIn(Reg); 199*0b57cec5SDimitry Andric BuildMI(MBB, MI, DL, TII.get(MSP430::PUSH16r)) 200*0b57cec5SDimitry Andric .addReg(Reg, RegState::Kill); 201*0b57cec5SDimitry Andric } 202*0b57cec5SDimitry Andric return true; 203*0b57cec5SDimitry Andric } 204*0b57cec5SDimitry Andric 205*0b57cec5SDimitry Andric bool 206*0b57cec5SDimitry Andric MSP430FrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, 207*0b57cec5SDimitry Andric MachineBasicBlock::iterator MI, 208*0b57cec5SDimitry Andric std::vector<CalleeSavedInfo> &CSI, 209*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI) const { 210*0b57cec5SDimitry Andric if (CSI.empty()) 211*0b57cec5SDimitry Andric return false; 212*0b57cec5SDimitry Andric 213*0b57cec5SDimitry Andric DebugLoc DL; 214*0b57cec5SDimitry Andric if (MI != MBB.end()) DL = MI->getDebugLoc(); 215*0b57cec5SDimitry Andric 216*0b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 217*0b57cec5SDimitry Andric const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); 218*0b57cec5SDimitry Andric 219*0b57cec5SDimitry Andric for (unsigned i = 0, e = CSI.size(); i != e; ++i) 220*0b57cec5SDimitry Andric BuildMI(MBB, MI, DL, TII.get(MSP430::POP16r), CSI[i].getReg()); 221*0b57cec5SDimitry Andric 222*0b57cec5SDimitry Andric return true; 223*0b57cec5SDimitry Andric } 224*0b57cec5SDimitry Andric 225*0b57cec5SDimitry Andric MachineBasicBlock::iterator MSP430FrameLowering::eliminateCallFramePseudoInstr( 226*0b57cec5SDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB, 227*0b57cec5SDimitry Andric MachineBasicBlock::iterator I) const { 228*0b57cec5SDimitry Andric const MSP430InstrInfo &TII = 229*0b57cec5SDimitry Andric *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo()); 230*0b57cec5SDimitry Andric unsigned StackAlign = getStackAlignment(); 231*0b57cec5SDimitry Andric 232*0b57cec5SDimitry Andric if (!hasReservedCallFrame(MF)) { 233*0b57cec5SDimitry Andric // If the stack pointer can be changed after prologue, turn the 234*0b57cec5SDimitry Andric // adjcallstackup instruction into a 'sub SP, <amt>' and the 235*0b57cec5SDimitry Andric // adjcallstackdown instruction into 'add SP, <amt>' 236*0b57cec5SDimitry Andric // TODO: consider using push / pop instead of sub + store / add 237*0b57cec5SDimitry Andric MachineInstr &Old = *I; 238*0b57cec5SDimitry Andric uint64_t Amount = TII.getFrameSize(Old); 239*0b57cec5SDimitry Andric if (Amount != 0) { 240*0b57cec5SDimitry Andric // We need to keep the stack aligned properly. To do this, we round the 241*0b57cec5SDimitry Andric // amount of space needed for the outgoing arguments up to the next 242*0b57cec5SDimitry Andric // alignment boundary. 243*0b57cec5SDimitry Andric Amount = (Amount+StackAlign-1)/StackAlign*StackAlign; 244*0b57cec5SDimitry Andric 245*0b57cec5SDimitry Andric MachineInstr *New = nullptr; 246*0b57cec5SDimitry Andric if (Old.getOpcode() == TII.getCallFrameSetupOpcode()) { 247*0b57cec5SDimitry Andric New = 248*0b57cec5SDimitry Andric BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::SUB16ri), MSP430::SP) 249*0b57cec5SDimitry Andric .addReg(MSP430::SP) 250*0b57cec5SDimitry Andric .addImm(Amount); 251*0b57cec5SDimitry Andric } else { 252*0b57cec5SDimitry Andric assert(Old.getOpcode() == TII.getCallFrameDestroyOpcode()); 253*0b57cec5SDimitry Andric // factor out the amount the callee already popped. 254*0b57cec5SDimitry Andric Amount -= TII.getFramePoppedByCallee(Old); 255*0b57cec5SDimitry Andric if (Amount) 256*0b57cec5SDimitry Andric New = BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::ADD16ri), 257*0b57cec5SDimitry Andric MSP430::SP) 258*0b57cec5SDimitry Andric .addReg(MSP430::SP) 259*0b57cec5SDimitry Andric .addImm(Amount); 260*0b57cec5SDimitry Andric } 261*0b57cec5SDimitry Andric 262*0b57cec5SDimitry Andric if (New) { 263*0b57cec5SDimitry Andric // The SRW implicit def is dead. 264*0b57cec5SDimitry Andric New->getOperand(3).setIsDead(); 265*0b57cec5SDimitry Andric 266*0b57cec5SDimitry Andric // Replace the pseudo instruction with a new instruction... 267*0b57cec5SDimitry Andric MBB.insert(I, New); 268*0b57cec5SDimitry Andric } 269*0b57cec5SDimitry Andric } 270*0b57cec5SDimitry Andric } else if (I->getOpcode() == TII.getCallFrameDestroyOpcode()) { 271*0b57cec5SDimitry Andric // If we are performing frame pointer elimination and if the callee pops 272*0b57cec5SDimitry Andric // something off the stack pointer, add it back. 273*0b57cec5SDimitry Andric if (uint64_t CalleeAmt = TII.getFramePoppedByCallee(*I)) { 274*0b57cec5SDimitry Andric MachineInstr &Old = *I; 275*0b57cec5SDimitry Andric MachineInstr *New = 276*0b57cec5SDimitry Andric BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::SUB16ri), MSP430::SP) 277*0b57cec5SDimitry Andric .addReg(MSP430::SP) 278*0b57cec5SDimitry Andric .addImm(CalleeAmt); 279*0b57cec5SDimitry Andric // The SRW implicit def is dead. 280*0b57cec5SDimitry Andric New->getOperand(3).setIsDead(); 281*0b57cec5SDimitry Andric 282*0b57cec5SDimitry Andric MBB.insert(I, New); 283*0b57cec5SDimitry Andric } 284*0b57cec5SDimitry Andric } 285*0b57cec5SDimitry Andric 286*0b57cec5SDimitry Andric return MBB.erase(I); 287*0b57cec5SDimitry Andric } 288*0b57cec5SDimitry Andric 289*0b57cec5SDimitry Andric void 290*0b57cec5SDimitry Andric MSP430FrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF, 291*0b57cec5SDimitry Andric RegScavenger *) const { 292*0b57cec5SDimitry Andric // Create a frame entry for the FP register that must be saved. 293*0b57cec5SDimitry Andric if (hasFP(MF)) { 294*0b57cec5SDimitry Andric int FrameIdx = MF.getFrameInfo().CreateFixedObject(2, -4, true); 295*0b57cec5SDimitry Andric (void)FrameIdx; 296*0b57cec5SDimitry Andric assert(FrameIdx == MF.getFrameInfo().getObjectIndexBegin() && 297*0b57cec5SDimitry Andric "Slot for FP register must be last in order to be found!"); 298*0b57cec5SDimitry Andric } 299*0b57cec5SDimitry Andric } 300