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 280b57cec5SDimitry Andric bool MSP430FrameLowering::hasFP(const MachineFunction &MF) const { 290b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric return (MF.getTarget().Options.DisableFramePointerElim(MF) || 320b57cec5SDimitry Andric MF.getFrameInfo().hasVarSizedObjects() || 330b57cec5SDimitry Andric MFI.isFrameAddressTaken()); 340b57cec5SDimitry Andric } 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric bool MSP430FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { 370b57cec5SDimitry Andric return !MF.getFrameInfo().hasVarSizedObjects(); 380b57cec5SDimitry Andric } 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric void MSP430FrameLowering::emitPrologue(MachineFunction &MF, 410b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 420b57cec5SDimitry Andric assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); 430b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 440b57cec5SDimitry Andric MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>(); 450b57cec5SDimitry Andric const MSP430InstrInfo &TII = 460b57cec5SDimitry Andric *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo()); 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(); 490b57cec5SDimitry Andric DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric // Get the number of bytes to allocate from the FrameInfo. 520b57cec5SDimitry Andric uint64_t StackSize = MFI.getStackSize(); 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric uint64_t NumBytes = 0; 550b57cec5SDimitry Andric if (hasFP(MF)) { 560b57cec5SDimitry Andric // Calculate required stack adjustment 570b57cec5SDimitry Andric uint64_t FrameSize = StackSize - 2; 580b57cec5SDimitry Andric NumBytes = FrameSize - MSP430FI->getCalleeSavedFrameSize(); 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric // Get the offset of the stack slot for the EBP register... which is 610b57cec5SDimitry Andric // guaranteed to be the last slot by processFunctionBeforeFrameFinalized. 620b57cec5SDimitry Andric // Update the frame offset adjustment. 630b57cec5SDimitry Andric MFI.setOffsetAdjustment(-NumBytes); 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric // Save FP into the appropriate stack slot... 660b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::PUSH16r)) 675ffd83dbSDimitry Andric .addReg(MSP430::R4, RegState::Kill); 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric // Update FP with the new base value... 705ffd83dbSDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::MOV16rr), MSP430::R4) 710b57cec5SDimitry Andric .addReg(MSP430::SP); 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric // Mark the FramePtr as live-in in every block except the entry. 74*349cc55cSDimitry Andric for (MachineBasicBlock &MBBJ : llvm::drop_begin(MF)) 75*349cc55cSDimitry Andric MBBJ.addLiveIn(MSP430::R4); 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric } else 780b57cec5SDimitry Andric NumBytes = StackSize - MSP430FI->getCalleeSavedFrameSize(); 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric // Skip the callee-saved push instructions. 810b57cec5SDimitry Andric while (MBBI != MBB.end() && (MBBI->getOpcode() == MSP430::PUSH16r)) 820b57cec5SDimitry Andric ++MBBI; 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric if (MBBI != MBB.end()) 850b57cec5SDimitry Andric DL = MBBI->getDebugLoc(); 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric if (NumBytes) { // adjust stack pointer: SP -= numbytes 880b57cec5SDimitry Andric // If there is an SUB16ri of SP immediately before this instruction, merge 890b57cec5SDimitry Andric // the two. 900b57cec5SDimitry Andric //NumBytes -= mergeSPUpdates(MBB, MBBI, true); 910b57cec5SDimitry Andric // If there is an ADD16ri or SUB16ri of SP immediately after this 920b57cec5SDimitry Andric // instruction, merge the two instructions. 930b57cec5SDimitry Andric // mergeSPUpdatesDown(MBB, MBBI, &NumBytes); 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric if (NumBytes) { 960b57cec5SDimitry Andric MachineInstr *MI = 970b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::SUB16ri), MSP430::SP) 980b57cec5SDimitry Andric .addReg(MSP430::SP).addImm(NumBytes); 990b57cec5SDimitry Andric // The SRW implicit def is dead. 1000b57cec5SDimitry Andric MI->getOperand(3).setIsDead(); 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric void MSP430FrameLowering::emitEpilogue(MachineFunction &MF, 1060b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 1070b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 1080b57cec5SDimitry Andric MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>(); 1090b57cec5SDimitry Andric const MSP430InstrInfo &TII = 1100b57cec5SDimitry Andric *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo()); 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); 1130b57cec5SDimitry Andric unsigned RetOpcode = MBBI->getOpcode(); 1140b57cec5SDimitry Andric DebugLoc DL = MBBI->getDebugLoc(); 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric switch (RetOpcode) { 1170b57cec5SDimitry Andric case MSP430::RET: 1180b57cec5SDimitry Andric case MSP430::RETI: break; // These are ok 1190b57cec5SDimitry Andric default: 1200b57cec5SDimitry Andric llvm_unreachable("Can only insert epilog into returning blocks"); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric // Get the number of bytes to allocate from the FrameInfo 1240b57cec5SDimitry Andric uint64_t StackSize = MFI.getStackSize(); 1250b57cec5SDimitry Andric unsigned CSSize = MSP430FI->getCalleeSavedFrameSize(); 1260b57cec5SDimitry Andric uint64_t NumBytes = 0; 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric if (hasFP(MF)) { 1290b57cec5SDimitry Andric // Calculate required stack adjustment 1300b57cec5SDimitry Andric uint64_t FrameSize = StackSize - 2; 1310b57cec5SDimitry Andric NumBytes = FrameSize - CSSize; 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric // pop FP. 1345ffd83dbSDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::POP16r), MSP430::R4); 1350b57cec5SDimitry Andric } else 1360b57cec5SDimitry Andric NumBytes = StackSize - CSSize; 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric // Skip the callee-saved pop instructions. 1390b57cec5SDimitry Andric while (MBBI != MBB.begin()) { 1400b57cec5SDimitry Andric MachineBasicBlock::iterator PI = std::prev(MBBI); 1410b57cec5SDimitry Andric unsigned Opc = PI->getOpcode(); 1420b57cec5SDimitry Andric if (Opc != MSP430::POP16r && !PI->isTerminator()) 1430b57cec5SDimitry Andric break; 1440b57cec5SDimitry Andric --MBBI; 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric DL = MBBI->getDebugLoc(); 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric // If there is an ADD16ri or SUB16ri of SP immediately before this 1500b57cec5SDimitry Andric // instruction, merge the two instructions. 1510b57cec5SDimitry Andric //if (NumBytes || MFI.hasVarSizedObjects()) 1520b57cec5SDimitry Andric // mergeSPUpdatesUp(MBB, MBBI, StackPtr, &NumBytes); 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric if (MFI.hasVarSizedObjects()) { 1550b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, 1565ffd83dbSDimitry Andric TII.get(MSP430::MOV16rr), MSP430::SP).addReg(MSP430::R4); 1570b57cec5SDimitry Andric if (CSSize) { 1580b57cec5SDimitry Andric MachineInstr *MI = 1590b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, 1600b57cec5SDimitry Andric TII.get(MSP430::SUB16ri), MSP430::SP) 1610b57cec5SDimitry Andric .addReg(MSP430::SP).addImm(CSSize); 1620b57cec5SDimitry Andric // The SRW implicit def is dead. 1630b57cec5SDimitry Andric MI->getOperand(3).setIsDead(); 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric } else { 1660b57cec5SDimitry Andric // adjust stack pointer back: SP += numbytes 1670b57cec5SDimitry Andric if (NumBytes) { 1680b57cec5SDimitry Andric MachineInstr *MI = 1690b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MSP430::ADD16ri), MSP430::SP) 1700b57cec5SDimitry Andric .addReg(MSP430::SP).addImm(NumBytes); 1710b57cec5SDimitry Andric // The SRW implicit def is dead. 1720b57cec5SDimitry Andric MI->getOperand(3).setIsDead(); 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric // FIXME: Can we eleminate these in favour of generic code? 1785ffd83dbSDimitry Andric bool MSP430FrameLowering::spillCalleeSavedRegisters( 1795ffd83dbSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 1805ffd83dbSDimitry Andric ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 1810b57cec5SDimitry Andric if (CSI.empty()) 1820b57cec5SDimitry Andric return false; 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric DebugLoc DL; 1850b57cec5SDimitry Andric if (MI != MBB.end()) DL = MI->getDebugLoc(); 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 1880b57cec5SDimitry Andric const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); 1890b57cec5SDimitry Andric MSP430MachineFunctionInfo *MFI = MF.getInfo<MSP430MachineFunctionInfo>(); 1900b57cec5SDimitry Andric MFI->setCalleeSavedFrameSize(CSI.size() * 2); 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric for (unsigned i = CSI.size(); i != 0; --i) { 1930b57cec5SDimitry Andric unsigned Reg = CSI[i-1].getReg(); 1940b57cec5SDimitry Andric // Add the callee-saved register as live-in. It's killed at the spill. 1950b57cec5SDimitry Andric MBB.addLiveIn(Reg); 1960b57cec5SDimitry Andric BuildMI(MBB, MI, DL, TII.get(MSP430::PUSH16r)) 1970b57cec5SDimitry Andric .addReg(Reg, RegState::Kill); 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric return true; 2000b57cec5SDimitry Andric } 2010b57cec5SDimitry Andric 2025ffd83dbSDimitry Andric bool MSP430FrameLowering::restoreCalleeSavedRegisters( 2035ffd83dbSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 2045ffd83dbSDimitry Andric MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 2050b57cec5SDimitry Andric if (CSI.empty()) 2060b57cec5SDimitry Andric return false; 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric DebugLoc DL; 2090b57cec5SDimitry Andric if (MI != MBB.end()) DL = MI->getDebugLoc(); 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 2120b57cec5SDimitry Andric const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric for (unsigned i = 0, e = CSI.size(); i != e; ++i) 2150b57cec5SDimitry Andric BuildMI(MBB, MI, DL, TII.get(MSP430::POP16r), CSI[i].getReg()); 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric return true; 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric MachineBasicBlock::iterator MSP430FrameLowering::eliminateCallFramePseudoInstr( 2210b57cec5SDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB, 2220b57cec5SDimitry Andric MachineBasicBlock::iterator I) const { 2230b57cec5SDimitry Andric const MSP430InstrInfo &TII = 2240b57cec5SDimitry Andric *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo()); 2250b57cec5SDimitry Andric if (!hasReservedCallFrame(MF)) { 2260b57cec5SDimitry Andric // If the stack pointer can be changed after prologue, turn the 2270b57cec5SDimitry Andric // adjcallstackup instruction into a 'sub SP, <amt>' and the 2280b57cec5SDimitry Andric // adjcallstackdown instruction into 'add SP, <amt>' 2290b57cec5SDimitry Andric // TODO: consider using push / pop instead of sub + store / add 2300b57cec5SDimitry Andric MachineInstr &Old = *I; 2310b57cec5SDimitry Andric uint64_t Amount = TII.getFrameSize(Old); 2320b57cec5SDimitry Andric if (Amount != 0) { 2330b57cec5SDimitry Andric // We need to keep the stack aligned properly. To do this, we round the 2340b57cec5SDimitry Andric // amount of space needed for the outgoing arguments up to the next 2350b57cec5SDimitry Andric // alignment boundary. 2365ffd83dbSDimitry Andric Amount = alignTo(Amount, getStackAlign()); 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric MachineInstr *New = nullptr; 2390b57cec5SDimitry Andric if (Old.getOpcode() == TII.getCallFrameSetupOpcode()) { 2400b57cec5SDimitry Andric New = 2410b57cec5SDimitry Andric BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::SUB16ri), MSP430::SP) 2420b57cec5SDimitry Andric .addReg(MSP430::SP) 2430b57cec5SDimitry Andric .addImm(Amount); 2440b57cec5SDimitry Andric } else { 2450b57cec5SDimitry Andric assert(Old.getOpcode() == TII.getCallFrameDestroyOpcode()); 2460b57cec5SDimitry Andric // factor out the amount the callee already popped. 2470b57cec5SDimitry Andric Amount -= TII.getFramePoppedByCallee(Old); 2480b57cec5SDimitry Andric if (Amount) 2490b57cec5SDimitry Andric New = BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::ADD16ri), 2500b57cec5SDimitry Andric MSP430::SP) 2510b57cec5SDimitry Andric .addReg(MSP430::SP) 2520b57cec5SDimitry Andric .addImm(Amount); 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric if (New) { 2560b57cec5SDimitry Andric // The SRW implicit def is dead. 2570b57cec5SDimitry Andric New->getOperand(3).setIsDead(); 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric // Replace the pseudo instruction with a new instruction... 2600b57cec5SDimitry Andric MBB.insert(I, New); 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric } 2630b57cec5SDimitry Andric } else if (I->getOpcode() == TII.getCallFrameDestroyOpcode()) { 2640b57cec5SDimitry Andric // If we are performing frame pointer elimination and if the callee pops 2650b57cec5SDimitry Andric // something off the stack pointer, add it back. 2660b57cec5SDimitry Andric if (uint64_t CalleeAmt = TII.getFramePoppedByCallee(*I)) { 2670b57cec5SDimitry Andric MachineInstr &Old = *I; 2680b57cec5SDimitry Andric MachineInstr *New = 2690b57cec5SDimitry Andric BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::SUB16ri), MSP430::SP) 2700b57cec5SDimitry Andric .addReg(MSP430::SP) 2710b57cec5SDimitry Andric .addImm(CalleeAmt); 2720b57cec5SDimitry Andric // The SRW implicit def is dead. 2730b57cec5SDimitry Andric New->getOperand(3).setIsDead(); 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric MBB.insert(I, New); 2760b57cec5SDimitry Andric } 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric return MBB.erase(I); 2800b57cec5SDimitry Andric } 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric void 2830b57cec5SDimitry Andric MSP430FrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF, 2840b57cec5SDimitry Andric RegScavenger *) const { 2850b57cec5SDimitry Andric // Create a frame entry for the FP register that must be saved. 2860b57cec5SDimitry Andric if (hasFP(MF)) { 2870b57cec5SDimitry Andric int FrameIdx = MF.getFrameInfo().CreateFixedObject(2, -4, true); 2880b57cec5SDimitry Andric (void)FrameIdx; 2890b57cec5SDimitry Andric assert(FrameIdx == MF.getFrameInfo().getObjectIndexBegin() && 2900b57cec5SDimitry Andric "Slot for FP register must be last in order to be found!"); 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric } 293