1b22310fdSJia Liu //===-- MSP430FrameLowering.cpp - MSP430 Frame Information ----------------===//
22f931281SAnton Korobeynikov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62f931281SAnton Korobeynikov //
72f931281SAnton Korobeynikov //===----------------------------------------------------------------------===//
82f931281SAnton Korobeynikov //
92f931281SAnton Korobeynikov // This file contains the MSP430 implementation of TargetFrameLowering class.
102f931281SAnton Korobeynikov //
112f931281SAnton Korobeynikov //===----------------------------------------------------------------------===//
122f931281SAnton Korobeynikov 
132f931281SAnton Korobeynikov #include "MSP430FrameLowering.h"
142f931281SAnton Korobeynikov #include "MSP430InstrInfo.h"
152f931281SAnton Korobeynikov #include "MSP430MachineFunctionInfo.h"
16d913448bSEric Christopher #include "MSP430Subtarget.h"
172f931281SAnton Korobeynikov #include "llvm/CodeGen/MachineFrameInfo.h"
182f931281SAnton Korobeynikov #include "llvm/CodeGen/MachineFunction.h"
192f931281SAnton Korobeynikov #include "llvm/CodeGen/MachineInstrBuilder.h"
202f931281SAnton Korobeynikov #include "llvm/CodeGen/MachineModuleInfo.h"
212f931281SAnton Korobeynikov #include "llvm/CodeGen/MachineRegisterInfo.h"
229fb823bbSChandler Carruth #include "llvm/IR/DataLayout.h"
239fb823bbSChandler Carruth #include "llvm/IR/Function.h"
24ed0881b2SChandler Carruth #include "llvm/Target/TargetOptions.h"
252f931281SAnton Korobeynikov 
262f931281SAnton Korobeynikov using namespace llvm;
272f931281SAnton Korobeynikov 
hasFP(const MachineFunction & MF) const282f931281SAnton Korobeynikov bool MSP430FrameLowering::hasFP(const MachineFunction &MF) const {
29941a705bSMatthias Braun   const MachineFrameInfo &MFI = MF.getFrameInfo();
302f931281SAnton Korobeynikov 
3150f02cb2SNick Lewycky   return (MF.getTarget().Options.DisableFramePointerElim(MF) ||
32941a705bSMatthias Braun           MF.getFrameInfo().hasVarSizedObjects() ||
33941a705bSMatthias Braun           MFI.isFrameAddressTaken());
342f931281SAnton Korobeynikov }
352f931281SAnton Korobeynikov 
hasReservedCallFrame(const MachineFunction & MF) const362f931281SAnton Korobeynikov bool MSP430FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
37941a705bSMatthias Braun   return !MF.getFrameInfo().hasVarSizedObjects();
382f931281SAnton Korobeynikov }
392f931281SAnton Korobeynikov 
emitPrologue(MachineFunction & MF,MachineBasicBlock & MBB) const4061b305edSQuentin Colombet void MSP430FrameLowering::emitPrologue(MachineFunction &MF,
4161b305edSQuentin Colombet                                        MachineBasicBlock &MBB) const {
4261b305edSQuentin Colombet   assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
43941a705bSMatthias Braun   MachineFrameInfo &MFI = MF.getFrameInfo();
442f931281SAnton Korobeynikov   MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>();
452f931281SAnton Korobeynikov   const MSP430InstrInfo &TII =
46fc6de428SEric Christopher       *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo());
472f931281SAnton Korobeynikov 
482f931281SAnton Korobeynikov   MachineBasicBlock::iterator MBBI = MBB.begin();
492f931281SAnton Korobeynikov   DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
502f931281SAnton Korobeynikov 
512f931281SAnton Korobeynikov   // Get the number of bytes to allocate from the FrameInfo.
52941a705bSMatthias Braun   uint64_t StackSize = MFI.getStackSize();
532f931281SAnton Korobeynikov 
542f931281SAnton Korobeynikov   uint64_t NumBytes = 0;
552f931281SAnton Korobeynikov   if (hasFP(MF)) {
562f931281SAnton Korobeynikov     // Calculate required stack adjustment
572f931281SAnton Korobeynikov     uint64_t FrameSize = StackSize - 2;
582f931281SAnton Korobeynikov     NumBytes = FrameSize - MSP430FI->getCalleeSavedFrameSize();
592f931281SAnton Korobeynikov 
602f931281SAnton Korobeynikov     // Get the offset of the stack slot for the EBP register... which is
612f931281SAnton Korobeynikov     // guaranteed to be the last slot by processFunctionBeforeFrameFinalized.
622f931281SAnton Korobeynikov     // Update the frame offset adjustment.
63941a705bSMatthias Braun     MFI.setOffsetAdjustment(-NumBytes);
642f931281SAnton Korobeynikov 
65eb19aea4SJob Noorman     // Save FP into the appropriate stack slot...
662f931281SAnton Korobeynikov     BuildMI(MBB, MBBI, DL, TII.get(MSP430::PUSH16r))
67cb56fa21SAnatoly Trosinenko       .addReg(MSP430::R4, RegState::Kill);
682f931281SAnton Korobeynikov 
69eb19aea4SJob Noorman     // Update FP with the new base value...
70cb56fa21SAnatoly Trosinenko     BuildMI(MBB, MBBI, DL, TII.get(MSP430::MOV16rr), MSP430::R4)
71eb19aea4SJob Noorman       .addReg(MSP430::SP);
722f931281SAnton Korobeynikov 
732f931281SAnton Korobeynikov     // Mark the FramePtr as live-in in every block except the entry.
74cfc74024SKazu Hirata     for (MachineBasicBlock &MBBJ : llvm::drop_begin(MF))
75cfc74024SKazu Hirata       MBBJ.addLiveIn(MSP430::R4);
762f931281SAnton Korobeynikov 
772f931281SAnton Korobeynikov   } else
782f931281SAnton Korobeynikov     NumBytes = StackSize - MSP430FI->getCalleeSavedFrameSize();
792f931281SAnton Korobeynikov 
802f931281SAnton Korobeynikov   // Skip the callee-saved push instructions.
812f931281SAnton Korobeynikov   while (MBBI != MBB.end() && (MBBI->getOpcode() == MSP430::PUSH16r))
822f931281SAnton Korobeynikov     ++MBBI;
832f931281SAnton Korobeynikov 
842f931281SAnton Korobeynikov   if (MBBI != MBB.end())
852f931281SAnton Korobeynikov     DL = MBBI->getDebugLoc();
862f931281SAnton Korobeynikov 
87eb19aea4SJob Noorman   if (NumBytes) { // adjust stack pointer: SP -= numbytes
88eb19aea4SJob Noorman     // If there is an SUB16ri of SP immediately before this instruction, merge
892f931281SAnton Korobeynikov     // the two.
902f931281SAnton Korobeynikov     //NumBytes -= mergeSPUpdates(MBB, MBBI, true);
91eb19aea4SJob Noorman     // If there is an ADD16ri or SUB16ri of SP immediately after this
922f931281SAnton Korobeynikov     // instruction, merge the two instructions.
932f931281SAnton Korobeynikov     // mergeSPUpdatesDown(MBB, MBBI, &NumBytes);
942f931281SAnton Korobeynikov 
952f931281SAnton Korobeynikov     if (NumBytes) {
962f931281SAnton Korobeynikov       MachineInstr *MI =
97eb19aea4SJob Noorman         BuildMI(MBB, MBBI, DL, TII.get(MSP430::SUB16ri), MSP430::SP)
98eb19aea4SJob Noorman         .addReg(MSP430::SP).addImm(NumBytes);
992f931281SAnton Korobeynikov       // The SRW implicit def is dead.
1002f931281SAnton Korobeynikov       MI->getOperand(3).setIsDead();
1012f931281SAnton Korobeynikov     }
1022f931281SAnton Korobeynikov   }
1032f931281SAnton Korobeynikov }
1042f931281SAnton Korobeynikov 
emitEpilogue(MachineFunction & MF,MachineBasicBlock & MBB) const1052f931281SAnton Korobeynikov void MSP430FrameLowering::emitEpilogue(MachineFunction &MF,
1062f931281SAnton Korobeynikov                                        MachineBasicBlock &MBB) const {
107941a705bSMatthias Braun   const MachineFrameInfo &MFI = MF.getFrameInfo();
1082f931281SAnton Korobeynikov   MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>();
1092f931281SAnton Korobeynikov   const MSP430InstrInfo &TII =
110fc6de428SEric Christopher       *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo());
1112f931281SAnton Korobeynikov 
1124bc5e389SJakob Stoklund Olesen   MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
1132f931281SAnton Korobeynikov   unsigned RetOpcode = MBBI->getOpcode();
1142f931281SAnton Korobeynikov   DebugLoc DL = MBBI->getDebugLoc();
1152f931281SAnton Korobeynikov 
1162f931281SAnton Korobeynikov   switch (RetOpcode) {
1172f931281SAnton Korobeynikov   case MSP430::RET:
1182f931281SAnton Korobeynikov   case MSP430::RETI: break;  // These are ok
1192f931281SAnton Korobeynikov   default:
1202f931281SAnton Korobeynikov     llvm_unreachable("Can only insert epilog into returning blocks");
1212f931281SAnton Korobeynikov   }
1222f931281SAnton Korobeynikov 
1232f931281SAnton Korobeynikov   // Get the number of bytes to allocate from the FrameInfo
124941a705bSMatthias Braun   uint64_t StackSize = MFI.getStackSize();
1252f931281SAnton Korobeynikov   unsigned CSSize = MSP430FI->getCalleeSavedFrameSize();
1262f931281SAnton Korobeynikov   uint64_t NumBytes = 0;
1272f931281SAnton Korobeynikov 
1282f931281SAnton Korobeynikov   if (hasFP(MF)) {
1292f931281SAnton Korobeynikov     // Calculate required stack adjustment
1302f931281SAnton Korobeynikov     uint64_t FrameSize = StackSize - 2;
1312f931281SAnton Korobeynikov     NumBytes = FrameSize - CSSize;
1322f931281SAnton Korobeynikov 
133eb19aea4SJob Noorman     // pop FP.
134cb56fa21SAnatoly Trosinenko     BuildMI(MBB, MBBI, DL, TII.get(MSP430::POP16r), MSP430::R4);
1352f931281SAnton Korobeynikov   } else
1362f931281SAnton Korobeynikov     NumBytes = StackSize - CSSize;
1372f931281SAnton Korobeynikov 
1382f931281SAnton Korobeynikov   // Skip the callee-saved pop instructions.
1392f931281SAnton Korobeynikov   while (MBBI != MBB.begin()) {
140b6d0bd48SBenjamin Kramer     MachineBasicBlock::iterator PI = std::prev(MBBI);
1412f931281SAnton Korobeynikov     unsigned Opc = PI->getOpcode();
1427f8e563aSEvan Cheng     if (Opc != MSP430::POP16r && !PI->isTerminator())
1432f931281SAnton Korobeynikov       break;
1442f931281SAnton Korobeynikov     --MBBI;
1452f931281SAnton Korobeynikov   }
1462f931281SAnton Korobeynikov 
1472f931281SAnton Korobeynikov   DL = MBBI->getDebugLoc();
1482f931281SAnton Korobeynikov 
149eb19aea4SJob Noorman   // If there is an ADD16ri or SUB16ri of SP immediately before this
1502f931281SAnton Korobeynikov   // instruction, merge the two instructions.
151941a705bSMatthias Braun   //if (NumBytes || MFI.hasVarSizedObjects())
1522f931281SAnton Korobeynikov   //  mergeSPUpdatesUp(MBB, MBBI, StackPtr, &NumBytes);
1532f931281SAnton Korobeynikov 
154941a705bSMatthias Braun   if (MFI.hasVarSizedObjects()) {
1552f931281SAnton Korobeynikov     BuildMI(MBB, MBBI, DL,
156cb56fa21SAnatoly Trosinenko             TII.get(MSP430::MOV16rr), MSP430::SP).addReg(MSP430::R4);
1572f931281SAnton Korobeynikov     if (CSSize) {
1582f931281SAnton Korobeynikov       MachineInstr *MI =
1592f931281SAnton Korobeynikov         BuildMI(MBB, MBBI, DL,
160eb19aea4SJob Noorman                 TII.get(MSP430::SUB16ri), MSP430::SP)
161eb19aea4SJob Noorman         .addReg(MSP430::SP).addImm(CSSize);
1622f931281SAnton Korobeynikov       // The SRW implicit def is dead.
1632f931281SAnton Korobeynikov       MI->getOperand(3).setIsDead();
1642f931281SAnton Korobeynikov     }
1652f931281SAnton Korobeynikov   } else {
166eb19aea4SJob Noorman     // adjust stack pointer back: SP += numbytes
1672f931281SAnton Korobeynikov     if (NumBytes) {
1682f931281SAnton Korobeynikov       MachineInstr *MI =
169eb19aea4SJob Noorman         BuildMI(MBB, MBBI, DL, TII.get(MSP430::ADD16ri), MSP430::SP)
170eb19aea4SJob Noorman         .addReg(MSP430::SP).addImm(NumBytes);
1712f931281SAnton Korobeynikov       // The SRW implicit def is dead.
1722f931281SAnton Korobeynikov       MI->getOperand(3).setIsDead();
1732f931281SAnton Korobeynikov     }
1742f931281SAnton Korobeynikov   }
1752f931281SAnton Korobeynikov }
1762f931281SAnton Korobeynikov 
1772f931281SAnton Korobeynikov // FIXME: Can we eleminate these in favour of generic code?
spillCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,ArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const178e4230a9fSBenjamin Kramer bool MSP430FrameLowering::spillCalleeSavedRegisters(
179e4230a9fSBenjamin Kramer     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
180e4230a9fSBenjamin Kramer     ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
1812f931281SAnton Korobeynikov   if (CSI.empty())
1822f931281SAnton Korobeynikov     return false;
1832f931281SAnton Korobeynikov 
1842f931281SAnton Korobeynikov   DebugLoc DL;
1852f931281SAnton Korobeynikov   if (MI != MBB.end()) DL = MI->getDebugLoc();
1862f931281SAnton Korobeynikov 
1872f931281SAnton Korobeynikov   MachineFunction &MF = *MBB.getParent();
188fc6de428SEric Christopher   const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
1892f931281SAnton Korobeynikov   MSP430MachineFunctionInfo *MFI = MF.getInfo<MSP430MachineFunctionInfo>();
1902f931281SAnton Korobeynikov   MFI->setCalleeSavedFrameSize(CSI.size() * 2);
1912f931281SAnton Korobeynikov 
19248349967SKazu Hirata   for (const CalleeSavedInfo &I : llvm::reverse(CSI)) {
193*d6b07348SJim Lin     Register Reg = I.getReg();
1942f931281SAnton Korobeynikov     // Add the callee-saved register as live-in. It's killed at the spill.
1952f931281SAnton Korobeynikov     MBB.addLiveIn(Reg);
1962f931281SAnton Korobeynikov     BuildMI(MBB, MI, DL, TII.get(MSP430::PUSH16r))
1972f931281SAnton Korobeynikov       .addReg(Reg, RegState::Kill);
1982f931281SAnton Korobeynikov   }
1992f931281SAnton Korobeynikov   return true;
2002f931281SAnton Korobeynikov }
2012f931281SAnton Korobeynikov 
restoreCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,MutableArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const202186dd631SBenjamin Kramer bool MSP430FrameLowering::restoreCalleeSavedRegisters(
203186dd631SBenjamin Kramer     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
204186dd631SBenjamin Kramer     MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
2052f931281SAnton Korobeynikov   if (CSI.empty())
2062f931281SAnton Korobeynikov     return false;
2072f931281SAnton Korobeynikov 
2082f931281SAnton Korobeynikov   DebugLoc DL;
2092f931281SAnton Korobeynikov   if (MI != MBB.end()) DL = MI->getDebugLoc();
2102f931281SAnton Korobeynikov 
2112f931281SAnton Korobeynikov   MachineFunction &MF = *MBB.getParent();
212fc6de428SEric Christopher   const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
2132f931281SAnton Korobeynikov 
214fc981cedSKazu Hirata   for (const CalleeSavedInfo &I : CSI)
215fc981cedSKazu Hirata     BuildMI(MBB, MI, DL, TII.get(MSP430::POP16r), I.getReg());
2162f931281SAnton Korobeynikov 
2172f931281SAnton Korobeynikov   return true;
2182f931281SAnton Korobeynikov }
2190a69176cSAnton Korobeynikov 
eliminateCallFramePseudoInstr(MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator I) const220e1a2e90fSHans Wennborg MachineBasicBlock::iterator MSP430FrameLowering::eliminateCallFramePseudoInstr(
221e1a2e90fSHans Wennborg     MachineFunction &MF, MachineBasicBlock &MBB,
2228da87163SEli Bendersky     MachineBasicBlock::iterator I) const {
2238da87163SEli Bendersky   const MSP430InstrInfo &TII =
224fc6de428SEric Christopher       *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo());
2258da87163SEli Bendersky   if (!hasReservedCallFrame(MF)) {
2268da87163SEli Bendersky     // If the stack pointer can be changed after prologue, turn the
227eb19aea4SJob Noorman     // adjcallstackup instruction into a 'sub SP, <amt>' and the
228eb19aea4SJob Noorman     // adjcallstackdown instruction into 'add SP, <amt>'
2298da87163SEli Bendersky     // TODO: consider using push / pop instead of sub + store / add
2308efc5b4fSDuncan P. N. Exon Smith     MachineInstr &Old = *I;
231d526b13eSSerge Pavlov     uint64_t Amount = TII.getFrameSize(Old);
2328da87163SEli Bendersky     if (Amount != 0) {
2338da87163SEli Bendersky       // We need to keep the stack aligned properly.  To do this, we round the
2348da87163SEli Bendersky       // amount of space needed for the outgoing arguments up to the next
2358da87163SEli Bendersky       // alignment boundary.
2363ba550a0SGuillaume Chatelet       Amount = alignTo(Amount, getStackAlign());
2378da87163SEli Bendersky 
238062a2baeSCraig Topper       MachineInstr *New = nullptr;
2398efc5b4fSDuncan P. N. Exon Smith       if (Old.getOpcode() == TII.getCallFrameSetupOpcode()) {
2408efc5b4fSDuncan P. N. Exon Smith         New =
2418efc5b4fSDuncan P. N. Exon Smith             BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::SUB16ri), MSP430::SP)
2428efc5b4fSDuncan P. N. Exon Smith                 .addReg(MSP430::SP)
2438efc5b4fSDuncan P. N. Exon Smith                 .addImm(Amount);
2448da87163SEli Bendersky       } else {
2458efc5b4fSDuncan P. N. Exon Smith         assert(Old.getOpcode() == TII.getCallFrameDestroyOpcode());
2468da87163SEli Bendersky         // factor out the amount the callee already popped.
247d526b13eSSerge Pavlov         Amount -= TII.getFramePoppedByCallee(Old);
2488da87163SEli Bendersky         if (Amount)
2498efc5b4fSDuncan P. N. Exon Smith           New = BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::ADD16ri),
2508efc5b4fSDuncan P. N. Exon Smith                         MSP430::SP)
2518efc5b4fSDuncan P. N. Exon Smith                     .addReg(MSP430::SP)
2528efc5b4fSDuncan P. N. Exon Smith                     .addImm(Amount);
2538da87163SEli Bendersky       }
2548da87163SEli Bendersky 
2558da87163SEli Bendersky       if (New) {
2568da87163SEli Bendersky         // The SRW implicit def is dead.
2578da87163SEli Bendersky         New->getOperand(3).setIsDead();
2588da87163SEli Bendersky 
2598da87163SEli Bendersky         // Replace the pseudo instruction with a new instruction...
2608da87163SEli Bendersky         MBB.insert(I, New);
2618da87163SEli Bendersky       }
2628da87163SEli Bendersky     }
2638da87163SEli Bendersky   } else if (I->getOpcode() == TII.getCallFrameDestroyOpcode()) {
2648da87163SEli Bendersky     // If we are performing frame pointer elimination and if the callee pops
2658da87163SEli Bendersky     // something off the stack pointer, add it back.
266d526b13eSSerge Pavlov     if (uint64_t CalleeAmt = TII.getFramePoppedByCallee(*I)) {
2678efc5b4fSDuncan P. N. Exon Smith       MachineInstr &Old = *I;
2688da87163SEli Bendersky       MachineInstr *New =
2698efc5b4fSDuncan P. N. Exon Smith           BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::SUB16ri), MSP430::SP)
2708efc5b4fSDuncan P. N. Exon Smith               .addReg(MSP430::SP)
2718efc5b4fSDuncan P. N. Exon Smith               .addImm(CalleeAmt);
2728da87163SEli Bendersky       // The SRW implicit def is dead.
2738da87163SEli Bendersky       New->getOperand(3).setIsDead();
2748da87163SEli Bendersky 
2758da87163SEli Bendersky       MBB.insert(I, New);
2768da87163SEli Bendersky     }
2778da87163SEli Bendersky   }
2788da87163SEli Bendersky 
279e1a2e90fSHans Wennborg   return MBB.erase(I);
2808da87163SEli Bendersky }
2818da87163SEli Bendersky 
2820a69176cSAnton Korobeynikov void
processFunctionBeforeFrameFinalized(MachineFunction & MF,RegScavenger *) const2835a765fddSHal Finkel MSP430FrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
2845a765fddSHal Finkel                                                          RegScavenger *) const {
285eb19aea4SJob Noorman   // Create a frame entry for the FP register that must be saved.
2868da87163SEli Bendersky   if (hasFP(MF)) {
287941a705bSMatthias Braun     int FrameIdx = MF.getFrameInfo().CreateFixedObject(2, -4, true);
2880a69176cSAnton Korobeynikov     (void)FrameIdx;
289941a705bSMatthias Braun     assert(FrameIdx == MF.getFrameInfo().getObjectIndexBegin() &&
290eb19aea4SJob Noorman            "Slot for FP register must be last in order to be found!");
2910a69176cSAnton Korobeynikov   }
2920a69176cSAnton Korobeynikov }
293