1234285Sdim//===-- HexagonFrameLowering.cpp - Define frame lowering ------------------===//
2234285Sdim//
3234285Sdim//                     The LLVM Compiler Infrastructure
4234285Sdim//
5234285Sdim// This file is distributed under the University of Illinois Open Source
6234285Sdim// License. See LICENSE.TXT for details.
7234285Sdim//
8234285Sdim//
9234285Sdim//===----------------------------------------------------------------------===//
10234285Sdim
11234285Sdim#include "HexagonFrameLowering.h"
12234285Sdim#include "Hexagon.h"
13234285Sdim#include "HexagonInstrInfo.h"
14249423Sdim#include "HexagonMachineFunctionInfo.h"
15234285Sdim#include "HexagonRegisterInfo.h"
16234285Sdim#include "HexagonSubtarget.h"
17234285Sdim#include "HexagonTargetMachine.h"
18234285Sdim#include "llvm/ADT/BitVector.h"
19234285Sdim#include "llvm/ADT/STLExtras.h"
20234285Sdim#include "llvm/CodeGen/AsmPrinter.h"
21249423Sdim#include "llvm/CodeGen/MachineFrameInfo.h"
22234285Sdim#include "llvm/CodeGen/MachineFunction.h"
23234285Sdim#include "llvm/CodeGen/MachineFunctionPass.h"
24249423Sdim#include "llvm/CodeGen/MachineInstrBuilder.h"
25234285Sdim#include "llvm/CodeGen/MachineModuleInfo.h"
26234285Sdim#include "llvm/CodeGen/MachineRegisterInfo.h"
27234285Sdim#include "llvm/CodeGen/RegisterScavenging.h"
28249423Sdim#include "llvm/IR/Function.h"
29249423Sdim#include "llvm/IR/Type.h"
30249423Sdim#include "llvm/MC/MCAsmInfo.h"
31234285Sdim#include "llvm/MC/MachineLocation.h"
32249423Sdim#include "llvm/Support/CommandLine.h"
33234285Sdim#include "llvm/Target/TargetInstrInfo.h"
34234285Sdim#include "llvm/Target/TargetMachine.h"
35234285Sdim#include "llvm/Target/TargetOptions.h"
36234285Sdim
37234285Sdimusing namespace llvm;
38234285Sdim
39234285Sdimstatic cl::opt<bool> DisableDeallocRet(
40234285Sdim                       "disable-hexagon-dealloc-ret",
41234285Sdim                       cl::Hidden,
42234285Sdim                       cl::desc("Disable Dealloc Return for Hexagon target"));
43234285Sdim
44234285Sdim/// determineFrameLayout - Determine the size of the frame and maximum call
45234285Sdim/// frame size.
46234285Sdimvoid HexagonFrameLowering::determineFrameLayout(MachineFunction &MF) const {
47234285Sdim  MachineFrameInfo *MFI = MF.getFrameInfo();
48234285Sdim
49234285Sdim  // Get the number of bytes to allocate from the FrameInfo.
50234285Sdim  unsigned FrameSize = MFI->getStackSize();
51234285Sdim
52234285Sdim  // Get the alignments provided by the target.
53234285Sdim  unsigned TargetAlign = MF.getTarget().getFrameLowering()->getStackAlignment();
54234285Sdim  // Get the maximum call frame size of all the calls.
55234285Sdim  unsigned maxCallFrameSize = MFI->getMaxCallFrameSize();
56234285Sdim
57234285Sdim  // If we have dynamic alloca then maxCallFrameSize needs to be aligned so
58234285Sdim  // that allocations will be aligned.
59234285Sdim  if (MFI->hasVarSizedObjects())
60234285Sdim    maxCallFrameSize = RoundUpToAlignment(maxCallFrameSize, TargetAlign);
61234285Sdim
62234285Sdim  // Update maximum call frame size.
63234285Sdim  MFI->setMaxCallFrameSize(maxCallFrameSize);
64234285Sdim
65234285Sdim  // Include call frame size in total.
66234285Sdim  FrameSize += maxCallFrameSize;
67234285Sdim
68234285Sdim  // Make sure the frame is aligned.
69234285Sdim  FrameSize = RoundUpToAlignment(FrameSize, TargetAlign);
70234285Sdim
71234285Sdim  // Update frame info.
72234285Sdim  MFI->setStackSize(FrameSize);
73234285Sdim}
74234285Sdim
75234285Sdim
76234285Sdimvoid HexagonFrameLowering::emitPrologue(MachineFunction &MF) const {
77234285Sdim  MachineBasicBlock &MBB = MF.front();
78234285Sdim  MachineFrameInfo *MFI = MF.getFrameInfo();
79234285Sdim  MachineBasicBlock::iterator MBBI = MBB.begin();
80234285Sdim  const HexagonRegisterInfo *QRI =
81234285Sdim    static_cast<const HexagonRegisterInfo *>(MF.getTarget().getRegisterInfo());
82234285Sdim  DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
83234285Sdim  determineFrameLayout(MF);
84234285Sdim
85234285Sdim  // Get the number of bytes to allocate from the FrameInfo.
86234285Sdim  int NumBytes = (int) MFI->getStackSize();
87234285Sdim
88234285Sdim  // LLVM expects allocframe not to be the first instruction in the
89234285Sdim  // basic block.
90234285Sdim  MachineBasicBlock::iterator InsertPt = MBB.begin();
91234285Sdim
92234285Sdim  //
93234285Sdim  // ALLOCA adjust regs.  Iterate over ADJDYNALLOC nodes and change the offset.
94234285Sdim  //
95234285Sdim  HexagonMachineFunctionInfo *FuncInfo =
96234285Sdim    MF.getInfo<HexagonMachineFunctionInfo>();
97234285Sdim  const std::vector<MachineInstr*>& AdjustRegs =
98234285Sdim    FuncInfo->getAllocaAdjustInsts();
99234285Sdim  for (std::vector<MachineInstr*>::const_iterator i = AdjustRegs.begin(),
100234285Sdim         e = AdjustRegs.end();
101234285Sdim       i != e; ++i) {
102234285Sdim    MachineInstr* MI = *i;
103234285Sdim    assert((MI->getOpcode() == Hexagon::ADJDYNALLOC) &&
104234285Sdim           "Expected adjust alloca node");
105234285Sdim
106234285Sdim    MachineOperand& MO = MI->getOperand(2);
107234285Sdim    assert(MO.isImm() && "Expected immediate");
108234285Sdim    MO.setImm(MFI->getMaxCallFrameSize());
109234285Sdim  }
110234285Sdim
111234285Sdim  //
112234285Sdim  // Only insert ALLOCFRAME if we need to.
113234285Sdim  //
114234285Sdim  if (hasFP(MF)) {
115234285Sdim    // Check for overflow.
116234285Sdim    // Hexagon_TODO: Ugh! hardcoding. Is there an API that can be used?
117234285Sdim    const int ALLOCFRAME_MAX = 16384;
118234285Sdim    const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
119234285Sdim
120234285Sdim    if (NumBytes >= ALLOCFRAME_MAX) {
121234285Sdim      // Emit allocframe(#0).
122234285Sdim      BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::ALLOCFRAME)).addImm(0);
123234285Sdim
124234285Sdim      // Subtract offset from frame pointer.
125234285Sdim      BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::CONST32_Int_Real),
126234285Sdim                                      HEXAGON_RESERVED_REG_1).addImm(NumBytes);
127234285Sdim      BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::SUB_rr),
128234285Sdim                                      QRI->getStackRegister()).
129234285Sdim                                      addReg(QRI->getStackRegister()).
130234285Sdim                                      addReg(HEXAGON_RESERVED_REG_1);
131234285Sdim    } else {
132234285Sdim      BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::ALLOCFRAME)).addImm(NumBytes);
133234285Sdim    }
134234285Sdim  }
135234285Sdim}
136234285Sdim// Returns true if MBB has a machine instructions that indicates a tail call
137234285Sdim// in the block.
138234285Sdimbool HexagonFrameLowering::hasTailCall(MachineBasicBlock &MBB) const {
139234285Sdim  MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
140234285Sdim  unsigned RetOpcode = MBBI->getOpcode();
141234285Sdim
142249423Sdim  return RetOpcode == Hexagon::TCRETURNtg || RetOpcode == Hexagon::TCRETURNtext;
143249423Sdim}
144234285Sdim
145234285Sdimvoid HexagonFrameLowering::emitEpilogue(MachineFunction &MF,
146234285Sdim                                     MachineBasicBlock &MBB) const {
147234285Sdim  MachineBasicBlock::iterator MBBI = prior(MBB.end());
148234285Sdim  DebugLoc dl = MBBI->getDebugLoc();
149234285Sdim  //
150263508Sdim  // Only insert deallocframe if we need to.  Also at -O0.  See comment
151263508Sdim  // in emitPrologue above.
152234285Sdim  //
153263508Sdim  if (hasFP(MF) || MF.getTarget().getOptLevel() == CodeGenOpt::None) {
154234285Sdim    MachineBasicBlock::iterator MBBI = prior(MBB.end());
155234285Sdim    MachineBasicBlock::iterator MBBI_end = MBB.end();
156234285Sdim
157234285Sdim    const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
158263508Sdim    // Handle EH_RETURN.
159263508Sdim    if (MBBI->getOpcode() == Hexagon::EH_RETURN_JMPR) {
160263508Sdim      assert(MBBI->getOperand(0).isReg() && "Offset should be in register!");
161263508Sdim      BuildMI(MBB, MBBI, dl, TII.get(Hexagon::DEALLOCFRAME));
162263508Sdim      BuildMI(MBB, MBBI, dl, TII.get(Hexagon::ADD_rr),
163263508Sdim              Hexagon::R29).addReg(Hexagon::R29).addReg(Hexagon::R28);
164263508Sdim      return;
165263508Sdim    }
166234285Sdim    // Replace 'jumpr r31' instruction with dealloc_return for V4 and higher
167234285Sdim    // versions.
168251662Sdim    if (STI.hasV4TOps() && MBBI->getOpcode() == Hexagon::JMPret
169234285Sdim                        && !DisableDeallocRet) {
170263508Sdim      // Check for RESTORE_DEALLOC_RET_JMP_V4 call. Don't emit an extra DEALLOC
171263508Sdim      // instruction if we encounter it.
172263508Sdim      MachineBasicBlock::iterator BeforeJMPR =
173263508Sdim        MBB.begin() == MBBI ? MBBI : prior(MBBI);
174263508Sdim      if (BeforeJMPR != MBBI &&
175263508Sdim          BeforeJMPR->getOpcode() == Hexagon::RESTORE_DEALLOC_RET_JMP_V4) {
176263508Sdim        // Remove the JMPR node.
177263508Sdim        MBB.erase(MBBI);
178263508Sdim        return;
179263508Sdim      }
180263508Sdim
181263508Sdim      // Add dealloc_return.
182263508Sdim      MachineInstrBuilder MIB =
183263508Sdim        BuildMI(MBB, MBBI_end, dl, TII.get(Hexagon::DEALLOC_RET_V4));
184263508Sdim      // Transfer the function live-out registers.
185263508Sdim      MIB->copyImplicitOps(*MBB.getParent(), &*MBBI);
186263508Sdim      // Remove the JUMPR node.
187234285Sdim      MBB.erase(MBBI);
188263508Sdim    } else { // Add deallocframe for V2 and V3, and V4 tail calls.
189263508Sdim      // Check for RESTORE_DEALLOC_BEFORE_TAILCALL_V4. We don't need an extra
190263508Sdim      // DEALLOCFRAME instruction after it.
191263508Sdim      MachineBasicBlock::iterator Term = MBB.getFirstTerminator();
192263508Sdim      MachineBasicBlock::iterator I =
193263508Sdim        Term == MBB.begin() ?  MBB.end() : prior(Term);
194263508Sdim      if (I != MBB.end() &&
195263508Sdim          I->getOpcode() == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4)
196263508Sdim        return;
197263508Sdim
198263508Sdim      BuildMI(MBB, MBBI, dl, TII.get(Hexagon::DEALLOCFRAME));
199234285Sdim    }
200234285Sdim  }
201234285Sdim}
202234285Sdim
203234285Sdimbool HexagonFrameLowering::hasFP(const MachineFunction &MF) const {
204234285Sdim  const MachineFrameInfo *MFI = MF.getFrameInfo();
205234285Sdim  const HexagonMachineFunctionInfo *FuncInfo =
206234285Sdim    MF.getInfo<HexagonMachineFunctionInfo>();
207234285Sdim  return (MFI->hasCalls() || (MFI->getStackSize() > 0) ||
208234285Sdim          FuncInfo->hasClobberLR() );
209234285Sdim}
210234285Sdim
211239462Sdimstatic inline
212239462Sdimunsigned uniqueSuperReg(unsigned Reg, const TargetRegisterInfo *TRI) {
213239462Sdim  MCSuperRegIterator SRI(Reg, TRI);
214239462Sdim  assert(SRI.isValid() && "Expected a superreg");
215239462Sdim  unsigned SuperReg = *SRI;
216239462Sdim  ++SRI;
217239462Sdim  assert(!SRI.isValid() && "Expected exactly one superreg");
218239462Sdim  return SuperReg;
219239462Sdim}
220239462Sdim
221234285Sdimbool
222234285SdimHexagonFrameLowering::spillCalleeSavedRegisters(
223234285Sdim                                        MachineBasicBlock &MBB,
224234285Sdim                                        MachineBasicBlock::iterator MI,
225234285Sdim                                        const std::vector<CalleeSavedInfo> &CSI,
226234285Sdim                                        const TargetRegisterInfo *TRI) const {
227234285Sdim  MachineFunction *MF = MBB.getParent();
228234285Sdim  const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo();
229234285Sdim
230234285Sdim  if (CSI.empty()) {
231234285Sdim    return false;
232234285Sdim  }
233234285Sdim
234234285Sdim  // We can only schedule double loads if we spill contiguous callee-saved regs
235234285Sdim  // For instance, we cannot scheduled double-word loads if we spill r24,
236234285Sdim  // r26, and r27.
237234285Sdim  // Hexagon_TODO: We can try to double-word align odd registers for -O2 and
238234285Sdim  // above.
239234285Sdim  bool ContiguousRegs = true;
240234285Sdim
241234285Sdim  for (unsigned i = 0; i < CSI.size(); ++i) {
242234285Sdim    unsigned Reg = CSI[i].getReg();
243234285Sdim
244234285Sdim    //
245234285Sdim    // Check if we can use a double-word store.
246234285Sdim    //
247239462Sdim    unsigned SuperReg = uniqueSuperReg(Reg, TRI);
248234285Sdim    bool CanUseDblStore = false;
249234285Sdim    const TargetRegisterClass* SuperRegClass = 0;
250234285Sdim
251234285Sdim    if (ContiguousRegs && (i < CSI.size()-1)) {
252239462Sdim      unsigned SuperRegNext = uniqueSuperReg(CSI[i+1].getReg(), TRI);
253239462Sdim      SuperRegClass = TRI->getMinimalPhysRegClass(SuperReg);
254239462Sdim      CanUseDblStore = (SuperRegNext == SuperReg);
255234285Sdim    }
256234285Sdim
257234285Sdim
258234285Sdim    if (CanUseDblStore) {
259239462Sdim      TII.storeRegToStackSlot(MBB, MI, SuperReg, true,
260234285Sdim                              CSI[i+1].getFrameIdx(), SuperRegClass, TRI);
261239462Sdim      MBB.addLiveIn(SuperReg);
262234285Sdim      ++i;
263234285Sdim    } else {
264234285Sdim      // Cannot use a double-word store.
265234285Sdim      ContiguousRegs = false;
266234285Sdim      const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
267234285Sdim      TII.storeRegToStackSlot(MBB, MI, Reg, true, CSI[i].getFrameIdx(), RC,
268234285Sdim                              TRI);
269234285Sdim      MBB.addLiveIn(Reg);
270234285Sdim    }
271234285Sdim  }
272234285Sdim  return true;
273234285Sdim}
274234285Sdim
275234285Sdim
276234285Sdimbool HexagonFrameLowering::restoreCalleeSavedRegisters(
277234285Sdim                                        MachineBasicBlock &MBB,
278234285Sdim                                        MachineBasicBlock::iterator MI,
279234285Sdim                                        const std::vector<CalleeSavedInfo> &CSI,
280234285Sdim                                        const TargetRegisterInfo *TRI) const {
281234285Sdim
282234285Sdim  MachineFunction *MF = MBB.getParent();
283234285Sdim  const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo();
284234285Sdim
285234285Sdim  if (CSI.empty()) {
286234285Sdim    return false;
287234285Sdim  }
288234285Sdim
289234285Sdim  // We can only schedule double loads if we spill contiguous callee-saved regs
290234285Sdim  // For instance, we cannot scheduled double-word loads if we spill r24,
291234285Sdim  // r26, and r27.
292234285Sdim  // Hexagon_TODO: We can try to double-word align odd registers for -O2 and
293234285Sdim  // above.
294234285Sdim  bool ContiguousRegs = true;
295234285Sdim
296234285Sdim  for (unsigned i = 0; i < CSI.size(); ++i) {
297234285Sdim    unsigned Reg = CSI[i].getReg();
298234285Sdim
299234285Sdim    //
300234285Sdim    // Check if we can use a double-word load.
301234285Sdim    //
302239462Sdim    unsigned SuperReg = uniqueSuperReg(Reg, TRI);
303234285Sdim    const TargetRegisterClass* SuperRegClass = 0;
304234285Sdim    bool CanUseDblLoad = false;
305234285Sdim    if (ContiguousRegs && (i < CSI.size()-1)) {
306239462Sdim      unsigned SuperRegNext = uniqueSuperReg(CSI[i+1].getReg(), TRI);
307239462Sdim      SuperRegClass = TRI->getMinimalPhysRegClass(SuperReg);
308239462Sdim      CanUseDblLoad = (SuperRegNext == SuperReg);
309234285Sdim    }
310234285Sdim
311234285Sdim
312234285Sdim    if (CanUseDblLoad) {
313239462Sdim      TII.loadRegFromStackSlot(MBB, MI, SuperReg, CSI[i+1].getFrameIdx(),
314234285Sdim                               SuperRegClass, TRI);
315239462Sdim      MBB.addLiveIn(SuperReg);
316234285Sdim      ++i;
317234285Sdim    } else {
318234285Sdim      // Cannot use a double-word load.
319234285Sdim      ContiguousRegs = false;
320234285Sdim      const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
321234285Sdim      TII.loadRegFromStackSlot(MBB, MI, Reg, CSI[i].getFrameIdx(), RC, TRI);
322234285Sdim      MBB.addLiveIn(Reg);
323234285Sdim    }
324234285Sdim  }
325234285Sdim  return true;
326234285Sdim}
327234285Sdim
328249423Sdimvoid HexagonFrameLowering::
329249423SdimeliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
330249423Sdim                              MachineBasicBlock::iterator I) const {
331249423Sdim  MachineInstr &MI = *I;
332249423Sdim
333249423Sdim  if (MI.getOpcode() == Hexagon::ADJCALLSTACKDOWN) {
334249423Sdim    // Hexagon_TODO: add code
335249423Sdim  } else if (MI.getOpcode() == Hexagon::ADJCALLSTACKUP) {
336249423Sdim    // Hexagon_TODO: add code
337249423Sdim  } else {
338249423Sdim    llvm_unreachable("Cannot handle this call frame pseudo instruction");
339249423Sdim  }
340249423Sdim  MBB.erase(I);
341249423Sdim}
342249423Sdim
343234285Sdimint HexagonFrameLowering::getFrameIndexOffset(const MachineFunction &MF,
344234285Sdim                                              int FI) const {
345234285Sdim  return MF.getFrameInfo()->getObjectOffset(FI);
346234285Sdim}
347