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/PostOrderIterator.h"
210b57cec5SDimitry Andric #include "llvm/ADT/SetVector.h"
220b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
230b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/LivePhysRegs.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h"
330b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
340b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
350b57cec5SDimitry Andric #include "llvm/CodeGen/MachinePostDominators.h"
360b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
37480093f4SDimitry Andric #include "llvm/CodeGen/PseudoSourceValue.h"
380b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h"
390b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
400b57cec5SDimitry Andric #include "llvm/IR/Attributes.h"
410b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h"
420b57cec5SDimitry Andric #include "llvm/IR/Function.h"
430b57cec5SDimitry Andric #include "llvm/MC/MCDwarf.h"
440b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
450b57cec5SDimitry Andric #include "llvm/Pass.h"
460b57cec5SDimitry Andric #include "llvm/Support/CodeGen.h"
470b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
480b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
490b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
500b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
510b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
520b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
530b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
540b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h"
550b57cec5SDimitry Andric #include <algorithm>
560b57cec5SDimitry Andric #include <cassert>
570b57cec5SDimitry Andric #include <cstdint>
580b57cec5SDimitry Andric #include <iterator>
590b57cec5SDimitry Andric #include <limits>
600b57cec5SDimitry Andric #include <map>
61bdd1243dSDimitry Andric #include <optional>
620b57cec5SDimitry Andric #include <utility>
630b57cec5SDimitry Andric #include <vector>
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric #define DEBUG_TYPE "hexagon-pei"
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric // Hexagon stack frame layout as defined by the ABI:
680b57cec5SDimitry Andric //
690b57cec5SDimitry Andric //                                                       Incoming arguments
700b57cec5SDimitry Andric //                                                       passed via stack
710b57cec5SDimitry Andric //                                                                      |
720b57cec5SDimitry Andric //                                                                      |
730b57cec5SDimitry Andric //        SP during function's                 FP during function's     |
740b57cec5SDimitry Andric //    +-- runtime (top of stack)               runtime (bottom) --+     |
750b57cec5SDimitry Andric //    |                                                           |     |
760b57cec5SDimitry Andric // --++---------------------+------------------+-----------------++-+-------
770b57cec5SDimitry Andric //   |  parameter area for  |  variable-size   |   fixed-size    |LR|  arg
780b57cec5SDimitry Andric //   |   called functions   |  local objects   |  local objects  |FP|
790b57cec5SDimitry Andric // --+----------------------+------------------+-----------------+--+-------
800b57cec5SDimitry Andric //    <-    size known    -> <- size unknown -> <- size known  ->
810b57cec5SDimitry Andric //
820b57cec5SDimitry Andric // Low address                                                 High address
830b57cec5SDimitry Andric //
840b57cec5SDimitry Andric // <--- stack growth
850b57cec5SDimitry Andric //
860b57cec5SDimitry Andric //
870b57cec5SDimitry Andric // - In any circumstances, the outgoing function arguments are always accessi-
880b57cec5SDimitry Andric //   ble using the SP, and the incoming arguments are accessible using the FP.
890b57cec5SDimitry Andric // - If the local objects are not aligned, they can always be accessed using
900b57cec5SDimitry Andric //   the FP.
910b57cec5SDimitry Andric // - If there are no variable-sized objects, the local objects can always be
920b57cec5SDimitry Andric //   accessed using the SP, regardless whether they are aligned or not. (The
930b57cec5SDimitry Andric //   alignment padding will be at the bottom of the stack (highest address),
940b57cec5SDimitry Andric //   and so the offset with respect to the SP will be known at the compile-
950b57cec5SDimitry Andric //   -time.)
960b57cec5SDimitry Andric //
970b57cec5SDimitry Andric // The only complication occurs if there are both, local aligned objects, and
980b57cec5SDimitry Andric // dynamically allocated (variable-sized) objects. The alignment pad will be
990b57cec5SDimitry Andric // placed between the FP and the local objects, thus preventing the use of the
1000b57cec5SDimitry Andric // FP to access the local objects. At the same time, the variable-sized objects
1010b57cec5SDimitry Andric // will be between the SP and the local objects, thus introducing an unknown
1020b57cec5SDimitry Andric // distance from the SP to the locals.
1030b57cec5SDimitry Andric //
1040b57cec5SDimitry Andric // To avoid this problem, a new register is created that holds the aligned
1050b57cec5SDimitry Andric // address of the bottom of the stack, referred in the sources as AP (aligned
1060b57cec5SDimitry Andric // pointer). The AP will be equal to "FP-p", where "p" is the smallest pad
1070b57cec5SDimitry Andric // that aligns AP to the required boundary (a maximum of the alignments of
1080b57cec5SDimitry Andric // all stack objects, fixed- and variable-sized). All local objects[1] will
1090b57cec5SDimitry Andric // then use AP as the base pointer.
1100b57cec5SDimitry Andric // [1] The exception is with "fixed" stack objects. "Fixed" stack objects get
1110b57cec5SDimitry Andric // their name from being allocated at fixed locations on the stack, relative
1120b57cec5SDimitry Andric // to the FP. In the presence of dynamic allocation and local alignment, such
1130b57cec5SDimitry Andric // objects can only be accessed through the FP.
1140b57cec5SDimitry Andric //
1150b57cec5SDimitry Andric // Illustration of the AP:
1160b57cec5SDimitry Andric //                                                                FP --+
1170b57cec5SDimitry Andric //                                                                     |
1180b57cec5SDimitry Andric // ---------------+---------------------+-----+-----------------------++-+--
1190b57cec5SDimitry Andric //   Rest of the  | Local stack objects | Pad |  Fixed stack objects  |LR|
1200b57cec5SDimitry Andric //   stack frame  | (aligned)           |     |  (CSR, spills, etc.)  |FP|
1210b57cec5SDimitry Andric // ---------------+---------------------+-----+-----------------+-----+--+--
1220b57cec5SDimitry Andric //                                      |<-- Multiple of the -->|
1230b57cec5SDimitry Andric //                                           stack alignment    +-- AP
1240b57cec5SDimitry Andric //
1250b57cec5SDimitry Andric // The AP is set up at the beginning of the function. Since it is not a dedi-
1260b57cec5SDimitry Andric // cated (reserved) register, it needs to be kept live throughout the function
1270b57cec5SDimitry Andric // to be available as the base register for local object accesses.
1280b57cec5SDimitry Andric // Normally, an address of a stack objects is obtained by a pseudo-instruction
1290b57cec5SDimitry Andric // PS_fi. To access local objects with the AP register present, a different
1300b57cec5SDimitry Andric // pseudo-instruction needs to be used: PS_fia. The PS_fia takes one extra
1310b57cec5SDimitry Andric // argument compared to PS_fi: the first input register is the AP register.
1320b57cec5SDimitry Andric // This keeps the register live between its definition and its uses.
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric // The AP register is originally set up using pseudo-instruction PS_aligna:
1350b57cec5SDimitry Andric //   AP = PS_aligna A
1360b57cec5SDimitry Andric // where
1370b57cec5SDimitry Andric //   A  - required stack alignment
1380b57cec5SDimitry Andric // The alignment value must be the maximum of all alignments required by
1390b57cec5SDimitry Andric // any stack object.
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric // The dynamic allocation uses a pseudo-instruction PS_alloca:
1420b57cec5SDimitry Andric //   Rd = PS_alloca Rs, A
1430b57cec5SDimitry Andric // where
1440b57cec5SDimitry Andric //   Rd - address of the allocated space
1450b57cec5SDimitry Andric //   Rs - minimum size (the actual allocated can be larger to accommodate
1460b57cec5SDimitry Andric //        alignment)
1470b57cec5SDimitry Andric //   A  - required alignment
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric using namespace llvm;
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric static cl::opt<bool> DisableDeallocRet("disable-hexagon-dealloc-ret",
1520b57cec5SDimitry Andric     cl::Hidden, cl::desc("Disable Dealloc Return for Hexagon target"));
1530b57cec5SDimitry Andric 
15481ad6265SDimitry Andric static cl::opt<unsigned>
15581ad6265SDimitry Andric     NumberScavengerSlots("number-scavenger-slots", cl::Hidden,
15681ad6265SDimitry Andric                          cl::desc("Set the number of scavenger slots"),
15781ad6265SDimitry Andric                          cl::init(2));
1580b57cec5SDimitry Andric 
15981ad6265SDimitry Andric static cl::opt<int>
16081ad6265SDimitry Andric     SpillFuncThreshold("spill-func-threshold", cl::Hidden,
16181ad6265SDimitry Andric                        cl::desc("Specify O2(not Os) spill func threshold"),
16281ad6265SDimitry Andric                        cl::init(6));
1630b57cec5SDimitry Andric 
16481ad6265SDimitry Andric static cl::opt<int>
16581ad6265SDimitry Andric     SpillFuncThresholdOs("spill-func-threshold-Os", cl::Hidden,
16681ad6265SDimitry Andric                          cl::desc("Specify Os spill func threshold"),
16781ad6265SDimitry Andric                          cl::init(1));
1680b57cec5SDimitry Andric 
16981ad6265SDimitry Andric static cl::opt<bool> EnableStackOVFSanitizer(
17081ad6265SDimitry Andric     "enable-stackovf-sanitizer", cl::Hidden,
17181ad6265SDimitry Andric     cl::desc("Enable runtime checks for stack overflow."), cl::init(false));
1720b57cec5SDimitry Andric 
17381ad6265SDimitry Andric static cl::opt<bool>
17481ad6265SDimitry Andric     EnableShrinkWrapping("hexagon-shrink-frame", cl::init(true), cl::Hidden,
1750b57cec5SDimitry Andric                          cl::desc("Enable stack frame shrink wrapping"));
1760b57cec5SDimitry Andric 
17781ad6265SDimitry Andric static cl::opt<unsigned>
17881ad6265SDimitry Andric     ShrinkLimit("shrink-frame-limit",
17981ad6265SDimitry Andric                 cl::init(std::numeric_limits<unsigned>::max()), cl::Hidden,
1800b57cec5SDimitry Andric                 cl::desc("Max count of stack frame shrink-wraps"));
1810b57cec5SDimitry Andric 
18281ad6265SDimitry Andric static cl::opt<bool>
18381ad6265SDimitry Andric     EnableSaveRestoreLong("enable-save-restore-long", cl::Hidden,
18481ad6265SDimitry Andric                           cl::desc("Enable long calls for save-restore stubs."),
18581ad6265SDimitry Andric                           cl::init(false));
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric static cl::opt<bool> EliminateFramePointer("hexagon-fp-elim", cl::init(true),
1880b57cec5SDimitry Andric     cl::Hidden, cl::desc("Refrain from using FP whenever possible"));
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric static cl::opt<bool> OptimizeSpillSlots("hexagon-opt-spill", cl::Hidden,
1910b57cec5SDimitry Andric     cl::init(true), cl::desc("Optimize spill slots"));
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric #ifndef NDEBUG
1940b57cec5SDimitry Andric static cl::opt<unsigned> SpillOptMax("spill-opt-max", cl::Hidden,
1950b57cec5SDimitry Andric     cl::init(std::numeric_limits<unsigned>::max()));
1960b57cec5SDimitry Andric static unsigned SpillOptCount = 0;
1970b57cec5SDimitry Andric #endif
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric namespace llvm {
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric   void initializeHexagonCallFrameInformationPass(PassRegistry&);
2020b57cec5SDimitry Andric   FunctionPass *createHexagonCallFrameInformation();
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric } // end namespace llvm
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric namespace {
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric   class HexagonCallFrameInformation : public MachineFunctionPass {
2090b57cec5SDimitry Andric   public:
2100b57cec5SDimitry Andric     static char ID;
2110b57cec5SDimitry Andric 
HexagonCallFrameInformation()2120b57cec5SDimitry Andric     HexagonCallFrameInformation() : MachineFunctionPass(ID) {
2130b57cec5SDimitry Andric       PassRegistry &PR = *PassRegistry::getPassRegistry();
2140b57cec5SDimitry Andric       initializeHexagonCallFrameInformationPass(PR);
2150b57cec5SDimitry Andric     }
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric     bool runOnMachineFunction(MachineFunction &MF) override;
2180b57cec5SDimitry Andric 
getRequiredProperties() const2190b57cec5SDimitry Andric     MachineFunctionProperties getRequiredProperties() const override {
2200b57cec5SDimitry Andric       return MachineFunctionProperties().set(
2210b57cec5SDimitry Andric           MachineFunctionProperties::Property::NoVRegs);
2220b57cec5SDimitry Andric     }
2230b57cec5SDimitry Andric   };
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric   char HexagonCallFrameInformation::ID = 0;
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric } // end anonymous namespace
2280b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)2290b57cec5SDimitry Andric bool HexagonCallFrameInformation::runOnMachineFunction(MachineFunction &MF) {
2300b57cec5SDimitry Andric   auto &HFI = *MF.getSubtarget<HexagonSubtarget>().getFrameLowering();
231480093f4SDimitry Andric   bool NeedCFI = MF.needsFrameMoves();
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   if (!NeedCFI)
2340b57cec5SDimitry Andric     return false;
2350b57cec5SDimitry Andric   HFI.insertCFIInstructions(MF);
2360b57cec5SDimitry Andric   return true;
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric INITIALIZE_PASS(HexagonCallFrameInformation, "hexagon-cfi",
2400b57cec5SDimitry Andric                 "Hexagon call frame information", false, false)
2410b57cec5SDimitry Andric 
createHexagonCallFrameInformation()2420b57cec5SDimitry Andric FunctionPass *llvm::createHexagonCallFrameInformation() {
2430b57cec5SDimitry Andric   return new HexagonCallFrameInformation();
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric /// Map a register pair Reg to the subregister that has the greater "number",
2470b57cec5SDimitry Andric /// i.e. D3 (aka R7:6) will be mapped to R7, etc.
getMax32BitSubRegister(Register Reg,const TargetRegisterInfo & TRI,bool hireg=true)248bdd1243dSDimitry Andric static Register getMax32BitSubRegister(Register Reg,
2490b57cec5SDimitry Andric                                        const TargetRegisterInfo &TRI,
2500b57cec5SDimitry Andric                                        bool hireg = true) {
2510b57cec5SDimitry Andric     if (Reg < Hexagon::D0 || Reg > Hexagon::D15)
2520b57cec5SDimitry Andric       return Reg;
2530b57cec5SDimitry Andric 
254bdd1243dSDimitry Andric     Register RegNo = 0;
25506c3fb27SDimitry Andric     for (MCPhysReg SubReg : TRI.subregs(Reg)) {
2560b57cec5SDimitry Andric       if (hireg) {
25706c3fb27SDimitry Andric         if (SubReg > RegNo)
25806c3fb27SDimitry Andric           RegNo = SubReg;
2590b57cec5SDimitry Andric       } else {
26006c3fb27SDimitry Andric         if (!RegNo || SubReg < RegNo)
26106c3fb27SDimitry Andric           RegNo = SubReg;
2620b57cec5SDimitry Andric       }
2630b57cec5SDimitry Andric     }
2640b57cec5SDimitry Andric     return RegNo;
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric /// Returns the callee saved register with the largest id in the vector.
getMaxCalleeSavedReg(ArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo & TRI)268bdd1243dSDimitry Andric static Register getMaxCalleeSavedReg(ArrayRef<CalleeSavedInfo> CSI,
2690b57cec5SDimitry Andric                                      const TargetRegisterInfo &TRI) {
2700b57cec5SDimitry Andric   static_assert(Hexagon::R1 > 0,
2710b57cec5SDimitry Andric                 "Assume physical registers are encoded as positive integers");
2720b57cec5SDimitry Andric   if (CSI.empty())
2730b57cec5SDimitry Andric     return 0;
2740b57cec5SDimitry Andric 
275bdd1243dSDimitry Andric   Register Max = getMax32BitSubRegister(CSI[0].getReg(), TRI);
2760b57cec5SDimitry Andric   for (unsigned I = 1, E = CSI.size(); I < E; ++I) {
277bdd1243dSDimitry Andric     Register Reg = getMax32BitSubRegister(CSI[I].getReg(), TRI);
2780b57cec5SDimitry Andric     if (Reg > Max)
2790b57cec5SDimitry Andric       Max = Reg;
2800b57cec5SDimitry Andric   }
2810b57cec5SDimitry Andric   return Max;
2820b57cec5SDimitry Andric }
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric /// Checks if the basic block contains any instruction that needs a stack
2850b57cec5SDimitry Andric /// frame to be already in place.
needsStackFrame(const MachineBasicBlock & MBB,const BitVector & CSR,const HexagonRegisterInfo & HRI)2860b57cec5SDimitry Andric static bool needsStackFrame(const MachineBasicBlock &MBB, const BitVector &CSR,
2870b57cec5SDimitry Andric                             const HexagonRegisterInfo &HRI) {
288349cc55cSDimitry Andric     for (const MachineInstr &MI : MBB) {
289349cc55cSDimitry Andric       if (MI.isCall())
2900b57cec5SDimitry Andric         return true;
291349cc55cSDimitry Andric       unsigned Opc = MI.getOpcode();
2920b57cec5SDimitry Andric       switch (Opc) {
2930b57cec5SDimitry Andric         case Hexagon::PS_alloca:
2940b57cec5SDimitry Andric         case Hexagon::PS_aligna:
2950b57cec5SDimitry Andric           return true;
2960b57cec5SDimitry Andric         default:
2970b57cec5SDimitry Andric           break;
2980b57cec5SDimitry Andric       }
2990b57cec5SDimitry Andric       // Check individual operands.
300349cc55cSDimitry Andric       for (const MachineOperand &MO : MI.operands()) {
3010b57cec5SDimitry Andric         // While the presence of a frame index does not prove that a stack
3020b57cec5SDimitry Andric         // frame will be required, all frame indexes should be within alloc-
3030b57cec5SDimitry Andric         // frame/deallocframe. Otherwise, the code that translates a frame
3040b57cec5SDimitry Andric         // index into an offset would have to be aware of the placement of
3050b57cec5SDimitry Andric         // the frame creation/destruction instructions.
3060b57cec5SDimitry Andric         if (MO.isFI())
3070b57cec5SDimitry Andric           return true;
3080b57cec5SDimitry Andric         if (MO.isReg()) {
3098bcb0991SDimitry Andric           Register R = MO.getReg();
31006c3fb27SDimitry Andric           // Debug instructions may refer to $noreg.
31106c3fb27SDimitry Andric           if (!R)
31206c3fb27SDimitry Andric             continue;
3130b57cec5SDimitry Andric           // Virtual registers will need scavenging, which then may require
3140b57cec5SDimitry Andric           // a stack slot.
315e8d8bef9SDimitry Andric           if (R.isVirtual())
3160b57cec5SDimitry Andric             return true;
31706c3fb27SDimitry Andric           for (MCPhysReg S : HRI.subregs_inclusive(R))
31806c3fb27SDimitry Andric             if (CSR[S])
3190b57cec5SDimitry Andric               return true;
3200b57cec5SDimitry Andric           continue;
3210b57cec5SDimitry Andric         }
3220b57cec5SDimitry Andric         if (MO.isRegMask()) {
3230b57cec5SDimitry Andric           // A regmask would normally have all callee-saved registers marked
3240b57cec5SDimitry Andric           // as preserved, so this check would not be needed, but in case of
3250b57cec5SDimitry Andric           // ever having other regmasks (for other calling conventions),
3260b57cec5SDimitry Andric           // make sure they would be processed correctly.
3270b57cec5SDimitry Andric           const uint32_t *BM = MO.getRegMask();
3280b57cec5SDimitry Andric           for (int x = CSR.find_first(); x >= 0; x = CSR.find_next(x)) {
3290b57cec5SDimitry Andric             unsigned R = x;
3300b57cec5SDimitry Andric             // If this regmask does not preserve a CSR, a frame will be needed.
3310b57cec5SDimitry Andric             if (!(BM[R/32] & (1u << (R%32))))
3320b57cec5SDimitry Andric               return true;
3330b57cec5SDimitry Andric           }
3340b57cec5SDimitry Andric         }
3350b57cec5SDimitry Andric       }
3360b57cec5SDimitry Andric     }
3370b57cec5SDimitry Andric     return false;
3380b57cec5SDimitry Andric }
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric   /// Returns true if MBB has a machine instructions that indicates a tail call
3410b57cec5SDimitry Andric   /// in the block.
hasTailCall(const MachineBasicBlock & MBB)3420b57cec5SDimitry Andric static bool hasTailCall(const MachineBasicBlock &MBB) {
3430b57cec5SDimitry Andric     MachineBasicBlock::const_iterator I = MBB.getLastNonDebugInstr();
3440b57cec5SDimitry Andric     if (I == MBB.end())
3450b57cec5SDimitry Andric       return false;
3460b57cec5SDimitry Andric     unsigned RetOpc = I->getOpcode();
3470b57cec5SDimitry Andric     return RetOpc == Hexagon::PS_tailcall_i || RetOpc == Hexagon::PS_tailcall_r;
3480b57cec5SDimitry Andric }
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric /// Returns true if MBB contains an instruction that returns.
hasReturn(const MachineBasicBlock & MBB)3510b57cec5SDimitry Andric static bool hasReturn(const MachineBasicBlock &MBB) {
352349cc55cSDimitry Andric     for (const MachineInstr &MI : MBB.terminators())
353349cc55cSDimitry Andric       if (MI.isReturn())
3540b57cec5SDimitry Andric         return true;
3550b57cec5SDimitry Andric     return false;
3560b57cec5SDimitry Andric }
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric /// Returns the "return" instruction from this block, or nullptr if there
3590b57cec5SDimitry Andric /// isn't any.
getReturn(MachineBasicBlock & MBB)3600b57cec5SDimitry Andric static MachineInstr *getReturn(MachineBasicBlock &MBB) {
3610b57cec5SDimitry Andric     for (auto &I : MBB)
3620b57cec5SDimitry Andric       if (I.isReturn())
3630b57cec5SDimitry Andric         return &I;
3640b57cec5SDimitry Andric     return nullptr;
3650b57cec5SDimitry Andric }
3660b57cec5SDimitry Andric 
isRestoreCall(unsigned Opc)3670b57cec5SDimitry Andric static bool isRestoreCall(unsigned Opc) {
3680b57cec5SDimitry Andric     switch (Opc) {
3690b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_RET_JMP_V4:
3700b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC:
3710b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT:
3720b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC:
3730b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT:
3740b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC:
3750b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4:
3760b57cec5SDimitry Andric       case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC:
3770b57cec5SDimitry Andric         return true;
3780b57cec5SDimitry Andric     }
3790b57cec5SDimitry Andric     return false;
3800b57cec5SDimitry Andric }
3810b57cec5SDimitry Andric 
isOptNone(const MachineFunction & MF)3820b57cec5SDimitry Andric static inline bool isOptNone(const MachineFunction &MF) {
3830b57cec5SDimitry Andric     return MF.getFunction().hasOptNone() ||
3845f757f3fSDimitry Andric            MF.getTarget().getOptLevel() == CodeGenOptLevel::None;
3850b57cec5SDimitry Andric }
3860b57cec5SDimitry Andric 
isOptSize(const MachineFunction & MF)3870b57cec5SDimitry Andric static inline bool isOptSize(const MachineFunction &MF) {
3880b57cec5SDimitry Andric     const Function &F = MF.getFunction();
3890b57cec5SDimitry Andric     return F.hasOptSize() && !F.hasMinSize();
3900b57cec5SDimitry Andric }
3910b57cec5SDimitry Andric 
isMinSize(const MachineFunction & MF)3920b57cec5SDimitry Andric static inline bool isMinSize(const MachineFunction &MF) {
3930b57cec5SDimitry Andric     return MF.getFunction().hasMinSize();
3940b57cec5SDimitry Andric }
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric /// Implements shrink-wrapping of the stack frame. By default, stack frame
3970b57cec5SDimitry Andric /// is created in the function entry block, and is cleaned up in every block
3980b57cec5SDimitry Andric /// that returns. This function finds alternate blocks: one for the frame
3990b57cec5SDimitry Andric /// setup (prolog) and one for the cleanup (epilog).
findShrunkPrologEpilog(MachineFunction & MF,MachineBasicBlock * & PrologB,MachineBasicBlock * & EpilogB) const4000b57cec5SDimitry Andric void HexagonFrameLowering::findShrunkPrologEpilog(MachineFunction &MF,
4010b57cec5SDimitry Andric       MachineBasicBlock *&PrologB, MachineBasicBlock *&EpilogB) const {
4020b57cec5SDimitry Andric   static unsigned ShrinkCounter = 0;
4030b57cec5SDimitry Andric 
4045ffd83dbSDimitry Andric   if (MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl() &&
4055ffd83dbSDimitry Andric       MF.getFunction().isVarArg())
4065ffd83dbSDimitry Andric     return;
4070b57cec5SDimitry Andric   if (ShrinkLimit.getPosition()) {
4080b57cec5SDimitry Andric     if (ShrinkCounter >= ShrinkLimit)
4090b57cec5SDimitry Andric       return;
4100b57cec5SDimitry Andric     ShrinkCounter++;
4110b57cec5SDimitry Andric   }
4120b57cec5SDimitry Andric 
4130b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric   MachineDominatorTree MDT;
4160b57cec5SDimitry Andric   MDT.runOnMachineFunction(MF);
4170b57cec5SDimitry Andric   MachinePostDominatorTree MPT;
4180b57cec5SDimitry Andric   MPT.runOnMachineFunction(MF);
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric   using UnsignedMap = DenseMap<unsigned, unsigned>;
4210b57cec5SDimitry Andric   using RPOTType = ReversePostOrderTraversal<const MachineFunction *>;
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric   UnsignedMap RPO;
4240b57cec5SDimitry Andric   RPOTType RPOT(&MF);
4250b57cec5SDimitry Andric   unsigned RPON = 0;
42604eeddc0SDimitry Andric   for (auto &I : RPOT)
42704eeddc0SDimitry Andric     RPO[I->getNumber()] = RPON++;
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric   // Don't process functions that have loops, at least for now. Placement
4300b57cec5SDimitry Andric   // of prolog and epilog must take loop structure into account. For simpli-
4310b57cec5SDimitry Andric   // city don't do it right now.
4320b57cec5SDimitry Andric   for (auto &I : MF) {
4330b57cec5SDimitry Andric     unsigned BN = RPO[I.getNumber()];
434349cc55cSDimitry Andric     for (MachineBasicBlock *Succ : I.successors())
4350b57cec5SDimitry Andric       // If found a back-edge, return.
436349cc55cSDimitry Andric       if (RPO[Succ->getNumber()] <= BN)
4370b57cec5SDimitry Andric         return;
4380b57cec5SDimitry Andric   }
4390b57cec5SDimitry Andric 
4400b57cec5SDimitry Andric   // Collect the set of blocks that need a stack frame to execute. Scan
4410b57cec5SDimitry Andric   // each block for uses/defs of callee-saved registers, calls, etc.
4420b57cec5SDimitry Andric   SmallVector<MachineBasicBlock*,16> SFBlocks;
4430b57cec5SDimitry Andric   BitVector CSR(Hexagon::NUM_TARGET_REGS);
4440b57cec5SDimitry Andric   for (const MCPhysReg *P = HRI.getCalleeSavedRegs(&MF); *P; ++P)
44506c3fb27SDimitry Andric     for (MCPhysReg S : HRI.subregs_inclusive(*P))
44606c3fb27SDimitry Andric       CSR[S] = true;
4470b57cec5SDimitry Andric 
4480b57cec5SDimitry Andric   for (auto &I : MF)
4490b57cec5SDimitry Andric     if (needsStackFrame(I, CSR, HRI))
4500b57cec5SDimitry Andric       SFBlocks.push_back(&I);
4510b57cec5SDimitry Andric 
4520b57cec5SDimitry Andric   LLVM_DEBUG({
4530b57cec5SDimitry Andric     dbgs() << "Blocks needing SF: {";
4540b57cec5SDimitry Andric     for (auto &B : SFBlocks)
4550b57cec5SDimitry Andric       dbgs() << " " << printMBBReference(*B);
4560b57cec5SDimitry Andric     dbgs() << " }\n";
4570b57cec5SDimitry Andric   });
4580b57cec5SDimitry Andric   // No frame needed?
4590b57cec5SDimitry Andric   if (SFBlocks.empty())
4600b57cec5SDimitry Andric     return;
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric   // Pick a common dominator and a common post-dominator.
4630b57cec5SDimitry Andric   MachineBasicBlock *DomB = SFBlocks[0];
4640b57cec5SDimitry Andric   for (unsigned i = 1, n = SFBlocks.size(); i < n; ++i) {
4650b57cec5SDimitry Andric     DomB = MDT.findNearestCommonDominator(DomB, SFBlocks[i]);
4660b57cec5SDimitry Andric     if (!DomB)
4670b57cec5SDimitry Andric       break;
4680b57cec5SDimitry Andric   }
4690b57cec5SDimitry Andric   MachineBasicBlock *PDomB = SFBlocks[0];
4700b57cec5SDimitry Andric   for (unsigned i = 1, n = SFBlocks.size(); i < n; ++i) {
4710b57cec5SDimitry Andric     PDomB = MPT.findNearestCommonDominator(PDomB, SFBlocks[i]);
4720b57cec5SDimitry Andric     if (!PDomB)
4730b57cec5SDimitry Andric       break;
4740b57cec5SDimitry Andric   }
4750b57cec5SDimitry Andric   LLVM_DEBUG({
4760b57cec5SDimitry Andric     dbgs() << "Computed dom block: ";
4770b57cec5SDimitry Andric     if (DomB)
4780b57cec5SDimitry Andric       dbgs() << printMBBReference(*DomB);
4790b57cec5SDimitry Andric     else
4800b57cec5SDimitry Andric       dbgs() << "<null>";
4810b57cec5SDimitry Andric     dbgs() << ", computed pdom block: ";
4820b57cec5SDimitry Andric     if (PDomB)
4830b57cec5SDimitry Andric       dbgs() << printMBBReference(*PDomB);
4840b57cec5SDimitry Andric     else
4850b57cec5SDimitry Andric       dbgs() << "<null>";
4860b57cec5SDimitry Andric     dbgs() << "\n";
4870b57cec5SDimitry Andric   });
4880b57cec5SDimitry Andric   if (!DomB || !PDomB)
4890b57cec5SDimitry Andric     return;
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric   // Make sure that DomB dominates PDomB and PDomB post-dominates DomB.
4920b57cec5SDimitry Andric   if (!MDT.dominates(DomB, PDomB)) {
4930b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Dom block does not dominate pdom block\n");
4940b57cec5SDimitry Andric     return;
4950b57cec5SDimitry Andric   }
4960b57cec5SDimitry Andric   if (!MPT.dominates(PDomB, DomB)) {
4970b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "PDom block does not post-dominate dom block\n");
4980b57cec5SDimitry Andric     return;
4990b57cec5SDimitry Andric   }
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric   // Finally, everything seems right.
5020b57cec5SDimitry Andric   PrologB = DomB;
5030b57cec5SDimitry Andric   EpilogB = PDomB;
5040b57cec5SDimitry Andric }
5050b57cec5SDimitry Andric 
5060b57cec5SDimitry Andric /// Perform most of the PEI work here:
5070b57cec5SDimitry Andric /// - saving/restoring of the callee-saved registers,
5080b57cec5SDimitry Andric /// - stack frame creation and destruction.
5090b57cec5SDimitry Andric /// Normally, this work is distributed among various functions, but doing it
5100b57cec5SDimitry Andric /// in one place allows shrink-wrapping of the stack frame.
emitPrologue(MachineFunction & MF,MachineBasicBlock & MBB) const5110b57cec5SDimitry Andric void HexagonFrameLowering::emitPrologue(MachineFunction &MF,
5120b57cec5SDimitry Andric                                         MachineBasicBlock &MBB) const {
5130b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
5140b57cec5SDimitry Andric 
5150b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
5160b57cec5SDimitry Andric   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric   MachineBasicBlock *PrologB = &MF.front(), *EpilogB = nullptr;
5190b57cec5SDimitry Andric   if (EnableShrinkWrapping)
5200b57cec5SDimitry Andric     findShrunkPrologEpilog(MF, PrologB, EpilogB);
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric   bool PrologueStubs = false;
5230b57cec5SDimitry Andric   insertCSRSpillsInBlock(*PrologB, CSI, HRI, PrologueStubs);
5240b57cec5SDimitry Andric   insertPrologueInBlock(*PrologB, PrologueStubs);
5250b57cec5SDimitry Andric   updateEntryPaths(MF, *PrologB);
5260b57cec5SDimitry Andric 
5270b57cec5SDimitry Andric   if (EpilogB) {
5280b57cec5SDimitry Andric     insertCSRRestoresInBlock(*EpilogB, CSI, HRI);
5290b57cec5SDimitry Andric     insertEpilogueInBlock(*EpilogB);
5300b57cec5SDimitry Andric   } else {
5310b57cec5SDimitry Andric     for (auto &B : MF)
5320b57cec5SDimitry Andric       if (B.isReturnBlock())
5330b57cec5SDimitry Andric         insertCSRRestoresInBlock(B, CSI, HRI);
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric     for (auto &B : MF)
5360b57cec5SDimitry Andric       if (B.isReturnBlock())
5370b57cec5SDimitry Andric         insertEpilogueInBlock(B);
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric     for (auto &B : MF) {
5400b57cec5SDimitry Andric       if (B.empty())
5410b57cec5SDimitry Andric         continue;
5420b57cec5SDimitry Andric       MachineInstr *RetI = getReturn(B);
5430b57cec5SDimitry Andric       if (!RetI || isRestoreCall(RetI->getOpcode()))
5440b57cec5SDimitry Andric         continue;
5450b57cec5SDimitry Andric       for (auto &R : CSI)
5460b57cec5SDimitry Andric         RetI->addOperand(MachineOperand::CreateReg(R.getReg(), false, true));
5470b57cec5SDimitry Andric     }
5480b57cec5SDimitry Andric   }
5490b57cec5SDimitry Andric 
5500b57cec5SDimitry Andric   if (EpilogB) {
5510b57cec5SDimitry Andric     // If there is an epilog block, it may not have a return instruction.
5520b57cec5SDimitry Andric     // In such case, we need to add the callee-saved registers as live-ins
5530b57cec5SDimitry Andric     // in all blocks on all paths from the epilog to any return block.
5540b57cec5SDimitry Andric     unsigned MaxBN = MF.getNumBlockIDs();
5550b57cec5SDimitry Andric     BitVector DoneT(MaxBN+1), DoneF(MaxBN+1), Path(MaxBN+1);
5560b57cec5SDimitry Andric     updateExitPaths(*EpilogB, *EpilogB, DoneT, DoneF, Path);
5570b57cec5SDimitry Andric   }
5580b57cec5SDimitry Andric }
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric /// Returns true if the target can safely skip saving callee-saved registers
5610b57cec5SDimitry Andric /// for noreturn nounwind functions.
enableCalleeSaveSkip(const MachineFunction & MF) const5620b57cec5SDimitry Andric bool HexagonFrameLowering::enableCalleeSaveSkip(
5630b57cec5SDimitry Andric     const MachineFunction &MF) const {
5640b57cec5SDimitry Andric   const auto &F = MF.getFunction();
5650b57cec5SDimitry Andric   assert(F.hasFnAttribute(Attribute::NoReturn) &&
5660b57cec5SDimitry Andric          F.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
5670b57cec5SDimitry Andric          !F.getFunction().hasFnAttribute(Attribute::UWTable));
5680b57cec5SDimitry Andric   (void)F;
5690b57cec5SDimitry Andric 
5700b57cec5SDimitry Andric   // No need to save callee saved registers if the function does not return.
5710b57cec5SDimitry Andric   return MF.getSubtarget<HexagonSubtarget>().noreturnStackElim();
5720b57cec5SDimitry Andric }
5730b57cec5SDimitry Andric 
5740b57cec5SDimitry Andric // Helper function used to determine when to eliminate the stack frame for
5750b57cec5SDimitry Andric // functions marked as noreturn and when the noreturn-stack-elim options are
5760b57cec5SDimitry Andric // specified. When both these conditions are true, then a FP may not be needed
5770b57cec5SDimitry Andric // if the function makes a call. It is very similar to enableCalleeSaveSkip,
5780b57cec5SDimitry Andric // but it used to check if the allocframe can be eliminated as well.
enableAllocFrameElim(const MachineFunction & MF)5790b57cec5SDimitry Andric static bool enableAllocFrameElim(const MachineFunction &MF) {
5800b57cec5SDimitry Andric   const auto &F = MF.getFunction();
5810b57cec5SDimitry Andric   const auto &MFI = MF.getFrameInfo();
5820b57cec5SDimitry Andric   const auto &HST = MF.getSubtarget<HexagonSubtarget>();
5830b57cec5SDimitry Andric   assert(!MFI.hasVarSizedObjects() &&
584fe6060f1SDimitry Andric          !HST.getRegisterInfo()->hasStackRealignment(MF));
5850b57cec5SDimitry Andric   return F.hasFnAttribute(Attribute::NoReturn) &&
5860b57cec5SDimitry Andric     F.hasFnAttribute(Attribute::NoUnwind) &&
5870b57cec5SDimitry Andric     !F.hasFnAttribute(Attribute::UWTable) && HST.noreturnStackElim() &&
5880b57cec5SDimitry Andric     MFI.getStackSize() == 0;
5890b57cec5SDimitry Andric }
5900b57cec5SDimitry Andric 
insertPrologueInBlock(MachineBasicBlock & MBB,bool PrologueStubs) const5910b57cec5SDimitry Andric void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB,
5920b57cec5SDimitry Andric       bool PrologueStubs) const {
5930b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
5940b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
5950b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
5960b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
5970b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
5980b57cec5SDimitry Andric 
5995ffd83dbSDimitry Andric   Align MaxAlign = std::max(MFI.getMaxAlign(), getStackAlign());
6000b57cec5SDimitry Andric 
6010b57cec5SDimitry Andric   // Calculate the total stack frame size.
6020b57cec5SDimitry Andric   // Get the number of bytes to allocate from the FrameInfo.
6030b57cec5SDimitry Andric   unsigned FrameSize = MFI.getStackSize();
6040b57cec5SDimitry Andric   // Round up the max call frame size to the max alignment on the stack.
6050b57cec5SDimitry Andric   unsigned MaxCFA = alignTo(MFI.getMaxCallFrameSize(), MaxAlign);
6060b57cec5SDimitry Andric   MFI.setMaxCallFrameSize(MaxCFA);
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric   FrameSize = MaxCFA + alignTo(FrameSize, MaxAlign);
6090b57cec5SDimitry Andric   MFI.setStackSize(FrameSize);
6100b57cec5SDimitry Andric 
6115ffd83dbSDimitry Andric   bool AlignStack = (MaxAlign > getStackAlign());
6120b57cec5SDimitry Andric 
6130b57cec5SDimitry Andric   // Get the number of bytes to allocate from the FrameInfo.
6140b57cec5SDimitry Andric   unsigned NumBytes = MFI.getStackSize();
615bdd1243dSDimitry Andric   Register SP = HRI.getStackRegister();
6160b57cec5SDimitry Andric   unsigned MaxCF = MFI.getMaxCallFrameSize();
6170b57cec5SDimitry Andric   MachineBasicBlock::iterator InsertPt = MBB.begin();
6180b57cec5SDimitry Andric 
6190b57cec5SDimitry Andric   SmallVector<MachineInstr *, 4> AdjustRegs;
6200b57cec5SDimitry Andric   for (auto &MBB : MF)
6210b57cec5SDimitry Andric     for (auto &MI : MBB)
6220b57cec5SDimitry Andric       if (MI.getOpcode() == Hexagon::PS_alloca)
6230b57cec5SDimitry Andric         AdjustRegs.push_back(&MI);
6240b57cec5SDimitry Andric 
625bdd1243dSDimitry Andric   for (auto *MI : AdjustRegs) {
6260b57cec5SDimitry Andric     assert((MI->getOpcode() == Hexagon::PS_alloca) && "Expected alloca");
6270b57cec5SDimitry Andric     expandAlloca(MI, HII, SP, MaxCF);
6280b57cec5SDimitry Andric     MI->eraseFromParent();
6290b57cec5SDimitry Andric   }
6300b57cec5SDimitry Andric 
6310b57cec5SDimitry Andric   DebugLoc dl = MBB.findDebugLoc(InsertPt);
6320b57cec5SDimitry Andric 
6335ffd83dbSDimitry Andric   if (MF.getFunction().isVarArg() &&
6345ffd83dbSDimitry Andric       MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl()) {
6355ffd83dbSDimitry Andric     // Calculate the size of register saved area.
6365ffd83dbSDimitry Andric     int NumVarArgRegs = 6 - FirstVarArgSavedReg;
6375ffd83dbSDimitry Andric     int RegisterSavedAreaSizePlusPadding = (NumVarArgRegs % 2 == 0)
6385ffd83dbSDimitry Andric                                               ? NumVarArgRegs * 4
6395ffd83dbSDimitry Andric                                               : NumVarArgRegs * 4 + 4;
6405ffd83dbSDimitry Andric     if (RegisterSavedAreaSizePlusPadding > 0) {
6415ffd83dbSDimitry Andric       // Decrement the stack pointer by size of register saved area plus
6425ffd83dbSDimitry Andric       // padding if any.
6435ffd83dbSDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP)
6445ffd83dbSDimitry Andric         .addReg(SP)
6455ffd83dbSDimitry Andric         .addImm(-RegisterSavedAreaSizePlusPadding)
6465ffd83dbSDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
6475ffd83dbSDimitry Andric 
6485ffd83dbSDimitry Andric       int NumBytes = 0;
6495ffd83dbSDimitry Andric       // Copy all the named arguments below register saved area.
6505ffd83dbSDimitry Andric       auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
6515ffd83dbSDimitry Andric       for (int i = HMFI.getFirstNamedArgFrameIndex(),
6525ffd83dbSDimitry Andric                e = HMFI.getLastNamedArgFrameIndex(); i >= e; --i) {
6535ffd83dbSDimitry Andric         uint64_t ObjSize = MFI.getObjectSize(i);
6545ffd83dbSDimitry Andric         Align ObjAlign = MFI.getObjectAlign(i);
6555ffd83dbSDimitry Andric 
6565ffd83dbSDimitry Andric         // Determine the kind of load/store that should be used.
6575ffd83dbSDimitry Andric         unsigned LDOpc, STOpc;
6585ffd83dbSDimitry Andric         uint64_t OpcodeChecker = ObjAlign.value();
6595ffd83dbSDimitry Andric 
6605ffd83dbSDimitry Andric         // Handle cases where alignment of an object is > its size.
6615ffd83dbSDimitry Andric         if (ObjAlign > ObjSize) {
6625ffd83dbSDimitry Andric           if (ObjSize <= 1)
6635ffd83dbSDimitry Andric             OpcodeChecker = 1;
6645ffd83dbSDimitry Andric           else if (ObjSize <= 2)
6655ffd83dbSDimitry Andric             OpcodeChecker = 2;
6665ffd83dbSDimitry Andric           else if (ObjSize <= 4)
6675ffd83dbSDimitry Andric             OpcodeChecker = 4;
6685ffd83dbSDimitry Andric           else if (ObjSize > 4)
6695ffd83dbSDimitry Andric             OpcodeChecker = 8;
6705ffd83dbSDimitry Andric         }
6715ffd83dbSDimitry Andric 
6725ffd83dbSDimitry Andric         switch (OpcodeChecker) {
6735ffd83dbSDimitry Andric           case 1:
6745ffd83dbSDimitry Andric             LDOpc = Hexagon::L2_loadrb_io;
6755ffd83dbSDimitry Andric             STOpc = Hexagon::S2_storerb_io;
6765ffd83dbSDimitry Andric             break;
6775ffd83dbSDimitry Andric           case 2:
6785ffd83dbSDimitry Andric             LDOpc = Hexagon::L2_loadrh_io;
6795ffd83dbSDimitry Andric             STOpc = Hexagon::S2_storerh_io;
6805ffd83dbSDimitry Andric             break;
6815ffd83dbSDimitry Andric           case 4:
6825ffd83dbSDimitry Andric             LDOpc = Hexagon::L2_loadri_io;
6835ffd83dbSDimitry Andric             STOpc = Hexagon::S2_storeri_io;
6845ffd83dbSDimitry Andric             break;
6855ffd83dbSDimitry Andric           case 8:
6865ffd83dbSDimitry Andric           default:
6875ffd83dbSDimitry Andric             LDOpc = Hexagon::L2_loadrd_io;
6885ffd83dbSDimitry Andric             STOpc = Hexagon::S2_storerd_io;
6895ffd83dbSDimitry Andric             break;
6905ffd83dbSDimitry Andric         }
6915ffd83dbSDimitry Andric 
692bdd1243dSDimitry Andric         Register RegUsed = LDOpc == Hexagon::L2_loadrd_io ? Hexagon::D3
6935ffd83dbSDimitry Andric                                                           : Hexagon::R6;
6945ffd83dbSDimitry Andric         int LoadStoreCount = ObjSize / OpcodeChecker;
6955ffd83dbSDimitry Andric 
6965ffd83dbSDimitry Andric         if (ObjSize % OpcodeChecker)
6975ffd83dbSDimitry Andric           ++LoadStoreCount;
6985ffd83dbSDimitry Andric 
6995ffd83dbSDimitry Andric         // Get the start location of the load. NumBytes is basically the
7005ffd83dbSDimitry Andric         // offset from the stack pointer of previous function, which would be
7015ffd83dbSDimitry Andric         // the caller in this case, as this function has variable argument
7025ffd83dbSDimitry Andric         // list.
7035ffd83dbSDimitry Andric         if (NumBytes != 0)
7045ffd83dbSDimitry Andric           NumBytes = alignTo(NumBytes, ObjAlign);
7055ffd83dbSDimitry Andric 
7065ffd83dbSDimitry Andric         int Count = 0;
7075ffd83dbSDimitry Andric         while (Count < LoadStoreCount) {
7085ffd83dbSDimitry Andric           // Load the value of the named argument on stack.
7095ffd83dbSDimitry Andric           BuildMI(MBB, InsertPt, dl, HII.get(LDOpc), RegUsed)
7105ffd83dbSDimitry Andric               .addReg(SP)
7115ffd83dbSDimitry Andric               .addImm(RegisterSavedAreaSizePlusPadding +
7125ffd83dbSDimitry Andric                       ObjAlign.value() * Count + NumBytes)
7135ffd83dbSDimitry Andric               .setMIFlag(MachineInstr::FrameSetup);
7145ffd83dbSDimitry Andric 
7155ffd83dbSDimitry Andric           // Store it below the register saved area plus padding.
7165ffd83dbSDimitry Andric           BuildMI(MBB, InsertPt, dl, HII.get(STOpc))
7175ffd83dbSDimitry Andric               .addReg(SP)
7185ffd83dbSDimitry Andric               .addImm(ObjAlign.value() * Count + NumBytes)
7195ffd83dbSDimitry Andric               .addReg(RegUsed)
7205ffd83dbSDimitry Andric               .setMIFlag(MachineInstr::FrameSetup);
7215ffd83dbSDimitry Andric 
7225ffd83dbSDimitry Andric           Count++;
7235ffd83dbSDimitry Andric         }
7245ffd83dbSDimitry Andric         NumBytes += MFI.getObjectSize(i);
7255ffd83dbSDimitry Andric       }
7265ffd83dbSDimitry Andric 
7275ffd83dbSDimitry Andric       // Make NumBytes 8 byte aligned
7285ffd83dbSDimitry Andric       NumBytes = alignTo(NumBytes, 8);
7295ffd83dbSDimitry Andric 
7305ffd83dbSDimitry Andric       // If the number of registers having variable arguments is odd,
7315ffd83dbSDimitry Andric       // leave 4 bytes of padding to get to the location where first
7325ffd83dbSDimitry Andric       // variable argument which was passed through register was copied.
7335ffd83dbSDimitry Andric       NumBytes = (NumVarArgRegs % 2 == 0) ? NumBytes : NumBytes + 4;
7345ffd83dbSDimitry Andric 
7355ffd83dbSDimitry Andric       for (int j = FirstVarArgSavedReg, i = 0; j < 6; ++j, ++i) {
7365ffd83dbSDimitry Andric         BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::S2_storeri_io))
7375ffd83dbSDimitry Andric           .addReg(SP)
7385ffd83dbSDimitry Andric           .addImm(NumBytes + 4 * i)
7395ffd83dbSDimitry Andric           .addReg(Hexagon::R0 + j)
7405ffd83dbSDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
7415ffd83dbSDimitry Andric       }
7425ffd83dbSDimitry Andric     }
7435ffd83dbSDimitry Andric   }
7445ffd83dbSDimitry Andric 
7450b57cec5SDimitry Andric   if (hasFP(MF)) {
7460b57cec5SDimitry Andric     insertAllocframe(MBB, InsertPt, NumBytes);
7470b57cec5SDimitry Andric     if (AlignStack) {
7480b57cec5SDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_andir), SP)
7490b57cec5SDimitry Andric           .addReg(SP)
7505ffd83dbSDimitry Andric           .addImm(-int64_t(MaxAlign.value()));
7510b57cec5SDimitry Andric     }
7520b57cec5SDimitry Andric     // If the stack-checking is enabled, and we spilled the callee-saved
7530b57cec5SDimitry Andric     // registers inline (i.e. did not use a spill function), then call
7540b57cec5SDimitry Andric     // the stack checker directly.
7550b57cec5SDimitry Andric     if (EnableStackOVFSanitizer && !PrologueStubs)
7560b57cec5SDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::PS_call_stk))
7570b57cec5SDimitry Andric              .addExternalSymbol("__runtime_stack_check");
7580b57cec5SDimitry Andric   } else if (NumBytes > 0) {
7590b57cec5SDimitry Andric     assert(alignTo(NumBytes, 8) == NumBytes);
7600b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP)
7610b57cec5SDimitry Andric       .addReg(SP)
7620b57cec5SDimitry Andric       .addImm(-int(NumBytes));
7630b57cec5SDimitry Andric   }
7640b57cec5SDimitry Andric }
7650b57cec5SDimitry Andric 
insertEpilogueInBlock(MachineBasicBlock & MBB) const7660b57cec5SDimitry Andric void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const {
7670b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
7680b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
7690b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
7700b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
771bdd1243dSDimitry Andric   Register SP = HRI.getStackRegister();
7720b57cec5SDimitry Andric 
7730b57cec5SDimitry Andric   MachineBasicBlock::iterator InsertPt = MBB.getFirstTerminator();
7740b57cec5SDimitry Andric   DebugLoc dl = MBB.findDebugLoc(InsertPt);
7750b57cec5SDimitry Andric 
7760b57cec5SDimitry Andric   if (!hasFP(MF)) {
7770b57cec5SDimitry Andric     MachineFrameInfo &MFI = MF.getFrameInfo();
7785ffd83dbSDimitry Andric     unsigned NumBytes = MFI.getStackSize();
7795ffd83dbSDimitry Andric     if (MF.getFunction().isVarArg() &&
7805ffd83dbSDimitry Andric         MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl()) {
7815ffd83dbSDimitry Andric       // On Hexagon Linux, deallocate the stack for the register saved area.
7825ffd83dbSDimitry Andric       int NumVarArgRegs = 6 - FirstVarArgSavedReg;
7835ffd83dbSDimitry Andric       int RegisterSavedAreaSizePlusPadding = (NumVarArgRegs % 2 == 0) ?
7845ffd83dbSDimitry Andric         (NumVarArgRegs * 4) : (NumVarArgRegs * 4 + 4);
7855ffd83dbSDimitry Andric       NumBytes += RegisterSavedAreaSizePlusPadding;
7865ffd83dbSDimitry Andric     }
7875ffd83dbSDimitry Andric     if (NumBytes) {
7880b57cec5SDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP)
7890b57cec5SDimitry Andric         .addReg(SP)
7900b57cec5SDimitry Andric         .addImm(NumBytes);
7910b57cec5SDimitry Andric     }
7920b57cec5SDimitry Andric     return;
7930b57cec5SDimitry Andric   }
7940b57cec5SDimitry Andric 
7950b57cec5SDimitry Andric   MachineInstr *RetI = getReturn(MBB);
7960b57cec5SDimitry Andric   unsigned RetOpc = RetI ? RetI->getOpcode() : 0;
7970b57cec5SDimitry Andric 
7980b57cec5SDimitry Andric   // Handle EH_RETURN.
7990b57cec5SDimitry Andric   if (RetOpc == Hexagon::EH_RETURN_JMPR) {
8000b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::L2_deallocframe))
8010b57cec5SDimitry Andric         .addDef(Hexagon::D15)
8020b57cec5SDimitry Andric         .addReg(Hexagon::R30);
8030b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_add), SP)
8040b57cec5SDimitry Andric         .addReg(SP)
8050b57cec5SDimitry Andric         .addReg(Hexagon::R28);
8060b57cec5SDimitry Andric     return;
8070b57cec5SDimitry Andric   }
8080b57cec5SDimitry Andric 
8090b57cec5SDimitry Andric   // Check for RESTORE_DEALLOC_RET* tail call. Don't emit an extra dealloc-
8100b57cec5SDimitry Andric   // frame instruction if we encounter it.
8110b57cec5SDimitry Andric   if (RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4 ||
8120b57cec5SDimitry Andric       RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC ||
8130b57cec5SDimitry Andric       RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT ||
8140b57cec5SDimitry Andric       RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC) {
8150b57cec5SDimitry Andric     MachineBasicBlock::iterator It = RetI;
8160b57cec5SDimitry Andric     ++It;
8170b57cec5SDimitry Andric     // Delete all instructions after the RESTORE (except labels).
8180b57cec5SDimitry Andric     while (It != MBB.end()) {
8190b57cec5SDimitry Andric       if (!It->isLabel())
8200b57cec5SDimitry Andric         It = MBB.erase(It);
8210b57cec5SDimitry Andric       else
8220b57cec5SDimitry Andric         ++It;
8230b57cec5SDimitry Andric     }
8240b57cec5SDimitry Andric     return;
8250b57cec5SDimitry Andric   }
8260b57cec5SDimitry Andric 
8270b57cec5SDimitry Andric   // It is possible that the restoring code is a call to a library function.
8280b57cec5SDimitry Andric   // All of the restore* functions include "deallocframe", so we need to make
8290b57cec5SDimitry Andric   // sure that we don't add an extra one.
8300b57cec5SDimitry Andric   bool NeedsDeallocframe = true;
8310b57cec5SDimitry Andric   if (!MBB.empty() && InsertPt != MBB.begin()) {
8320b57cec5SDimitry Andric     MachineBasicBlock::iterator PrevIt = std::prev(InsertPt);
8330b57cec5SDimitry Andric     unsigned COpc = PrevIt->getOpcode();
8340b57cec5SDimitry Andric     if (COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4 ||
8350b57cec5SDimitry Andric         COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC ||
8360b57cec5SDimitry Andric         COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT ||
8370b57cec5SDimitry Andric         COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC ||
8380b57cec5SDimitry Andric         COpc == Hexagon::PS_call_nr || COpc == Hexagon::PS_callr_nr)
8390b57cec5SDimitry Andric       NeedsDeallocframe = false;
8400b57cec5SDimitry Andric   }
8410b57cec5SDimitry Andric 
8425ffd83dbSDimitry Andric   if (!MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl() ||
8435ffd83dbSDimitry Andric       !MF.getFunction().isVarArg()) {
8440b57cec5SDimitry Andric     if (!NeedsDeallocframe)
8450b57cec5SDimitry Andric       return;
8465ffd83dbSDimitry Andric     // If the returning instruction is PS_jmpret, replace it with
8475ffd83dbSDimitry Andric     // dealloc_return, otherwise just add deallocframe. The function
8485ffd83dbSDimitry Andric     // could be returning via a tail call.
8490b57cec5SDimitry Andric     if (RetOpc != Hexagon::PS_jmpret || DisableDeallocRet) {
8500b57cec5SDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::L2_deallocframe))
8510b57cec5SDimitry Andric       .addDef(Hexagon::D15)
8520b57cec5SDimitry Andric       .addReg(Hexagon::R30);
8530b57cec5SDimitry Andric       return;
8540b57cec5SDimitry Andric     }
8550b57cec5SDimitry Andric     unsigned NewOpc = Hexagon::L4_return;
8560b57cec5SDimitry Andric     MachineInstr *NewI = BuildMI(MBB, RetI, dl, HII.get(NewOpc))
8570b57cec5SDimitry Andric       .addDef(Hexagon::D15)
8580b57cec5SDimitry Andric       .addReg(Hexagon::R30);
8590b57cec5SDimitry Andric     // Transfer the function live-out registers.
8600b57cec5SDimitry Andric     NewI->copyImplicitOps(MF, *RetI);
8610b57cec5SDimitry Andric     MBB.erase(RetI);
8625ffd83dbSDimitry Andric   } else {
8635ffd83dbSDimitry Andric     // L2_deallocframe instruction after it.
8645ffd83dbSDimitry Andric     // Calculate the size of register saved area.
8655ffd83dbSDimitry Andric     int NumVarArgRegs = 6 - FirstVarArgSavedReg;
8665ffd83dbSDimitry Andric     int RegisterSavedAreaSizePlusPadding = (NumVarArgRegs % 2 == 0) ?
8675ffd83dbSDimitry Andric       (NumVarArgRegs * 4) : (NumVarArgRegs * 4 + 4);
8685ffd83dbSDimitry Andric 
8695ffd83dbSDimitry Andric     MachineBasicBlock::iterator Term = MBB.getFirstTerminator();
8705ffd83dbSDimitry Andric     MachineBasicBlock::iterator I = (Term == MBB.begin()) ? MBB.end()
8715ffd83dbSDimitry Andric                                                           : std::prev(Term);
8725ffd83dbSDimitry Andric     if (I == MBB.end() ||
8735ffd83dbSDimitry Andric        (I->getOpcode() != Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT &&
8745ffd83dbSDimitry Andric         I->getOpcode() != Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC &&
8755ffd83dbSDimitry Andric         I->getOpcode() != Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4 &&
8765ffd83dbSDimitry Andric         I->getOpcode() != Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC))
8775ffd83dbSDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::L2_deallocframe))
8785ffd83dbSDimitry Andric         .addDef(Hexagon::D15)
8795ffd83dbSDimitry Andric         .addReg(Hexagon::R30);
8805ffd83dbSDimitry Andric     if (RegisterSavedAreaSizePlusPadding != 0)
8815ffd83dbSDimitry Andric       BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP)
8825ffd83dbSDimitry Andric         .addReg(SP)
8835ffd83dbSDimitry Andric         .addImm(RegisterSavedAreaSizePlusPadding);
8845ffd83dbSDimitry Andric   }
8850b57cec5SDimitry Andric }
8860b57cec5SDimitry Andric 
insertAllocframe(MachineBasicBlock & MBB,MachineBasicBlock::iterator InsertPt,unsigned NumBytes) const8870b57cec5SDimitry Andric void HexagonFrameLowering::insertAllocframe(MachineBasicBlock &MBB,
8880b57cec5SDimitry Andric       MachineBasicBlock::iterator InsertPt, unsigned NumBytes) const {
8890b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
8900b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
8910b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
8920b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
8930b57cec5SDimitry Andric 
8940b57cec5SDimitry Andric   // Check for overflow.
8950b57cec5SDimitry Andric   // Hexagon_TODO: Ugh! hardcoding. Is there an API that can be used?
8960b57cec5SDimitry Andric   const unsigned int ALLOCFRAME_MAX = 16384;
8970b57cec5SDimitry Andric 
8980b57cec5SDimitry Andric   // Create a dummy memory operand to avoid allocframe from being treated as
8990b57cec5SDimitry Andric   // a volatile memory reference.
9000b57cec5SDimitry Andric   auto *MMO = MF.getMachineMemOperand(MachinePointerInfo::getStack(MF, 0),
9015ffd83dbSDimitry Andric                                       MachineMemOperand::MOStore, 4, Align(4));
9020b57cec5SDimitry Andric 
9030b57cec5SDimitry Andric   DebugLoc dl = MBB.findDebugLoc(InsertPt);
904bdd1243dSDimitry Andric   Register SP = HRI.getStackRegister();
9050b57cec5SDimitry Andric 
9060b57cec5SDimitry Andric   if (NumBytes >= ALLOCFRAME_MAX) {
9070b57cec5SDimitry Andric     // Emit allocframe(#0).
9080b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::S2_allocframe))
9090b57cec5SDimitry Andric       .addDef(SP)
9100b57cec5SDimitry Andric       .addReg(SP)
9110b57cec5SDimitry Andric       .addImm(0)
9120b57cec5SDimitry Andric       .addMemOperand(MMO);
9130b57cec5SDimitry Andric 
9140b57cec5SDimitry Andric     // Subtract the size from the stack pointer.
915bdd1243dSDimitry Andric     Register SP = HRI.getStackRegister();
9160b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP)
9170b57cec5SDimitry Andric       .addReg(SP)
9180b57cec5SDimitry Andric       .addImm(-int(NumBytes));
9190b57cec5SDimitry Andric   } else {
9200b57cec5SDimitry Andric     BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::S2_allocframe))
9210b57cec5SDimitry Andric       .addDef(SP)
9220b57cec5SDimitry Andric       .addReg(SP)
9230b57cec5SDimitry Andric       .addImm(NumBytes)
9240b57cec5SDimitry Andric       .addMemOperand(MMO);
9250b57cec5SDimitry Andric   }
9260b57cec5SDimitry Andric }
9270b57cec5SDimitry Andric 
updateEntryPaths(MachineFunction & MF,MachineBasicBlock & SaveB) const9280b57cec5SDimitry Andric void HexagonFrameLowering::updateEntryPaths(MachineFunction &MF,
9290b57cec5SDimitry Andric       MachineBasicBlock &SaveB) const {
9300b57cec5SDimitry Andric   SetVector<unsigned> Worklist;
9310b57cec5SDimitry Andric 
9320b57cec5SDimitry Andric   MachineBasicBlock &EntryB = MF.front();
9330b57cec5SDimitry Andric   Worklist.insert(EntryB.getNumber());
9340b57cec5SDimitry Andric 
9350b57cec5SDimitry Andric   unsigned SaveN = SaveB.getNumber();
9360b57cec5SDimitry Andric   auto &CSI = MF.getFrameInfo().getCalleeSavedInfo();
9370b57cec5SDimitry Andric 
9380b57cec5SDimitry Andric   for (unsigned i = 0; i < Worklist.size(); ++i) {
9390b57cec5SDimitry Andric     unsigned BN = Worklist[i];
9400b57cec5SDimitry Andric     MachineBasicBlock &MBB = *MF.getBlockNumbered(BN);
9410b57cec5SDimitry Andric     for (auto &R : CSI)
9420b57cec5SDimitry Andric       if (!MBB.isLiveIn(R.getReg()))
9430b57cec5SDimitry Andric         MBB.addLiveIn(R.getReg());
9440b57cec5SDimitry Andric     if (BN != SaveN)
9450b57cec5SDimitry Andric       for (auto &SB : MBB.successors())
9460b57cec5SDimitry Andric         Worklist.insert(SB->getNumber());
9470b57cec5SDimitry Andric   }
9480b57cec5SDimitry Andric }
9490b57cec5SDimitry Andric 
updateExitPaths(MachineBasicBlock & MBB,MachineBasicBlock & RestoreB,BitVector & DoneT,BitVector & DoneF,BitVector & Path) const9500b57cec5SDimitry Andric bool HexagonFrameLowering::updateExitPaths(MachineBasicBlock &MBB,
9510b57cec5SDimitry Andric       MachineBasicBlock &RestoreB, BitVector &DoneT, BitVector &DoneF,
9520b57cec5SDimitry Andric       BitVector &Path) const {
9530b57cec5SDimitry Andric   assert(MBB.getNumber() >= 0);
9540b57cec5SDimitry Andric   unsigned BN = MBB.getNumber();
9550b57cec5SDimitry Andric   if (Path[BN] || DoneF[BN])
9560b57cec5SDimitry Andric     return false;
9570b57cec5SDimitry Andric   if (DoneT[BN])
9580b57cec5SDimitry Andric     return true;
9590b57cec5SDimitry Andric 
9600b57cec5SDimitry Andric   auto &CSI = MBB.getParent()->getFrameInfo().getCalleeSavedInfo();
9610b57cec5SDimitry Andric 
9620b57cec5SDimitry Andric   Path[BN] = true;
9630b57cec5SDimitry Andric   bool ReachedExit = false;
9640b57cec5SDimitry Andric   for (auto &SB : MBB.successors())
9650b57cec5SDimitry Andric     ReachedExit |= updateExitPaths(*SB, RestoreB, DoneT, DoneF, Path);
9660b57cec5SDimitry Andric 
9670b57cec5SDimitry Andric   if (!MBB.empty() && MBB.back().isReturn()) {
9680b57cec5SDimitry Andric     // Add implicit uses of all callee-saved registers to the reached
9690b57cec5SDimitry Andric     // return instructions. This is to prevent the anti-dependency breaker
9700b57cec5SDimitry Andric     // from renaming these registers.
9710b57cec5SDimitry Andric     MachineInstr &RetI = MBB.back();
9720b57cec5SDimitry Andric     if (!isRestoreCall(RetI.getOpcode()))
9730b57cec5SDimitry Andric       for (auto &R : CSI)
9740b57cec5SDimitry Andric         RetI.addOperand(MachineOperand::CreateReg(R.getReg(), false, true));
9750b57cec5SDimitry Andric     ReachedExit = true;
9760b57cec5SDimitry Andric   }
9770b57cec5SDimitry Andric 
9780b57cec5SDimitry Andric   // We don't want to add unnecessary live-ins to the restore block: since
9790b57cec5SDimitry Andric   // the callee-saved registers are being defined in it, the entry of the
9800b57cec5SDimitry Andric   // restore block cannot be on the path from the definitions to any exit.
9810b57cec5SDimitry Andric   if (ReachedExit && &MBB != &RestoreB) {
9820b57cec5SDimitry Andric     for (auto &R : CSI)
9830b57cec5SDimitry Andric       if (!MBB.isLiveIn(R.getReg()))
9840b57cec5SDimitry Andric         MBB.addLiveIn(R.getReg());
9850b57cec5SDimitry Andric     DoneT[BN] = true;
9860b57cec5SDimitry Andric   }
9870b57cec5SDimitry Andric   if (!ReachedExit)
9880b57cec5SDimitry Andric     DoneF[BN] = true;
9890b57cec5SDimitry Andric 
9900b57cec5SDimitry Andric   Path[BN] = false;
9910b57cec5SDimitry Andric   return ReachedExit;
9920b57cec5SDimitry Andric }
9930b57cec5SDimitry Andric 
994bdd1243dSDimitry Andric static std::optional<MachineBasicBlock::iterator>
findCFILocation(MachineBasicBlock & B)9950b57cec5SDimitry Andric findCFILocation(MachineBasicBlock &B) {
9960b57cec5SDimitry Andric     // The CFI instructions need to be inserted right after allocframe.
9970b57cec5SDimitry Andric     // An exception to this is a situation where allocframe is bundled
9980b57cec5SDimitry Andric     // with a call: then the CFI instructions need to be inserted before
9990b57cec5SDimitry Andric     // the packet with the allocframe+call (in case the call throws an
10000b57cec5SDimitry Andric     // exception).
10010b57cec5SDimitry Andric     auto End = B.instr_end();
10020b57cec5SDimitry Andric 
10030b57cec5SDimitry Andric     for (MachineInstr &I : B) {
10040b57cec5SDimitry Andric       MachineBasicBlock::iterator It = I.getIterator();
10050b57cec5SDimitry Andric       if (!I.isBundle()) {
10060b57cec5SDimitry Andric         if (I.getOpcode() == Hexagon::S2_allocframe)
10070b57cec5SDimitry Andric           return std::next(It);
10080b57cec5SDimitry Andric         continue;
10090b57cec5SDimitry Andric       }
10100b57cec5SDimitry Andric       // I is a bundle.
10110b57cec5SDimitry Andric       bool HasCall = false, HasAllocFrame = false;
10120b57cec5SDimitry Andric       auto T = It.getInstrIterator();
10130b57cec5SDimitry Andric       while (++T != End && T->isBundled()) {
10140b57cec5SDimitry Andric         if (T->getOpcode() == Hexagon::S2_allocframe)
10150b57cec5SDimitry Andric           HasAllocFrame = true;
10160b57cec5SDimitry Andric         else if (T->isCall())
10170b57cec5SDimitry Andric           HasCall = true;
10180b57cec5SDimitry Andric       }
10190b57cec5SDimitry Andric       if (HasAllocFrame)
10200b57cec5SDimitry Andric         return HasCall ? It : std::next(It);
10210b57cec5SDimitry Andric     }
1022bdd1243dSDimitry Andric     return std::nullopt;
10230b57cec5SDimitry Andric }
10240b57cec5SDimitry Andric 
insertCFIInstructions(MachineFunction & MF) const10250b57cec5SDimitry Andric void HexagonFrameLowering::insertCFIInstructions(MachineFunction &MF) const {
1026bdd1243dSDimitry Andric     for (auto &B : MF)
1027bdd1243dSDimitry Andric       if (auto At = findCFILocation(B))
1028bdd1243dSDimitry Andric         insertCFIInstructionsAt(B, *At);
10290b57cec5SDimitry Andric }
10300b57cec5SDimitry Andric 
insertCFIInstructionsAt(MachineBasicBlock & MBB,MachineBasicBlock::iterator At) const10310b57cec5SDimitry Andric void HexagonFrameLowering::insertCFIInstructionsAt(MachineBasicBlock &MBB,
10320b57cec5SDimitry Andric       MachineBasicBlock::iterator At) const {
10330b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
10340b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
10350b57cec5SDimitry Andric   MachineModuleInfo &MMI = MF.getMMI();
10360b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
10370b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
10380b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
10390b57cec5SDimitry Andric 
10400b57cec5SDimitry Andric   // If CFI instructions have debug information attached, something goes
10410b57cec5SDimitry Andric   // wrong with the final assembly generation: the prolog_end is placed
10420b57cec5SDimitry Andric   // in a wrong location.
10430b57cec5SDimitry Andric   DebugLoc DL;
10440b57cec5SDimitry Andric   const MCInstrDesc &CFID = HII.get(TargetOpcode::CFI_INSTRUCTION);
10450b57cec5SDimitry Andric 
10460b57cec5SDimitry Andric   MCSymbol *FrameLabel = MMI.getContext().createTempSymbol();
10470b57cec5SDimitry Andric   bool HasFP = hasFP(MF);
10480b57cec5SDimitry Andric 
10490b57cec5SDimitry Andric   if (HasFP) {
10500b57cec5SDimitry Andric     unsigned DwFPReg = HRI.getDwarfRegNum(HRI.getFrameRegister(), true);
10510b57cec5SDimitry Andric     unsigned DwRAReg = HRI.getDwarfRegNum(HRI.getRARegister(), true);
10520b57cec5SDimitry Andric 
10530b57cec5SDimitry Andric     // Define CFA via an offset from the value of FP.
10540b57cec5SDimitry Andric     //
10550b57cec5SDimitry Andric     //  -8   -4    0 (SP)
10560b57cec5SDimitry Andric     // --+----+----+---------------------
10570b57cec5SDimitry Andric     //   | FP | LR |          increasing addresses -->
10580b57cec5SDimitry Andric     // --+----+----+---------------------
10590b57cec5SDimitry Andric     //   |         +-- Old SP (before allocframe)
10600b57cec5SDimitry Andric     //   +-- New FP (after allocframe)
10610b57cec5SDimitry Andric     //
10625ffd83dbSDimitry Andric     // MCCFIInstruction::cfiDefCfa adds the offset from the register.
10630b57cec5SDimitry Andric     // MCCFIInstruction::createOffset takes the offset without sign change.
10645ffd83dbSDimitry Andric     auto DefCfa = MCCFIInstruction::cfiDefCfa(FrameLabel, DwFPReg, 8);
10650b57cec5SDimitry Andric     BuildMI(MBB, At, DL, CFID)
10660b57cec5SDimitry Andric         .addCFIIndex(MF.addFrameInst(DefCfa));
10670b57cec5SDimitry Andric     // R31 (return addr) = CFA - 4
10680b57cec5SDimitry Andric     auto OffR31 = MCCFIInstruction::createOffset(FrameLabel, DwRAReg, -4);
10690b57cec5SDimitry Andric     BuildMI(MBB, At, DL, CFID)
10700b57cec5SDimitry Andric         .addCFIIndex(MF.addFrameInst(OffR31));
10710b57cec5SDimitry Andric     // R30 (frame ptr) = CFA - 8
10720b57cec5SDimitry Andric     auto OffR30 = MCCFIInstruction::createOffset(FrameLabel, DwFPReg, -8);
10730b57cec5SDimitry Andric     BuildMI(MBB, At, DL, CFID)
10740b57cec5SDimitry Andric         .addCFIIndex(MF.addFrameInst(OffR30));
10750b57cec5SDimitry Andric   }
10760b57cec5SDimitry Andric 
1077bdd1243dSDimitry Andric   static Register RegsToMove[] = {
10780b57cec5SDimitry Andric     Hexagon::R1,  Hexagon::R0,  Hexagon::R3,  Hexagon::R2,
10790b57cec5SDimitry Andric     Hexagon::R17, Hexagon::R16, Hexagon::R19, Hexagon::R18,
10800b57cec5SDimitry Andric     Hexagon::R21, Hexagon::R20, Hexagon::R23, Hexagon::R22,
10810b57cec5SDimitry Andric     Hexagon::R25, Hexagon::R24, Hexagon::R27, Hexagon::R26,
10820b57cec5SDimitry Andric     Hexagon::D0,  Hexagon::D1,  Hexagon::D8,  Hexagon::D9,
10830b57cec5SDimitry Andric     Hexagon::D10, Hexagon::D11, Hexagon::D12, Hexagon::D13,
10840b57cec5SDimitry Andric     Hexagon::NoRegister
10850b57cec5SDimitry Andric   };
10860b57cec5SDimitry Andric 
10870b57cec5SDimitry Andric   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
10880b57cec5SDimitry Andric 
10890b57cec5SDimitry Andric   for (unsigned i = 0; RegsToMove[i] != Hexagon::NoRegister; ++i) {
1090bdd1243dSDimitry Andric     Register Reg = RegsToMove[i];
10910b57cec5SDimitry Andric     auto IfR = [Reg] (const CalleeSavedInfo &C) -> bool {
10920b57cec5SDimitry Andric       return C.getReg() == Reg;
10930b57cec5SDimitry Andric     };
10940b57cec5SDimitry Andric     auto F = find_if(CSI, IfR);
10950b57cec5SDimitry Andric     if (F == CSI.end())
10960b57cec5SDimitry Andric       continue;
10970b57cec5SDimitry Andric 
10980b57cec5SDimitry Andric     int64_t Offset;
10990b57cec5SDimitry Andric     if (HasFP) {
11000b57cec5SDimitry Andric       // If the function has a frame pointer (i.e. has an allocframe),
11010b57cec5SDimitry Andric       // then the CFA has been defined in terms of FP. Any offsets in
11020b57cec5SDimitry Andric       // the following CFI instructions have to be defined relative
11030b57cec5SDimitry Andric       // to FP, which points to the bottom of the stack frame.
11040b57cec5SDimitry Andric       // The function getFrameIndexReference can still choose to use SP
11050b57cec5SDimitry Andric       // for the offset calculation, so we cannot simply call it here.
11060b57cec5SDimitry Andric       // Instead, get the offset (relative to the FP) directly.
11070b57cec5SDimitry Andric       Offset = MFI.getObjectOffset(F->getFrameIdx());
11080b57cec5SDimitry Andric     } else {
11095ffd83dbSDimitry Andric       Register FrameReg;
1110e8d8bef9SDimitry Andric       Offset =
1111e8d8bef9SDimitry Andric           getFrameIndexReference(MF, F->getFrameIdx(), FrameReg).getFixed();
11120b57cec5SDimitry Andric     }
11130b57cec5SDimitry Andric     // Subtract 8 to make room for R30 and R31, which are added above.
11140b57cec5SDimitry Andric     Offset -= 8;
11150b57cec5SDimitry Andric 
11160b57cec5SDimitry Andric     if (Reg < Hexagon::D0 || Reg > Hexagon::D15) {
11170b57cec5SDimitry Andric       unsigned DwarfReg = HRI.getDwarfRegNum(Reg, true);
11180b57cec5SDimitry Andric       auto OffReg = MCCFIInstruction::createOffset(FrameLabel, DwarfReg,
11190b57cec5SDimitry Andric                                                    Offset);
11200b57cec5SDimitry Andric       BuildMI(MBB, At, DL, CFID)
11210b57cec5SDimitry Andric           .addCFIIndex(MF.addFrameInst(OffReg));
11220b57cec5SDimitry Andric     } else {
11230b57cec5SDimitry Andric       // Split the double regs into subregs, and generate appropriate
11240b57cec5SDimitry Andric       // cfi_offsets.
11250b57cec5SDimitry Andric       // The only reason, we are split double regs is, llvm-mc does not
11260b57cec5SDimitry Andric       // understand paired registers for cfi_offset.
11270b57cec5SDimitry Andric       // Eg .cfi_offset r1:0, -64
11280b57cec5SDimitry Andric 
11298bcb0991SDimitry Andric       Register HiReg = HRI.getSubReg(Reg, Hexagon::isub_hi);
11308bcb0991SDimitry Andric       Register LoReg = HRI.getSubReg(Reg, Hexagon::isub_lo);
11310b57cec5SDimitry Andric       unsigned HiDwarfReg = HRI.getDwarfRegNum(HiReg, true);
11320b57cec5SDimitry Andric       unsigned LoDwarfReg = HRI.getDwarfRegNum(LoReg, true);
11330b57cec5SDimitry Andric       auto OffHi = MCCFIInstruction::createOffset(FrameLabel, HiDwarfReg,
11340b57cec5SDimitry Andric                                                   Offset+4);
11350b57cec5SDimitry Andric       BuildMI(MBB, At, DL, CFID)
11360b57cec5SDimitry Andric           .addCFIIndex(MF.addFrameInst(OffHi));
11370b57cec5SDimitry Andric       auto OffLo = MCCFIInstruction::createOffset(FrameLabel, LoDwarfReg,
11380b57cec5SDimitry Andric                                                   Offset);
11390b57cec5SDimitry Andric       BuildMI(MBB, At, DL, CFID)
11400b57cec5SDimitry Andric           .addCFIIndex(MF.addFrameInst(OffLo));
11410b57cec5SDimitry Andric     }
11420b57cec5SDimitry Andric   }
11430b57cec5SDimitry Andric }
11440b57cec5SDimitry Andric 
hasFP(const MachineFunction & MF) const11450b57cec5SDimitry Andric bool HexagonFrameLowering::hasFP(const MachineFunction &MF) const {
11460b57cec5SDimitry Andric   if (MF.getFunction().hasFnAttribute(Attribute::Naked))
11470b57cec5SDimitry Andric     return false;
11480b57cec5SDimitry Andric 
11490b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
11500b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
1151fe6060f1SDimitry Andric   bool HasExtraAlign = HRI.hasStackRealignment(MF);
11520b57cec5SDimitry Andric   bool HasAlloca = MFI.hasVarSizedObjects();
11530b57cec5SDimitry Andric 
11540b57cec5SDimitry Andric   // Insert ALLOCFRAME if we need to or at -O0 for the debugger.  Think
11550b57cec5SDimitry Andric   // that this shouldn't be required, but doing so now because gcc does and
11560b57cec5SDimitry Andric   // gdb can't break at the start of the function without it.  Will remove if
11570b57cec5SDimitry Andric   // this turns out to be a gdb bug.
11580b57cec5SDimitry Andric   //
11595f757f3fSDimitry Andric   if (MF.getTarget().getOptLevel() == CodeGenOptLevel::None)
11600b57cec5SDimitry Andric     return true;
11610b57cec5SDimitry Andric 
11620b57cec5SDimitry Andric   // By default we want to use SP (since it's always there). FP requires
11630b57cec5SDimitry Andric   // some setup (i.e. ALLOCFRAME).
11640b57cec5SDimitry Andric   // Both, alloca and stack alignment modify the stack pointer by an
11650b57cec5SDimitry Andric   // undetermined value, so we need to save it at the entry to the function
11660b57cec5SDimitry Andric   // (i.e. use allocframe).
11670b57cec5SDimitry Andric   if (HasAlloca || HasExtraAlign)
11680b57cec5SDimitry Andric     return true;
11690b57cec5SDimitry Andric 
11700b57cec5SDimitry Andric   if (MFI.getStackSize() > 0) {
11710b57cec5SDimitry Andric     // If FP-elimination is disabled, we have to use FP at this point.
11720b57cec5SDimitry Andric     const TargetMachine &TM = MF.getTarget();
11730b57cec5SDimitry Andric     if (TM.Options.DisableFramePointerElim(MF) || !EliminateFramePointer)
11740b57cec5SDimitry Andric       return true;
11750b57cec5SDimitry Andric     if (EnableStackOVFSanitizer)
11760b57cec5SDimitry Andric       return true;
11770b57cec5SDimitry Andric   }
11780b57cec5SDimitry Andric 
11790b57cec5SDimitry Andric   const auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
11800b57cec5SDimitry Andric   if ((MFI.hasCalls() && !enableAllocFrameElim(MF)) || HMFI.hasClobberLR())
11810b57cec5SDimitry Andric     return true;
11820b57cec5SDimitry Andric 
11830b57cec5SDimitry Andric   return false;
11840b57cec5SDimitry Andric }
11850b57cec5SDimitry Andric 
11860b57cec5SDimitry Andric enum SpillKind {
11870b57cec5SDimitry Andric   SK_ToMem,
11880b57cec5SDimitry Andric   SK_FromMem,
11890b57cec5SDimitry Andric   SK_FromMemTailcall
11900b57cec5SDimitry Andric };
11910b57cec5SDimitry Andric 
getSpillFunctionFor(Register MaxReg,SpillKind SpillType,bool Stkchk=false)1192bdd1243dSDimitry Andric static const char *getSpillFunctionFor(Register MaxReg, SpillKind SpillType,
11930b57cec5SDimitry Andric       bool Stkchk = false) {
11940b57cec5SDimitry Andric   const char * V4SpillToMemoryFunctions[] = {
11950b57cec5SDimitry Andric     "__save_r16_through_r17",
11960b57cec5SDimitry Andric     "__save_r16_through_r19",
11970b57cec5SDimitry Andric     "__save_r16_through_r21",
11980b57cec5SDimitry Andric     "__save_r16_through_r23",
11990b57cec5SDimitry Andric     "__save_r16_through_r25",
12000b57cec5SDimitry Andric     "__save_r16_through_r27" };
12010b57cec5SDimitry Andric 
12020b57cec5SDimitry Andric   const char * V4SpillToMemoryStkchkFunctions[] = {
12030b57cec5SDimitry Andric     "__save_r16_through_r17_stkchk",
12040b57cec5SDimitry Andric     "__save_r16_through_r19_stkchk",
12050b57cec5SDimitry Andric     "__save_r16_through_r21_stkchk",
12060b57cec5SDimitry Andric     "__save_r16_through_r23_stkchk",
12070b57cec5SDimitry Andric     "__save_r16_through_r25_stkchk",
12080b57cec5SDimitry Andric     "__save_r16_through_r27_stkchk" };
12090b57cec5SDimitry Andric 
12100b57cec5SDimitry Andric   const char * V4SpillFromMemoryFunctions[] = {
12110b57cec5SDimitry Andric     "__restore_r16_through_r17_and_deallocframe",
12120b57cec5SDimitry Andric     "__restore_r16_through_r19_and_deallocframe",
12130b57cec5SDimitry Andric     "__restore_r16_through_r21_and_deallocframe",
12140b57cec5SDimitry Andric     "__restore_r16_through_r23_and_deallocframe",
12150b57cec5SDimitry Andric     "__restore_r16_through_r25_and_deallocframe",
12160b57cec5SDimitry Andric     "__restore_r16_through_r27_and_deallocframe" };
12170b57cec5SDimitry Andric 
12180b57cec5SDimitry Andric   const char * V4SpillFromMemoryTailcallFunctions[] = {
12190b57cec5SDimitry Andric     "__restore_r16_through_r17_and_deallocframe_before_tailcall",
12200b57cec5SDimitry Andric     "__restore_r16_through_r19_and_deallocframe_before_tailcall",
12210b57cec5SDimitry Andric     "__restore_r16_through_r21_and_deallocframe_before_tailcall",
12220b57cec5SDimitry Andric     "__restore_r16_through_r23_and_deallocframe_before_tailcall",
12230b57cec5SDimitry Andric     "__restore_r16_through_r25_and_deallocframe_before_tailcall",
12240b57cec5SDimitry Andric     "__restore_r16_through_r27_and_deallocframe_before_tailcall"
12250b57cec5SDimitry Andric   };
12260b57cec5SDimitry Andric 
12270b57cec5SDimitry Andric   const char **SpillFunc = nullptr;
12280b57cec5SDimitry Andric 
12290b57cec5SDimitry Andric   switch(SpillType) {
12300b57cec5SDimitry Andric   case SK_ToMem:
12310b57cec5SDimitry Andric     SpillFunc = Stkchk ? V4SpillToMemoryStkchkFunctions
12320b57cec5SDimitry Andric                        : V4SpillToMemoryFunctions;
12330b57cec5SDimitry Andric     break;
12340b57cec5SDimitry Andric   case SK_FromMem:
12350b57cec5SDimitry Andric     SpillFunc = V4SpillFromMemoryFunctions;
12360b57cec5SDimitry Andric     break;
12370b57cec5SDimitry Andric   case SK_FromMemTailcall:
12380b57cec5SDimitry Andric     SpillFunc = V4SpillFromMemoryTailcallFunctions;
12390b57cec5SDimitry Andric     break;
12400b57cec5SDimitry Andric   }
12410b57cec5SDimitry Andric   assert(SpillFunc && "Unknown spill kind");
12420b57cec5SDimitry Andric 
12430b57cec5SDimitry Andric   // Spill all callee-saved registers up to the highest register used.
12440b57cec5SDimitry Andric   switch (MaxReg) {
12450b57cec5SDimitry Andric   case Hexagon::R17:
12460b57cec5SDimitry Andric     return SpillFunc[0];
12470b57cec5SDimitry Andric   case Hexagon::R19:
12480b57cec5SDimitry Andric     return SpillFunc[1];
12490b57cec5SDimitry Andric   case Hexagon::R21:
12500b57cec5SDimitry Andric     return SpillFunc[2];
12510b57cec5SDimitry Andric   case Hexagon::R23:
12520b57cec5SDimitry Andric     return SpillFunc[3];
12530b57cec5SDimitry Andric   case Hexagon::R25:
12540b57cec5SDimitry Andric     return SpillFunc[4];
12550b57cec5SDimitry Andric   case Hexagon::R27:
12560b57cec5SDimitry Andric     return SpillFunc[5];
12570b57cec5SDimitry Andric   default:
12580b57cec5SDimitry Andric     llvm_unreachable("Unhandled maximum callee save register");
12590b57cec5SDimitry Andric   }
12600b57cec5SDimitry Andric   return nullptr;
12610b57cec5SDimitry Andric }
12620b57cec5SDimitry Andric 
1263e8d8bef9SDimitry Andric StackOffset
getFrameIndexReference(const MachineFunction & MF,int FI,Register & FrameReg) const1264e8d8bef9SDimitry Andric HexagonFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
12655ffd83dbSDimitry Andric                                              Register &FrameReg) const {
12660b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
12670b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
12680b57cec5SDimitry Andric 
12690b57cec5SDimitry Andric   int Offset = MFI.getObjectOffset(FI);
12700b57cec5SDimitry Andric   bool HasAlloca = MFI.hasVarSizedObjects();
1271fe6060f1SDimitry Andric   bool HasExtraAlign = HRI.hasStackRealignment(MF);
12725f757f3fSDimitry Andric   bool NoOpt = MF.getTarget().getOptLevel() == CodeGenOptLevel::None;
12730b57cec5SDimitry Andric 
12740b57cec5SDimitry Andric   auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
12750b57cec5SDimitry Andric   unsigned FrameSize = MFI.getStackSize();
12765ffd83dbSDimitry Andric   Register SP = HRI.getStackRegister();
12775ffd83dbSDimitry Andric   Register FP = HRI.getFrameRegister();
1278bdd1243dSDimitry Andric   Register AP = HMFI.getStackAlignBaseReg();
12790b57cec5SDimitry Andric   // It may happen that AP will be absent even HasAlloca && HasExtraAlign
12800b57cec5SDimitry Andric   // is true. HasExtraAlign may be set because of vector spills, without
12810b57cec5SDimitry Andric   // aligned locals or aligned outgoing function arguments. Since vector
12820b57cec5SDimitry Andric   // spills will ultimately be "unaligned", it is safe to use FP as the
12830b57cec5SDimitry Andric   // base register.
12840b57cec5SDimitry Andric   // In fact, in such a scenario the stack is actually not required to be
12850b57cec5SDimitry Andric   // aligned, although it may end up being aligned anyway, since this
12860b57cec5SDimitry Andric   // particular case is not easily detectable. The alignment will be
12870b57cec5SDimitry Andric   // unnecessary, but not incorrect.
12880b57cec5SDimitry Andric   // Unfortunately there is no quick way to verify that the above is
12890b57cec5SDimitry Andric   // indeed the case (and that it's not a result of an error), so just
12900b57cec5SDimitry Andric   // assume that missing AP will be replaced by FP.
12910b57cec5SDimitry Andric   // (A better fix would be to rematerialize AP from FP and always align
12920b57cec5SDimitry Andric   // vector spills.)
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 
insertCSRSpillsInBlock(MachineBasicBlock & MBB,const CSIVect & CSI,const HexagonRegisterInfo & HRI,bool & PrologueStubs) const13610b57cec5SDimitry 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;
1375bdd1243dSDimitry Andric     Register 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.
14094824e7fdSDimitry Andric     for (const CalleeSavedInfo &I : CSI)
14104824e7fdSDimitry Andric       MBB.addLiveIn(I.getReg());
14110b57cec5SDimitry Andric     return true;
14120b57cec5SDimitry Andric   }
14130b57cec5SDimitry Andric 
14144824e7fdSDimitry Andric   for (const CalleeSavedInfo &I : CSI) {
141504eeddc0SDimitry Andric     Register Reg = 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);
14204824e7fdSDimitry Andric     int FI = I.getFrameIdx();
14210b57cec5SDimitry Andric     const TargetRegisterClass *RC = HRI.getMinimalPhysRegClass(Reg);
1422bdd1243dSDimitry Andric     HII.storeRegToStackSlot(MBB, MI, Reg, IsKill, FI, RC, &HRI, Register());
14230b57cec5SDimitry Andric     if (IsKill)
14240b57cec5SDimitry Andric       MBB.addLiveIn(Reg);
14250b57cec5SDimitry Andric   }
14260b57cec5SDimitry Andric   return true;
14270b57cec5SDimitry Andric }
14280b57cec5SDimitry Andric 
insertCSRRestoresInBlock(MachineBasicBlock & MBB,const CSIVect & CSI,const HexagonRegisterInfo & HRI) const14290b57cec5SDimitry 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);
1441bdd1243dSDimitry Andric     Register 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 
14834824e7fdSDimitry Andric   for (const CalleeSavedInfo &I : CSI) {
148404eeddc0SDimitry Andric     Register Reg = I.getReg();
14850b57cec5SDimitry Andric     const TargetRegisterClass *RC = HRI.getMinimalPhysRegClass(Reg);
14864824e7fdSDimitry Andric     int FI = I.getFrameIdx();
1487bdd1243dSDimitry Andric     HII.loadRegFromStackSlot(MBB, MI, Reg, FI, RC, &HRI, Register());
14880b57cec5SDimitry Andric   }
14890b57cec5SDimitry Andric 
14900b57cec5SDimitry Andric   return true;
14910b57cec5SDimitry Andric }
14920b57cec5SDimitry Andric 
eliminateCallFramePseudoInstr(MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator I) const14930b57cec5SDimitry 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 
processFunctionBeforeFrameFinalized(MachineFunction & MF,RegScavenger * RS) const15040b57cec5SDimitry 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 
15170b57cec5SDimitry Andric   // Set the physical aligned-stack base address register.
1518bdd1243dSDimitry Andric   Register AP = 0;
15190b57cec5SDimitry Andric   if (const MachineInstr *AI = getAlignaInstr(MF))
15200b57cec5SDimitry Andric     AP = AI->getOperand(0).getReg();
15210b57cec5SDimitry Andric   auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
1522bdd1243dSDimitry Andric   assert(!AP.isValid() || AP.isPhysical());
1523bdd1243dSDimitry Andric   HMFI.setStackAlignBaseReg(AP);
15240b57cec5SDimitry Andric }
15250b57cec5SDimitry Andric 
15260b57cec5SDimitry Andric /// Returns true if there are no caller-saved registers available in class RC.
needToReserveScavengingSpillSlots(MachineFunction & MF,const HexagonRegisterInfo & HRI,const TargetRegisterClass * RC)15270b57cec5SDimitry Andric static bool needToReserveScavengingSpillSlots(MachineFunction &MF,
15280b57cec5SDimitry Andric       const HexagonRegisterInfo &HRI, const TargetRegisterClass *RC) {
15290b57cec5SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
15300b57cec5SDimitry Andric 
1531bdd1243dSDimitry Andric   auto IsUsed = [&HRI,&MRI] (Register Reg) -> bool {
15320b57cec5SDimitry Andric     for (MCRegAliasIterator AI(Reg, &HRI, true); AI.isValid(); ++AI)
15330b57cec5SDimitry Andric       if (MRI.isPhysRegUsed(*AI))
15340b57cec5SDimitry Andric         return true;
15350b57cec5SDimitry Andric     return false;
15360b57cec5SDimitry Andric   };
15370b57cec5SDimitry Andric 
15380b57cec5SDimitry Andric   // Check for an unused caller-saved register. Callee-saved registers
15390b57cec5SDimitry Andric   // have become pristine by now.
15400b57cec5SDimitry Andric   for (const MCPhysReg *P = HRI.getCallerSavedRegs(&MF, RC); *P; ++P)
15410b57cec5SDimitry Andric     if (!IsUsed(*P))
15420b57cec5SDimitry Andric       return false;
15430b57cec5SDimitry Andric 
15440b57cec5SDimitry Andric   // All caller-saved registers are used.
15450b57cec5SDimitry Andric   return true;
15460b57cec5SDimitry Andric }
15470b57cec5SDimitry Andric 
15480b57cec5SDimitry Andric #ifndef NDEBUG
dump_registers(BitVector & Regs,const TargetRegisterInfo & TRI)15490b57cec5SDimitry Andric static void dump_registers(BitVector &Regs, const TargetRegisterInfo &TRI) {
15500b57cec5SDimitry Andric   dbgs() << '{';
15510b57cec5SDimitry Andric   for (int x = Regs.find_first(); x >= 0; x = Regs.find_next(x)) {
1552bdd1243dSDimitry Andric     Register R = x;
15530b57cec5SDimitry Andric     dbgs() << ' ' << printReg(R, &TRI);
15540b57cec5SDimitry Andric   }
15550b57cec5SDimitry Andric   dbgs() << " }";
15560b57cec5SDimitry Andric }
15570b57cec5SDimitry Andric #endif
15580b57cec5SDimitry Andric 
assignCalleeSavedSpillSlots(MachineFunction & MF,const TargetRegisterInfo * TRI,std::vector<CalleeSavedInfo> & CSI) const15590b57cec5SDimitry Andric bool HexagonFrameLowering::assignCalleeSavedSpillSlots(MachineFunction &MF,
15600b57cec5SDimitry Andric       const TargetRegisterInfo *TRI, std::vector<CalleeSavedInfo> &CSI) const {
15610b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << __func__ << " on " << MF.getName() << '\n');
15620b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
15630b57cec5SDimitry Andric   BitVector SRegs(Hexagon::NUM_TARGET_REGS);
15640b57cec5SDimitry Andric 
15650b57cec5SDimitry Andric   // Generate a set of unique, callee-saved registers (SRegs), where each
15660b57cec5SDimitry Andric   // register in the set is maximal in terms of sub-/super-register relation,
15670b57cec5SDimitry Andric   // i.e. for each R in SRegs, no proper super-register of R is also in SRegs.
15680b57cec5SDimitry Andric 
15690b57cec5SDimitry Andric   // (1) For each callee-saved register, add that register and all of its
15700b57cec5SDimitry Andric   // sub-registers to SRegs.
15710b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Initial CS registers: {");
15724824e7fdSDimitry Andric   for (const CalleeSavedInfo &I : CSI) {
157304eeddc0SDimitry Andric     Register R = I.getReg();
15740b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ' ' << printReg(R, TRI));
157506c3fb27SDimitry Andric     for (MCPhysReg SR : TRI->subregs_inclusive(R))
157606c3fb27SDimitry Andric       SRegs[SR] = true;
15770b57cec5SDimitry Andric   }
15780b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << " }\n");
15790b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "SRegs.1: "; dump_registers(SRegs, *TRI);
15800b57cec5SDimitry Andric              dbgs() << "\n");
15810b57cec5SDimitry Andric 
15820b57cec5SDimitry Andric   // (2) For each reserved register, remove that register and all of its
15830b57cec5SDimitry Andric   // sub- and super-registers from SRegs.
15840b57cec5SDimitry Andric   BitVector Reserved = TRI->getReservedRegs(MF);
1585bdd1243dSDimitry Andric   // Unreserve the stack align register: it is reserved for this function
1586bdd1243dSDimitry Andric   // only, it still needs to be saved/restored.
1587bdd1243dSDimitry Andric   Register AP =
1588bdd1243dSDimitry Andric       MF.getInfo<HexagonMachineFunctionInfo>()->getStackAlignBaseReg();
1589bdd1243dSDimitry Andric   if (AP.isValid()) {
1590bdd1243dSDimitry Andric     Reserved[AP] = false;
1591bdd1243dSDimitry Andric     // Unreserve super-regs if no other subregisters are reserved.
159206c3fb27SDimitry Andric     for (MCPhysReg SP : TRI->superregs(AP)) {
1593bdd1243dSDimitry Andric       bool HasResSub = false;
159406c3fb27SDimitry Andric       for (MCPhysReg SB : TRI->subregs(SP)) {
159506c3fb27SDimitry Andric         if (!Reserved[SB])
1596bdd1243dSDimitry Andric           continue;
1597bdd1243dSDimitry Andric         HasResSub = true;
1598bdd1243dSDimitry Andric         break;
1599bdd1243dSDimitry Andric       }
1600bdd1243dSDimitry Andric       if (!HasResSub)
160106c3fb27SDimitry Andric         Reserved[SP] = false;
1602bdd1243dSDimitry Andric     }
1603bdd1243dSDimitry Andric   }
1604bdd1243dSDimitry Andric 
16050b57cec5SDimitry Andric   for (int x = Reserved.find_first(); x >= 0; x = Reserved.find_next(x)) {
1606bdd1243dSDimitry Andric     Register R = x;
160706c3fb27SDimitry Andric     for (MCPhysReg SR : TRI->superregs_inclusive(R))
160806c3fb27SDimitry Andric       SRegs[SR] = false;
16090b57cec5SDimitry Andric   }
16100b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Res:     "; dump_registers(Reserved, *TRI);
16110b57cec5SDimitry Andric              dbgs() << "\n");
16120b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "SRegs.2: "; dump_registers(SRegs, *TRI);
16130b57cec5SDimitry Andric              dbgs() << "\n");
16140b57cec5SDimitry Andric 
16150b57cec5SDimitry Andric   // (3) Collect all registers that have at least one sub-register in SRegs,
16160b57cec5SDimitry Andric   // and also have no sub-registers that are reserved. These will be the can-
16170b57cec5SDimitry Andric   // didates for saving as a whole instead of their individual sub-registers.
16180b57cec5SDimitry Andric   // (Saving R17:16 instead of R16 is fine, but only if R17 was not reserved.)
16190b57cec5SDimitry Andric   BitVector TmpSup(Hexagon::NUM_TARGET_REGS);
16200b57cec5SDimitry Andric   for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) {
1621bdd1243dSDimitry Andric     Register R = x;
162206c3fb27SDimitry Andric     for (MCPhysReg SR : TRI->superregs(R))
162306c3fb27SDimitry Andric       TmpSup[SR] = true;
16240b57cec5SDimitry Andric   }
16250b57cec5SDimitry Andric   for (int x = TmpSup.find_first(); x >= 0; x = TmpSup.find_next(x)) {
1626bdd1243dSDimitry Andric     Register R = x;
162706c3fb27SDimitry Andric     for (MCPhysReg SR : TRI->subregs_inclusive(R)) {
162806c3fb27SDimitry Andric       if (!Reserved[SR])
16290b57cec5SDimitry Andric         continue;
16300b57cec5SDimitry Andric       TmpSup[R] = false;
16310b57cec5SDimitry Andric       break;
16320b57cec5SDimitry Andric     }
16330b57cec5SDimitry Andric   }
16340b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "TmpSup:  "; dump_registers(TmpSup, *TRI);
16350b57cec5SDimitry Andric              dbgs() << "\n");
16360b57cec5SDimitry Andric 
16370b57cec5SDimitry Andric   // (4) Include all super-registers found in (3) into SRegs.
16380b57cec5SDimitry Andric   SRegs |= TmpSup;
16390b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "SRegs.4: "; dump_registers(SRegs, *TRI);
16400b57cec5SDimitry Andric              dbgs() << "\n");
16410b57cec5SDimitry Andric 
16420b57cec5SDimitry Andric   // (5) For each register R in SRegs, if any super-register of R is in SRegs,
16430b57cec5SDimitry Andric   // remove R from SRegs.
16440b57cec5SDimitry Andric   for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) {
1645bdd1243dSDimitry Andric     Register R = x;
164606c3fb27SDimitry Andric     for (MCPhysReg SR : TRI->superregs(R)) {
164706c3fb27SDimitry Andric       if (!SRegs[SR])
16480b57cec5SDimitry Andric         continue;
16490b57cec5SDimitry Andric       SRegs[R] = false;
16500b57cec5SDimitry Andric       break;
16510b57cec5SDimitry Andric     }
16520b57cec5SDimitry Andric   }
16530b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "SRegs.5: "; dump_registers(SRegs, *TRI);
16540b57cec5SDimitry Andric              dbgs() << "\n");
16550b57cec5SDimitry Andric 
16560b57cec5SDimitry Andric   // Now, for each register that has a fixed stack slot, create the stack
16570b57cec5SDimitry Andric   // object for it.
16580b57cec5SDimitry Andric   CSI.clear();
16590b57cec5SDimitry Andric 
16600b57cec5SDimitry Andric   using SpillSlot = TargetFrameLowering::SpillSlot;
16610b57cec5SDimitry Andric 
16620b57cec5SDimitry Andric   unsigned NumFixed;
16630b57cec5SDimitry Andric   int MinOffset = 0;  // CS offsets are negative.
16640b57cec5SDimitry Andric   const SpillSlot *FixedSlots = getCalleeSavedSpillSlots(NumFixed);
16650b57cec5SDimitry Andric   for (const SpillSlot *S = FixedSlots; S != FixedSlots+NumFixed; ++S) {
16660b57cec5SDimitry Andric     if (!SRegs[S->Reg])
16670b57cec5SDimitry Andric       continue;
16680b57cec5SDimitry Andric     const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(S->Reg);
16690b57cec5SDimitry Andric     int FI = MFI.CreateFixedSpillStackObject(TRI->getSpillSize(*RC), S->Offset);
16700b57cec5SDimitry Andric     MinOffset = std::min(MinOffset, S->Offset);
16710b57cec5SDimitry Andric     CSI.push_back(CalleeSavedInfo(S->Reg, FI));
16720b57cec5SDimitry Andric     SRegs[S->Reg] = false;
16730b57cec5SDimitry Andric   }
16740b57cec5SDimitry Andric 
16750b57cec5SDimitry Andric   // There can be some registers that don't have fixed slots. For example,
16760b57cec5SDimitry Andric   // we need to store R0-R3 in functions with exception handling. For each
16770b57cec5SDimitry Andric   // such register, create a non-fixed stack object.
16780b57cec5SDimitry Andric   for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) {
1679bdd1243dSDimitry Andric     Register R = x;
16800b57cec5SDimitry Andric     const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(R);
16810b57cec5SDimitry Andric     unsigned Size = TRI->getSpillSize(*RC);
16820b57cec5SDimitry Andric     int Off = MinOffset - Size;
16835ffd83dbSDimitry Andric     Align Alignment = std::min(TRI->getSpillAlign(*RC), getStackAlign());
16845ffd83dbSDimitry Andric     Off &= -Alignment.value();
16850b57cec5SDimitry Andric     int FI = MFI.CreateFixedSpillStackObject(Size, Off);
16860b57cec5SDimitry Andric     MinOffset = std::min(MinOffset, Off);
16870b57cec5SDimitry Andric     CSI.push_back(CalleeSavedInfo(R, FI));
16880b57cec5SDimitry Andric     SRegs[R] = false;
16890b57cec5SDimitry Andric   }
16900b57cec5SDimitry Andric 
16910b57cec5SDimitry Andric   LLVM_DEBUG({
16920b57cec5SDimitry Andric     dbgs() << "CS information: {";
16934824e7fdSDimitry Andric     for (const CalleeSavedInfo &I : CSI) {
16944824e7fdSDimitry Andric       int FI = I.getFrameIdx();
16950b57cec5SDimitry Andric       int Off = MFI.getObjectOffset(FI);
16964824e7fdSDimitry Andric       dbgs() << ' ' << printReg(I.getReg(), TRI) << ":fi#" << FI << ":sp";
16970b57cec5SDimitry Andric       if (Off >= 0)
16980b57cec5SDimitry Andric         dbgs() << '+';
16990b57cec5SDimitry Andric       dbgs() << Off;
17000b57cec5SDimitry Andric     }
17010b57cec5SDimitry Andric     dbgs() << " }\n";
17020b57cec5SDimitry Andric   });
17030b57cec5SDimitry Andric 
17040b57cec5SDimitry Andric #ifndef NDEBUG
17050b57cec5SDimitry Andric   // Verify that all registers were handled.
17060b57cec5SDimitry Andric   bool MissedReg = false;
17070b57cec5SDimitry Andric   for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) {
1708bdd1243dSDimitry Andric     Register R = x;
17090b57cec5SDimitry Andric     dbgs() << printReg(R, TRI) << ' ';
17100b57cec5SDimitry Andric     MissedReg = true;
17110b57cec5SDimitry Andric   }
17120b57cec5SDimitry Andric   if (MissedReg)
17130b57cec5SDimitry Andric     llvm_unreachable("...there are unhandled callee-saved registers!");
17140b57cec5SDimitry Andric #endif
17150b57cec5SDimitry Andric 
17160b57cec5SDimitry Andric   return true;
17170b57cec5SDimitry Andric }
17180b57cec5SDimitry Andric 
expandCopy(MachineBasicBlock & B,MachineBasicBlock::iterator It,MachineRegisterInfo & MRI,const HexagonInstrInfo & HII,SmallVectorImpl<Register> & NewRegs) const17190b57cec5SDimitry Andric bool HexagonFrameLowering::expandCopy(MachineBasicBlock &B,
17200b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
1721bdd1243dSDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const {
17220b57cec5SDimitry Andric   MachineInstr *MI = &*It;
17230b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
17248bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
17258bcb0991SDimitry Andric   Register SrcR = MI->getOperand(1).getReg();
17260b57cec5SDimitry Andric   if (!Hexagon::ModRegsRegClass.contains(DstR) ||
17270b57cec5SDimitry Andric       !Hexagon::ModRegsRegClass.contains(SrcR))
17280b57cec5SDimitry Andric     return false;
17290b57cec5SDimitry Andric 
17308bcb0991SDimitry Andric   Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
17310b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(TargetOpcode::COPY), TmpR).add(MI->getOperand(1));
17320b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(TargetOpcode::COPY), DstR)
17330b57cec5SDimitry Andric     .addReg(TmpR, RegState::Kill);
17340b57cec5SDimitry Andric 
17350b57cec5SDimitry Andric   NewRegs.push_back(TmpR);
17360b57cec5SDimitry Andric   B.erase(It);
17370b57cec5SDimitry Andric   return true;
17380b57cec5SDimitry Andric }
17390b57cec5SDimitry Andric 
expandStoreInt(MachineBasicBlock & B,MachineBasicBlock::iterator It,MachineRegisterInfo & MRI,const HexagonInstrInfo & HII,SmallVectorImpl<Register> & NewRegs) const17400b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreInt(MachineBasicBlock &B,
17410b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
1742bdd1243dSDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const {
17430b57cec5SDimitry Andric   MachineInstr *MI = &*It;
17440b57cec5SDimitry Andric   if (!MI->getOperand(0).isFI())
17450b57cec5SDimitry Andric     return false;
17460b57cec5SDimitry Andric 
17470b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
17480b57cec5SDimitry Andric   unsigned Opc = MI->getOpcode();
17498bcb0991SDimitry Andric   Register SrcR = MI->getOperand(2).getReg();
17500b57cec5SDimitry Andric   bool IsKill = MI->getOperand(2).isKill();
17510b57cec5SDimitry Andric   int FI = MI->getOperand(0).getIndex();
17520b57cec5SDimitry Andric 
17530b57cec5SDimitry Andric   // TmpR = C2_tfrpr SrcR   if SrcR is a predicate register
17540b57cec5SDimitry Andric   // TmpR = A2_tfrcrr SrcR  if SrcR is a modifier register
17558bcb0991SDimitry Andric   Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
17560b57cec5SDimitry Andric   unsigned TfrOpc = (Opc == Hexagon::STriw_pred) ? Hexagon::C2_tfrpr
17570b57cec5SDimitry Andric                                                  : Hexagon::A2_tfrcrr;
17580b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(TfrOpc), TmpR)
17590b57cec5SDimitry Andric     .addReg(SrcR, getKillRegState(IsKill));
17600b57cec5SDimitry Andric 
17610b57cec5SDimitry Andric   // S2_storeri_io FI, 0, TmpR
17620b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::S2_storeri_io))
17630b57cec5SDimitry Andric       .addFrameIndex(FI)
17640b57cec5SDimitry Andric       .addImm(0)
17650b57cec5SDimitry Andric       .addReg(TmpR, RegState::Kill)
17660b57cec5SDimitry Andric       .cloneMemRefs(*MI);
17670b57cec5SDimitry Andric 
17680b57cec5SDimitry Andric   NewRegs.push_back(TmpR);
17690b57cec5SDimitry Andric   B.erase(It);
17700b57cec5SDimitry Andric   return true;
17710b57cec5SDimitry Andric }
17720b57cec5SDimitry Andric 
expandLoadInt(MachineBasicBlock & B,MachineBasicBlock::iterator It,MachineRegisterInfo & MRI,const HexagonInstrInfo & HII,SmallVectorImpl<Register> & NewRegs) const17730b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadInt(MachineBasicBlock &B,
17740b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
1775bdd1243dSDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const {
17760b57cec5SDimitry Andric   MachineInstr *MI = &*It;
17770b57cec5SDimitry Andric   if (!MI->getOperand(1).isFI())
17780b57cec5SDimitry Andric     return false;
17790b57cec5SDimitry Andric 
17800b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
17810b57cec5SDimitry Andric   unsigned Opc = MI->getOpcode();
17828bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
17830b57cec5SDimitry Andric   int FI = MI->getOperand(1).getIndex();
17840b57cec5SDimitry Andric 
17850b57cec5SDimitry Andric   // TmpR = L2_loadri_io FI, 0
17868bcb0991SDimitry Andric   Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
17870b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::L2_loadri_io), TmpR)
17880b57cec5SDimitry Andric       .addFrameIndex(FI)
17890b57cec5SDimitry Andric       .addImm(0)
17900b57cec5SDimitry Andric       .cloneMemRefs(*MI);
17910b57cec5SDimitry Andric 
17920b57cec5SDimitry Andric   // DstR = C2_tfrrp TmpR   if DstR is a predicate register
17930b57cec5SDimitry Andric   // DstR = A2_tfrrcr TmpR  if DstR is a modifier register
17940b57cec5SDimitry Andric   unsigned TfrOpc = (Opc == Hexagon::LDriw_pred) ? Hexagon::C2_tfrrp
17950b57cec5SDimitry Andric                                                  : Hexagon::A2_tfrrcr;
17960b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(TfrOpc), DstR)
17970b57cec5SDimitry Andric     .addReg(TmpR, RegState::Kill);
17980b57cec5SDimitry Andric 
17990b57cec5SDimitry Andric   NewRegs.push_back(TmpR);
18000b57cec5SDimitry Andric   B.erase(It);
18010b57cec5SDimitry Andric   return true;
18020b57cec5SDimitry Andric }
18030b57cec5SDimitry Andric 
expandStoreVecPred(MachineBasicBlock & B,MachineBasicBlock::iterator It,MachineRegisterInfo & MRI,const HexagonInstrInfo & HII,SmallVectorImpl<Register> & NewRegs) const18040b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVecPred(MachineBasicBlock &B,
18050b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
1806bdd1243dSDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const {
18070b57cec5SDimitry Andric   MachineInstr *MI = &*It;
18080b57cec5SDimitry Andric   if (!MI->getOperand(0).isFI())
18090b57cec5SDimitry Andric     return false;
18100b57cec5SDimitry Andric 
18110b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
18128bcb0991SDimitry Andric   Register SrcR = MI->getOperand(2).getReg();
18130b57cec5SDimitry Andric   bool IsKill = MI->getOperand(2).isKill();
18140b57cec5SDimitry Andric   int FI = MI->getOperand(0).getIndex();
18150b57cec5SDimitry Andric   auto *RC = &Hexagon::HvxVRRegClass;
18160b57cec5SDimitry Andric 
18170b57cec5SDimitry Andric   // Insert transfer to general vector register.
18180b57cec5SDimitry Andric   //   TmpR0 = A2_tfrsi 0x01010101
18190b57cec5SDimitry Andric   //   TmpR1 = V6_vandqrt Qx, TmpR0
18200b57cec5SDimitry Andric   //   store FI, 0, TmpR1
18218bcb0991SDimitry Andric   Register TmpR0 = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
18228bcb0991SDimitry Andric   Register TmpR1 = MRI.createVirtualRegister(RC);
18230b57cec5SDimitry Andric 
18240b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::A2_tfrsi), TmpR0)
18250b57cec5SDimitry Andric     .addImm(0x01010101);
18260b57cec5SDimitry Andric 
18270b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::V6_vandqrt), TmpR1)
18280b57cec5SDimitry Andric     .addReg(SrcR, getKillRegState(IsKill))
18290b57cec5SDimitry Andric     .addReg(TmpR0, RegState::Kill);
18300b57cec5SDimitry Andric 
18310b57cec5SDimitry Andric   auto *HRI = B.getParent()->getSubtarget<HexagonSubtarget>().getRegisterInfo();
1832bdd1243dSDimitry Andric   HII.storeRegToStackSlot(B, It, TmpR1, true, FI, RC, HRI, Register());
18330b57cec5SDimitry Andric   expandStoreVec(B, std::prev(It), MRI, HII, NewRegs);
18340b57cec5SDimitry Andric 
18350b57cec5SDimitry Andric   NewRegs.push_back(TmpR0);
18360b57cec5SDimitry Andric   NewRegs.push_back(TmpR1);
18370b57cec5SDimitry Andric   B.erase(It);
18380b57cec5SDimitry Andric   return true;
18390b57cec5SDimitry Andric }
18400b57cec5SDimitry Andric 
expandLoadVecPred(MachineBasicBlock & B,MachineBasicBlock::iterator It,MachineRegisterInfo & MRI,const HexagonInstrInfo & HII,SmallVectorImpl<Register> & NewRegs) const18410b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVecPred(MachineBasicBlock &B,
18420b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
1843bdd1243dSDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const {
18440b57cec5SDimitry Andric   MachineInstr *MI = &*It;
18450b57cec5SDimitry Andric   if (!MI->getOperand(1).isFI())
18460b57cec5SDimitry Andric     return false;
18470b57cec5SDimitry Andric 
18480b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
18498bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
18500b57cec5SDimitry Andric   int FI = MI->getOperand(1).getIndex();
18510b57cec5SDimitry Andric   auto *RC = &Hexagon::HvxVRRegClass;
18520b57cec5SDimitry Andric 
18530b57cec5SDimitry Andric   // TmpR0 = A2_tfrsi 0x01010101
18540b57cec5SDimitry Andric   // TmpR1 = load FI, 0
18550b57cec5SDimitry Andric   // DstR = V6_vandvrt TmpR1, TmpR0
18568bcb0991SDimitry Andric   Register TmpR0 = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
18578bcb0991SDimitry Andric   Register TmpR1 = MRI.createVirtualRegister(RC);
18580b57cec5SDimitry Andric 
18590b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::A2_tfrsi), TmpR0)
18600b57cec5SDimitry Andric     .addImm(0x01010101);
18610b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
18620b57cec5SDimitry Andric   auto *HRI = MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
1863bdd1243dSDimitry Andric   HII.loadRegFromStackSlot(B, It, TmpR1, FI, RC, HRI, Register());
18640b57cec5SDimitry Andric   expandLoadVec(B, std::prev(It), MRI, HII, NewRegs);
18650b57cec5SDimitry Andric 
18660b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(Hexagon::V6_vandvrt), DstR)
18670b57cec5SDimitry Andric     .addReg(TmpR1, RegState::Kill)
18680b57cec5SDimitry Andric     .addReg(TmpR0, RegState::Kill);
18690b57cec5SDimitry Andric 
18700b57cec5SDimitry Andric   NewRegs.push_back(TmpR0);
18710b57cec5SDimitry Andric   NewRegs.push_back(TmpR1);
18720b57cec5SDimitry Andric   B.erase(It);
18730b57cec5SDimitry Andric   return true;
18740b57cec5SDimitry Andric }
18750b57cec5SDimitry Andric 
expandStoreVec2(MachineBasicBlock & B,MachineBasicBlock::iterator It,MachineRegisterInfo & MRI,const HexagonInstrInfo & HII,SmallVectorImpl<Register> & NewRegs) const18760b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVec2(MachineBasicBlock &B,
18770b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
1878bdd1243dSDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const {
18790b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
18800b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
18810b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
18820b57cec5SDimitry Andric   MachineInstr *MI = &*It;
18830b57cec5SDimitry Andric   if (!MI->getOperand(0).isFI())
18840b57cec5SDimitry Andric     return false;
18850b57cec5SDimitry Andric 
18860b57cec5SDimitry Andric   // It is possible that the double vector being stored is only partially
18870b57cec5SDimitry Andric   // defined. From the point of view of the liveness tracking, it is ok to
18880b57cec5SDimitry Andric   // store it as a whole, but if we break it up we may end up storing a
18890b57cec5SDimitry Andric   // register that is entirely undefined.
18900b57cec5SDimitry Andric   LivePhysRegs LPR(HRI);
18910b57cec5SDimitry Andric   LPR.addLiveIns(B);
18920b57cec5SDimitry Andric   SmallVector<std::pair<MCPhysReg, const MachineOperand*>,2> Clobbers;
18930b57cec5SDimitry Andric   for (auto R = B.begin(); R != It; ++R) {
18940b57cec5SDimitry Andric     Clobbers.clear();
18950b57cec5SDimitry Andric     LPR.stepForward(*R, Clobbers);
18960b57cec5SDimitry Andric   }
18970b57cec5SDimitry Andric 
18980b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
18998bcb0991SDimitry Andric   Register SrcR = MI->getOperand(2).getReg();
19008bcb0991SDimitry Andric   Register SrcLo = HRI.getSubReg(SrcR, Hexagon::vsub_lo);
19018bcb0991SDimitry Andric   Register SrcHi = HRI.getSubReg(SrcR, Hexagon::vsub_hi);
19020b57cec5SDimitry Andric   bool IsKill = MI->getOperand(2).isKill();
19030b57cec5SDimitry Andric   int FI = MI->getOperand(0).getIndex();
19040b57cec5SDimitry Andric 
19050b57cec5SDimitry Andric   unsigned Size = HRI.getSpillSize(Hexagon::HvxVRRegClass);
19065ffd83dbSDimitry Andric   Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass);
19075ffd83dbSDimitry Andric   Align HasAlign = MFI.getObjectAlign(FI);
19080b57cec5SDimitry Andric   unsigned StoreOpc;
19090b57cec5SDimitry Andric 
19100b57cec5SDimitry Andric   // Store low part.
19110b57cec5SDimitry Andric   if (LPR.contains(SrcLo)) {
1912bdd1243dSDimitry Andric     StoreOpc = NeedAlign <= HasAlign ? Hexagon::V6_vS32b_ai
19130b57cec5SDimitry Andric                                      : Hexagon::V6_vS32Ub_ai;
19140b57cec5SDimitry Andric     BuildMI(B, It, DL, HII.get(StoreOpc))
19150b57cec5SDimitry Andric         .addFrameIndex(FI)
19160b57cec5SDimitry Andric         .addImm(0)
19170b57cec5SDimitry Andric         .addReg(SrcLo, getKillRegState(IsKill))
19180b57cec5SDimitry Andric         .cloneMemRefs(*MI);
19190b57cec5SDimitry Andric   }
19200b57cec5SDimitry Andric 
19210b57cec5SDimitry Andric   // Store high part.
19220b57cec5SDimitry Andric   if (LPR.contains(SrcHi)) {
1923bdd1243dSDimitry Andric     StoreOpc = NeedAlign <= HasAlign ? Hexagon::V6_vS32b_ai
19240b57cec5SDimitry Andric                                      : Hexagon::V6_vS32Ub_ai;
19250b57cec5SDimitry Andric     BuildMI(B, It, DL, HII.get(StoreOpc))
19260b57cec5SDimitry Andric         .addFrameIndex(FI)
19270b57cec5SDimitry Andric         .addImm(Size)
19280b57cec5SDimitry Andric         .addReg(SrcHi, getKillRegState(IsKill))
19290b57cec5SDimitry Andric         .cloneMemRefs(*MI);
19300b57cec5SDimitry Andric   }
19310b57cec5SDimitry Andric 
19320b57cec5SDimitry Andric   B.erase(It);
19330b57cec5SDimitry Andric   return true;
19340b57cec5SDimitry Andric }
19350b57cec5SDimitry Andric 
expandLoadVec2(MachineBasicBlock & B,MachineBasicBlock::iterator It,MachineRegisterInfo & MRI,const HexagonInstrInfo & HII,SmallVectorImpl<Register> & NewRegs) const19360b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVec2(MachineBasicBlock &B,
19370b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
1938bdd1243dSDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const {
19390b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
19400b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
19410b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
19420b57cec5SDimitry Andric   MachineInstr *MI = &*It;
19430b57cec5SDimitry Andric   if (!MI->getOperand(1).isFI())
19440b57cec5SDimitry Andric     return false;
19450b57cec5SDimitry Andric 
19460b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
19478bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
19488bcb0991SDimitry Andric   Register DstHi = HRI.getSubReg(DstR, Hexagon::vsub_hi);
19498bcb0991SDimitry Andric   Register DstLo = HRI.getSubReg(DstR, Hexagon::vsub_lo);
19500b57cec5SDimitry Andric   int FI = MI->getOperand(1).getIndex();
19510b57cec5SDimitry Andric 
19520b57cec5SDimitry Andric   unsigned Size = HRI.getSpillSize(Hexagon::HvxVRRegClass);
19535ffd83dbSDimitry Andric   Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass);
19545ffd83dbSDimitry Andric   Align HasAlign = MFI.getObjectAlign(FI);
19550b57cec5SDimitry Andric   unsigned LoadOpc;
19560b57cec5SDimitry Andric 
19570b57cec5SDimitry Andric   // Load low part.
1958bdd1243dSDimitry Andric   LoadOpc = NeedAlign <= HasAlign ? Hexagon::V6_vL32b_ai
19590b57cec5SDimitry Andric                                   : Hexagon::V6_vL32Ub_ai;
19600b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(LoadOpc), DstLo)
19610b57cec5SDimitry Andric       .addFrameIndex(FI)
19620b57cec5SDimitry Andric       .addImm(0)
19630b57cec5SDimitry Andric       .cloneMemRefs(*MI);
19640b57cec5SDimitry Andric 
19650b57cec5SDimitry Andric   // Load high part.
1966bdd1243dSDimitry Andric   LoadOpc = NeedAlign <= HasAlign ? Hexagon::V6_vL32b_ai
19670b57cec5SDimitry Andric                                   : Hexagon::V6_vL32Ub_ai;
19680b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(LoadOpc), DstHi)
19690b57cec5SDimitry Andric       .addFrameIndex(FI)
19700b57cec5SDimitry Andric       .addImm(Size)
19710b57cec5SDimitry Andric       .cloneMemRefs(*MI);
19720b57cec5SDimitry Andric 
19730b57cec5SDimitry Andric   B.erase(It);
19740b57cec5SDimitry Andric   return true;
19750b57cec5SDimitry Andric }
19760b57cec5SDimitry Andric 
expandStoreVec(MachineBasicBlock & B,MachineBasicBlock::iterator It,MachineRegisterInfo & MRI,const HexagonInstrInfo & HII,SmallVectorImpl<Register> & NewRegs) const19770b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVec(MachineBasicBlock &B,
19780b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
1979bdd1243dSDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const {
19800b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
19810b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
19820b57cec5SDimitry Andric   MachineInstr *MI = &*It;
19830b57cec5SDimitry Andric   if (!MI->getOperand(0).isFI())
19840b57cec5SDimitry Andric     return false;
19850b57cec5SDimitry Andric 
19860b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
19870b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
19888bcb0991SDimitry Andric   Register SrcR = MI->getOperand(2).getReg();
19890b57cec5SDimitry Andric   bool IsKill = MI->getOperand(2).isKill();
19900b57cec5SDimitry Andric   int FI = MI->getOperand(0).getIndex();
19910b57cec5SDimitry Andric 
19925ffd83dbSDimitry Andric   Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass);
19935ffd83dbSDimitry Andric   Align HasAlign = MFI.getObjectAlign(FI);
1994bdd1243dSDimitry Andric   unsigned StoreOpc = NeedAlign <= HasAlign ? Hexagon::V6_vS32b_ai
19950b57cec5SDimitry Andric                                             : Hexagon::V6_vS32Ub_ai;
19960b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(StoreOpc))
19970b57cec5SDimitry Andric       .addFrameIndex(FI)
19980b57cec5SDimitry Andric       .addImm(0)
19990b57cec5SDimitry Andric       .addReg(SrcR, getKillRegState(IsKill))
20000b57cec5SDimitry Andric       .cloneMemRefs(*MI);
20010b57cec5SDimitry Andric 
20020b57cec5SDimitry Andric   B.erase(It);
20030b57cec5SDimitry Andric   return true;
20040b57cec5SDimitry Andric }
20050b57cec5SDimitry Andric 
expandLoadVec(MachineBasicBlock & B,MachineBasicBlock::iterator It,MachineRegisterInfo & MRI,const HexagonInstrInfo & HII,SmallVectorImpl<Register> & NewRegs) const20060b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVec(MachineBasicBlock &B,
20070b57cec5SDimitry Andric       MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
2008bdd1243dSDimitry Andric       const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const {
20090b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
20100b57cec5SDimitry Andric   auto &MFI = MF.getFrameInfo();
20110b57cec5SDimitry Andric   MachineInstr *MI = &*It;
20120b57cec5SDimitry Andric   if (!MI->getOperand(1).isFI())
20130b57cec5SDimitry Andric     return false;
20140b57cec5SDimitry Andric 
20150b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
20160b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
20178bcb0991SDimitry Andric   Register DstR = MI->getOperand(0).getReg();
20180b57cec5SDimitry Andric   int FI = MI->getOperand(1).getIndex();
20190b57cec5SDimitry Andric 
20205ffd83dbSDimitry Andric   Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass);
20215ffd83dbSDimitry Andric   Align HasAlign = MFI.getObjectAlign(FI);
2022bdd1243dSDimitry Andric   unsigned LoadOpc = NeedAlign <= HasAlign ? Hexagon::V6_vL32b_ai
20230b57cec5SDimitry Andric                                            : Hexagon::V6_vL32Ub_ai;
20240b57cec5SDimitry Andric   BuildMI(B, It, DL, HII.get(LoadOpc), DstR)
20250b57cec5SDimitry Andric       .addFrameIndex(FI)
20260b57cec5SDimitry Andric       .addImm(0)
20270b57cec5SDimitry Andric       .cloneMemRefs(*MI);
20280b57cec5SDimitry Andric 
20290b57cec5SDimitry Andric   B.erase(It);
20300b57cec5SDimitry Andric   return true;
20310b57cec5SDimitry Andric }
20320b57cec5SDimitry Andric 
expandSpillMacros(MachineFunction & MF,SmallVectorImpl<Register> & NewRegs) const20330b57cec5SDimitry Andric bool HexagonFrameLowering::expandSpillMacros(MachineFunction &MF,
2034bdd1243dSDimitry Andric       SmallVectorImpl<Register> &NewRegs) const {
20350b57cec5SDimitry Andric   auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
20360b57cec5SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
20370b57cec5SDimitry Andric   bool Changed = false;
20380b57cec5SDimitry Andric 
20390b57cec5SDimitry Andric   for (auto &B : MF) {
20400b57cec5SDimitry Andric     // Traverse the basic block.
20410b57cec5SDimitry Andric     MachineBasicBlock::iterator NextI;
20420b57cec5SDimitry Andric     for (auto I = B.begin(), E = B.end(); I != E; I = NextI) {
20430b57cec5SDimitry Andric       MachineInstr *MI = &*I;
20440b57cec5SDimitry Andric       NextI = std::next(I);
20450b57cec5SDimitry Andric       unsigned Opc = MI->getOpcode();
20460b57cec5SDimitry Andric 
20470b57cec5SDimitry Andric       switch (Opc) {
20480b57cec5SDimitry Andric         case TargetOpcode::COPY:
20490b57cec5SDimitry Andric           Changed |= expandCopy(B, I, MRI, HII, NewRegs);
20500b57cec5SDimitry Andric           break;
20510b57cec5SDimitry Andric         case Hexagon::STriw_pred:
20520b57cec5SDimitry Andric         case Hexagon::STriw_ctr:
20530b57cec5SDimitry Andric           Changed |= expandStoreInt(B, I, MRI, HII, NewRegs);
20540b57cec5SDimitry Andric           break;
20550b57cec5SDimitry Andric         case Hexagon::LDriw_pred:
20560b57cec5SDimitry Andric         case Hexagon::LDriw_ctr:
20570b57cec5SDimitry Andric           Changed |= expandLoadInt(B, I, MRI, HII, NewRegs);
20580b57cec5SDimitry Andric           break;
20590b57cec5SDimitry Andric         case Hexagon::PS_vstorerq_ai:
20600b57cec5SDimitry Andric           Changed |= expandStoreVecPred(B, I, MRI, HII, NewRegs);
20610b57cec5SDimitry Andric           break;
20620b57cec5SDimitry Andric         case Hexagon::PS_vloadrq_ai:
20630b57cec5SDimitry Andric           Changed |= expandLoadVecPred(B, I, MRI, HII, NewRegs);
20640b57cec5SDimitry Andric           break;
20650b57cec5SDimitry Andric         case Hexagon::PS_vloadrw_ai:
20660b57cec5SDimitry Andric           Changed |= expandLoadVec2(B, I, MRI, HII, NewRegs);
20670b57cec5SDimitry Andric           break;
20680b57cec5SDimitry Andric         case Hexagon::PS_vstorerw_ai:
20690b57cec5SDimitry Andric           Changed |= expandStoreVec2(B, I, MRI, HII, NewRegs);
20700b57cec5SDimitry Andric           break;
20710b57cec5SDimitry Andric       }
20720b57cec5SDimitry Andric     }
20730b57cec5SDimitry Andric   }
20740b57cec5SDimitry Andric 
20750b57cec5SDimitry Andric   return Changed;
20760b57cec5SDimitry Andric }
20770b57cec5SDimitry Andric 
determineCalleeSaves(MachineFunction & MF,BitVector & SavedRegs,RegScavenger * RS) const20780b57cec5SDimitry Andric void HexagonFrameLowering::determineCalleeSaves(MachineFunction &MF,
20790b57cec5SDimitry Andric                                                 BitVector &SavedRegs,
20800b57cec5SDimitry Andric                                                 RegScavenger *RS) const {
20810b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
20820b57cec5SDimitry Andric 
20830b57cec5SDimitry Andric   SavedRegs.resize(HRI.getNumRegs());
20840b57cec5SDimitry Andric 
20850b57cec5SDimitry Andric   // If we have a function containing __builtin_eh_return we want to spill and
20860b57cec5SDimitry Andric   // restore all callee saved registers. Pretend that they are used.
20870b57cec5SDimitry Andric   if (MF.getInfo<HexagonMachineFunctionInfo>()->hasEHReturn())
20880b57cec5SDimitry Andric     for (const MCPhysReg *R = HRI.getCalleeSavedRegs(&MF); *R; ++R)
20890b57cec5SDimitry Andric       SavedRegs.set(*R);
20900b57cec5SDimitry Andric 
20910b57cec5SDimitry Andric   // Replace predicate register pseudo spill code.
2092bdd1243dSDimitry Andric   SmallVector<Register,8> NewRegs;
20930b57cec5SDimitry Andric   expandSpillMacros(MF, NewRegs);
20940b57cec5SDimitry Andric   if (OptimizeSpillSlots && !isOptNone(MF))
20950b57cec5SDimitry Andric     optimizeSpillSlots(MF, NewRegs);
20960b57cec5SDimitry Andric 
20970b57cec5SDimitry Andric   // We need to reserve a spill slot if scavenging could potentially require
20980b57cec5SDimitry Andric   // spilling a scavenged register.
20990b57cec5SDimitry Andric   if (!NewRegs.empty() || mayOverflowFrameOffset(MF)) {
21000b57cec5SDimitry Andric     MachineFrameInfo &MFI = MF.getFrameInfo();
21010b57cec5SDimitry Andric     MachineRegisterInfo &MRI = MF.getRegInfo();
21020b57cec5SDimitry Andric     SetVector<const TargetRegisterClass*> SpillRCs;
21030b57cec5SDimitry Andric     // Reserve an int register in any case, because it could be used to hold
21040b57cec5SDimitry Andric     // the stack offset in case it does not fit into a spill instruction.
21050b57cec5SDimitry Andric     SpillRCs.insert(&Hexagon::IntRegsRegClass);
21060b57cec5SDimitry Andric 
2107bdd1243dSDimitry Andric     for (Register VR : NewRegs)
21080b57cec5SDimitry Andric       SpillRCs.insert(MRI.getRegClass(VR));
21090b57cec5SDimitry Andric 
2110bdd1243dSDimitry Andric     for (const auto *RC : SpillRCs) {
21110b57cec5SDimitry Andric       if (!needToReserveScavengingSpillSlots(MF, HRI, RC))
21120b57cec5SDimitry Andric         continue;
2113480093f4SDimitry Andric       unsigned Num = 1;
2114480093f4SDimitry Andric       switch (RC->getID()) {
2115480093f4SDimitry Andric         case Hexagon::IntRegsRegClassID:
2116480093f4SDimitry Andric           Num = NumberScavengerSlots;
2117480093f4SDimitry Andric           break;
2118480093f4SDimitry Andric         case Hexagon::HvxQRRegClassID:
2119480093f4SDimitry Andric           Num = 2; // Vector predicate spills also need a vector register.
2120480093f4SDimitry Andric           break;
2121480093f4SDimitry Andric       }
21225ffd83dbSDimitry Andric       unsigned S = HRI.getSpillSize(*RC);
21235ffd83dbSDimitry Andric       Align A = HRI.getSpillAlign(*RC);
21240b57cec5SDimitry Andric       for (unsigned i = 0; i < Num; i++) {
21250b57cec5SDimitry Andric         int NewFI = MFI.CreateSpillStackObject(S, A);
21260b57cec5SDimitry Andric         RS->addScavengingFrameIndex(NewFI);
21270b57cec5SDimitry Andric       }
21280b57cec5SDimitry Andric     }
21290b57cec5SDimitry Andric   }
21300b57cec5SDimitry Andric 
21310b57cec5SDimitry Andric   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
21320b57cec5SDimitry Andric }
21330b57cec5SDimitry Andric 
findPhysReg(MachineFunction & MF,HexagonBlockRanges::IndexRange & FIR,HexagonBlockRanges::InstrIndexMap & IndexMap,HexagonBlockRanges::RegToRangeMap & DeadMap,const TargetRegisterClass * RC) const2134bdd1243dSDimitry Andric Register HexagonFrameLowering::findPhysReg(MachineFunction &MF,
21350b57cec5SDimitry Andric       HexagonBlockRanges::IndexRange &FIR,
21360b57cec5SDimitry Andric       HexagonBlockRanges::InstrIndexMap &IndexMap,
21370b57cec5SDimitry Andric       HexagonBlockRanges::RegToRangeMap &DeadMap,
21380b57cec5SDimitry Andric       const TargetRegisterClass *RC) const {
21390b57cec5SDimitry Andric   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
21400b57cec5SDimitry Andric   auto &MRI = MF.getRegInfo();
21410b57cec5SDimitry Andric 
2142bdd1243dSDimitry Andric   auto isDead = [&FIR,&DeadMap] (Register Reg) -> bool {
21430b57cec5SDimitry Andric     auto F = DeadMap.find({Reg,0});
21440b57cec5SDimitry Andric     if (F == DeadMap.end())
21450b57cec5SDimitry Andric       return false;
21460b57cec5SDimitry Andric     for (auto &DR : F->second)
21470b57cec5SDimitry Andric       if (DR.contains(FIR))
21480b57cec5SDimitry Andric         return true;
21490b57cec5SDimitry Andric     return false;
21500b57cec5SDimitry Andric   };
21510b57cec5SDimitry Andric 
2152bdd1243dSDimitry Andric   for (Register Reg : RC->getRawAllocationOrder(MF)) {
21530b57cec5SDimitry Andric     bool Dead = true;
21540b57cec5SDimitry Andric     for (auto R : HexagonBlockRanges::expandToSubRegs({Reg,0}, MRI, HRI)) {
21550b57cec5SDimitry Andric       if (isDead(R.Reg))
21560b57cec5SDimitry Andric         continue;
21570b57cec5SDimitry Andric       Dead = false;
21580b57cec5SDimitry Andric       break;
21590b57cec5SDimitry Andric     }
21600b57cec5SDimitry Andric     if (Dead)
21610b57cec5SDimitry Andric       return Reg;
21620b57cec5SDimitry Andric   }
21630b57cec5SDimitry Andric   return 0;
21640b57cec5SDimitry Andric }
21650b57cec5SDimitry Andric 
optimizeSpillSlots(MachineFunction & MF,SmallVectorImpl<Register> & VRegs) const21660b57cec5SDimitry Andric void HexagonFrameLowering::optimizeSpillSlots(MachineFunction &MF,
2167bdd1243dSDimitry Andric       SmallVectorImpl<Register> &VRegs) const {
21680b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
21690b57cec5SDimitry Andric   auto &HII = *HST.getInstrInfo();
21700b57cec5SDimitry Andric   auto &HRI = *HST.getRegisterInfo();
21710b57cec5SDimitry Andric   auto &MRI = MF.getRegInfo();
21720b57cec5SDimitry Andric   HexagonBlockRanges HBR(MF);
21730b57cec5SDimitry Andric 
21740b57cec5SDimitry Andric   using BlockIndexMap =
21750b57cec5SDimitry Andric       std::map<MachineBasicBlock *, HexagonBlockRanges::InstrIndexMap>;
21760b57cec5SDimitry Andric   using BlockRangeMap =
21770b57cec5SDimitry Andric       std::map<MachineBasicBlock *, HexagonBlockRanges::RangeList>;
21780b57cec5SDimitry Andric   using IndexType = HexagonBlockRanges::IndexType;
21790b57cec5SDimitry Andric 
21800b57cec5SDimitry Andric   struct SlotInfo {
21810b57cec5SDimitry Andric     BlockRangeMap Map;
21820b57cec5SDimitry Andric     unsigned Size = 0;
21830b57cec5SDimitry Andric     const TargetRegisterClass *RC = nullptr;
21840b57cec5SDimitry Andric 
21850b57cec5SDimitry Andric     SlotInfo() = default;
21860b57cec5SDimitry Andric   };
21870b57cec5SDimitry Andric 
21880b57cec5SDimitry Andric   BlockIndexMap BlockIndexes;
21890b57cec5SDimitry Andric   SmallSet<int,4> BadFIs;
21900b57cec5SDimitry Andric   std::map<int,SlotInfo> FIRangeMap;
21910b57cec5SDimitry Andric 
21920b57cec5SDimitry Andric   // Accumulate register classes: get a common class for a pre-existing
21930b57cec5SDimitry Andric   // class HaveRC and a new class NewRC. Return nullptr if a common class
21940b57cec5SDimitry Andric   // cannot be found, otherwise return the resulting class. If HaveRC is
21950b57cec5SDimitry Andric   // nullptr, assume that it is still unset.
21960b57cec5SDimitry Andric   auto getCommonRC =
21970b57cec5SDimitry Andric       [](const TargetRegisterClass *HaveRC,
21980b57cec5SDimitry Andric          const TargetRegisterClass *NewRC) -> const TargetRegisterClass * {
21990b57cec5SDimitry Andric     if (HaveRC == nullptr || HaveRC == NewRC)
22000b57cec5SDimitry Andric       return NewRC;
22010b57cec5SDimitry Andric     // Different classes, both non-null. Pick the more general one.
22020b57cec5SDimitry Andric     if (HaveRC->hasSubClassEq(NewRC))
22030b57cec5SDimitry Andric       return HaveRC;
22040b57cec5SDimitry Andric     if (NewRC->hasSubClassEq(HaveRC))
22050b57cec5SDimitry Andric       return NewRC;
22060b57cec5SDimitry Andric     return nullptr;
22070b57cec5SDimitry Andric   };
22080b57cec5SDimitry Andric 
22090b57cec5SDimitry Andric   // Scan all blocks in the function. Check all occurrences of frame indexes,
22100b57cec5SDimitry Andric   // and collect relevant information.
22110b57cec5SDimitry Andric   for (auto &B : MF) {
22120b57cec5SDimitry Andric     std::map<int,IndexType> LastStore, LastLoad;
22130b57cec5SDimitry Andric     // Emplace appears not to be supported in gcc 4.7.2-4.
22140b57cec5SDimitry Andric     //auto P = BlockIndexes.emplace(&B, HexagonBlockRanges::InstrIndexMap(B));
22150b57cec5SDimitry Andric     auto P = BlockIndexes.insert(
22160b57cec5SDimitry Andric                 std::make_pair(&B, HexagonBlockRanges::InstrIndexMap(B)));
22170b57cec5SDimitry Andric     auto &IndexMap = P.first->second;
22180b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Index map for " << printMBBReference(B) << "\n"
22190b57cec5SDimitry Andric                       << IndexMap << '\n');
22200b57cec5SDimitry Andric 
22210b57cec5SDimitry Andric     for (auto &In : B) {
22220b57cec5SDimitry Andric       int LFI, SFI;
22230b57cec5SDimitry Andric       bool Load = HII.isLoadFromStackSlot(In, LFI) && !HII.isPredicated(In);
22240b57cec5SDimitry Andric       bool Store = HII.isStoreToStackSlot(In, SFI) && !HII.isPredicated(In);
22250b57cec5SDimitry Andric       if (Load && Store) {
22260b57cec5SDimitry Andric         // If it's both a load and a store, then we won't handle it.
22270b57cec5SDimitry Andric         BadFIs.insert(LFI);
22280b57cec5SDimitry Andric         BadFIs.insert(SFI);
22290b57cec5SDimitry Andric         continue;
22300b57cec5SDimitry Andric       }
22310b57cec5SDimitry Andric       // Check for register classes of the register used as the source for
22320b57cec5SDimitry Andric       // the store, and the register used as the destination for the load.
22330b57cec5SDimitry Andric       // Also, only accept base+imm_offset addressing modes. Other addressing
22340b57cec5SDimitry Andric       // modes can have side-effects (post-increments, etc.). For stack
22350b57cec5SDimitry Andric       // slots they are very unlikely, so there is not much loss due to
22360b57cec5SDimitry Andric       // this restriction.
22370b57cec5SDimitry Andric       if (Load || Store) {
22380b57cec5SDimitry Andric         int TFI = Load ? LFI : SFI;
22390b57cec5SDimitry Andric         unsigned AM = HII.getAddrMode(In);
22400b57cec5SDimitry Andric         SlotInfo &SI = FIRangeMap[TFI];
22410b57cec5SDimitry Andric         bool Bad = (AM != HexagonII::BaseImmOffset);
22420b57cec5SDimitry Andric         if (!Bad) {
22430b57cec5SDimitry Andric           // If the addressing mode is ok, check the register class.
22440b57cec5SDimitry Andric           unsigned OpNum = Load ? 0 : 2;
22450b57cec5SDimitry Andric           auto *RC = HII.getRegClass(In.getDesc(), OpNum, &HRI, MF);
22460b57cec5SDimitry Andric           RC = getCommonRC(SI.RC, RC);
22470b57cec5SDimitry Andric           if (RC == nullptr)
22480b57cec5SDimitry Andric             Bad = true;
22490b57cec5SDimitry Andric           else
22500b57cec5SDimitry Andric             SI.RC = RC;
22510b57cec5SDimitry Andric         }
22520b57cec5SDimitry Andric         if (!Bad) {
22530b57cec5SDimitry Andric           // Check sizes.
22540b57cec5SDimitry Andric           unsigned S = HII.getMemAccessSize(In);
22550b57cec5SDimitry Andric           if (SI.Size != 0 && SI.Size != S)
22560b57cec5SDimitry Andric             Bad = true;
22570b57cec5SDimitry Andric           else
22580b57cec5SDimitry Andric             SI.Size = S;
22590b57cec5SDimitry Andric         }
22600b57cec5SDimitry Andric         if (!Bad) {
22610b57cec5SDimitry Andric           for (auto *Mo : In.memoperands()) {
22620b57cec5SDimitry Andric             if (!Mo->isVolatile() && !Mo->isAtomic())
22630b57cec5SDimitry Andric               continue;
22640b57cec5SDimitry Andric             Bad = true;
22650b57cec5SDimitry Andric             break;
22660b57cec5SDimitry Andric           }
22670b57cec5SDimitry Andric         }
22680b57cec5SDimitry Andric         if (Bad)
22690b57cec5SDimitry Andric           BadFIs.insert(TFI);
22700b57cec5SDimitry Andric       }
22710b57cec5SDimitry Andric 
22720b57cec5SDimitry Andric       // Locate uses of frame indices.
22730b57cec5SDimitry Andric       for (unsigned i = 0, n = In.getNumOperands(); i < n; ++i) {
22740b57cec5SDimitry Andric         const MachineOperand &Op = In.getOperand(i);
22750b57cec5SDimitry Andric         if (!Op.isFI())
22760b57cec5SDimitry Andric           continue;
22770b57cec5SDimitry Andric         int FI = Op.getIndex();
22780b57cec5SDimitry Andric         // Make sure that the following operand is an immediate and that
22790b57cec5SDimitry Andric         // it is 0. This is the offset in the stack object.
22800b57cec5SDimitry Andric         if (i+1 >= n || !In.getOperand(i+1).isImm() ||
22810b57cec5SDimitry Andric             In.getOperand(i+1).getImm() != 0)
22820b57cec5SDimitry Andric           BadFIs.insert(FI);
22830b57cec5SDimitry Andric         if (BadFIs.count(FI))
22840b57cec5SDimitry Andric           continue;
22850b57cec5SDimitry Andric 
22860b57cec5SDimitry Andric         IndexType Index = IndexMap.getIndex(&In);
22870b57cec5SDimitry Andric         if (Load) {
22880b57cec5SDimitry Andric           if (LastStore[FI] == IndexType::None)
22890b57cec5SDimitry Andric             LastStore[FI] = IndexType::Entry;
22900b57cec5SDimitry Andric           LastLoad[FI] = Index;
22910b57cec5SDimitry Andric         } else if (Store) {
22920b57cec5SDimitry Andric           HexagonBlockRanges::RangeList &RL = FIRangeMap[FI].Map[&B];
22930b57cec5SDimitry Andric           if (LastStore[FI] != IndexType::None)
22940b57cec5SDimitry Andric             RL.add(LastStore[FI], LastLoad[FI], false, false);
22950b57cec5SDimitry Andric           else if (LastLoad[FI] != IndexType::None)
22960b57cec5SDimitry Andric             RL.add(IndexType::Entry, LastLoad[FI], false, false);
22970b57cec5SDimitry Andric           LastLoad[FI] = IndexType::None;
22980b57cec5SDimitry Andric           LastStore[FI] = Index;
22990b57cec5SDimitry Andric         } else {
23000b57cec5SDimitry Andric           BadFIs.insert(FI);
23010b57cec5SDimitry Andric         }
23020b57cec5SDimitry Andric       }
23030b57cec5SDimitry Andric     }
23040b57cec5SDimitry Andric 
23050b57cec5SDimitry Andric     for (auto &I : LastLoad) {
23060b57cec5SDimitry Andric       IndexType LL = I.second;
23070b57cec5SDimitry Andric       if (LL == IndexType::None)
23080b57cec5SDimitry Andric         continue;
23090b57cec5SDimitry Andric       auto &RL = FIRangeMap[I.first].Map[&B];
23100b57cec5SDimitry Andric       IndexType &LS = LastStore[I.first];
23110b57cec5SDimitry Andric       if (LS != IndexType::None)
23120b57cec5SDimitry Andric         RL.add(LS, LL, false, false);
23130b57cec5SDimitry Andric       else
23140b57cec5SDimitry Andric         RL.add(IndexType::Entry, LL, false, false);
23150b57cec5SDimitry Andric       LS = IndexType::None;
23160b57cec5SDimitry Andric     }
23170b57cec5SDimitry Andric     for (auto &I : LastStore) {
23180b57cec5SDimitry Andric       IndexType LS = I.second;
23190b57cec5SDimitry Andric       if (LS == IndexType::None)
23200b57cec5SDimitry Andric         continue;
23210b57cec5SDimitry Andric       auto &RL = FIRangeMap[I.first].Map[&B];
23220b57cec5SDimitry Andric       RL.add(LS, IndexType::None, false, false);
23230b57cec5SDimitry Andric     }
23240b57cec5SDimitry Andric   }
23250b57cec5SDimitry Andric 
23260b57cec5SDimitry Andric   LLVM_DEBUG({
23270b57cec5SDimitry Andric     for (auto &P : FIRangeMap) {
23280b57cec5SDimitry Andric       dbgs() << "fi#" << P.first;
23290b57cec5SDimitry Andric       if (BadFIs.count(P.first))
23300b57cec5SDimitry Andric         dbgs() << " (bad)";
23310b57cec5SDimitry Andric       dbgs() << "  RC: ";
23320b57cec5SDimitry Andric       if (P.second.RC != nullptr)
23330b57cec5SDimitry Andric         dbgs() << HRI.getRegClassName(P.second.RC) << '\n';
23340b57cec5SDimitry Andric       else
23350b57cec5SDimitry Andric         dbgs() << "<null>\n";
23360b57cec5SDimitry Andric       for (auto &R : P.second.Map)
23370b57cec5SDimitry Andric         dbgs() << "  " << printMBBReference(*R.first) << " { " << R.second
23380b57cec5SDimitry Andric                << "}\n";
23390b57cec5SDimitry Andric     }
23400b57cec5SDimitry Andric   });
23410b57cec5SDimitry Andric 
23420b57cec5SDimitry Andric   // When a slot is loaded from in a block without being stored to in the
23430b57cec5SDimitry Andric   // same block, it is live-on-entry to this block. To avoid CFG analysis,
23440b57cec5SDimitry Andric   // consider this slot to be live-on-exit from all blocks.
23450b57cec5SDimitry Andric   SmallSet<int,4> LoxFIs;
23460b57cec5SDimitry Andric 
23470b57cec5SDimitry Andric   std::map<MachineBasicBlock*,std::vector<int>> BlockFIMap;
23480b57cec5SDimitry Andric 
23490b57cec5SDimitry Andric   for (auto &P : FIRangeMap) {
23500b57cec5SDimitry Andric     // P = pair(FI, map: BB->RangeList)
23510b57cec5SDimitry Andric     if (BadFIs.count(P.first))
23520b57cec5SDimitry Andric       continue;
23530b57cec5SDimitry Andric     for (auto &B : MF) {
23540b57cec5SDimitry Andric       auto F = P.second.Map.find(&B);
23550b57cec5SDimitry Andric       // F = pair(BB, RangeList)
23560b57cec5SDimitry Andric       if (F == P.second.Map.end() || F->second.empty())
23570b57cec5SDimitry Andric         continue;
23580b57cec5SDimitry Andric       HexagonBlockRanges::IndexRange &IR = F->second.front();
23590b57cec5SDimitry Andric       if (IR.start() == IndexType::Entry)
23600b57cec5SDimitry Andric         LoxFIs.insert(P.first);
23610b57cec5SDimitry Andric       BlockFIMap[&B].push_back(P.first);
23620b57cec5SDimitry Andric     }
23630b57cec5SDimitry Andric   }
23640b57cec5SDimitry Andric 
23650b57cec5SDimitry Andric   LLVM_DEBUG({
23660b57cec5SDimitry Andric     dbgs() << "Block-to-FI map (* -- live-on-exit):\n";
23670b57cec5SDimitry Andric     for (auto &P : BlockFIMap) {
23680b57cec5SDimitry Andric       auto &FIs = P.second;
23690b57cec5SDimitry Andric       if (FIs.empty())
23700b57cec5SDimitry Andric         continue;
23710b57cec5SDimitry Andric       dbgs() << "  " << printMBBReference(*P.first) << ": {";
23720b57cec5SDimitry Andric       for (auto I : FIs) {
23730b57cec5SDimitry Andric         dbgs() << " fi#" << I;
23740b57cec5SDimitry Andric         if (LoxFIs.count(I))
23750b57cec5SDimitry Andric           dbgs() << '*';
23760b57cec5SDimitry Andric       }
23770b57cec5SDimitry Andric       dbgs() << " }\n";
23780b57cec5SDimitry Andric     }
23790b57cec5SDimitry Andric   });
23800b57cec5SDimitry Andric 
23810b57cec5SDimitry Andric #ifndef NDEBUG
23820b57cec5SDimitry Andric   bool HasOptLimit = SpillOptMax.getPosition();
23830b57cec5SDimitry Andric #endif
23840b57cec5SDimitry Andric 
23850b57cec5SDimitry Andric   // eliminate loads, when all loads eliminated, eliminate all stores.
23860b57cec5SDimitry Andric   for (auto &B : MF) {
23870b57cec5SDimitry Andric     auto F = BlockIndexes.find(&B);
23880b57cec5SDimitry Andric     assert(F != BlockIndexes.end());
23890b57cec5SDimitry Andric     HexagonBlockRanges::InstrIndexMap &IM = F->second;
23900b57cec5SDimitry Andric     HexagonBlockRanges::RegToRangeMap LM = HBR.computeLiveMap(IM);
23910b57cec5SDimitry Andric     HexagonBlockRanges::RegToRangeMap DM = HBR.computeDeadMap(IM, LM);
23920b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << printMBBReference(B) << " dead map\n"
23930b57cec5SDimitry Andric                       << HexagonBlockRanges::PrintRangeMap(DM, HRI));
23940b57cec5SDimitry Andric 
23950b57cec5SDimitry Andric     for (auto FI : BlockFIMap[&B]) {
23960b57cec5SDimitry Andric       if (BadFIs.count(FI))
23970b57cec5SDimitry Andric         continue;
23980b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Working on fi#" << FI << '\n');
23990b57cec5SDimitry Andric       HexagonBlockRanges::RangeList &RL = FIRangeMap[FI].Map[&B];
24000b57cec5SDimitry Andric       for (auto &Range : RL) {
24010b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "--Examining range:" << RL << '\n');
24020b57cec5SDimitry Andric         if (!IndexType::isInstr(Range.start()) ||
24030b57cec5SDimitry Andric             !IndexType::isInstr(Range.end()))
24040b57cec5SDimitry Andric           continue;
24050b57cec5SDimitry Andric         MachineInstr &SI = *IM.getInstr(Range.start());
24060b57cec5SDimitry Andric         MachineInstr &EI = *IM.getInstr(Range.end());
24070b57cec5SDimitry Andric         assert(SI.mayStore() && "Unexpected start instruction");
24080b57cec5SDimitry Andric         assert(EI.mayLoad() && "Unexpected end instruction");
24090b57cec5SDimitry Andric         MachineOperand &SrcOp = SI.getOperand(2);
24100b57cec5SDimitry Andric 
24110b57cec5SDimitry Andric         HexagonBlockRanges::RegisterRef SrcRR = { SrcOp.getReg(),
24120b57cec5SDimitry Andric                                                   SrcOp.getSubReg() };
24130b57cec5SDimitry Andric         auto *RC = HII.getRegClass(SI.getDesc(), 2, &HRI, MF);
24140b57cec5SDimitry Andric         // The this-> is needed to unconfuse MSVC.
2415bdd1243dSDimitry Andric         Register FoundR = this->findPhysReg(MF, Range, IM, DM, RC);
24160b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "Replacement reg:" << printReg(FoundR, &HRI)
24170b57cec5SDimitry Andric                           << '\n');
24180b57cec5SDimitry Andric         if (FoundR == 0)
24190b57cec5SDimitry Andric           continue;
24200b57cec5SDimitry Andric #ifndef NDEBUG
24210b57cec5SDimitry Andric         if (HasOptLimit) {
24220b57cec5SDimitry Andric           if (SpillOptCount >= SpillOptMax)
24230b57cec5SDimitry Andric             return;
24240b57cec5SDimitry Andric           SpillOptCount++;
24250b57cec5SDimitry Andric         }
24260b57cec5SDimitry Andric #endif
24270b57cec5SDimitry Andric 
24280b57cec5SDimitry Andric         // Generate the copy-in: "FoundR = COPY SrcR" at the store location.
24290b57cec5SDimitry Andric         MachineBasicBlock::iterator StartIt = SI.getIterator(), NextIt;
24300b57cec5SDimitry Andric         MachineInstr *CopyIn = nullptr;
24310b57cec5SDimitry Andric         if (SrcRR.Reg != FoundR || SrcRR.Sub != 0) {
24320b57cec5SDimitry Andric           const DebugLoc &DL = SI.getDebugLoc();
24330b57cec5SDimitry Andric           CopyIn = BuildMI(B, StartIt, DL, HII.get(TargetOpcode::COPY), FoundR)
24340b57cec5SDimitry Andric                        .add(SrcOp);
24350b57cec5SDimitry Andric         }
24360b57cec5SDimitry Andric 
24370b57cec5SDimitry Andric         ++StartIt;
24380b57cec5SDimitry Andric         // Check if this is a last store and the FI is live-on-exit.
24390b57cec5SDimitry Andric         if (LoxFIs.count(FI) && (&Range == &RL.back())) {
24400b57cec5SDimitry Andric           // Update store's source register.
24410b57cec5SDimitry Andric           if (unsigned SR = SrcOp.getSubReg())
24420b57cec5SDimitry Andric             SrcOp.setReg(HRI.getSubReg(FoundR, SR));
24430b57cec5SDimitry Andric           else
24440b57cec5SDimitry Andric             SrcOp.setReg(FoundR);
24450b57cec5SDimitry Andric           SrcOp.setSubReg(0);
24460b57cec5SDimitry Andric           // We are keeping this register live.
24470b57cec5SDimitry Andric           SrcOp.setIsKill(false);
24480b57cec5SDimitry Andric         } else {
24490b57cec5SDimitry Andric           B.erase(&SI);
24500b57cec5SDimitry Andric           IM.replaceInstr(&SI, CopyIn);
24510b57cec5SDimitry Andric         }
24520b57cec5SDimitry Andric 
24530b57cec5SDimitry Andric         auto EndIt = std::next(EI.getIterator());
24540b57cec5SDimitry Andric         for (auto It = StartIt; It != EndIt; It = NextIt) {
24550b57cec5SDimitry Andric           MachineInstr &MI = *It;
24560b57cec5SDimitry Andric           NextIt = std::next(It);
24570b57cec5SDimitry Andric           int TFI;
24580b57cec5SDimitry Andric           if (!HII.isLoadFromStackSlot(MI, TFI) || TFI != FI)
24590b57cec5SDimitry Andric             continue;
24608bcb0991SDimitry Andric           Register DstR = MI.getOperand(0).getReg();
24610b57cec5SDimitry Andric           assert(MI.getOperand(0).getSubReg() == 0);
24620b57cec5SDimitry Andric           MachineInstr *CopyOut = nullptr;
24630b57cec5SDimitry Andric           if (DstR != FoundR) {
24640b57cec5SDimitry Andric             DebugLoc DL = MI.getDebugLoc();
24650b57cec5SDimitry Andric             unsigned MemSize = HII.getMemAccessSize(MI);
24660b57cec5SDimitry Andric             assert(HII.getAddrMode(MI) == HexagonII::BaseImmOffset);
24670b57cec5SDimitry Andric             unsigned CopyOpc = TargetOpcode::COPY;
24680b57cec5SDimitry Andric             if (HII.isSignExtendingLoad(MI))
24690b57cec5SDimitry Andric               CopyOpc = (MemSize == 1) ? Hexagon::A2_sxtb : Hexagon::A2_sxth;
24700b57cec5SDimitry Andric             else if (HII.isZeroExtendingLoad(MI))
24710b57cec5SDimitry Andric               CopyOpc = (MemSize == 1) ? Hexagon::A2_zxtb : Hexagon::A2_zxth;
24720b57cec5SDimitry Andric             CopyOut = BuildMI(B, It, DL, HII.get(CopyOpc), DstR)
24730b57cec5SDimitry Andric                         .addReg(FoundR, getKillRegState(&MI == &EI));
24740b57cec5SDimitry Andric           }
24750b57cec5SDimitry Andric           IM.replaceInstr(&MI, CopyOut);
24760b57cec5SDimitry Andric           B.erase(It);
24770b57cec5SDimitry Andric         }
24780b57cec5SDimitry Andric 
24790b57cec5SDimitry Andric         // Update the dead map.
24800b57cec5SDimitry Andric         HexagonBlockRanges::RegisterRef FoundRR = { FoundR, 0 };
24810b57cec5SDimitry Andric         for (auto RR : HexagonBlockRanges::expandToSubRegs(FoundRR, MRI, HRI))
24820b57cec5SDimitry Andric           DM[RR].subtract(Range);
24830b57cec5SDimitry Andric       } // for Range in range list
24840b57cec5SDimitry Andric     }
24850b57cec5SDimitry Andric   }
24860b57cec5SDimitry Andric }
24870b57cec5SDimitry Andric 
expandAlloca(MachineInstr * AI,const HexagonInstrInfo & HII,Register SP,unsigned CF) const24880b57cec5SDimitry Andric void HexagonFrameLowering::expandAlloca(MachineInstr *AI,
2489bdd1243dSDimitry Andric       const HexagonInstrInfo &HII, Register SP, unsigned CF) const {
24900b57cec5SDimitry Andric   MachineBasicBlock &MB = *AI->getParent();
24910b57cec5SDimitry Andric   DebugLoc DL = AI->getDebugLoc();
24920b57cec5SDimitry Andric   unsigned A = AI->getOperand(2).getImm();
24930b57cec5SDimitry Andric 
24940b57cec5SDimitry Andric   // Have
24950b57cec5SDimitry Andric   //    Rd  = alloca Rs, #A
24960b57cec5SDimitry Andric   //
24970b57cec5SDimitry Andric   // If Rs and Rd are different registers, use this sequence:
24980b57cec5SDimitry Andric   //    Rd  = sub(r29, Rs)
24990b57cec5SDimitry Andric   //    r29 = sub(r29, Rs)
25000b57cec5SDimitry Andric   //    Rd  = and(Rd, #-A)    ; if necessary
25010b57cec5SDimitry Andric   //    r29 = and(r29, #-A)   ; if necessary
25020b57cec5SDimitry Andric   //    Rd  = add(Rd, #CF)    ; CF size aligned to at most A
25030b57cec5SDimitry Andric   // otherwise, do
25040b57cec5SDimitry Andric   //    Rd  = sub(r29, Rs)
25050b57cec5SDimitry Andric   //    Rd  = and(Rd, #-A)    ; if necessary
25060b57cec5SDimitry Andric   //    r29 = Rd
25070b57cec5SDimitry Andric   //    Rd  = add(Rd, #CF)    ; CF size aligned to at most A
25080b57cec5SDimitry Andric 
25090b57cec5SDimitry Andric   MachineOperand &RdOp = AI->getOperand(0);
25100b57cec5SDimitry Andric   MachineOperand &RsOp = AI->getOperand(1);
2511bdd1243dSDimitry Andric   Register Rd = RdOp.getReg(), Rs = RsOp.getReg();
25120b57cec5SDimitry Andric 
25130b57cec5SDimitry Andric   // Rd = sub(r29, Rs)
25140b57cec5SDimitry Andric   BuildMI(MB, AI, DL, HII.get(Hexagon::A2_sub), Rd)
25150b57cec5SDimitry Andric       .addReg(SP)
25160b57cec5SDimitry Andric       .addReg(Rs);
25170b57cec5SDimitry Andric   if (Rs != Rd) {
25180b57cec5SDimitry Andric     // r29 = sub(r29, Rs)
25190b57cec5SDimitry Andric     BuildMI(MB, AI, DL, HII.get(Hexagon::A2_sub), SP)
25200b57cec5SDimitry Andric         .addReg(SP)
25210b57cec5SDimitry Andric         .addReg(Rs);
25220b57cec5SDimitry Andric   }
25230b57cec5SDimitry Andric   if (A > 8) {
25240b57cec5SDimitry Andric     // Rd  = and(Rd, #-A)
25250b57cec5SDimitry Andric     BuildMI(MB, AI, DL, HII.get(Hexagon::A2_andir), Rd)
25260b57cec5SDimitry Andric         .addReg(Rd)
25270b57cec5SDimitry Andric         .addImm(-int64_t(A));
25280b57cec5SDimitry Andric     if (Rs != Rd)
25290b57cec5SDimitry Andric       BuildMI(MB, AI, DL, HII.get(Hexagon::A2_andir), SP)
25300b57cec5SDimitry Andric           .addReg(SP)
25310b57cec5SDimitry Andric           .addImm(-int64_t(A));
25320b57cec5SDimitry Andric   }
25330b57cec5SDimitry Andric   if (Rs == Rd) {
25340b57cec5SDimitry Andric     // r29 = Rd
25350b57cec5SDimitry Andric     BuildMI(MB, AI, DL, HII.get(TargetOpcode::COPY), SP)
25360b57cec5SDimitry Andric         .addReg(Rd);
25370b57cec5SDimitry Andric   }
25380b57cec5SDimitry Andric   if (CF > 0) {
25390b57cec5SDimitry Andric     // Rd = add(Rd, #CF)
25400b57cec5SDimitry Andric     BuildMI(MB, AI, DL, HII.get(Hexagon::A2_addi), Rd)
25410b57cec5SDimitry Andric         .addReg(Rd)
25420b57cec5SDimitry Andric         .addImm(CF);
25430b57cec5SDimitry Andric   }
25440b57cec5SDimitry Andric }
25450b57cec5SDimitry Andric 
needsAligna(const MachineFunction & MF) const25460b57cec5SDimitry Andric bool HexagonFrameLowering::needsAligna(const MachineFunction &MF) const {
25470b57cec5SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
25480b57cec5SDimitry Andric   if (!MFI.hasVarSizedObjects())
25490b57cec5SDimitry Andric     return false;
2550480093f4SDimitry Andric   // Do not check for max stack object alignment here, because the stack
2551480093f4SDimitry Andric   // may not be complete yet. Assume that we will need PS_aligna if there
2552480093f4SDimitry Andric   // are variable-sized objects.
25530b57cec5SDimitry Andric   return true;
25540b57cec5SDimitry Andric }
25550b57cec5SDimitry Andric 
getAlignaInstr(const MachineFunction & MF) const25560b57cec5SDimitry Andric const MachineInstr *HexagonFrameLowering::getAlignaInstr(
25570b57cec5SDimitry Andric       const MachineFunction &MF) const {
25580b57cec5SDimitry Andric   for (auto &B : MF)
25590b57cec5SDimitry Andric     for (auto &I : B)
25600b57cec5SDimitry Andric       if (I.getOpcode() == Hexagon::PS_aligna)
25610b57cec5SDimitry Andric         return &I;
25620b57cec5SDimitry Andric   return nullptr;
25630b57cec5SDimitry Andric }
25640b57cec5SDimitry Andric 
25650b57cec5SDimitry Andric /// Adds all callee-saved registers as implicit uses or defs to the
25660b57cec5SDimitry Andric /// instruction.
addCalleeSaveRegistersAsImpOperand(MachineInstr * MI,const CSIVect & CSI,bool IsDef,bool IsKill) const25670b57cec5SDimitry Andric void HexagonFrameLowering::addCalleeSaveRegistersAsImpOperand(MachineInstr *MI,
25680b57cec5SDimitry Andric       const CSIVect &CSI, bool IsDef, bool IsKill) const {
25690b57cec5SDimitry Andric   // Add the callee-saved registers as implicit uses.
25700b57cec5SDimitry Andric   for (auto &R : CSI)
25710b57cec5SDimitry Andric     MI->addOperand(MachineOperand::CreateReg(R.getReg(), IsDef, true, IsKill));
25720b57cec5SDimitry Andric }
25730b57cec5SDimitry Andric 
25740b57cec5SDimitry Andric /// Determine whether the callee-saved register saves and restores should
25750b57cec5SDimitry Andric /// be generated via inline code. If this function returns "true", inline
25760b57cec5SDimitry Andric /// code will be generated. If this function returns "false", additional
25770b57cec5SDimitry Andric /// checks are performed, which may still lead to the inline code.
shouldInlineCSR(const MachineFunction & MF,const CSIVect & CSI) const25780b57cec5SDimitry Andric bool HexagonFrameLowering::shouldInlineCSR(const MachineFunction &MF,
25790b57cec5SDimitry Andric       const CSIVect &CSI) const {
25805ffd83dbSDimitry Andric   if (MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl())
25815ffd83dbSDimitry Andric     return true;
25820b57cec5SDimitry Andric   if (MF.getInfo<HexagonMachineFunctionInfo>()->hasEHReturn())
25830b57cec5SDimitry Andric     return true;
25840b57cec5SDimitry Andric   if (!hasFP(MF))
25850b57cec5SDimitry Andric     return true;
25860b57cec5SDimitry Andric   if (!isOptSize(MF) && !isMinSize(MF))
25875f757f3fSDimitry Andric     if (MF.getTarget().getOptLevel() > CodeGenOptLevel::Default)
25880b57cec5SDimitry Andric       return true;
25890b57cec5SDimitry Andric 
25900b57cec5SDimitry Andric   // Check if CSI only has double registers, and if the registers form
25910b57cec5SDimitry Andric   // a contiguous block starting from D8.
25920b57cec5SDimitry Andric   BitVector Regs(Hexagon::NUM_TARGET_REGS);
25934824e7fdSDimitry Andric   for (const CalleeSavedInfo &I : CSI) {
259404eeddc0SDimitry Andric     Register R = I.getReg();
25950b57cec5SDimitry Andric     if (!Hexagon::DoubleRegsRegClass.contains(R))
25960b57cec5SDimitry Andric       return true;
25970b57cec5SDimitry Andric     Regs[R] = true;
25980b57cec5SDimitry Andric   }
25990b57cec5SDimitry Andric   int F = Regs.find_first();
26000b57cec5SDimitry Andric   if (F != Hexagon::D8)
26010b57cec5SDimitry Andric     return true;
26020b57cec5SDimitry Andric   while (F >= 0) {
26030b57cec5SDimitry Andric     int N = Regs.find_next(F);
26040b57cec5SDimitry Andric     if (N >= 0 && N != F+1)
26050b57cec5SDimitry Andric       return true;
26060b57cec5SDimitry Andric     F = N;
26070b57cec5SDimitry Andric   }
26080b57cec5SDimitry Andric 
26090b57cec5SDimitry Andric   return false;
26100b57cec5SDimitry Andric }
26110b57cec5SDimitry Andric 
useSpillFunction(const MachineFunction & MF,const CSIVect & CSI) const26120b57cec5SDimitry Andric bool HexagonFrameLowering::useSpillFunction(const MachineFunction &MF,
26130b57cec5SDimitry Andric       const CSIVect &CSI) const {
26140b57cec5SDimitry Andric   if (shouldInlineCSR(MF, CSI))
26150b57cec5SDimitry Andric     return false;
26160b57cec5SDimitry Andric   unsigned NumCSI = CSI.size();
26170b57cec5SDimitry Andric   if (NumCSI <= 1)
26180b57cec5SDimitry Andric     return false;
26190b57cec5SDimitry Andric 
26200b57cec5SDimitry Andric   unsigned Threshold = isOptSize(MF) ? SpillFuncThresholdOs
26210b57cec5SDimitry Andric                                      : SpillFuncThreshold;
26220b57cec5SDimitry Andric   return Threshold < NumCSI;
26230b57cec5SDimitry Andric }
26240b57cec5SDimitry Andric 
useRestoreFunction(const MachineFunction & MF,const CSIVect & CSI) const26250b57cec5SDimitry Andric bool HexagonFrameLowering::useRestoreFunction(const MachineFunction &MF,
26260b57cec5SDimitry Andric       const CSIVect &CSI) const {
26270b57cec5SDimitry Andric   if (shouldInlineCSR(MF, CSI))
26280b57cec5SDimitry Andric     return false;
26290b57cec5SDimitry Andric   // The restore functions do a bit more than just restoring registers.
26300b57cec5SDimitry Andric   // The non-returning versions will go back directly to the caller's
26310b57cec5SDimitry Andric   // caller, others will clean up the stack frame in preparation for
26320b57cec5SDimitry Andric   // a tail call. Using them can still save code size even if only one
26330b57cec5SDimitry Andric   // register is getting restores. Make the decision based on -Oz:
26340b57cec5SDimitry Andric   // using -Os will use inline restore for a single register.
26350b57cec5SDimitry Andric   if (isMinSize(MF))
26360b57cec5SDimitry Andric     return true;
26370b57cec5SDimitry Andric   unsigned NumCSI = CSI.size();
26380b57cec5SDimitry Andric   if (NumCSI <= 1)
26390b57cec5SDimitry Andric     return false;
26400b57cec5SDimitry Andric 
26410b57cec5SDimitry Andric   unsigned Threshold = isOptSize(MF) ? SpillFuncThresholdOs-1
26420b57cec5SDimitry Andric                                      : SpillFuncThreshold;
26430b57cec5SDimitry Andric   return Threshold < NumCSI;
26440b57cec5SDimitry Andric }
26450b57cec5SDimitry Andric 
mayOverflowFrameOffset(MachineFunction & MF) const26460b57cec5SDimitry Andric bool HexagonFrameLowering::mayOverflowFrameOffset(MachineFunction &MF) const {
26470b57cec5SDimitry Andric   unsigned StackSize = MF.getFrameInfo().estimateStackSize(MF);
26480b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
26490b57cec5SDimitry Andric   // A fairly simplistic guess as to whether a potential load/store to a
26500b57cec5SDimitry Andric   // stack location could require an extra register.
26510b57cec5SDimitry Andric   if (HST.useHVXOps() && StackSize > 256)
26520b57cec5SDimitry Andric     return true;
26530b57cec5SDimitry Andric 
26540b57cec5SDimitry Andric   // Check if the function has store-immediate instructions that access
26550b57cec5SDimitry Andric   // the stack. Since the offset field is not extendable, if the stack
26560b57cec5SDimitry Andric   // size exceeds the offset limit (6 bits, shifted), the stores will
26570b57cec5SDimitry Andric   // require a new base register.
26580b57cec5SDimitry Andric   bool HasImmStack = false;
26590b57cec5SDimitry Andric   unsigned MinLS = ~0u;   // Log_2 of the memory access size.
26600b57cec5SDimitry Andric 
26610b57cec5SDimitry Andric   for (const MachineBasicBlock &B : MF) {
26620b57cec5SDimitry Andric     for (const MachineInstr &MI : B) {
26630b57cec5SDimitry Andric       unsigned LS = 0;
26640b57cec5SDimitry Andric       switch (MI.getOpcode()) {
26650b57cec5SDimitry Andric         case Hexagon::S4_storeirit_io:
26660b57cec5SDimitry Andric         case Hexagon::S4_storeirif_io:
26670b57cec5SDimitry Andric         case Hexagon::S4_storeiri_io:
26680b57cec5SDimitry Andric           ++LS;
2669bdd1243dSDimitry Andric           [[fallthrough]];
26700b57cec5SDimitry Andric         case Hexagon::S4_storeirht_io:
26710b57cec5SDimitry Andric         case Hexagon::S4_storeirhf_io:
26720b57cec5SDimitry Andric         case Hexagon::S4_storeirh_io:
26730b57cec5SDimitry Andric           ++LS;
2674bdd1243dSDimitry Andric           [[fallthrough]];
26750b57cec5SDimitry Andric         case Hexagon::S4_storeirbt_io:
26760b57cec5SDimitry Andric         case Hexagon::S4_storeirbf_io:
26770b57cec5SDimitry Andric         case Hexagon::S4_storeirb_io:
26780b57cec5SDimitry Andric           if (MI.getOperand(0).isFI())
26790b57cec5SDimitry Andric             HasImmStack = true;
26800b57cec5SDimitry Andric           MinLS = std::min(MinLS, LS);
26810b57cec5SDimitry Andric           break;
26820b57cec5SDimitry Andric       }
26830b57cec5SDimitry Andric     }
26840b57cec5SDimitry Andric   }
26850b57cec5SDimitry Andric 
26860b57cec5SDimitry Andric   if (HasImmStack)
26870b57cec5SDimitry Andric     return !isUInt<6>(StackSize >> MinLS);
26880b57cec5SDimitry Andric 
26890b57cec5SDimitry Andric   return false;
26900b57cec5SDimitry Andric }
2691