xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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"
39480093f4SDimitry 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();
227480093f4SDimitry 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.
2645ffd83dbSDimitry Andric static unsigned getMaxCalleeSavedReg(ArrayRef<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.
309e8d8bef9SDimitry Andric           if (R.isVirtual())
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 
3985ffd83dbSDimitry Andric   if (MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl() &&
3995ffd83dbSDimitry Andric       MF.getFunction().isVarArg())
4005ffd83dbSDimitry Andric     return;
4010b57cec5SDimitry Andric   if (ShrinkLimit.getPosition()) {
4020b57cec5SDimitry Andric     if (ShrinkCounter >= ShrinkLimit)
4030b57cec5SDimitry Andric       return;
4040b57cec5SDimitry Andric     ShrinkCounter++;
4050b57cec5SDimitry Andric   }
4060b57cec5SDimitry Andric 
4070b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric   MachineDominatorTree MDT;
4100b57cec5SDimitry Andric   MDT.runOnMachineFunction(MF);
4110b57cec5SDimitry Andric   MachinePostDominatorTree MPT;
4120b57cec5SDimitry Andric   MPT.runOnMachineFunction(MF);
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric   using UnsignedMap = DenseMap<unsigned, unsigned>;
4150b57cec5SDimitry Andric   using RPOTType = ReversePostOrderTraversal<const MachineFunction *>;
4160b57cec5SDimitry Andric 
4170b57cec5SDimitry Andric   UnsignedMap RPO;
4180b57cec5SDimitry Andric   RPOTType RPOT(&MF);
4190b57cec5SDimitry Andric   unsigned RPON = 0;
4200b57cec5SDimitry Andric   for (RPOTType::rpo_iterator I = RPOT.begin(), E = RPOT.end(); I != E; ++I)
4210b57cec5SDimitry Andric     RPO[(*I)->getNumber()] = RPON++;
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric   // Don't process functions that have loops, at least for now. Placement
4240b57cec5SDimitry Andric   // of prolog and epilog must take loop structure into account. For simpli-
4250b57cec5SDimitry Andric   // city don't do it right now.
4260b57cec5SDimitry Andric   for (auto &I : MF) {
4270b57cec5SDimitry Andric     unsigned BN = RPO[I.getNumber()];
4280b57cec5SDimitry Andric     for (auto SI = I.succ_begin(), SE = I.succ_end(); SI != SE; ++SI) {
4290b57cec5SDimitry Andric       // If found a back-edge, return.
4300b57cec5SDimitry Andric       if (RPO[(*SI)->getNumber()] <= BN)
4310b57cec5SDimitry Andric         return;
4320b57cec5SDimitry Andric     }
4330b57cec5SDimitry Andric   }
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric   // Collect the set of blocks that need a stack frame to execute. Scan
4360b57cec5SDimitry Andric   // each block for uses/defs of callee-saved registers, calls, etc.
4370b57cec5SDimitry Andric   SmallVector<MachineBasicBlock*,16> SFBlocks;
4380b57cec5SDimitry Andric   BitVector CSR(Hexagon::NUM_TARGET_REGS);
4390b57cec5SDimitry Andric   for (const MCPhysReg *P = HRI.getCalleeSavedRegs(&MF); *P; ++P)
4400b57cec5SDimitry Andric     for (MCSubRegIterator S(*P, &HRI, true); S.isValid(); ++S)
4410b57cec5SDimitry Andric       CSR[*S] = true;
4420b57cec5SDimitry Andric 
4430b57cec5SDimitry Andric   for (auto &I : MF)
4440b57cec5SDimitry Andric     if (needsStackFrame(I, CSR, HRI))
4450b57cec5SDimitry Andric       SFBlocks.push_back(&I);
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric   LLVM_DEBUG({
4480b57cec5SDimitry Andric     dbgs() << "Blocks needing SF: {";
4490b57cec5SDimitry Andric     for (auto &B : SFBlocks)
4500b57cec5SDimitry Andric       dbgs() << " " << printMBBReference(*B);
4510b57cec5SDimitry Andric     dbgs() << " }\n";
4520b57cec5SDimitry Andric   });
4530b57cec5SDimitry Andric   // No frame needed?
4540b57cec5SDimitry Andric   if (SFBlocks.empty())
4550b57cec5SDimitry Andric     return;
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric   // Pick a common dominator and a common post-dominator.
4580b57cec5SDimitry Andric   MachineBasicBlock *DomB = SFBlocks[0];
4590b57cec5SDimitry Andric   for (unsigned i = 1, n = SFBlocks.size(); i < n; ++i) {
4600b57cec5SDimitry Andric     DomB = MDT.findNearestCommonDominator(DomB, SFBlocks[i]);
4610b57cec5SDimitry Andric     if (!DomB)
4620b57cec5SDimitry Andric       break;
4630b57cec5SDimitry Andric   }
4640b57cec5SDimitry Andric   MachineBasicBlock *PDomB = SFBlocks[0];
4650b57cec5SDimitry Andric   for (unsigned i = 1, n = SFBlocks.size(); i < n; ++i) {
4660b57cec5SDimitry Andric     PDomB = MPT.findNearestCommonDominator(PDomB, SFBlocks[i]);
4670b57cec5SDimitry Andric     if (!PDomB)
4680b57cec5SDimitry Andric       break;
4690b57cec5SDimitry Andric   }
4700b57cec5SDimitry Andric   LLVM_DEBUG({
4710b57cec5SDimitry Andric     dbgs() << "Computed dom block: ";
4720b57cec5SDimitry Andric     if (DomB)
4730b57cec5SDimitry Andric       dbgs() << printMBBReference(*DomB);
4740b57cec5SDimitry Andric     else
4750b57cec5SDimitry Andric       dbgs() << "<null>";
4760b57cec5SDimitry Andric     dbgs() << ", computed pdom block: ";
4770b57cec5SDimitry Andric     if (PDomB)
4780b57cec5SDimitry Andric       dbgs() << printMBBReference(*PDomB);
4790b57cec5SDimitry Andric     else
4800b57cec5SDimitry Andric       dbgs() << "<null>";
4810b57cec5SDimitry Andric     dbgs() << "\n";
4820b57cec5SDimitry Andric   });
4830b57cec5SDimitry Andric   if (!DomB || !PDomB)
4840b57cec5SDimitry Andric     return;
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric   // Make sure that DomB dominates PDomB and PDomB post-dominates DomB.
4870b57cec5SDimitry Andric   if (!MDT.dominates(DomB, PDomB)) {
4880b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Dom block does not dominate pdom block\n");
4890b57cec5SDimitry Andric     return;
4900b57cec5SDimitry Andric   }
4910b57cec5SDimitry Andric   if (!MPT.dominates(PDomB, DomB)) {
4920b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "PDom block does not post-dominate dom block\n");
4930b57cec5SDimitry Andric     return;
4940b57cec5SDimitry Andric   }
4950b57cec5SDimitry Andric 
4960b57cec5SDimitry Andric   // Finally, everything seems right.
4970b57cec5SDimitry Andric   PrologB = DomB;
4980b57cec5SDimitry Andric   EpilogB = PDomB;
4990b57cec5SDimitry Andric }
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric /// Perform most of the PEI work here:
5020b57cec5SDimitry Andric /// - saving/restoring of the callee-saved registers,
5030b57cec5SDimitry Andric /// - stack frame creation and destruction.
5040b57cec5SDimitry Andric /// Normally, this work is distributed among various functions, but doing it
5050b57cec5SDimitry Andric /// in one place allows shrink-wrapping of the stack frame.
5060b57cec5SDimitry Andric void HexagonFrameLowering::emitPrologue(MachineFunction &MF,
5070b57cec5SDimitry Andric                                         MachineBasicBlock &MBB) const {
5080b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
5110b57cec5SDimitry Andric   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
5120b57cec5SDimitry Andric 
5130b57cec5SDimitry Andric   MachineBasicBlock *PrologB = &MF.front(), *EpilogB = nullptr;
5140b57cec5SDimitry Andric   if (EnableShrinkWrapping)
5150b57cec5SDimitry Andric     findShrunkPrologEpilog(MF, PrologB, EpilogB);
5160b57cec5SDimitry Andric 
5170b57cec5SDimitry Andric   bool PrologueStubs = false;
5180b57cec5SDimitry Andric   insertCSRSpillsInBlock(*PrologB, CSI, HRI, PrologueStubs);
5190b57cec5SDimitry Andric   insertPrologueInBlock(*PrologB, PrologueStubs);
5200b57cec5SDimitry Andric   updateEntryPaths(MF, *PrologB);
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric   if (EpilogB) {
5230b57cec5SDimitry Andric     insertCSRRestoresInBlock(*EpilogB, CSI, HRI);
5240b57cec5SDimitry Andric     insertEpilogueInBlock(*EpilogB);
5250b57cec5SDimitry Andric   } else {
5260b57cec5SDimitry Andric     for (auto &B : MF)
5270b57cec5SDimitry Andric       if (B.isReturnBlock())
5280b57cec5SDimitry Andric         insertCSRRestoresInBlock(B, CSI, HRI);
5290b57cec5SDimitry Andric 
5300b57cec5SDimitry Andric     for (auto &B : MF)
5310b57cec5SDimitry Andric       if (B.isReturnBlock())
5320b57cec5SDimitry Andric         insertEpilogueInBlock(B);
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric     for (auto &B : MF) {
5350b57cec5SDimitry Andric       if (B.empty())
5360b57cec5SDimitry Andric         continue;
5370b57cec5SDimitry Andric       MachineInstr *RetI = getReturn(B);
5380b57cec5SDimitry Andric       if (!RetI || isRestoreCall(RetI->getOpcode()))
5390b57cec5SDimitry Andric         continue;
5400b57cec5SDimitry Andric       for (auto &R : CSI)
5410b57cec5SDimitry Andric         RetI->addOperand(MachineOperand::CreateReg(R.getReg(), false, true));
5420b57cec5SDimitry Andric     }
5430b57cec5SDimitry Andric   }
5440b57cec5SDimitry Andric 
5450b57cec5SDimitry Andric   if (EpilogB) {
5460b57cec5SDimitry Andric     // If there is an epilog block, it may not have a return instruction.
5470b57cec5SDimitry Andric     // In such case, we need to add the callee-saved registers as live-ins
5480b57cec5SDimitry Andric     // in all blocks on all paths from the epilog to any return block.
5490b57cec5SDimitry Andric     unsigned MaxBN = MF.getNumBlockIDs();
5500b57cec5SDimitry Andric     BitVector DoneT(MaxBN+1), DoneF(MaxBN+1), Path(MaxBN+1);
5510b57cec5SDimitry Andric     updateExitPaths(*EpilogB, *EpilogB, DoneT, DoneF, Path);
5520b57cec5SDimitry Andric   }
5530b57cec5SDimitry Andric }
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric /// Returns true if the target can safely skip saving callee-saved registers
5560b57cec5SDimitry Andric /// for noreturn nounwind functions.
5570b57cec5SDimitry Andric bool HexagonFrameLowering::enableCalleeSaveSkip(
5580b57cec5SDimitry Andric     const MachineFunction &MF) const {
5590b57cec5SDimitry Andric   const auto &F = MF.getFunction();
5600b57cec5SDimitry Andric   assert(F.hasFnAttribute(Attribute::NoReturn) &&
5610b57cec5SDimitry Andric          F.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
5620b57cec5SDimitry Andric          !F.getFunction().hasFnAttribute(Attribute::UWTable));
5630b57cec5SDimitry Andric   (void)F;
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric   // No need to save callee saved registers if the function does not return.
5660b57cec5SDimitry Andric   return MF.getSubtarget<HexagonSubtarget>().noreturnStackElim();
5670b57cec5SDimitry Andric }
5680b57cec5SDimitry Andric 
5690b57cec5SDimitry Andric // Helper function used to determine when to eliminate the stack frame for
5700b57cec5SDimitry Andric // functions marked as noreturn and when the noreturn-stack-elim options are
5710b57cec5SDimitry Andric // specified. When both these conditions are true, then a FP may not be needed
5720b57cec5SDimitry Andric // if the function makes a call. It is very similar to enableCalleeSaveSkip,
5730b57cec5SDimitry Andric // but it used to check if the allocframe can be eliminated as well.
5740b57cec5SDimitry Andric static bool enableAllocFrameElim(const MachineFunction &MF) {
5750b57cec5SDimitry Andric   const auto &F = MF.getFunction();
5760b57cec5SDimitry Andric   const auto &MFI = MF.getFrameInfo();
5770b57cec5SDimitry Andric   const auto &HST = MF.getSubtarget<HexagonSubtarget>();
5780b57cec5SDimitry Andric   assert(!MFI.hasVarSizedObjects() &&
579*fe6060f1SDimitry Andric          !HST.getRegisterInfo()->hasStackRealignment(MF));
5800b57cec5SDimitry Andric   return F.hasFnAttribute(Attribute::NoReturn) &&
5810b57cec5SDimitry Andric     F.hasFnAttribute(Attribute::NoUnwind) &&
5820b57cec5SDimitry Andric     !F.hasFnAttribute(Attribute::UWTable) && HST.noreturnStackElim() &&
5830b57cec5SDimitry Andric     MFI.getStackSize() == 0;
5840b57cec5SDimitry Andric }
5850b57cec5SDimitry Andric 
5860b57cec5SDimitry Andric void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB,
5870b57cec5SDimitry Andric       bool PrologueStubs) const {
5880b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
5890b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
5900b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
5910b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
5920b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
5930b57cec5SDimitry Andric 
5945ffd83dbSDimitry Andric   Align MaxAlign = std::max(MFI.getMaxAlign(), getStackAlign());
5950b57cec5SDimitry Andric 
5960b57cec5SDimitry Andric   // Calculate the total stack frame size.
5970b57cec5SDimitry Andric   // Get the number of bytes to allocate from the FrameInfo.
5980b57cec5SDimitry Andric   unsigned FrameSize = MFI.getStackSize();
5990b57cec5SDimitry Andric   // Round up the max call frame size to the max alignment on the stack.
6000b57cec5SDimitry Andric   unsigned MaxCFA = alignTo(MFI.getMaxCallFrameSize(), MaxAlign);
6010b57cec5SDimitry Andric   MFI.setMaxCallFrameSize(MaxCFA);
6020b57cec5SDimitry Andric 
6030b57cec5SDimitry Andric   FrameSize = MaxCFA + alignTo(FrameSize, MaxAlign);
6040b57cec5SDimitry Andric   MFI.setStackSize(FrameSize);
6050b57cec5SDimitry Andric 
6065ffd83dbSDimitry Andric   bool AlignStack = (MaxAlign > getStackAlign());
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric   // Get the number of bytes to allocate from the FrameInfo.
6090b57cec5SDimitry Andric   unsigned NumBytes = MFI.getStackSize();
6100b57cec5SDimitry Andric   unsigned SP = HRI.getStackRegister();
6110b57cec5SDimitry Andric   unsigned MaxCF = MFI.getMaxCallFrameSize();
6120b57cec5SDimitry Andric   MachineBasicBlock::iterator InsertPt = MBB.begin();
6130b57cec5SDimitry Andric 
6140b57cec5SDimitry Andric   SmallVector<MachineInstr *, 4> AdjustRegs;
6150b57cec5SDimitry Andric   for (auto &MBB : MF)
6160b57cec5SDimitry Andric     for (auto &MI : MBB)
6170b57cec5SDimitry Andric       if (MI.getOpcode() == Hexagon::PS_alloca)
6180b57cec5SDimitry Andric         AdjustRegs.push_back(&MI);
6190b57cec5SDimitry Andric 
6200b57cec5SDimitry Andric   for (auto MI : AdjustRegs) {
6210b57cec5SDimitry Andric     assert((MI->getOpcode() == Hexagon::PS_alloca) && "Expected alloca");
6220b57cec5SDimitry Andric     expandAlloca(MI, HII, SP, MaxCF);
6230b57cec5SDimitry Andric     MI->eraseFromParent();
6240b57cec5SDimitry Andric   }
6250b57cec5SDimitry Andric 
6260b57cec5SDimitry Andric   DebugLoc dl = MBB.findDebugLoc(InsertPt);
6270b57cec5SDimitry Andric 
6285ffd83dbSDimitry Andric   if (MF.getFunction().isVarArg() &&
6295ffd83dbSDimitry Andric       MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl()) {
6305ffd83dbSDimitry Andric     // Calculate the size of register saved area.
6315ffd83dbSDimitry Andric     int NumVarArgRegs = 6 - FirstVarArgSavedReg;
6325ffd83dbSDimitry Andric     int RegisterSavedAreaSizePlusPadding = (NumVarArgRegs % 2 == 0)
6335ffd83dbSDimitry Andric                                               ? NumVarArgRegs * 4
6345ffd83dbSDimitry Andric                                               : NumVarArgRegs * 4 + 4;
6355ffd83dbSDimitry Andric     if (RegisterSavedAreaSizePlusPadding > 0) {
6365ffd83dbSDimitry Andric       // Decrement the stack pointer by size of register saved area plus
6375ffd83dbSDimitry Andric       // padding if any.
6385ffd83dbSDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP)
6395ffd83dbSDimitry Andric         .addReg(SP)
6405ffd83dbSDimitry Andric         .addImm(-RegisterSavedAreaSizePlusPadding)
6415ffd83dbSDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
6425ffd83dbSDimitry Andric 
6435ffd83dbSDimitry Andric       int NumBytes = 0;
6445ffd83dbSDimitry Andric       // Copy all the named arguments below register saved area.
6455ffd83dbSDimitry Andric       auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
6465ffd83dbSDimitry Andric       for (int i = HMFI.getFirstNamedArgFrameIndex(),
6475ffd83dbSDimitry Andric                e = HMFI.getLastNamedArgFrameIndex(); i >= e; --i) {
6485ffd83dbSDimitry Andric         uint64_t ObjSize = MFI.getObjectSize(i);
6495ffd83dbSDimitry Andric         Align ObjAlign = MFI.getObjectAlign(i);
6505ffd83dbSDimitry Andric 
6515ffd83dbSDimitry Andric         // Determine the kind of load/store that should be used.
6525ffd83dbSDimitry Andric         unsigned LDOpc, STOpc;
6535ffd83dbSDimitry Andric         uint64_t OpcodeChecker = ObjAlign.value();
6545ffd83dbSDimitry Andric 
6555ffd83dbSDimitry Andric         // Handle cases where alignment of an object is > its size.
6565ffd83dbSDimitry Andric         if (ObjAlign > ObjSize) {
6575ffd83dbSDimitry Andric           if (ObjSize <= 1)
6585ffd83dbSDimitry Andric             OpcodeChecker = 1;
6595ffd83dbSDimitry Andric           else if (ObjSize <= 2)
6605ffd83dbSDimitry Andric             OpcodeChecker = 2;
6615ffd83dbSDimitry Andric           else if (ObjSize <= 4)
6625ffd83dbSDimitry Andric             OpcodeChecker = 4;
6635ffd83dbSDimitry Andric           else if (ObjSize > 4)
6645ffd83dbSDimitry Andric             OpcodeChecker = 8;
6655ffd83dbSDimitry Andric         }
6665ffd83dbSDimitry Andric 
6675ffd83dbSDimitry Andric         switch (OpcodeChecker) {
6685ffd83dbSDimitry Andric           case 1:
6695ffd83dbSDimitry Andric             LDOpc = Hexagon::L2_loadrb_io;
6705ffd83dbSDimitry Andric             STOpc = Hexagon::S2_storerb_io;
6715ffd83dbSDimitry Andric             break;
6725ffd83dbSDimitry Andric           case 2:
6735ffd83dbSDimitry Andric             LDOpc = Hexagon::L2_loadrh_io;
6745ffd83dbSDimitry Andric             STOpc = Hexagon::S2_storerh_io;
6755ffd83dbSDimitry Andric             break;
6765ffd83dbSDimitry Andric           case 4:
6775ffd83dbSDimitry Andric             LDOpc = Hexagon::L2_loadri_io;
6785ffd83dbSDimitry Andric             STOpc = Hexagon::S2_storeri_io;
6795ffd83dbSDimitry Andric             break;
6805ffd83dbSDimitry Andric           case 8:
6815ffd83dbSDimitry Andric           default:
6825ffd83dbSDimitry Andric             LDOpc = Hexagon::L2_loadrd_io;
6835ffd83dbSDimitry Andric             STOpc = Hexagon::S2_storerd_io;
6845ffd83dbSDimitry Andric             break;
6855ffd83dbSDimitry Andric         }
6865ffd83dbSDimitry Andric 
6875ffd83dbSDimitry Andric         unsigned RegUsed = LDOpc == Hexagon::L2_loadrd_io ? Hexagon::D3
6885ffd83dbSDimitry Andric                                                           : Hexagon::R6;
6895ffd83dbSDimitry Andric         int LoadStoreCount = ObjSize / OpcodeChecker;
6905ffd83dbSDimitry Andric 
6915ffd83dbSDimitry Andric         if (ObjSize % OpcodeChecker)
6925ffd83dbSDimitry Andric           ++LoadStoreCount;
6935ffd83dbSDimitry Andric 
6945ffd83dbSDimitry Andric         // Get the start location of the load. NumBytes is basically the
6955ffd83dbSDimitry Andric         // offset from the stack pointer of previous function, which would be
6965ffd83dbSDimitry Andric         // the caller in this case, as this function has variable argument
6975ffd83dbSDimitry Andric         // list.
6985ffd83dbSDimitry Andric         if (NumBytes != 0)
6995ffd83dbSDimitry Andric           NumBytes = alignTo(NumBytes, ObjAlign);
7005ffd83dbSDimitry Andric 
7015ffd83dbSDimitry Andric         int Count = 0;
7025ffd83dbSDimitry Andric         while (Count < LoadStoreCount) {
7035ffd83dbSDimitry Andric           // Load the value of the named argument on stack.
7045ffd83dbSDimitry Andric           BuildMI(MBB, InsertPt, dl, HII.get(LDOpc), RegUsed)
7055ffd83dbSDimitry Andric               .addReg(SP)
7065ffd83dbSDimitry Andric               .addImm(RegisterSavedAreaSizePlusPadding +
7075ffd83dbSDimitry Andric                       ObjAlign.value() * Count + NumBytes)
7085ffd83dbSDimitry Andric               .setMIFlag(MachineInstr::FrameSetup);
7095ffd83dbSDimitry Andric 
7105ffd83dbSDimitry Andric           // Store it below the register saved area plus padding.
7115ffd83dbSDimitry Andric           BuildMI(MBB, InsertPt, dl, HII.get(STOpc))
7125ffd83dbSDimitry Andric               .addReg(SP)
7135ffd83dbSDimitry Andric               .addImm(ObjAlign.value() * Count + NumBytes)
7145ffd83dbSDimitry Andric               .addReg(RegUsed)
7155ffd83dbSDimitry Andric               .setMIFlag(MachineInstr::FrameSetup);
7165ffd83dbSDimitry Andric 
7175ffd83dbSDimitry Andric           Count++;
7185ffd83dbSDimitry Andric         }
7195ffd83dbSDimitry Andric         NumBytes += MFI.getObjectSize(i);
7205ffd83dbSDimitry Andric       }
7215ffd83dbSDimitry Andric 
7225ffd83dbSDimitry Andric       // Make NumBytes 8 byte aligned
7235ffd83dbSDimitry Andric       NumBytes = alignTo(NumBytes, 8);
7245ffd83dbSDimitry Andric 
7255ffd83dbSDimitry Andric       // If the number of registers having variable arguments is odd,
7265ffd83dbSDimitry Andric       // leave 4 bytes of padding to get to the location where first
7275ffd83dbSDimitry Andric       // variable argument which was passed through register was copied.
7285ffd83dbSDimitry Andric       NumBytes = (NumVarArgRegs % 2 == 0) ? NumBytes : NumBytes + 4;
7295ffd83dbSDimitry Andric 
7305ffd83dbSDimitry Andric       for (int j = FirstVarArgSavedReg, i = 0; j < 6; ++j, ++i) {
7315ffd83dbSDimitry Andric         BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::S2_storeri_io))
7325ffd83dbSDimitry Andric           .addReg(SP)
7335ffd83dbSDimitry Andric           .addImm(NumBytes + 4 * i)
7345ffd83dbSDimitry Andric           .addReg(Hexagon::R0 + j)
7355ffd83dbSDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
7365ffd83dbSDimitry Andric       }
7375ffd83dbSDimitry Andric     }
7385ffd83dbSDimitry Andric   }
7395ffd83dbSDimitry Andric 
7400b57cec5SDimitry Andric   if (hasFP(MF)) {
7410b57cec5SDimitry Andric     insertAllocframe(MBB, InsertPt, NumBytes);
7420b57cec5SDimitry Andric     if (AlignStack) {
7430b57cec5SDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_andir), SP)
7440b57cec5SDimitry Andric           .addReg(SP)
7455ffd83dbSDimitry Andric           .addImm(-int64_t(MaxAlign.value()));
7460b57cec5SDimitry Andric     }
7470b57cec5SDimitry Andric     // If the stack-checking is enabled, and we spilled the callee-saved
7480b57cec5SDimitry Andric     // registers inline (i.e. did not use a spill function), then call
7490b57cec5SDimitry Andric     // the stack checker directly.
7500b57cec5SDimitry Andric     if (EnableStackOVFSanitizer && !PrologueStubs)
7510b57cec5SDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::PS_call_stk))
7520b57cec5SDimitry Andric              .addExternalSymbol("__runtime_stack_check");
7530b57cec5SDimitry Andric   } else if (NumBytes > 0) {
7540b57cec5SDimitry Andric     assert(alignTo(NumBytes, 8) == NumBytes);
7550b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP)
7560b57cec5SDimitry Andric       .addReg(SP)
7570b57cec5SDimitry Andric       .addImm(-int(NumBytes));
7580b57cec5SDimitry Andric   }
7590b57cec5SDimitry Andric }
7600b57cec5SDimitry Andric 
7610b57cec5SDimitry Andric void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const {
7620b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
7630b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
7640b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
7650b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
7660b57cec5SDimitry Andric   unsigned SP = HRI.getStackRegister();
7670b57cec5SDimitry Andric 
7680b57cec5SDimitry Andric   MachineBasicBlock::iterator InsertPt = MBB.getFirstTerminator();
7690b57cec5SDimitry Andric   DebugLoc dl = MBB.findDebugLoc(InsertPt);
7700b57cec5SDimitry Andric 
7710b57cec5SDimitry Andric   if (!hasFP(MF)) {
7720b57cec5SDimitry Andric     MachineFrameInfo &MFI = MF.getFrameInfo();
7735ffd83dbSDimitry Andric     unsigned NumBytes = MFI.getStackSize();
7745ffd83dbSDimitry Andric     if (MF.getFunction().isVarArg() &&
7755ffd83dbSDimitry Andric         MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl()) {
7765ffd83dbSDimitry Andric       // On Hexagon Linux, deallocate the stack for the register saved area.
7775ffd83dbSDimitry Andric       int NumVarArgRegs = 6 - FirstVarArgSavedReg;
7785ffd83dbSDimitry Andric       int RegisterSavedAreaSizePlusPadding = (NumVarArgRegs % 2 == 0) ?
7795ffd83dbSDimitry Andric         (NumVarArgRegs * 4) : (NumVarArgRegs * 4 + 4);
7805ffd83dbSDimitry Andric       NumBytes += RegisterSavedAreaSizePlusPadding;
7815ffd83dbSDimitry Andric     }
7825ffd83dbSDimitry Andric     if (NumBytes) {
7830b57cec5SDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP)
7840b57cec5SDimitry Andric         .addReg(SP)
7850b57cec5SDimitry Andric         .addImm(NumBytes);
7860b57cec5SDimitry Andric     }
7870b57cec5SDimitry Andric     return;
7880b57cec5SDimitry Andric   }
7890b57cec5SDimitry Andric 
7900b57cec5SDimitry Andric   MachineInstr *RetI = getReturn(MBB);
7910b57cec5SDimitry Andric   unsigned RetOpc = RetI ? RetI->getOpcode() : 0;
7920b57cec5SDimitry Andric 
7930b57cec5SDimitry Andric   // Handle EH_RETURN.
7940b57cec5SDimitry Andric   if (RetOpc == Hexagon::EH_RETURN_JMPR) {
7950b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::L2_deallocframe))
7960b57cec5SDimitry Andric         .addDef(Hexagon::D15)
7970b57cec5SDimitry Andric         .addReg(Hexagon::R30);
7980b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_add), SP)
7990b57cec5SDimitry Andric         .addReg(SP)
8000b57cec5SDimitry Andric         .addReg(Hexagon::R28);
8010b57cec5SDimitry Andric     return;
8020b57cec5SDimitry Andric   }
8030b57cec5SDimitry Andric 
8040b57cec5SDimitry Andric   // Check for RESTORE_DEALLOC_RET* tail call. Don't emit an extra dealloc-
8050b57cec5SDimitry Andric   // frame instruction if we encounter it.
8060b57cec5SDimitry Andric   if (RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4 ||
8070b57cec5SDimitry Andric       RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC ||
8080b57cec5SDimitry Andric       RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT ||
8090b57cec5SDimitry Andric       RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC) {
8100b57cec5SDimitry Andric     MachineBasicBlock::iterator It = RetI;
8110b57cec5SDimitry Andric     ++It;
8120b57cec5SDimitry Andric     // Delete all instructions after the RESTORE (except labels).
8130b57cec5SDimitry Andric     while (It != MBB.end()) {
8140b57cec5SDimitry Andric       if (!It->isLabel())
8150b57cec5SDimitry Andric         It = MBB.erase(It);
8160b57cec5SDimitry Andric       else
8170b57cec5SDimitry Andric         ++It;
8180b57cec5SDimitry Andric     }
8190b57cec5SDimitry Andric     return;
8200b57cec5SDimitry Andric   }
8210b57cec5SDimitry Andric 
8220b57cec5SDimitry Andric   // It is possible that the restoring code is a call to a library function.
8230b57cec5SDimitry Andric   // All of the restore* functions include "deallocframe", so we need to make
8240b57cec5SDimitry Andric   // sure that we don't add an extra one.
8250b57cec5SDimitry Andric   bool NeedsDeallocframe = true;
8260b57cec5SDimitry Andric   if (!MBB.empty() && InsertPt != MBB.begin()) {
8270b57cec5SDimitry Andric     MachineBasicBlock::iterator PrevIt = std::prev(InsertPt);
8280b57cec5SDimitry Andric     unsigned COpc = PrevIt->getOpcode();
8290b57cec5SDimitry Andric     if (COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4 ||
8300b57cec5SDimitry Andric         COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC ||
8310b57cec5SDimitry Andric         COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT ||
8320b57cec5SDimitry Andric         COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC ||
8330b57cec5SDimitry Andric         COpc == Hexagon::PS_call_nr || COpc == Hexagon::PS_callr_nr)
8340b57cec5SDimitry Andric       NeedsDeallocframe = false;
8350b57cec5SDimitry Andric   }
8360b57cec5SDimitry Andric 
8375ffd83dbSDimitry Andric   if (!MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl() ||
8385ffd83dbSDimitry Andric       !MF.getFunction().isVarArg()) {
8390b57cec5SDimitry Andric     if (!NeedsDeallocframe)
8400b57cec5SDimitry Andric       return;
8415ffd83dbSDimitry Andric     // If the returning instruction is PS_jmpret, replace it with
8425ffd83dbSDimitry Andric     // dealloc_return, otherwise just add deallocframe. The function
8435ffd83dbSDimitry Andric     // could be returning via a tail call.
8440b57cec5SDimitry Andric     if (RetOpc != Hexagon::PS_jmpret || DisableDeallocRet) {
8450b57cec5SDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::L2_deallocframe))
8460b57cec5SDimitry Andric       .addDef(Hexagon::D15)
8470b57cec5SDimitry Andric       .addReg(Hexagon::R30);
8480b57cec5SDimitry Andric       return;
8490b57cec5SDimitry Andric     }
8500b57cec5SDimitry Andric     unsigned NewOpc = Hexagon::L4_return;
8510b57cec5SDimitry Andric     MachineInstr *NewI = BuildMI(MBB, RetI, dl, HII.get(NewOpc))
8520b57cec5SDimitry Andric       .addDef(Hexagon::D15)
8530b57cec5SDimitry Andric       .addReg(Hexagon::R30);
8540b57cec5SDimitry Andric     // Transfer the function live-out registers.
8550b57cec5SDimitry Andric     NewI->copyImplicitOps(MF, *RetI);
8560b57cec5SDimitry Andric     MBB.erase(RetI);
8575ffd83dbSDimitry Andric   } else {
8585ffd83dbSDimitry Andric     // L2_deallocframe instruction after it.
8595ffd83dbSDimitry Andric     // Calculate the size of register saved area.
8605ffd83dbSDimitry Andric     int NumVarArgRegs = 6 - FirstVarArgSavedReg;
8615ffd83dbSDimitry Andric     int RegisterSavedAreaSizePlusPadding = (NumVarArgRegs % 2 == 0) ?
8625ffd83dbSDimitry Andric       (NumVarArgRegs * 4) : (NumVarArgRegs * 4 + 4);
8635ffd83dbSDimitry Andric 
8645ffd83dbSDimitry Andric     MachineBasicBlock::iterator Term = MBB.getFirstTerminator();
8655ffd83dbSDimitry Andric     MachineBasicBlock::iterator I = (Term == MBB.begin()) ? MBB.end()
8665ffd83dbSDimitry Andric                                                           : std::prev(Term);
8675ffd83dbSDimitry Andric     if (I == MBB.end() ||
8685ffd83dbSDimitry Andric        (I->getOpcode() != Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT &&
8695ffd83dbSDimitry Andric         I->getOpcode() != Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC &&
8705ffd83dbSDimitry Andric         I->getOpcode() != Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4 &&
8715ffd83dbSDimitry Andric         I->getOpcode() != Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC))
8725ffd83dbSDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::L2_deallocframe))
8735ffd83dbSDimitry Andric         .addDef(Hexagon::D15)
8745ffd83dbSDimitry Andric         .addReg(Hexagon::R30);
8755ffd83dbSDimitry Andric     if (RegisterSavedAreaSizePlusPadding != 0)
8765ffd83dbSDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP)
8775ffd83dbSDimitry Andric         .addReg(SP)
8785ffd83dbSDimitry Andric         .addImm(RegisterSavedAreaSizePlusPadding);
8795ffd83dbSDimitry Andric   }
8800b57cec5SDimitry Andric }
8810b57cec5SDimitry Andric 
8820b57cec5SDimitry Andric void HexagonFrameLowering::insertAllocframe(MachineBasicBlock &MBB,
8830b57cec5SDimitry Andric       MachineBasicBlock::iterator InsertPt, unsigned NumBytes) const {
8840b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
8850b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
8860b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
8870b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
8880b57cec5SDimitry Andric 
8890b57cec5SDimitry Andric   // Check for overflow.
8900b57cec5SDimitry Andric   // Hexagon_TODO: Ugh! hardcoding. Is there an API that can be used?
8910b57cec5SDimitry Andric   const unsigned int ALLOCFRAME_MAX = 16384;
8920b57cec5SDimitry Andric 
8930b57cec5SDimitry Andric   // Create a dummy memory operand to avoid allocframe from being treated as
8940b57cec5SDimitry Andric   // a volatile memory reference.
8950b57cec5SDimitry Andric   auto *MMO = MF.getMachineMemOperand(MachinePointerInfo::getStack(MF, 0),
8965ffd83dbSDimitry Andric                                       MachineMemOperand::MOStore, 4, Align(4));
8970b57cec5SDimitry Andric 
8980b57cec5SDimitry Andric   DebugLoc dl = MBB.findDebugLoc(InsertPt);
8990b57cec5SDimitry Andric   unsigned SP = HRI.getStackRegister();
9000b57cec5SDimitry Andric 
9010b57cec5SDimitry Andric   if (NumBytes >= ALLOCFRAME_MAX) {
9020b57cec5SDimitry Andric     // Emit allocframe(#0).
9030b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::S2_allocframe))
9040b57cec5SDimitry Andric       .addDef(SP)
9050b57cec5SDimitry Andric       .addReg(SP)
9060b57cec5SDimitry Andric       .addImm(0)
9070b57cec5SDimitry Andric       .addMemOperand(MMO);
9080b57cec5SDimitry Andric 
9090b57cec5SDimitry Andric     // Subtract the size from the stack pointer.
9100b57cec5SDimitry Andric     unsigned SP = HRI.getStackRegister();
9110b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP)
9120b57cec5SDimitry Andric       .addReg(SP)
9130b57cec5SDimitry Andric       .addImm(-int(NumBytes));
9140b57cec5SDimitry Andric   } else {
9150b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::S2_allocframe))
9160b57cec5SDimitry Andric       .addDef(SP)
9170b57cec5SDimitry Andric       .addReg(SP)
9180b57cec5SDimitry Andric       .addImm(NumBytes)
9190b57cec5SDimitry Andric       .addMemOperand(MMO);
9200b57cec5SDimitry Andric   }
9210b57cec5SDimitry Andric }
9220b57cec5SDimitry Andric 
9230b57cec5SDimitry Andric void HexagonFrameLowering::updateEntryPaths(MachineFunction &MF,
9240b57cec5SDimitry Andric       MachineBasicBlock &SaveB) const {
9250b57cec5SDimitry Andric   SetVector<unsigned> Worklist;
9260b57cec5SDimitry Andric 
9270b57cec5SDimitry Andric   MachineBasicBlock &EntryB = MF.front();
9280b57cec5SDimitry Andric   Worklist.insert(EntryB.getNumber());
9290b57cec5SDimitry Andric 
9300b57cec5SDimitry Andric   unsigned SaveN = SaveB.getNumber();
9310b57cec5SDimitry Andric   auto &CSI = MF.getFrameInfo().getCalleeSavedInfo();
9320b57cec5SDimitry Andric 
9330b57cec5SDimitry Andric   for (unsigned i = 0; i < Worklist.size(); ++i) {
9340b57cec5SDimitry Andric     unsigned BN = Worklist[i];
9350b57cec5SDimitry Andric     MachineBasicBlock &MBB = *MF.getBlockNumbered(BN);
9360b57cec5SDimitry Andric     for (auto &R : CSI)
9370b57cec5SDimitry Andric       if (!MBB.isLiveIn(R.getReg()))
9380b57cec5SDimitry Andric         MBB.addLiveIn(R.getReg());
9390b57cec5SDimitry Andric     if (BN != SaveN)
9400b57cec5SDimitry Andric       for (auto &SB : MBB.successors())
9410b57cec5SDimitry Andric         Worklist.insert(SB->getNumber());
9420b57cec5SDimitry Andric   }
9430b57cec5SDimitry Andric }
9440b57cec5SDimitry Andric 
9450b57cec5SDimitry Andric bool HexagonFrameLowering::updateExitPaths(MachineBasicBlock &MBB,
9460b57cec5SDimitry Andric       MachineBasicBlock &RestoreB, BitVector &DoneT, BitVector &DoneF,
9470b57cec5SDimitry Andric       BitVector &Path) const {
9480b57cec5SDimitry Andric   assert(MBB.getNumber() >= 0);
9490b57cec5SDimitry Andric   unsigned BN = MBB.getNumber();
9500b57cec5SDimitry Andric   if (Path[BN] || DoneF[BN])
9510b57cec5SDimitry Andric     return false;
9520b57cec5SDimitry Andric   if (DoneT[BN])
9530b57cec5SDimitry Andric     return true;
9540b57cec5SDimitry Andric 
9550b57cec5SDimitry Andric   auto &CSI = MBB.getParent()->getFrameInfo().getCalleeSavedInfo();
9560b57cec5SDimitry Andric 
9570b57cec5SDimitry Andric   Path[BN] = true;
9580b57cec5SDimitry Andric   bool ReachedExit = false;
9590b57cec5SDimitry Andric   for (auto &SB : MBB.successors())
9600b57cec5SDimitry Andric     ReachedExit |= updateExitPaths(*SB, RestoreB, DoneT, DoneF, Path);
9610b57cec5SDimitry Andric 
9620b57cec5SDimitry Andric   if (!MBB.empty() && MBB.back().isReturn()) {
9630b57cec5SDimitry Andric     // Add implicit uses of all callee-saved registers to the reached
9640b57cec5SDimitry Andric     // return instructions. This is to prevent the anti-dependency breaker
9650b57cec5SDimitry Andric     // from renaming these registers.
9660b57cec5SDimitry Andric     MachineInstr &RetI = MBB.back();
9670b57cec5SDimitry Andric     if (!isRestoreCall(RetI.getOpcode()))
9680b57cec5SDimitry Andric       for (auto &R : CSI)
9690b57cec5SDimitry Andric         RetI.addOperand(MachineOperand::CreateReg(R.getReg(), false, true));
9700b57cec5SDimitry Andric     ReachedExit = true;
9710b57cec5SDimitry Andric   }
9720b57cec5SDimitry Andric 
9730b57cec5SDimitry Andric   // We don't want to add unnecessary live-ins to the restore block: since
9740b57cec5SDimitry Andric   // the callee-saved registers are being defined in it, the entry of the
9750b57cec5SDimitry Andric   // restore block cannot be on the path from the definitions to any exit.
9760b57cec5SDimitry Andric   if (ReachedExit && &MBB != &RestoreB) {
9770b57cec5SDimitry Andric     for (auto &R : CSI)
9780b57cec5SDimitry Andric       if (!MBB.isLiveIn(R.getReg()))
9790b57cec5SDimitry Andric         MBB.addLiveIn(R.getReg());
9800b57cec5SDimitry Andric     DoneT[BN] = true;
9810b57cec5SDimitry Andric   }
9820b57cec5SDimitry Andric   if (!ReachedExit)
9830b57cec5SDimitry Andric     DoneF[BN] = true;
9840b57cec5SDimitry Andric 
9850b57cec5SDimitry Andric   Path[BN] = false;
9860b57cec5SDimitry Andric   return ReachedExit;
9870b57cec5SDimitry Andric }
9880b57cec5SDimitry Andric 
9890b57cec5SDimitry Andric static Optional<MachineBasicBlock::iterator>
9900b57cec5SDimitry Andric findCFILocation(MachineBasicBlock &B) {
9910b57cec5SDimitry Andric     // The CFI instructions need to be inserted right after allocframe.
9920b57cec5SDimitry Andric     // An exception to this is a situation where allocframe is bundled
9930b57cec5SDimitry Andric     // with a call: then the CFI instructions need to be inserted before
9940b57cec5SDimitry Andric     // the packet with the allocframe+call (in case the call throws an
9950b57cec5SDimitry Andric     // exception).
9960b57cec5SDimitry Andric     auto End = B.instr_end();
9970b57cec5SDimitry Andric 
9980b57cec5SDimitry Andric     for (MachineInstr &I : B) {
9990b57cec5SDimitry Andric       MachineBasicBlock::iterator It = I.getIterator();
10000b57cec5SDimitry Andric       if (!I.isBundle()) {
10010b57cec5SDimitry Andric         if (I.getOpcode() == Hexagon::S2_allocframe)
10020b57cec5SDimitry Andric           return std::next(It);
10030b57cec5SDimitry Andric         continue;
10040b57cec5SDimitry Andric       }
10050b57cec5SDimitry Andric       // I is a bundle.
10060b57cec5SDimitry Andric       bool HasCall = false, HasAllocFrame = false;
10070b57cec5SDimitry Andric       auto T = It.getInstrIterator();
10080b57cec5SDimitry Andric       while (++T != End && T->isBundled()) {
10090b57cec5SDimitry Andric         if (T->getOpcode() == Hexagon::S2_allocframe)
10100b57cec5SDimitry Andric           HasAllocFrame = true;
10110b57cec5SDimitry Andric         else if (T->isCall())
10120b57cec5SDimitry Andric           HasCall = true;
10130b57cec5SDimitry Andric       }
10140b57cec5SDimitry Andric       if (HasAllocFrame)
10150b57cec5SDimitry Andric         return HasCall ? It : std::next(It);
10160b57cec5SDimitry Andric     }
10170b57cec5SDimitry Andric     return None;
10180b57cec5SDimitry Andric }
10190b57cec5SDimitry Andric 
10200b57cec5SDimitry Andric void HexagonFrameLowering::insertCFIInstructions(MachineFunction &MF) const {
10210b57cec5SDimitry Andric   for (auto &B : MF) {
10220b57cec5SDimitry Andric     auto At = findCFILocation(B);
10230b57cec5SDimitry Andric     if (At.hasValue())
10240b57cec5SDimitry Andric       insertCFIInstructionsAt(B, At.getValue());
10250b57cec5SDimitry Andric   }
10260b57cec5SDimitry Andric }
10270b57cec5SDimitry Andric 
10280b57cec5SDimitry Andric void HexagonFrameLowering::insertCFIInstructionsAt(MachineBasicBlock &MBB,
10290b57cec5SDimitry Andric       MachineBasicBlock::iterator At) const {
10300b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
10310b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
10320b57cec5SDimitry Andric   MachineModuleInfo &MMI = MF.getMMI();
10330b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
10340b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
10350b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
10360b57cec5SDimitry Andric 
10370b57cec5SDimitry Andric   // If CFI instructions have debug information attached, something goes
10380b57cec5SDimitry Andric   // wrong with the final assembly generation: the prolog_end is placed
10390b57cec5SDimitry Andric   // in a wrong location.
10400b57cec5SDimitry Andric   DebugLoc DL;
10410b57cec5SDimitry Andric   const MCInstrDesc &CFID = HII.get(TargetOpcode::CFI_INSTRUCTION);
10420b57cec5SDimitry Andric 
10430b57cec5SDimitry Andric   MCSymbol *FrameLabel = MMI.getContext().createTempSymbol();
10440b57cec5SDimitry Andric   bool HasFP = hasFP(MF);
10450b57cec5SDimitry Andric 
10460b57cec5SDimitry Andric   if (HasFP) {
10470b57cec5SDimitry Andric     unsigned DwFPReg = HRI.getDwarfRegNum(HRI.getFrameRegister(), true);
10480b57cec5SDimitry Andric     unsigned DwRAReg = HRI.getDwarfRegNum(HRI.getRARegister(), true);
10490b57cec5SDimitry Andric 
10500b57cec5SDimitry Andric     // Define CFA via an offset from the value of FP.
10510b57cec5SDimitry Andric     //
10520b57cec5SDimitry Andric     //  -8   -4    0 (SP)
10530b57cec5SDimitry Andric     // --+----+----+---------------------
10540b57cec5SDimitry Andric     //   | FP | LR |          increasing addresses -->
10550b57cec5SDimitry Andric     // --+----+----+---------------------
10560b57cec5SDimitry Andric     //   |         +-- Old SP (before allocframe)
10570b57cec5SDimitry Andric     //   +-- New FP (after allocframe)
10580b57cec5SDimitry Andric     //
10595ffd83dbSDimitry Andric     // MCCFIInstruction::cfiDefCfa adds the offset from the register.
10600b57cec5SDimitry Andric     // MCCFIInstruction::createOffset takes the offset without sign change.
10615ffd83dbSDimitry Andric     auto DefCfa = MCCFIInstruction::cfiDefCfa(FrameLabel, DwFPReg, 8);
10620b57cec5SDimitry Andric     BuildMI(MBB, At, DL, CFID)
10630b57cec5SDimitry Andric         .addCFIIndex(MF.addFrameInst(DefCfa));
10640b57cec5SDimitry Andric     // R31 (return addr) = CFA - 4
10650b57cec5SDimitry Andric     auto OffR31 = MCCFIInstruction::createOffset(FrameLabel, DwRAReg, -4);
10660b57cec5SDimitry Andric     BuildMI(MBB, At, DL, CFID)
10670b57cec5SDimitry Andric         .addCFIIndex(MF.addFrameInst(OffR31));
10680b57cec5SDimitry Andric     // R30 (frame ptr) = CFA - 8
10690b57cec5SDimitry Andric     auto OffR30 = MCCFIInstruction::createOffset(FrameLabel, DwFPReg, -8);
10700b57cec5SDimitry Andric     BuildMI(MBB, At, DL, CFID)
10710b57cec5SDimitry Andric         .addCFIIndex(MF.addFrameInst(OffR30));
10720b57cec5SDimitry Andric   }
10730b57cec5SDimitry Andric 
10740b57cec5SDimitry Andric   static unsigned int RegsToMove[] = {
10750b57cec5SDimitry Andric     Hexagon::R1,  Hexagon::R0,  Hexagon::R3,  Hexagon::R2,
10760b57cec5SDimitry Andric     Hexagon::R17, Hexagon::R16, Hexagon::R19, Hexagon::R18,
10770b57cec5SDimitry Andric     Hexagon::R21, Hexagon::R20, Hexagon::R23, Hexagon::R22,
10780b57cec5SDimitry Andric     Hexagon::R25, Hexagon::R24, Hexagon::R27, Hexagon::R26,
10790b57cec5SDimitry Andric     Hexagon::D0,  Hexagon::D1,  Hexagon::D8,  Hexagon::D9,
10800b57cec5SDimitry Andric     Hexagon::D10, Hexagon::D11, Hexagon::D12, Hexagon::D13,
10810b57cec5SDimitry Andric     Hexagon::NoRegister
10820b57cec5SDimitry Andric   };
10830b57cec5SDimitry Andric 
10840b57cec5SDimitry Andric   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
10850b57cec5SDimitry Andric 
10860b57cec5SDimitry Andric   for (unsigned i = 0; RegsToMove[i] != Hexagon::NoRegister; ++i) {
10870b57cec5SDimitry Andric     unsigned Reg = RegsToMove[i];
10880b57cec5SDimitry Andric     auto IfR = [Reg] (const CalleeSavedInfo &C) -> bool {
10890b57cec5SDimitry Andric       return C.getReg() == Reg;
10900b57cec5SDimitry Andric     };
10910b57cec5SDimitry Andric     auto F = find_if(CSI, IfR);
10920b57cec5SDimitry Andric     if (F == CSI.end())
10930b57cec5SDimitry Andric       continue;
10940b57cec5SDimitry Andric 
10950b57cec5SDimitry Andric     int64_t Offset;
10960b57cec5SDimitry Andric     if (HasFP) {
10970b57cec5SDimitry Andric       // If the function has a frame pointer (i.e. has an allocframe),
10980b57cec5SDimitry Andric       // then the CFA has been defined in terms of FP. Any offsets in
10990b57cec5SDimitry Andric       // the following CFI instructions have to be defined relative
11000b57cec5SDimitry Andric       // to FP, which points to the bottom of the stack frame.
11010b57cec5SDimitry Andric       // The function getFrameIndexReference can still choose to use SP
11020b57cec5SDimitry Andric       // for the offset calculation, so we cannot simply call it here.
11030b57cec5SDimitry Andric       // Instead, get the offset (relative to the FP) directly.
11040b57cec5SDimitry Andric       Offset = MFI.getObjectOffset(F->getFrameIdx());
11050b57cec5SDimitry Andric     } else {
11065ffd83dbSDimitry Andric       Register FrameReg;
1107e8d8bef9SDimitry Andric       Offset =
1108e8d8bef9SDimitry Andric           getFrameIndexReference(MF, F->getFrameIdx(), FrameReg).getFixed();
11090b57cec5SDimitry Andric     }
11100b57cec5SDimitry Andric     // Subtract 8 to make room for R30 and R31, which are added above.
11110b57cec5SDimitry Andric     Offset -= 8;
11120b57cec5SDimitry Andric 
11130b57cec5SDimitry Andric     if (Reg < Hexagon::D0 || Reg > Hexagon::D15) {
11140b57cec5SDimitry Andric       unsigned DwarfReg = HRI.getDwarfRegNum(Reg, true);
11150b57cec5SDimitry Andric       auto OffReg = MCCFIInstruction::createOffset(FrameLabel, DwarfReg,
11160b57cec5SDimitry Andric                                                    Offset);
11170b57cec5SDimitry Andric       BuildMI(MBB, At, DL, CFID)
11180b57cec5SDimitry Andric           .addCFIIndex(MF.addFrameInst(OffReg));
11190b57cec5SDimitry Andric     } else {
11200b57cec5SDimitry Andric       // Split the double regs into subregs, and generate appropriate
11210b57cec5SDimitry Andric       // cfi_offsets.
11220b57cec5SDimitry Andric       // The only reason, we are split double regs is, llvm-mc does not
11230b57cec5SDimitry Andric       // understand paired registers for cfi_offset.
11240b57cec5SDimitry Andric       // Eg .cfi_offset r1:0, -64
11250b57cec5SDimitry Andric 
11268bcb0991SDimitry Andric       Register HiReg = HRI.getSubReg(Reg, Hexagon::isub_hi);
11278bcb0991SDimitry Andric       Register LoReg = HRI.getSubReg(Reg, Hexagon::isub_lo);
11280b57cec5SDimitry Andric       unsigned HiDwarfReg = HRI.getDwarfRegNum(HiReg, true);
11290b57cec5SDimitry Andric       unsigned LoDwarfReg = HRI.getDwarfRegNum(LoReg, true);
11300b57cec5SDimitry Andric       auto OffHi = MCCFIInstruction::createOffset(FrameLabel, HiDwarfReg,
11310b57cec5SDimitry Andric                                                   Offset+4);
11320b57cec5SDimitry Andric       BuildMI(MBB, At, DL, CFID)
11330b57cec5SDimitry Andric           .addCFIIndex(MF.addFrameInst(OffHi));
11340b57cec5SDimitry Andric       auto OffLo = MCCFIInstruction::createOffset(FrameLabel, LoDwarfReg,
11350b57cec5SDimitry Andric                                                   Offset);
11360b57cec5SDimitry Andric       BuildMI(MBB, At, DL, CFID)
11370b57cec5SDimitry Andric           .addCFIIndex(MF.addFrameInst(OffLo));
11380b57cec5SDimitry Andric     }
11390b57cec5SDimitry Andric   }
11400b57cec5SDimitry Andric }
11410b57cec5SDimitry Andric 
11420b57cec5SDimitry Andric bool HexagonFrameLowering::hasFP(const MachineFunction &MF) const {
11430b57cec5SDimitry Andric   if (MF.getFunction().hasFnAttribute(Attribute::Naked))
11440b57cec5SDimitry Andric     return false;
11450b57cec5SDimitry Andric 
11460b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
11470b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
1148*fe6060f1SDimitry Andric   bool HasExtraAlign = HRI.hasStackRealignment(MF);
11490b57cec5SDimitry Andric   bool HasAlloca = MFI.hasVarSizedObjects();
11500b57cec5SDimitry Andric 
11510b57cec5SDimitry Andric   // Insert ALLOCFRAME if we need to or at -O0 for the debugger.  Think
11520b57cec5SDimitry Andric   // that this shouldn't be required, but doing so now because gcc does and
11530b57cec5SDimitry Andric   // gdb can't break at the start of the function without it.  Will remove if
11540b57cec5SDimitry Andric   // this turns out to be a gdb bug.
11550b57cec5SDimitry Andric   //
11560b57cec5SDimitry Andric   if (MF.getTarget().getOptLevel() == CodeGenOpt::None)
11570b57cec5SDimitry Andric     return true;
11580b57cec5SDimitry Andric 
11590b57cec5SDimitry Andric   // By default we want to use SP (since it's always there). FP requires
11600b57cec5SDimitry Andric   // some setup (i.e. ALLOCFRAME).
11610b57cec5SDimitry Andric   // Both, alloca and stack alignment modify the stack pointer by an
11620b57cec5SDimitry Andric   // undetermined value, so we need to save it at the entry to the function
11630b57cec5SDimitry Andric   // (i.e. use allocframe).
11640b57cec5SDimitry Andric   if (HasAlloca || HasExtraAlign)
11650b57cec5SDimitry Andric     return true;
11660b57cec5SDimitry Andric 
11670b57cec5SDimitry Andric   if (MFI.getStackSize() > 0) {
11680b57cec5SDimitry Andric     // If FP-elimination is disabled, we have to use FP at this point.
11690b57cec5SDimitry Andric     const TargetMachine &TM = MF.getTarget();
11700b57cec5SDimitry Andric     if (TM.Options.DisableFramePointerElim(MF) || !EliminateFramePointer)
11710b57cec5SDimitry Andric       return true;
11720b57cec5SDimitry Andric     if (EnableStackOVFSanitizer)
11730b57cec5SDimitry Andric       return true;
11740b57cec5SDimitry Andric   }
11750b57cec5SDimitry Andric 
11760b57cec5SDimitry Andric   const auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
11770b57cec5SDimitry Andric   if ((MFI.hasCalls() && !enableAllocFrameElim(MF)) || HMFI.hasClobberLR())
11780b57cec5SDimitry Andric     return true;
11790b57cec5SDimitry Andric 
11800b57cec5SDimitry Andric   return false;
11810b57cec5SDimitry Andric }
11820b57cec5SDimitry Andric 
11830b57cec5SDimitry Andric enum SpillKind {
11840b57cec5SDimitry Andric   SK_ToMem,
11850b57cec5SDimitry Andric   SK_FromMem,
11860b57cec5SDimitry Andric   SK_FromMemTailcall
11870b57cec5SDimitry Andric };
11880b57cec5SDimitry Andric 
11890b57cec5SDimitry Andric static const char *getSpillFunctionFor(unsigned MaxReg, SpillKind SpillType,
11900b57cec5SDimitry Andric       bool Stkchk = false) {
11910b57cec5SDimitry Andric   const char * V4SpillToMemoryFunctions[] = {
11920b57cec5SDimitry Andric     "__save_r16_through_r17",
11930b57cec5SDimitry Andric     "__save_r16_through_r19",
11940b57cec5SDimitry Andric     "__save_r16_through_r21",
11950b57cec5SDimitry Andric     "__save_r16_through_r23",
11960b57cec5SDimitry Andric     "__save_r16_through_r25",
11970b57cec5SDimitry Andric     "__save_r16_through_r27" };
11980b57cec5SDimitry Andric 
11990b57cec5SDimitry Andric   const char * V4SpillToMemoryStkchkFunctions[] = {
12000b57cec5SDimitry Andric     "__save_r16_through_r17_stkchk",
12010b57cec5SDimitry Andric     "__save_r16_through_r19_stkchk",
12020b57cec5SDimitry Andric     "__save_r16_through_r21_stkchk",
12030b57cec5SDimitry Andric     "__save_r16_through_r23_stkchk",
12040b57cec5SDimitry Andric     "__save_r16_through_r25_stkchk",
12050b57cec5SDimitry Andric     "__save_r16_through_r27_stkchk" };
12060b57cec5SDimitry Andric 
12070b57cec5SDimitry Andric   const char * V4SpillFromMemoryFunctions[] = {
12080b57cec5SDimitry Andric     "__restore_r16_through_r17_and_deallocframe",
12090b57cec5SDimitry Andric     "__restore_r16_through_r19_and_deallocframe",
12100b57cec5SDimitry Andric     "__restore_r16_through_r21_and_deallocframe",
12110b57cec5SDimitry Andric     "__restore_r16_through_r23_and_deallocframe",
12120b57cec5SDimitry Andric     "__restore_r16_through_r25_and_deallocframe",
12130b57cec5SDimitry Andric     "__restore_r16_through_r27_and_deallocframe" };
12140b57cec5SDimitry Andric 
12150b57cec5SDimitry Andric   const char * V4SpillFromMemoryTailcallFunctions[] = {
12160b57cec5SDimitry Andric     "__restore_r16_through_r17_and_deallocframe_before_tailcall",
12170b57cec5SDimitry Andric     "__restore_r16_through_r19_and_deallocframe_before_tailcall",
12180b57cec5SDimitry Andric     "__restore_r16_through_r21_and_deallocframe_before_tailcall",
12190b57cec5SDimitry Andric     "__restore_r16_through_r23_and_deallocframe_before_tailcall",
12200b57cec5SDimitry Andric     "__restore_r16_through_r25_and_deallocframe_before_tailcall",
12210b57cec5SDimitry Andric     "__restore_r16_through_r27_and_deallocframe_before_tailcall"
12220b57cec5SDimitry Andric   };
12230b57cec5SDimitry Andric 
12240b57cec5SDimitry Andric   const char **SpillFunc = nullptr;
12250b57cec5SDimitry Andric 
12260b57cec5SDimitry Andric   switch(SpillType) {
12270b57cec5SDimitry Andric   case SK_ToMem:
12280b57cec5SDimitry Andric     SpillFunc = Stkchk ? V4SpillToMemoryStkchkFunctions
12290b57cec5SDimitry Andric                        : V4SpillToMemoryFunctions;
12300b57cec5SDimitry Andric     break;
12310b57cec5SDimitry Andric   case SK_FromMem:
12320b57cec5SDimitry Andric     SpillFunc = V4SpillFromMemoryFunctions;
12330b57cec5SDimitry Andric     break;
12340b57cec5SDimitry Andric   case SK_FromMemTailcall:
12350b57cec5SDimitry Andric     SpillFunc = V4SpillFromMemoryTailcallFunctions;
12360b57cec5SDimitry Andric     break;
12370b57cec5SDimitry Andric   }
12380b57cec5SDimitry Andric   assert(SpillFunc && "Unknown spill kind");
12390b57cec5SDimitry Andric 
12400b57cec5SDimitry Andric   // Spill all callee-saved registers up to the highest register used.
12410b57cec5SDimitry Andric   switch (MaxReg) {
12420b57cec5SDimitry Andric   case Hexagon::R17:
12430b57cec5SDimitry Andric     return SpillFunc[0];
12440b57cec5SDimitry Andric   case Hexagon::R19:
12450b57cec5SDimitry Andric     return SpillFunc[1];
12460b57cec5SDimitry Andric   case Hexagon::R21:
12470b57cec5SDimitry Andric     return SpillFunc[2];
12480b57cec5SDimitry Andric   case Hexagon::R23:
12490b57cec5SDimitry Andric     return SpillFunc[3];
12500b57cec5SDimitry Andric   case Hexagon::R25:
12510b57cec5SDimitry Andric     return SpillFunc[4];
12520b57cec5SDimitry Andric   case Hexagon::R27:
12530b57cec5SDimitry Andric     return SpillFunc[5];
12540b57cec5SDimitry Andric   default:
12550b57cec5SDimitry Andric     llvm_unreachable("Unhandled maximum callee save register");
12560b57cec5SDimitry Andric   }
12570b57cec5SDimitry Andric   return nullptr;
12580b57cec5SDimitry Andric }
12590b57cec5SDimitry Andric 
1260e8d8bef9SDimitry Andric StackOffset
1261e8d8bef9SDimitry Andric HexagonFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
12625ffd83dbSDimitry Andric                                              Register &FrameReg) const {
12630b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
12640b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
12650b57cec5SDimitry Andric 
12660b57cec5SDimitry Andric   int Offset = MFI.getObjectOffset(FI);
12670b57cec5SDimitry Andric   bool HasAlloca = MFI.hasVarSizedObjects();
1268*fe6060f1SDimitry Andric   bool HasExtraAlign = HRI.hasStackRealignment(MF);
12690b57cec5SDimitry Andric   bool NoOpt = MF.getTarget().getOptLevel() == CodeGenOpt::None;
12700b57cec5SDimitry Andric 
12710b57cec5SDimitry Andric   auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
12720b57cec5SDimitry Andric   unsigned FrameSize = MFI.getStackSize();
12735ffd83dbSDimitry Andric   Register SP = HRI.getStackRegister();
12745ffd83dbSDimitry Andric   Register FP = HRI.getFrameRegister();
12755ffd83dbSDimitry Andric   Register AP = HMFI.getStackAlignBasePhysReg();
12760b57cec5SDimitry Andric   // It may happen that AP will be absent even HasAlloca && HasExtraAlign
12770b57cec5SDimitry Andric   // is true. HasExtraAlign may be set because of vector spills, without
12780b57cec5SDimitry Andric   // aligned locals or aligned outgoing function arguments. Since vector
12790b57cec5SDimitry Andric   // spills will ultimately be "unaligned", it is safe to use FP as the
12800b57cec5SDimitry Andric   // base register.
12810b57cec5SDimitry Andric   // In fact, in such a scenario the stack is actually not required to be
12820b57cec5SDimitry Andric   // aligned, although it may end up being aligned anyway, since this
12830b57cec5SDimitry Andric   // particular case is not easily detectable. The alignment will be
12840b57cec5SDimitry Andric   // unnecessary, but not incorrect.
12850b57cec5SDimitry Andric   // Unfortunately there is no quick way to verify that the above is
12860b57cec5SDimitry Andric   // indeed the case (and that it's not a result of an error), so just
12870b57cec5SDimitry Andric   // assume that missing AP will be replaced by FP.
12880b57cec5SDimitry Andric   // (A better fix would be to rematerialize AP from FP and always align
12890b57cec5SDimitry Andric   // vector spills.)
12900b57cec5SDimitry Andric   if (AP == 0)
12910b57cec5SDimitry Andric     AP = FP;
12920b57cec5SDimitry Andric 
12930b57cec5SDimitry Andric   bool UseFP = false, UseAP = false;  // Default: use SP (except at -O0).
12940b57cec5SDimitry Andric   // Use FP at -O0, except when there are objects with extra alignment.
12950b57cec5SDimitry Andric   // That additional alignment requirement may cause a pad to be inserted,
12960b57cec5SDimitry Andric   // which will make it impossible to use FP to access objects located
12970b57cec5SDimitry Andric   // past the pad.
12980b57cec5SDimitry Andric   if (NoOpt && !HasExtraAlign)
12990b57cec5SDimitry Andric     UseFP = true;
13000b57cec5SDimitry Andric   if (MFI.isFixedObjectIndex(FI) || MFI.isObjectPreAllocated(FI)) {
13010b57cec5SDimitry Andric     // Fixed and preallocated objects will be located before any padding
13020b57cec5SDimitry Andric     // so FP must be used to access them.
13030b57cec5SDimitry Andric     UseFP |= (HasAlloca || HasExtraAlign);
13040b57cec5SDimitry Andric   } else {
13050b57cec5SDimitry Andric     if (HasAlloca) {
13060b57cec5SDimitry Andric       if (HasExtraAlign)
13070b57cec5SDimitry Andric         UseAP = true;
13080b57cec5SDimitry Andric       else
13090b57cec5SDimitry Andric         UseFP = true;
13100b57cec5SDimitry Andric     }
13110b57cec5SDimitry Andric   }
13120b57cec5SDimitry Andric 
13130b57cec5SDimitry Andric   // If FP was picked, then there had better be FP.
13140b57cec5SDimitry Andric   bool HasFP = hasFP(MF);
13150b57cec5SDimitry Andric   assert((HasFP || !UseFP) && "This function must have frame pointer");
13160b57cec5SDimitry Andric 
13170b57cec5SDimitry Andric   // Having FP implies allocframe. Allocframe will store extra 8 bytes:
13180b57cec5SDimitry Andric   // FP/LR. If the base register is used to access an object across these
13190b57cec5SDimitry Andric   // 8 bytes, then the offset will need to be adjusted by 8.
13200b57cec5SDimitry Andric   //
13210b57cec5SDimitry Andric   // After allocframe:
13220b57cec5SDimitry Andric   //                    HexagonISelLowering adds 8 to ---+
13230b57cec5SDimitry Andric   //                    the offsets of all stack-based   |
13240b57cec5SDimitry Andric   //                    arguments (*)                    |
13250b57cec5SDimitry Andric   //                                                     |
13260b57cec5SDimitry Andric   //   getObjectOffset < 0   0     8  getObjectOffset >= 8
13270b57cec5SDimitry Andric   // ------------------------+-----+------------------------> increasing
13280b57cec5SDimitry Andric   //     <local objects>     |FP/LR|    <input arguments>     addresses
13290b57cec5SDimitry Andric   // -----------------+------+-----+------------------------>
13300b57cec5SDimitry Andric   //                  |      |
13310b57cec5SDimitry Andric   //    SP/AP point --+      +-- FP points here (**)
13320b57cec5SDimitry Andric   //    somewhere on
13330b57cec5SDimitry Andric   //    this side of FP/LR
13340b57cec5SDimitry Andric   //
13350b57cec5SDimitry Andric   // (*) See LowerFormalArguments. The FP/LR is assumed to be present.
13360b57cec5SDimitry Andric   // (**) *FP == old-FP. FP+0..7 are the bytes of FP/LR.
13370b57cec5SDimitry Andric 
13380b57cec5SDimitry Andric   // The lowering assumes that FP/LR is present, and so the offsets of
13390b57cec5SDimitry Andric   // the formal arguments start at 8. If FP/LR is not there we need to
13400b57cec5SDimitry Andric   // reduce the offset by 8.
13410b57cec5SDimitry Andric   if (Offset > 0 && !HasFP)
13420b57cec5SDimitry Andric     Offset -= 8;
13430b57cec5SDimitry Andric 
13440b57cec5SDimitry Andric   if (UseFP)
13450b57cec5SDimitry Andric     FrameReg = FP;
13460b57cec5SDimitry Andric   else if (UseAP)
13470b57cec5SDimitry Andric     FrameReg = AP;
13480b57cec5SDimitry Andric   else
13490b57cec5SDimitry Andric     FrameReg = SP;
13500b57cec5SDimitry Andric 
13510b57cec5SDimitry Andric   // Calculate the actual offset in the instruction. If there is no FP
13520b57cec5SDimitry Andric   // (in other words, no allocframe), then SP will not be adjusted (i.e.
13530b57cec5SDimitry Andric   // there will be no SP -= FrameSize), so the frame size should not be
13540b57cec5SDimitry Andric   // added to the calculated offset.
13550b57cec5SDimitry Andric   int RealOffset = Offset;
13560b57cec5SDimitry Andric   if (!UseFP && !UseAP)
13570b57cec5SDimitry Andric     RealOffset = FrameSize+Offset;
1358e8d8bef9SDimitry Andric   return StackOffset::getFixed(RealOffset);
13590b57cec5SDimitry Andric }
13600b57cec5SDimitry Andric 
13610b57cec5SDimitry Andric bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB,
13620b57cec5SDimitry Andric       const CSIVect &CSI, const HexagonRegisterInfo &HRI,
13630b57cec5SDimitry Andric       bool &PrologueStubs) const {
13640b57cec5SDimitry Andric   if (CSI.empty())
13650b57cec5SDimitry Andric     return true;
13660b57cec5SDimitry Andric 
13670b57cec5SDimitry Andric   MachineBasicBlock::iterator MI = MBB.begin();
13680b57cec5SDimitry Andric   PrologueStubs = false;
13690b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
13700b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
13710b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
13720b57cec5SDimitry Andric 
13730b57cec5SDimitry Andric   if (useSpillFunction(MF, CSI)) {
13740b57cec5SDimitry Andric     PrologueStubs = true;
13750b57cec5SDimitry Andric     unsigned MaxReg = getMaxCalleeSavedReg(CSI, HRI);
13760b57cec5SDimitry Andric     bool StkOvrFlowEnabled = EnableStackOVFSanitizer;
13770b57cec5SDimitry Andric     const char *SpillFun = getSpillFunctionFor(MaxReg, SK_ToMem,
13780b57cec5SDimitry Andric                                                StkOvrFlowEnabled);
13790b57cec5SDimitry Andric     auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget());
13800b57cec5SDimitry Andric     bool IsPIC = HTM.isPositionIndependent();
13810b57cec5SDimitry Andric     bool LongCalls = HST.useLongCalls() || EnableSaveRestoreLong;
13820b57cec5SDimitry Andric 
13830b57cec5SDimitry Andric     // Call spill function.
13840b57cec5SDimitry Andric     DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc();
13850b57cec5SDimitry Andric     unsigned SpillOpc;
13860b57cec5SDimitry Andric     if (StkOvrFlowEnabled) {
13870b57cec5SDimitry Andric       if (LongCalls)
13880b57cec5SDimitry Andric         SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_EXT_PIC
13890b57cec5SDimitry Andric                          : Hexagon::SAVE_REGISTERS_CALL_V4STK_EXT;
13900b57cec5SDimitry Andric       else
13910b57cec5SDimitry Andric         SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_PIC
13920b57cec5SDimitry Andric                          : Hexagon::SAVE_REGISTERS_CALL_V4STK;
13930b57cec5SDimitry Andric     } else {
13940b57cec5SDimitry Andric       if (LongCalls)
13950b57cec5SDimitry Andric         SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_EXT_PIC
13960b57cec5SDimitry Andric                          : Hexagon::SAVE_REGISTERS_CALL_V4_EXT;
13970b57cec5SDimitry Andric       else
13980b57cec5SDimitry Andric         SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_PIC
13990b57cec5SDimitry Andric                          : Hexagon::SAVE_REGISTERS_CALL_V4;
14000b57cec5SDimitry Andric     }
14010b57cec5SDimitry Andric 
14020b57cec5SDimitry Andric     MachineInstr *SaveRegsCall =
14030b57cec5SDimitry Andric         BuildMI(MBB, MI, DL, HII.get(SpillOpc))
14040b57cec5SDimitry Andric           .addExternalSymbol(SpillFun);
14050b57cec5SDimitry Andric 
14060b57cec5SDimitry Andric     // Add callee-saved registers as use.
14070b57cec5SDimitry Andric     addCalleeSaveRegistersAsImpOperand(SaveRegsCall, CSI, false, true);
14080b57cec5SDimitry Andric     // Add live in registers.
14090b57cec5SDimitry Andric     for (unsigned I = 0; I < CSI.size(); ++I)
14100b57cec5SDimitry Andric       MBB.addLiveIn(CSI[I].getReg());
14110b57cec5SDimitry Andric     return true;
14120b57cec5SDimitry Andric   }
14130b57cec5SDimitry Andric 
14140b57cec5SDimitry Andric   for (unsigned i = 0, n = CSI.size(); i < n; ++i) {
14150b57cec5SDimitry Andric     unsigned Reg = CSI[i].getReg();
14160b57cec5SDimitry Andric     // Add live in registers. We treat eh_return callee saved register r0 - r3
14170b57cec5SDimitry Andric     // specially. They are not really callee saved registers as they are not
14180b57cec5SDimitry Andric     // supposed to be killed.
14190b57cec5SDimitry Andric     bool IsKill = !HRI.isEHReturnCalleeSaveReg(Reg);
14200b57cec5SDimitry Andric     int FI = CSI[i].getFrameIdx();
14210b57cec5SDimitry Andric     const TargetRegisterClass *RC = HRI.getMinimalPhysRegClass(Reg);
14220b57cec5SDimitry Andric     HII.storeRegToStackSlot(MBB, MI, Reg, IsKill, FI, RC, &HRI);
14230b57cec5SDimitry Andric     if (IsKill)
14240b57cec5SDimitry Andric       MBB.addLiveIn(Reg);
14250b57cec5SDimitry Andric   }
14260b57cec5SDimitry Andric   return true;
14270b57cec5SDimitry Andric }
14280b57cec5SDimitry Andric 
14290b57cec5SDimitry Andric bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
14300b57cec5SDimitry Andric       const CSIVect &CSI, const HexagonRegisterInfo &HRI) const {
14310b57cec5SDimitry Andric   if (CSI.empty())
14320b57cec5SDimitry Andric     return false;
14330b57cec5SDimitry Andric 
14340b57cec5SDimitry Andric   MachineBasicBlock::iterator MI = MBB.getFirstTerminator();
14350b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
14360b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
14370b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
14380b57cec5SDimitry Andric 
14390b57cec5SDimitry Andric   if (useRestoreFunction(MF, CSI)) {
14400b57cec5SDimitry Andric     bool HasTC = hasTailCall(MBB) || !hasReturn(MBB);
14410b57cec5SDimitry Andric     unsigned MaxR = getMaxCalleeSavedReg(CSI, HRI);
14420b57cec5SDimitry Andric     SpillKind Kind = HasTC ? SK_FromMemTailcall : SK_FromMem;
14430b57cec5SDimitry Andric     const char *RestoreFn = getSpillFunctionFor(MaxR, Kind);
14440b57cec5SDimitry Andric     auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget());
14450b57cec5SDimitry Andric     bool IsPIC = HTM.isPositionIndependent();
14460b57cec5SDimitry Andric     bool LongCalls = HST.useLongCalls() || EnableSaveRestoreLong;
14470b57cec5SDimitry Andric 
14480b57cec5SDimitry Andric     // Call spill function.
14490b57cec5SDimitry Andric     DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc()
14500b57cec5SDimitry Andric                                   : MBB.findDebugLoc(MBB.end());
14510b57cec5SDimitry Andric     MachineInstr *DeallocCall = nullptr;
14520b57cec5SDimitry Andric 
14530b57cec5SDimitry Andric     if (HasTC) {
14540b57cec5SDimitry Andric       unsigned RetOpc;
14550b57cec5SDimitry Andric       if (LongCalls)
14560b57cec5SDimitry Andric         RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC
14570b57cec5SDimitry Andric                        : Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT;
14580b57cec5SDimitry Andric       else
14590b57cec5SDimitry Andric         RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC
14600b57cec5SDimitry Andric                        : Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4;
14610b57cec5SDimitry Andric       DeallocCall = BuildMI(MBB, MI, DL, HII.get(RetOpc))
14620b57cec5SDimitry Andric           .addExternalSymbol(RestoreFn);
14630b57cec5SDimitry Andric     } else {
14640b57cec5SDimitry Andric       // The block has a return.
14650b57cec5SDimitry Andric       MachineBasicBlock::iterator It = MBB.getFirstTerminator();
14660b57cec5SDimitry Andric       assert(It->isReturn() && std::next(It) == MBB.end());
14670b57cec5SDimitry Andric       unsigned RetOpc;
14680b57cec5SDimitry Andric       if (LongCalls)
14690b57cec5SDimitry Andric         RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC
14700b57cec5SDimitry Andric                        : Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT;
14710b57cec5SDimitry Andric       else
14720b57cec5SDimitry Andric         RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC
14730b57cec5SDimitry Andric                        : Hexagon::RESTORE_DEALLOC_RET_JMP_V4;
14740b57cec5SDimitry Andric       DeallocCall = BuildMI(MBB, It, DL, HII.get(RetOpc))
14750b57cec5SDimitry Andric           .addExternalSymbol(RestoreFn);
14760b57cec5SDimitry Andric       // Transfer the function live-out registers.
14770b57cec5SDimitry Andric       DeallocCall->copyImplicitOps(MF, *It);
14780b57cec5SDimitry Andric     }
14790b57cec5SDimitry Andric     addCalleeSaveRegistersAsImpOperand(DeallocCall, CSI, true, false);
14800b57cec5SDimitry Andric     return true;
14810b57cec5SDimitry Andric   }
14820b57cec5SDimitry Andric 
14830b57cec5SDimitry Andric   for (unsigned i = 0; i < CSI.size(); ++i) {
14840b57cec5SDimitry Andric     unsigned Reg = CSI[i].getReg();
14850b57cec5SDimitry Andric     const TargetRegisterClass *RC = HRI.getMinimalPhysRegClass(Reg);
14860b57cec5SDimitry Andric     int FI = CSI[i].getFrameIdx();
14870b57cec5SDimitry Andric     HII.loadRegFromStackSlot(MBB, MI, Reg, FI, RC, &HRI);
14880b57cec5SDimitry Andric   }
14890b57cec5SDimitry Andric 
14900b57cec5SDimitry Andric   return true;
14910b57cec5SDimitry Andric }
14920b57cec5SDimitry Andric 
14930b57cec5SDimitry Andric MachineBasicBlock::iterator HexagonFrameLowering::eliminateCallFramePseudoInstr(
14940b57cec5SDimitry Andric     MachineFunction &MF, MachineBasicBlock &MBB,
14950b57cec5SDimitry Andric     MachineBasicBlock::iterator I) const {
14960b57cec5SDimitry Andric   MachineInstr &MI = *I;
14970b57cec5SDimitry Andric   unsigned Opc = MI.getOpcode();
14980b57cec5SDimitry Andric   (void)Opc; // Silence compiler warning.
14990b57cec5SDimitry Andric   assert((Opc == Hexagon::ADJCALLSTACKDOWN || Opc == Hexagon::ADJCALLSTACKUP) &&
15000b57cec5SDimitry Andric          "Cannot handle this call frame pseudo instruction");
15010b57cec5SDimitry Andric   return MBB.erase(I);
15020b57cec5SDimitry Andric }
15030b57cec5SDimitry Andric 
15040b57cec5SDimitry Andric void HexagonFrameLowering::processFunctionBeforeFrameFinalized(
15050b57cec5SDimitry Andric     MachineFunction &MF, RegScavenger *RS) const {
15060b57cec5SDimitry Andric   // If this function has uses aligned stack and also has variable sized stack
15070b57cec5SDimitry Andric   // objects, then we need to map all spill slots to fixed positions, so that
15080b57cec5SDimitry Andric   // they can be accessed through FP. Otherwise they would have to be accessed
15090b57cec5SDimitry Andric   // via AP, which may not be available at the particular place in the program.
15100b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
15110b57cec5SDimitry Andric   bool HasAlloca = MFI.hasVarSizedObjects();
15125ffd83dbSDimitry Andric   bool NeedsAlign = (MFI.getMaxAlign() > getStackAlign());
15130b57cec5SDimitry Andric 
15140b57cec5SDimitry Andric   if (!HasAlloca || !NeedsAlign)
15150b57cec5SDimitry Andric     return;
15160b57cec5SDimitry Andric 
1517480093f4SDimitry Andric   SmallSet<int, 4> DealignSlots;
15180b57cec5SDimitry Andric   unsigned LFS = MFI.getLocalFrameSize();
15190b57cec5SDimitry Andric   for (int i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {
15200b57cec5SDimitry Andric     if (!MFI.isSpillSlotObjectIndex(i) || MFI.isDeadObjectIndex(i))
15210b57cec5SDimitry Andric       continue;
15220b57cec5SDimitry Andric     unsigned S = MFI.getObjectSize(i);
15230b57cec5SDimitry Andric     // Reduce the alignment to at most 8. This will require unaligned vector
15240b57cec5SDimitry Andric     // stores if they happen here.
15255ffd83dbSDimitry Andric     Align A = std::max(MFI.getObjectAlign(i), Align(8));
15265ffd83dbSDimitry Andric     MFI.setObjectAlignment(i, Align(8));
15270b57cec5SDimitry Andric     LFS = alignTo(LFS+S, A);
1528480093f4SDimitry Andric     MFI.mapLocalFrameObject(i, -static_cast<int64_t>(LFS));
1529480093f4SDimitry Andric     DealignSlots.insert(i);
15300b57cec5SDimitry Andric   }
15310b57cec5SDimitry Andric 
15320b57cec5SDimitry Andric   MFI.setLocalFrameSize(LFS);
15338bcb0991SDimitry Andric   Align A = MFI.getLocalFrameMaxAlign();
15340b57cec5SDimitry Andric   assert(A <= 8 && "Unexpected local frame alignment");
15358bcb0991SDimitry Andric   if (A == 1)
15368bcb0991SDimitry Andric     MFI.setLocalFrameMaxAlign(Align(8));
15370b57cec5SDimitry Andric   MFI.setUseLocalStackAllocationBlock(true);
15380b57cec5SDimitry Andric 
1539480093f4SDimitry Andric   // Go over all MachineMemOperands in the code, and change the ones that
1540480093f4SDimitry Andric   // refer to the dealigned stack slots to reflect the new alignment.
1541480093f4SDimitry Andric   if (!DealignSlots.empty()) {
1542480093f4SDimitry Andric     for (MachineBasicBlock &BB : MF) {
1543480093f4SDimitry Andric       for (MachineInstr &MI : BB) {
1544480093f4SDimitry Andric         bool KeepOld = true;
1545480093f4SDimitry Andric         ArrayRef<MachineMemOperand*> memops = MI.memoperands();
1546480093f4SDimitry Andric         SmallVector<MachineMemOperand*,1> new_memops;
1547480093f4SDimitry Andric         for (MachineMemOperand *MMO : memops) {
1548480093f4SDimitry Andric           auto *PV = MMO->getPseudoValue();
1549480093f4SDimitry Andric           if (auto *FS = dyn_cast_or_null<FixedStackPseudoSourceValue>(PV)) {
1550480093f4SDimitry Andric             int FI = FS->getFrameIndex();
1551480093f4SDimitry Andric             if (DealignSlots.count(FI)) {
15525ffd83dbSDimitry Andric               auto *NewMMO = MF.getMachineMemOperand(
15535ffd83dbSDimitry Andric                   MMO->getPointerInfo(), MMO->getFlags(), MMO->getSize(),
15545ffd83dbSDimitry Andric                   MFI.getObjectAlign(FI), MMO->getAAInfo(), MMO->getRanges(),
1555*fe6060f1SDimitry Andric                   MMO->getSyncScopeID(), MMO->getSuccessOrdering(),
1556480093f4SDimitry Andric                   MMO->getFailureOrdering());
1557480093f4SDimitry Andric               new_memops.push_back(NewMMO);
1558480093f4SDimitry Andric               KeepOld = false;
1559480093f4SDimitry Andric               continue;
1560480093f4SDimitry Andric             }
1561480093f4SDimitry Andric           }
1562480093f4SDimitry Andric           new_memops.push_back(MMO);
1563480093f4SDimitry Andric         }
1564480093f4SDimitry Andric         if (!KeepOld)
1565480093f4SDimitry Andric           MI.setMemRefs(MF, new_memops);
1566480093f4SDimitry Andric       }
1567480093f4SDimitry Andric     }
1568480093f4SDimitry Andric   }
1569480093f4SDimitry Andric 
15700b57cec5SDimitry Andric   // Set the physical aligned-stack base address register.
15710b57cec5SDimitry Andric   unsigned AP = 0;
15720b57cec5SDimitry Andric   if (const MachineInstr *AI = getAlignaInstr(MF))
15730b57cec5SDimitry Andric     AP = AI->getOperand(0).getReg();
15740b57cec5SDimitry Andric   auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
15750b57cec5SDimitry Andric   HMFI.setStackAlignBasePhysReg(AP);
15760b57cec5SDimitry Andric }
15770b57cec5SDimitry Andric 
15780b57cec5SDimitry Andric /// Returns true if there are no caller-saved registers available in class RC.
15790b57cec5SDimitry Andric static bool needToReserveScavengingSpillSlots(MachineFunction &MF,
15800b57cec5SDimitry Andric       const HexagonRegisterInfo &HRI, const TargetRegisterClass *RC) {
15810b57cec5SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
15820b57cec5SDimitry Andric 
15830b57cec5SDimitry Andric   auto IsUsed = [&HRI,&MRI] (unsigned Reg) -> bool {
15840b57cec5SDimitry Andric     for (MCRegAliasIterator AI(Reg, &HRI, true); AI.isValid(); ++AI)
15850b57cec5SDimitry Andric       if (MRI.isPhysRegUsed(*AI))
15860b57cec5SDimitry Andric         return true;
15870b57cec5SDimitry Andric     return false;
15880b57cec5SDimitry Andric   };
15890b57cec5SDimitry Andric 
15900b57cec5SDimitry Andric   // Check for an unused caller-saved register. Callee-saved registers
15910b57cec5SDimitry Andric   // have become pristine by now.
15920b57cec5SDimitry Andric   for (const MCPhysReg *P = HRI.getCallerSavedRegs(&MF, RC); *P; ++P)
15930b57cec5SDimitry Andric     if (!IsUsed(*P))
15940b57cec5SDimitry Andric       return false;
15950b57cec5SDimitry Andric 
15960b57cec5SDimitry Andric   // All caller-saved registers are used.
15970b57cec5SDimitry Andric   return true;
15980b57cec5SDimitry Andric }
15990b57cec5SDimitry Andric 
16000b57cec5SDimitry Andric #ifndef NDEBUG
16010b57cec5SDimitry Andric static void dump_registers(BitVector &Regs, const TargetRegisterInfo &TRI) {
16020b57cec5SDimitry Andric   dbgs() << '{';
16030b57cec5SDimitry Andric   for (int x = Regs.find_first(); x >= 0; x = Regs.find_next(x)) {
16040b57cec5SDimitry Andric     unsigned R = x;
16050b57cec5SDimitry Andric     dbgs() << ' ' << printReg(R, &TRI);
16060b57cec5SDimitry Andric   }
16070b57cec5SDimitry Andric   dbgs() << " }";
16080b57cec5SDimitry Andric }
16090b57cec5SDimitry Andric #endif
16100b57cec5SDimitry Andric 
16110b57cec5SDimitry Andric bool HexagonFrameLowering::assignCalleeSavedSpillSlots(MachineFunction &MF,
16120b57cec5SDimitry Andric       const TargetRegisterInfo *TRI, std::vector<CalleeSavedInfo> &CSI) const {
16130b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << __func__ << " on " << MF.getName() << '\n');
16140b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
16150b57cec5SDimitry Andric   BitVector SRegs(Hexagon::NUM_TARGET_REGS);
16160b57cec5SDimitry Andric 
16170b57cec5SDimitry Andric   // Generate a set of unique, callee-saved registers (SRegs), where each
16180b57cec5SDimitry Andric   // register in the set is maximal in terms of sub-/super-register relation,
16190b57cec5SDimitry Andric   // i.e. for each R in SRegs, no proper super-register of R is also in SRegs.
16200b57cec5SDimitry Andric 
16210b57cec5SDimitry Andric   // (1) For each callee-saved register, add that register and all of its
16220b57cec5SDimitry Andric   // sub-registers to SRegs.
16230b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Initial CS registers: {");
16240b57cec5SDimitry Andric   for (unsigned i = 0, n = CSI.size(); i < n; ++i) {
16250b57cec5SDimitry Andric     unsigned R = CSI[i].getReg();
16260b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ' ' << printReg(R, TRI));
16270b57cec5SDimitry Andric     for (MCSubRegIterator SR(R, TRI, true); SR.isValid(); ++SR)
16280b57cec5SDimitry Andric       SRegs[*SR] = true;
16290b57cec5SDimitry Andric   }
16300b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << " }\n");
16310b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "SRegs.1: "; dump_registers(SRegs, *TRI);
16320b57cec5SDimitry Andric              dbgs() << "\n");
16330b57cec5SDimitry Andric 
16340b57cec5SDimitry Andric   // (2) For each reserved register, remove that register and all of its
16350b57cec5SDimitry Andric   // sub- and super-registers from SRegs.
16360b57cec5SDimitry Andric   BitVector Reserved = TRI->getReservedRegs(MF);
16370b57cec5SDimitry Andric   for (int x = Reserved.find_first(); x >= 0; x = Reserved.find_next(x)) {
16380b57cec5SDimitry Andric     unsigned R = x;
16390b57cec5SDimitry Andric     for (MCSuperRegIterator SR(R, TRI, true); SR.isValid(); ++SR)
16400b57cec5SDimitry Andric       SRegs[*SR] = false;
16410b57cec5SDimitry Andric   }
16420b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Res:     "; dump_registers(Reserved, *TRI);
16430b57cec5SDimitry Andric              dbgs() << "\n");
16440b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "SRegs.2: "; dump_registers(SRegs, *TRI);
16450b57cec5SDimitry Andric              dbgs() << "\n");
16460b57cec5SDimitry Andric 
16470b57cec5SDimitry Andric   // (3) Collect all registers that have at least one sub-register in SRegs,
16480b57cec5SDimitry Andric   // and also have no sub-registers that are reserved. These will be the can-
16490b57cec5SDimitry Andric   // didates for saving as a whole instead of their individual sub-registers.
16500b57cec5SDimitry Andric   // (Saving R17:16 instead of R16 is fine, but only if R17 was not reserved.)
16510b57cec5SDimitry Andric   BitVector TmpSup(Hexagon::NUM_TARGET_REGS);
16520b57cec5SDimitry Andric   for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) {
16530b57cec5SDimitry Andric     unsigned R = x;
16540b57cec5SDimitry Andric     for (MCSuperRegIterator SR(R, TRI); SR.isValid(); ++SR)
16550b57cec5SDimitry Andric       TmpSup[*SR] = true;
16560b57cec5SDimitry Andric   }
16570b57cec5SDimitry Andric   for (int x = TmpSup.find_first(); x >= 0; x = TmpSup.find_next(x)) {
16580b57cec5SDimitry Andric     unsigned R = x;
16590b57cec5SDimitry Andric     for (MCSubRegIterator SR(R, TRI, true); SR.isValid(); ++SR) {
16600b57cec5SDimitry Andric       if (!Reserved[*SR])
16610b57cec5SDimitry Andric         continue;
16620b57cec5SDimitry Andric       TmpSup[R] = false;
16630b57cec5SDimitry Andric       break;
16640b57cec5SDimitry Andric     }
16650b57cec5SDimitry Andric   }
16660b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "TmpSup:  "; dump_registers(TmpSup, *TRI);
16670b57cec5SDimitry Andric              dbgs() << "\n");
16680b57cec5SDimitry Andric 
16690b57cec5SDimitry Andric   // (4) Include all super-registers found in (3) into SRegs.
16700b57cec5SDimitry Andric   SRegs |= TmpSup;
16710b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "SRegs.4: "; dump_registers(SRegs, *TRI);
16720b57cec5SDimitry Andric              dbgs() << "\n");
16730b57cec5SDimitry Andric 
16740b57cec5SDimitry Andric   // (5) For each register R in SRegs, if any super-register of R is in SRegs,
16750b57cec5SDimitry Andric   // remove R from SRegs.
16760b57cec5SDimitry Andric   for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) {
16770b57cec5SDimitry Andric     unsigned R = x;
16780b57cec5SDimitry Andric     for (MCSuperRegIterator SR(R, TRI); SR.isValid(); ++SR) {
16790b57cec5SDimitry Andric       if (!SRegs[*SR])
16800b57cec5SDimitry Andric         continue;
16810b57cec5SDimitry Andric       SRegs[R] = false;
16820b57cec5SDimitry Andric       break;
16830b57cec5SDimitry Andric     }
16840b57cec5SDimitry Andric   }
16850b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "SRegs.5: "; dump_registers(SRegs, *TRI);
16860b57cec5SDimitry Andric              dbgs() << "\n");
16870b57cec5SDimitry Andric 
16880b57cec5SDimitry Andric   // Now, for each register that has a fixed stack slot, create the stack
16890b57cec5SDimitry Andric   // object for it.
16900b57cec5SDimitry Andric   CSI.clear();
16910b57cec5SDimitry Andric 
16920b57cec5SDimitry Andric   using SpillSlot = TargetFrameLowering::SpillSlot;
16930b57cec5SDimitry Andric 
16940b57cec5SDimitry Andric   unsigned NumFixed;
16950b57cec5SDimitry Andric   int MinOffset = 0;  // CS offsets are negative.
16960b57cec5SDimitry Andric   const SpillSlot *FixedSlots = getCalleeSavedSpillSlots(NumFixed);
16970b57cec5SDimitry Andric   for (const SpillSlot *S = FixedSlots; S != FixedSlots+NumFixed; ++S) {
16980b57cec5SDimitry Andric     if (!SRegs[S->Reg])
16990b57cec5SDimitry Andric       continue;
17000b57cec5SDimitry Andric     const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(S->Reg);
17010b57cec5SDimitry Andric     int FI = MFI.CreateFixedSpillStackObject(TRI->getSpillSize(*RC), S->Offset);
17020b57cec5SDimitry Andric     MinOffset = std::min(MinOffset, S->Offset);
17030b57cec5SDimitry Andric     CSI.push_back(CalleeSavedInfo(S->Reg, FI));
17040b57cec5SDimitry Andric     SRegs[S->Reg] = false;
17050b57cec5SDimitry Andric   }
17060b57cec5SDimitry Andric 
17070b57cec5SDimitry Andric   // There can be some registers that don't have fixed slots. For example,
17080b57cec5SDimitry Andric   // we need to store R0-R3 in functions with exception handling. For each
17090b57cec5SDimitry Andric   // such register, create a non-fixed stack object.
17100b57cec5SDimitry Andric   for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) {
17110b57cec5SDimitry Andric     unsigned R = x;
17120b57cec5SDimitry Andric     const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(R);
17130b57cec5SDimitry Andric     unsigned Size = TRI->getSpillSize(*RC);
17140b57cec5SDimitry Andric     int Off = MinOffset - Size;
17155ffd83dbSDimitry Andric     Align Alignment = std::min(TRI->getSpillAlign(*RC), getStackAlign());
17165ffd83dbSDimitry Andric     Off &= -Alignment.value();
17170b57cec5SDimitry Andric     int FI = MFI.CreateFixedSpillStackObject(Size, Off);
17180b57cec5SDimitry Andric     MinOffset = std::min(MinOffset, Off);
17190b57cec5SDimitry Andric     CSI.push_back(CalleeSavedInfo(R, FI));
17200b57cec5SDimitry Andric     SRegs[R] = false;
17210b57cec5SDimitry Andric   }
17220b57cec5SDimitry Andric 
17230b57cec5SDimitry Andric   LLVM_DEBUG({
17240b57cec5SDimitry Andric     dbgs() << "CS information: {";
17250b57cec5SDimitry Andric     for (unsigned i = 0, n = CSI.size(); i < n; ++i) {
17260b57cec5SDimitry Andric       int FI = CSI[i].getFrameIdx();
17270b57cec5SDimitry Andric       int Off = MFI.getObjectOffset(FI);
17280b57cec5SDimitry Andric       dbgs() << ' ' << printReg(CSI[i].getReg(), TRI) << ":fi#" << FI << ":sp";
17290b57cec5SDimitry Andric       if (Off >= 0)
17300b57cec5SDimitry Andric         dbgs() << '+';
17310b57cec5SDimitry Andric       dbgs() << Off;
17320b57cec5SDimitry Andric     }
17330b57cec5SDimitry Andric     dbgs() << " }\n";
17340b57cec5SDimitry Andric   });
17350b57cec5SDimitry Andric 
17360b57cec5SDimitry Andric #ifndef NDEBUG
17370b57cec5SDimitry Andric   // Verify that all registers were handled.
17380b57cec5SDimitry Andric   bool MissedReg = false;
17390b57cec5SDimitry Andric   for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) {
17400b57cec5SDimitry Andric     unsigned R = x;
17410b57cec5SDimitry Andric     dbgs() << printReg(R, TRI) << ' ';
17420b57cec5SDimitry Andric     MissedReg = true;
17430b57cec5SDimitry Andric   }
17440b57cec5SDimitry Andric   if (MissedReg)
17450b57cec5SDimitry Andric     llvm_unreachable("...there are unhandled callee-saved registers!");
17460b57cec5SDimitry Andric #endif
17470b57cec5SDimitry Andric 
17480b57cec5SDimitry Andric   return true;
17490b57cec5SDimitry Andric }
17500b57cec5SDimitry Andric 
17510b57cec5SDimitry Andric bool HexagonFrameLowering::expandCopy(MachineBasicBlock &B,
17520b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
17530b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
17540b57cec5SDimitry Andric   MachineInstr *MI = &*It;
17550b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
17568bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
17578bcb0991SDimitry Andric   Register SrcR = MI->getOperand(1).getReg();
17580b57cec5SDimitry Andric   if (!Hexagon::ModRegsRegClass.contains(DstR) ||
17590b57cec5SDimitry Andric       !Hexagon::ModRegsRegClass.contains(SrcR))
17600b57cec5SDimitry Andric     return false;
17610b57cec5SDimitry Andric 
17628bcb0991SDimitry Andric   Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
17630b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(TargetOpcode::COPY), TmpR).add(MI->getOperand(1));
17640b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(TargetOpcode::COPY), DstR)
17650b57cec5SDimitry Andric     .addReg(TmpR, RegState::Kill);
17660b57cec5SDimitry Andric 
17670b57cec5SDimitry Andric   NewRegs.push_back(TmpR);
17680b57cec5SDimitry Andric   B.erase(It);
17690b57cec5SDimitry Andric   return true;
17700b57cec5SDimitry Andric }
17710b57cec5SDimitry Andric 
17720b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreInt(MachineBasicBlock &B,
17730b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
17740b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
17750b57cec5SDimitry Andric   MachineInstr *MI = &*It;
17760b57cec5SDimitry Andric   if (!MI->getOperand(0).isFI())
17770b57cec5SDimitry Andric     return false;
17780b57cec5SDimitry Andric 
17790b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
17800b57cec5SDimitry Andric   unsigned Opc = MI->getOpcode();
17818bcb0991SDimitry Andric   Register SrcR = MI->getOperand(2).getReg();
17820b57cec5SDimitry Andric   bool IsKill = MI->getOperand(2).isKill();
17830b57cec5SDimitry Andric   int FI = MI->getOperand(0).getIndex();
17840b57cec5SDimitry Andric 
17850b57cec5SDimitry Andric   // TmpR = C2_tfrpr SrcR   if SrcR is a predicate register
17860b57cec5SDimitry Andric   // TmpR = A2_tfrcrr SrcR  if SrcR is a modifier register
17878bcb0991SDimitry Andric   Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
17880b57cec5SDimitry Andric   unsigned TfrOpc = (Opc == Hexagon::STriw_pred) ? Hexagon::C2_tfrpr
17890b57cec5SDimitry Andric                                                  : Hexagon::A2_tfrcrr;
17900b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(TfrOpc), TmpR)
17910b57cec5SDimitry Andric     .addReg(SrcR, getKillRegState(IsKill));
17920b57cec5SDimitry Andric 
17930b57cec5SDimitry Andric   // S2_storeri_io FI, 0, TmpR
17940b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::S2_storeri_io))
17950b57cec5SDimitry Andric       .addFrameIndex(FI)
17960b57cec5SDimitry Andric       .addImm(0)
17970b57cec5SDimitry Andric       .addReg(TmpR, RegState::Kill)
17980b57cec5SDimitry Andric       .cloneMemRefs(*MI);
17990b57cec5SDimitry Andric 
18000b57cec5SDimitry Andric   NewRegs.push_back(TmpR);
18010b57cec5SDimitry Andric   B.erase(It);
18020b57cec5SDimitry Andric   return true;
18030b57cec5SDimitry Andric }
18040b57cec5SDimitry Andric 
18050b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadInt(MachineBasicBlock &B,
18060b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
18070b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
18080b57cec5SDimitry Andric   MachineInstr *MI = &*It;
18090b57cec5SDimitry Andric   if (!MI->getOperand(1).isFI())
18100b57cec5SDimitry Andric     return false;
18110b57cec5SDimitry Andric 
18120b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
18130b57cec5SDimitry Andric   unsigned Opc = MI->getOpcode();
18148bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
18150b57cec5SDimitry Andric   int FI = MI->getOperand(1).getIndex();
18160b57cec5SDimitry Andric 
18170b57cec5SDimitry Andric   // TmpR = L2_loadri_io FI, 0
18188bcb0991SDimitry Andric   Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
18190b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::L2_loadri_io), TmpR)
18200b57cec5SDimitry Andric       .addFrameIndex(FI)
18210b57cec5SDimitry Andric       .addImm(0)
18220b57cec5SDimitry Andric       .cloneMemRefs(*MI);
18230b57cec5SDimitry Andric 
18240b57cec5SDimitry Andric   // DstR = C2_tfrrp TmpR   if DstR is a predicate register
18250b57cec5SDimitry Andric   // DstR = A2_tfrrcr TmpR  if DstR is a modifier register
18260b57cec5SDimitry Andric   unsigned TfrOpc = (Opc == Hexagon::LDriw_pred) ? Hexagon::C2_tfrrp
18270b57cec5SDimitry Andric                                                  : Hexagon::A2_tfrrcr;
18280b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(TfrOpc), DstR)
18290b57cec5SDimitry Andric     .addReg(TmpR, RegState::Kill);
18300b57cec5SDimitry Andric 
18310b57cec5SDimitry Andric   NewRegs.push_back(TmpR);
18320b57cec5SDimitry Andric   B.erase(It);
18330b57cec5SDimitry Andric   return true;
18340b57cec5SDimitry Andric }
18350b57cec5SDimitry Andric 
18360b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVecPred(MachineBasicBlock &B,
18370b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
18380b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
18390b57cec5SDimitry Andric   MachineInstr *MI = &*It;
18400b57cec5SDimitry Andric   if (!MI->getOperand(0).isFI())
18410b57cec5SDimitry Andric     return false;
18420b57cec5SDimitry Andric 
18430b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
18448bcb0991SDimitry Andric   Register SrcR = MI->getOperand(2).getReg();
18450b57cec5SDimitry Andric   bool IsKill = MI->getOperand(2).isKill();
18460b57cec5SDimitry Andric   int FI = MI->getOperand(0).getIndex();
18470b57cec5SDimitry Andric   auto *RC = &Hexagon::HvxVRRegClass;
18480b57cec5SDimitry Andric 
18490b57cec5SDimitry Andric   // Insert transfer to general vector register.
18500b57cec5SDimitry Andric   //   TmpR0 = A2_tfrsi 0x01010101
18510b57cec5SDimitry Andric   //   TmpR1 = V6_vandqrt Qx, TmpR0
18520b57cec5SDimitry Andric   //   store FI, 0, TmpR1
18538bcb0991SDimitry Andric   Register TmpR0 = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
18548bcb0991SDimitry Andric   Register TmpR1 = MRI.createVirtualRegister(RC);
18550b57cec5SDimitry Andric 
18560b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::A2_tfrsi), TmpR0)
18570b57cec5SDimitry Andric     .addImm(0x01010101);
18580b57cec5SDimitry Andric 
18590b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::V6_vandqrt), TmpR1)
18600b57cec5SDimitry Andric     .addReg(SrcR, getKillRegState(IsKill))
18610b57cec5SDimitry Andric     .addReg(TmpR0, RegState::Kill);
18620b57cec5SDimitry Andric 
18630b57cec5SDimitry Andric   auto *HRI = B.getParent()->getSubtarget<HexagonSubtarget>().getRegisterInfo();
18640b57cec5SDimitry Andric   HII.storeRegToStackSlot(B, It, TmpR1, true, FI, RC, HRI);
18650b57cec5SDimitry Andric   expandStoreVec(B, std::prev(It), MRI, HII, NewRegs);
18660b57cec5SDimitry Andric 
18670b57cec5SDimitry Andric   NewRegs.push_back(TmpR0);
18680b57cec5SDimitry Andric   NewRegs.push_back(TmpR1);
18690b57cec5SDimitry Andric   B.erase(It);
18700b57cec5SDimitry Andric   return true;
18710b57cec5SDimitry Andric }
18720b57cec5SDimitry Andric 
18730b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVecPred(MachineBasicBlock &B,
18740b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
18750b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
18760b57cec5SDimitry Andric   MachineInstr *MI = &*It;
18770b57cec5SDimitry Andric   if (!MI->getOperand(1).isFI())
18780b57cec5SDimitry Andric     return false;
18790b57cec5SDimitry Andric 
18800b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
18818bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
18820b57cec5SDimitry Andric   int FI = MI->getOperand(1).getIndex();
18830b57cec5SDimitry Andric   auto *RC = &Hexagon::HvxVRRegClass;
18840b57cec5SDimitry Andric 
18850b57cec5SDimitry Andric   // TmpR0 = A2_tfrsi 0x01010101
18860b57cec5SDimitry Andric   // TmpR1 = load FI, 0
18870b57cec5SDimitry Andric   // DstR = V6_vandvrt TmpR1, TmpR0
18888bcb0991SDimitry Andric   Register TmpR0 = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
18898bcb0991SDimitry Andric   Register TmpR1 = MRI.createVirtualRegister(RC);
18900b57cec5SDimitry Andric 
18910b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::A2_tfrsi), TmpR0)
18920b57cec5SDimitry Andric     .addImm(0x01010101);
18930b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
18940b57cec5SDimitry Andric   auto *HRI = MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
18950b57cec5SDimitry Andric   HII.loadRegFromStackSlot(B, It, TmpR1, FI, RC, HRI);
18960b57cec5SDimitry Andric   expandLoadVec(B, std::prev(It), MRI, HII, NewRegs);
18970b57cec5SDimitry Andric 
18980b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::V6_vandvrt), DstR)
18990b57cec5SDimitry Andric     .addReg(TmpR1, RegState::Kill)
19000b57cec5SDimitry Andric     .addReg(TmpR0, RegState::Kill);
19010b57cec5SDimitry Andric 
19020b57cec5SDimitry Andric   NewRegs.push_back(TmpR0);
19030b57cec5SDimitry Andric   NewRegs.push_back(TmpR1);
19040b57cec5SDimitry Andric   B.erase(It);
19050b57cec5SDimitry Andric   return true;
19060b57cec5SDimitry Andric }
19070b57cec5SDimitry Andric 
19080b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVec2(MachineBasicBlock &B,
19090b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
19100b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
19110b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
19120b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
19130b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
19140b57cec5SDimitry Andric   MachineInstr *MI = &*It;
19150b57cec5SDimitry Andric   if (!MI->getOperand(0).isFI())
19160b57cec5SDimitry Andric     return false;
19170b57cec5SDimitry Andric 
19180b57cec5SDimitry Andric   // It is possible that the double vector being stored is only partially
19190b57cec5SDimitry Andric   // defined. From the point of view of the liveness tracking, it is ok to
19200b57cec5SDimitry Andric   // store it as a whole, but if we break it up we may end up storing a
19210b57cec5SDimitry Andric   // register that is entirely undefined.
19220b57cec5SDimitry Andric   LivePhysRegs LPR(HRI);
19230b57cec5SDimitry Andric   LPR.addLiveIns(B);
19240b57cec5SDimitry Andric   SmallVector<std::pair<MCPhysReg, const MachineOperand*>,2> Clobbers;
19250b57cec5SDimitry Andric   for (auto R = B.begin(); R != It; ++R) {
19260b57cec5SDimitry Andric     Clobbers.clear();
19270b57cec5SDimitry Andric     LPR.stepForward(*R, Clobbers);
19280b57cec5SDimitry Andric   }
19290b57cec5SDimitry Andric 
19300b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
19318bcb0991SDimitry Andric   Register SrcR = MI->getOperand(2).getReg();
19328bcb0991SDimitry Andric   Register SrcLo = HRI.getSubReg(SrcR, Hexagon::vsub_lo);
19338bcb0991SDimitry Andric   Register SrcHi = HRI.getSubReg(SrcR, Hexagon::vsub_hi);
19340b57cec5SDimitry Andric   bool IsKill = MI->getOperand(2).isKill();
19350b57cec5SDimitry Andric   int FI = MI->getOperand(0).getIndex();
1936480093f4SDimitry Andric   bool NeedsAligna = needsAligna(MF);
19370b57cec5SDimitry Andric 
19380b57cec5SDimitry Andric   unsigned Size = HRI.getSpillSize(Hexagon::HvxVRRegClass);
19395ffd83dbSDimitry Andric   Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass);
19405ffd83dbSDimitry Andric   Align HasAlign = MFI.getObjectAlign(FI);
19410b57cec5SDimitry Andric   unsigned StoreOpc;
19420b57cec5SDimitry Andric 
19435ffd83dbSDimitry Andric   auto UseAligned = [&](Align NeedAlign, Align HasAlign) {
1944480093f4SDimitry Andric     return !NeedsAligna && (NeedAlign <= HasAlign);
1945480093f4SDimitry Andric   };
1946480093f4SDimitry Andric 
19470b57cec5SDimitry Andric   // Store low part.
19480b57cec5SDimitry Andric   if (LPR.contains(SrcLo)) {
1949480093f4SDimitry Andric     StoreOpc = UseAligned(NeedAlign, HasAlign) ? Hexagon::V6_vS32b_ai
19500b57cec5SDimitry Andric                                                : Hexagon::V6_vS32Ub_ai;
19510b57cec5SDimitry Andric     BuildMI(B, It, DL, HII.get(StoreOpc))
19520b57cec5SDimitry Andric         .addFrameIndex(FI)
19530b57cec5SDimitry Andric         .addImm(0)
19540b57cec5SDimitry Andric         .addReg(SrcLo, getKillRegState(IsKill))
19550b57cec5SDimitry Andric         .cloneMemRefs(*MI);
19560b57cec5SDimitry Andric   }
19570b57cec5SDimitry Andric 
19580b57cec5SDimitry Andric   // Store high part.
19590b57cec5SDimitry Andric   if (LPR.contains(SrcHi)) {
1960480093f4SDimitry Andric     StoreOpc = UseAligned(NeedAlign, HasAlign) ? Hexagon::V6_vS32b_ai
19610b57cec5SDimitry Andric                                                : Hexagon::V6_vS32Ub_ai;
19620b57cec5SDimitry Andric     BuildMI(B, It, DL, HII.get(StoreOpc))
19630b57cec5SDimitry Andric         .addFrameIndex(FI)
19640b57cec5SDimitry Andric         .addImm(Size)
19650b57cec5SDimitry Andric         .addReg(SrcHi, getKillRegState(IsKill))
19660b57cec5SDimitry Andric         .cloneMemRefs(*MI);
19670b57cec5SDimitry Andric   }
19680b57cec5SDimitry Andric 
19690b57cec5SDimitry Andric   B.erase(It);
19700b57cec5SDimitry Andric   return true;
19710b57cec5SDimitry Andric }
19720b57cec5SDimitry Andric 
19730b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVec2(MachineBasicBlock &B,
19740b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
19750b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
19760b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
19770b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
19780b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
19790b57cec5SDimitry Andric   MachineInstr *MI = &*It;
19800b57cec5SDimitry Andric   if (!MI->getOperand(1).isFI())
19810b57cec5SDimitry Andric     return false;
19820b57cec5SDimitry Andric 
19830b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
19848bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
19858bcb0991SDimitry Andric   Register DstHi = HRI.getSubReg(DstR, Hexagon::vsub_hi);
19868bcb0991SDimitry Andric   Register DstLo = HRI.getSubReg(DstR, Hexagon::vsub_lo);
19870b57cec5SDimitry Andric   int FI = MI->getOperand(1).getIndex();
1988480093f4SDimitry Andric   bool NeedsAligna = needsAligna(MF);
19890b57cec5SDimitry Andric 
19900b57cec5SDimitry Andric   unsigned Size = HRI.getSpillSize(Hexagon::HvxVRRegClass);
19915ffd83dbSDimitry Andric   Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass);
19925ffd83dbSDimitry Andric   Align HasAlign = MFI.getObjectAlign(FI);
19930b57cec5SDimitry Andric   unsigned LoadOpc;
19940b57cec5SDimitry Andric 
19955ffd83dbSDimitry Andric   auto UseAligned = [&](Align NeedAlign, Align HasAlign) {
1996480093f4SDimitry Andric     return !NeedsAligna && (NeedAlign <= HasAlign);
1997480093f4SDimitry Andric   };
1998480093f4SDimitry Andric 
19990b57cec5SDimitry Andric   // Load low part.
2000480093f4SDimitry Andric   LoadOpc = UseAligned(NeedAlign, HasAlign) ? Hexagon::V6_vL32b_ai
20010b57cec5SDimitry Andric                                             : Hexagon::V6_vL32Ub_ai;
20020b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(LoadOpc), DstLo)
20030b57cec5SDimitry Andric       .addFrameIndex(FI)
20040b57cec5SDimitry Andric       .addImm(0)
20050b57cec5SDimitry Andric       .cloneMemRefs(*MI);
20060b57cec5SDimitry Andric 
20070b57cec5SDimitry Andric   // Load high part.
2008480093f4SDimitry Andric   LoadOpc = UseAligned(NeedAlign, HasAlign) ? Hexagon::V6_vL32b_ai
20090b57cec5SDimitry Andric                                             : Hexagon::V6_vL32Ub_ai;
20100b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(LoadOpc), DstHi)
20110b57cec5SDimitry Andric       .addFrameIndex(FI)
20120b57cec5SDimitry Andric       .addImm(Size)
20130b57cec5SDimitry Andric       .cloneMemRefs(*MI);
20140b57cec5SDimitry Andric 
20150b57cec5SDimitry Andric   B.erase(It);
20160b57cec5SDimitry Andric   return true;
20170b57cec5SDimitry Andric }
20180b57cec5SDimitry Andric 
20190b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVec(MachineBasicBlock &B,
20200b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
20210b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
20220b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
20230b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
20240b57cec5SDimitry Andric   MachineInstr *MI = &*It;
20250b57cec5SDimitry Andric   if (!MI->getOperand(0).isFI())
20260b57cec5SDimitry Andric     return false;
20270b57cec5SDimitry Andric 
2028480093f4SDimitry Andric   bool NeedsAligna = needsAligna(MF);
20290b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
20300b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
20318bcb0991SDimitry Andric   Register SrcR = MI->getOperand(2).getReg();
20320b57cec5SDimitry Andric   bool IsKill = MI->getOperand(2).isKill();
20330b57cec5SDimitry Andric   int FI = MI->getOperand(0).getIndex();
20340b57cec5SDimitry Andric 
20355ffd83dbSDimitry Andric   Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass);
20365ffd83dbSDimitry Andric   Align HasAlign = MFI.getObjectAlign(FI);
2037480093f4SDimitry Andric   bool UseAligned = !NeedsAligna && (NeedAlign <= HasAlign);
2038480093f4SDimitry Andric   unsigned StoreOpc = UseAligned ? Hexagon::V6_vS32b_ai
20390b57cec5SDimitry Andric                                  : Hexagon::V6_vS32Ub_ai;
20400b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(StoreOpc))
20410b57cec5SDimitry Andric       .addFrameIndex(FI)
20420b57cec5SDimitry Andric       .addImm(0)
20430b57cec5SDimitry Andric       .addReg(SrcR, getKillRegState(IsKill))
20440b57cec5SDimitry Andric       .cloneMemRefs(*MI);
20450b57cec5SDimitry Andric 
20460b57cec5SDimitry Andric   B.erase(It);
20470b57cec5SDimitry Andric   return true;
20480b57cec5SDimitry Andric }
20490b57cec5SDimitry Andric 
20500b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVec(MachineBasicBlock &B,
20510b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
20520b57cec5SDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
20530b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
20540b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
20550b57cec5SDimitry Andric   MachineInstr *MI = &*It;
20560b57cec5SDimitry Andric   if (!MI->getOperand(1).isFI())
20570b57cec5SDimitry Andric     return false;
20580b57cec5SDimitry Andric 
2059480093f4SDimitry Andric   bool NeedsAligna = needsAligna(MF);
20600b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
20610b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
20628bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
20630b57cec5SDimitry Andric   int FI = MI->getOperand(1).getIndex();
20640b57cec5SDimitry Andric 
20655ffd83dbSDimitry Andric   Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass);
20665ffd83dbSDimitry Andric   Align HasAlign = MFI.getObjectAlign(FI);
2067480093f4SDimitry Andric   bool UseAligned = !NeedsAligna && (NeedAlign <= HasAlign);
2068480093f4SDimitry Andric   unsigned LoadOpc = UseAligned ? Hexagon::V6_vL32b_ai
20690b57cec5SDimitry Andric                                 : Hexagon::V6_vL32Ub_ai;
20700b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(LoadOpc), DstR)
20710b57cec5SDimitry Andric       .addFrameIndex(FI)
20720b57cec5SDimitry Andric       .addImm(0)
20730b57cec5SDimitry Andric       .cloneMemRefs(*MI);
20740b57cec5SDimitry Andric 
20750b57cec5SDimitry Andric   B.erase(It);
20760b57cec5SDimitry Andric   return true;
20770b57cec5SDimitry Andric }
20780b57cec5SDimitry Andric 
20790b57cec5SDimitry Andric bool HexagonFrameLowering::expandSpillMacros(MachineFunction &MF,
20800b57cec5SDimitry Andric       SmallVectorImpl<unsigned> &NewRegs) const {
20810b57cec5SDimitry Andric   auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
20820b57cec5SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
20830b57cec5SDimitry Andric   bool Changed = false;
20840b57cec5SDimitry Andric 
20850b57cec5SDimitry Andric   for (auto &B : MF) {
20860b57cec5SDimitry Andric     // Traverse the basic block.
20870b57cec5SDimitry Andric     MachineBasicBlock::iterator NextI;
20880b57cec5SDimitry Andric     for (auto I = B.begin(), E = B.end(); I != E; I = NextI) {
20890b57cec5SDimitry Andric       MachineInstr *MI = &*I;
20900b57cec5SDimitry Andric       NextI = std::next(I);
20910b57cec5SDimitry Andric       unsigned Opc = MI->getOpcode();
20920b57cec5SDimitry Andric 
20930b57cec5SDimitry Andric       switch (Opc) {
20940b57cec5SDimitry Andric         case TargetOpcode::COPY:
20950b57cec5SDimitry Andric           Changed |= expandCopy(B, I, MRI, HII, NewRegs);
20960b57cec5SDimitry Andric           break;
20970b57cec5SDimitry Andric         case Hexagon::STriw_pred:
20980b57cec5SDimitry Andric         case Hexagon::STriw_ctr:
20990b57cec5SDimitry Andric           Changed |= expandStoreInt(B, I, MRI, HII, NewRegs);
21000b57cec5SDimitry Andric           break;
21010b57cec5SDimitry Andric         case Hexagon::LDriw_pred:
21020b57cec5SDimitry Andric         case Hexagon::LDriw_ctr:
21030b57cec5SDimitry Andric           Changed |= expandLoadInt(B, I, MRI, HII, NewRegs);
21040b57cec5SDimitry Andric           break;
21050b57cec5SDimitry Andric         case Hexagon::PS_vstorerq_ai:
21060b57cec5SDimitry Andric           Changed |= expandStoreVecPred(B, I, MRI, HII, NewRegs);
21070b57cec5SDimitry Andric           break;
21080b57cec5SDimitry Andric         case Hexagon::PS_vloadrq_ai:
21090b57cec5SDimitry Andric           Changed |= expandLoadVecPred(B, I, MRI, HII, NewRegs);
21100b57cec5SDimitry Andric           break;
21110b57cec5SDimitry Andric         case Hexagon::PS_vloadrw_ai:
21120b57cec5SDimitry Andric           Changed |= expandLoadVec2(B, I, MRI, HII, NewRegs);
21130b57cec5SDimitry Andric           break;
21140b57cec5SDimitry Andric         case Hexagon::PS_vstorerw_ai:
21150b57cec5SDimitry Andric           Changed |= expandStoreVec2(B, I, MRI, HII, NewRegs);
21160b57cec5SDimitry Andric           break;
21170b57cec5SDimitry Andric       }
21180b57cec5SDimitry Andric     }
21190b57cec5SDimitry Andric   }
21200b57cec5SDimitry Andric 
21210b57cec5SDimitry Andric   return Changed;
21220b57cec5SDimitry Andric }
21230b57cec5SDimitry Andric 
21240b57cec5SDimitry Andric void HexagonFrameLowering::determineCalleeSaves(MachineFunction &MF,
21250b57cec5SDimitry Andric                                                 BitVector &SavedRegs,
21260b57cec5SDimitry Andric                                                 RegScavenger *RS) const {
21270b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
21280b57cec5SDimitry Andric 
21290b57cec5SDimitry Andric   SavedRegs.resize(HRI.getNumRegs());
21300b57cec5SDimitry Andric 
21310b57cec5SDimitry Andric   // If we have a function containing __builtin_eh_return we want to spill and
21320b57cec5SDimitry Andric   // restore all callee saved registers. Pretend that they are used.
21330b57cec5SDimitry Andric   if (MF.getInfo<HexagonMachineFunctionInfo>()->hasEHReturn())
21340b57cec5SDimitry Andric     for (const MCPhysReg *R = HRI.getCalleeSavedRegs(&MF); *R; ++R)
21350b57cec5SDimitry Andric       SavedRegs.set(*R);
21360b57cec5SDimitry Andric 
21370b57cec5SDimitry Andric   // Replace predicate register pseudo spill code.
21380b57cec5SDimitry Andric   SmallVector<unsigned,8> NewRegs;
21390b57cec5SDimitry Andric   expandSpillMacros(MF, NewRegs);
21400b57cec5SDimitry Andric   if (OptimizeSpillSlots && !isOptNone(MF))
21410b57cec5SDimitry Andric     optimizeSpillSlots(MF, NewRegs);
21420b57cec5SDimitry Andric 
21430b57cec5SDimitry Andric   // We need to reserve a spill slot if scavenging could potentially require
21440b57cec5SDimitry Andric   // spilling a scavenged register.
21450b57cec5SDimitry Andric   if (!NewRegs.empty() || mayOverflowFrameOffset(MF)) {
21460b57cec5SDimitry Andric     MachineFrameInfo &MFI = MF.getFrameInfo();
21470b57cec5SDimitry Andric     MachineRegisterInfo &MRI = MF.getRegInfo();
21480b57cec5SDimitry Andric     SetVector<const TargetRegisterClass*> SpillRCs;
21490b57cec5SDimitry Andric     // Reserve an int register in any case, because it could be used to hold
21500b57cec5SDimitry Andric     // the stack offset in case it does not fit into a spill instruction.
21510b57cec5SDimitry Andric     SpillRCs.insert(&Hexagon::IntRegsRegClass);
21520b57cec5SDimitry Andric 
21530b57cec5SDimitry Andric     for (unsigned VR : NewRegs)
21540b57cec5SDimitry Andric       SpillRCs.insert(MRI.getRegClass(VR));
21550b57cec5SDimitry Andric 
21560b57cec5SDimitry Andric     for (auto *RC : SpillRCs) {
21570b57cec5SDimitry Andric       if (!needToReserveScavengingSpillSlots(MF, HRI, RC))
21580b57cec5SDimitry Andric         continue;
2159480093f4SDimitry Andric       unsigned Num = 1;
2160480093f4SDimitry Andric       switch (RC->getID()) {
2161480093f4SDimitry Andric         case Hexagon::IntRegsRegClassID:
2162480093f4SDimitry Andric           Num = NumberScavengerSlots;
2163480093f4SDimitry Andric           break;
2164480093f4SDimitry Andric         case Hexagon::HvxQRRegClassID:
2165480093f4SDimitry Andric           Num = 2; // Vector predicate spills also need a vector register.
2166480093f4SDimitry Andric           break;
2167480093f4SDimitry Andric       }
21685ffd83dbSDimitry Andric       unsigned S = HRI.getSpillSize(*RC);
21695ffd83dbSDimitry Andric       Align A = HRI.getSpillAlign(*RC);
21700b57cec5SDimitry Andric       for (unsigned i = 0; i < Num; i++) {
21710b57cec5SDimitry Andric         int NewFI = MFI.CreateSpillStackObject(S, A);
21720b57cec5SDimitry Andric         RS->addScavengingFrameIndex(NewFI);
21730b57cec5SDimitry Andric       }
21740b57cec5SDimitry Andric     }
21750b57cec5SDimitry Andric   }
21760b57cec5SDimitry Andric 
21770b57cec5SDimitry Andric   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
21780b57cec5SDimitry Andric }
21790b57cec5SDimitry Andric 
21800b57cec5SDimitry Andric unsigned HexagonFrameLowering::findPhysReg(MachineFunction &MF,
21810b57cec5SDimitry Andric       HexagonBlockRanges::IndexRange &FIR,
21820b57cec5SDimitry Andric       HexagonBlockRanges::InstrIndexMap &IndexMap,
21830b57cec5SDimitry Andric       HexagonBlockRanges::RegToRangeMap &DeadMap,
21840b57cec5SDimitry Andric       const TargetRegisterClass *RC) const {
21850b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
21860b57cec5SDimitry Andric   auto &MRI = MF.getRegInfo();
21870b57cec5SDimitry Andric 
21880b57cec5SDimitry Andric   auto isDead = [&FIR,&DeadMap] (unsigned Reg) -> bool {
21890b57cec5SDimitry Andric     auto F = DeadMap.find({Reg,0});
21900b57cec5SDimitry Andric     if (F == DeadMap.end())
21910b57cec5SDimitry Andric       return false;
21920b57cec5SDimitry Andric     for (auto &DR : F->second)
21930b57cec5SDimitry Andric       if (DR.contains(FIR))
21940b57cec5SDimitry Andric         return true;
21950b57cec5SDimitry Andric     return false;
21960b57cec5SDimitry Andric   };
21970b57cec5SDimitry Andric 
21980b57cec5SDimitry Andric   for (unsigned Reg : RC->getRawAllocationOrder(MF)) {
21990b57cec5SDimitry Andric     bool Dead = true;
22000b57cec5SDimitry Andric     for (auto R : HexagonBlockRanges::expandToSubRegs({Reg,0}, MRI, HRI)) {
22010b57cec5SDimitry Andric       if (isDead(R.Reg))
22020b57cec5SDimitry Andric         continue;
22030b57cec5SDimitry Andric       Dead = false;
22040b57cec5SDimitry Andric       break;
22050b57cec5SDimitry Andric     }
22060b57cec5SDimitry Andric     if (Dead)
22070b57cec5SDimitry Andric       return Reg;
22080b57cec5SDimitry Andric   }
22090b57cec5SDimitry Andric   return 0;
22100b57cec5SDimitry Andric }
22110b57cec5SDimitry Andric 
22120b57cec5SDimitry Andric void HexagonFrameLowering::optimizeSpillSlots(MachineFunction &MF,
22130b57cec5SDimitry Andric       SmallVectorImpl<unsigned> &VRegs) const {
22140b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
22150b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
22160b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
22170b57cec5SDimitry Andric   auto &MRI = MF.getRegInfo();
22180b57cec5SDimitry Andric   HexagonBlockRanges HBR(MF);
22190b57cec5SDimitry Andric 
22200b57cec5SDimitry Andric   using BlockIndexMap =
22210b57cec5SDimitry Andric       std::map<MachineBasicBlock *, HexagonBlockRanges::InstrIndexMap>;
22220b57cec5SDimitry Andric   using BlockRangeMap =
22230b57cec5SDimitry Andric       std::map<MachineBasicBlock *, HexagonBlockRanges::RangeList>;
22240b57cec5SDimitry Andric   using IndexType = HexagonBlockRanges::IndexType;
22250b57cec5SDimitry Andric 
22260b57cec5SDimitry Andric   struct SlotInfo {
22270b57cec5SDimitry Andric     BlockRangeMap Map;
22280b57cec5SDimitry Andric     unsigned Size = 0;
22290b57cec5SDimitry Andric     const TargetRegisterClass *RC = nullptr;
22300b57cec5SDimitry Andric 
22310b57cec5SDimitry Andric     SlotInfo() = default;
22320b57cec5SDimitry Andric   };
22330b57cec5SDimitry Andric 
22340b57cec5SDimitry Andric   BlockIndexMap BlockIndexes;
22350b57cec5SDimitry Andric   SmallSet<int,4> BadFIs;
22360b57cec5SDimitry Andric   std::map<int,SlotInfo> FIRangeMap;
22370b57cec5SDimitry Andric 
22380b57cec5SDimitry Andric   // Accumulate register classes: get a common class for a pre-existing
22390b57cec5SDimitry Andric   // class HaveRC and a new class NewRC. Return nullptr if a common class
22400b57cec5SDimitry Andric   // cannot be found, otherwise return the resulting class. If HaveRC is
22410b57cec5SDimitry Andric   // nullptr, assume that it is still unset.
22420b57cec5SDimitry Andric   auto getCommonRC =
22430b57cec5SDimitry Andric       [](const TargetRegisterClass *HaveRC,
22440b57cec5SDimitry Andric          const TargetRegisterClass *NewRC) -> const TargetRegisterClass * {
22450b57cec5SDimitry Andric     if (HaveRC == nullptr || HaveRC == NewRC)
22460b57cec5SDimitry Andric       return NewRC;
22470b57cec5SDimitry Andric     // Different classes, both non-null. Pick the more general one.
22480b57cec5SDimitry Andric     if (HaveRC->hasSubClassEq(NewRC))
22490b57cec5SDimitry Andric       return HaveRC;
22500b57cec5SDimitry Andric     if (NewRC->hasSubClassEq(HaveRC))
22510b57cec5SDimitry Andric       return NewRC;
22520b57cec5SDimitry Andric     return nullptr;
22530b57cec5SDimitry Andric   };
22540b57cec5SDimitry Andric 
22550b57cec5SDimitry Andric   // Scan all blocks in the function. Check all occurrences of frame indexes,
22560b57cec5SDimitry Andric   // and collect relevant information.
22570b57cec5SDimitry Andric   for (auto &B : MF) {
22580b57cec5SDimitry Andric     std::map<int,IndexType> LastStore, LastLoad;
22590b57cec5SDimitry Andric     // Emplace appears not to be supported in gcc 4.7.2-4.
22600b57cec5SDimitry Andric     //auto P = BlockIndexes.emplace(&B, HexagonBlockRanges::InstrIndexMap(B));
22610b57cec5SDimitry Andric     auto P = BlockIndexes.insert(
22620b57cec5SDimitry Andric                 std::make_pair(&B, HexagonBlockRanges::InstrIndexMap(B)));
22630b57cec5SDimitry Andric     auto &IndexMap = P.first->second;
22640b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Index map for " << printMBBReference(B) << "\n"
22650b57cec5SDimitry Andric                       << IndexMap << '\n');
22660b57cec5SDimitry Andric 
22670b57cec5SDimitry Andric     for (auto &In : B) {
22680b57cec5SDimitry Andric       int LFI, SFI;
22690b57cec5SDimitry Andric       bool Load = HII.isLoadFromStackSlot(In, LFI) && !HII.isPredicated(In);
22700b57cec5SDimitry Andric       bool Store = HII.isStoreToStackSlot(In, SFI) && !HII.isPredicated(In);
22710b57cec5SDimitry Andric       if (Load && Store) {
22720b57cec5SDimitry Andric         // If it's both a load and a store, then we won't handle it.
22730b57cec5SDimitry Andric         BadFIs.insert(LFI);
22740b57cec5SDimitry Andric         BadFIs.insert(SFI);
22750b57cec5SDimitry Andric         continue;
22760b57cec5SDimitry Andric       }
22770b57cec5SDimitry Andric       // Check for register classes of the register used as the source for
22780b57cec5SDimitry Andric       // the store, and the register used as the destination for the load.
22790b57cec5SDimitry Andric       // Also, only accept base+imm_offset addressing modes. Other addressing
22800b57cec5SDimitry Andric       // modes can have side-effects (post-increments, etc.). For stack
22810b57cec5SDimitry Andric       // slots they are very unlikely, so there is not much loss due to
22820b57cec5SDimitry Andric       // this restriction.
22830b57cec5SDimitry Andric       if (Load || Store) {
22840b57cec5SDimitry Andric         int TFI = Load ? LFI : SFI;
22850b57cec5SDimitry Andric         unsigned AM = HII.getAddrMode(In);
22860b57cec5SDimitry Andric         SlotInfo &SI = FIRangeMap[TFI];
22870b57cec5SDimitry Andric         bool Bad = (AM != HexagonII::BaseImmOffset);
22880b57cec5SDimitry Andric         if (!Bad) {
22890b57cec5SDimitry Andric           // If the addressing mode is ok, check the register class.
22900b57cec5SDimitry Andric           unsigned OpNum = Load ? 0 : 2;
22910b57cec5SDimitry Andric           auto *RC = HII.getRegClass(In.getDesc(), OpNum, &HRI, MF);
22920b57cec5SDimitry Andric           RC = getCommonRC(SI.RC, RC);
22930b57cec5SDimitry Andric           if (RC == nullptr)
22940b57cec5SDimitry Andric             Bad = true;
22950b57cec5SDimitry Andric           else
22960b57cec5SDimitry Andric             SI.RC = RC;
22970b57cec5SDimitry Andric         }
22980b57cec5SDimitry Andric         if (!Bad) {
22990b57cec5SDimitry Andric           // Check sizes.
23000b57cec5SDimitry Andric           unsigned S = HII.getMemAccessSize(In);
23010b57cec5SDimitry Andric           if (SI.Size != 0 && SI.Size != S)
23020b57cec5SDimitry Andric             Bad = true;
23030b57cec5SDimitry Andric           else
23040b57cec5SDimitry Andric             SI.Size = S;
23050b57cec5SDimitry Andric         }
23060b57cec5SDimitry Andric         if (!Bad) {
23070b57cec5SDimitry Andric           for (auto *Mo : In.memoperands()) {
23080b57cec5SDimitry Andric             if (!Mo->isVolatile() && !Mo->isAtomic())
23090b57cec5SDimitry Andric               continue;
23100b57cec5SDimitry Andric             Bad = true;
23110b57cec5SDimitry Andric             break;
23120b57cec5SDimitry Andric           }
23130b57cec5SDimitry Andric         }
23140b57cec5SDimitry Andric         if (Bad)
23150b57cec5SDimitry Andric           BadFIs.insert(TFI);
23160b57cec5SDimitry Andric       }
23170b57cec5SDimitry Andric 
23180b57cec5SDimitry Andric       // Locate uses of frame indices.
23190b57cec5SDimitry Andric       for (unsigned i = 0, n = In.getNumOperands(); i < n; ++i) {
23200b57cec5SDimitry Andric         const MachineOperand &Op = In.getOperand(i);
23210b57cec5SDimitry Andric         if (!Op.isFI())
23220b57cec5SDimitry Andric           continue;
23230b57cec5SDimitry Andric         int FI = Op.getIndex();
23240b57cec5SDimitry Andric         // Make sure that the following operand is an immediate and that
23250b57cec5SDimitry Andric         // it is 0. This is the offset in the stack object.
23260b57cec5SDimitry Andric         if (i+1 >= n || !In.getOperand(i+1).isImm() ||
23270b57cec5SDimitry Andric             In.getOperand(i+1).getImm() != 0)
23280b57cec5SDimitry Andric           BadFIs.insert(FI);
23290b57cec5SDimitry Andric         if (BadFIs.count(FI))
23300b57cec5SDimitry Andric           continue;
23310b57cec5SDimitry Andric 
23320b57cec5SDimitry Andric         IndexType Index = IndexMap.getIndex(&In);
23330b57cec5SDimitry Andric         if (Load) {
23340b57cec5SDimitry Andric           if (LastStore[FI] == IndexType::None)
23350b57cec5SDimitry Andric             LastStore[FI] = IndexType::Entry;
23360b57cec5SDimitry Andric           LastLoad[FI] = Index;
23370b57cec5SDimitry Andric         } else if (Store) {
23380b57cec5SDimitry Andric           HexagonBlockRanges::RangeList &RL = FIRangeMap[FI].Map[&B];
23390b57cec5SDimitry Andric           if (LastStore[FI] != IndexType::None)
23400b57cec5SDimitry Andric             RL.add(LastStore[FI], LastLoad[FI], false, false);
23410b57cec5SDimitry Andric           else if (LastLoad[FI] != IndexType::None)
23420b57cec5SDimitry Andric             RL.add(IndexType::Entry, LastLoad[FI], false, false);
23430b57cec5SDimitry Andric           LastLoad[FI] = IndexType::None;
23440b57cec5SDimitry Andric           LastStore[FI] = Index;
23450b57cec5SDimitry Andric         } else {
23460b57cec5SDimitry Andric           BadFIs.insert(FI);
23470b57cec5SDimitry Andric         }
23480b57cec5SDimitry Andric       }
23490b57cec5SDimitry Andric     }
23500b57cec5SDimitry Andric 
23510b57cec5SDimitry Andric     for (auto &I : LastLoad) {
23520b57cec5SDimitry Andric       IndexType LL = I.second;
23530b57cec5SDimitry Andric       if (LL == IndexType::None)
23540b57cec5SDimitry Andric         continue;
23550b57cec5SDimitry Andric       auto &RL = FIRangeMap[I.first].Map[&B];
23560b57cec5SDimitry Andric       IndexType &LS = LastStore[I.first];
23570b57cec5SDimitry Andric       if (LS != IndexType::None)
23580b57cec5SDimitry Andric         RL.add(LS, LL, false, false);
23590b57cec5SDimitry Andric       else
23600b57cec5SDimitry Andric         RL.add(IndexType::Entry, LL, false, false);
23610b57cec5SDimitry Andric       LS = IndexType::None;
23620b57cec5SDimitry Andric     }
23630b57cec5SDimitry Andric     for (auto &I : LastStore) {
23640b57cec5SDimitry Andric       IndexType LS = I.second;
23650b57cec5SDimitry Andric       if (LS == IndexType::None)
23660b57cec5SDimitry Andric         continue;
23670b57cec5SDimitry Andric       auto &RL = FIRangeMap[I.first].Map[&B];
23680b57cec5SDimitry Andric       RL.add(LS, IndexType::None, false, false);
23690b57cec5SDimitry Andric     }
23700b57cec5SDimitry Andric   }
23710b57cec5SDimitry Andric 
23720b57cec5SDimitry Andric   LLVM_DEBUG({
23730b57cec5SDimitry Andric     for (auto &P : FIRangeMap) {
23740b57cec5SDimitry Andric       dbgs() << "fi#" << P.first;
23750b57cec5SDimitry Andric       if (BadFIs.count(P.first))
23760b57cec5SDimitry Andric         dbgs() << " (bad)";
23770b57cec5SDimitry Andric       dbgs() << "  RC: ";
23780b57cec5SDimitry Andric       if (P.second.RC != nullptr)
23790b57cec5SDimitry Andric         dbgs() << HRI.getRegClassName(P.second.RC) << '\n';
23800b57cec5SDimitry Andric       else
23810b57cec5SDimitry Andric         dbgs() << "<null>\n";
23820b57cec5SDimitry Andric       for (auto &R : P.second.Map)
23830b57cec5SDimitry Andric         dbgs() << "  " << printMBBReference(*R.first) << " { " << R.second
23840b57cec5SDimitry Andric                << "}\n";
23850b57cec5SDimitry Andric     }
23860b57cec5SDimitry Andric   });
23870b57cec5SDimitry Andric 
23880b57cec5SDimitry Andric   // When a slot is loaded from in a block without being stored to in the
23890b57cec5SDimitry Andric   // same block, it is live-on-entry to this block. To avoid CFG analysis,
23900b57cec5SDimitry Andric   // consider this slot to be live-on-exit from all blocks.
23910b57cec5SDimitry Andric   SmallSet<int,4> LoxFIs;
23920b57cec5SDimitry Andric 
23930b57cec5SDimitry Andric   std::map<MachineBasicBlock*,std::vector<int>> BlockFIMap;
23940b57cec5SDimitry Andric 
23950b57cec5SDimitry Andric   for (auto &P : FIRangeMap) {
23960b57cec5SDimitry Andric     // P = pair(FI, map: BB->RangeList)
23970b57cec5SDimitry Andric     if (BadFIs.count(P.first))
23980b57cec5SDimitry Andric       continue;
23990b57cec5SDimitry Andric     for (auto &B : MF) {
24000b57cec5SDimitry Andric       auto F = P.second.Map.find(&B);
24010b57cec5SDimitry Andric       // F = pair(BB, RangeList)
24020b57cec5SDimitry Andric       if (F == P.second.Map.end() || F->second.empty())
24030b57cec5SDimitry Andric         continue;
24040b57cec5SDimitry Andric       HexagonBlockRanges::IndexRange &IR = F->second.front();
24050b57cec5SDimitry Andric       if (IR.start() == IndexType::Entry)
24060b57cec5SDimitry Andric         LoxFIs.insert(P.first);
24070b57cec5SDimitry Andric       BlockFIMap[&B].push_back(P.first);
24080b57cec5SDimitry Andric     }
24090b57cec5SDimitry Andric   }
24100b57cec5SDimitry Andric 
24110b57cec5SDimitry Andric   LLVM_DEBUG({
24120b57cec5SDimitry Andric     dbgs() << "Block-to-FI map (* -- live-on-exit):\n";
24130b57cec5SDimitry Andric     for (auto &P : BlockFIMap) {
24140b57cec5SDimitry Andric       auto &FIs = P.second;
24150b57cec5SDimitry Andric       if (FIs.empty())
24160b57cec5SDimitry Andric         continue;
24170b57cec5SDimitry Andric       dbgs() << "  " << printMBBReference(*P.first) << ": {";
24180b57cec5SDimitry Andric       for (auto I : FIs) {
24190b57cec5SDimitry Andric         dbgs() << " fi#" << I;
24200b57cec5SDimitry Andric         if (LoxFIs.count(I))
24210b57cec5SDimitry Andric           dbgs() << '*';
24220b57cec5SDimitry Andric       }
24230b57cec5SDimitry Andric       dbgs() << " }\n";
24240b57cec5SDimitry Andric     }
24250b57cec5SDimitry Andric   });
24260b57cec5SDimitry Andric 
24270b57cec5SDimitry Andric #ifndef NDEBUG
24280b57cec5SDimitry Andric   bool HasOptLimit = SpillOptMax.getPosition();
24290b57cec5SDimitry Andric #endif
24300b57cec5SDimitry Andric 
24310b57cec5SDimitry Andric   // eliminate loads, when all loads eliminated, eliminate all stores.
24320b57cec5SDimitry Andric   for (auto &B : MF) {
24330b57cec5SDimitry Andric     auto F = BlockIndexes.find(&B);
24340b57cec5SDimitry Andric     assert(F != BlockIndexes.end());
24350b57cec5SDimitry Andric     HexagonBlockRanges::InstrIndexMap &IM = F->second;
24360b57cec5SDimitry Andric     HexagonBlockRanges::RegToRangeMap LM = HBR.computeLiveMap(IM);
24370b57cec5SDimitry Andric     HexagonBlockRanges::RegToRangeMap DM = HBR.computeDeadMap(IM, LM);
24380b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << printMBBReference(B) << " dead map\n"
24390b57cec5SDimitry Andric                       << HexagonBlockRanges::PrintRangeMap(DM, HRI));
24400b57cec5SDimitry Andric 
24410b57cec5SDimitry Andric     for (auto FI : BlockFIMap[&B]) {
24420b57cec5SDimitry Andric       if (BadFIs.count(FI))
24430b57cec5SDimitry Andric         continue;
24440b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Working on fi#" << FI << '\n');
24450b57cec5SDimitry Andric       HexagonBlockRanges::RangeList &RL = FIRangeMap[FI].Map[&B];
24460b57cec5SDimitry Andric       for (auto &Range : RL) {
24470b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "--Examining range:" << RL << '\n');
24480b57cec5SDimitry Andric         if (!IndexType::isInstr(Range.start()) ||
24490b57cec5SDimitry Andric             !IndexType::isInstr(Range.end()))
24500b57cec5SDimitry Andric           continue;
24510b57cec5SDimitry Andric         MachineInstr &SI = *IM.getInstr(Range.start());
24520b57cec5SDimitry Andric         MachineInstr &EI = *IM.getInstr(Range.end());
24530b57cec5SDimitry Andric         assert(SI.mayStore() && "Unexpected start instruction");
24540b57cec5SDimitry Andric         assert(EI.mayLoad() && "Unexpected end instruction");
24550b57cec5SDimitry Andric         MachineOperand &SrcOp = SI.getOperand(2);
24560b57cec5SDimitry Andric 
24570b57cec5SDimitry Andric         HexagonBlockRanges::RegisterRef SrcRR = { SrcOp.getReg(),
24580b57cec5SDimitry Andric                                                   SrcOp.getSubReg() };
24590b57cec5SDimitry Andric         auto *RC = HII.getRegClass(SI.getDesc(), 2, &HRI, MF);
24600b57cec5SDimitry Andric         // The this-> is needed to unconfuse MSVC.
24610b57cec5SDimitry Andric         unsigned FoundR = this->findPhysReg(MF, Range, IM, DM, RC);
24620b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "Replacement reg:" << printReg(FoundR, &HRI)
24630b57cec5SDimitry Andric                           << '\n');
24640b57cec5SDimitry Andric         if (FoundR == 0)
24650b57cec5SDimitry Andric           continue;
24660b57cec5SDimitry Andric #ifndef NDEBUG
24670b57cec5SDimitry Andric         if (HasOptLimit) {
24680b57cec5SDimitry Andric           if (SpillOptCount >= SpillOptMax)
24690b57cec5SDimitry Andric             return;
24700b57cec5SDimitry Andric           SpillOptCount++;
24710b57cec5SDimitry Andric         }
24720b57cec5SDimitry Andric #endif
24730b57cec5SDimitry Andric 
24740b57cec5SDimitry Andric         // Generate the copy-in: "FoundR = COPY SrcR" at the store location.
24750b57cec5SDimitry Andric         MachineBasicBlock::iterator StartIt = SI.getIterator(), NextIt;
24760b57cec5SDimitry Andric         MachineInstr *CopyIn = nullptr;
24770b57cec5SDimitry Andric         if (SrcRR.Reg != FoundR || SrcRR.Sub != 0) {
24780b57cec5SDimitry Andric           const DebugLoc &DL = SI.getDebugLoc();
24790b57cec5SDimitry Andric           CopyIn = BuildMI(B, StartIt, DL, HII.get(TargetOpcode::COPY), FoundR)
24800b57cec5SDimitry Andric                        .add(SrcOp);
24810b57cec5SDimitry Andric         }
24820b57cec5SDimitry Andric 
24830b57cec5SDimitry Andric         ++StartIt;
24840b57cec5SDimitry Andric         // Check if this is a last store and the FI is live-on-exit.
24850b57cec5SDimitry Andric         if (LoxFIs.count(FI) && (&Range == &RL.back())) {
24860b57cec5SDimitry Andric           // Update store's source register.
24870b57cec5SDimitry Andric           if (unsigned SR = SrcOp.getSubReg())
24880b57cec5SDimitry Andric             SrcOp.setReg(HRI.getSubReg(FoundR, SR));
24890b57cec5SDimitry Andric           else
24900b57cec5SDimitry Andric             SrcOp.setReg(FoundR);
24910b57cec5SDimitry Andric           SrcOp.setSubReg(0);
24920b57cec5SDimitry Andric           // We are keeping this register live.
24930b57cec5SDimitry Andric           SrcOp.setIsKill(false);
24940b57cec5SDimitry Andric         } else {
24950b57cec5SDimitry Andric           B.erase(&SI);
24960b57cec5SDimitry Andric           IM.replaceInstr(&SI, CopyIn);
24970b57cec5SDimitry Andric         }
24980b57cec5SDimitry Andric 
24990b57cec5SDimitry Andric         auto EndIt = std::next(EI.getIterator());
25000b57cec5SDimitry Andric         for (auto It = StartIt; It != EndIt; It = NextIt) {
25010b57cec5SDimitry Andric           MachineInstr &MI = *It;
25020b57cec5SDimitry Andric           NextIt = std::next(It);
25030b57cec5SDimitry Andric           int TFI;
25040b57cec5SDimitry Andric           if (!HII.isLoadFromStackSlot(MI, TFI) || TFI != FI)
25050b57cec5SDimitry Andric             continue;
25068bcb0991SDimitry Andric           Register DstR = MI.getOperand(0).getReg();
25070b57cec5SDimitry Andric           assert(MI.getOperand(0).getSubReg() == 0);
25080b57cec5SDimitry Andric           MachineInstr *CopyOut = nullptr;
25090b57cec5SDimitry Andric           if (DstR != FoundR) {
25100b57cec5SDimitry Andric             DebugLoc DL = MI.getDebugLoc();
25110b57cec5SDimitry Andric             unsigned MemSize = HII.getMemAccessSize(MI);
25120b57cec5SDimitry Andric             assert(HII.getAddrMode(MI) == HexagonII::BaseImmOffset);
25130b57cec5SDimitry Andric             unsigned CopyOpc = TargetOpcode::COPY;
25140b57cec5SDimitry Andric             if (HII.isSignExtendingLoad(MI))
25150b57cec5SDimitry Andric               CopyOpc = (MemSize == 1) ? Hexagon::A2_sxtb : Hexagon::A2_sxth;
25160b57cec5SDimitry Andric             else if (HII.isZeroExtendingLoad(MI))
25170b57cec5SDimitry Andric               CopyOpc = (MemSize == 1) ? Hexagon::A2_zxtb : Hexagon::A2_zxth;
25180b57cec5SDimitry Andric             CopyOut = BuildMI(B, It, DL, HII.get(CopyOpc), DstR)
25190b57cec5SDimitry Andric                         .addReg(FoundR, getKillRegState(&MI == &EI));
25200b57cec5SDimitry Andric           }
25210b57cec5SDimitry Andric           IM.replaceInstr(&MI, CopyOut);
25220b57cec5SDimitry Andric           B.erase(It);
25230b57cec5SDimitry Andric         }
25240b57cec5SDimitry Andric 
25250b57cec5SDimitry Andric         // Update the dead map.
25260b57cec5SDimitry Andric         HexagonBlockRanges::RegisterRef FoundRR = { FoundR, 0 };
25270b57cec5SDimitry Andric         for (auto RR : HexagonBlockRanges::expandToSubRegs(FoundRR, MRI, HRI))
25280b57cec5SDimitry Andric           DM[RR].subtract(Range);
25290b57cec5SDimitry Andric       } // for Range in range list
25300b57cec5SDimitry Andric     }
25310b57cec5SDimitry Andric   }
25320b57cec5SDimitry Andric }
25330b57cec5SDimitry Andric 
25340b57cec5SDimitry Andric void HexagonFrameLowering::expandAlloca(MachineInstr *AI,
25350b57cec5SDimitry Andric       const HexagonInstrInfo &HII, unsigned SP, unsigned CF) const {
25360b57cec5SDimitry Andric   MachineBasicBlock &MB = *AI->getParent();
25370b57cec5SDimitry Andric   DebugLoc DL = AI->getDebugLoc();
25380b57cec5SDimitry Andric   unsigned A = AI->getOperand(2).getImm();
25390b57cec5SDimitry Andric 
25400b57cec5SDimitry Andric   // Have
25410b57cec5SDimitry Andric   //    Rd  = alloca Rs, #A
25420b57cec5SDimitry Andric   //
25430b57cec5SDimitry Andric   // If Rs and Rd are different registers, use this sequence:
25440b57cec5SDimitry Andric   //    Rd  = sub(r29, Rs)
25450b57cec5SDimitry Andric   //    r29 = sub(r29, Rs)
25460b57cec5SDimitry Andric   //    Rd  = and(Rd, #-A)    ; if necessary
25470b57cec5SDimitry Andric   //    r29 = and(r29, #-A)   ; if necessary
25480b57cec5SDimitry Andric   //    Rd  = add(Rd, #CF)    ; CF size aligned to at most A
25490b57cec5SDimitry Andric   // otherwise, do
25500b57cec5SDimitry Andric   //    Rd  = sub(r29, Rs)
25510b57cec5SDimitry Andric   //    Rd  = and(Rd, #-A)    ; if necessary
25520b57cec5SDimitry Andric   //    r29 = Rd
25530b57cec5SDimitry Andric   //    Rd  = add(Rd, #CF)    ; CF size aligned to at most A
25540b57cec5SDimitry Andric 
25550b57cec5SDimitry Andric   MachineOperand &RdOp = AI->getOperand(0);
25560b57cec5SDimitry Andric   MachineOperand &RsOp = AI->getOperand(1);
25570b57cec5SDimitry Andric   unsigned Rd = RdOp.getReg(), Rs = RsOp.getReg();
25580b57cec5SDimitry Andric 
25590b57cec5SDimitry Andric   // Rd = sub(r29, Rs)
25600b57cec5SDimitry Andric   BuildMI(MB, AI, DL, HII.get(Hexagon::A2_sub), Rd)
25610b57cec5SDimitry Andric       .addReg(SP)
25620b57cec5SDimitry Andric       .addReg(Rs);
25630b57cec5SDimitry Andric   if (Rs != Rd) {
25640b57cec5SDimitry Andric     // r29 = sub(r29, Rs)
25650b57cec5SDimitry Andric     BuildMI(MB, AI, DL, HII.get(Hexagon::A2_sub), SP)
25660b57cec5SDimitry Andric         .addReg(SP)
25670b57cec5SDimitry Andric         .addReg(Rs);
25680b57cec5SDimitry Andric   }
25690b57cec5SDimitry Andric   if (A > 8) {
25700b57cec5SDimitry Andric     // Rd  = and(Rd, #-A)
25710b57cec5SDimitry Andric     BuildMI(MB, AI, DL, HII.get(Hexagon::A2_andir), Rd)
25720b57cec5SDimitry Andric         .addReg(Rd)
25730b57cec5SDimitry Andric         .addImm(-int64_t(A));
25740b57cec5SDimitry Andric     if (Rs != Rd)
25750b57cec5SDimitry Andric       BuildMI(MB, AI, DL, HII.get(Hexagon::A2_andir), SP)
25760b57cec5SDimitry Andric           .addReg(SP)
25770b57cec5SDimitry Andric           .addImm(-int64_t(A));
25780b57cec5SDimitry Andric   }
25790b57cec5SDimitry Andric   if (Rs == Rd) {
25800b57cec5SDimitry Andric     // r29 = Rd
25810b57cec5SDimitry Andric     BuildMI(MB, AI, DL, HII.get(TargetOpcode::COPY), SP)
25820b57cec5SDimitry Andric         .addReg(Rd);
25830b57cec5SDimitry Andric   }
25840b57cec5SDimitry Andric   if (CF > 0) {
25850b57cec5SDimitry Andric     // Rd = add(Rd, #CF)
25860b57cec5SDimitry Andric     BuildMI(MB, AI, DL, HII.get(Hexagon::A2_addi), Rd)
25870b57cec5SDimitry Andric         .addReg(Rd)
25880b57cec5SDimitry Andric         .addImm(CF);
25890b57cec5SDimitry Andric   }
25900b57cec5SDimitry Andric }
25910b57cec5SDimitry Andric 
25920b57cec5SDimitry Andric bool HexagonFrameLowering::needsAligna(const MachineFunction &MF) const {
25930b57cec5SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
25940b57cec5SDimitry Andric   if (!MFI.hasVarSizedObjects())
25950b57cec5SDimitry Andric     return false;
2596480093f4SDimitry Andric   // Do not check for max stack object alignment here, because the stack
2597480093f4SDimitry Andric   // may not be complete yet. Assume that we will need PS_aligna if there
2598480093f4SDimitry Andric   // are variable-sized objects.
25990b57cec5SDimitry Andric   return true;
26000b57cec5SDimitry Andric }
26010b57cec5SDimitry Andric 
26020b57cec5SDimitry Andric const MachineInstr *HexagonFrameLowering::getAlignaInstr(
26030b57cec5SDimitry Andric       const MachineFunction &MF) const {
26040b57cec5SDimitry Andric   for (auto &B : MF)
26050b57cec5SDimitry Andric     for (auto &I : B)
26060b57cec5SDimitry Andric       if (I.getOpcode() == Hexagon::PS_aligna)
26070b57cec5SDimitry Andric         return &I;
26080b57cec5SDimitry Andric   return nullptr;
26090b57cec5SDimitry Andric }
26100b57cec5SDimitry Andric 
26110b57cec5SDimitry Andric /// Adds all callee-saved registers as implicit uses or defs to the
26120b57cec5SDimitry Andric /// instruction.
26130b57cec5SDimitry Andric void HexagonFrameLowering::addCalleeSaveRegistersAsImpOperand(MachineInstr *MI,
26140b57cec5SDimitry Andric       const CSIVect &CSI, bool IsDef, bool IsKill) const {
26150b57cec5SDimitry Andric   // Add the callee-saved registers as implicit uses.
26160b57cec5SDimitry Andric   for (auto &R : CSI)
26170b57cec5SDimitry Andric     MI->addOperand(MachineOperand::CreateReg(R.getReg(), IsDef, true, IsKill));
26180b57cec5SDimitry Andric }
26190b57cec5SDimitry Andric 
26200b57cec5SDimitry Andric /// Determine whether the callee-saved register saves and restores should
26210b57cec5SDimitry Andric /// be generated via inline code. If this function returns "true", inline
26220b57cec5SDimitry Andric /// code will be generated. If this function returns "false", additional
26230b57cec5SDimitry Andric /// checks are performed, which may still lead to the inline code.
26240b57cec5SDimitry Andric bool HexagonFrameLowering::shouldInlineCSR(const MachineFunction &MF,
26250b57cec5SDimitry Andric       const CSIVect &CSI) const {
26265ffd83dbSDimitry Andric   if (MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl())
26275ffd83dbSDimitry Andric     return true;
26280b57cec5SDimitry Andric   if (MF.getInfo<HexagonMachineFunctionInfo>()->hasEHReturn())
26290b57cec5SDimitry Andric     return true;
26300b57cec5SDimitry Andric   if (!hasFP(MF))
26310b57cec5SDimitry Andric     return true;
26320b57cec5SDimitry Andric   if (!isOptSize(MF) && !isMinSize(MF))
26330b57cec5SDimitry Andric     if (MF.getTarget().getOptLevel() > CodeGenOpt::Default)
26340b57cec5SDimitry Andric       return true;
26350b57cec5SDimitry Andric 
26360b57cec5SDimitry Andric   // Check if CSI only has double registers, and if the registers form
26370b57cec5SDimitry Andric   // a contiguous block starting from D8.
26380b57cec5SDimitry Andric   BitVector Regs(Hexagon::NUM_TARGET_REGS);
26390b57cec5SDimitry Andric   for (unsigned i = 0, n = CSI.size(); i < n; ++i) {
26400b57cec5SDimitry Andric     unsigned R = CSI[i].getReg();
26410b57cec5SDimitry Andric     if (!Hexagon::DoubleRegsRegClass.contains(R))
26420b57cec5SDimitry Andric       return true;
26430b57cec5SDimitry Andric     Regs[R] = true;
26440b57cec5SDimitry Andric   }
26450b57cec5SDimitry Andric   int F = Regs.find_first();
26460b57cec5SDimitry Andric   if (F != Hexagon::D8)
26470b57cec5SDimitry Andric     return true;
26480b57cec5SDimitry Andric   while (F >= 0) {
26490b57cec5SDimitry Andric     int N = Regs.find_next(F);
26500b57cec5SDimitry Andric     if (N >= 0 && N != F+1)
26510b57cec5SDimitry Andric       return true;
26520b57cec5SDimitry Andric     F = N;
26530b57cec5SDimitry Andric   }
26540b57cec5SDimitry Andric 
26550b57cec5SDimitry Andric   return false;
26560b57cec5SDimitry Andric }
26570b57cec5SDimitry Andric 
26580b57cec5SDimitry Andric bool HexagonFrameLowering::useSpillFunction(const MachineFunction &MF,
26590b57cec5SDimitry Andric       const CSIVect &CSI) const {
26600b57cec5SDimitry Andric   if (shouldInlineCSR(MF, CSI))
26610b57cec5SDimitry Andric     return false;
26620b57cec5SDimitry Andric   unsigned NumCSI = CSI.size();
26630b57cec5SDimitry Andric   if (NumCSI <= 1)
26640b57cec5SDimitry Andric     return false;
26650b57cec5SDimitry Andric 
26660b57cec5SDimitry Andric   unsigned Threshold = isOptSize(MF) ? SpillFuncThresholdOs
26670b57cec5SDimitry Andric                                      : SpillFuncThreshold;
26680b57cec5SDimitry Andric   return Threshold < NumCSI;
26690b57cec5SDimitry Andric }
26700b57cec5SDimitry Andric 
26710b57cec5SDimitry Andric bool HexagonFrameLowering::useRestoreFunction(const MachineFunction &MF,
26720b57cec5SDimitry Andric       const CSIVect &CSI) const {
26730b57cec5SDimitry Andric   if (shouldInlineCSR(MF, CSI))
26740b57cec5SDimitry Andric     return false;
26750b57cec5SDimitry Andric   // The restore functions do a bit more than just restoring registers.
26760b57cec5SDimitry Andric   // The non-returning versions will go back directly to the caller's
26770b57cec5SDimitry Andric   // caller, others will clean up the stack frame in preparation for
26780b57cec5SDimitry Andric   // a tail call. Using them can still save code size even if only one
26790b57cec5SDimitry Andric   // register is getting restores. Make the decision based on -Oz:
26800b57cec5SDimitry Andric   // using -Os will use inline restore for a single register.
26810b57cec5SDimitry Andric   if (isMinSize(MF))
26820b57cec5SDimitry Andric     return true;
26830b57cec5SDimitry Andric   unsigned NumCSI = CSI.size();
26840b57cec5SDimitry Andric   if (NumCSI <= 1)
26850b57cec5SDimitry Andric     return false;
26860b57cec5SDimitry Andric 
26870b57cec5SDimitry Andric   unsigned Threshold = isOptSize(MF) ? SpillFuncThresholdOs-1
26880b57cec5SDimitry Andric                                      : SpillFuncThreshold;
26890b57cec5SDimitry Andric   return Threshold < NumCSI;
26900b57cec5SDimitry Andric }
26910b57cec5SDimitry Andric 
26920b57cec5SDimitry Andric bool HexagonFrameLowering::mayOverflowFrameOffset(MachineFunction &MF) const {
26930b57cec5SDimitry Andric   unsigned StackSize = MF.getFrameInfo().estimateStackSize(MF);
26940b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
26950b57cec5SDimitry Andric   // A fairly simplistic guess as to whether a potential load/store to a
26960b57cec5SDimitry Andric   // stack location could require an extra register.
26970b57cec5SDimitry Andric   if (HST.useHVXOps() && StackSize > 256)
26980b57cec5SDimitry Andric     return true;
26990b57cec5SDimitry Andric 
27000b57cec5SDimitry Andric   // Check if the function has store-immediate instructions that access
27010b57cec5SDimitry Andric   // the stack. Since the offset field is not extendable, if the stack
27020b57cec5SDimitry Andric   // size exceeds the offset limit (6 bits, shifted), the stores will
27030b57cec5SDimitry Andric   // require a new base register.
27040b57cec5SDimitry Andric   bool HasImmStack = false;
27050b57cec5SDimitry Andric   unsigned MinLS = ~0u;   // Log_2 of the memory access size.
27060b57cec5SDimitry Andric 
27070b57cec5SDimitry Andric   for (const MachineBasicBlock &B : MF) {
27080b57cec5SDimitry Andric     for (const MachineInstr &MI : B) {
27090b57cec5SDimitry Andric       unsigned LS = 0;
27100b57cec5SDimitry Andric       switch (MI.getOpcode()) {
27110b57cec5SDimitry Andric         case Hexagon::S4_storeirit_io:
27120b57cec5SDimitry Andric         case Hexagon::S4_storeirif_io:
27130b57cec5SDimitry Andric         case Hexagon::S4_storeiri_io:
27140b57cec5SDimitry Andric           ++LS;
27150b57cec5SDimitry Andric           LLVM_FALLTHROUGH;
27160b57cec5SDimitry Andric         case Hexagon::S4_storeirht_io:
27170b57cec5SDimitry Andric         case Hexagon::S4_storeirhf_io:
27180b57cec5SDimitry Andric         case Hexagon::S4_storeirh_io:
27190b57cec5SDimitry Andric           ++LS;
27200b57cec5SDimitry Andric           LLVM_FALLTHROUGH;
27210b57cec5SDimitry Andric         case Hexagon::S4_storeirbt_io:
27220b57cec5SDimitry Andric         case Hexagon::S4_storeirbf_io:
27230b57cec5SDimitry Andric         case Hexagon::S4_storeirb_io:
27240b57cec5SDimitry Andric           if (MI.getOperand(0).isFI())
27250b57cec5SDimitry Andric             HasImmStack = true;
27260b57cec5SDimitry Andric           MinLS = std::min(MinLS, LS);
27270b57cec5SDimitry Andric           break;
27280b57cec5SDimitry Andric       }
27290b57cec5SDimitry Andric     }
27300b57cec5SDimitry Andric   }
27310b57cec5SDimitry Andric 
27320b57cec5SDimitry Andric   if (HasImmStack)
27330b57cec5SDimitry Andric     return !isUInt<6>(StackSize >> MinLS);
27340b57cec5SDimitry Andric 
27350b57cec5SDimitry Andric   return false;
27360b57cec5SDimitry Andric }
2737