10b57cec5SDimitry Andric //===-- MSP430FrameLowering.cpp - MSP430 Frame Information ----------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file contains the MSP430 implementation of TargetFrameLowering class. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "MSP430FrameLowering.h" 140b57cec5SDimitry Andric #include "MSP430InstrInfo.h" 150b57cec5SDimitry Andric #include "MSP430MachineFunctionInfo.h" 160b57cec5SDimitry Andric #include "MSP430Subtarget.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 220b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 230b57cec5SDimitry Andric #include "llvm/IR/Function.h" 240b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h" 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric 28*06c3fb27SDimitry Andric MSP430FrameLowering::MSP430FrameLowering(const MSP430Subtarget &STI) 29*06c3fb27SDimitry Andric : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(2), -2, 30*06c3fb27SDimitry Andric Align(2)), 31*06c3fb27SDimitry Andric STI(STI), TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {} 32*06c3fb27SDimitry Andric 330b57cec5SDimitry Andric bool MSP430FrameLowering::hasFP(const MachineFunction &MF) const { 340b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric return (MF.getTarget().Options.DisableFramePointerElim(MF) || 370b57cec5SDimitry Andric MF.getFrameInfo().hasVarSizedObjects() || 380b57cec5SDimitry Andric MFI.isFrameAddressTaken()); 390b57cec5SDimitry Andric } 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric bool MSP430FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { 420b57cec5SDimitry Andric return !MF.getFrameInfo().hasVarSizedObjects(); 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 45*06c3fb27SDimitry Andric void MSP430FrameLowering::BuildCFI(MachineBasicBlock &MBB, 46*06c3fb27SDimitry Andric MachineBasicBlock::iterator MBBI, 47*06c3fb27SDimitry Andric const DebugLoc &DL, 48*06c3fb27SDimitry Andric const MCCFIInstruction &CFIInst, 49*06c3fb27SDimitry Andric MachineInstr::MIFlag Flag) const { 50*06c3fb27SDimitry Andric MachineFunction &MF = *MBB.getParent(); 51*06c3fb27SDimitry Andric unsigned CFIIndex = MF.addFrameInst(CFIInst); 52*06c3fb27SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) 53*06c3fb27SDimitry Andric .addCFIIndex(CFIIndex) 54*06c3fb27SDimitry Andric .setMIFlag(Flag); 55*06c3fb27SDimitry Andric } 56*06c3fb27SDimitry Andric 57*06c3fb27SDimitry Andric void MSP430FrameLowering::emitCalleeSavedFrameMoves( 58*06c3fb27SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 59*06c3fb27SDimitry Andric const DebugLoc &DL, bool IsPrologue) const { 60*06c3fb27SDimitry Andric MachineFunction &MF = *MBB.getParent(); 61*06c3fb27SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 62*06c3fb27SDimitry Andric MachineModuleInfo &MMI = MF.getMMI(); 63*06c3fb27SDimitry Andric const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); 64*06c3fb27SDimitry Andric 65*06c3fb27SDimitry Andric // Add callee saved registers to move list. 66*06c3fb27SDimitry Andric const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 67*06c3fb27SDimitry Andric 68*06c3fb27SDimitry Andric // Calculate offsets. 69*06c3fb27SDimitry Andric for (const CalleeSavedInfo &I : CSI) { 70*06c3fb27SDimitry Andric int64_t Offset = MFI.getObjectOffset(I.getFrameIdx()); 71*06c3fb27SDimitry Andric Register Reg = I.getReg(); 72*06c3fb27SDimitry Andric unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true); 73*06c3fb27SDimitry Andric 74*06c3fb27SDimitry Andric if (IsPrologue) { 75*06c3fb27SDimitry Andric BuildCFI(MBB, MBBI, DL, 76*06c3fb27SDimitry Andric MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset)); 77*06c3fb27SDimitry Andric } else { 78*06c3fb27SDimitry Andric BuildCFI(MBB, MBBI, DL, 79*06c3fb27SDimitry Andric MCCFIInstruction::createRestore(nullptr, DwarfReg)); 80*06c3fb27SDimitry Andric } 81*06c3fb27SDimitry Andric } 82*06c3fb27SDimitry Andric } 83*06c3fb27SDimitry Andric 840b57cec5SDimitry Andric void MSP430FrameLowering::emitPrologue(MachineFunction &MF, 850b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 860b57cec5SDimitry Andric assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); 870b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 880b57cec5SDimitry Andric MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>(); 890b57cec5SDimitry Andric const MSP430InstrInfo &TII = 900b57cec5SDimitry Andric *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo()); 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(); 930b57cec5SDimitry Andric DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric // Get the number of bytes to allocate from the FrameInfo. 960b57cec5SDimitry Andric uint64_t StackSize = MFI.getStackSize(); 97*06c3fb27SDimitry Andric int stackGrowth = -2; 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric uint64_t NumBytes = 0; 1000b57cec5SDimitry Andric if (hasFP(MF)) { 1010b57cec5SDimitry Andric // Calculate required stack adjustment 1020b57cec5SDimitry Andric uint64_t FrameSize = StackSize - 2; 1030b57cec5SDimitry Andric NumBytes = FrameSize - MSP430FI->getCalleeSavedFrameSize(); 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric // Get the offset of the stack slot for the EBP register... which is 1060b57cec5SDimitry Andric // guaranteed to be the last slot by processFunctionBeforeFrameFinalized. 1070b57cec5SDimitry Andric // Update the frame offset adjustment. 1080b57cec5SDimitry Andric MFI.setOffsetAdjustment(-NumBytes); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric // Save FP into the appropriate stack slot... 1110b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::PUSH16r)) 112*06c3fb27SDimitry Andric .addReg(MSP430::R4, RegState::Kill) 113*06c3fb27SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 114*06c3fb27SDimitry Andric 115*06c3fb27SDimitry Andric // Mark the place where FP was saved. 116*06c3fb27SDimitry Andric // Define the current CFA rule to use the provided offset. 117*06c3fb27SDimitry Andric BuildCFI(MBB, MBBI, DL, 118*06c3fb27SDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, -2 * stackGrowth), 119*06c3fb27SDimitry Andric MachineInstr::FrameSetup); 120*06c3fb27SDimitry Andric 121*06c3fb27SDimitry Andric // Change the rule for the FramePtr to be an "offset" rule. 122*06c3fb27SDimitry Andric unsigned DwarfFramePtr = TRI->getDwarfRegNum(MSP430::R4, true); 123*06c3fb27SDimitry Andric BuildCFI( 124*06c3fb27SDimitry Andric MBB, MBBI, DL, 125*06c3fb27SDimitry Andric MCCFIInstruction::createOffset(nullptr, DwarfFramePtr, 2 * stackGrowth), 126*06c3fb27SDimitry Andric MachineInstr::FrameSetup); 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric // Update FP with the new base value... 1295ffd83dbSDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::MOV16rr), MSP430::R4) 130*06c3fb27SDimitry Andric .addReg(MSP430::SP) 131*06c3fb27SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 132*06c3fb27SDimitry Andric 133*06c3fb27SDimitry Andric // Mark effective beginning of when frame pointer becomes valid. 134*06c3fb27SDimitry Andric // Define the current CFA to use the FP register. 135*06c3fb27SDimitry Andric BuildCFI(MBB, MBBI, DL, 136*06c3fb27SDimitry Andric MCCFIInstruction::createDefCfaRegister(nullptr, DwarfFramePtr), 137*06c3fb27SDimitry Andric MachineInstr::FrameSetup); 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric // Mark the FramePtr as live-in in every block except the entry. 140349cc55cSDimitry Andric for (MachineBasicBlock &MBBJ : llvm::drop_begin(MF)) 141349cc55cSDimitry Andric MBBJ.addLiveIn(MSP430::R4); 1420b57cec5SDimitry Andric } else 1430b57cec5SDimitry Andric NumBytes = StackSize - MSP430FI->getCalleeSavedFrameSize(); 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric // Skip the callee-saved push instructions. 146*06c3fb27SDimitry Andric int StackOffset = 2 * stackGrowth; 147*06c3fb27SDimitry Andric while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup) && 148*06c3fb27SDimitry Andric (MBBI->getOpcode() == MSP430::PUSH16r)) { 1490b57cec5SDimitry Andric ++MBBI; 1500b57cec5SDimitry Andric 151*06c3fb27SDimitry Andric if (!hasFP(MF)) { 152*06c3fb27SDimitry Andric // Mark callee-saved push instruction. 153*06c3fb27SDimitry Andric // Define the current CFA rule to use the provided offset. 154*06c3fb27SDimitry Andric assert(StackSize && "Expected stack frame"); 155*06c3fb27SDimitry Andric BuildCFI(MBB, MBBI, DL, 156*06c3fb27SDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, -StackOffset), 157*06c3fb27SDimitry Andric MachineInstr::FrameSetup); 158*06c3fb27SDimitry Andric StackOffset += stackGrowth; 159*06c3fb27SDimitry Andric } 160*06c3fb27SDimitry Andric } 161*06c3fb27SDimitry Andric 1620b57cec5SDimitry Andric if (MBBI != MBB.end()) 1630b57cec5SDimitry Andric DL = MBBI->getDebugLoc(); 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric if (NumBytes) { // adjust stack pointer: SP -= numbytes 1660b57cec5SDimitry Andric // If there is an SUB16ri of SP immediately before this instruction, merge 1670b57cec5SDimitry Andric // the two. 1680b57cec5SDimitry Andric //NumBytes -= mergeSPUpdates(MBB, MBBI, true); 1690b57cec5SDimitry Andric // If there is an ADD16ri or SUB16ri of SP immediately after this 1700b57cec5SDimitry Andric // instruction, merge the two instructions. 1710b57cec5SDimitry Andric // mergeSPUpdatesDown(MBB, MBBI, &NumBytes); 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric if (NumBytes) { 1740b57cec5SDimitry Andric MachineInstr *MI = 1750b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::SUB16ri), MSP430::SP) 176*06c3fb27SDimitry Andric .addReg(MSP430::SP) 177*06c3fb27SDimitry Andric .addImm(NumBytes) 178*06c3fb27SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 1790b57cec5SDimitry Andric // The SRW implicit def is dead. 1800b57cec5SDimitry Andric MI->getOperand(3).setIsDead(); 1810b57cec5SDimitry Andric } 182*06c3fb27SDimitry Andric if (!hasFP(MF)) { 183*06c3fb27SDimitry Andric // Adjust the previous CFA value if CFA was not redefined by FP 184*06c3fb27SDimitry Andric BuildCFI( 185*06c3fb27SDimitry Andric MBB, MBBI, DL, 186*06c3fb27SDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize - stackGrowth), 187*06c3fb27SDimitry Andric MachineInstr::FrameSetup); 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric 191*06c3fb27SDimitry Andric emitCalleeSavedFrameMoves(MBB, MBBI, DL, true); 192*06c3fb27SDimitry Andric } 193*06c3fb27SDimitry Andric 1940b57cec5SDimitry Andric void MSP430FrameLowering::emitEpilogue(MachineFunction &MF, 1950b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 1960b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 1970b57cec5SDimitry Andric MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>(); 1980b57cec5SDimitry Andric const MSP430InstrInfo &TII = 1990b57cec5SDimitry Andric *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo()); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); 2020b57cec5SDimitry Andric unsigned RetOpcode = MBBI->getOpcode(); 2030b57cec5SDimitry Andric DebugLoc DL = MBBI->getDebugLoc(); 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric switch (RetOpcode) { 2060b57cec5SDimitry Andric case MSP430::RET: 2070b57cec5SDimitry Andric case MSP430::RETI: break; // These are ok 2080b57cec5SDimitry Andric default: 2090b57cec5SDimitry Andric llvm_unreachable("Can only insert epilog into returning blocks"); 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric // Get the number of bytes to allocate from the FrameInfo 2130b57cec5SDimitry Andric uint64_t StackSize = MFI.getStackSize(); 2140b57cec5SDimitry Andric unsigned CSSize = MSP430FI->getCalleeSavedFrameSize(); 2150b57cec5SDimitry Andric uint64_t NumBytes = 0; 2160b57cec5SDimitry Andric 217*06c3fb27SDimitry Andric MachineBasicBlock::iterator AfterPop = MBBI; 2180b57cec5SDimitry Andric if (hasFP(MF)) { 2190b57cec5SDimitry Andric // Calculate required stack adjustment 2200b57cec5SDimitry Andric uint64_t FrameSize = StackSize - 2; 2210b57cec5SDimitry Andric NumBytes = FrameSize - CSSize; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric // pop FP. 224*06c3fb27SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::POP16r), MSP430::R4) 225*06c3fb27SDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 226*06c3fb27SDimitry Andric unsigned DwarfStackPtr = TRI->getDwarfRegNum(MSP430::SP, true); 227*06c3fb27SDimitry Andric BuildCFI(MBB, MBBI, DL, 228*06c3fb27SDimitry Andric MCCFIInstruction::cfiDefCfa(nullptr, DwarfStackPtr, 2), 229*06c3fb27SDimitry Andric MachineInstr::FrameDestroy); 230*06c3fb27SDimitry Andric --MBBI; 231*06c3fb27SDimitry Andric if (!MBB.succ_empty() && !MBB.isReturnBlock()) { 232*06c3fb27SDimitry Andric unsigned DwarfFramePtr = TRI->getDwarfRegNum(MSP430::R4, true); 233*06c3fb27SDimitry Andric BuildCFI(MBB, AfterPop, DL, 234*06c3fb27SDimitry Andric MCCFIInstruction::createRestore(nullptr, DwarfFramePtr), 235*06c3fb27SDimitry Andric MachineInstr::FrameDestroy); 236*06c3fb27SDimitry Andric --MBBI; 237*06c3fb27SDimitry Andric --AfterPop; 238*06c3fb27SDimitry Andric } 2390b57cec5SDimitry Andric } else 2400b57cec5SDimitry Andric NumBytes = StackSize - CSSize; 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric // Skip the callee-saved pop instructions. 243*06c3fb27SDimitry Andric MachineBasicBlock::iterator FirstCSPop = MBBI; 2440b57cec5SDimitry Andric while (MBBI != MBB.begin()) { 2450b57cec5SDimitry Andric MachineBasicBlock::iterator PI = std::prev(MBBI); 2460b57cec5SDimitry Andric unsigned Opc = PI->getOpcode(); 247*06c3fb27SDimitry Andric if ((Opc != MSP430::POP16r || !PI->getFlag(MachineInstr::FrameDestroy)) && 248*06c3fb27SDimitry Andric !PI->isTerminator()) 2490b57cec5SDimitry Andric break; 250*06c3fb27SDimitry Andric FirstCSPop = PI; 2510b57cec5SDimitry Andric --MBBI; 2520b57cec5SDimitry Andric } 253*06c3fb27SDimitry Andric MBBI = FirstCSPop; 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric DL = MBBI->getDebugLoc(); 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric // If there is an ADD16ri or SUB16ri of SP immediately before this 2580b57cec5SDimitry Andric // instruction, merge the two instructions. 2590b57cec5SDimitry Andric //if (NumBytes || MFI.hasVarSizedObjects()) 2600b57cec5SDimitry Andric // mergeSPUpdatesUp(MBB, MBBI, StackPtr, &NumBytes); 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric if (MFI.hasVarSizedObjects()) { 263*06c3fb27SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::MOV16rr), MSP430::SP) 264*06c3fb27SDimitry Andric .addReg(MSP430::R4) 265*06c3fb27SDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 2660b57cec5SDimitry Andric if (CSSize) { 2670b57cec5SDimitry Andric MachineInstr *MI = 268*06c3fb27SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::SUB16ri), MSP430::SP) 269*06c3fb27SDimitry Andric .addReg(MSP430::SP) 270*06c3fb27SDimitry Andric .addImm(CSSize) 271*06c3fb27SDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 2720b57cec5SDimitry Andric // The SRW implicit def is dead. 2730b57cec5SDimitry Andric MI->getOperand(3).setIsDead(); 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric } else { 2760b57cec5SDimitry Andric // adjust stack pointer back: SP += numbytes 2770b57cec5SDimitry Andric if (NumBytes) { 2780b57cec5SDimitry Andric MachineInstr *MI = 2790b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::ADD16ri), MSP430::SP) 280*06c3fb27SDimitry Andric .addReg(MSP430::SP) 281*06c3fb27SDimitry Andric .addImm(NumBytes) 282*06c3fb27SDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 2830b57cec5SDimitry Andric // The SRW implicit def is dead. 2840b57cec5SDimitry Andric MI->getOperand(3).setIsDead(); 285*06c3fb27SDimitry Andric 286*06c3fb27SDimitry Andric if (!hasFP(MF)) { 287*06c3fb27SDimitry Andric // Adjust CFA value if it was defined by SP 288*06c3fb27SDimitry Andric BuildCFI(MBB, MBBI, DL, 289*06c3fb27SDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, CSSize + 2), 290*06c3fb27SDimitry Andric MachineInstr::FrameDestroy); 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric } 2940b57cec5SDimitry Andric 295*06c3fb27SDimitry Andric if (!hasFP(MF)) { 296*06c3fb27SDimitry Andric MBBI = FirstCSPop; 297*06c3fb27SDimitry Andric int64_t Offset = -CSSize - 2; 298*06c3fb27SDimitry Andric // Mark callee-saved pop instruction. 299*06c3fb27SDimitry Andric // Define the current CFA rule to use the provided offset. 300*06c3fb27SDimitry Andric while (MBBI != MBB.end()) { 301*06c3fb27SDimitry Andric MachineBasicBlock::iterator PI = MBBI; 302*06c3fb27SDimitry Andric unsigned Opc = PI->getOpcode(); 303*06c3fb27SDimitry Andric ++MBBI; 304*06c3fb27SDimitry Andric if (Opc == MSP430::POP16r) { 305*06c3fb27SDimitry Andric Offset += 2; 306*06c3fb27SDimitry Andric BuildCFI(MBB, MBBI, DL, 307*06c3fb27SDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, -Offset), 308*06c3fb27SDimitry Andric MachineInstr::FrameDestroy); 309*06c3fb27SDimitry Andric } 310*06c3fb27SDimitry Andric } 311*06c3fb27SDimitry Andric } 312*06c3fb27SDimitry Andric emitCalleeSavedFrameMoves(MBB, AfterPop, DL, false); 313*06c3fb27SDimitry Andric } 314*06c3fb27SDimitry Andric 3150b57cec5SDimitry Andric // FIXME: Can we eleminate these in favour of generic code? 3165ffd83dbSDimitry Andric bool MSP430FrameLowering::spillCalleeSavedRegisters( 3175ffd83dbSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 3185ffd83dbSDimitry Andric ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 3190b57cec5SDimitry Andric if (CSI.empty()) 3200b57cec5SDimitry Andric return false; 3210b57cec5SDimitry Andric 3220b57cec5SDimitry Andric DebugLoc DL; 3230b57cec5SDimitry Andric if (MI != MBB.end()) DL = MI->getDebugLoc(); 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 3260b57cec5SDimitry Andric const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); 3270b57cec5SDimitry Andric MSP430MachineFunctionInfo *MFI = MF.getInfo<MSP430MachineFunctionInfo>(); 3280b57cec5SDimitry Andric MFI->setCalleeSavedFrameSize(CSI.size() * 2); 3290b57cec5SDimitry Andric 330*06c3fb27SDimitry Andric for (const CalleeSavedInfo &I : CSI) { 33104eeddc0SDimitry Andric Register Reg = I.getReg(); 3320b57cec5SDimitry Andric // Add the callee-saved register as live-in. It's killed at the spill. 3330b57cec5SDimitry Andric MBB.addLiveIn(Reg); 3340b57cec5SDimitry Andric BuildMI(MBB, MI, DL, TII.get(MSP430::PUSH16r)) 335*06c3fb27SDimitry Andric .addReg(Reg, RegState::Kill) 336*06c3fb27SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 3370b57cec5SDimitry Andric } 3380b57cec5SDimitry Andric return true; 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric 3415ffd83dbSDimitry Andric bool MSP430FrameLowering::restoreCalleeSavedRegisters( 3425ffd83dbSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 3435ffd83dbSDimitry Andric MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 3440b57cec5SDimitry Andric if (CSI.empty()) 3450b57cec5SDimitry Andric return false; 3460b57cec5SDimitry Andric 3470b57cec5SDimitry Andric DebugLoc DL; 3480b57cec5SDimitry Andric if (MI != MBB.end()) DL = MI->getDebugLoc(); 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 3510b57cec5SDimitry Andric const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); 3520b57cec5SDimitry Andric 353*06c3fb27SDimitry Andric for (const CalleeSavedInfo &I : llvm::reverse(CSI)) 354*06c3fb27SDimitry Andric BuildMI(MBB, MI, DL, TII.get(MSP430::POP16r), I.getReg()) 355*06c3fb27SDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric return true; 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric MachineBasicBlock::iterator MSP430FrameLowering::eliminateCallFramePseudoInstr( 3610b57cec5SDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB, 3620b57cec5SDimitry Andric MachineBasicBlock::iterator I) const { 3630b57cec5SDimitry Andric const MSP430InstrInfo &TII = 3640b57cec5SDimitry Andric *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo()); 3650b57cec5SDimitry Andric if (!hasReservedCallFrame(MF)) { 3660b57cec5SDimitry Andric // If the stack pointer can be changed after prologue, turn the 3670b57cec5SDimitry Andric // adjcallstackup instruction into a 'sub SP, <amt>' and the 3680b57cec5SDimitry Andric // adjcallstackdown instruction into 'add SP, <amt>' 3690b57cec5SDimitry Andric // TODO: consider using push / pop instead of sub + store / add 3700b57cec5SDimitry Andric MachineInstr &Old = *I; 3710b57cec5SDimitry Andric uint64_t Amount = TII.getFrameSize(Old); 3720b57cec5SDimitry Andric if (Amount != 0) { 3730b57cec5SDimitry Andric // We need to keep the stack aligned properly. To do this, we round the 3740b57cec5SDimitry Andric // amount of space needed for the outgoing arguments up to the next 3750b57cec5SDimitry Andric // alignment boundary. 3765ffd83dbSDimitry Andric Amount = alignTo(Amount, getStackAlign()); 3770b57cec5SDimitry Andric 3780b57cec5SDimitry Andric MachineInstr *New = nullptr; 3790b57cec5SDimitry Andric if (Old.getOpcode() == TII.getCallFrameSetupOpcode()) { 3800b57cec5SDimitry Andric New = 3810b57cec5SDimitry Andric BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::SUB16ri), MSP430::SP) 3820b57cec5SDimitry Andric .addReg(MSP430::SP) 3830b57cec5SDimitry Andric .addImm(Amount); 3840b57cec5SDimitry Andric } else { 3850b57cec5SDimitry Andric assert(Old.getOpcode() == TII.getCallFrameDestroyOpcode()); 3860b57cec5SDimitry Andric // factor out the amount the callee already popped. 3870b57cec5SDimitry Andric Amount -= TII.getFramePoppedByCallee(Old); 3880b57cec5SDimitry Andric if (Amount) 3890b57cec5SDimitry Andric New = BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::ADD16ri), 3900b57cec5SDimitry Andric MSP430::SP) 3910b57cec5SDimitry Andric .addReg(MSP430::SP) 3920b57cec5SDimitry Andric .addImm(Amount); 3930b57cec5SDimitry Andric } 3940b57cec5SDimitry Andric 3950b57cec5SDimitry Andric if (New) { 3960b57cec5SDimitry Andric // The SRW implicit def is dead. 3970b57cec5SDimitry Andric New->getOperand(3).setIsDead(); 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric // Replace the pseudo instruction with a new instruction... 4000b57cec5SDimitry Andric MBB.insert(I, New); 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric } 4030b57cec5SDimitry Andric } else if (I->getOpcode() == TII.getCallFrameDestroyOpcode()) { 4040b57cec5SDimitry Andric // If we are performing frame pointer elimination and if the callee pops 4050b57cec5SDimitry Andric // something off the stack pointer, add it back. 4060b57cec5SDimitry Andric if (uint64_t CalleeAmt = TII.getFramePoppedByCallee(*I)) { 4070b57cec5SDimitry Andric MachineInstr &Old = *I; 4080b57cec5SDimitry Andric MachineInstr *New = 4090b57cec5SDimitry Andric BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::SUB16ri), MSP430::SP) 4100b57cec5SDimitry Andric .addReg(MSP430::SP) 4110b57cec5SDimitry Andric .addImm(CalleeAmt); 412*06c3fb27SDimitry Andric if (!hasFP(MF)) { 413*06c3fb27SDimitry Andric DebugLoc DL = I->getDebugLoc(); 414*06c3fb27SDimitry Andric BuildCFI(MBB, I, DL, 415*06c3fb27SDimitry Andric MCCFIInstruction::createAdjustCfaOffset(nullptr, CalleeAmt)); 416*06c3fb27SDimitry Andric } 4170b57cec5SDimitry Andric // The SRW implicit def is dead. 4180b57cec5SDimitry Andric New->getOperand(3).setIsDead(); 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric MBB.insert(I, New); 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric } 4230b57cec5SDimitry Andric 4240b57cec5SDimitry Andric return MBB.erase(I); 4250b57cec5SDimitry Andric } 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric void 4280b57cec5SDimitry Andric MSP430FrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF, 4290b57cec5SDimitry Andric RegScavenger *) const { 4300b57cec5SDimitry Andric // Create a frame entry for the FP register that must be saved. 4310b57cec5SDimitry Andric if (hasFP(MF)) { 4320b57cec5SDimitry Andric int FrameIdx = MF.getFrameInfo().CreateFixedObject(2, -4, true); 4330b57cec5SDimitry Andric (void)FrameIdx; 4340b57cec5SDimitry Andric assert(FrameIdx == MF.getFrameInfo().getObjectIndexBegin() && 4350b57cec5SDimitry Andric "Slot for FP register must be last in order to be found!"); 4360b57cec5SDimitry Andric } 4370b57cec5SDimitry Andric } 438