xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
10b57cec5SDimitry Andric //===- HexagonFrameLowering.cpp - Define frame lowering -------------------===//
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 
100b57cec5SDimitry Andric #include "HexagonFrameLowering.h"
110b57cec5SDimitry Andric #include "HexagonBlockRanges.h"
120b57cec5SDimitry Andric #include "HexagonInstrInfo.h"
130b57cec5SDimitry Andric #include "HexagonMachineFunctionInfo.h"
140b57cec5SDimitry Andric #include "HexagonRegisterInfo.h"
150b57cec5SDimitry Andric #include "HexagonSubtarget.h"
160b57cec5SDimitry Andric #include "HexagonTargetMachine.h"
170b57cec5SDimitry Andric #include "MCTargetDesc/HexagonBaseInfo.h"
180b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h"
190b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
200b57cec5SDimitry Andric #include "llvm/ADT/None.h"
210b57cec5SDimitry Andric #include "llvm/ADT/Optional.h"
220b57cec5SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
230b57cec5SDimitry Andric #include "llvm/ADT/SetVector.h"
240b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
250b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/LivePhysRegs.h"
270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
330b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
340b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h"
350b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
360b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
370b57cec5SDimitry Andric #include "llvm/CodeGen/MachinePostDominators.h"
380b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
39*480093f4SDimitry Andric #include "llvm/CodeGen/PseudoSourceValue.h"
400b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h"
410b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
420b57cec5SDimitry Andric #include "llvm/IR/Attributes.h"
430b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h"
440b57cec5SDimitry Andric #include "llvm/IR/Function.h"
450b57cec5SDimitry Andric #include "llvm/MC/MCDwarf.h"
460b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
470b57cec5SDimitry Andric #include "llvm/Pass.h"
480b57cec5SDimitry Andric #include "llvm/Support/CodeGen.h"
490b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
500b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
510b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
520b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
530b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
540b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
550b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
560b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h"
570b57cec5SDimitry Andric #include <algorithm>
580b57cec5SDimitry Andric #include <cassert>
590b57cec5SDimitry Andric #include <cstdint>
600b57cec5SDimitry Andric #include <iterator>
610b57cec5SDimitry Andric #include <limits>
620b57cec5SDimitry Andric #include <map>
630b57cec5SDimitry Andric #include <utility>
640b57cec5SDimitry Andric #include <vector>
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric #define DEBUG_TYPE "hexagon-pei"
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric // Hexagon stack frame layout as defined by the ABI:
690b57cec5SDimitry Andric //
700b57cec5SDimitry Andric //                                                       Incoming arguments
710b57cec5SDimitry Andric //                                                       passed via stack
720b57cec5SDimitry Andric //                                                                      |
730b57cec5SDimitry Andric //                                                                      |
740b57cec5SDimitry Andric //        SP during function's                 FP during function's     |
750b57cec5SDimitry Andric //    +-- runtime (top of stack)               runtime (bottom) --+     |
760b57cec5SDimitry Andric //    |                                                           |     |
770b57cec5SDimitry Andric // --++---------------------+------------------+-----------------++-+-------
780b57cec5SDimitry Andric //   |  parameter area for  |  variable-size   |   fixed-size    |LR|  arg
790b57cec5SDimitry Andric //   |   called functions   |  local objects   |  local objects  |FP|
800b57cec5SDimitry Andric // --+----------------------+------------------+-----------------+--+-------
810b57cec5SDimitry Andric //    <-    size known    -> <- size unknown -> <- size known  ->
820b57cec5SDimitry Andric //
830b57cec5SDimitry Andric // Low address                                                 High address
840b57cec5SDimitry Andric //
850b57cec5SDimitry Andric // <--- stack growth
860b57cec5SDimitry Andric //
870b57cec5SDimitry Andric //
880b57cec5SDimitry Andric // - In any circumstances, the outgoing function arguments are always accessi-
890b57cec5SDimitry Andric //   ble using the SP, and the incoming arguments are accessible using the FP.
900b57cec5SDimitry Andric // - If the local objects are not aligned, they can always be accessed using
910b57cec5SDimitry Andric //   the FP.
920b57cec5SDimitry Andric // - If there are no variable-sized objects, the local objects can always be
930b57cec5SDimitry Andric //   accessed using the SP, regardless whether they are aligned or not. (The
940b57cec5SDimitry Andric //   alignment padding will be at the bottom of the stack (highest address),
950b57cec5SDimitry Andric //   and so the offset with respect to the SP will be known at the compile-
960b57cec5SDimitry Andric //   -time.)
970b57cec5SDimitry Andric //
980b57cec5SDimitry Andric // The only complication occurs if there are both, local aligned objects, and
990b57cec5SDimitry Andric // dynamically allocated (variable-sized) objects. The alignment pad will be
1000b57cec5SDimitry Andric // placed between the FP and the local objects, thus preventing the use of the
1010b57cec5SDimitry Andric // FP to access the local objects. At the same time, the variable-sized objects
1020b57cec5SDimitry Andric // will be between the SP and the local objects, thus introducing an unknown
1030b57cec5SDimitry Andric // distance from the SP to the locals.
1040b57cec5SDimitry Andric //
1050b57cec5SDimitry Andric // To avoid this problem, a new register is created that holds the aligned
1060b57cec5SDimitry Andric // address of the bottom of the stack, referred in the sources as AP (aligned
1070b57cec5SDimitry Andric // pointer). The AP will be equal to "FP-p", where "p" is the smallest pad
1080b57cec5SDimitry Andric // that aligns AP to the required boundary (a maximum of the alignments of
1090b57cec5SDimitry Andric // all stack objects, fixed- and variable-sized). All local objects[1] will
1100b57cec5SDimitry Andric // then use AP as the base pointer.
1110b57cec5SDimitry Andric // [1] The exception is with "fixed" stack objects. "Fixed" stack objects get
1120b57cec5SDimitry Andric // their name from being allocated at fixed locations on the stack, relative
1130b57cec5SDimitry Andric // to the FP. In the presence of dynamic allocation and local alignment, such
1140b57cec5SDimitry Andric // objects can only be accessed through the FP.
1150b57cec5SDimitry Andric //
1160b57cec5SDimitry Andric // Illustration of the AP:
1170b57cec5SDimitry Andric //                                                                FP --+
1180b57cec5SDimitry Andric //                                                                     |
1190b57cec5SDimitry Andric // ---------------+---------------------+-----+-----------------------++-+--
1200b57cec5SDimitry Andric //   Rest of the  | Local stack objects | Pad |  Fixed stack objects  |LR|
1210b57cec5SDimitry Andric //   stack frame  | (aligned)           |     |  (CSR, spills, etc.)  |FP|
1220b57cec5SDimitry Andric // ---------------+---------------------+-----+-----------------+-----+--+--
1230b57cec5SDimitry Andric //                                      |<-- Multiple of the -->|
1240b57cec5SDimitry Andric //                                           stack alignment    +-- AP
1250b57cec5SDimitry Andric //
1260b57cec5SDimitry Andric // The AP is set up at the beginning of the function. Since it is not a dedi-
1270b57cec5SDimitry Andric // cated (reserved) register, it needs to be kept live throughout the function
1280b57cec5SDimitry Andric // to be available as the base register for local object accesses.
1290b57cec5SDimitry Andric // Normally, an address of a stack objects is obtained by a pseudo-instruction
1300b57cec5SDimitry Andric // PS_fi. To access local objects with the AP register present, a different
1310b57cec5SDimitry Andric // pseudo-instruction needs to be used: PS_fia. The PS_fia takes one extra
1320b57cec5SDimitry Andric // argument compared to PS_fi: the first input register is the AP register.
1330b57cec5SDimitry Andric // This keeps the register live between its definition and its uses.
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric // The AP register is originally set up using pseudo-instruction PS_aligna:
1360b57cec5SDimitry Andric //   AP = PS_aligna A
1370b57cec5SDimitry Andric // where
1380b57cec5SDimitry Andric //   A  - required stack alignment
1390b57cec5SDimitry Andric // The alignment value must be the maximum of all alignments required by
1400b57cec5SDimitry Andric // any stack object.
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric // The dynamic allocation uses a pseudo-instruction PS_alloca:
1430b57cec5SDimitry Andric //   Rd = PS_alloca Rs, A
1440b57cec5SDimitry Andric // where
1450b57cec5SDimitry Andric //   Rd - address of the allocated space
1460b57cec5SDimitry Andric //   Rs - minimum size (the actual allocated can be larger to accommodate
1470b57cec5SDimitry Andric //        alignment)
1480b57cec5SDimitry Andric //   A  - required alignment
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric using namespace llvm;
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric static cl::opt<bool> DisableDeallocRet("disable-hexagon-dealloc-ret",
1530b57cec5SDimitry Andric     cl::Hidden, cl::desc("Disable Dealloc Return for Hexagon target"));
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric static cl::opt<unsigned> NumberScavengerSlots("number-scavenger-slots",
1560b57cec5SDimitry Andric     cl::Hidden, cl::desc("Set the number of scavenger slots"), cl::init(2),
1570b57cec5SDimitry Andric     cl::ZeroOrMore);
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric static cl::opt<int> SpillFuncThreshold("spill-func-threshold",
1600b57cec5SDimitry Andric     cl::Hidden, cl::desc("Specify O2(not Os) spill func threshold"),
1610b57cec5SDimitry Andric     cl::init(6), cl::ZeroOrMore);
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric static cl::opt<int> SpillFuncThresholdOs("spill-func-threshold-Os",
1640b57cec5SDimitry Andric     cl::Hidden, cl::desc("Specify Os spill func threshold"),
1650b57cec5SDimitry Andric     cl::init(1), cl::ZeroOrMore);
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric static cl::opt<bool> EnableStackOVFSanitizer("enable-stackovf-sanitizer",
1680b57cec5SDimitry Andric     cl::Hidden, cl::desc("Enable runtime checks for stack overflow."),
1690b57cec5SDimitry Andric     cl::init(false), cl::ZeroOrMore);
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric static cl::opt<bool> EnableShrinkWrapping("hexagon-shrink-frame",
1720b57cec5SDimitry Andric     cl::init(true), cl::Hidden, cl::ZeroOrMore,
1730b57cec5SDimitry Andric     cl::desc("Enable stack frame shrink wrapping"));
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric static cl::opt<unsigned> ShrinkLimit("shrink-frame-limit",
1760b57cec5SDimitry Andric     cl::init(std::numeric_limits<unsigned>::max()), cl::Hidden, cl::ZeroOrMore,
1770b57cec5SDimitry Andric     cl::desc("Max count of stack frame shrink-wraps"));
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric static cl::opt<bool> EnableSaveRestoreLong("enable-save-restore-long",
1800b57cec5SDimitry Andric     cl::Hidden, cl::desc("Enable long calls for save-restore stubs."),
1810b57cec5SDimitry Andric     cl::init(false), cl::ZeroOrMore);
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric static cl::opt<bool> EliminateFramePointer("hexagon-fp-elim", cl::init(true),
1840b57cec5SDimitry Andric     cl::Hidden, cl::desc("Refrain from using FP whenever possible"));
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric static cl::opt<bool> OptimizeSpillSlots("hexagon-opt-spill", cl::Hidden,
1870b57cec5SDimitry Andric     cl::init(true), cl::desc("Optimize spill slots"));
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric #ifndef NDEBUG
1900b57cec5SDimitry Andric static cl::opt<unsigned> SpillOptMax("spill-opt-max", cl::Hidden,
1910b57cec5SDimitry Andric     cl::init(std::numeric_limits<unsigned>::max()));
1920b57cec5SDimitry Andric static unsigned SpillOptCount = 0;
1930b57cec5SDimitry Andric #endif
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric namespace llvm {
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   void initializeHexagonCallFrameInformationPass(PassRegistry&);
1980b57cec5SDimitry Andric   FunctionPass *createHexagonCallFrameInformation();
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric } // end namespace llvm
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric namespace {
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   class HexagonCallFrameInformation : public MachineFunctionPass {
2050b57cec5SDimitry Andric   public:
2060b57cec5SDimitry Andric     static char ID;
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric     HexagonCallFrameInformation() : MachineFunctionPass(ID) {
2090b57cec5SDimitry Andric       PassRegistry &PR = *PassRegistry::getPassRegistry();
2100b57cec5SDimitry Andric       initializeHexagonCallFrameInformationPass(PR);
2110b57cec5SDimitry Andric     }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric     bool runOnMachineFunction(MachineFunction &MF) override;
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric     MachineFunctionProperties getRequiredProperties() const override {
2160b57cec5SDimitry Andric       return MachineFunctionProperties().set(
2170b57cec5SDimitry Andric           MachineFunctionProperties::Property::NoVRegs);
2180b57cec5SDimitry Andric     }
2190b57cec5SDimitry Andric   };
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   char HexagonCallFrameInformation::ID = 0;
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric } // end anonymous namespace
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric bool HexagonCallFrameInformation::runOnMachineFunction(MachineFunction &MF) {
2260b57cec5SDimitry Andric   auto &HFI = *MF.getSubtarget<HexagonSubtarget>().getFrameLowering();
227*480093f4SDimitry Andric   bool NeedCFI = MF.needsFrameMoves();
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric   if (!NeedCFI)
2300b57cec5SDimitry Andric     return false;
2310b57cec5SDimitry Andric   HFI.insertCFIInstructions(MF);
2320b57cec5SDimitry Andric   return true;
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric INITIALIZE_PASS(HexagonCallFrameInformation, "hexagon-cfi",
2360b57cec5SDimitry Andric                 "Hexagon call frame information", false, false)
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric FunctionPass *llvm::createHexagonCallFrameInformation() {
2390b57cec5SDimitry Andric   return new HexagonCallFrameInformation();
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric /// Map a register pair Reg to the subregister that has the greater "number",
2430b57cec5SDimitry Andric /// i.e. D3 (aka R7:6) will be mapped to R7, etc.
2440b57cec5SDimitry Andric static unsigned getMax32BitSubRegister(unsigned Reg,
2450b57cec5SDimitry Andric                                        const TargetRegisterInfo &TRI,
2460b57cec5SDimitry Andric                                        bool hireg = true) {
2470b57cec5SDimitry Andric     if (Reg < Hexagon::D0 || Reg > Hexagon::D15)
2480b57cec5SDimitry Andric       return Reg;
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric     unsigned RegNo = 0;
2510b57cec5SDimitry Andric     for (MCSubRegIterator SubRegs(Reg, &TRI); SubRegs.isValid(); ++SubRegs) {
2520b57cec5SDimitry Andric       if (hireg) {
2530b57cec5SDimitry Andric         if (*SubRegs > RegNo)
2540b57cec5SDimitry Andric           RegNo = *SubRegs;
2550b57cec5SDimitry Andric       } else {
2560b57cec5SDimitry Andric         if (!RegNo || *SubRegs < RegNo)
2570b57cec5SDimitry Andric           RegNo = *SubRegs;
2580b57cec5SDimitry Andric       }
2590b57cec5SDimitry Andric     }
2600b57cec5SDimitry Andric     return RegNo;
2610b57cec5SDimitry Andric }
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric /// Returns the callee saved register with the largest id in the vector.
2640b57cec5SDimitry Andric static unsigned getMaxCalleeSavedReg(const std::vector<CalleeSavedInfo> &CSI,
2650b57cec5SDimitry Andric                                      const TargetRegisterInfo &TRI) {
2660b57cec5SDimitry Andric     static_assert(Hexagon::R1 > 0,
2670b57cec5SDimitry Andric                   "Assume physical registers are encoded as positive integers");
2680b57cec5SDimitry Andric     if (CSI.empty())
2690b57cec5SDimitry Andric       return 0;
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric     unsigned Max = getMax32BitSubRegister(CSI[0].getReg(), TRI);
2720b57cec5SDimitry Andric     for (unsigned I = 1, E = CSI.size(); I < E; ++I) {
2730b57cec5SDimitry Andric       unsigned Reg = getMax32BitSubRegister(CSI[I].getReg(), TRI);
2740b57cec5SDimitry Andric       if (Reg > Max)
2750b57cec5SDimitry Andric         Max = Reg;
2760b57cec5SDimitry Andric     }
2770b57cec5SDimitry Andric     return Max;
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric /// Checks if the basic block contains any instruction that needs a stack
2810b57cec5SDimitry Andric /// frame to be already in place.
2820b57cec5SDimitry Andric static bool needsStackFrame(const MachineBasicBlock &MBB, const BitVector &CSR,
2830b57cec5SDimitry Andric                             const HexagonRegisterInfo &HRI) {
2840b57cec5SDimitry Andric     for (auto &I : MBB) {
2850b57cec5SDimitry Andric       const MachineInstr *MI = &I;
2860b57cec5SDimitry Andric       if (MI->isCall())
2870b57cec5SDimitry Andric         return true;
2880b57cec5SDimitry Andric       unsigned Opc = MI->getOpcode();
2890b57cec5SDimitry Andric       switch (Opc) {
2900b57cec5SDimitry Andric         case Hexagon::PS_alloca:
2910b57cec5SDimitry Andric         case Hexagon::PS_aligna:
2920b57cec5SDimitry Andric           return true;
2930b57cec5SDimitry Andric         default:
2940b57cec5SDimitry Andric           break;
2950b57cec5SDimitry Andric       }
2960b57cec5SDimitry Andric       // Check individual operands.
2970b57cec5SDimitry Andric       for (const MachineOperand &MO : MI->operands()) {
2980b57cec5SDimitry Andric         // While the presence of a frame index does not prove that a stack
2990b57cec5SDimitry Andric         // frame will be required, all frame indexes should be within alloc-
3000b57cec5SDimitry Andric         // frame/deallocframe. Otherwise, the code that translates a frame
3010b57cec5SDimitry Andric         // index into an offset would have to be aware of the placement of
3020b57cec5SDimitry Andric         // the frame creation/destruction instructions.
3030b57cec5SDimitry Andric         if (MO.isFI())
3040b57cec5SDimitry Andric           return true;
3050b57cec5SDimitry Andric         if (MO.isReg()) {
3068bcb0991SDimitry Andric           Register R = MO.getReg();
3070b57cec5SDimitry Andric           // Virtual registers will need scavenging, which then may require
3080b57cec5SDimitry Andric           // a stack slot.
3098bcb0991SDimitry Andric           if (Register::isVirtualRegister(R))
3100b57cec5SDimitry Andric             return true;
3110b57cec5SDimitry Andric           for (MCSubRegIterator S(R, &HRI, true); S.isValid(); ++S)
3120b57cec5SDimitry Andric             if (CSR[*S])
3130b57cec5SDimitry Andric               return true;
3140b57cec5SDimitry Andric           continue;
3150b57cec5SDimitry Andric         }
3160b57cec5SDimitry Andric         if (MO.isRegMask()) {
3170b57cec5SDimitry Andric           // A regmask would normally have all callee-saved registers marked
3180b57cec5SDimitry Andric           // as preserved, so this check would not be needed, but in case of
3190b57cec5SDimitry Andric           // ever having other regmasks (for other calling conventions),
3200b57cec5SDimitry Andric           // make sure they would be processed correctly.
3210b57cec5SDimitry Andric           const uint32_t *BM = MO.getRegMask();
3220b57cec5SDimitry Andric           for (int x = CSR.find_first(); x >= 0; x = CSR.find_next(x)) {
3230b57cec5SDimitry Andric             unsigned R = x;
3240b57cec5SDimitry Andric             // If this regmask does not preserve a CSR, a frame will be needed.
3250b57cec5SDimitry Andric             if (!(BM[R/32] & (1u << (R%32))))
3260b57cec5SDimitry Andric               return true;
3270b57cec5SDimitry Andric           }
3280b57cec5SDimitry Andric         }
3290b57cec5SDimitry Andric       }
3300b57cec5SDimitry Andric     }
3310b57cec5SDimitry Andric     return false;
3320b57cec5SDimitry Andric }
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric   /// Returns true if MBB has a machine instructions that indicates a tail call
3350b57cec5SDimitry Andric   /// in the block.
3360b57cec5SDimitry Andric static bool hasTailCall(const MachineBasicBlock &MBB) {
3370b57cec5SDimitry Andric     MachineBasicBlock::const_iterator I = MBB.getLastNonDebugInstr();
3380b57cec5SDimitry Andric     if (I == MBB.end())
3390b57cec5SDimitry Andric       return false;
3400b57cec5SDimitry Andric     unsigned RetOpc = I->getOpcode();
3410b57cec5SDimitry Andric     return RetOpc == Hexagon::PS_tailcall_i || RetOpc == Hexagon::PS_tailcall_r;
3420b57cec5SDimitry Andric }
3430b57cec5SDimitry Andric 
3440b57cec5SDimitry Andric /// Returns true if MBB contains an instruction that returns.
3450b57cec5SDimitry Andric static bool hasReturn(const MachineBasicBlock &MBB) {
3460b57cec5SDimitry Andric     for (auto I = MBB.getFirstTerminator(), E = MBB.end(); I != E; ++I)
3470b57cec5SDimitry Andric       if (I->isReturn())
3480b57cec5SDimitry Andric         return true;
3490b57cec5SDimitry Andric     return false;
3500b57cec5SDimitry Andric }
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric /// Returns the "return" instruction from this block, or nullptr if there
3530b57cec5SDimitry Andric /// isn't any.
3540b57cec5SDimitry Andric static MachineInstr *getReturn(MachineBasicBlock &MBB) {
3550b57cec5SDimitry Andric     for (auto &I : MBB)
3560b57cec5SDimitry Andric       if (I.isReturn())
3570b57cec5SDimitry Andric         return &I;
3580b57cec5SDimitry Andric     return nullptr;
3590b57cec5SDimitry Andric }
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric static bool isRestoreCall(unsigned Opc) {
3620b57cec5SDimitry Andric     switch (Opc) {
3630b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_RET_JMP_V4:
3640b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC:
3650b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT:
3660b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC:
3670b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT:
3680b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC:
3690b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4:
3700b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC:
3710b57cec5SDimitry Andric         return true;
3720b57cec5SDimitry Andric     }
3730b57cec5SDimitry Andric     return false;
3740b57cec5SDimitry Andric }
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric static inline bool isOptNone(const MachineFunction &MF) {
3770b57cec5SDimitry Andric     return MF.getFunction().hasOptNone() ||
3780b57cec5SDimitry Andric            MF.getTarget().getOptLevel() == CodeGenOpt::None;
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric static inline bool isOptSize(const MachineFunction &MF) {
3820b57cec5SDimitry Andric     const Function &F = MF.getFunction();
3830b57cec5SDimitry Andric     return F.hasOptSize() && !F.hasMinSize();
3840b57cec5SDimitry Andric }
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric static inline bool isMinSize(const MachineFunction &MF) {
3870b57cec5SDimitry Andric     return MF.getFunction().hasMinSize();
3880b57cec5SDimitry Andric }
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric /// Implements shrink-wrapping of the stack frame. By default, stack frame
3910b57cec5SDimitry Andric /// is created in the function entry block, and is cleaned up in every block
3920b57cec5SDimitry Andric /// that returns. This function finds alternate blocks: one for the frame
3930b57cec5SDimitry Andric /// setup (prolog) and one for the cleanup (epilog).
3940b57cec5SDimitry Andric void HexagonFrameLowering::findShrunkPrologEpilog(MachineFunction &MF,
3950b57cec5SDimitry Andric       MachineBasicBlock *&PrologB, MachineBasicBlock *&EpilogB) const {
3960b57cec5SDimitry Andric   static unsigned ShrinkCounter = 0;
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric   if (ShrinkLimit.getPosition()) {
3990b57cec5SDimitry Andric     if (ShrinkCounter >= ShrinkLimit)
4000b57cec5SDimitry Andric       return;
4010b57cec5SDimitry Andric     ShrinkCounter++;
4020b57cec5SDimitry Andric   }
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric   MachineDominatorTree MDT;
4070b57cec5SDimitry Andric   MDT.runOnMachineFunction(MF);
4080b57cec5SDimitry Andric   MachinePostDominatorTree MPT;
4090b57cec5SDimitry Andric   MPT.runOnMachineFunction(MF);
4100b57cec5SDimitry Andric 
4110b57cec5SDimitry Andric   using UnsignedMap = DenseMap<unsigned, unsigned>;
4120b57cec5SDimitry Andric   using RPOTType = ReversePostOrderTraversal<const MachineFunction *>;
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric   UnsignedMap RPO;
4150b57cec5SDimitry Andric   RPOTType RPOT(&MF);
4160b57cec5SDimitry Andric   unsigned RPON = 0;
4170b57cec5SDimitry Andric   for (RPOTType::rpo_iterator I = RPOT.begin(), E = RPOT.end(); I != E; ++I)
4180b57cec5SDimitry Andric     RPO[(*I)->getNumber()] = RPON++;
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric   // Don't process functions that have loops, at least for now. Placement
4210b57cec5SDimitry Andric   // of prolog and epilog must take loop structure into account. For simpli-
4220b57cec5SDimitry Andric   // city don't do it right now.
4230b57cec5SDimitry Andric   for (auto &I : MF) {
4240b57cec5SDimitry Andric     unsigned BN = RPO[I.getNumber()];
4250b57cec5SDimitry Andric     for (auto SI = I.succ_begin(), SE = I.succ_end(); SI != SE; ++SI) {
4260b57cec5SDimitry Andric       // If found a back-edge, return.
4270b57cec5SDimitry Andric       if (RPO[(*SI)->getNumber()] <= BN)
4280b57cec5SDimitry Andric         return;
4290b57cec5SDimitry Andric     }
4300b57cec5SDimitry Andric   }
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric   // Collect the set of blocks that need a stack frame to execute. Scan
4330b57cec5SDimitry Andric   // each block for uses/defs of callee-saved registers, calls, etc.
4340b57cec5SDimitry Andric   SmallVector<MachineBasicBlock*,16> SFBlocks;
4350b57cec5SDimitry Andric   BitVector CSR(Hexagon::NUM_TARGET_REGS);
4360b57cec5SDimitry Andric   for (const MCPhysReg *P = HRI.getCalleeSavedRegs(&MF); *P; ++P)
4370b57cec5SDimitry Andric     for (MCSubRegIterator S(*P, &HRI, true); S.isValid(); ++S)
4380b57cec5SDimitry Andric       CSR[*S] = true;
4390b57cec5SDimitry Andric 
4400b57cec5SDimitry Andric   for (auto &I : MF)
4410b57cec5SDimitry Andric     if (needsStackFrame(I, CSR, HRI))
4420b57cec5SDimitry Andric       SFBlocks.push_back(&I);
4430b57cec5SDimitry Andric 
4440b57cec5SDimitry Andric   LLVM_DEBUG({
4450b57cec5SDimitry Andric     dbgs() << "Blocks needing SF: {";
4460b57cec5SDimitry Andric     for (auto &B : SFBlocks)
4470b57cec5SDimitry Andric       dbgs() << " " << printMBBReference(*B);
4480b57cec5SDimitry Andric     dbgs() << " }\n";
4490b57cec5SDimitry Andric   });
4500b57cec5SDimitry Andric   // No frame needed?
4510b57cec5SDimitry Andric   if (SFBlocks.empty())
4520b57cec5SDimitry Andric     return;
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric   // Pick a common dominator and a common post-dominator.
4550b57cec5SDimitry Andric   MachineBasicBlock *DomB = SFBlocks[0];
4560b57cec5SDimitry Andric   for (unsigned i = 1, n = SFBlocks.size(); i < n; ++i) {
4570b57cec5SDimitry Andric     DomB = MDT.findNearestCommonDominator(DomB, SFBlocks[i]);
4580b57cec5SDimitry Andric     if (!DomB)
4590b57cec5SDimitry Andric       break;
4600b57cec5SDimitry Andric   }
4610b57cec5SDimitry Andric   MachineBasicBlock *PDomB = SFBlocks[0];
4620b57cec5SDimitry Andric   for (unsigned i = 1, n = SFBlocks.size(); i < n; ++i) {
4630b57cec5SDimitry Andric     PDomB = MPT.findNearestCommonDominator(PDomB, SFBlocks[i]);
4640b57cec5SDimitry Andric     if (!PDomB)
4650b57cec5SDimitry Andric       break;
4660b57cec5SDimitry Andric   }
4670b57cec5SDimitry Andric   LLVM_DEBUG({
4680b57cec5SDimitry Andric     dbgs() << "Computed dom block: ";
4690b57cec5SDimitry Andric     if (DomB)
4700b57cec5SDimitry Andric       dbgs() << printMBBReference(*DomB);
4710b57cec5SDimitry Andric     else
4720b57cec5SDimitry Andric       dbgs() << "<null>";
4730b57cec5SDimitry Andric     dbgs() << ", computed pdom block: ";
4740b57cec5SDimitry Andric     if (PDomB)
4750b57cec5SDimitry Andric       dbgs() << printMBBReference(*PDomB);
4760b57cec5SDimitry Andric     else
4770b57cec5SDimitry Andric       dbgs() << "<null>";
4780b57cec5SDimitry Andric     dbgs() << "\n";
4790b57cec5SDimitry Andric   });
4800b57cec5SDimitry Andric   if (!DomB || !PDomB)
4810b57cec5SDimitry Andric     return;
4820b57cec5SDimitry Andric 
4830b57cec5SDimitry Andric   // Make sure that DomB dominates PDomB and PDomB post-dominates DomB.
4840b57cec5SDimitry Andric   if (!MDT.dominates(DomB, PDomB)) {
4850b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Dom block does not dominate pdom block\n");
4860b57cec5SDimitry Andric     return;
4870b57cec5SDimitry Andric   }
4880b57cec5SDimitry Andric   if (!MPT.dominates(PDomB, DomB)) {
4890b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "PDom block does not post-dominate dom block\n");
4900b57cec5SDimitry Andric     return;
4910b57cec5SDimitry Andric   }
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric   // Finally, everything seems right.
4940b57cec5SDimitry Andric   PrologB = DomB;
4950b57cec5SDimitry Andric   EpilogB = PDomB;
4960b57cec5SDimitry Andric }
4970b57cec5SDimitry Andric 
4980b57cec5SDimitry Andric /// Perform most of the PEI work here:
4990b57cec5SDimitry Andric /// - saving/restoring of the callee-saved registers,
5000b57cec5SDimitry Andric /// - stack frame creation and destruction.
5010b57cec5SDimitry Andric /// Normally, this work is distributed among various functions, but doing it
5020b57cec5SDimitry Andric /// in one place allows shrink-wrapping of the stack frame.
5030b57cec5SDimitry Andric void HexagonFrameLowering::emitPrologue(MachineFunction &MF,
5040b57cec5SDimitry Andric                                         MachineBasicBlock &MBB) const {
5050b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
5060b57cec5SDimitry Andric 
5070b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
5080b57cec5SDimitry Andric   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric   MachineBasicBlock *PrologB = &MF.front(), *EpilogB = nullptr;
5110b57cec5SDimitry Andric   if (EnableShrinkWrapping)
5120b57cec5SDimitry Andric     findShrunkPrologEpilog(MF, PrologB, EpilogB);
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric   bool PrologueStubs = false;
5150b57cec5SDimitry Andric   insertCSRSpillsInBlock(*PrologB, CSI, HRI, PrologueStubs);
5160b57cec5SDimitry Andric   insertPrologueInBlock(*PrologB, PrologueStubs);
5170b57cec5SDimitry Andric   updateEntryPaths(MF, *PrologB);
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric   if (EpilogB) {
5200b57cec5SDimitry Andric     insertCSRRestoresInBlock(*EpilogB, CSI, HRI);
5210b57cec5SDimitry Andric     insertEpilogueInBlock(*EpilogB);
5220b57cec5SDimitry Andric   } else {
5230b57cec5SDimitry Andric     for (auto &B : MF)
5240b57cec5SDimitry Andric       if (B.isReturnBlock())
5250b57cec5SDimitry Andric         insertCSRRestoresInBlock(B, CSI, HRI);
5260b57cec5SDimitry Andric 
5270b57cec5SDimitry Andric     for (auto &B : MF)
5280b57cec5SDimitry Andric       if (B.isReturnBlock())
5290b57cec5SDimitry Andric         insertEpilogueInBlock(B);
5300b57cec5SDimitry Andric 
5310b57cec5SDimitry Andric     for (auto &B : MF) {
5320b57cec5SDimitry Andric       if (B.empty())
5330b57cec5SDimitry Andric         continue;
5340b57cec5SDimitry Andric       MachineInstr *RetI = getReturn(B);
5350b57cec5SDimitry Andric       if (!RetI || isRestoreCall(RetI->getOpcode()))
5360b57cec5SDimitry Andric         continue;
5370b57cec5SDimitry Andric       for (auto &R : CSI)
5380b57cec5SDimitry Andric         RetI->addOperand(MachineOperand::CreateReg(R.getReg(), false, true));
5390b57cec5SDimitry Andric     }
5400b57cec5SDimitry Andric   }
5410b57cec5SDimitry Andric 
5420b57cec5SDimitry Andric   if (EpilogB) {
5430b57cec5SDimitry Andric     // If there is an epilog block, it may not have a return instruction.
5440b57cec5SDimitry Andric     // In such case, we need to add the callee-saved registers as live-ins
5450b57cec5SDimitry Andric     // in all blocks on all paths from the epilog to any return block.
5460b57cec5SDimitry Andric     unsigned MaxBN = MF.getNumBlockIDs();
5470b57cec5SDimitry Andric     BitVector DoneT(MaxBN+1), DoneF(MaxBN+1), Path(MaxBN+1);
5480b57cec5SDimitry Andric     updateExitPaths(*EpilogB, *EpilogB, DoneT, DoneF, Path);
5490b57cec5SDimitry Andric   }
5500b57cec5SDimitry Andric }
5510b57cec5SDimitry Andric 
5520b57cec5SDimitry Andric /// Returns true if the target can safely skip saving callee-saved registers
5530b57cec5SDimitry Andric /// for noreturn nounwind functions.
5540b57cec5SDimitry Andric bool HexagonFrameLowering::enableCalleeSaveSkip(
5550b57cec5SDimitry Andric     const MachineFunction &MF) const {
5560b57cec5SDimitry Andric   const auto &F = MF.getFunction();
5570b57cec5SDimitry Andric   assert(F.hasFnAttribute(Attribute::NoReturn) &&
5580b57cec5SDimitry Andric          F.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
5590b57cec5SDimitry Andric          !F.getFunction().hasFnAttribute(Attribute::UWTable));
5600b57cec5SDimitry Andric   (void)F;
5610b57cec5SDimitry Andric 
5620b57cec5SDimitry Andric   // No need to save callee saved registers if the function does not return.
5630b57cec5SDimitry Andric   return MF.getSubtarget<HexagonSubtarget>().noreturnStackElim();
5640b57cec5SDimitry Andric }
5650b57cec5SDimitry Andric 
5660b57cec5SDimitry Andric // Helper function used to determine when to eliminate the stack frame for
5670b57cec5SDimitry Andric // functions marked as noreturn and when the noreturn-stack-elim options are
5680b57cec5SDimitry Andric // specified. When both these conditions are true, then a FP may not be needed
5690b57cec5SDimitry Andric // if the function makes a call. It is very similar to enableCalleeSaveSkip,
5700b57cec5SDimitry Andric // but it used to check if the allocframe can be eliminated as well.
5710b57cec5SDimitry Andric static bool enableAllocFrameElim(const MachineFunction &MF) {
5720b57cec5SDimitry Andric   const auto &F = MF.getFunction();
5730b57cec5SDimitry Andric   const auto &MFI = MF.getFrameInfo();
5740b57cec5SDimitry Andric   const auto &HST = MF.getSubtarget<HexagonSubtarget>();
5750b57cec5SDimitry Andric   assert(!MFI.hasVarSizedObjects() &&
5760b57cec5SDimitry Andric          !HST.getRegisterInfo()->needsStackRealignment(MF));
5770b57cec5SDimitry Andric   return F.hasFnAttribute(Attribute::NoReturn) &&
5780b57cec5SDimitry Andric     F.hasFnAttribute(Attribute::NoUnwind) &&
5790b57cec5SDimitry Andric     !F.hasFnAttribute(Attribute::UWTable) && HST.noreturnStackElim() &&
5800b57cec5SDimitry Andric     MFI.getStackSize() == 0;
5810b57cec5SDimitry Andric }
5820b57cec5SDimitry Andric 
5830b57cec5SDimitry Andric void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB,
5840b57cec5SDimitry Andric       bool PrologueStubs) const {
5850b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
5860b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
5870b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
5880b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
5890b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
5900b57cec5SDimitry Andric 
5910b57cec5SDimitry Andric   unsigned MaxAlign = std::max(MFI.getMaxAlignment(), getStackAlignment());
5920b57cec5SDimitry Andric 
5930b57cec5SDimitry Andric   // Calculate the total stack frame size.
5940b57cec5SDimitry Andric   // Get the number of bytes to allocate from the FrameInfo.
5950b57cec5SDimitry Andric   unsigned FrameSize = MFI.getStackSize();
5960b57cec5SDimitry Andric   // Round up the max call frame size to the max alignment on the stack.
5970b57cec5SDimitry Andric   unsigned MaxCFA = alignTo(MFI.getMaxCallFrameSize(), MaxAlign);
5980b57cec5SDimitry Andric   MFI.setMaxCallFrameSize(MaxCFA);
5990b57cec5SDimitry Andric 
6000b57cec5SDimitry Andric   FrameSize = MaxCFA + alignTo(FrameSize, MaxAlign);
6010b57cec5SDimitry Andric   MFI.setStackSize(FrameSize);
6020b57cec5SDimitry Andric 
6030b57cec5SDimitry Andric   bool AlignStack = (MaxAlign > getStackAlignment());
6040b57cec5SDimitry Andric 
6050b57cec5SDimitry Andric   // Get the number of bytes to allocate from the FrameInfo.
6060b57cec5SDimitry Andric   unsigned NumBytes = MFI.getStackSize();
6070b57cec5SDimitry Andric   unsigned SP = HRI.getStackRegister();
6080b57cec5SDimitry Andric   unsigned MaxCF = MFI.getMaxCallFrameSize();
6090b57cec5SDimitry Andric   MachineBasicBlock::iterator InsertPt = MBB.begin();
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric   SmallVector<MachineInstr *, 4> AdjustRegs;
6120b57cec5SDimitry Andric   for (auto &MBB : MF)
6130b57cec5SDimitry Andric     for (auto &MI : MBB)
6140b57cec5SDimitry Andric       if (MI.getOpcode() == Hexagon::PS_alloca)
6150b57cec5SDimitry Andric         AdjustRegs.push_back(&MI);
6160b57cec5SDimitry Andric 
6170b57cec5SDimitry Andric   for (auto MI : AdjustRegs) {
6180b57cec5SDimitry Andric     assert((MI->getOpcode() == Hexagon::PS_alloca) && "Expected alloca");
6190b57cec5SDimitry Andric     expandAlloca(MI, HII, SP, MaxCF);
6200b57cec5SDimitry Andric     MI->eraseFromParent();
6210b57cec5SDimitry Andric   }
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric   DebugLoc dl = MBB.findDebugLoc(InsertPt);
6240b57cec5SDimitry Andric 
6250b57cec5SDimitry Andric   if (hasFP(MF)) {
6260b57cec5SDimitry Andric     insertAllocframe(MBB, InsertPt, NumBytes);
6270b57cec5SDimitry Andric     if (AlignStack) {
6280b57cec5SDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_andir), SP)
6290b57cec5SDimitry Andric           .addReg(SP)
6300b57cec5SDimitry Andric           .addImm(-int64_t(MaxAlign));
6310b57cec5SDimitry Andric     }
6320b57cec5SDimitry Andric     // If the stack-checking is enabled, and we spilled the callee-saved
6330b57cec5SDimitry Andric     // registers inline (i.e. did not use a spill function), then call
6340b57cec5SDimitry Andric     // the stack checker directly.
6350b57cec5SDimitry Andric     if (EnableStackOVFSanitizer && !PrologueStubs)
6360b57cec5SDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::PS_call_stk))
6370b57cec5SDimitry Andric              .addExternalSymbol("__runtime_stack_check");
6380b57cec5SDimitry Andric   } else if (NumBytes > 0) {
6390b57cec5SDimitry Andric     assert(alignTo(NumBytes, 8) == NumBytes);
6400b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP)
6410b57cec5SDimitry Andric       .addReg(SP)
6420b57cec5SDimitry Andric       .addImm(-int(NumBytes));
6430b57cec5SDimitry Andric   }
6440b57cec5SDimitry Andric }
6450b57cec5SDimitry Andric 
6460b57cec5SDimitry Andric void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const {
6470b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
6480b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
6490b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
6500b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
6510b57cec5SDimitry Andric   unsigned SP = HRI.getStackRegister();
6520b57cec5SDimitry Andric 
6530b57cec5SDimitry Andric   MachineBasicBlock::iterator InsertPt = MBB.getFirstTerminator();
6540b57cec5SDimitry Andric   DebugLoc dl = MBB.findDebugLoc(InsertPt);
6550b57cec5SDimitry Andric 
6560b57cec5SDimitry Andric   if (!hasFP(MF)) {
6570b57cec5SDimitry Andric     MachineFrameInfo &MFI = MF.getFrameInfo();
6580b57cec5SDimitry Andric     if (unsigned NumBytes = MFI.getStackSize()) {
6590b57cec5SDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP)
6600b57cec5SDimitry Andric         .addReg(SP)
6610b57cec5SDimitry Andric         .addImm(NumBytes);
6620b57cec5SDimitry Andric     }
6630b57cec5SDimitry Andric     return;
6640b57cec5SDimitry Andric   }
6650b57cec5SDimitry Andric 
6660b57cec5SDimitry Andric   MachineInstr *RetI = getReturn(MBB);
6670b57cec5SDimitry Andric   unsigned RetOpc = RetI ? RetI->getOpcode() : 0;
6680b57cec5SDimitry Andric 
6690b57cec5SDimitry Andric   // Handle EH_RETURN.
6700b57cec5SDimitry Andric   if (RetOpc == Hexagon::EH_RETURN_JMPR) {
6710b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::L2_deallocframe))
6720b57cec5SDimitry Andric         .addDef(Hexagon::D15)
6730b57cec5SDimitry Andric         .addReg(Hexagon::R30);
6740b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_add), SP)
6750b57cec5SDimitry Andric         .addReg(SP)
6760b57cec5SDimitry Andric         .addReg(Hexagon::R28);
6770b57cec5SDimitry Andric     return;
6780b57cec5SDimitry Andric   }
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric   // Check for RESTORE_DEALLOC_RET* tail call. Don't emit an extra dealloc-
6810b57cec5SDimitry Andric   // frame instruction if we encounter it.
6820b57cec5SDimitry Andric   if (RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4 ||
6830b57cec5SDimitry Andric       RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC ||
6840b57cec5SDimitry Andric       RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT ||
6850b57cec5SDimitry Andric       RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC) {
6860b57cec5SDimitry Andric     MachineBasicBlock::iterator It = RetI;
6870b57cec5SDimitry Andric     ++It;
6880b57cec5SDimitry Andric     // Delete all instructions after the RESTORE (except labels).
6890b57cec5SDimitry Andric     while (It != MBB.end()) {
6900b57cec5SDimitry Andric       if (!It->isLabel())
6910b57cec5SDimitry Andric         It = MBB.erase(It);
6920b57cec5SDimitry Andric       else
6930b57cec5SDimitry Andric         ++It;
6940b57cec5SDimitry Andric     }
6950b57cec5SDimitry Andric     return;
6960b57cec5SDimitry Andric   }
6970b57cec5SDimitry Andric 
6980b57cec5SDimitry Andric   // It is possible that the restoring code is a call to a library function.
6990b57cec5SDimitry Andric   // All of the restore* functions include "deallocframe", so we need to make
7000b57cec5SDimitry Andric   // sure that we don't add an extra one.
7010b57cec5SDimitry Andric   bool NeedsDeallocframe = true;
7020b57cec5SDimitry Andric   if (!MBB.empty() && InsertPt != MBB.begin()) {
7030b57cec5SDimitry Andric     MachineBasicBlock::iterator PrevIt = std::prev(InsertPt);
7040b57cec5SDimitry Andric     unsigned COpc = PrevIt->getOpcode();
7050b57cec5SDimitry Andric     if (COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4 ||
7060b57cec5SDimitry Andric         COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC ||
7070b57cec5SDimitry Andric         COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT ||
7080b57cec5SDimitry Andric         COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC ||
7090b57cec5SDimitry Andric         COpc == Hexagon::PS_call_nr || COpc == Hexagon::PS_callr_nr)
7100b57cec5SDimitry Andric       NeedsDeallocframe = false;
7110b57cec5SDimitry Andric   }
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric   if (!NeedsDeallocframe)
7140b57cec5SDimitry Andric     return;
7150b57cec5SDimitry Andric   // If the returning instruction is PS_jmpret, replace it with dealloc_return,
7160b57cec5SDimitry Andric   // otherwise just add deallocframe. The function could be returning via a
7170b57cec5SDimitry Andric   // tail call.
7180b57cec5SDimitry Andric   if (RetOpc != Hexagon::PS_jmpret || DisableDeallocRet) {
7190b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::L2_deallocframe))
7200b57cec5SDimitry Andric       .addDef(Hexagon::D15)
7210b57cec5SDimitry Andric       .addReg(Hexagon::R30);
7220b57cec5SDimitry Andric     return;
7230b57cec5SDimitry Andric   }
7240b57cec5SDimitry Andric   unsigned NewOpc = Hexagon::L4_return;
7250b57cec5SDimitry Andric   MachineInstr *NewI = BuildMI(MBB, RetI, dl, HII.get(NewOpc))
7260b57cec5SDimitry Andric       .addDef(Hexagon::D15)
7270b57cec5SDimitry Andric       .addReg(Hexagon::R30);
7280b57cec5SDimitry Andric   // Transfer the function live-out registers.
7290b57cec5SDimitry Andric   NewI->copyImplicitOps(MF, *RetI);
7300b57cec5SDimitry Andric   MBB.erase(RetI);
7310b57cec5SDimitry Andric }
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric void HexagonFrameLowering::insertAllocframe(MachineBasicBlock &MBB,
7340b57cec5SDimitry Andric       MachineBasicBlock::iterator InsertPt, unsigned NumBytes) const {
7350b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
7360b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
7370b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
7380b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric   // Check for overflow.
7410b57cec5SDimitry Andric   // Hexagon_TODO: Ugh! hardcoding. Is there an API that can be used?
7420b57cec5SDimitry Andric   const unsigned int ALLOCFRAME_MAX = 16384;
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric   // Create a dummy memory operand to avoid allocframe from being treated as
7450b57cec5SDimitry Andric   // a volatile memory reference.
7460b57cec5SDimitry Andric   auto *MMO = MF.getMachineMemOperand(MachinePointerInfo::getStack(MF, 0),
7470b57cec5SDimitry Andric                                       MachineMemOperand::MOStore, 4, 4);
7480b57cec5SDimitry Andric 
7490b57cec5SDimitry Andric   DebugLoc dl = MBB.findDebugLoc(InsertPt);
7500b57cec5SDimitry Andric   unsigned SP = HRI.getStackRegister();
7510b57cec5SDimitry Andric 
7520b57cec5SDimitry Andric   if (NumBytes >= ALLOCFRAME_MAX) {
7530b57cec5SDimitry Andric     // Emit allocframe(#0).
7540b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::S2_allocframe))
7550b57cec5SDimitry Andric       .addDef(SP)
7560b57cec5SDimitry Andric       .addReg(SP)
7570b57cec5SDimitry Andric       .addImm(0)
7580b57cec5SDimitry Andric       .addMemOperand(MMO);
7590b57cec5SDimitry Andric 
7600b57cec5SDimitry Andric     // Subtract the size from the stack pointer.
7610b57cec5SDimitry Andric     unsigned SP = HRI.getStackRegister();
7620b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP)
7630b57cec5SDimitry Andric       .addReg(SP)
7640b57cec5SDimitry Andric       .addImm(-int(NumBytes));
7650b57cec5SDimitry Andric   } else {
7660b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::S2_allocframe))
7670b57cec5SDimitry Andric       .addDef(SP)
7680b57cec5SDimitry Andric       .addReg(SP)
7690b57cec5SDimitry Andric       .addImm(NumBytes)
7700b57cec5SDimitry Andric       .addMemOperand(MMO);
7710b57cec5SDimitry Andric   }
7720b57cec5SDimitry Andric }
7730b57cec5SDimitry Andric 
7740b57cec5SDimitry Andric void HexagonFrameLowering::updateEntryPaths(MachineFunction &MF,
7750b57cec5SDimitry Andric       MachineBasicBlock &SaveB) const {
7760b57cec5SDimitry Andric   SetVector<unsigned> Worklist;
7770b57cec5SDimitry Andric 
7780b57cec5SDimitry Andric   MachineBasicBlock &EntryB = MF.front();
7790b57cec5SDimitry Andric   Worklist.insert(EntryB.getNumber());
7800b57cec5SDimitry Andric 
7810b57cec5SDimitry Andric   unsigned SaveN = SaveB.getNumber();
7820b57cec5SDimitry Andric   auto &CSI = MF.getFrameInfo().getCalleeSavedInfo();
7830b57cec5SDimitry Andric 
7840b57cec5SDimitry Andric   for (unsigned i = 0; i < Worklist.size(); ++i) {
7850b57cec5SDimitry Andric     unsigned BN = Worklist[i];
7860b57cec5SDimitry Andric     MachineBasicBlock &MBB = *MF.getBlockNumbered(BN);
7870b57cec5SDimitry Andric     for (auto &R : CSI)
7880b57cec5SDimitry Andric       if (!MBB.isLiveIn(R.getReg()))
7890b57cec5SDimitry Andric         MBB.addLiveIn(R.getReg());
7900b57cec5SDimitry Andric     if (BN != SaveN)
7910b57cec5SDimitry Andric       for (auto &SB : MBB.successors())
7920b57cec5SDimitry Andric         Worklist.insert(SB->getNumber());
7930b57cec5SDimitry Andric   }
7940b57cec5SDimitry Andric }
7950b57cec5SDimitry Andric 
7960b57cec5SDimitry Andric bool HexagonFrameLowering::updateExitPaths(MachineBasicBlock &MBB,
7970b57cec5SDimitry Andric       MachineBasicBlock &RestoreB, BitVector &DoneT, BitVector &DoneF,
7980b57cec5SDimitry Andric       BitVector &Path) const {
7990b57cec5SDimitry Andric   assert(MBB.getNumber() >= 0);
8000b57cec5SDimitry Andric   unsigned BN = MBB.getNumber();
8010b57cec5SDimitry Andric   if (Path[BN] || DoneF[BN])
8020b57cec5SDimitry Andric     return false;
8030b57cec5SDimitry Andric   if (DoneT[BN])
8040b57cec5SDimitry Andric     return true;
8050b57cec5SDimitry Andric 
8060b57cec5SDimitry Andric   auto &CSI = MBB.getParent()->getFrameInfo().getCalleeSavedInfo();
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric   Path[BN] = true;
8090b57cec5SDimitry Andric   bool ReachedExit = false;
8100b57cec5SDimitry Andric   for (auto &SB : MBB.successors())
8110b57cec5SDimitry Andric     ReachedExit |= updateExitPaths(*SB, RestoreB, DoneT, DoneF, Path);
8120b57cec5SDimitry Andric 
8130b57cec5SDimitry Andric   if (!MBB.empty() && MBB.back().isReturn()) {
8140b57cec5SDimitry Andric     // Add implicit uses of all callee-saved registers to the reached
8150b57cec5SDimitry Andric     // return instructions. This is to prevent the anti-dependency breaker
8160b57cec5SDimitry Andric     // from renaming these registers.
8170b57cec5SDimitry Andric     MachineInstr &RetI = MBB.back();
8180b57cec5SDimitry Andric     if (!isRestoreCall(RetI.getOpcode()))
8190b57cec5SDimitry Andric       for (auto &R : CSI)
8200b57cec5SDimitry Andric         RetI.addOperand(MachineOperand::CreateReg(R.getReg(), false, true));
8210b57cec5SDimitry Andric     ReachedExit = true;
8220b57cec5SDimitry Andric   }
8230b57cec5SDimitry Andric 
8240b57cec5SDimitry Andric   // We don't want to add unnecessary live-ins to the restore block: since
8250b57cec5SDimitry Andric   // the callee-saved registers are being defined in it, the entry of the
8260b57cec5SDimitry Andric   // restore block cannot be on the path from the definitions to any exit.
8270b57cec5SDimitry Andric   if (ReachedExit && &MBB != &RestoreB) {
8280b57cec5SDimitry Andric     for (auto &R : CSI)
8290b57cec5SDimitry Andric       if (!MBB.isLiveIn(R.getReg()))
8300b57cec5SDimitry Andric         MBB.addLiveIn(R.getReg());
8310b57cec5SDimitry Andric     DoneT[BN] = true;
8320b57cec5SDimitry Andric   }
8330b57cec5SDimitry Andric   if (!ReachedExit)
8340b57cec5SDimitry Andric     DoneF[BN] = true;
8350b57cec5SDimitry Andric 
8360b57cec5SDimitry Andric   Path[BN] = false;
8370b57cec5SDimitry Andric   return ReachedExit;
8380b57cec5SDimitry Andric }
8390b57cec5SDimitry Andric 
8400b57cec5SDimitry Andric static Optional<MachineBasicBlock::iterator>
8410b57cec5SDimitry Andric findCFILocation(MachineBasicBlock &B) {
8420b57cec5SDimitry Andric     // The CFI instructions need to be inserted right after allocframe.
8430b57cec5SDimitry Andric     // An exception to this is a situation where allocframe is bundled
8440b57cec5SDimitry Andric     // with a call: then the CFI instructions need to be inserted before
8450b57cec5SDimitry Andric     // the packet with the allocframe+call (in case the call throws an
8460b57cec5SDimitry Andric     // exception).
8470b57cec5SDimitry Andric     auto End = B.instr_end();
8480b57cec5SDimitry Andric 
8490b57cec5SDimitry Andric     for (MachineInstr &I : B) {
8500b57cec5SDimitry Andric       MachineBasicBlock::iterator It = I.getIterator();
8510b57cec5SDimitry Andric       if (!I.isBundle()) {
8520b57cec5SDimitry Andric         if (I.getOpcode() == Hexagon::S2_allocframe)
8530b57cec5SDimitry Andric           return std::next(It);
8540b57cec5SDimitry Andric         continue;
8550b57cec5SDimitry Andric       }
8560b57cec5SDimitry Andric       // I is a bundle.
8570b57cec5SDimitry Andric       bool HasCall = false, HasAllocFrame = false;
8580b57cec5SDimitry Andric       auto T = It.getInstrIterator();
8590b57cec5SDimitry Andric       while (++T != End && T->isBundled()) {
8600b57cec5SDimitry Andric         if (T->getOpcode() == Hexagon::S2_allocframe)
8610b57cec5SDimitry Andric           HasAllocFrame = true;
8620b57cec5SDimitry Andric         else if (T->isCall())
8630b57cec5SDimitry Andric           HasCall = true;
8640b57cec5SDimitry Andric       }
8650b57cec5SDimitry Andric       if (HasAllocFrame)
8660b57cec5SDimitry Andric         return HasCall ? It : std::next(It);
8670b57cec5SDimitry Andric     }
8680b57cec5SDimitry Andric     return None;
8690b57cec5SDimitry Andric }
8700b57cec5SDimitry Andric 
8710b57cec5SDimitry Andric void HexagonFrameLowering::insertCFIInstructions(MachineFunction &MF) const {
8720b57cec5SDimitry Andric   for (auto &B : MF) {
8730b57cec5SDimitry Andric     auto At = findCFILocation(B);
8740b57cec5SDimitry Andric     if (At.hasValue())
8750b57cec5SDimitry Andric       insertCFIInstructionsAt(B, At.getValue());
8760b57cec5SDimitry Andric   }
8770b57cec5SDimitry Andric }
8780b57cec5SDimitry Andric 
8790b57cec5SDimitry Andric void HexagonFrameLowering::insertCFIInstructionsAt(MachineBasicBlock &MBB,
8800b57cec5SDimitry Andric       MachineBasicBlock::iterator At) const {
8810b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
8820b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
8830b57cec5SDimitry Andric   MachineModuleInfo &MMI = MF.getMMI();
8840b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
8850b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
8860b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
8870b57cec5SDimitry Andric 
8880b57cec5SDimitry Andric   // If CFI instructions have debug information attached, something goes
8890b57cec5SDimitry Andric   // wrong with the final assembly generation: the prolog_end is placed
8900b57cec5SDimitry Andric   // in a wrong location.
8910b57cec5SDimitry Andric   DebugLoc DL;
8920b57cec5SDimitry Andric   const MCInstrDesc &CFID = HII.get(TargetOpcode::CFI_INSTRUCTION);
8930b57cec5SDimitry Andric 
8940b57cec5SDimitry Andric   MCSymbol *FrameLabel = MMI.getContext().createTempSymbol();
8950b57cec5SDimitry Andric   bool HasFP = hasFP(MF);
8960b57cec5SDimitry Andric 
8970b57cec5SDimitry Andric   if (HasFP) {
8980b57cec5SDimitry Andric     unsigned DwFPReg = HRI.getDwarfRegNum(HRI.getFrameRegister(), true);
8990b57cec5SDimitry Andric     unsigned DwRAReg = HRI.getDwarfRegNum(HRI.getRARegister(), true);
9000b57cec5SDimitry Andric 
9010b57cec5SDimitry Andric     // Define CFA via an offset from the value of FP.
9020b57cec5SDimitry Andric     //
9030b57cec5SDimitry Andric     //  -8   -4    0 (SP)
9040b57cec5SDimitry Andric     // --+----+----+---------------------
9050b57cec5SDimitry Andric     //   | FP | LR |          increasing addresses -->
9060b57cec5SDimitry Andric     // --+----+----+---------------------
9070b57cec5SDimitry Andric     //   |         +-- Old SP (before allocframe)
9080b57cec5SDimitry Andric     //   +-- New FP (after allocframe)
9090b57cec5SDimitry Andric     //
9100b57cec5SDimitry Andric     // MCCFIInstruction::createDefCfa subtracts the offset from the register.
9110b57cec5SDimitry Andric     // MCCFIInstruction::createOffset takes the offset without sign change.
9120b57cec5SDimitry Andric     auto DefCfa = MCCFIInstruction::createDefCfa(FrameLabel, DwFPReg, -8);
9130b57cec5SDimitry Andric     BuildMI(MBB, At, DL, CFID)
9140b57cec5SDimitry Andric         .addCFIIndex(MF.addFrameInst(DefCfa));
9150b57cec5SDimitry Andric     // R31 (return addr) = CFA - 4
9160b57cec5SDimitry Andric     auto OffR31 = MCCFIInstruction::createOffset(FrameLabel, DwRAReg, -4);
9170b57cec5SDimitry Andric     BuildMI(MBB, At, DL, CFID)
9180b57cec5SDimitry Andric         .addCFIIndex(MF.addFrameInst(OffR31));
9190b57cec5SDimitry Andric     // R30 (frame ptr) = CFA - 8
9200b57cec5SDimitry Andric     auto OffR30 = MCCFIInstruction::createOffset(FrameLabel, DwFPReg, -8);
9210b57cec5SDimitry Andric     BuildMI(MBB, At, DL, CFID)
9220b57cec5SDimitry Andric         .addCFIIndex(MF.addFrameInst(OffR30));
9230b57cec5SDimitry Andric   }
9240b57cec5SDimitry Andric 
9250b57cec5SDimitry Andric   static unsigned int RegsToMove[] = {
9260b57cec5SDimitry Andric     Hexagon::R1,  Hexagon::R0,  Hexagon::R3,  Hexagon::R2,
9270b57cec5SDimitry Andric     Hexagon::R17, Hexagon::R16, Hexagon::R19, Hexagon::R18,
9280b57cec5SDimitry Andric     Hexagon::R21, Hexagon::R20, Hexagon::R23, Hexagon::R22,
9290b57cec5SDimitry Andric     Hexagon::R25, Hexagon::R24, Hexagon::R27, Hexagon::R26,
9300b57cec5SDimitry Andric     Hexagon::D0,  Hexagon::D1,  Hexagon::D8,  Hexagon::D9,
9310b57cec5SDimitry Andric     Hexagon::D10, Hexagon::D11, Hexagon::D12, Hexagon::D13,
9320b57cec5SDimitry Andric     Hexagon::NoRegister
9330b57cec5SDimitry Andric   };
9340b57cec5SDimitry Andric 
9350b57cec5SDimitry Andric   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
9360b57cec5SDimitry Andric 
9370b57cec5SDimitry Andric   for (unsigned i = 0; RegsToMove[i] != Hexagon::NoRegister; ++i) {
9380b57cec5SDimitry Andric     unsigned Reg = RegsToMove[i];
9390b57cec5SDimitry Andric     auto IfR = [Reg] (const CalleeSavedInfo &C) -> bool {
9400b57cec5SDimitry Andric       return C.getReg() == Reg;
9410b57cec5SDimitry Andric     };
9420b57cec5SDimitry Andric     auto F = find_if(CSI, IfR);
9430b57cec5SDimitry Andric     if (F == CSI.end())
9440b57cec5SDimitry Andric       continue;
9450b57cec5SDimitry Andric 
9460b57cec5SDimitry Andric     int64_t Offset;
9470b57cec5SDimitry Andric     if (HasFP) {
9480b57cec5SDimitry Andric       // If the function has a frame pointer (i.e. has an allocframe),
9490b57cec5SDimitry Andric       // then the CFA has been defined in terms of FP. Any offsets in
9500b57cec5SDimitry Andric       // the following CFI instructions have to be defined relative
9510b57cec5SDimitry Andric       // to FP, which points to the bottom of the stack frame.
9520b57cec5SDimitry Andric       // The function getFrameIndexReference can still choose to use SP
9530b57cec5SDimitry Andric       // for the offset calculation, so we cannot simply call it here.
9540b57cec5SDimitry Andric       // Instead, get the offset (relative to the FP) directly.
9550b57cec5SDimitry Andric       Offset = MFI.getObjectOffset(F->getFrameIdx());
9560b57cec5SDimitry Andric     } else {
9570b57cec5SDimitry Andric       unsigned FrameReg;
9580b57cec5SDimitry Andric       Offset = getFrameIndexReference(MF, F->getFrameIdx(), FrameReg);
9590b57cec5SDimitry Andric     }
9600b57cec5SDimitry Andric     // Subtract 8 to make room for R30 and R31, which are added above.
9610b57cec5SDimitry Andric     Offset -= 8;
9620b57cec5SDimitry Andric 
9630b57cec5SDimitry Andric     if (Reg < Hexagon::D0 || Reg > Hexagon::D15) {
9640b57cec5SDimitry Andric       unsigned DwarfReg = HRI.getDwarfRegNum(Reg, true);
9650b57cec5SDimitry Andric       auto OffReg = MCCFIInstruction::createOffset(FrameLabel, DwarfReg,
9660b57cec5SDimitry Andric                                                    Offset);
9670b57cec5SDimitry Andric       BuildMI(MBB, At, DL, CFID)
9680b57cec5SDimitry Andric           .addCFIIndex(MF.addFrameInst(OffReg));
9690b57cec5SDimitry Andric     } else {
9700b57cec5SDimitry Andric       // Split the double regs into subregs, and generate appropriate
9710b57cec5SDimitry Andric       // cfi_offsets.
9720b57cec5SDimitry Andric       // The only reason, we are split double regs is, llvm-mc does not
9730b57cec5SDimitry Andric       // understand paired registers for cfi_offset.
9740b57cec5SDimitry Andric       // Eg .cfi_offset r1:0, -64
9750b57cec5SDimitry Andric 
9768bcb0991SDimitry Andric       Register HiReg = HRI.getSubReg(Reg, Hexagon::isub_hi);
9778bcb0991SDimitry Andric       Register LoReg = HRI.getSubReg(Reg, Hexagon::isub_lo);
9780b57cec5SDimitry Andric       unsigned HiDwarfReg = HRI.getDwarfRegNum(HiReg, true);
9790b57cec5SDimitry Andric       unsigned LoDwarfReg = HRI.getDwarfRegNum(LoReg, true);
9800b57cec5SDimitry Andric       auto OffHi = MCCFIInstruction::createOffset(FrameLabel, HiDwarfReg,
9810b57cec5SDimitry Andric                                                   Offset+4);
9820b57cec5SDimitry Andric       BuildMI(MBB, At, DL, CFID)
9830b57cec5SDimitry Andric           .addCFIIndex(MF.addFrameInst(OffHi));
9840b57cec5SDimitry Andric       auto OffLo = MCCFIInstruction::createOffset(FrameLabel, LoDwarfReg,
9850b57cec5SDimitry Andric                                                   Offset);
9860b57cec5SDimitry Andric       BuildMI(MBB, At, DL, CFID)
9870b57cec5SDimitry Andric           .addCFIIndex(MF.addFrameInst(OffLo));
9880b57cec5SDimitry Andric     }
9890b57cec5SDimitry Andric   }
9900b57cec5SDimitry Andric }
9910b57cec5SDimitry Andric 
9920b57cec5SDimitry Andric bool HexagonFrameLowering::hasFP(const MachineFunction &MF) const {
9930b57cec5SDimitry Andric   if (MF.getFunction().hasFnAttribute(Attribute::Naked))
9940b57cec5SDimitry Andric     return false;
9950b57cec5SDimitry Andric 
9960b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
9970b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
9980b57cec5SDimitry Andric   bool HasExtraAlign = HRI.needsStackRealignment(MF);
9990b57cec5SDimitry Andric   bool HasAlloca = MFI.hasVarSizedObjects();
10000b57cec5SDimitry Andric 
10010b57cec5SDimitry Andric   // Insert ALLOCFRAME if we need to or at -O0 for the debugger.  Think
10020b57cec5SDimitry Andric   // that this shouldn't be required, but doing so now because gcc does and
10030b57cec5SDimitry Andric   // gdb can't break at the start of the function without it.  Will remove if
10040b57cec5SDimitry Andric   // this turns out to be a gdb bug.
10050b57cec5SDimitry Andric   //
10060b57cec5SDimitry Andric   if (MF.getTarget().getOptLevel() == CodeGenOpt::None)
10070b57cec5SDimitry Andric     return true;
10080b57cec5SDimitry Andric 
10090b57cec5SDimitry Andric   // By default we want to use SP (since it's always there). FP requires
10100b57cec5SDimitry Andric   // some setup (i.e. ALLOCFRAME).
10110b57cec5SDimitry Andric   // Both, alloca and stack alignment modify the stack pointer by an
10120b57cec5SDimitry Andric   // undetermined value, so we need to save it at the entry to the function
10130b57cec5SDimitry Andric   // (i.e. use allocframe).
10140b57cec5SDimitry Andric   if (HasAlloca || HasExtraAlign)
10150b57cec5SDimitry Andric     return true;
10160b57cec5SDimitry Andric 
10170b57cec5SDimitry Andric   if (MFI.getStackSize() > 0) {
10180b57cec5SDimitry Andric     // If FP-elimination is disabled, we have to use FP at this point.
10190b57cec5SDimitry Andric     const TargetMachine &TM = MF.getTarget();
10200b57cec5SDimitry Andric     if (TM.Options.DisableFramePointerElim(MF) || !EliminateFramePointer)
10210b57cec5SDimitry Andric       return true;
10220b57cec5SDimitry Andric     if (EnableStackOVFSanitizer)
10230b57cec5SDimitry Andric       return true;
10240b57cec5SDimitry Andric   }
10250b57cec5SDimitry Andric 
10260b57cec5SDimitry Andric   const auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
10270b57cec5SDimitry Andric   if ((MFI.hasCalls() && !enableAllocFrameElim(MF)) || HMFI.hasClobberLR())
10280b57cec5SDimitry Andric     return true;
10290b57cec5SDimitry Andric 
10300b57cec5SDimitry Andric   return false;
10310b57cec5SDimitry Andric }
10320b57cec5SDimitry Andric 
10330b57cec5SDimitry Andric enum SpillKind {
10340b57cec5SDimitry Andric   SK_ToMem,
10350b57cec5SDimitry Andric   SK_FromMem,
10360b57cec5SDimitry Andric   SK_FromMemTailcall
10370b57cec5SDimitry Andric };
10380b57cec5SDimitry Andric 
10390b57cec5SDimitry Andric static const char *getSpillFunctionFor(unsigned MaxReg, SpillKind SpillType,
10400b57cec5SDimitry Andric       bool Stkchk = false) {
10410b57cec5SDimitry Andric   const char * V4SpillToMemoryFunctions[] = {
10420b57cec5SDimitry Andric     "__save_r16_through_r17",
10430b57cec5SDimitry Andric     "__save_r16_through_r19",
10440b57cec5SDimitry Andric     "__save_r16_through_r21",
10450b57cec5SDimitry Andric     "__save_r16_through_r23",
10460b57cec5SDimitry Andric     "__save_r16_through_r25",
10470b57cec5SDimitry Andric     "__save_r16_through_r27" };
10480b57cec5SDimitry Andric 
10490b57cec5SDimitry Andric   const char * V4SpillToMemoryStkchkFunctions[] = {
10500b57cec5SDimitry Andric     "__save_r16_through_r17_stkchk",
10510b57cec5SDimitry Andric     "__save_r16_through_r19_stkchk",
10520b57cec5SDimitry Andric     "__save_r16_through_r21_stkchk",
10530b57cec5SDimitry Andric     "__save_r16_through_r23_stkchk",
10540b57cec5SDimitry Andric     "__save_r16_through_r25_stkchk",
10550b57cec5SDimitry Andric     "__save_r16_through_r27_stkchk" };
10560b57cec5SDimitry Andric 
10570b57cec5SDimitry Andric   const char * V4SpillFromMemoryFunctions[] = {
10580b57cec5SDimitry Andric     "__restore_r16_through_r17_and_deallocframe",
10590b57cec5SDimitry Andric     "__restore_r16_through_r19_and_deallocframe",
10600b57cec5SDimitry Andric     "__restore_r16_through_r21_and_deallocframe",
10610b57cec5SDimitry Andric     "__restore_r16_through_r23_and_deallocframe",
10620b57cec5SDimitry Andric     "__restore_r16_through_r25_and_deallocframe",
10630b57cec5SDimitry Andric     "__restore_r16_through_r27_and_deallocframe" };
10640b57cec5SDimitry Andric 
10650b57cec5SDimitry Andric   const char * V4SpillFromMemoryTailcallFunctions[] = {
10660b57cec5SDimitry Andric     "__restore_r16_through_r17_and_deallocframe_before_tailcall",
10670b57cec5SDimitry Andric     "__restore_r16_through_r19_and_deallocframe_before_tailcall",
10680b57cec5SDimitry Andric     "__restore_r16_through_r21_and_deallocframe_before_tailcall",
10690b57cec5SDimitry Andric     "__restore_r16_through_r23_and_deallocframe_before_tailcall",
10700b57cec5SDimitry Andric     "__restore_r16_through_r25_and_deallocframe_before_tailcall",
10710b57cec5SDimitry Andric     "__restore_r16_through_r27_and_deallocframe_before_tailcall"
10720b57cec5SDimitry Andric   };
10730b57cec5SDimitry Andric 
10740b57cec5SDimitry Andric   const char **SpillFunc = nullptr;
10750b57cec5SDimitry Andric 
10760b57cec5SDimitry Andric   switch(SpillType) {
10770b57cec5SDimitry Andric   case SK_ToMem:
10780b57cec5SDimitry Andric     SpillFunc = Stkchk ? V4SpillToMemoryStkchkFunctions
10790b57cec5SDimitry Andric                        : V4SpillToMemoryFunctions;
10800b57cec5SDimitry Andric     break;
10810b57cec5SDimitry Andric   case SK_FromMem:
10820b57cec5SDimitry Andric     SpillFunc = V4SpillFromMemoryFunctions;
10830b57cec5SDimitry Andric     break;
10840b57cec5SDimitry Andric   case SK_FromMemTailcall:
10850b57cec5SDimitry Andric     SpillFunc = V4SpillFromMemoryTailcallFunctions;
10860b57cec5SDimitry Andric     break;
10870b57cec5SDimitry Andric   }
10880b57cec5SDimitry Andric   assert(SpillFunc && "Unknown spill kind");
10890b57cec5SDimitry Andric 
10900b57cec5SDimitry Andric   // Spill all callee-saved registers up to the highest register used.
10910b57cec5SDimitry Andric   switch (MaxReg) {
10920b57cec5SDimitry Andric   case Hexagon::R17:
10930b57cec5SDimitry Andric     return SpillFunc[0];
10940b57cec5SDimitry Andric   case Hexagon::R19:
10950b57cec5SDimitry Andric     return SpillFunc[1];
10960b57cec5SDimitry Andric   case Hexagon::R21:
10970b57cec5SDimitry Andric     return SpillFunc[2];
10980b57cec5SDimitry Andric   case Hexagon::R23:
10990b57cec5SDimitry Andric     return SpillFunc[3];
11000b57cec5SDimitry Andric   case Hexagon::R25:
11010b57cec5SDimitry Andric     return SpillFunc[4];
11020b57cec5SDimitry Andric   case Hexagon::R27:
11030b57cec5SDimitry Andric     return SpillFunc[5];
11040b57cec5SDimitry Andric   default:
11050b57cec5SDimitry Andric     llvm_unreachable("Unhandled maximum callee save register");
11060b57cec5SDimitry Andric   }
11070b57cec5SDimitry Andric   return nullptr;
11080b57cec5SDimitry Andric }
11090b57cec5SDimitry Andric 
11100b57cec5SDimitry Andric int HexagonFrameLowering::getFrameIndexReference(const MachineFunction &MF,
11110b57cec5SDimitry Andric       int FI, unsigned &FrameReg) const {
11120b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
11130b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
11140b57cec5SDimitry Andric 
11150b57cec5SDimitry Andric   int Offset = MFI.getObjectOffset(FI);
11160b57cec5SDimitry Andric   bool HasAlloca = MFI.hasVarSizedObjects();
11170b57cec5SDimitry Andric   bool HasExtraAlign = HRI.needsStackRealignment(MF);
11180b57cec5SDimitry Andric   bool NoOpt = MF.getTarget().getOptLevel() == CodeGenOpt::None;
11190b57cec5SDimitry Andric 
11200b57cec5SDimitry Andric   auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
11210b57cec5SDimitry Andric   unsigned FrameSize = MFI.getStackSize();
11220b57cec5SDimitry Andric   unsigned SP = HRI.getStackRegister();
11230b57cec5SDimitry Andric   unsigned FP = HRI.getFrameRegister();
11240b57cec5SDimitry Andric   unsigned AP = HMFI.getStackAlignBasePhysReg();
11250b57cec5SDimitry Andric   // It may happen that AP will be absent even HasAlloca && HasExtraAlign
11260b57cec5SDimitry Andric   // is true. HasExtraAlign may be set because of vector spills, without
11270b57cec5SDimitry Andric   // aligned locals or aligned outgoing function arguments. Since vector
11280b57cec5SDimitry Andric   // spills will ultimately be "unaligned", it is safe to use FP as the
11290b57cec5SDimitry Andric   // base register.
11300b57cec5SDimitry Andric   // In fact, in such a scenario the stack is actually not required to be
11310b57cec5SDimitry Andric   // aligned, although it may end up being aligned anyway, since this
11320b57cec5SDimitry Andric   // particular case is not easily detectable. The alignment will be
11330b57cec5SDimitry Andric   // unnecessary, but not incorrect.
11340b57cec5SDimitry Andric   // Unfortunately there is no quick way to verify that the above is
11350b57cec5SDimitry Andric   // indeed the case (and that it's not a result of an error), so just
11360b57cec5SDimitry Andric   // assume that missing AP will be replaced by FP.
11370b57cec5SDimitry Andric   // (A better fix would be to rematerialize AP from FP and always align
11380b57cec5SDimitry Andric   // vector spills.)
11390b57cec5SDimitry Andric   if (AP == 0)
11400b57cec5SDimitry Andric     AP = FP;
11410b57cec5SDimitry Andric 
11420b57cec5SDimitry Andric   bool UseFP = false, UseAP = false;  // Default: use SP (except at -O0).
11430b57cec5SDimitry Andric   // Use FP at -O0, except when there are objects with extra alignment.
11440b57cec5SDimitry Andric   // That additional alignment requirement may cause a pad to be inserted,
11450b57cec5SDimitry Andric   // which will make it impossible to use FP to access objects located
11460b57cec5SDimitry Andric   // past the pad.
11470b57cec5SDimitry Andric   if (NoOpt && !HasExtraAlign)
11480b57cec5SDimitry Andric     UseFP = true;
11490b57cec5SDimitry Andric   if (MFI.isFixedObjectIndex(FI) || MFI.isObjectPreAllocated(FI)) {
11500b57cec5SDimitry Andric     // Fixed and preallocated objects will be located before any padding
11510b57cec5SDimitry Andric     // so FP must be used to access them.
11520b57cec5SDimitry Andric     UseFP |= (HasAlloca || HasExtraAlign);
11530b57cec5SDimitry Andric   } else {
11540b57cec5SDimitry Andric     if (HasAlloca) {
11550b57cec5SDimitry Andric       if (HasExtraAlign)
11560b57cec5SDimitry Andric         UseAP = true;
11570b57cec5SDimitry Andric       else
11580b57cec5SDimitry Andric         UseFP = true;
11590b57cec5SDimitry Andric     }
11600b57cec5SDimitry Andric   }
11610b57cec5SDimitry Andric 
11620b57cec5SDimitry Andric   // If FP was picked, then there had better be FP.
11630b57cec5SDimitry Andric   bool HasFP = hasFP(MF);
11640b57cec5SDimitry Andric   assert((HasFP || !UseFP) && "This function must have frame pointer");
11650b57cec5SDimitry Andric 
11660b57cec5SDimitry Andric   // Having FP implies allocframe. Allocframe will store extra 8 bytes:
11670b57cec5SDimitry Andric   // FP/LR. If the base register is used to access an object across these
11680b57cec5SDimitry Andric   // 8 bytes, then the offset will need to be adjusted by 8.
11690b57cec5SDimitry Andric   //
11700b57cec5SDimitry Andric   // After allocframe:
11710b57cec5SDimitry Andric   //                    HexagonISelLowering adds 8 to ---+
11720b57cec5SDimitry Andric   //                    the offsets of all stack-based   |
11730b57cec5SDimitry Andric   //                    arguments (*)                    |
11740b57cec5SDimitry Andric   //                                                     |
11750b57cec5SDimitry Andric   //   getObjectOffset < 0   0     8  getObjectOffset >= 8
11760b57cec5SDimitry Andric   // ------------------------+-----+------------------------> increasing
11770b57cec5SDimitry Andric   //     <local objects>     |FP/LR|    <input arguments>     addresses
11780b57cec5SDimitry Andric   // -----------------+------+-----+------------------------>
11790b57cec5SDimitry Andric   //                  |      |
11800b57cec5SDimitry Andric   //    SP/AP point --+      +-- FP points here (**)
11810b57cec5SDimitry Andric   //    somewhere on
11820b57cec5SDimitry Andric   //    this side of FP/LR
11830b57cec5SDimitry Andric   //
11840b57cec5SDimitry Andric   // (*) See LowerFormalArguments. The FP/LR is assumed to be present.
11850b57cec5SDimitry Andric   // (**) *FP == old-FP. FP+0..7 are the bytes of FP/LR.
11860b57cec5SDimitry Andric 
11870b57cec5SDimitry Andric   // The lowering assumes that FP/LR is present, and so the offsets of
11880b57cec5SDimitry Andric   // the formal arguments start at 8. If FP/LR is not there we need to
11890b57cec5SDimitry Andric   // reduce the offset by 8.
11900b57cec5SDimitry Andric   if (Offset > 0 && !HasFP)
11910b57cec5SDimitry Andric     Offset -= 8;
11920b57cec5SDimitry Andric 
11930b57cec5SDimitry Andric   if (UseFP)
11940b57cec5SDimitry Andric     FrameReg = FP;
11950b57cec5SDimitry Andric   else if (UseAP)
11960b57cec5SDimitry Andric     FrameReg = AP;
11970b57cec5SDimitry Andric   else
11980b57cec5SDimitry Andric     FrameReg = SP;
11990b57cec5SDimitry Andric 
12000b57cec5SDimitry Andric   // Calculate the actual offset in the instruction. If there is no FP
12010b57cec5SDimitry Andric   // (in other words, no allocframe), then SP will not be adjusted (i.e.
12020b57cec5SDimitry Andric   // there will be no SP -= FrameSize), so the frame size should not be
12030b57cec5SDimitry Andric   // added to the calculated offset.
12040b57cec5SDimitry Andric   int RealOffset = Offset;
12050b57cec5SDimitry Andric   if (!UseFP && !UseAP)
12060b57cec5SDimitry Andric     RealOffset = FrameSize+Offset;
12070b57cec5SDimitry Andric   return RealOffset;
12080b57cec5SDimitry Andric }
12090b57cec5SDimitry Andric 
12100b57cec5SDimitry Andric bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB,
12110b57cec5SDimitry Andric       const CSIVect &CSI, const HexagonRegisterInfo &HRI,
12120b57cec5SDimitry Andric       bool &PrologueStubs) const {
12130b57cec5SDimitry Andric   if (CSI.empty())
12140b57cec5SDimitry Andric     return true;
12150b57cec5SDimitry Andric 
12160b57cec5SDimitry Andric   MachineBasicBlock::iterator MI = MBB.begin();
12170b57cec5SDimitry Andric   PrologueStubs = false;
12180b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
12190b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
12200b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
12210b57cec5SDimitry Andric 
12220b57cec5SDimitry Andric   if (useSpillFunction(MF, CSI)) {
12230b57cec5SDimitry Andric     PrologueStubs = true;
12240b57cec5SDimitry Andric     unsigned MaxReg = getMaxCalleeSavedReg(CSI, HRI);
12250b57cec5SDimitry Andric     bool StkOvrFlowEnabled = EnableStackOVFSanitizer;
12260b57cec5SDimitry Andric     const char *SpillFun = getSpillFunctionFor(MaxReg, SK_ToMem,
12270b57cec5SDimitry Andric                                                StkOvrFlowEnabled);
12280b57cec5SDimitry Andric     auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget());
12290b57cec5SDimitry Andric     bool IsPIC = HTM.isPositionIndependent();
12300b57cec5SDimitry Andric     bool LongCalls = HST.useLongCalls() || EnableSaveRestoreLong;
12310b57cec5SDimitry Andric 
12320b57cec5SDimitry Andric     // Call spill function.
12330b57cec5SDimitry Andric     DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc();
12340b57cec5SDimitry Andric     unsigned SpillOpc;
12350b57cec5SDimitry Andric     if (StkOvrFlowEnabled) {
12360b57cec5SDimitry Andric       if (LongCalls)
12370b57cec5SDimitry Andric         SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_EXT_PIC
12380b57cec5SDimitry Andric                          : Hexagon::SAVE_REGISTERS_CALL_V4STK_EXT;
12390b57cec5SDimitry Andric       else
12400b57cec5SDimitry Andric         SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_PIC
12410b57cec5SDimitry Andric                          : Hexagon::SAVE_REGISTERS_CALL_V4STK;
12420b57cec5SDimitry Andric     } else {
12430b57cec5SDimitry Andric       if (LongCalls)
12440b57cec5SDimitry Andric         SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_EXT_PIC
12450b57cec5SDimitry Andric                          : Hexagon::SAVE_REGISTERS_CALL_V4_EXT;
12460b57cec5SDimitry Andric       else
12470b57cec5SDimitry Andric         SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_PIC
12480b57cec5SDimitry Andric                          : Hexagon::SAVE_REGISTERS_CALL_V4;
12490b57cec5SDimitry Andric     }
12500b57cec5SDimitry Andric 
12510b57cec5SDimitry Andric     MachineInstr *SaveRegsCall =
12520b57cec5SDimitry Andric         BuildMI(MBB, MI, DL, HII.get(SpillOpc))
12530b57cec5SDimitry Andric           .addExternalSymbol(SpillFun);
12540b57cec5SDimitry Andric 
12550b57cec5SDimitry Andric     // Add callee-saved registers as use.
12560b57cec5SDimitry Andric     addCalleeSaveRegistersAsImpOperand(SaveRegsCall, CSI, false, true);
12570b57cec5SDimitry Andric     // Add live in registers.
12580b57cec5SDimitry Andric     for (unsigned I = 0; I < CSI.size(); ++I)
12590b57cec5SDimitry Andric       MBB.addLiveIn(CSI[I].getReg());
12600b57cec5SDimitry Andric     return true;
12610b57cec5SDimitry Andric   }
12620b57cec5SDimitry Andric 
12630b57cec5SDimitry Andric   for (unsigned i = 0, n = CSI.size(); i < n; ++i) {
12640b57cec5SDimitry Andric     unsigned Reg = CSI[i].getReg();
12650b57cec5SDimitry Andric     // Add live in registers. We treat eh_return callee saved register r0 - r3
12660b57cec5SDimitry Andric     // specially. They are not really callee saved registers as they are not
12670b57cec5SDimitry Andric     // supposed to be killed.
12680b57cec5SDimitry Andric     bool IsKill = !HRI.isEHReturnCalleeSaveReg(Reg);
12690b57cec5SDimitry Andric     int FI = CSI[i].getFrameIdx();
12700b57cec5SDimitry Andric     const TargetRegisterClass *RC = HRI.getMinimalPhysRegClass(Reg);
12710b57cec5SDimitry Andric     HII.storeRegToStackSlot(MBB, MI, Reg, IsKill, FI, RC, &HRI);
12720b57cec5SDimitry Andric     if (IsKill)
12730b57cec5SDimitry Andric       MBB.addLiveIn(Reg);
12740b57cec5SDimitry Andric   }
12750b57cec5SDimitry Andric   return true;
12760b57cec5SDimitry Andric }
12770b57cec5SDimitry Andric 
12780b57cec5SDimitry Andric bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
12790b57cec5SDimitry Andric       const CSIVect &CSI, const HexagonRegisterInfo &HRI) const {
12800b57cec5SDimitry Andric   if (CSI.empty())
12810b57cec5SDimitry Andric     return false;
12820b57cec5SDimitry Andric 
12830b57cec5SDimitry Andric   MachineBasicBlock::iterator MI = MBB.getFirstTerminator();
12840b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
12850b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
12860b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
12870b57cec5SDimitry Andric 
12880b57cec5SDimitry Andric   if (useRestoreFunction(MF, CSI)) {
12890b57cec5SDimitry Andric     bool HasTC = hasTailCall(MBB) || !hasReturn(MBB);
12900b57cec5SDimitry Andric     unsigned MaxR = getMaxCalleeSavedReg(CSI, HRI);
12910b57cec5SDimitry Andric     SpillKind Kind = HasTC ? SK_FromMemTailcall : SK_FromMem;
12920b57cec5SDimitry Andric     const char *RestoreFn = getSpillFunctionFor(MaxR, Kind);
12930b57cec5SDimitry Andric     auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget());
12940b57cec5SDimitry Andric     bool IsPIC = HTM.isPositionIndependent();
12950b57cec5SDimitry Andric     bool LongCalls = HST.useLongCalls() || EnableSaveRestoreLong;
12960b57cec5SDimitry Andric 
12970b57cec5SDimitry Andric     // Call spill function.
12980b57cec5SDimitry Andric     DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc()
12990b57cec5SDimitry Andric                                   : MBB.findDebugLoc(MBB.end());
13000b57cec5SDimitry Andric     MachineInstr *DeallocCall = nullptr;
13010b57cec5SDimitry Andric 
13020b57cec5SDimitry Andric     if (HasTC) {
13030b57cec5SDimitry Andric       unsigned RetOpc;
13040b57cec5SDimitry Andric       if (LongCalls)
13050b57cec5SDimitry Andric         RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC
13060b57cec5SDimitry Andric                        : Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT;
13070b57cec5SDimitry Andric       else
13080b57cec5SDimitry Andric         RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC
13090b57cec5SDimitry Andric                        : Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4;
13100b57cec5SDimitry Andric       DeallocCall = BuildMI(MBB, MI, DL, HII.get(RetOpc))
13110b57cec5SDimitry Andric           .addExternalSymbol(RestoreFn);
13120b57cec5SDimitry Andric     } else {
13130b57cec5SDimitry Andric       // The block has a return.
13140b57cec5SDimitry Andric       MachineBasicBlock::iterator It = MBB.getFirstTerminator();
13150b57cec5SDimitry Andric       assert(It->isReturn() && std::next(It) == MBB.end());
13160b57cec5SDimitry Andric       unsigned RetOpc;
13170b57cec5SDimitry Andric       if (LongCalls)
13180b57cec5SDimitry Andric         RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC
13190b57cec5SDimitry Andric                        : Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT;
13200b57cec5SDimitry Andric       else
13210b57cec5SDimitry Andric         RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC
13220b57cec5SDimitry Andric                        : Hexagon::RESTORE_DEALLOC_RET_JMP_V4;
13230b57cec5SDimitry Andric       DeallocCall = BuildMI(MBB, It, DL, HII.get(RetOpc))
13240b57cec5SDimitry Andric           .addExternalSymbol(RestoreFn);
13250b57cec5SDimitry Andric       // Transfer the function live-out registers.
13260b57cec5SDimitry Andric       DeallocCall->copyImplicitOps(MF, *It);
13270b57cec5SDimitry Andric     }
13280b57cec5SDimitry Andric     addCalleeSaveRegistersAsImpOperand(DeallocCall, CSI, true, false);
13290b57cec5SDimitry Andric     return true;
13300b57cec5SDimitry Andric   }
13310b57cec5SDimitry Andric 
13320b57cec5SDimitry Andric   for (unsigned i = 0; i < CSI.size(); ++i) {
13330b57cec5SDimitry Andric     unsigned Reg = CSI[i].getReg();
13340b57cec5SDimitry Andric     const TargetRegisterClass *RC = HRI.getMinimalPhysRegClass(Reg);
13350b57cec5SDimitry Andric     int FI = CSI[i].getFrameIdx();
13360b57cec5SDimitry Andric     HII.loadRegFromStackSlot(MBB, MI, Reg, FI, RC, &HRI);
13370b57cec5SDimitry Andric   }
13380b57cec5SDimitry Andric 
13390b57cec5SDimitry Andric   return true;
13400b57cec5SDimitry Andric }
13410b57cec5SDimitry Andric 
13420b57cec5SDimitry Andric MachineBasicBlock::iterator HexagonFrameLowering::eliminateCallFramePseudoInstr(
13430b57cec5SDimitry Andric     MachineFunction &MF, MachineBasicBlock &MBB,
13440b57cec5SDimitry Andric     MachineBasicBlock::iterator I) const {
13450b57cec5SDimitry Andric   MachineInstr &MI = *I;
13460b57cec5SDimitry Andric   unsigned Opc = MI.getOpcode();
13470b57cec5SDimitry Andric   (void)Opc; // Silence compiler warning.
13480b57cec5SDimitry Andric   assert((Opc == Hexagon::ADJCALLSTACKDOWN || Opc == Hexagon::ADJCALLSTACKUP) &&
13490b57cec5SDimitry Andric          "Cannot handle this call frame pseudo instruction");
13500b57cec5SDimitry Andric   return MBB.erase(I);
13510b57cec5SDimitry Andric }
13520b57cec5SDimitry Andric 
13530b57cec5SDimitry Andric void HexagonFrameLowering::processFunctionBeforeFrameFinalized(
13540b57cec5SDimitry Andric     MachineFunction &MF, RegScavenger *RS) const {
13550b57cec5SDimitry Andric   // If this function has uses aligned stack and also has variable sized stack
13560b57cec5SDimitry Andric   // objects, then we need to map all spill slots to fixed positions, so that
13570b57cec5SDimitry Andric   // they can be accessed through FP. Otherwise they would have to be accessed
13580b57cec5SDimitry Andric   // via AP, which may not be available at the particular place in the program.
13590b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
13600b57cec5SDimitry Andric   bool HasAlloca = MFI.hasVarSizedObjects();
13610b57cec5SDimitry Andric   bool NeedsAlign = (MFI.getMaxAlignment() > getStackAlignment());
13620b57cec5SDimitry Andric 
13630b57cec5SDimitry Andric   if (!HasAlloca || !NeedsAlign)
13640b57cec5SDimitry Andric     return;
13650b57cec5SDimitry Andric 
1366*480093f4SDimitry Andric   SmallSet<int, 4> DealignSlots;
13670b57cec5SDimitry Andric   unsigned LFS = MFI.getLocalFrameSize();
13680b57cec5SDimitry Andric   for (int i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {
13690b57cec5SDimitry Andric     if (!MFI.isSpillSlotObjectIndex(i) || MFI.isDeadObjectIndex(i))
13700b57cec5SDimitry Andric       continue;
13710b57cec5SDimitry Andric     unsigned S = MFI.getObjectSize(i);
13720b57cec5SDimitry Andric     // Reduce the alignment to at most 8. This will require unaligned vector
13730b57cec5SDimitry Andric     // stores if they happen here.
13740b57cec5SDimitry Andric     unsigned A = std::max(MFI.getObjectAlignment(i), 8U);
13750b57cec5SDimitry Andric     MFI.setObjectAlignment(i, 8);
13760b57cec5SDimitry Andric     LFS = alignTo(LFS+S, A);
1377*480093f4SDimitry Andric     MFI.mapLocalFrameObject(i, -static_cast<int64_t>(LFS));
1378*480093f4SDimitry Andric     DealignSlots.insert(i);
13790b57cec5SDimitry Andric   }
13800b57cec5SDimitry Andric 
13810b57cec5SDimitry Andric   MFI.setLocalFrameSize(LFS);
13828bcb0991SDimitry Andric   Align A = MFI.getLocalFrameMaxAlign();
13830b57cec5SDimitry Andric   assert(A <= 8 && "Unexpected local frame alignment");
13848bcb0991SDimitry Andric   if (A == 1)
13858bcb0991SDimitry Andric     MFI.setLocalFrameMaxAlign(Align(8));
13860b57cec5SDimitry Andric   MFI.setUseLocalStackAllocationBlock(true);
13870b57cec5SDimitry Andric 
1388*480093f4SDimitry Andric   // Go over all MachineMemOperands in the code, and change the ones that
1389*480093f4SDimitry Andric   // refer to the dealigned stack slots to reflect the new alignment.
1390*480093f4SDimitry Andric   if (!DealignSlots.empty()) {
1391*480093f4SDimitry Andric     for (MachineBasicBlock &BB : MF) {
1392*480093f4SDimitry Andric       for (MachineInstr &MI : BB) {
1393*480093f4SDimitry Andric         bool KeepOld = true;
1394*480093f4SDimitry Andric         ArrayRef<MachineMemOperand*> memops = MI.memoperands();
1395*480093f4SDimitry Andric         SmallVector<MachineMemOperand*,1> new_memops;
1396*480093f4SDimitry Andric         for (MachineMemOperand *MMO : memops) {
1397*480093f4SDimitry Andric           auto *PV = MMO->getPseudoValue();
1398*480093f4SDimitry Andric           if (auto *FS = dyn_cast_or_null<FixedStackPseudoSourceValue>(PV)) {
1399*480093f4SDimitry Andric             int FI = FS->getFrameIndex();
1400*480093f4SDimitry Andric             if (DealignSlots.count(FI)) {
1401*480093f4SDimitry Andric               unsigned A = MFI.getObjectAlignment(FI);
1402*480093f4SDimitry Andric               auto *NewMMO = MF.getMachineMemOperand(MMO->getPointerInfo(),
1403*480093f4SDimitry Andric                                 MMO->getFlags(), MMO->getSize(), A,
1404*480093f4SDimitry Andric                                 MMO->getAAInfo(), MMO->getRanges(),
1405*480093f4SDimitry Andric                                 MMO->getSyncScopeID(), MMO->getOrdering(),
1406*480093f4SDimitry Andric                                 MMO->getFailureOrdering());
1407*480093f4SDimitry Andric               new_memops.push_back(NewMMO);
1408*480093f4SDimitry Andric               KeepOld = false;
1409*480093f4SDimitry Andric               continue;
1410*480093f4SDimitry Andric             }
1411*480093f4SDimitry Andric           }
1412*480093f4SDimitry Andric           new_memops.push_back(MMO);
1413*480093f4SDimitry Andric         }
1414*480093f4SDimitry Andric         if (!KeepOld)
1415*480093f4SDimitry Andric           MI.setMemRefs(MF, new_memops);
1416*480093f4SDimitry Andric       }
1417*480093f4SDimitry Andric     }
1418*480093f4SDimitry Andric   }
1419*480093f4SDimitry Andric 
14200b57cec5SDimitry Andric   // Set the physical aligned-stack base address register.
14210b57cec5SDimitry Andric   unsigned AP = 0;
14220b57cec5SDimitry Andric   if (const MachineInstr *AI = getAlignaInstr(MF))
14230b57cec5SDimitry Andric     AP = AI->getOperand(0).getReg();
14240b57cec5SDimitry Andric   auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
14250b57cec5SDimitry Andric   HMFI.setStackAlignBasePhysReg(AP);
14260b57cec5SDimitry Andric }
14270b57cec5SDimitry Andric 
14280b57cec5SDimitry Andric /// Returns true if there are no caller-saved registers available in class RC.
14290b57cec5SDimitry Andric static bool needToReserveScavengingSpillSlots(MachineFunction &MF,
14300b57cec5SDimitry Andric       const HexagonRegisterInfo &HRI, const TargetRegisterClass *RC) {
14310b57cec5SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
14320b57cec5SDimitry Andric 
14330b57cec5SDimitry Andric   auto IsUsed = [&HRI,&MRI] (unsigned Reg) -> bool {
14340b57cec5SDimitry Andric     for (MCRegAliasIterator AI(Reg, &HRI, true); AI.isValid(); ++AI)
14350b57cec5SDimitry Andric       if (MRI.isPhysRegUsed(*AI))
14360b57cec5SDimitry Andric         return true;
14370b57cec5SDimitry Andric     return false;
14380b57cec5SDimitry Andric   };
14390b57cec5SDimitry Andric 
14400b57cec5SDimitry Andric   // Check for an unused caller-saved register. Callee-saved registers
14410b57cec5SDimitry Andric   // have become pristine by now.
14420b57cec5SDimitry Andric   for (const MCPhysReg *P = HRI.getCallerSavedRegs(&MF, RC); *P; ++P)
14430b57cec5SDimitry Andric     if (!IsUsed(*P))
14440b57cec5SDimitry Andric       return false;
14450b57cec5SDimitry Andric 
14460b57cec5SDimitry Andric   // All caller-saved registers are used.
14470b57cec5SDimitry Andric   return true;
14480b57cec5SDimitry Andric }
14490b57cec5SDimitry Andric 
14500b57cec5SDimitry Andric #ifndef NDEBUG
14510b57cec5SDimitry Andric static void dump_registers(BitVector &Regs, const TargetRegisterInfo &TRI) {
14520b57cec5SDimitry Andric   dbgs() << '{';
14530b57cec5SDimitry Andric   for (int x = Regs.find_first(); x >= 0; x = Regs.find_next(x)) {
14540b57cec5SDimitry Andric     unsigned R = x;
14550b57cec5SDimitry Andric     dbgs() << ' ' << printReg(R, &TRI);
14560b57cec5SDimitry Andric   }
14570b57cec5SDimitry Andric   dbgs() << " }";
14580b57cec5SDimitry Andric }
14590b57cec5SDimitry Andric #endif
14600b57cec5SDimitry Andric 
14610b57cec5SDimitry Andric bool HexagonFrameLowering::assignCalleeSavedSpillSlots(MachineFunction &MF,
14620b57cec5SDimitry Andric       const TargetRegisterInfo *TRI, std::vector<CalleeSavedInfo> &CSI) const {
14630b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << __func__ << " on " << MF.getName() << '\n');
14640b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
14650b57cec5SDimitry Andric   BitVector SRegs(Hexagon::NUM_TARGET_REGS);
14660b57cec5SDimitry Andric 
14670b57cec5SDimitry Andric   // Generate a set of unique, callee-saved registers (SRegs), where each
14680b57cec5SDimitry Andric   // register in the set is maximal in terms of sub-/super-register relation,
14690b57cec5SDimitry Andric   // i.e. for each R in SRegs, no proper super-register of R is also in SRegs.
14700b57cec5SDimitry Andric 
14710b57cec5SDimitry Andric   // (1) For each callee-saved register, add that register and all of its
14720b57cec5SDimitry Andric   // sub-registers to SRegs.
14730b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Initial CS registers: {");
14740b57cec5SDimitry Andric   for (unsigned i = 0, n = CSI.size(); i < n; ++i) {
14750b57cec5SDimitry Andric     unsigned R = CSI[i].getReg();
14760b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ' ' << printReg(R, TRI));
14770b57cec5SDimitry Andric     for (MCSubRegIterator SR(R, TRI, true); SR.isValid(); ++SR)
14780b57cec5SDimitry Andric       SRegs[*SR] = true;
14790b57cec5SDimitry Andric   }
14800b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << " }\n");
14810b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "SRegs.1: "; dump_registers(SRegs, *TRI);
14820b57cec5SDimitry Andric              dbgs() << "\n");
14830b57cec5SDimitry Andric 
14840b57cec5SDimitry Andric   // (2) For each reserved register, remove that register and all of its
14850b57cec5SDimitry Andric   // sub- and super-registers from SRegs.
14860b57cec5SDimitry Andric   BitVector Reserved = TRI->getReservedRegs(MF);
14870b57cec5SDimitry Andric   for (int x = Reserved.find_first(); x >= 0; x = Reserved.find_next(x)) {
14880b57cec5SDimitry Andric     unsigned R = x;
14890b57cec5SDimitry Andric     for (MCSuperRegIterator SR(R, TRI, true); SR.isValid(); ++SR)
14900b57cec5SDimitry Andric       SRegs[*SR] = false;
14910b57cec5SDimitry Andric   }
14920b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Res:     "; dump_registers(Reserved, *TRI);
14930b57cec5SDimitry Andric              dbgs() << "\n");
14940b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "SRegs.2: "; dump_registers(SRegs, *TRI);
14950b57cec5SDimitry Andric              dbgs() << "\n");
14960b57cec5SDimitry Andric 
14970b57cec5SDimitry Andric   // (3) Collect all registers that have at least one sub-register in SRegs,
14980b57cec5SDimitry Andric   // and also have no sub-registers that are reserved. These will be the can-
14990b57cec5SDimitry Andric   // didates for saving as a whole instead of their individual sub-registers.
15000b57cec5SDimitry Andric   // (Saving R17:16 instead of R16 is fine, but only if R17 was not reserved.)
15010b57cec5SDimitry Andric   BitVector TmpSup(Hexagon::NUM_TARGET_REGS);
15020b57cec5SDimitry Andric   for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) {
15030b57cec5SDimitry Andric     unsigned R = x;
15040b57cec5SDimitry Andric     for (MCSuperRegIterator SR(R, TRI); SR.isValid(); ++SR)
15050b57cec5SDimitry Andric       TmpSup[*SR] = true;
15060b57cec5SDimitry Andric   }
15070b57cec5SDimitry Andric   for (int x = TmpSup.find_first(); x >= 0; x = TmpSup.find_next(x)) {
15080b57cec5SDimitry Andric     unsigned R = x;
15090b57cec5SDimitry Andric     for (MCSubRegIterator SR(R, TRI, true); SR.isValid(); ++SR) {
15100b57cec5SDimitry Andric       if (!Reserved[*SR])
15110b57cec5SDimitry Andric         continue;
15120b57cec5SDimitry Andric       TmpSup[R] = false;
15130b57cec5SDimitry Andric       break;
15140b57cec5SDimitry Andric     }
15150b57cec5SDimitry Andric   }
15160b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "TmpSup:  "; dump_registers(TmpSup, *TRI);
15170b57cec5SDimitry Andric              dbgs() << "\n");
15180b57cec5SDimitry Andric 
15190b57cec5SDimitry Andric   // (4) Include all super-registers found in (3) into SRegs.
15200b57cec5SDimitry Andric   SRegs |= TmpSup;
15210b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "SRegs.4: "; dump_registers(SRegs, *TRI);
15220b57cec5SDimitry Andric              dbgs() << "\n");
15230b57cec5SDimitry Andric 
15240b57cec5SDimitry Andric   // (5) For each register R in SRegs, if any super-register of R is in SRegs,
15250b57cec5SDimitry Andric   // remove R from SRegs.
15260b57cec5SDimitry Andric   for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) {
15270b57cec5SDimitry Andric     unsigned R = x;
15280b57cec5SDimitry Andric     for (MCSuperRegIterator SR(R, TRI); SR.isValid(); ++SR) {
15290b57cec5SDimitry Andric       if (!SRegs[*SR])
15300b57cec5SDimitry Andric         continue;
15310b57cec5SDimitry Andric       SRegs[R] = false;
15320b57cec5SDimitry Andric       break;
15330b57cec5SDimitry Andric     }
15340b57cec5SDimitry Andric   }
15350b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "SRegs.5: "; dump_registers(SRegs, *TRI);
15360b57cec5SDimitry Andric              dbgs() << "\n");
15370b57cec5SDimitry Andric 
15380b57cec5SDimitry Andric   // Now, for each register that has a fixed stack slot, create the stack
15390b57cec5SDimitry Andric   // object for it.
15400b57cec5SDimitry Andric   CSI.clear();
15410b57cec5SDimitry Andric 
15420b57cec5SDimitry Andric   using SpillSlot = TargetFrameLowering::SpillSlot;
15430b57cec5SDimitry Andric 
15440b57cec5SDimitry Andric   unsigned NumFixed;
15450b57cec5SDimitry Andric   int MinOffset = 0;  // CS offsets are negative.
15460b57cec5SDimitry Andric   const SpillSlot *FixedSlots = getCalleeSavedSpillSlots(NumFixed);
15470b57cec5SDimitry Andric   for (const SpillSlot *S = FixedSlots; S != FixedSlots+NumFixed; ++S) {
15480b57cec5SDimitry Andric     if (!SRegs[S->Reg])
15490b57cec5SDimitry Andric       continue;
15500b57cec5SDimitry Andric     const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(S->Reg);
15510b57cec5SDimitry Andric     int FI = MFI.CreateFixedSpillStackObject(TRI->getSpillSize(*RC), S->Offset);
15520b57cec5SDimitry Andric     MinOffset = std::min(MinOffset, S->Offset);
15530b57cec5SDimitry Andric     CSI.push_back(CalleeSavedInfo(S->Reg, FI));
15540b57cec5SDimitry Andric     SRegs[S->Reg] = false;
15550b57cec5SDimitry Andric   }
15560b57cec5SDimitry Andric 
15570b57cec5SDimitry Andric   // There can be some registers that don't have fixed slots. For example,
15580b57cec5SDimitry Andric   // we need to store R0-R3 in functions with exception handling. For each
15590b57cec5SDimitry Andric   // such register, create a non-fixed stack object.
15600b57cec5SDimitry Andric   for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) {
15610b57cec5SDimitry Andric     unsigned R = x;
15620b57cec5SDimitry Andric     const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(R);
15630b57cec5SDimitry Andric     unsigned Size = TRI->getSpillSize(*RC);
15640b57cec5SDimitry Andric     int Off = MinOffset - Size;
15650b57cec5SDimitry Andric     unsigned Align = std::min(TRI->getSpillAlignment(*RC), getStackAlignment());
15660b57cec5SDimitry Andric     assert(isPowerOf2_32(Align));
15670b57cec5SDimitry Andric     Off &= -Align;
15680b57cec5SDimitry Andric     int FI = MFI.CreateFixedSpillStackObject(Size, Off);
15690b57cec5SDimitry Andric     MinOffset = std::min(MinOffset, Off);
15700b57cec5SDimitry Andric     CSI.push_back(CalleeSavedInfo(R, FI));
15710b57cec5SDimitry Andric     SRegs[R] = false;
15720b57cec5SDimitry Andric   }
15730b57cec5SDimitry Andric 
15740b57cec5SDimitry Andric   LLVM_DEBUG({
15750b57cec5SDimitry Andric     dbgs() << "CS information: {";
15760b57cec5SDimitry Andric     for (unsigned i = 0, n = CSI.size(); i < n; ++i) {
15770b57cec5SDimitry Andric       int FI = CSI[i].getFrameIdx();
15780b57cec5SDimitry Andric       int Off = MFI.getObjectOffset(FI);
15790b57cec5SDimitry Andric       dbgs() << ' ' << printReg(CSI[i].getReg(), TRI) << ":fi#" << FI << ":sp";
15800b57cec5SDimitry Andric       if (Off >= 0)
15810b57cec5SDimitry Andric         dbgs() << '+';
15820b57cec5SDimitry Andric       dbgs() << Off;
15830b57cec5SDimitry Andric     }
15840b57cec5SDimitry Andric     dbgs() << " }\n";
15850b57cec5SDimitry Andric   });
15860b57cec5SDimitry Andric 
15870b57cec5SDimitry Andric #ifndef NDEBUG
15880b57cec5SDimitry Andric   // Verify that all registers were handled.
15890b57cec5SDimitry Andric   bool MissedReg = false;
15900b57cec5SDimitry Andric   for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) {
15910b57cec5SDimitry Andric     unsigned R = x;
15920b57cec5SDimitry Andric     dbgs() << printReg(R, TRI) << ' ';
15930b57cec5SDimitry Andric     MissedReg = true;
15940b57cec5SDimitry Andric   }
15950b57cec5SDimitry Andric   if (MissedReg)
15960b57cec5SDimitry Andric     llvm_unreachable("...there are unhandled callee-saved registers!");
15970b57cec5SDimitry Andric #endif
15980b57cec5SDimitry Andric 
15990b57cec5SDimitry Andric   return true;
16000b57cec5SDimitry Andric }
16010b57cec5SDimitry Andric 
16020b57cec5SDimitry Andric bool HexagonFrameLowering::expandCopy(MachineBasicBlock &B,
16030b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
16040b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
16050b57cec5SDimitry Andric   MachineInstr *MI = &*It;
16060b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
16078bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
16088bcb0991SDimitry Andric   Register SrcR = MI->getOperand(1).getReg();
16090b57cec5SDimitry Andric   if (!Hexagon::ModRegsRegClass.contains(DstR) ||
16100b57cec5SDimitry Andric       !Hexagon::ModRegsRegClass.contains(SrcR))
16110b57cec5SDimitry Andric     return false;
16120b57cec5SDimitry Andric 
16138bcb0991SDimitry Andric   Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
16140b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(TargetOpcode::COPY), TmpR).add(MI->getOperand(1));
16150b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(TargetOpcode::COPY), DstR)
16160b57cec5SDimitry Andric     .addReg(TmpR, RegState::Kill);
16170b57cec5SDimitry Andric 
16180b57cec5SDimitry Andric   NewRegs.push_back(TmpR);
16190b57cec5SDimitry Andric   B.erase(It);
16200b57cec5SDimitry Andric   return true;
16210b57cec5SDimitry Andric }
16220b57cec5SDimitry Andric 
16230b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreInt(MachineBasicBlock &B,
16240b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
16250b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
16260b57cec5SDimitry Andric   MachineInstr *MI = &*It;
16270b57cec5SDimitry Andric   if (!MI->getOperand(0).isFI())
16280b57cec5SDimitry Andric     return false;
16290b57cec5SDimitry Andric 
16300b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
16310b57cec5SDimitry Andric   unsigned Opc = MI->getOpcode();
16328bcb0991SDimitry Andric   Register SrcR = MI->getOperand(2).getReg();
16330b57cec5SDimitry Andric   bool IsKill = MI->getOperand(2).isKill();
16340b57cec5SDimitry Andric   int FI = MI->getOperand(0).getIndex();
16350b57cec5SDimitry Andric 
16360b57cec5SDimitry Andric   // TmpR = C2_tfrpr SrcR   if SrcR is a predicate register
16370b57cec5SDimitry Andric   // TmpR = A2_tfrcrr SrcR  if SrcR is a modifier register
16388bcb0991SDimitry Andric   Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
16390b57cec5SDimitry Andric   unsigned TfrOpc = (Opc == Hexagon::STriw_pred) ? Hexagon::C2_tfrpr
16400b57cec5SDimitry Andric                                                  : Hexagon::A2_tfrcrr;
16410b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(TfrOpc), TmpR)
16420b57cec5SDimitry Andric     .addReg(SrcR, getKillRegState(IsKill));
16430b57cec5SDimitry Andric 
16440b57cec5SDimitry Andric   // S2_storeri_io FI, 0, TmpR
16450b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::S2_storeri_io))
16460b57cec5SDimitry Andric       .addFrameIndex(FI)
16470b57cec5SDimitry Andric       .addImm(0)
16480b57cec5SDimitry Andric       .addReg(TmpR, RegState::Kill)
16490b57cec5SDimitry Andric       .cloneMemRefs(*MI);
16500b57cec5SDimitry Andric 
16510b57cec5SDimitry Andric   NewRegs.push_back(TmpR);
16520b57cec5SDimitry Andric   B.erase(It);
16530b57cec5SDimitry Andric   return true;
16540b57cec5SDimitry Andric }
16550b57cec5SDimitry Andric 
16560b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadInt(MachineBasicBlock &B,
16570b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
16580b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
16590b57cec5SDimitry Andric   MachineInstr *MI = &*It;
16600b57cec5SDimitry Andric   if (!MI->getOperand(1).isFI())
16610b57cec5SDimitry Andric     return false;
16620b57cec5SDimitry Andric 
16630b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
16640b57cec5SDimitry Andric   unsigned Opc = MI->getOpcode();
16658bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
16660b57cec5SDimitry Andric   int FI = MI->getOperand(1).getIndex();
16670b57cec5SDimitry Andric 
16680b57cec5SDimitry Andric   // TmpR = L2_loadri_io FI, 0
16698bcb0991SDimitry Andric   Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
16700b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::L2_loadri_io), TmpR)
16710b57cec5SDimitry Andric       .addFrameIndex(FI)
16720b57cec5SDimitry Andric       .addImm(0)
16730b57cec5SDimitry Andric       .cloneMemRefs(*MI);
16740b57cec5SDimitry Andric 
16750b57cec5SDimitry Andric   // DstR = C2_tfrrp TmpR   if DstR is a predicate register
16760b57cec5SDimitry Andric   // DstR = A2_tfrrcr TmpR  if DstR is a modifier register
16770b57cec5SDimitry Andric   unsigned TfrOpc = (Opc == Hexagon::LDriw_pred) ? Hexagon::C2_tfrrp
16780b57cec5SDimitry Andric                                                  : Hexagon::A2_tfrrcr;
16790b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(TfrOpc), DstR)
16800b57cec5SDimitry Andric     .addReg(TmpR, RegState::Kill);
16810b57cec5SDimitry Andric 
16820b57cec5SDimitry Andric   NewRegs.push_back(TmpR);
16830b57cec5SDimitry Andric   B.erase(It);
16840b57cec5SDimitry Andric   return true;
16850b57cec5SDimitry Andric }
16860b57cec5SDimitry Andric 
16870b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVecPred(MachineBasicBlock &B,
16880b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
16890b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
16900b57cec5SDimitry Andric   MachineInstr *MI = &*It;
16910b57cec5SDimitry Andric   if (!MI->getOperand(0).isFI())
16920b57cec5SDimitry Andric     return false;
16930b57cec5SDimitry Andric 
16940b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
16958bcb0991SDimitry Andric   Register SrcR = MI->getOperand(2).getReg();
16960b57cec5SDimitry Andric   bool IsKill = MI->getOperand(2).isKill();
16970b57cec5SDimitry Andric   int FI = MI->getOperand(0).getIndex();
16980b57cec5SDimitry Andric   auto *RC = &Hexagon::HvxVRRegClass;
16990b57cec5SDimitry Andric 
17000b57cec5SDimitry Andric   // Insert transfer to general vector register.
17010b57cec5SDimitry Andric   //   TmpR0 = A2_tfrsi 0x01010101
17020b57cec5SDimitry Andric   //   TmpR1 = V6_vandqrt Qx, TmpR0
17030b57cec5SDimitry Andric   //   store FI, 0, TmpR1
17048bcb0991SDimitry Andric   Register TmpR0 = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
17058bcb0991SDimitry Andric   Register TmpR1 = MRI.createVirtualRegister(RC);
17060b57cec5SDimitry Andric 
17070b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::A2_tfrsi), TmpR0)
17080b57cec5SDimitry Andric     .addImm(0x01010101);
17090b57cec5SDimitry Andric 
17100b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::V6_vandqrt), TmpR1)
17110b57cec5SDimitry Andric     .addReg(SrcR, getKillRegState(IsKill))
17120b57cec5SDimitry Andric     .addReg(TmpR0, RegState::Kill);
17130b57cec5SDimitry Andric 
17140b57cec5SDimitry Andric   auto *HRI = B.getParent()->getSubtarget<HexagonSubtarget>().getRegisterInfo();
17150b57cec5SDimitry Andric   HII.storeRegToStackSlot(B, It, TmpR1, true, FI, RC, HRI);
17160b57cec5SDimitry Andric   expandStoreVec(B, std::prev(It), MRI, HII, NewRegs);
17170b57cec5SDimitry Andric 
17180b57cec5SDimitry Andric   NewRegs.push_back(TmpR0);
17190b57cec5SDimitry Andric   NewRegs.push_back(TmpR1);
17200b57cec5SDimitry Andric   B.erase(It);
17210b57cec5SDimitry Andric   return true;
17220b57cec5SDimitry Andric }
17230b57cec5SDimitry Andric 
17240b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVecPred(MachineBasicBlock &B,
17250b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
17260b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
17270b57cec5SDimitry Andric   MachineInstr *MI = &*It;
17280b57cec5SDimitry Andric   if (!MI->getOperand(1).isFI())
17290b57cec5SDimitry Andric     return false;
17300b57cec5SDimitry Andric 
17310b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
17328bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
17330b57cec5SDimitry Andric   int FI = MI->getOperand(1).getIndex();
17340b57cec5SDimitry Andric   auto *RC = &Hexagon::HvxVRRegClass;
17350b57cec5SDimitry Andric 
17360b57cec5SDimitry Andric   // TmpR0 = A2_tfrsi 0x01010101
17370b57cec5SDimitry Andric   // TmpR1 = load FI, 0
17380b57cec5SDimitry Andric   // DstR = V6_vandvrt TmpR1, TmpR0
17398bcb0991SDimitry Andric   Register TmpR0 = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
17408bcb0991SDimitry Andric   Register TmpR1 = MRI.createVirtualRegister(RC);
17410b57cec5SDimitry Andric 
17420b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::A2_tfrsi), TmpR0)
17430b57cec5SDimitry Andric     .addImm(0x01010101);
17440b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
17450b57cec5SDimitry Andric   auto *HRI = MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
17460b57cec5SDimitry Andric   HII.loadRegFromStackSlot(B, It, TmpR1, FI, RC, HRI);
17470b57cec5SDimitry Andric   expandLoadVec(B, std::prev(It), MRI, HII, NewRegs);
17480b57cec5SDimitry Andric 
17490b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::V6_vandvrt), DstR)
17500b57cec5SDimitry Andric     .addReg(TmpR1, RegState::Kill)
17510b57cec5SDimitry Andric     .addReg(TmpR0, RegState::Kill);
17520b57cec5SDimitry Andric 
17530b57cec5SDimitry Andric   NewRegs.push_back(TmpR0);
17540b57cec5SDimitry Andric   NewRegs.push_back(TmpR1);
17550b57cec5SDimitry Andric   B.erase(It);
17560b57cec5SDimitry Andric   return true;
17570b57cec5SDimitry Andric }
17580b57cec5SDimitry Andric 
17590b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVec2(MachineBasicBlock &B,
17600b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
17610b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
17620b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
17630b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
17640b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
17650b57cec5SDimitry Andric   MachineInstr *MI = &*It;
17660b57cec5SDimitry Andric   if (!MI->getOperand(0).isFI())
17670b57cec5SDimitry Andric     return false;
17680b57cec5SDimitry Andric 
17690b57cec5SDimitry Andric   // It is possible that the double vector being stored is only partially
17700b57cec5SDimitry Andric   // defined. From the point of view of the liveness tracking, it is ok to
17710b57cec5SDimitry Andric   // store it as a whole, but if we break it up we may end up storing a
17720b57cec5SDimitry Andric   // register that is entirely undefined.
17730b57cec5SDimitry Andric   LivePhysRegs LPR(HRI);
17740b57cec5SDimitry Andric   LPR.addLiveIns(B);
17750b57cec5SDimitry Andric   SmallVector<std::pair<MCPhysReg, const MachineOperand*>,2> Clobbers;
17760b57cec5SDimitry Andric   for (auto R = B.begin(); R != It; ++R) {
17770b57cec5SDimitry Andric     Clobbers.clear();
17780b57cec5SDimitry Andric     LPR.stepForward(*R, Clobbers);
17790b57cec5SDimitry Andric   }
17800b57cec5SDimitry Andric 
17810b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
17828bcb0991SDimitry Andric   Register SrcR = MI->getOperand(2).getReg();
17838bcb0991SDimitry Andric   Register SrcLo = HRI.getSubReg(SrcR, Hexagon::vsub_lo);
17848bcb0991SDimitry Andric   Register SrcHi = HRI.getSubReg(SrcR, Hexagon::vsub_hi);
17850b57cec5SDimitry Andric   bool IsKill = MI->getOperand(2).isKill();
17860b57cec5SDimitry Andric   int FI = MI->getOperand(0).getIndex();
1787*480093f4SDimitry Andric   bool NeedsAligna = needsAligna(MF);
17880b57cec5SDimitry Andric 
17890b57cec5SDimitry Andric   unsigned Size = HRI.getSpillSize(Hexagon::HvxVRRegClass);
17900b57cec5SDimitry Andric   unsigned NeedAlign = HRI.getSpillAlignment(Hexagon::HvxVRRegClass);
17910b57cec5SDimitry Andric   unsigned HasAlign = MFI.getObjectAlignment(FI);
17920b57cec5SDimitry Andric   unsigned StoreOpc;
17930b57cec5SDimitry Andric 
1794*480093f4SDimitry Andric   auto UseAligned = [&] (unsigned NeedAlign, unsigned HasAlign) {
1795*480093f4SDimitry Andric     return !NeedsAligna && (NeedAlign <= HasAlign);
1796*480093f4SDimitry Andric   };
1797*480093f4SDimitry Andric 
17980b57cec5SDimitry Andric   // Store low part.
17990b57cec5SDimitry Andric   if (LPR.contains(SrcLo)) {
1800*480093f4SDimitry Andric     StoreOpc = UseAligned(NeedAlign, HasAlign) ? Hexagon::V6_vS32b_ai
18010b57cec5SDimitry Andric                                                : Hexagon::V6_vS32Ub_ai;
18020b57cec5SDimitry Andric     BuildMI(B, It, DL, HII.get(StoreOpc))
18030b57cec5SDimitry Andric         .addFrameIndex(FI)
18040b57cec5SDimitry Andric         .addImm(0)
18050b57cec5SDimitry Andric         .addReg(SrcLo, getKillRegState(IsKill))
18060b57cec5SDimitry Andric         .cloneMemRefs(*MI);
18070b57cec5SDimitry Andric   }
18080b57cec5SDimitry Andric 
18090b57cec5SDimitry Andric   // Store high part.
18100b57cec5SDimitry Andric   if (LPR.contains(SrcHi)) {
1811*480093f4SDimitry Andric     StoreOpc = UseAligned(NeedAlign, HasAlign) ? Hexagon::V6_vS32b_ai
18120b57cec5SDimitry Andric                                                : Hexagon::V6_vS32Ub_ai;
18130b57cec5SDimitry Andric     BuildMI(B, It, DL, HII.get(StoreOpc))
18140b57cec5SDimitry Andric         .addFrameIndex(FI)
18150b57cec5SDimitry Andric         .addImm(Size)
18160b57cec5SDimitry Andric         .addReg(SrcHi, getKillRegState(IsKill))
18170b57cec5SDimitry Andric         .cloneMemRefs(*MI);
18180b57cec5SDimitry Andric   }
18190b57cec5SDimitry Andric 
18200b57cec5SDimitry Andric   B.erase(It);
18210b57cec5SDimitry Andric   return true;
18220b57cec5SDimitry Andric }
18230b57cec5SDimitry Andric 
18240b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVec2(MachineBasicBlock &B,
18250b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
18260b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
18270b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
18280b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
18290b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
18300b57cec5SDimitry Andric   MachineInstr *MI = &*It;
18310b57cec5SDimitry Andric   if (!MI->getOperand(1).isFI())
18320b57cec5SDimitry Andric     return false;
18330b57cec5SDimitry Andric 
18340b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
18358bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
18368bcb0991SDimitry Andric   Register DstHi = HRI.getSubReg(DstR, Hexagon::vsub_hi);
18378bcb0991SDimitry Andric   Register DstLo = HRI.getSubReg(DstR, Hexagon::vsub_lo);
18380b57cec5SDimitry Andric   int FI = MI->getOperand(1).getIndex();
1839*480093f4SDimitry Andric   bool NeedsAligna = needsAligna(MF);
18400b57cec5SDimitry Andric 
18410b57cec5SDimitry Andric   unsigned Size = HRI.getSpillSize(Hexagon::HvxVRRegClass);
18420b57cec5SDimitry Andric   unsigned NeedAlign = HRI.getSpillAlignment(Hexagon::HvxVRRegClass);
18430b57cec5SDimitry Andric   unsigned HasAlign = MFI.getObjectAlignment(FI);
18440b57cec5SDimitry Andric   unsigned LoadOpc;
18450b57cec5SDimitry Andric 
1846*480093f4SDimitry Andric   auto UseAligned = [&] (unsigned NeedAlign, unsigned HasAlign) {
1847*480093f4SDimitry Andric     return !NeedsAligna && (NeedAlign <= HasAlign);
1848*480093f4SDimitry Andric   };
1849*480093f4SDimitry Andric 
18500b57cec5SDimitry Andric   // Load low part.
1851*480093f4SDimitry Andric   LoadOpc = UseAligned(NeedAlign, HasAlign) ? Hexagon::V6_vL32b_ai
18520b57cec5SDimitry Andric                                             : Hexagon::V6_vL32Ub_ai;
18530b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(LoadOpc), DstLo)
18540b57cec5SDimitry Andric       .addFrameIndex(FI)
18550b57cec5SDimitry Andric       .addImm(0)
18560b57cec5SDimitry Andric       .cloneMemRefs(*MI);
18570b57cec5SDimitry Andric 
18580b57cec5SDimitry Andric   // Load high part.
1859*480093f4SDimitry Andric   LoadOpc = UseAligned(NeedAlign, HasAlign) ? Hexagon::V6_vL32b_ai
18600b57cec5SDimitry Andric                                             : Hexagon::V6_vL32Ub_ai;
18610b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(LoadOpc), DstHi)
18620b57cec5SDimitry Andric       .addFrameIndex(FI)
18630b57cec5SDimitry Andric       .addImm(Size)
18640b57cec5SDimitry Andric       .cloneMemRefs(*MI);
18650b57cec5SDimitry Andric 
18660b57cec5SDimitry Andric   B.erase(It);
18670b57cec5SDimitry Andric   return true;
18680b57cec5SDimitry Andric }
18690b57cec5SDimitry Andric 
18700b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVec(MachineBasicBlock &B,
18710b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
18720b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
18730b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
18740b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
18750b57cec5SDimitry Andric   MachineInstr *MI = &*It;
18760b57cec5SDimitry Andric   if (!MI->getOperand(0).isFI())
18770b57cec5SDimitry Andric     return false;
18780b57cec5SDimitry Andric 
1879*480093f4SDimitry Andric   bool NeedsAligna = needsAligna(MF);
18800b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
18810b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
18828bcb0991SDimitry Andric   Register SrcR = MI->getOperand(2).getReg();
18830b57cec5SDimitry Andric   bool IsKill = MI->getOperand(2).isKill();
18840b57cec5SDimitry Andric   int FI = MI->getOperand(0).getIndex();
18850b57cec5SDimitry Andric 
18860b57cec5SDimitry Andric   unsigned NeedAlign = HRI.getSpillAlignment(Hexagon::HvxVRRegClass);
18870b57cec5SDimitry Andric   unsigned HasAlign = MFI.getObjectAlignment(FI);
1888*480093f4SDimitry Andric   bool UseAligned = !NeedsAligna && (NeedAlign <= HasAlign);
1889*480093f4SDimitry Andric   unsigned StoreOpc = UseAligned ? Hexagon::V6_vS32b_ai
18900b57cec5SDimitry Andric                                  : Hexagon::V6_vS32Ub_ai;
18910b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(StoreOpc))
18920b57cec5SDimitry Andric       .addFrameIndex(FI)
18930b57cec5SDimitry Andric       .addImm(0)
18940b57cec5SDimitry Andric       .addReg(SrcR, getKillRegState(IsKill))
18950b57cec5SDimitry Andric       .cloneMemRefs(*MI);
18960b57cec5SDimitry Andric 
18970b57cec5SDimitry Andric   B.erase(It);
18980b57cec5SDimitry Andric   return true;
18990b57cec5SDimitry Andric }
19000b57cec5SDimitry Andric 
19010b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVec(MachineBasicBlock &B,
19020b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
19030b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
19040b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
19050b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
19060b57cec5SDimitry Andric   MachineInstr *MI = &*It;
19070b57cec5SDimitry Andric   if (!MI->getOperand(1).isFI())
19080b57cec5SDimitry Andric     return false;
19090b57cec5SDimitry Andric 
1910*480093f4SDimitry Andric   bool NeedsAligna = needsAligna(MF);
19110b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
19120b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
19138bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
19140b57cec5SDimitry Andric   int FI = MI->getOperand(1).getIndex();
19150b57cec5SDimitry Andric 
19160b57cec5SDimitry Andric   unsigned NeedAlign = HRI.getSpillAlignment(Hexagon::HvxVRRegClass);
19170b57cec5SDimitry Andric   unsigned HasAlign = MFI.getObjectAlignment(FI);
1918*480093f4SDimitry Andric   bool UseAligned = !NeedsAligna && (NeedAlign <= HasAlign);
1919*480093f4SDimitry Andric   unsigned LoadOpc = UseAligned ? Hexagon::V6_vL32b_ai
19200b57cec5SDimitry Andric                                 : Hexagon::V6_vL32Ub_ai;
19210b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(LoadOpc), DstR)
19220b57cec5SDimitry Andric       .addFrameIndex(FI)
19230b57cec5SDimitry Andric       .addImm(0)
19240b57cec5SDimitry Andric       .cloneMemRefs(*MI);
19250b57cec5SDimitry Andric 
19260b57cec5SDimitry Andric   B.erase(It);
19270b57cec5SDimitry Andric   return true;
19280b57cec5SDimitry Andric }
19290b57cec5SDimitry Andric 
19300b57cec5SDimitry Andric bool HexagonFrameLowering::expandSpillMacros(MachineFunction &MF,
19310b57cec5SDimitry Andric       SmallVectorImpl<unsigned> &NewRegs) const {
19320b57cec5SDimitry Andric   auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
19330b57cec5SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
19340b57cec5SDimitry Andric   bool Changed = false;
19350b57cec5SDimitry Andric 
19360b57cec5SDimitry Andric   for (auto &B : MF) {
19370b57cec5SDimitry Andric     // Traverse the basic block.
19380b57cec5SDimitry Andric     MachineBasicBlock::iterator NextI;
19390b57cec5SDimitry Andric     for (auto I = B.begin(), E = B.end(); I != E; I = NextI) {
19400b57cec5SDimitry Andric       MachineInstr *MI = &*I;
19410b57cec5SDimitry Andric       NextI = std::next(I);
19420b57cec5SDimitry Andric       unsigned Opc = MI->getOpcode();
19430b57cec5SDimitry Andric 
19440b57cec5SDimitry Andric       switch (Opc) {
19450b57cec5SDimitry Andric         case TargetOpcode::COPY:
19460b57cec5SDimitry Andric           Changed |= expandCopy(B, I, MRI, HII, NewRegs);
19470b57cec5SDimitry Andric           break;
19480b57cec5SDimitry Andric         case Hexagon::STriw_pred:
19490b57cec5SDimitry Andric         case Hexagon::STriw_ctr:
19500b57cec5SDimitry Andric           Changed |= expandStoreInt(B, I, MRI, HII, NewRegs);
19510b57cec5SDimitry Andric           break;
19520b57cec5SDimitry Andric         case Hexagon::LDriw_pred:
19530b57cec5SDimitry Andric         case Hexagon::LDriw_ctr:
19540b57cec5SDimitry Andric           Changed |= expandLoadInt(B, I, MRI, HII, NewRegs);
19550b57cec5SDimitry Andric           break;
19560b57cec5SDimitry Andric         case Hexagon::PS_vstorerq_ai:
19570b57cec5SDimitry Andric           Changed |= expandStoreVecPred(B, I, MRI, HII, NewRegs);
19580b57cec5SDimitry Andric           break;
19590b57cec5SDimitry Andric         case Hexagon::PS_vloadrq_ai:
19600b57cec5SDimitry Andric           Changed |= expandLoadVecPred(B, I, MRI, HII, NewRegs);
19610b57cec5SDimitry Andric           break;
19620b57cec5SDimitry Andric         case Hexagon::PS_vloadrw_ai:
19630b57cec5SDimitry Andric           Changed |= expandLoadVec2(B, I, MRI, HII, NewRegs);
19640b57cec5SDimitry Andric           break;
19650b57cec5SDimitry Andric         case Hexagon::PS_vstorerw_ai:
19660b57cec5SDimitry Andric           Changed |= expandStoreVec2(B, I, MRI, HII, NewRegs);
19670b57cec5SDimitry Andric           break;
19680b57cec5SDimitry Andric       }
19690b57cec5SDimitry Andric     }
19700b57cec5SDimitry Andric   }
19710b57cec5SDimitry Andric 
19720b57cec5SDimitry Andric   return Changed;
19730b57cec5SDimitry Andric }
19740b57cec5SDimitry Andric 
19750b57cec5SDimitry Andric void HexagonFrameLowering::determineCalleeSaves(MachineFunction &MF,
19760b57cec5SDimitry Andric                                                 BitVector &SavedRegs,
19770b57cec5SDimitry Andric                                                 RegScavenger *RS) const {
19780b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
19790b57cec5SDimitry Andric 
19800b57cec5SDimitry Andric   SavedRegs.resize(HRI.getNumRegs());
19810b57cec5SDimitry Andric 
19820b57cec5SDimitry Andric   // If we have a function containing __builtin_eh_return we want to spill and
19830b57cec5SDimitry Andric   // restore all callee saved registers. Pretend that they are used.
19840b57cec5SDimitry Andric   if (MF.getInfo<HexagonMachineFunctionInfo>()->hasEHReturn())
19850b57cec5SDimitry Andric     for (const MCPhysReg *R = HRI.getCalleeSavedRegs(&MF); *R; ++R)
19860b57cec5SDimitry Andric       SavedRegs.set(*R);
19870b57cec5SDimitry Andric 
19880b57cec5SDimitry Andric   // Replace predicate register pseudo spill code.
19890b57cec5SDimitry Andric   SmallVector<unsigned,8> NewRegs;
19900b57cec5SDimitry Andric   expandSpillMacros(MF, NewRegs);
19910b57cec5SDimitry Andric   if (OptimizeSpillSlots && !isOptNone(MF))
19920b57cec5SDimitry Andric     optimizeSpillSlots(MF, NewRegs);
19930b57cec5SDimitry Andric 
19940b57cec5SDimitry Andric   // We need to reserve a spill slot if scavenging could potentially require
19950b57cec5SDimitry Andric   // spilling a scavenged register.
19960b57cec5SDimitry Andric   if (!NewRegs.empty() || mayOverflowFrameOffset(MF)) {
19970b57cec5SDimitry Andric     MachineFrameInfo &MFI = MF.getFrameInfo();
19980b57cec5SDimitry Andric     MachineRegisterInfo &MRI = MF.getRegInfo();
19990b57cec5SDimitry Andric     SetVector<const TargetRegisterClass*> SpillRCs;
20000b57cec5SDimitry Andric     // Reserve an int register in any case, because it could be used to hold
20010b57cec5SDimitry Andric     // the stack offset in case it does not fit into a spill instruction.
20020b57cec5SDimitry Andric     SpillRCs.insert(&Hexagon::IntRegsRegClass);
20030b57cec5SDimitry Andric 
20040b57cec5SDimitry Andric     for (unsigned VR : NewRegs)
20050b57cec5SDimitry Andric       SpillRCs.insert(MRI.getRegClass(VR));
20060b57cec5SDimitry Andric 
20070b57cec5SDimitry Andric     for (auto *RC : SpillRCs) {
20080b57cec5SDimitry Andric       if (!needToReserveScavengingSpillSlots(MF, HRI, RC))
20090b57cec5SDimitry Andric         continue;
2010*480093f4SDimitry Andric       unsigned Num = 1;
2011*480093f4SDimitry Andric       switch (RC->getID()) {
2012*480093f4SDimitry Andric         case Hexagon::IntRegsRegClassID:
2013*480093f4SDimitry Andric           Num = NumberScavengerSlots;
2014*480093f4SDimitry Andric           break;
2015*480093f4SDimitry Andric         case Hexagon::HvxQRRegClassID:
2016*480093f4SDimitry Andric           Num = 2; // Vector predicate spills also need a vector register.
2017*480093f4SDimitry Andric           break;
2018*480093f4SDimitry Andric       }
20190b57cec5SDimitry Andric       unsigned S = HRI.getSpillSize(*RC), A = HRI.getSpillAlignment(*RC);
20200b57cec5SDimitry Andric       for (unsigned i = 0; i < Num; i++) {
20210b57cec5SDimitry Andric         int NewFI = MFI.CreateSpillStackObject(S, A);
20220b57cec5SDimitry Andric         RS->addScavengingFrameIndex(NewFI);
20230b57cec5SDimitry Andric       }
20240b57cec5SDimitry Andric     }
20250b57cec5SDimitry Andric   }
20260b57cec5SDimitry Andric 
20270b57cec5SDimitry Andric   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
20280b57cec5SDimitry Andric }
20290b57cec5SDimitry Andric 
20300b57cec5SDimitry Andric unsigned HexagonFrameLowering::findPhysReg(MachineFunction &MF,
20310b57cec5SDimitry Andric       HexagonBlockRanges::IndexRange &FIR,
20320b57cec5SDimitry Andric       HexagonBlockRanges::InstrIndexMap &IndexMap,
20330b57cec5SDimitry Andric       HexagonBlockRanges::RegToRangeMap &DeadMap,
20340b57cec5SDimitry Andric       const TargetRegisterClass *RC) const {
20350b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
20360b57cec5SDimitry Andric   auto &MRI = MF.getRegInfo();
20370b57cec5SDimitry Andric 
20380b57cec5SDimitry Andric   auto isDead = [&FIR,&DeadMap] (unsigned Reg) -> bool {
20390b57cec5SDimitry Andric     auto F = DeadMap.find({Reg,0});
20400b57cec5SDimitry Andric     if (F == DeadMap.end())
20410b57cec5SDimitry Andric       return false;
20420b57cec5SDimitry Andric     for (auto &DR : F->second)
20430b57cec5SDimitry Andric       if (DR.contains(FIR))
20440b57cec5SDimitry Andric         return true;
20450b57cec5SDimitry Andric     return false;
20460b57cec5SDimitry Andric   };
20470b57cec5SDimitry Andric 
20480b57cec5SDimitry Andric   for (unsigned Reg : RC->getRawAllocationOrder(MF)) {
20490b57cec5SDimitry Andric     bool Dead = true;
20500b57cec5SDimitry Andric     for (auto R : HexagonBlockRanges::expandToSubRegs({Reg,0}, MRI, HRI)) {
20510b57cec5SDimitry Andric       if (isDead(R.Reg))
20520b57cec5SDimitry Andric         continue;
20530b57cec5SDimitry Andric       Dead = false;
20540b57cec5SDimitry Andric       break;
20550b57cec5SDimitry Andric     }
20560b57cec5SDimitry Andric     if (Dead)
20570b57cec5SDimitry Andric       return Reg;
20580b57cec5SDimitry Andric   }
20590b57cec5SDimitry Andric   return 0;
20600b57cec5SDimitry Andric }
20610b57cec5SDimitry Andric 
20620b57cec5SDimitry Andric void HexagonFrameLowering::optimizeSpillSlots(MachineFunction &MF,
20630b57cec5SDimitry Andric       SmallVectorImpl<unsigned> &VRegs) const {
20640b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
20650b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
20660b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
20670b57cec5SDimitry Andric   auto &MRI = MF.getRegInfo();
20680b57cec5SDimitry Andric   HexagonBlockRanges HBR(MF);
20690b57cec5SDimitry Andric 
20700b57cec5SDimitry Andric   using BlockIndexMap =
20710b57cec5SDimitry Andric       std::map<MachineBasicBlock *, HexagonBlockRanges::InstrIndexMap>;
20720b57cec5SDimitry Andric   using BlockRangeMap =
20730b57cec5SDimitry Andric       std::map<MachineBasicBlock *, HexagonBlockRanges::RangeList>;
20740b57cec5SDimitry Andric   using IndexType = HexagonBlockRanges::IndexType;
20750b57cec5SDimitry Andric 
20760b57cec5SDimitry Andric   struct SlotInfo {
20770b57cec5SDimitry Andric     BlockRangeMap Map;
20780b57cec5SDimitry Andric     unsigned Size = 0;
20790b57cec5SDimitry Andric     const TargetRegisterClass *RC = nullptr;
20800b57cec5SDimitry Andric 
20810b57cec5SDimitry Andric     SlotInfo() = default;
20820b57cec5SDimitry Andric   };
20830b57cec5SDimitry Andric 
20840b57cec5SDimitry Andric   BlockIndexMap BlockIndexes;
20850b57cec5SDimitry Andric   SmallSet<int,4> BadFIs;
20860b57cec5SDimitry Andric   std::map<int,SlotInfo> FIRangeMap;
20870b57cec5SDimitry Andric 
20880b57cec5SDimitry Andric   // Accumulate register classes: get a common class for a pre-existing
20890b57cec5SDimitry Andric   // class HaveRC and a new class NewRC. Return nullptr if a common class
20900b57cec5SDimitry Andric   // cannot be found, otherwise return the resulting class. If HaveRC is
20910b57cec5SDimitry Andric   // nullptr, assume that it is still unset.
20920b57cec5SDimitry Andric   auto getCommonRC =
20930b57cec5SDimitry Andric       [](const TargetRegisterClass *HaveRC,
20940b57cec5SDimitry Andric          const TargetRegisterClass *NewRC) -> const TargetRegisterClass * {
20950b57cec5SDimitry Andric     if (HaveRC == nullptr || HaveRC == NewRC)
20960b57cec5SDimitry Andric       return NewRC;
20970b57cec5SDimitry Andric     // Different classes, both non-null. Pick the more general one.
20980b57cec5SDimitry Andric     if (HaveRC->hasSubClassEq(NewRC))
20990b57cec5SDimitry Andric       return HaveRC;
21000b57cec5SDimitry Andric     if (NewRC->hasSubClassEq(HaveRC))
21010b57cec5SDimitry Andric       return NewRC;
21020b57cec5SDimitry Andric     return nullptr;
21030b57cec5SDimitry Andric   };
21040b57cec5SDimitry Andric 
21050b57cec5SDimitry Andric   // Scan all blocks in the function. Check all occurrences of frame indexes,
21060b57cec5SDimitry Andric   // and collect relevant information.
21070b57cec5SDimitry Andric   for (auto &B : MF) {
21080b57cec5SDimitry Andric     std::map<int,IndexType> LastStore, LastLoad;
21090b57cec5SDimitry Andric     // Emplace appears not to be supported in gcc 4.7.2-4.
21100b57cec5SDimitry Andric     //auto P = BlockIndexes.emplace(&B, HexagonBlockRanges::InstrIndexMap(B));
21110b57cec5SDimitry Andric     auto P = BlockIndexes.insert(
21120b57cec5SDimitry Andric                 std::make_pair(&B, HexagonBlockRanges::InstrIndexMap(B)));
21130b57cec5SDimitry Andric     auto &IndexMap = P.first->second;
21140b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Index map for " << printMBBReference(B) << "\n"
21150b57cec5SDimitry Andric                       << IndexMap << '\n');
21160b57cec5SDimitry Andric 
21170b57cec5SDimitry Andric     for (auto &In : B) {
21180b57cec5SDimitry Andric       int LFI, SFI;
21190b57cec5SDimitry Andric       bool Load = HII.isLoadFromStackSlot(In, LFI) && !HII.isPredicated(In);
21200b57cec5SDimitry Andric       bool Store = HII.isStoreToStackSlot(In, SFI) && !HII.isPredicated(In);
21210b57cec5SDimitry Andric       if (Load && Store) {
21220b57cec5SDimitry Andric         // If it's both a load and a store, then we won't handle it.
21230b57cec5SDimitry Andric         BadFIs.insert(LFI);
21240b57cec5SDimitry Andric         BadFIs.insert(SFI);
21250b57cec5SDimitry Andric         continue;
21260b57cec5SDimitry Andric       }
21270b57cec5SDimitry Andric       // Check for register classes of the register used as the source for
21280b57cec5SDimitry Andric       // the store, and the register used as the destination for the load.
21290b57cec5SDimitry Andric       // Also, only accept base+imm_offset addressing modes. Other addressing
21300b57cec5SDimitry Andric       // modes can have side-effects (post-increments, etc.). For stack
21310b57cec5SDimitry Andric       // slots they are very unlikely, so there is not much loss due to
21320b57cec5SDimitry Andric       // this restriction.
21330b57cec5SDimitry Andric       if (Load || Store) {
21340b57cec5SDimitry Andric         int TFI = Load ? LFI : SFI;
21350b57cec5SDimitry Andric         unsigned AM = HII.getAddrMode(In);
21360b57cec5SDimitry Andric         SlotInfo &SI = FIRangeMap[TFI];
21370b57cec5SDimitry Andric         bool Bad = (AM != HexagonII::BaseImmOffset);
21380b57cec5SDimitry Andric         if (!Bad) {
21390b57cec5SDimitry Andric           // If the addressing mode is ok, check the register class.
21400b57cec5SDimitry Andric           unsigned OpNum = Load ? 0 : 2;
21410b57cec5SDimitry Andric           auto *RC = HII.getRegClass(In.getDesc(), OpNum, &HRI, MF);
21420b57cec5SDimitry Andric           RC = getCommonRC(SI.RC, RC);
21430b57cec5SDimitry Andric           if (RC == nullptr)
21440b57cec5SDimitry Andric             Bad = true;
21450b57cec5SDimitry Andric           else
21460b57cec5SDimitry Andric             SI.RC = RC;
21470b57cec5SDimitry Andric         }
21480b57cec5SDimitry Andric         if (!Bad) {
21490b57cec5SDimitry Andric           // Check sizes.
21500b57cec5SDimitry Andric           unsigned S = HII.getMemAccessSize(In);
21510b57cec5SDimitry Andric           if (SI.Size != 0 && SI.Size != S)
21520b57cec5SDimitry Andric             Bad = true;
21530b57cec5SDimitry Andric           else
21540b57cec5SDimitry Andric             SI.Size = S;
21550b57cec5SDimitry Andric         }
21560b57cec5SDimitry Andric         if (!Bad) {
21570b57cec5SDimitry Andric           for (auto *Mo : In.memoperands()) {
21580b57cec5SDimitry Andric             if (!Mo->isVolatile() && !Mo->isAtomic())
21590b57cec5SDimitry Andric               continue;
21600b57cec5SDimitry Andric             Bad = true;
21610b57cec5SDimitry Andric             break;
21620b57cec5SDimitry Andric           }
21630b57cec5SDimitry Andric         }
21640b57cec5SDimitry Andric         if (Bad)
21650b57cec5SDimitry Andric           BadFIs.insert(TFI);
21660b57cec5SDimitry Andric       }
21670b57cec5SDimitry Andric 
21680b57cec5SDimitry Andric       // Locate uses of frame indices.
21690b57cec5SDimitry Andric       for (unsigned i = 0, n = In.getNumOperands(); i < n; ++i) {
21700b57cec5SDimitry Andric         const MachineOperand &Op = In.getOperand(i);
21710b57cec5SDimitry Andric         if (!Op.isFI())
21720b57cec5SDimitry Andric           continue;
21730b57cec5SDimitry Andric         int FI = Op.getIndex();
21740b57cec5SDimitry Andric         // Make sure that the following operand is an immediate and that
21750b57cec5SDimitry Andric         // it is 0. This is the offset in the stack object.
21760b57cec5SDimitry Andric         if (i+1 >= n || !In.getOperand(i+1).isImm() ||
21770b57cec5SDimitry Andric             In.getOperand(i+1).getImm() != 0)
21780b57cec5SDimitry Andric           BadFIs.insert(FI);
21790b57cec5SDimitry Andric         if (BadFIs.count(FI))
21800b57cec5SDimitry Andric           continue;
21810b57cec5SDimitry Andric 
21820b57cec5SDimitry Andric         IndexType Index = IndexMap.getIndex(&In);
21830b57cec5SDimitry Andric         if (Load) {
21840b57cec5SDimitry Andric           if (LastStore[FI] == IndexType::None)
21850b57cec5SDimitry Andric             LastStore[FI] = IndexType::Entry;
21860b57cec5SDimitry Andric           LastLoad[FI] = Index;
21870b57cec5SDimitry Andric         } else if (Store) {
21880b57cec5SDimitry Andric           HexagonBlockRanges::RangeList &RL = FIRangeMap[FI].Map[&B];
21890b57cec5SDimitry Andric           if (LastStore[FI] != IndexType::None)
21900b57cec5SDimitry Andric             RL.add(LastStore[FI], LastLoad[FI], false, false);
21910b57cec5SDimitry Andric           else if (LastLoad[FI] != IndexType::None)
21920b57cec5SDimitry Andric             RL.add(IndexType::Entry, LastLoad[FI], false, false);
21930b57cec5SDimitry Andric           LastLoad[FI] = IndexType::None;
21940b57cec5SDimitry Andric           LastStore[FI] = Index;
21950b57cec5SDimitry Andric         } else {
21960b57cec5SDimitry Andric           BadFIs.insert(FI);
21970b57cec5SDimitry Andric         }
21980b57cec5SDimitry Andric       }
21990b57cec5SDimitry Andric     }
22000b57cec5SDimitry Andric 
22010b57cec5SDimitry Andric     for (auto &I : LastLoad) {
22020b57cec5SDimitry Andric       IndexType LL = I.second;
22030b57cec5SDimitry Andric       if (LL == IndexType::None)
22040b57cec5SDimitry Andric         continue;
22050b57cec5SDimitry Andric       auto &RL = FIRangeMap[I.first].Map[&B];
22060b57cec5SDimitry Andric       IndexType &LS = LastStore[I.first];
22070b57cec5SDimitry Andric       if (LS != IndexType::None)
22080b57cec5SDimitry Andric         RL.add(LS, LL, false, false);
22090b57cec5SDimitry Andric       else
22100b57cec5SDimitry Andric         RL.add(IndexType::Entry, LL, false, false);
22110b57cec5SDimitry Andric       LS = IndexType::None;
22120b57cec5SDimitry Andric     }
22130b57cec5SDimitry Andric     for (auto &I : LastStore) {
22140b57cec5SDimitry Andric       IndexType LS = I.second;
22150b57cec5SDimitry Andric       if (LS == IndexType::None)
22160b57cec5SDimitry Andric         continue;
22170b57cec5SDimitry Andric       auto &RL = FIRangeMap[I.first].Map[&B];
22180b57cec5SDimitry Andric       RL.add(LS, IndexType::None, false, false);
22190b57cec5SDimitry Andric     }
22200b57cec5SDimitry Andric   }
22210b57cec5SDimitry Andric 
22220b57cec5SDimitry Andric   LLVM_DEBUG({
22230b57cec5SDimitry Andric     for (auto &P : FIRangeMap) {
22240b57cec5SDimitry Andric       dbgs() << "fi#" << P.first;
22250b57cec5SDimitry Andric       if (BadFIs.count(P.first))
22260b57cec5SDimitry Andric         dbgs() << " (bad)";
22270b57cec5SDimitry Andric       dbgs() << "  RC: ";
22280b57cec5SDimitry Andric       if (P.second.RC != nullptr)
22290b57cec5SDimitry Andric         dbgs() << HRI.getRegClassName(P.second.RC) << '\n';
22300b57cec5SDimitry Andric       else
22310b57cec5SDimitry Andric         dbgs() << "<null>\n";
22320b57cec5SDimitry Andric       for (auto &R : P.second.Map)
22330b57cec5SDimitry Andric         dbgs() << "  " << printMBBReference(*R.first) << " { " << R.second
22340b57cec5SDimitry Andric                << "}\n";
22350b57cec5SDimitry Andric     }
22360b57cec5SDimitry Andric   });
22370b57cec5SDimitry Andric 
22380b57cec5SDimitry Andric   // When a slot is loaded from in a block without being stored to in the
22390b57cec5SDimitry Andric   // same block, it is live-on-entry to this block. To avoid CFG analysis,
22400b57cec5SDimitry Andric   // consider this slot to be live-on-exit from all blocks.
22410b57cec5SDimitry Andric   SmallSet<int,4> LoxFIs;
22420b57cec5SDimitry Andric 
22430b57cec5SDimitry Andric   std::map<MachineBasicBlock*,std::vector<int>> BlockFIMap;
22440b57cec5SDimitry Andric 
22450b57cec5SDimitry Andric   for (auto &P : FIRangeMap) {
22460b57cec5SDimitry Andric     // P = pair(FI, map: BB->RangeList)
22470b57cec5SDimitry Andric     if (BadFIs.count(P.first))
22480b57cec5SDimitry Andric       continue;
22490b57cec5SDimitry Andric     for (auto &B : MF) {
22500b57cec5SDimitry Andric       auto F = P.second.Map.find(&B);
22510b57cec5SDimitry Andric       // F = pair(BB, RangeList)
22520b57cec5SDimitry Andric       if (F == P.second.Map.end() || F->second.empty())
22530b57cec5SDimitry Andric         continue;
22540b57cec5SDimitry Andric       HexagonBlockRanges::IndexRange &IR = F->second.front();
22550b57cec5SDimitry Andric       if (IR.start() == IndexType::Entry)
22560b57cec5SDimitry Andric         LoxFIs.insert(P.first);
22570b57cec5SDimitry Andric       BlockFIMap[&B].push_back(P.first);
22580b57cec5SDimitry Andric     }
22590b57cec5SDimitry Andric   }
22600b57cec5SDimitry Andric 
22610b57cec5SDimitry Andric   LLVM_DEBUG({
22620b57cec5SDimitry Andric     dbgs() << "Block-to-FI map (* -- live-on-exit):\n";
22630b57cec5SDimitry Andric     for (auto &P : BlockFIMap) {
22640b57cec5SDimitry Andric       auto &FIs = P.second;
22650b57cec5SDimitry Andric       if (FIs.empty())
22660b57cec5SDimitry Andric         continue;
22670b57cec5SDimitry Andric       dbgs() << "  " << printMBBReference(*P.first) << ": {";
22680b57cec5SDimitry Andric       for (auto I : FIs) {
22690b57cec5SDimitry Andric         dbgs() << " fi#" << I;
22700b57cec5SDimitry Andric         if (LoxFIs.count(I))
22710b57cec5SDimitry Andric           dbgs() << '*';
22720b57cec5SDimitry Andric       }
22730b57cec5SDimitry Andric       dbgs() << " }\n";
22740b57cec5SDimitry Andric     }
22750b57cec5SDimitry Andric   });
22760b57cec5SDimitry Andric 
22770b57cec5SDimitry Andric #ifndef NDEBUG
22780b57cec5SDimitry Andric   bool HasOptLimit = SpillOptMax.getPosition();
22790b57cec5SDimitry Andric #endif
22800b57cec5SDimitry Andric 
22810b57cec5SDimitry Andric   // eliminate loads, when all loads eliminated, eliminate all stores.
22820b57cec5SDimitry Andric   for (auto &B : MF) {
22830b57cec5SDimitry Andric     auto F = BlockIndexes.find(&B);
22840b57cec5SDimitry Andric     assert(F != BlockIndexes.end());
22850b57cec5SDimitry Andric     HexagonBlockRanges::InstrIndexMap &IM = F->second;
22860b57cec5SDimitry Andric     HexagonBlockRanges::RegToRangeMap LM = HBR.computeLiveMap(IM);
22870b57cec5SDimitry Andric     HexagonBlockRanges::RegToRangeMap DM = HBR.computeDeadMap(IM, LM);
22880b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << printMBBReference(B) << " dead map\n"
22890b57cec5SDimitry Andric                       << HexagonBlockRanges::PrintRangeMap(DM, HRI));
22900b57cec5SDimitry Andric 
22910b57cec5SDimitry Andric     for (auto FI : BlockFIMap[&B]) {
22920b57cec5SDimitry Andric       if (BadFIs.count(FI))
22930b57cec5SDimitry Andric         continue;
22940b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Working on fi#" << FI << '\n');
22950b57cec5SDimitry Andric       HexagonBlockRanges::RangeList &RL = FIRangeMap[FI].Map[&B];
22960b57cec5SDimitry Andric       for (auto &Range : RL) {
22970b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "--Examining range:" << RL << '\n');
22980b57cec5SDimitry Andric         if (!IndexType::isInstr(Range.start()) ||
22990b57cec5SDimitry Andric             !IndexType::isInstr(Range.end()))
23000b57cec5SDimitry Andric           continue;
23010b57cec5SDimitry Andric         MachineInstr &SI = *IM.getInstr(Range.start());
23020b57cec5SDimitry Andric         MachineInstr &EI = *IM.getInstr(Range.end());
23030b57cec5SDimitry Andric         assert(SI.mayStore() && "Unexpected start instruction");
23040b57cec5SDimitry Andric         assert(EI.mayLoad() && "Unexpected end instruction");
23050b57cec5SDimitry Andric         MachineOperand &SrcOp = SI.getOperand(2);
23060b57cec5SDimitry Andric 
23070b57cec5SDimitry Andric         HexagonBlockRanges::RegisterRef SrcRR = { SrcOp.getReg(),
23080b57cec5SDimitry Andric                                                   SrcOp.getSubReg() };
23090b57cec5SDimitry Andric         auto *RC = HII.getRegClass(SI.getDesc(), 2, &HRI, MF);
23100b57cec5SDimitry Andric         // The this-> is needed to unconfuse MSVC.
23110b57cec5SDimitry Andric         unsigned FoundR = this->findPhysReg(MF, Range, IM, DM, RC);
23120b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "Replacement reg:" << printReg(FoundR, &HRI)
23130b57cec5SDimitry Andric                           << '\n');
23140b57cec5SDimitry Andric         if (FoundR == 0)
23150b57cec5SDimitry Andric           continue;
23160b57cec5SDimitry Andric #ifndef NDEBUG
23170b57cec5SDimitry Andric         if (HasOptLimit) {
23180b57cec5SDimitry Andric           if (SpillOptCount >= SpillOptMax)
23190b57cec5SDimitry Andric             return;
23200b57cec5SDimitry Andric           SpillOptCount++;
23210b57cec5SDimitry Andric         }
23220b57cec5SDimitry Andric #endif
23230b57cec5SDimitry Andric 
23240b57cec5SDimitry Andric         // Generate the copy-in: "FoundR = COPY SrcR" at the store location.
23250b57cec5SDimitry Andric         MachineBasicBlock::iterator StartIt = SI.getIterator(), NextIt;
23260b57cec5SDimitry Andric         MachineInstr *CopyIn = nullptr;
23270b57cec5SDimitry Andric         if (SrcRR.Reg != FoundR || SrcRR.Sub != 0) {
23280b57cec5SDimitry Andric           const DebugLoc &DL = SI.getDebugLoc();
23290b57cec5SDimitry Andric           CopyIn = BuildMI(B, StartIt, DL, HII.get(TargetOpcode::COPY), FoundR)
23300b57cec5SDimitry Andric                        .add(SrcOp);
23310b57cec5SDimitry Andric         }
23320b57cec5SDimitry Andric 
23330b57cec5SDimitry Andric         ++StartIt;
23340b57cec5SDimitry Andric         // Check if this is a last store and the FI is live-on-exit.
23350b57cec5SDimitry Andric         if (LoxFIs.count(FI) && (&Range == &RL.back())) {
23360b57cec5SDimitry Andric           // Update store's source register.
23370b57cec5SDimitry Andric           if (unsigned SR = SrcOp.getSubReg())
23380b57cec5SDimitry Andric             SrcOp.setReg(HRI.getSubReg(FoundR, SR));
23390b57cec5SDimitry Andric           else
23400b57cec5SDimitry Andric             SrcOp.setReg(FoundR);
23410b57cec5SDimitry Andric           SrcOp.setSubReg(0);
23420b57cec5SDimitry Andric           // We are keeping this register live.
23430b57cec5SDimitry Andric           SrcOp.setIsKill(false);
23440b57cec5SDimitry Andric         } else {
23450b57cec5SDimitry Andric           B.erase(&SI);
23460b57cec5SDimitry Andric           IM.replaceInstr(&SI, CopyIn);
23470b57cec5SDimitry Andric         }
23480b57cec5SDimitry Andric 
23490b57cec5SDimitry Andric         auto EndIt = std::next(EI.getIterator());
23500b57cec5SDimitry Andric         for (auto It = StartIt; It != EndIt; It = NextIt) {
23510b57cec5SDimitry Andric           MachineInstr &MI = *It;
23520b57cec5SDimitry Andric           NextIt = std::next(It);
23530b57cec5SDimitry Andric           int TFI;
23540b57cec5SDimitry Andric           if (!HII.isLoadFromStackSlot(MI, TFI) || TFI != FI)
23550b57cec5SDimitry Andric             continue;
23568bcb0991SDimitry Andric           Register DstR = MI.getOperand(0).getReg();
23570b57cec5SDimitry Andric           assert(MI.getOperand(0).getSubReg() == 0);
23580b57cec5SDimitry Andric           MachineInstr *CopyOut = nullptr;
23590b57cec5SDimitry Andric           if (DstR != FoundR) {
23600b57cec5SDimitry Andric             DebugLoc DL = MI.getDebugLoc();
23610b57cec5SDimitry Andric             unsigned MemSize = HII.getMemAccessSize(MI);
23620b57cec5SDimitry Andric             assert(HII.getAddrMode(MI) == HexagonII::BaseImmOffset);
23630b57cec5SDimitry Andric             unsigned CopyOpc = TargetOpcode::COPY;
23640b57cec5SDimitry Andric             if (HII.isSignExtendingLoad(MI))
23650b57cec5SDimitry Andric               CopyOpc = (MemSize == 1) ? Hexagon::A2_sxtb : Hexagon::A2_sxth;
23660b57cec5SDimitry Andric             else if (HII.isZeroExtendingLoad(MI))
23670b57cec5SDimitry Andric               CopyOpc = (MemSize == 1) ? Hexagon::A2_zxtb : Hexagon::A2_zxth;
23680b57cec5SDimitry Andric             CopyOut = BuildMI(B, It, DL, HII.get(CopyOpc), DstR)
23690b57cec5SDimitry Andric                         .addReg(FoundR, getKillRegState(&MI == &EI));
23700b57cec5SDimitry Andric           }
23710b57cec5SDimitry Andric           IM.replaceInstr(&MI, CopyOut);
23720b57cec5SDimitry Andric           B.erase(It);
23730b57cec5SDimitry Andric         }
23740b57cec5SDimitry Andric 
23750b57cec5SDimitry Andric         // Update the dead map.
23760b57cec5SDimitry Andric         HexagonBlockRanges::RegisterRef FoundRR = { FoundR, 0 };
23770b57cec5SDimitry Andric         for (auto RR : HexagonBlockRanges::expandToSubRegs(FoundRR, MRI, HRI))
23780b57cec5SDimitry Andric           DM[RR].subtract(Range);
23790b57cec5SDimitry Andric       } // for Range in range list
23800b57cec5SDimitry Andric     }
23810b57cec5SDimitry Andric   }
23820b57cec5SDimitry Andric }
23830b57cec5SDimitry Andric 
23840b57cec5SDimitry Andric void HexagonFrameLowering::expandAlloca(MachineInstr *AI,
23850b57cec5SDimitry Andric       const HexagonInstrInfo &HII, unsigned SP, unsigned CF) const {
23860b57cec5SDimitry Andric   MachineBasicBlock &MB = *AI->getParent();
23870b57cec5SDimitry Andric   DebugLoc DL = AI->getDebugLoc();
23880b57cec5SDimitry Andric   unsigned A = AI->getOperand(2).getImm();
23890b57cec5SDimitry Andric 
23900b57cec5SDimitry Andric   // Have
23910b57cec5SDimitry Andric   //    Rd  = alloca Rs, #A
23920b57cec5SDimitry Andric   //
23930b57cec5SDimitry Andric   // If Rs and Rd are different registers, use this sequence:
23940b57cec5SDimitry Andric   //    Rd  = sub(r29, Rs)
23950b57cec5SDimitry Andric   //    r29 = sub(r29, Rs)
23960b57cec5SDimitry Andric   //    Rd  = and(Rd, #-A)    ; if necessary
23970b57cec5SDimitry Andric   //    r29 = and(r29, #-A)   ; if necessary
23980b57cec5SDimitry Andric   //    Rd  = add(Rd, #CF)    ; CF size aligned to at most A
23990b57cec5SDimitry Andric   // otherwise, do
24000b57cec5SDimitry Andric   //    Rd  = sub(r29, Rs)
24010b57cec5SDimitry Andric   //    Rd  = and(Rd, #-A)    ; if necessary
24020b57cec5SDimitry Andric   //    r29 = Rd
24030b57cec5SDimitry Andric   //    Rd  = add(Rd, #CF)    ; CF size aligned to at most A
24040b57cec5SDimitry Andric 
24050b57cec5SDimitry Andric   MachineOperand &RdOp = AI->getOperand(0);
24060b57cec5SDimitry Andric   MachineOperand &RsOp = AI->getOperand(1);
24070b57cec5SDimitry Andric   unsigned Rd = RdOp.getReg(), Rs = RsOp.getReg();
24080b57cec5SDimitry Andric 
24090b57cec5SDimitry Andric   // Rd = sub(r29, Rs)
24100b57cec5SDimitry Andric   BuildMI(MB, AI, DL, HII.get(Hexagon::A2_sub), Rd)
24110b57cec5SDimitry Andric       .addReg(SP)
24120b57cec5SDimitry Andric       .addReg(Rs);
24130b57cec5SDimitry Andric   if (Rs != Rd) {
24140b57cec5SDimitry Andric     // r29 = sub(r29, Rs)
24150b57cec5SDimitry Andric     BuildMI(MB, AI, DL, HII.get(Hexagon::A2_sub), SP)
24160b57cec5SDimitry Andric         .addReg(SP)
24170b57cec5SDimitry Andric         .addReg(Rs);
24180b57cec5SDimitry Andric   }
24190b57cec5SDimitry Andric   if (A > 8) {
24200b57cec5SDimitry Andric     // Rd  = and(Rd, #-A)
24210b57cec5SDimitry Andric     BuildMI(MB, AI, DL, HII.get(Hexagon::A2_andir), Rd)
24220b57cec5SDimitry Andric         .addReg(Rd)
24230b57cec5SDimitry Andric         .addImm(-int64_t(A));
24240b57cec5SDimitry Andric     if (Rs != Rd)
24250b57cec5SDimitry Andric       BuildMI(MB, AI, DL, HII.get(Hexagon::A2_andir), SP)
24260b57cec5SDimitry Andric           .addReg(SP)
24270b57cec5SDimitry Andric           .addImm(-int64_t(A));
24280b57cec5SDimitry Andric   }
24290b57cec5SDimitry Andric   if (Rs == Rd) {
24300b57cec5SDimitry Andric     // r29 = Rd
24310b57cec5SDimitry Andric     BuildMI(MB, AI, DL, HII.get(TargetOpcode::COPY), SP)
24320b57cec5SDimitry Andric         .addReg(Rd);
24330b57cec5SDimitry Andric   }
24340b57cec5SDimitry Andric   if (CF > 0) {
24350b57cec5SDimitry Andric     // Rd = add(Rd, #CF)
24360b57cec5SDimitry Andric     BuildMI(MB, AI, DL, HII.get(Hexagon::A2_addi), Rd)
24370b57cec5SDimitry Andric         .addReg(Rd)
24380b57cec5SDimitry Andric         .addImm(CF);
24390b57cec5SDimitry Andric   }
24400b57cec5SDimitry Andric }
24410b57cec5SDimitry Andric 
24420b57cec5SDimitry Andric bool HexagonFrameLowering::needsAligna(const MachineFunction &MF) const {
24430b57cec5SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
24440b57cec5SDimitry Andric   if (!MFI.hasVarSizedObjects())
24450b57cec5SDimitry Andric     return false;
2446*480093f4SDimitry Andric   // Do not check for max stack object alignment here, because the stack
2447*480093f4SDimitry Andric   // may not be complete yet. Assume that we will need PS_aligna if there
2448*480093f4SDimitry Andric   // are variable-sized objects.
24490b57cec5SDimitry Andric   return true;
24500b57cec5SDimitry Andric }
24510b57cec5SDimitry Andric 
24520b57cec5SDimitry Andric const MachineInstr *HexagonFrameLowering::getAlignaInstr(
24530b57cec5SDimitry Andric       const MachineFunction &MF) const {
24540b57cec5SDimitry Andric   for (auto &B : MF)
24550b57cec5SDimitry Andric     for (auto &I : B)
24560b57cec5SDimitry Andric       if (I.getOpcode() == Hexagon::PS_aligna)
24570b57cec5SDimitry Andric         return &I;
24580b57cec5SDimitry Andric   return nullptr;
24590b57cec5SDimitry Andric }
24600b57cec5SDimitry Andric 
24610b57cec5SDimitry Andric /// Adds all callee-saved registers as implicit uses or defs to the
24620b57cec5SDimitry Andric /// instruction.
24630b57cec5SDimitry Andric void HexagonFrameLowering::addCalleeSaveRegistersAsImpOperand(MachineInstr *MI,
24640b57cec5SDimitry Andric       const CSIVect &CSI, bool IsDef, bool IsKill) const {
24650b57cec5SDimitry Andric   // Add the callee-saved registers as implicit uses.
24660b57cec5SDimitry Andric   for (auto &R : CSI)
24670b57cec5SDimitry Andric     MI->addOperand(MachineOperand::CreateReg(R.getReg(), IsDef, true, IsKill));
24680b57cec5SDimitry Andric }
24690b57cec5SDimitry Andric 
24700b57cec5SDimitry Andric /// Determine whether the callee-saved register saves and restores should
24710b57cec5SDimitry Andric /// be generated via inline code. If this function returns "true", inline
24720b57cec5SDimitry Andric /// code will be generated. If this function returns "false", additional
24730b57cec5SDimitry Andric /// checks are performed, which may still lead to the inline code.
24740b57cec5SDimitry Andric bool HexagonFrameLowering::shouldInlineCSR(const MachineFunction &MF,
24750b57cec5SDimitry Andric       const CSIVect &CSI) const {
24760b57cec5SDimitry Andric   if (MF.getInfo<HexagonMachineFunctionInfo>()->hasEHReturn())
24770b57cec5SDimitry Andric     return true;
24780b57cec5SDimitry Andric   if (!hasFP(MF))
24790b57cec5SDimitry Andric     return true;
24800b57cec5SDimitry Andric   if (!isOptSize(MF) && !isMinSize(MF))
24810b57cec5SDimitry Andric     if (MF.getTarget().getOptLevel() > CodeGenOpt::Default)
24820b57cec5SDimitry Andric       return true;
24830b57cec5SDimitry Andric 
24840b57cec5SDimitry Andric   // Check if CSI only has double registers, and if the registers form
24850b57cec5SDimitry Andric   // a contiguous block starting from D8.
24860b57cec5SDimitry Andric   BitVector Regs(Hexagon::NUM_TARGET_REGS);
24870b57cec5SDimitry Andric   for (unsigned i = 0, n = CSI.size(); i < n; ++i) {
24880b57cec5SDimitry Andric     unsigned R = CSI[i].getReg();
24890b57cec5SDimitry Andric     if (!Hexagon::DoubleRegsRegClass.contains(R))
24900b57cec5SDimitry Andric       return true;
24910b57cec5SDimitry Andric     Regs[R] = true;
24920b57cec5SDimitry Andric   }
24930b57cec5SDimitry Andric   int F = Regs.find_first();
24940b57cec5SDimitry Andric   if (F != Hexagon::D8)
24950b57cec5SDimitry Andric     return true;
24960b57cec5SDimitry Andric   while (F >= 0) {
24970b57cec5SDimitry Andric     int N = Regs.find_next(F);
24980b57cec5SDimitry Andric     if (N >= 0 && N != F+1)
24990b57cec5SDimitry Andric       return true;
25000b57cec5SDimitry Andric     F = N;
25010b57cec5SDimitry Andric   }
25020b57cec5SDimitry Andric 
25030b57cec5SDimitry Andric   return false;
25040b57cec5SDimitry Andric }
25050b57cec5SDimitry Andric 
25060b57cec5SDimitry Andric bool HexagonFrameLowering::useSpillFunction(const MachineFunction &MF,
25070b57cec5SDimitry Andric       const CSIVect &CSI) const {
25080b57cec5SDimitry Andric   if (shouldInlineCSR(MF, CSI))
25090b57cec5SDimitry Andric     return false;
25100b57cec5SDimitry Andric   unsigned NumCSI = CSI.size();
25110b57cec5SDimitry Andric   if (NumCSI <= 1)
25120b57cec5SDimitry Andric     return false;
25130b57cec5SDimitry Andric 
25140b57cec5SDimitry Andric   unsigned Threshold = isOptSize(MF) ? SpillFuncThresholdOs
25150b57cec5SDimitry Andric                                      : SpillFuncThreshold;
25160b57cec5SDimitry Andric   return Threshold < NumCSI;
25170b57cec5SDimitry Andric }
25180b57cec5SDimitry Andric 
25190b57cec5SDimitry Andric bool HexagonFrameLowering::useRestoreFunction(const MachineFunction &MF,
25200b57cec5SDimitry Andric       const CSIVect &CSI) const {
25210b57cec5SDimitry Andric   if (shouldInlineCSR(MF, CSI))
25220b57cec5SDimitry Andric     return false;
25230b57cec5SDimitry Andric   // The restore functions do a bit more than just restoring registers.
25240b57cec5SDimitry Andric   // The non-returning versions will go back directly to the caller's
25250b57cec5SDimitry Andric   // caller, others will clean up the stack frame in preparation for
25260b57cec5SDimitry Andric   // a tail call. Using them can still save code size even if only one
25270b57cec5SDimitry Andric   // register is getting restores. Make the decision based on -Oz:
25280b57cec5SDimitry Andric   // using -Os will use inline restore for a single register.
25290b57cec5SDimitry Andric   if (isMinSize(MF))
25300b57cec5SDimitry Andric     return true;
25310b57cec5SDimitry Andric   unsigned NumCSI = CSI.size();
25320b57cec5SDimitry Andric   if (NumCSI <= 1)
25330b57cec5SDimitry Andric     return false;
25340b57cec5SDimitry Andric 
25350b57cec5SDimitry Andric   unsigned Threshold = isOptSize(MF) ? SpillFuncThresholdOs-1
25360b57cec5SDimitry Andric                                      : SpillFuncThreshold;
25370b57cec5SDimitry Andric   return Threshold < NumCSI;
25380b57cec5SDimitry Andric }
25390b57cec5SDimitry Andric 
25400b57cec5SDimitry Andric bool HexagonFrameLowering::mayOverflowFrameOffset(MachineFunction &MF) const {
25410b57cec5SDimitry Andric   unsigned StackSize = MF.getFrameInfo().estimateStackSize(MF);
25420b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
25430b57cec5SDimitry Andric   // A fairly simplistic guess as to whether a potential load/store to a
25440b57cec5SDimitry Andric   // stack location could require an extra register.
25450b57cec5SDimitry Andric   if (HST.useHVXOps() && StackSize > 256)
25460b57cec5SDimitry Andric     return true;
25470b57cec5SDimitry Andric 
25480b57cec5SDimitry Andric   // Check if the function has store-immediate instructions that access
25490b57cec5SDimitry Andric   // the stack. Since the offset field is not extendable, if the stack
25500b57cec5SDimitry Andric   // size exceeds the offset limit (6 bits, shifted), the stores will
25510b57cec5SDimitry Andric   // require a new base register.
25520b57cec5SDimitry Andric   bool HasImmStack = false;
25530b57cec5SDimitry Andric   unsigned MinLS = ~0u;   // Log_2 of the memory access size.
25540b57cec5SDimitry Andric 
25550b57cec5SDimitry Andric   for (const MachineBasicBlock &B : MF) {
25560b57cec5SDimitry Andric     for (const MachineInstr &MI : B) {
25570b57cec5SDimitry Andric       unsigned LS = 0;
25580b57cec5SDimitry Andric       switch (MI.getOpcode()) {
25590b57cec5SDimitry Andric         case Hexagon::S4_storeirit_io:
25600b57cec5SDimitry Andric         case Hexagon::S4_storeirif_io:
25610b57cec5SDimitry Andric         case Hexagon::S4_storeiri_io:
25620b57cec5SDimitry Andric           ++LS;
25630b57cec5SDimitry Andric           LLVM_FALLTHROUGH;
25640b57cec5SDimitry Andric         case Hexagon::S4_storeirht_io:
25650b57cec5SDimitry Andric         case Hexagon::S4_storeirhf_io:
25660b57cec5SDimitry Andric         case Hexagon::S4_storeirh_io:
25670b57cec5SDimitry Andric           ++LS;
25680b57cec5SDimitry Andric           LLVM_FALLTHROUGH;
25690b57cec5SDimitry Andric         case Hexagon::S4_storeirbt_io:
25700b57cec5SDimitry Andric         case Hexagon::S4_storeirbf_io:
25710b57cec5SDimitry Andric         case Hexagon::S4_storeirb_io:
25720b57cec5SDimitry Andric           if (MI.getOperand(0).isFI())
25730b57cec5SDimitry Andric             HasImmStack = true;
25740b57cec5SDimitry Andric           MinLS = std::min(MinLS, LS);
25750b57cec5SDimitry Andric           break;
25760b57cec5SDimitry Andric       }
25770b57cec5SDimitry Andric     }
25780b57cec5SDimitry Andric   }
25790b57cec5SDimitry Andric 
25800b57cec5SDimitry Andric   if (HasImmStack)
25810b57cec5SDimitry Andric     return !isUInt<6>(StackSize >> MinLS);
25820b57cec5SDimitry Andric 
25830b57cec5SDimitry Andric   return false;
25840b57cec5SDimitry Andric }
2585