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 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 2190b57cec5SDimitry 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 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 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. 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. 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. 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. 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. 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. 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 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 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 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 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). 4000b57cec5SDimitry 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; 4160fca6ea1SDimitry Andric MDT.calculate(MF); 4170b57cec5SDimitry Andric MachinePostDominatorTree MPT; 4180fca6ea1SDimitry Andric MPT.recalculate(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. 5110b57cec5SDimitry 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. 5620b57cec5SDimitry 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. 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 5910b57cec5SDimitry 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 7660b57cec5SDimitry 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 8870b57cec5SDimitry 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 9280b57cec5SDimitry 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 9500b57cec5SDimitry 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> 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 10250b57cec5SDimitry 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 10310b57cec5SDimitry 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 auto &HST = MF.getSubtarget<HexagonSubtarget>(); 10360b57cec5SDimitry Andric auto &HII = *HST.getInstrInfo(); 10370b57cec5SDimitry Andric auto &HRI = *HST.getRegisterInfo(); 10380b57cec5SDimitry Andric 10390b57cec5SDimitry Andric // If CFI instructions have debug information attached, something goes 10400b57cec5SDimitry Andric // wrong with the final assembly generation: the prolog_end is placed 10410b57cec5SDimitry Andric // in a wrong location. 10420b57cec5SDimitry Andric DebugLoc DL; 10430b57cec5SDimitry Andric const MCInstrDesc &CFID = HII.get(TargetOpcode::CFI_INSTRUCTION); 10440b57cec5SDimitry Andric 10450fca6ea1SDimitry Andric MCSymbol *FrameLabel = MF.getContext().createTempSymbol(); 10460b57cec5SDimitry Andric bool HasFP = hasFP(MF); 10470b57cec5SDimitry Andric 10480b57cec5SDimitry Andric if (HasFP) { 10490b57cec5SDimitry Andric unsigned DwFPReg = HRI.getDwarfRegNum(HRI.getFrameRegister(), true); 10500b57cec5SDimitry Andric unsigned DwRAReg = HRI.getDwarfRegNum(HRI.getRARegister(), true); 10510b57cec5SDimitry Andric 10520b57cec5SDimitry Andric // Define CFA via an offset from the value of FP. 10530b57cec5SDimitry Andric // 10540b57cec5SDimitry Andric // -8 -4 0 (SP) 10550b57cec5SDimitry Andric // --+----+----+--------------------- 10560b57cec5SDimitry Andric // | FP | LR | increasing addresses --> 10570b57cec5SDimitry Andric // --+----+----+--------------------- 10580b57cec5SDimitry Andric // | +-- Old SP (before allocframe) 10590b57cec5SDimitry Andric // +-- New FP (after allocframe) 10600b57cec5SDimitry Andric // 10615ffd83dbSDimitry Andric // MCCFIInstruction::cfiDefCfa adds the offset from the register. 10620b57cec5SDimitry Andric // MCCFIInstruction::createOffset takes the offset without sign change. 10635ffd83dbSDimitry Andric auto DefCfa = MCCFIInstruction::cfiDefCfa(FrameLabel, DwFPReg, 8); 10640b57cec5SDimitry Andric BuildMI(MBB, At, DL, CFID) 10650b57cec5SDimitry Andric .addCFIIndex(MF.addFrameInst(DefCfa)); 10660b57cec5SDimitry Andric // R31 (return addr) = CFA - 4 10670b57cec5SDimitry Andric auto OffR31 = MCCFIInstruction::createOffset(FrameLabel, DwRAReg, -4); 10680b57cec5SDimitry Andric BuildMI(MBB, At, DL, CFID) 10690b57cec5SDimitry Andric .addCFIIndex(MF.addFrameInst(OffR31)); 10700b57cec5SDimitry Andric // R30 (frame ptr) = CFA - 8 10710b57cec5SDimitry Andric auto OffR30 = MCCFIInstruction::createOffset(FrameLabel, DwFPReg, -8); 10720b57cec5SDimitry Andric BuildMI(MBB, At, DL, CFID) 10730b57cec5SDimitry Andric .addCFIIndex(MF.addFrameInst(OffR30)); 10740b57cec5SDimitry Andric } 10750b57cec5SDimitry Andric 1076bdd1243dSDimitry Andric static Register RegsToMove[] = { 10770b57cec5SDimitry Andric Hexagon::R1, Hexagon::R0, Hexagon::R3, Hexagon::R2, 10780b57cec5SDimitry Andric Hexagon::R17, Hexagon::R16, Hexagon::R19, Hexagon::R18, 10790b57cec5SDimitry Andric Hexagon::R21, Hexagon::R20, Hexagon::R23, Hexagon::R22, 10800b57cec5SDimitry Andric Hexagon::R25, Hexagon::R24, Hexagon::R27, Hexagon::R26, 10810b57cec5SDimitry Andric Hexagon::D0, Hexagon::D1, Hexagon::D8, Hexagon::D9, 10820b57cec5SDimitry Andric Hexagon::D10, Hexagon::D11, Hexagon::D12, Hexagon::D13, 10830b57cec5SDimitry Andric Hexagon::NoRegister 10840b57cec5SDimitry Andric }; 10850b57cec5SDimitry Andric 10860b57cec5SDimitry Andric const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 10870b57cec5SDimitry Andric 10880b57cec5SDimitry Andric for (unsigned i = 0; RegsToMove[i] != Hexagon::NoRegister; ++i) { 1089bdd1243dSDimitry Andric Register Reg = RegsToMove[i]; 10900b57cec5SDimitry Andric auto IfR = [Reg] (const CalleeSavedInfo &C) -> bool { 10910b57cec5SDimitry Andric return C.getReg() == Reg; 10920b57cec5SDimitry Andric }; 10930b57cec5SDimitry Andric auto F = find_if(CSI, IfR); 10940b57cec5SDimitry Andric if (F == CSI.end()) 10950b57cec5SDimitry Andric continue; 10960b57cec5SDimitry Andric 10970b57cec5SDimitry Andric int64_t Offset; 10980b57cec5SDimitry Andric if (HasFP) { 10990b57cec5SDimitry Andric // If the function has a frame pointer (i.e. has an allocframe), 11000b57cec5SDimitry Andric // then the CFA has been defined in terms of FP. Any offsets in 11010b57cec5SDimitry Andric // the following CFI instructions have to be defined relative 11020b57cec5SDimitry Andric // to FP, which points to the bottom of the stack frame. 11030b57cec5SDimitry Andric // The function getFrameIndexReference can still choose to use SP 11040b57cec5SDimitry Andric // for the offset calculation, so we cannot simply call it here. 11050b57cec5SDimitry Andric // Instead, get the offset (relative to the FP) directly. 11060b57cec5SDimitry Andric Offset = MFI.getObjectOffset(F->getFrameIdx()); 11070b57cec5SDimitry Andric } else { 11085ffd83dbSDimitry Andric Register FrameReg; 1109e8d8bef9SDimitry Andric Offset = 1110e8d8bef9SDimitry Andric getFrameIndexReference(MF, F->getFrameIdx(), FrameReg).getFixed(); 11110b57cec5SDimitry Andric } 11120b57cec5SDimitry Andric // Subtract 8 to make room for R30 and R31, which are added above. 11130b57cec5SDimitry Andric Offset -= 8; 11140b57cec5SDimitry Andric 11150b57cec5SDimitry Andric if (Reg < Hexagon::D0 || Reg > Hexagon::D15) { 11160b57cec5SDimitry Andric unsigned DwarfReg = HRI.getDwarfRegNum(Reg, true); 11170b57cec5SDimitry Andric auto OffReg = MCCFIInstruction::createOffset(FrameLabel, DwarfReg, 11180b57cec5SDimitry Andric Offset); 11190b57cec5SDimitry Andric BuildMI(MBB, At, DL, CFID) 11200b57cec5SDimitry Andric .addCFIIndex(MF.addFrameInst(OffReg)); 11210b57cec5SDimitry Andric } else { 11220b57cec5SDimitry Andric // Split the double regs into subregs, and generate appropriate 11230b57cec5SDimitry Andric // cfi_offsets. 11240b57cec5SDimitry Andric // The only reason, we are split double regs is, llvm-mc does not 11250b57cec5SDimitry Andric // understand paired registers for cfi_offset. 11260b57cec5SDimitry Andric // Eg .cfi_offset r1:0, -64 11270b57cec5SDimitry Andric 11288bcb0991SDimitry Andric Register HiReg = HRI.getSubReg(Reg, Hexagon::isub_hi); 11298bcb0991SDimitry Andric Register LoReg = HRI.getSubReg(Reg, Hexagon::isub_lo); 11300b57cec5SDimitry Andric unsigned HiDwarfReg = HRI.getDwarfRegNum(HiReg, true); 11310b57cec5SDimitry Andric unsigned LoDwarfReg = HRI.getDwarfRegNum(LoReg, true); 11320b57cec5SDimitry Andric auto OffHi = MCCFIInstruction::createOffset(FrameLabel, HiDwarfReg, 11330b57cec5SDimitry Andric Offset+4); 11340b57cec5SDimitry Andric BuildMI(MBB, At, DL, CFID) 11350b57cec5SDimitry Andric .addCFIIndex(MF.addFrameInst(OffHi)); 11360b57cec5SDimitry Andric auto OffLo = MCCFIInstruction::createOffset(FrameLabel, LoDwarfReg, 11370b57cec5SDimitry Andric Offset); 11380b57cec5SDimitry Andric BuildMI(MBB, At, DL, CFID) 11390b57cec5SDimitry Andric .addCFIIndex(MF.addFrameInst(OffLo)); 11400b57cec5SDimitry Andric } 11410b57cec5SDimitry Andric } 11420b57cec5SDimitry Andric } 11430b57cec5SDimitry Andric 11440b57cec5SDimitry Andric bool HexagonFrameLowering::hasFP(const MachineFunction &MF) const { 11450b57cec5SDimitry Andric if (MF.getFunction().hasFnAttribute(Attribute::Naked)) 11460b57cec5SDimitry Andric return false; 11470b57cec5SDimitry Andric 11480b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 11490b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 1150fe6060f1SDimitry Andric bool HasExtraAlign = HRI.hasStackRealignment(MF); 11510b57cec5SDimitry Andric bool HasAlloca = MFI.hasVarSizedObjects(); 11520b57cec5SDimitry Andric 11530b57cec5SDimitry Andric // Insert ALLOCFRAME if we need to or at -O0 for the debugger. Think 11540b57cec5SDimitry Andric // that this shouldn't be required, but doing so now because gcc does and 11550b57cec5SDimitry Andric // gdb can't break at the start of the function without it. Will remove if 11560b57cec5SDimitry Andric // this turns out to be a gdb bug. 11570b57cec5SDimitry Andric // 11585f757f3fSDimitry Andric if (MF.getTarget().getOptLevel() == CodeGenOptLevel::None) 11590b57cec5SDimitry Andric return true; 11600b57cec5SDimitry Andric 11610b57cec5SDimitry Andric // By default we want to use SP (since it's always there). FP requires 11620b57cec5SDimitry Andric // some setup (i.e. ALLOCFRAME). 11630b57cec5SDimitry Andric // Both, alloca and stack alignment modify the stack pointer by an 11640b57cec5SDimitry Andric // undetermined value, so we need to save it at the entry to the function 11650b57cec5SDimitry Andric // (i.e. use allocframe). 11660b57cec5SDimitry Andric if (HasAlloca || HasExtraAlign) 11670b57cec5SDimitry Andric return true; 11680b57cec5SDimitry Andric 11690b57cec5SDimitry Andric if (MFI.getStackSize() > 0) { 11700b57cec5SDimitry Andric // If FP-elimination is disabled, we have to use FP at this point. 11710b57cec5SDimitry Andric const TargetMachine &TM = MF.getTarget(); 11720b57cec5SDimitry Andric if (TM.Options.DisableFramePointerElim(MF) || !EliminateFramePointer) 11730b57cec5SDimitry Andric return true; 11740b57cec5SDimitry Andric if (EnableStackOVFSanitizer) 11750b57cec5SDimitry Andric return true; 11760b57cec5SDimitry Andric } 11770b57cec5SDimitry Andric 11780b57cec5SDimitry Andric const auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>(); 11790b57cec5SDimitry Andric if ((MFI.hasCalls() && !enableAllocFrameElim(MF)) || HMFI.hasClobberLR()) 11800b57cec5SDimitry Andric return true; 11810b57cec5SDimitry Andric 11820b57cec5SDimitry Andric return false; 11830b57cec5SDimitry Andric } 11840b57cec5SDimitry Andric 11850b57cec5SDimitry Andric enum SpillKind { 11860b57cec5SDimitry Andric SK_ToMem, 11870b57cec5SDimitry Andric SK_FromMem, 11880b57cec5SDimitry Andric SK_FromMemTailcall 11890b57cec5SDimitry Andric }; 11900b57cec5SDimitry Andric 1191bdd1243dSDimitry Andric static const char *getSpillFunctionFor(Register MaxReg, SpillKind SpillType, 11920b57cec5SDimitry Andric bool Stkchk = false) { 11930b57cec5SDimitry Andric const char * V4SpillToMemoryFunctions[] = { 11940b57cec5SDimitry Andric "__save_r16_through_r17", 11950b57cec5SDimitry Andric "__save_r16_through_r19", 11960b57cec5SDimitry Andric "__save_r16_through_r21", 11970b57cec5SDimitry Andric "__save_r16_through_r23", 11980b57cec5SDimitry Andric "__save_r16_through_r25", 11990b57cec5SDimitry Andric "__save_r16_through_r27" }; 12000b57cec5SDimitry Andric 12010b57cec5SDimitry Andric const char * V4SpillToMemoryStkchkFunctions[] = { 12020b57cec5SDimitry Andric "__save_r16_through_r17_stkchk", 12030b57cec5SDimitry Andric "__save_r16_through_r19_stkchk", 12040b57cec5SDimitry Andric "__save_r16_through_r21_stkchk", 12050b57cec5SDimitry Andric "__save_r16_through_r23_stkchk", 12060b57cec5SDimitry Andric "__save_r16_through_r25_stkchk", 12070b57cec5SDimitry Andric "__save_r16_through_r27_stkchk" }; 12080b57cec5SDimitry Andric 12090b57cec5SDimitry Andric const char * V4SpillFromMemoryFunctions[] = { 12100b57cec5SDimitry Andric "__restore_r16_through_r17_and_deallocframe", 12110b57cec5SDimitry Andric "__restore_r16_through_r19_and_deallocframe", 12120b57cec5SDimitry Andric "__restore_r16_through_r21_and_deallocframe", 12130b57cec5SDimitry Andric "__restore_r16_through_r23_and_deallocframe", 12140b57cec5SDimitry Andric "__restore_r16_through_r25_and_deallocframe", 12150b57cec5SDimitry Andric "__restore_r16_through_r27_and_deallocframe" }; 12160b57cec5SDimitry Andric 12170b57cec5SDimitry Andric const char * V4SpillFromMemoryTailcallFunctions[] = { 12180b57cec5SDimitry Andric "__restore_r16_through_r17_and_deallocframe_before_tailcall", 12190b57cec5SDimitry Andric "__restore_r16_through_r19_and_deallocframe_before_tailcall", 12200b57cec5SDimitry Andric "__restore_r16_through_r21_and_deallocframe_before_tailcall", 12210b57cec5SDimitry Andric "__restore_r16_through_r23_and_deallocframe_before_tailcall", 12220b57cec5SDimitry Andric "__restore_r16_through_r25_and_deallocframe_before_tailcall", 12230b57cec5SDimitry Andric "__restore_r16_through_r27_and_deallocframe_before_tailcall" 12240b57cec5SDimitry Andric }; 12250b57cec5SDimitry Andric 12260b57cec5SDimitry Andric const char **SpillFunc = nullptr; 12270b57cec5SDimitry Andric 12280b57cec5SDimitry Andric switch(SpillType) { 12290b57cec5SDimitry Andric case SK_ToMem: 12300b57cec5SDimitry Andric SpillFunc = Stkchk ? V4SpillToMemoryStkchkFunctions 12310b57cec5SDimitry Andric : V4SpillToMemoryFunctions; 12320b57cec5SDimitry Andric break; 12330b57cec5SDimitry Andric case SK_FromMem: 12340b57cec5SDimitry Andric SpillFunc = V4SpillFromMemoryFunctions; 12350b57cec5SDimitry Andric break; 12360b57cec5SDimitry Andric case SK_FromMemTailcall: 12370b57cec5SDimitry Andric SpillFunc = V4SpillFromMemoryTailcallFunctions; 12380b57cec5SDimitry Andric break; 12390b57cec5SDimitry Andric } 12400b57cec5SDimitry Andric assert(SpillFunc && "Unknown spill kind"); 12410b57cec5SDimitry Andric 12420b57cec5SDimitry Andric // Spill all callee-saved registers up to the highest register used. 12430b57cec5SDimitry Andric switch (MaxReg) { 12440b57cec5SDimitry Andric case Hexagon::R17: 12450b57cec5SDimitry Andric return SpillFunc[0]; 12460b57cec5SDimitry Andric case Hexagon::R19: 12470b57cec5SDimitry Andric return SpillFunc[1]; 12480b57cec5SDimitry Andric case Hexagon::R21: 12490b57cec5SDimitry Andric return SpillFunc[2]; 12500b57cec5SDimitry Andric case Hexagon::R23: 12510b57cec5SDimitry Andric return SpillFunc[3]; 12520b57cec5SDimitry Andric case Hexagon::R25: 12530b57cec5SDimitry Andric return SpillFunc[4]; 12540b57cec5SDimitry Andric case Hexagon::R27: 12550b57cec5SDimitry Andric return SpillFunc[5]; 12560b57cec5SDimitry Andric default: 12570b57cec5SDimitry Andric llvm_unreachable("Unhandled maximum callee save register"); 12580b57cec5SDimitry Andric } 12590b57cec5SDimitry Andric return nullptr; 12600b57cec5SDimitry Andric } 12610b57cec5SDimitry Andric 1262e8d8bef9SDimitry Andric StackOffset 1263e8d8bef9SDimitry Andric HexagonFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, 12645ffd83dbSDimitry Andric Register &FrameReg) const { 12650b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 12660b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 12670b57cec5SDimitry Andric 12680b57cec5SDimitry Andric int Offset = MFI.getObjectOffset(FI); 12690b57cec5SDimitry Andric bool HasAlloca = MFI.hasVarSizedObjects(); 1270fe6060f1SDimitry Andric bool HasExtraAlign = HRI.hasStackRealignment(MF); 12715f757f3fSDimitry Andric bool NoOpt = MF.getTarget().getOptLevel() == CodeGenOptLevel::None; 12720b57cec5SDimitry Andric 12730b57cec5SDimitry Andric auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>(); 12740b57cec5SDimitry Andric unsigned FrameSize = MFI.getStackSize(); 12755ffd83dbSDimitry Andric Register SP = HRI.getStackRegister(); 12765ffd83dbSDimitry Andric Register FP = HRI.getFrameRegister(); 1277bdd1243dSDimitry Andric Register AP = HMFI.getStackAlignBaseReg(); 12780b57cec5SDimitry Andric // It may happen that AP will be absent even HasAlloca && HasExtraAlign 12790b57cec5SDimitry Andric // is true. HasExtraAlign may be set because of vector spills, without 12800b57cec5SDimitry Andric // aligned locals or aligned outgoing function arguments. Since vector 12810b57cec5SDimitry Andric // spills will ultimately be "unaligned", it is safe to use FP as the 12820b57cec5SDimitry Andric // base register. 12830b57cec5SDimitry Andric // In fact, in such a scenario the stack is actually not required to be 12840b57cec5SDimitry Andric // aligned, although it may end up being aligned anyway, since this 12850b57cec5SDimitry Andric // particular case is not easily detectable. The alignment will be 12860b57cec5SDimitry Andric // unnecessary, but not incorrect. 12870b57cec5SDimitry Andric // Unfortunately there is no quick way to verify that the above is 12880b57cec5SDimitry Andric // indeed the case (and that it's not a result of an error), so just 12890b57cec5SDimitry Andric // assume that missing AP will be replaced by FP. 12900b57cec5SDimitry Andric // (A better fix would be to rematerialize AP from FP and always align 12910b57cec5SDimitry Andric // vector spills.) 12920b57cec5SDimitry Andric bool UseFP = false, UseAP = false; // Default: use SP (except at -O0). 12930b57cec5SDimitry Andric // Use FP at -O0, except when there are objects with extra alignment. 12940b57cec5SDimitry Andric // That additional alignment requirement may cause a pad to be inserted, 12950b57cec5SDimitry Andric // which will make it impossible to use FP to access objects located 12960b57cec5SDimitry Andric // past the pad. 12970b57cec5SDimitry Andric if (NoOpt && !HasExtraAlign) 12980b57cec5SDimitry Andric UseFP = true; 12990b57cec5SDimitry Andric if (MFI.isFixedObjectIndex(FI) || MFI.isObjectPreAllocated(FI)) { 13000b57cec5SDimitry Andric // Fixed and preallocated objects will be located before any padding 13010b57cec5SDimitry Andric // so FP must be used to access them. 13020b57cec5SDimitry Andric UseFP |= (HasAlloca || HasExtraAlign); 13030b57cec5SDimitry Andric } else { 13040b57cec5SDimitry Andric if (HasAlloca) { 13050b57cec5SDimitry Andric if (HasExtraAlign) 13060b57cec5SDimitry Andric UseAP = true; 13070b57cec5SDimitry Andric else 13080b57cec5SDimitry Andric UseFP = true; 13090b57cec5SDimitry Andric } 13100b57cec5SDimitry Andric } 13110b57cec5SDimitry Andric 13120b57cec5SDimitry Andric // If FP was picked, then there had better be FP. 13130b57cec5SDimitry Andric bool HasFP = hasFP(MF); 13140b57cec5SDimitry Andric assert((HasFP || !UseFP) && "This function must have frame pointer"); 13150b57cec5SDimitry Andric 13160b57cec5SDimitry Andric // Having FP implies allocframe. Allocframe will store extra 8 bytes: 13170b57cec5SDimitry Andric // FP/LR. If the base register is used to access an object across these 13180b57cec5SDimitry Andric // 8 bytes, then the offset will need to be adjusted by 8. 13190b57cec5SDimitry Andric // 13200b57cec5SDimitry Andric // After allocframe: 13210b57cec5SDimitry Andric // HexagonISelLowering adds 8 to ---+ 13220b57cec5SDimitry Andric // the offsets of all stack-based | 13230b57cec5SDimitry Andric // arguments (*) | 13240b57cec5SDimitry Andric // | 13250b57cec5SDimitry Andric // getObjectOffset < 0 0 8 getObjectOffset >= 8 13260b57cec5SDimitry Andric // ------------------------+-----+------------------------> increasing 13270b57cec5SDimitry Andric // <local objects> |FP/LR| <input arguments> addresses 13280b57cec5SDimitry Andric // -----------------+------+-----+------------------------> 13290b57cec5SDimitry Andric // | | 13300b57cec5SDimitry Andric // SP/AP point --+ +-- FP points here (**) 13310b57cec5SDimitry Andric // somewhere on 13320b57cec5SDimitry Andric // this side of FP/LR 13330b57cec5SDimitry Andric // 13340b57cec5SDimitry Andric // (*) See LowerFormalArguments. The FP/LR is assumed to be present. 13350b57cec5SDimitry Andric // (**) *FP == old-FP. FP+0..7 are the bytes of FP/LR. 13360b57cec5SDimitry Andric 13370b57cec5SDimitry Andric // The lowering assumes that FP/LR is present, and so the offsets of 13380b57cec5SDimitry Andric // the formal arguments start at 8. If FP/LR is not there we need to 13390b57cec5SDimitry Andric // reduce the offset by 8. 13400b57cec5SDimitry Andric if (Offset > 0 && !HasFP) 13410b57cec5SDimitry Andric Offset -= 8; 13420b57cec5SDimitry Andric 13430b57cec5SDimitry Andric if (UseFP) 13440b57cec5SDimitry Andric FrameReg = FP; 13450b57cec5SDimitry Andric else if (UseAP) 13460b57cec5SDimitry Andric FrameReg = AP; 13470b57cec5SDimitry Andric else 13480b57cec5SDimitry Andric FrameReg = SP; 13490b57cec5SDimitry Andric 13500b57cec5SDimitry Andric // Calculate the actual offset in the instruction. If there is no FP 13510b57cec5SDimitry Andric // (in other words, no allocframe), then SP will not be adjusted (i.e. 13520b57cec5SDimitry Andric // there will be no SP -= FrameSize), so the frame size should not be 13530b57cec5SDimitry Andric // added to the calculated offset. 13540b57cec5SDimitry Andric int RealOffset = Offset; 13550b57cec5SDimitry Andric if (!UseFP && !UseAP) 13560b57cec5SDimitry Andric RealOffset = FrameSize+Offset; 1357e8d8bef9SDimitry Andric return StackOffset::getFixed(RealOffset); 13580b57cec5SDimitry Andric } 13590b57cec5SDimitry Andric 13600b57cec5SDimitry Andric bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB, 13610b57cec5SDimitry Andric const CSIVect &CSI, const HexagonRegisterInfo &HRI, 13620b57cec5SDimitry Andric bool &PrologueStubs) const { 13630b57cec5SDimitry Andric if (CSI.empty()) 13640b57cec5SDimitry Andric return true; 13650b57cec5SDimitry Andric 13660b57cec5SDimitry Andric MachineBasicBlock::iterator MI = MBB.begin(); 13670b57cec5SDimitry Andric PrologueStubs = false; 13680b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 13690b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 13700b57cec5SDimitry Andric auto &HII = *HST.getInstrInfo(); 13710b57cec5SDimitry Andric 13720b57cec5SDimitry Andric if (useSpillFunction(MF, CSI)) { 13730b57cec5SDimitry Andric PrologueStubs = true; 1374bdd1243dSDimitry Andric Register MaxReg = getMaxCalleeSavedReg(CSI, HRI); 13750b57cec5SDimitry Andric bool StkOvrFlowEnabled = EnableStackOVFSanitizer; 13760b57cec5SDimitry Andric const char *SpillFun = getSpillFunctionFor(MaxReg, SK_ToMem, 13770b57cec5SDimitry Andric StkOvrFlowEnabled); 13780b57cec5SDimitry Andric auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget()); 13790b57cec5SDimitry Andric bool IsPIC = HTM.isPositionIndependent(); 13800b57cec5SDimitry Andric bool LongCalls = HST.useLongCalls() || EnableSaveRestoreLong; 13810b57cec5SDimitry Andric 13820b57cec5SDimitry Andric // Call spill function. 13830b57cec5SDimitry Andric DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc(); 13840b57cec5SDimitry Andric unsigned SpillOpc; 13850b57cec5SDimitry Andric if (StkOvrFlowEnabled) { 13860b57cec5SDimitry Andric if (LongCalls) 13870b57cec5SDimitry Andric SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_EXT_PIC 13880b57cec5SDimitry Andric : Hexagon::SAVE_REGISTERS_CALL_V4STK_EXT; 13890b57cec5SDimitry Andric else 13900b57cec5SDimitry Andric SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_PIC 13910b57cec5SDimitry Andric : Hexagon::SAVE_REGISTERS_CALL_V4STK; 13920b57cec5SDimitry Andric } else { 13930b57cec5SDimitry Andric if (LongCalls) 13940b57cec5SDimitry Andric SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_EXT_PIC 13950b57cec5SDimitry Andric : Hexagon::SAVE_REGISTERS_CALL_V4_EXT; 13960b57cec5SDimitry Andric else 13970b57cec5SDimitry Andric SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_PIC 13980b57cec5SDimitry Andric : Hexagon::SAVE_REGISTERS_CALL_V4; 13990b57cec5SDimitry Andric } 14000b57cec5SDimitry Andric 14010b57cec5SDimitry Andric MachineInstr *SaveRegsCall = 14020b57cec5SDimitry Andric BuildMI(MBB, MI, DL, HII.get(SpillOpc)) 14030b57cec5SDimitry Andric .addExternalSymbol(SpillFun); 14040b57cec5SDimitry Andric 14050b57cec5SDimitry Andric // Add callee-saved registers as use. 14060b57cec5SDimitry Andric addCalleeSaveRegistersAsImpOperand(SaveRegsCall, CSI, false, true); 14070b57cec5SDimitry Andric // Add live in registers. 14084824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) 14094824e7fdSDimitry Andric MBB.addLiveIn(I.getReg()); 14100b57cec5SDimitry Andric return true; 14110b57cec5SDimitry Andric } 14120b57cec5SDimitry Andric 14134824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 141404eeddc0SDimitry Andric Register Reg = I.getReg(); 14150b57cec5SDimitry Andric // Add live in registers. We treat eh_return callee saved register r0 - r3 14160b57cec5SDimitry Andric // specially. They are not really callee saved registers as they are not 14170b57cec5SDimitry Andric // supposed to be killed. 14180b57cec5SDimitry Andric bool IsKill = !HRI.isEHReturnCalleeSaveReg(Reg); 14194824e7fdSDimitry Andric int FI = I.getFrameIdx(); 14200b57cec5SDimitry Andric const TargetRegisterClass *RC = HRI.getMinimalPhysRegClass(Reg); 1421bdd1243dSDimitry Andric HII.storeRegToStackSlot(MBB, MI, Reg, IsKill, FI, RC, &HRI, Register()); 14220b57cec5SDimitry Andric if (IsKill) 14230b57cec5SDimitry Andric MBB.addLiveIn(Reg); 14240b57cec5SDimitry Andric } 14250b57cec5SDimitry Andric return true; 14260b57cec5SDimitry Andric } 14270b57cec5SDimitry Andric 14280b57cec5SDimitry Andric bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB, 14290b57cec5SDimitry Andric const CSIVect &CSI, const HexagonRegisterInfo &HRI) const { 14300b57cec5SDimitry Andric if (CSI.empty()) 14310b57cec5SDimitry Andric return false; 14320b57cec5SDimitry Andric 14330b57cec5SDimitry Andric MachineBasicBlock::iterator MI = MBB.getFirstTerminator(); 14340b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 14350b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 14360b57cec5SDimitry Andric auto &HII = *HST.getInstrInfo(); 14370b57cec5SDimitry Andric 14380b57cec5SDimitry Andric if (useRestoreFunction(MF, CSI)) { 14390b57cec5SDimitry Andric bool HasTC = hasTailCall(MBB) || !hasReturn(MBB); 1440bdd1243dSDimitry Andric Register MaxR = getMaxCalleeSavedReg(CSI, HRI); 14410b57cec5SDimitry Andric SpillKind Kind = HasTC ? SK_FromMemTailcall : SK_FromMem; 14420b57cec5SDimitry Andric const char *RestoreFn = getSpillFunctionFor(MaxR, Kind); 14430b57cec5SDimitry Andric auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget()); 14440b57cec5SDimitry Andric bool IsPIC = HTM.isPositionIndependent(); 14450b57cec5SDimitry Andric bool LongCalls = HST.useLongCalls() || EnableSaveRestoreLong; 14460b57cec5SDimitry Andric 14470b57cec5SDimitry Andric // Call spill function. 14480b57cec5SDimitry Andric DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() 14490b57cec5SDimitry Andric : MBB.findDebugLoc(MBB.end()); 14500b57cec5SDimitry Andric MachineInstr *DeallocCall = nullptr; 14510b57cec5SDimitry Andric 14520b57cec5SDimitry Andric if (HasTC) { 14530b57cec5SDimitry Andric unsigned RetOpc; 14540b57cec5SDimitry Andric if (LongCalls) 14550b57cec5SDimitry Andric RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC 14560b57cec5SDimitry Andric : Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT; 14570b57cec5SDimitry Andric else 14580b57cec5SDimitry Andric RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC 14590b57cec5SDimitry Andric : Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4; 14600b57cec5SDimitry Andric DeallocCall = BuildMI(MBB, MI, DL, HII.get(RetOpc)) 14610b57cec5SDimitry Andric .addExternalSymbol(RestoreFn); 14620b57cec5SDimitry Andric } else { 14630b57cec5SDimitry Andric // The block has a return. 14640b57cec5SDimitry Andric MachineBasicBlock::iterator It = MBB.getFirstTerminator(); 14650b57cec5SDimitry Andric assert(It->isReturn() && std::next(It) == MBB.end()); 14660b57cec5SDimitry Andric unsigned RetOpc; 14670b57cec5SDimitry Andric if (LongCalls) 14680b57cec5SDimitry Andric RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC 14690b57cec5SDimitry Andric : Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT; 14700b57cec5SDimitry Andric else 14710b57cec5SDimitry Andric RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC 14720b57cec5SDimitry Andric : Hexagon::RESTORE_DEALLOC_RET_JMP_V4; 14730b57cec5SDimitry Andric DeallocCall = BuildMI(MBB, It, DL, HII.get(RetOpc)) 14740b57cec5SDimitry Andric .addExternalSymbol(RestoreFn); 14750b57cec5SDimitry Andric // Transfer the function live-out registers. 14760b57cec5SDimitry Andric DeallocCall->copyImplicitOps(MF, *It); 14770b57cec5SDimitry Andric } 14780b57cec5SDimitry Andric addCalleeSaveRegistersAsImpOperand(DeallocCall, CSI, true, false); 14790b57cec5SDimitry Andric return true; 14800b57cec5SDimitry Andric } 14810b57cec5SDimitry Andric 14824824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 148304eeddc0SDimitry Andric Register Reg = I.getReg(); 14840b57cec5SDimitry Andric const TargetRegisterClass *RC = HRI.getMinimalPhysRegClass(Reg); 14854824e7fdSDimitry Andric int FI = I.getFrameIdx(); 1486bdd1243dSDimitry Andric HII.loadRegFromStackSlot(MBB, MI, Reg, FI, RC, &HRI, Register()); 14870b57cec5SDimitry Andric } 14880b57cec5SDimitry Andric 14890b57cec5SDimitry Andric return true; 14900b57cec5SDimitry Andric } 14910b57cec5SDimitry Andric 14920b57cec5SDimitry Andric MachineBasicBlock::iterator HexagonFrameLowering::eliminateCallFramePseudoInstr( 14930b57cec5SDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB, 14940b57cec5SDimitry Andric MachineBasicBlock::iterator I) const { 14950b57cec5SDimitry Andric MachineInstr &MI = *I; 14960b57cec5SDimitry Andric unsigned Opc = MI.getOpcode(); 14970b57cec5SDimitry Andric (void)Opc; // Silence compiler warning. 14980b57cec5SDimitry Andric assert((Opc == Hexagon::ADJCALLSTACKDOWN || Opc == Hexagon::ADJCALLSTACKUP) && 14990b57cec5SDimitry Andric "Cannot handle this call frame pseudo instruction"); 15000b57cec5SDimitry Andric return MBB.erase(I); 15010b57cec5SDimitry Andric } 15020b57cec5SDimitry Andric 15030b57cec5SDimitry Andric void HexagonFrameLowering::processFunctionBeforeFrameFinalized( 15040b57cec5SDimitry Andric MachineFunction &MF, RegScavenger *RS) const { 15050b57cec5SDimitry Andric // If this function has uses aligned stack and also has variable sized stack 15060b57cec5SDimitry Andric // objects, then we need to map all spill slots to fixed positions, so that 15070b57cec5SDimitry Andric // they can be accessed through FP. Otherwise they would have to be accessed 15080b57cec5SDimitry Andric // via AP, which may not be available at the particular place in the program. 15090b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 15100b57cec5SDimitry Andric bool HasAlloca = MFI.hasVarSizedObjects(); 15115ffd83dbSDimitry Andric bool NeedsAlign = (MFI.getMaxAlign() > getStackAlign()); 15120b57cec5SDimitry Andric 15130b57cec5SDimitry Andric if (!HasAlloca || !NeedsAlign) 15140b57cec5SDimitry Andric return; 15150b57cec5SDimitry Andric 15160b57cec5SDimitry Andric // Set the physical aligned-stack base address register. 1517bdd1243dSDimitry Andric Register AP = 0; 15180b57cec5SDimitry Andric if (const MachineInstr *AI = getAlignaInstr(MF)) 15190b57cec5SDimitry Andric AP = AI->getOperand(0).getReg(); 15200b57cec5SDimitry Andric auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>(); 1521bdd1243dSDimitry Andric assert(!AP.isValid() || AP.isPhysical()); 1522bdd1243dSDimitry Andric HMFI.setStackAlignBaseReg(AP); 15230b57cec5SDimitry Andric } 15240b57cec5SDimitry Andric 15250b57cec5SDimitry Andric /// Returns true if there are no caller-saved registers available in class RC. 15260b57cec5SDimitry Andric static bool needToReserveScavengingSpillSlots(MachineFunction &MF, 15270b57cec5SDimitry Andric const HexagonRegisterInfo &HRI, const TargetRegisterClass *RC) { 15280b57cec5SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 15290b57cec5SDimitry Andric 1530bdd1243dSDimitry Andric auto IsUsed = [&HRI,&MRI] (Register Reg) -> bool { 15310b57cec5SDimitry Andric for (MCRegAliasIterator AI(Reg, &HRI, true); AI.isValid(); ++AI) 15320b57cec5SDimitry Andric if (MRI.isPhysRegUsed(*AI)) 15330b57cec5SDimitry Andric return true; 15340b57cec5SDimitry Andric return false; 15350b57cec5SDimitry Andric }; 15360b57cec5SDimitry Andric 15370b57cec5SDimitry Andric // Check for an unused caller-saved register. Callee-saved registers 15380b57cec5SDimitry Andric // have become pristine by now. 15390b57cec5SDimitry Andric for (const MCPhysReg *P = HRI.getCallerSavedRegs(&MF, RC); *P; ++P) 15400b57cec5SDimitry Andric if (!IsUsed(*P)) 15410b57cec5SDimitry Andric return false; 15420b57cec5SDimitry Andric 15430b57cec5SDimitry Andric // All caller-saved registers are used. 15440b57cec5SDimitry Andric return true; 15450b57cec5SDimitry Andric } 15460b57cec5SDimitry Andric 15470b57cec5SDimitry Andric #ifndef NDEBUG 15480b57cec5SDimitry Andric static void dump_registers(BitVector &Regs, const TargetRegisterInfo &TRI) { 15490b57cec5SDimitry Andric dbgs() << '{'; 15500b57cec5SDimitry Andric for (int x = Regs.find_first(); x >= 0; x = Regs.find_next(x)) { 1551bdd1243dSDimitry Andric Register R = x; 15520b57cec5SDimitry Andric dbgs() << ' ' << printReg(R, &TRI); 15530b57cec5SDimitry Andric } 15540b57cec5SDimitry Andric dbgs() << " }"; 15550b57cec5SDimitry Andric } 15560b57cec5SDimitry Andric #endif 15570b57cec5SDimitry Andric 15580b57cec5SDimitry Andric bool HexagonFrameLowering::assignCalleeSavedSpillSlots(MachineFunction &MF, 15590b57cec5SDimitry Andric const TargetRegisterInfo *TRI, std::vector<CalleeSavedInfo> &CSI) const { 15600b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << __func__ << " on " << MF.getName() << '\n'); 15610b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 15620b57cec5SDimitry Andric BitVector SRegs(Hexagon::NUM_TARGET_REGS); 15630b57cec5SDimitry Andric 15640b57cec5SDimitry Andric // Generate a set of unique, callee-saved registers (SRegs), where each 15650b57cec5SDimitry Andric // register in the set is maximal in terms of sub-/super-register relation, 15660b57cec5SDimitry Andric // i.e. for each R in SRegs, no proper super-register of R is also in SRegs. 15670b57cec5SDimitry Andric 15680b57cec5SDimitry Andric // (1) For each callee-saved register, add that register and all of its 15690b57cec5SDimitry Andric // sub-registers to SRegs. 15700b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Initial CS registers: {"); 15714824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 157204eeddc0SDimitry Andric Register R = I.getReg(); 15730b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << ' ' << printReg(R, TRI)); 157406c3fb27SDimitry Andric for (MCPhysReg SR : TRI->subregs_inclusive(R)) 157506c3fb27SDimitry Andric SRegs[SR] = true; 15760b57cec5SDimitry Andric } 15770b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " }\n"); 15780b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "SRegs.1: "; dump_registers(SRegs, *TRI); 15790b57cec5SDimitry Andric dbgs() << "\n"); 15800b57cec5SDimitry Andric 15810b57cec5SDimitry Andric // (2) For each reserved register, remove that register and all of its 15820b57cec5SDimitry Andric // sub- and super-registers from SRegs. 15830b57cec5SDimitry Andric BitVector Reserved = TRI->getReservedRegs(MF); 1584bdd1243dSDimitry Andric // Unreserve the stack align register: it is reserved for this function 1585bdd1243dSDimitry Andric // only, it still needs to be saved/restored. 1586bdd1243dSDimitry Andric Register AP = 1587bdd1243dSDimitry Andric MF.getInfo<HexagonMachineFunctionInfo>()->getStackAlignBaseReg(); 1588bdd1243dSDimitry Andric if (AP.isValid()) { 1589bdd1243dSDimitry Andric Reserved[AP] = false; 1590bdd1243dSDimitry Andric // Unreserve super-regs if no other subregisters are reserved. 159106c3fb27SDimitry Andric for (MCPhysReg SP : TRI->superregs(AP)) { 1592bdd1243dSDimitry Andric bool HasResSub = false; 159306c3fb27SDimitry Andric for (MCPhysReg SB : TRI->subregs(SP)) { 159406c3fb27SDimitry Andric if (!Reserved[SB]) 1595bdd1243dSDimitry Andric continue; 1596bdd1243dSDimitry Andric HasResSub = true; 1597bdd1243dSDimitry Andric break; 1598bdd1243dSDimitry Andric } 1599bdd1243dSDimitry Andric if (!HasResSub) 160006c3fb27SDimitry Andric Reserved[SP] = false; 1601bdd1243dSDimitry Andric } 1602bdd1243dSDimitry Andric } 1603bdd1243dSDimitry Andric 16040b57cec5SDimitry Andric for (int x = Reserved.find_first(); x >= 0; x = Reserved.find_next(x)) { 1605bdd1243dSDimitry Andric Register R = x; 160606c3fb27SDimitry Andric for (MCPhysReg SR : TRI->superregs_inclusive(R)) 160706c3fb27SDimitry Andric SRegs[SR] = false; 16080b57cec5SDimitry Andric } 16090b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Res: "; dump_registers(Reserved, *TRI); 16100b57cec5SDimitry Andric dbgs() << "\n"); 16110b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "SRegs.2: "; dump_registers(SRegs, *TRI); 16120b57cec5SDimitry Andric dbgs() << "\n"); 16130b57cec5SDimitry Andric 16140b57cec5SDimitry Andric // (3) Collect all registers that have at least one sub-register in SRegs, 16150b57cec5SDimitry Andric // and also have no sub-registers that are reserved. These will be the can- 16160b57cec5SDimitry Andric // didates for saving as a whole instead of their individual sub-registers. 16170b57cec5SDimitry Andric // (Saving R17:16 instead of R16 is fine, but only if R17 was not reserved.) 16180b57cec5SDimitry Andric BitVector TmpSup(Hexagon::NUM_TARGET_REGS); 16190b57cec5SDimitry Andric for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) { 1620bdd1243dSDimitry Andric Register R = x; 162106c3fb27SDimitry Andric for (MCPhysReg SR : TRI->superregs(R)) 162206c3fb27SDimitry Andric TmpSup[SR] = true; 16230b57cec5SDimitry Andric } 16240b57cec5SDimitry Andric for (int x = TmpSup.find_first(); x >= 0; x = TmpSup.find_next(x)) { 1625bdd1243dSDimitry Andric Register R = x; 162606c3fb27SDimitry Andric for (MCPhysReg SR : TRI->subregs_inclusive(R)) { 162706c3fb27SDimitry Andric if (!Reserved[SR]) 16280b57cec5SDimitry Andric continue; 16290b57cec5SDimitry Andric TmpSup[R] = false; 16300b57cec5SDimitry Andric break; 16310b57cec5SDimitry Andric } 16320b57cec5SDimitry Andric } 16330b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "TmpSup: "; dump_registers(TmpSup, *TRI); 16340b57cec5SDimitry Andric dbgs() << "\n"); 16350b57cec5SDimitry Andric 16360b57cec5SDimitry Andric // (4) Include all super-registers found in (3) into SRegs. 16370b57cec5SDimitry Andric SRegs |= TmpSup; 16380b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "SRegs.4: "; dump_registers(SRegs, *TRI); 16390b57cec5SDimitry Andric dbgs() << "\n"); 16400b57cec5SDimitry Andric 16410b57cec5SDimitry Andric // (5) For each register R in SRegs, if any super-register of R is in SRegs, 16420b57cec5SDimitry Andric // remove R from SRegs. 16430b57cec5SDimitry Andric for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) { 1644bdd1243dSDimitry Andric Register R = x; 164506c3fb27SDimitry Andric for (MCPhysReg SR : TRI->superregs(R)) { 164606c3fb27SDimitry Andric if (!SRegs[SR]) 16470b57cec5SDimitry Andric continue; 16480b57cec5SDimitry Andric SRegs[R] = false; 16490b57cec5SDimitry Andric break; 16500b57cec5SDimitry Andric } 16510b57cec5SDimitry Andric } 16520b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "SRegs.5: "; dump_registers(SRegs, *TRI); 16530b57cec5SDimitry Andric dbgs() << "\n"); 16540b57cec5SDimitry Andric 16550b57cec5SDimitry Andric // Now, for each register that has a fixed stack slot, create the stack 16560b57cec5SDimitry Andric // object for it. 16570b57cec5SDimitry Andric CSI.clear(); 16580b57cec5SDimitry Andric 16590b57cec5SDimitry Andric using SpillSlot = TargetFrameLowering::SpillSlot; 16600b57cec5SDimitry Andric 16610b57cec5SDimitry Andric unsigned NumFixed; 1662*36b606aeSDimitry Andric int64_t MinOffset = 0; // CS offsets are negative. 16630b57cec5SDimitry Andric const SpillSlot *FixedSlots = getCalleeSavedSpillSlots(NumFixed); 16640b57cec5SDimitry Andric for (const SpillSlot *S = FixedSlots; S != FixedSlots+NumFixed; ++S) { 16650b57cec5SDimitry Andric if (!SRegs[S->Reg]) 16660b57cec5SDimitry Andric continue; 16670b57cec5SDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(S->Reg); 16680b57cec5SDimitry Andric int FI = MFI.CreateFixedSpillStackObject(TRI->getSpillSize(*RC), S->Offset); 16690b57cec5SDimitry Andric MinOffset = std::min(MinOffset, S->Offset); 16700b57cec5SDimitry Andric CSI.push_back(CalleeSavedInfo(S->Reg, FI)); 16710b57cec5SDimitry Andric SRegs[S->Reg] = false; 16720b57cec5SDimitry Andric } 16730b57cec5SDimitry Andric 16740b57cec5SDimitry Andric // There can be some registers that don't have fixed slots. For example, 16750b57cec5SDimitry Andric // we need to store R0-R3 in functions with exception handling. For each 16760b57cec5SDimitry Andric // such register, create a non-fixed stack object. 16770b57cec5SDimitry Andric for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) { 1678bdd1243dSDimitry Andric Register R = x; 16790b57cec5SDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(R); 16800b57cec5SDimitry Andric unsigned Size = TRI->getSpillSize(*RC); 1681*36b606aeSDimitry Andric int64_t Off = MinOffset - Size; 16825ffd83dbSDimitry Andric Align Alignment = std::min(TRI->getSpillAlign(*RC), getStackAlign()); 16835ffd83dbSDimitry Andric Off &= -Alignment.value(); 16840b57cec5SDimitry Andric int FI = MFI.CreateFixedSpillStackObject(Size, Off); 16850b57cec5SDimitry Andric MinOffset = std::min(MinOffset, Off); 16860b57cec5SDimitry Andric CSI.push_back(CalleeSavedInfo(R, FI)); 16870b57cec5SDimitry Andric SRegs[R] = false; 16880b57cec5SDimitry Andric } 16890b57cec5SDimitry Andric 16900b57cec5SDimitry Andric LLVM_DEBUG({ 16910b57cec5SDimitry Andric dbgs() << "CS information: {"; 16924824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 16934824e7fdSDimitry Andric int FI = I.getFrameIdx(); 16940b57cec5SDimitry Andric int Off = MFI.getObjectOffset(FI); 16954824e7fdSDimitry Andric dbgs() << ' ' << printReg(I.getReg(), TRI) << ":fi#" << FI << ":sp"; 16960b57cec5SDimitry Andric if (Off >= 0) 16970b57cec5SDimitry Andric dbgs() << '+'; 16980b57cec5SDimitry Andric dbgs() << Off; 16990b57cec5SDimitry Andric } 17000b57cec5SDimitry Andric dbgs() << " }\n"; 17010b57cec5SDimitry Andric }); 17020b57cec5SDimitry Andric 17030b57cec5SDimitry Andric #ifndef NDEBUG 17040b57cec5SDimitry Andric // Verify that all registers were handled. 17050b57cec5SDimitry Andric bool MissedReg = false; 17060b57cec5SDimitry Andric for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) { 1707bdd1243dSDimitry Andric Register R = x; 17080b57cec5SDimitry Andric dbgs() << printReg(R, TRI) << ' '; 17090b57cec5SDimitry Andric MissedReg = true; 17100b57cec5SDimitry Andric } 17110b57cec5SDimitry Andric if (MissedReg) 17120b57cec5SDimitry Andric llvm_unreachable("...there are unhandled callee-saved registers!"); 17130b57cec5SDimitry Andric #endif 17140b57cec5SDimitry Andric 17150b57cec5SDimitry Andric return true; 17160b57cec5SDimitry Andric } 17170b57cec5SDimitry Andric 17180b57cec5SDimitry Andric bool HexagonFrameLowering::expandCopy(MachineBasicBlock &B, 17190b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 1720bdd1243dSDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const { 17210b57cec5SDimitry Andric MachineInstr *MI = &*It; 17220b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 17238bcb0991SDimitry Andric Register DstR = MI->getOperand(0).getReg(); 17248bcb0991SDimitry Andric Register SrcR = MI->getOperand(1).getReg(); 17250b57cec5SDimitry Andric if (!Hexagon::ModRegsRegClass.contains(DstR) || 17260b57cec5SDimitry Andric !Hexagon::ModRegsRegClass.contains(SrcR)) 17270b57cec5SDimitry Andric return false; 17280b57cec5SDimitry Andric 17298bcb0991SDimitry Andric Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); 17300b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(TargetOpcode::COPY), TmpR).add(MI->getOperand(1)); 17310b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(TargetOpcode::COPY), DstR) 17320b57cec5SDimitry Andric .addReg(TmpR, RegState::Kill); 17330b57cec5SDimitry Andric 17340b57cec5SDimitry Andric NewRegs.push_back(TmpR); 17350b57cec5SDimitry Andric B.erase(It); 17360b57cec5SDimitry Andric return true; 17370b57cec5SDimitry Andric } 17380b57cec5SDimitry Andric 17390b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreInt(MachineBasicBlock &B, 17400b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 1741bdd1243dSDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const { 17420b57cec5SDimitry Andric MachineInstr *MI = &*It; 17430b57cec5SDimitry Andric if (!MI->getOperand(0).isFI()) 17440b57cec5SDimitry Andric return false; 17450b57cec5SDimitry Andric 17460b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 17470b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 17488bcb0991SDimitry Andric Register SrcR = MI->getOperand(2).getReg(); 17490b57cec5SDimitry Andric bool IsKill = MI->getOperand(2).isKill(); 17500b57cec5SDimitry Andric int FI = MI->getOperand(0).getIndex(); 17510b57cec5SDimitry Andric 17520b57cec5SDimitry Andric // TmpR = C2_tfrpr SrcR if SrcR is a predicate register 17530b57cec5SDimitry Andric // TmpR = A2_tfrcrr SrcR if SrcR is a modifier register 17548bcb0991SDimitry Andric Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); 17550b57cec5SDimitry Andric unsigned TfrOpc = (Opc == Hexagon::STriw_pred) ? Hexagon::C2_tfrpr 17560b57cec5SDimitry Andric : Hexagon::A2_tfrcrr; 17570b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(TfrOpc), TmpR) 17580b57cec5SDimitry Andric .addReg(SrcR, getKillRegState(IsKill)); 17590b57cec5SDimitry Andric 17600b57cec5SDimitry Andric // S2_storeri_io FI, 0, TmpR 17610b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(Hexagon::S2_storeri_io)) 17620b57cec5SDimitry Andric .addFrameIndex(FI) 17630b57cec5SDimitry Andric .addImm(0) 17640b57cec5SDimitry Andric .addReg(TmpR, RegState::Kill) 17650b57cec5SDimitry Andric .cloneMemRefs(*MI); 17660b57cec5SDimitry Andric 17670b57cec5SDimitry Andric NewRegs.push_back(TmpR); 17680b57cec5SDimitry Andric B.erase(It); 17690b57cec5SDimitry Andric return true; 17700b57cec5SDimitry Andric } 17710b57cec5SDimitry Andric 17720b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadInt(MachineBasicBlock &B, 17730b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 1774bdd1243dSDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const { 17750b57cec5SDimitry Andric MachineInstr *MI = &*It; 17760b57cec5SDimitry Andric if (!MI->getOperand(1).isFI()) 17770b57cec5SDimitry Andric return false; 17780b57cec5SDimitry Andric 17790b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 17800b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 17818bcb0991SDimitry Andric Register DstR = MI->getOperand(0).getReg(); 17820b57cec5SDimitry Andric int FI = MI->getOperand(1).getIndex(); 17830b57cec5SDimitry Andric 17840b57cec5SDimitry Andric // TmpR = L2_loadri_io FI, 0 17858bcb0991SDimitry Andric Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); 17860b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(Hexagon::L2_loadri_io), TmpR) 17870b57cec5SDimitry Andric .addFrameIndex(FI) 17880b57cec5SDimitry Andric .addImm(0) 17890b57cec5SDimitry Andric .cloneMemRefs(*MI); 17900b57cec5SDimitry Andric 17910b57cec5SDimitry Andric // DstR = C2_tfrrp TmpR if DstR is a predicate register 17920b57cec5SDimitry Andric // DstR = A2_tfrrcr TmpR if DstR is a modifier register 17930b57cec5SDimitry Andric unsigned TfrOpc = (Opc == Hexagon::LDriw_pred) ? Hexagon::C2_tfrrp 17940b57cec5SDimitry Andric : Hexagon::A2_tfrrcr; 17950b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(TfrOpc), DstR) 17960b57cec5SDimitry Andric .addReg(TmpR, RegState::Kill); 17970b57cec5SDimitry Andric 17980b57cec5SDimitry Andric NewRegs.push_back(TmpR); 17990b57cec5SDimitry Andric B.erase(It); 18000b57cec5SDimitry Andric return true; 18010b57cec5SDimitry Andric } 18020b57cec5SDimitry Andric 18030b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVecPred(MachineBasicBlock &B, 18040b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 1805bdd1243dSDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const { 18060b57cec5SDimitry Andric MachineInstr *MI = &*It; 18070b57cec5SDimitry Andric if (!MI->getOperand(0).isFI()) 18080b57cec5SDimitry Andric return false; 18090b57cec5SDimitry Andric 18100b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 18118bcb0991SDimitry Andric Register SrcR = MI->getOperand(2).getReg(); 18120b57cec5SDimitry Andric bool IsKill = MI->getOperand(2).isKill(); 18130b57cec5SDimitry Andric int FI = MI->getOperand(0).getIndex(); 18140b57cec5SDimitry Andric auto *RC = &Hexagon::HvxVRRegClass; 18150b57cec5SDimitry Andric 18160b57cec5SDimitry Andric // Insert transfer to general vector register. 18170b57cec5SDimitry Andric // TmpR0 = A2_tfrsi 0x01010101 18180b57cec5SDimitry Andric // TmpR1 = V6_vandqrt Qx, TmpR0 18190b57cec5SDimitry Andric // store FI, 0, TmpR1 18208bcb0991SDimitry Andric Register TmpR0 = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); 18218bcb0991SDimitry Andric Register TmpR1 = MRI.createVirtualRegister(RC); 18220b57cec5SDimitry Andric 18230b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(Hexagon::A2_tfrsi), TmpR0) 18240b57cec5SDimitry Andric .addImm(0x01010101); 18250b57cec5SDimitry Andric 18260b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(Hexagon::V6_vandqrt), TmpR1) 18270b57cec5SDimitry Andric .addReg(SrcR, getKillRegState(IsKill)) 18280b57cec5SDimitry Andric .addReg(TmpR0, RegState::Kill); 18290b57cec5SDimitry Andric 18300b57cec5SDimitry Andric auto *HRI = B.getParent()->getSubtarget<HexagonSubtarget>().getRegisterInfo(); 1831bdd1243dSDimitry Andric HII.storeRegToStackSlot(B, It, TmpR1, true, FI, RC, HRI, Register()); 18320b57cec5SDimitry Andric expandStoreVec(B, std::prev(It), MRI, HII, NewRegs); 18330b57cec5SDimitry Andric 18340b57cec5SDimitry Andric NewRegs.push_back(TmpR0); 18350b57cec5SDimitry Andric NewRegs.push_back(TmpR1); 18360b57cec5SDimitry Andric B.erase(It); 18370b57cec5SDimitry Andric return true; 18380b57cec5SDimitry Andric } 18390b57cec5SDimitry Andric 18400b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVecPred(MachineBasicBlock &B, 18410b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 1842bdd1243dSDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const { 18430b57cec5SDimitry Andric MachineInstr *MI = &*It; 18440b57cec5SDimitry Andric if (!MI->getOperand(1).isFI()) 18450b57cec5SDimitry Andric return false; 18460b57cec5SDimitry Andric 18470b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 18488bcb0991SDimitry Andric Register DstR = MI->getOperand(0).getReg(); 18490b57cec5SDimitry Andric int FI = MI->getOperand(1).getIndex(); 18500b57cec5SDimitry Andric auto *RC = &Hexagon::HvxVRRegClass; 18510b57cec5SDimitry Andric 18520b57cec5SDimitry Andric // TmpR0 = A2_tfrsi 0x01010101 18530b57cec5SDimitry Andric // TmpR1 = load FI, 0 18540b57cec5SDimitry Andric // DstR = V6_vandvrt TmpR1, TmpR0 18558bcb0991SDimitry Andric Register TmpR0 = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); 18568bcb0991SDimitry Andric Register TmpR1 = MRI.createVirtualRegister(RC); 18570b57cec5SDimitry Andric 18580b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(Hexagon::A2_tfrsi), TmpR0) 18590b57cec5SDimitry Andric .addImm(0x01010101); 18600b57cec5SDimitry Andric MachineFunction &MF = *B.getParent(); 18610b57cec5SDimitry Andric auto *HRI = MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 1862bdd1243dSDimitry Andric HII.loadRegFromStackSlot(B, It, TmpR1, FI, RC, HRI, Register()); 18630b57cec5SDimitry Andric expandLoadVec(B, std::prev(It), MRI, HII, NewRegs); 18640b57cec5SDimitry Andric 18650b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(Hexagon::V6_vandvrt), DstR) 18660b57cec5SDimitry Andric .addReg(TmpR1, RegState::Kill) 18670b57cec5SDimitry Andric .addReg(TmpR0, RegState::Kill); 18680b57cec5SDimitry Andric 18690b57cec5SDimitry Andric NewRegs.push_back(TmpR0); 18700b57cec5SDimitry Andric NewRegs.push_back(TmpR1); 18710b57cec5SDimitry Andric B.erase(It); 18720b57cec5SDimitry Andric return true; 18730b57cec5SDimitry Andric } 18740b57cec5SDimitry Andric 18750b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVec2(MachineBasicBlock &B, 18760b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 1877bdd1243dSDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const { 18780b57cec5SDimitry Andric MachineFunction &MF = *B.getParent(); 18790b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 18800b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 18810b57cec5SDimitry Andric MachineInstr *MI = &*It; 18820b57cec5SDimitry Andric if (!MI->getOperand(0).isFI()) 18830b57cec5SDimitry Andric return false; 18840b57cec5SDimitry Andric 18850b57cec5SDimitry Andric // It is possible that the double vector being stored is only partially 18860b57cec5SDimitry Andric // defined. From the point of view of the liveness tracking, it is ok to 18870b57cec5SDimitry Andric // store it as a whole, but if we break it up we may end up storing a 18880b57cec5SDimitry Andric // register that is entirely undefined. 18890b57cec5SDimitry Andric LivePhysRegs LPR(HRI); 18900b57cec5SDimitry Andric LPR.addLiveIns(B); 18910b57cec5SDimitry Andric SmallVector<std::pair<MCPhysReg, const MachineOperand*>,2> Clobbers; 18920b57cec5SDimitry Andric for (auto R = B.begin(); R != It; ++R) { 18930b57cec5SDimitry Andric Clobbers.clear(); 18940b57cec5SDimitry Andric LPR.stepForward(*R, Clobbers); 18950b57cec5SDimitry Andric } 18960b57cec5SDimitry Andric 18970b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 18988bcb0991SDimitry Andric Register SrcR = MI->getOperand(2).getReg(); 18998bcb0991SDimitry Andric Register SrcLo = HRI.getSubReg(SrcR, Hexagon::vsub_lo); 19008bcb0991SDimitry Andric Register SrcHi = HRI.getSubReg(SrcR, Hexagon::vsub_hi); 19010b57cec5SDimitry Andric bool IsKill = MI->getOperand(2).isKill(); 19020b57cec5SDimitry Andric int FI = MI->getOperand(0).getIndex(); 19030b57cec5SDimitry Andric 19040b57cec5SDimitry Andric unsigned Size = HRI.getSpillSize(Hexagon::HvxVRRegClass); 19055ffd83dbSDimitry Andric Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass); 19065ffd83dbSDimitry Andric Align HasAlign = MFI.getObjectAlign(FI); 19070b57cec5SDimitry Andric unsigned StoreOpc; 19080b57cec5SDimitry Andric 19090b57cec5SDimitry Andric // Store low part. 19100b57cec5SDimitry Andric if (LPR.contains(SrcLo)) { 1911bdd1243dSDimitry Andric StoreOpc = NeedAlign <= HasAlign ? Hexagon::V6_vS32b_ai 19120b57cec5SDimitry Andric : Hexagon::V6_vS32Ub_ai; 19130b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(StoreOpc)) 19140b57cec5SDimitry Andric .addFrameIndex(FI) 19150b57cec5SDimitry Andric .addImm(0) 19160b57cec5SDimitry Andric .addReg(SrcLo, getKillRegState(IsKill)) 19170b57cec5SDimitry Andric .cloneMemRefs(*MI); 19180b57cec5SDimitry Andric } 19190b57cec5SDimitry Andric 19200b57cec5SDimitry Andric // Store high part. 19210b57cec5SDimitry Andric if (LPR.contains(SrcHi)) { 1922bdd1243dSDimitry Andric StoreOpc = NeedAlign <= HasAlign ? Hexagon::V6_vS32b_ai 19230b57cec5SDimitry Andric : Hexagon::V6_vS32Ub_ai; 19240b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(StoreOpc)) 19250b57cec5SDimitry Andric .addFrameIndex(FI) 19260b57cec5SDimitry Andric .addImm(Size) 19270b57cec5SDimitry Andric .addReg(SrcHi, getKillRegState(IsKill)) 19280b57cec5SDimitry Andric .cloneMemRefs(*MI); 19290b57cec5SDimitry Andric } 19300b57cec5SDimitry Andric 19310b57cec5SDimitry Andric B.erase(It); 19320b57cec5SDimitry Andric return true; 19330b57cec5SDimitry Andric } 19340b57cec5SDimitry Andric 19350b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVec2(MachineBasicBlock &B, 19360b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 1937bdd1243dSDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const { 19380b57cec5SDimitry Andric MachineFunction &MF = *B.getParent(); 19390b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 19400b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 19410b57cec5SDimitry Andric MachineInstr *MI = &*It; 19420b57cec5SDimitry Andric if (!MI->getOperand(1).isFI()) 19430b57cec5SDimitry Andric return false; 19440b57cec5SDimitry Andric 19450b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 19468bcb0991SDimitry Andric Register DstR = MI->getOperand(0).getReg(); 19478bcb0991SDimitry Andric Register DstHi = HRI.getSubReg(DstR, Hexagon::vsub_hi); 19488bcb0991SDimitry Andric Register DstLo = HRI.getSubReg(DstR, Hexagon::vsub_lo); 19490b57cec5SDimitry Andric int FI = MI->getOperand(1).getIndex(); 19500b57cec5SDimitry Andric 19510b57cec5SDimitry Andric unsigned Size = HRI.getSpillSize(Hexagon::HvxVRRegClass); 19525ffd83dbSDimitry Andric Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass); 19535ffd83dbSDimitry Andric Align HasAlign = MFI.getObjectAlign(FI); 19540b57cec5SDimitry Andric unsigned LoadOpc; 19550b57cec5SDimitry Andric 19560b57cec5SDimitry Andric // Load low part. 1957bdd1243dSDimitry Andric LoadOpc = NeedAlign <= HasAlign ? Hexagon::V6_vL32b_ai 19580b57cec5SDimitry Andric : Hexagon::V6_vL32Ub_ai; 19590b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(LoadOpc), DstLo) 19600b57cec5SDimitry Andric .addFrameIndex(FI) 19610b57cec5SDimitry Andric .addImm(0) 19620b57cec5SDimitry Andric .cloneMemRefs(*MI); 19630b57cec5SDimitry Andric 19640b57cec5SDimitry Andric // Load high part. 1965bdd1243dSDimitry Andric LoadOpc = NeedAlign <= HasAlign ? Hexagon::V6_vL32b_ai 19660b57cec5SDimitry Andric : Hexagon::V6_vL32Ub_ai; 19670b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(LoadOpc), DstHi) 19680b57cec5SDimitry Andric .addFrameIndex(FI) 19690b57cec5SDimitry Andric .addImm(Size) 19700b57cec5SDimitry Andric .cloneMemRefs(*MI); 19710b57cec5SDimitry Andric 19720b57cec5SDimitry Andric B.erase(It); 19730b57cec5SDimitry Andric return true; 19740b57cec5SDimitry Andric } 19750b57cec5SDimitry Andric 19760b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVec(MachineBasicBlock &B, 19770b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 1978bdd1243dSDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const { 19790b57cec5SDimitry Andric MachineFunction &MF = *B.getParent(); 19800b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 19810b57cec5SDimitry Andric MachineInstr *MI = &*It; 19820b57cec5SDimitry Andric if (!MI->getOperand(0).isFI()) 19830b57cec5SDimitry Andric return false; 19840b57cec5SDimitry Andric 19850b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 19860b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 19878bcb0991SDimitry Andric Register SrcR = MI->getOperand(2).getReg(); 19880b57cec5SDimitry Andric bool IsKill = MI->getOperand(2).isKill(); 19890b57cec5SDimitry Andric int FI = MI->getOperand(0).getIndex(); 19900b57cec5SDimitry Andric 19915ffd83dbSDimitry Andric Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass); 19925ffd83dbSDimitry Andric Align HasAlign = MFI.getObjectAlign(FI); 1993bdd1243dSDimitry Andric unsigned StoreOpc = NeedAlign <= HasAlign ? Hexagon::V6_vS32b_ai 19940b57cec5SDimitry Andric : Hexagon::V6_vS32Ub_ai; 19950b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(StoreOpc)) 19960b57cec5SDimitry Andric .addFrameIndex(FI) 19970b57cec5SDimitry Andric .addImm(0) 19980b57cec5SDimitry Andric .addReg(SrcR, getKillRegState(IsKill)) 19990b57cec5SDimitry Andric .cloneMemRefs(*MI); 20000b57cec5SDimitry Andric 20010b57cec5SDimitry Andric B.erase(It); 20020b57cec5SDimitry Andric return true; 20030b57cec5SDimitry Andric } 20040b57cec5SDimitry Andric 20050b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVec(MachineBasicBlock &B, 20060b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 2007bdd1243dSDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<Register> &NewRegs) const { 20080b57cec5SDimitry Andric MachineFunction &MF = *B.getParent(); 20090b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 20100b57cec5SDimitry Andric MachineInstr *MI = &*It; 20110b57cec5SDimitry Andric if (!MI->getOperand(1).isFI()) 20120b57cec5SDimitry Andric return false; 20130b57cec5SDimitry Andric 20140b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 20150b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 20168bcb0991SDimitry Andric Register DstR = MI->getOperand(0).getReg(); 20170b57cec5SDimitry Andric int FI = MI->getOperand(1).getIndex(); 20180b57cec5SDimitry Andric 20195ffd83dbSDimitry Andric Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass); 20205ffd83dbSDimitry Andric Align HasAlign = MFI.getObjectAlign(FI); 2021bdd1243dSDimitry Andric unsigned LoadOpc = NeedAlign <= HasAlign ? Hexagon::V6_vL32b_ai 20220b57cec5SDimitry Andric : Hexagon::V6_vL32Ub_ai; 20230b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(LoadOpc), DstR) 20240b57cec5SDimitry Andric .addFrameIndex(FI) 20250b57cec5SDimitry Andric .addImm(0) 20260b57cec5SDimitry Andric .cloneMemRefs(*MI); 20270b57cec5SDimitry Andric 20280b57cec5SDimitry Andric B.erase(It); 20290b57cec5SDimitry Andric return true; 20300b57cec5SDimitry Andric } 20310b57cec5SDimitry Andric 20320b57cec5SDimitry Andric bool HexagonFrameLowering::expandSpillMacros(MachineFunction &MF, 2033bdd1243dSDimitry Andric SmallVectorImpl<Register> &NewRegs) const { 20340b57cec5SDimitry Andric auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo(); 20350b57cec5SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 20360b57cec5SDimitry Andric bool Changed = false; 20370b57cec5SDimitry Andric 20380b57cec5SDimitry Andric for (auto &B : MF) { 20390b57cec5SDimitry Andric // Traverse the basic block. 20400b57cec5SDimitry Andric MachineBasicBlock::iterator NextI; 20410b57cec5SDimitry Andric for (auto I = B.begin(), E = B.end(); I != E; I = NextI) { 20420b57cec5SDimitry Andric MachineInstr *MI = &*I; 20430b57cec5SDimitry Andric NextI = std::next(I); 20440b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 20450b57cec5SDimitry Andric 20460b57cec5SDimitry Andric switch (Opc) { 20470b57cec5SDimitry Andric case TargetOpcode::COPY: 20480b57cec5SDimitry Andric Changed |= expandCopy(B, I, MRI, HII, NewRegs); 20490b57cec5SDimitry Andric break; 20500b57cec5SDimitry Andric case Hexagon::STriw_pred: 20510b57cec5SDimitry Andric case Hexagon::STriw_ctr: 20520b57cec5SDimitry Andric Changed |= expandStoreInt(B, I, MRI, HII, NewRegs); 20530b57cec5SDimitry Andric break; 20540b57cec5SDimitry Andric case Hexagon::LDriw_pred: 20550b57cec5SDimitry Andric case Hexagon::LDriw_ctr: 20560b57cec5SDimitry Andric Changed |= expandLoadInt(B, I, MRI, HII, NewRegs); 20570b57cec5SDimitry Andric break; 20580b57cec5SDimitry Andric case Hexagon::PS_vstorerq_ai: 20590b57cec5SDimitry Andric Changed |= expandStoreVecPred(B, I, MRI, HII, NewRegs); 20600b57cec5SDimitry Andric break; 20610b57cec5SDimitry Andric case Hexagon::PS_vloadrq_ai: 20620b57cec5SDimitry Andric Changed |= expandLoadVecPred(B, I, MRI, HII, NewRegs); 20630b57cec5SDimitry Andric break; 20640b57cec5SDimitry Andric case Hexagon::PS_vloadrw_ai: 20650b57cec5SDimitry Andric Changed |= expandLoadVec2(B, I, MRI, HII, NewRegs); 20660b57cec5SDimitry Andric break; 20670b57cec5SDimitry Andric case Hexagon::PS_vstorerw_ai: 20680b57cec5SDimitry Andric Changed |= expandStoreVec2(B, I, MRI, HII, NewRegs); 20690b57cec5SDimitry Andric break; 20700b57cec5SDimitry Andric } 20710b57cec5SDimitry Andric } 20720b57cec5SDimitry Andric } 20730b57cec5SDimitry Andric 20740b57cec5SDimitry Andric return Changed; 20750b57cec5SDimitry Andric } 20760b57cec5SDimitry Andric 20770b57cec5SDimitry Andric void HexagonFrameLowering::determineCalleeSaves(MachineFunction &MF, 20780b57cec5SDimitry Andric BitVector &SavedRegs, 20790b57cec5SDimitry Andric RegScavenger *RS) const { 20800b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 20810b57cec5SDimitry Andric 20820b57cec5SDimitry Andric SavedRegs.resize(HRI.getNumRegs()); 20830b57cec5SDimitry Andric 20840b57cec5SDimitry Andric // If we have a function containing __builtin_eh_return we want to spill and 20850b57cec5SDimitry Andric // restore all callee saved registers. Pretend that they are used. 20860b57cec5SDimitry Andric if (MF.getInfo<HexagonMachineFunctionInfo>()->hasEHReturn()) 20870b57cec5SDimitry Andric for (const MCPhysReg *R = HRI.getCalleeSavedRegs(&MF); *R; ++R) 20880b57cec5SDimitry Andric SavedRegs.set(*R); 20890b57cec5SDimitry Andric 20900b57cec5SDimitry Andric // Replace predicate register pseudo spill code. 2091bdd1243dSDimitry Andric SmallVector<Register,8> NewRegs; 20920b57cec5SDimitry Andric expandSpillMacros(MF, NewRegs); 20930b57cec5SDimitry Andric if (OptimizeSpillSlots && !isOptNone(MF)) 20940b57cec5SDimitry Andric optimizeSpillSlots(MF, NewRegs); 20950b57cec5SDimitry Andric 20960b57cec5SDimitry Andric // We need to reserve a spill slot if scavenging could potentially require 20970b57cec5SDimitry Andric // spilling a scavenged register. 20980b57cec5SDimitry Andric if (!NewRegs.empty() || mayOverflowFrameOffset(MF)) { 20990b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 21000b57cec5SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 21010b57cec5SDimitry Andric SetVector<const TargetRegisterClass*> SpillRCs; 21020b57cec5SDimitry Andric // Reserve an int register in any case, because it could be used to hold 21030b57cec5SDimitry Andric // the stack offset in case it does not fit into a spill instruction. 21040b57cec5SDimitry Andric SpillRCs.insert(&Hexagon::IntRegsRegClass); 21050b57cec5SDimitry Andric 2106bdd1243dSDimitry Andric for (Register VR : NewRegs) 21070b57cec5SDimitry Andric SpillRCs.insert(MRI.getRegClass(VR)); 21080b57cec5SDimitry Andric 2109bdd1243dSDimitry Andric for (const auto *RC : SpillRCs) { 21100b57cec5SDimitry Andric if (!needToReserveScavengingSpillSlots(MF, HRI, RC)) 21110b57cec5SDimitry Andric continue; 2112480093f4SDimitry Andric unsigned Num = 1; 2113480093f4SDimitry Andric switch (RC->getID()) { 2114480093f4SDimitry Andric case Hexagon::IntRegsRegClassID: 2115480093f4SDimitry Andric Num = NumberScavengerSlots; 2116480093f4SDimitry Andric break; 2117480093f4SDimitry Andric case Hexagon::HvxQRRegClassID: 2118480093f4SDimitry Andric Num = 2; // Vector predicate spills also need a vector register. 2119480093f4SDimitry Andric break; 2120480093f4SDimitry Andric } 21215ffd83dbSDimitry Andric unsigned S = HRI.getSpillSize(*RC); 21225ffd83dbSDimitry Andric Align A = HRI.getSpillAlign(*RC); 21230b57cec5SDimitry Andric for (unsigned i = 0; i < Num; i++) { 21240b57cec5SDimitry Andric int NewFI = MFI.CreateSpillStackObject(S, A); 21250b57cec5SDimitry Andric RS->addScavengingFrameIndex(NewFI); 21260b57cec5SDimitry Andric } 21270b57cec5SDimitry Andric } 21280b57cec5SDimitry Andric } 21290b57cec5SDimitry Andric 21300b57cec5SDimitry Andric TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 21310b57cec5SDimitry Andric } 21320b57cec5SDimitry Andric 2133bdd1243dSDimitry Andric Register HexagonFrameLowering::findPhysReg(MachineFunction &MF, 21340b57cec5SDimitry Andric HexagonBlockRanges::IndexRange &FIR, 21350b57cec5SDimitry Andric HexagonBlockRanges::InstrIndexMap &IndexMap, 21360b57cec5SDimitry Andric HexagonBlockRanges::RegToRangeMap &DeadMap, 21370b57cec5SDimitry Andric const TargetRegisterClass *RC) const { 21380b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 21390b57cec5SDimitry Andric auto &MRI = MF.getRegInfo(); 21400b57cec5SDimitry Andric 2141bdd1243dSDimitry Andric auto isDead = [&FIR,&DeadMap] (Register Reg) -> bool { 21420b57cec5SDimitry Andric auto F = DeadMap.find({Reg,0}); 21430b57cec5SDimitry Andric if (F == DeadMap.end()) 21440b57cec5SDimitry Andric return false; 21450b57cec5SDimitry Andric for (auto &DR : F->second) 21460b57cec5SDimitry Andric if (DR.contains(FIR)) 21470b57cec5SDimitry Andric return true; 21480b57cec5SDimitry Andric return false; 21490b57cec5SDimitry Andric }; 21500b57cec5SDimitry Andric 2151bdd1243dSDimitry Andric for (Register Reg : RC->getRawAllocationOrder(MF)) { 21520b57cec5SDimitry Andric bool Dead = true; 21530b57cec5SDimitry Andric for (auto R : HexagonBlockRanges::expandToSubRegs({Reg,0}, MRI, HRI)) { 21540b57cec5SDimitry Andric if (isDead(R.Reg)) 21550b57cec5SDimitry Andric continue; 21560b57cec5SDimitry Andric Dead = false; 21570b57cec5SDimitry Andric break; 21580b57cec5SDimitry Andric } 21590b57cec5SDimitry Andric if (Dead) 21600b57cec5SDimitry Andric return Reg; 21610b57cec5SDimitry Andric } 21620b57cec5SDimitry Andric return 0; 21630b57cec5SDimitry Andric } 21640b57cec5SDimitry Andric 21650b57cec5SDimitry Andric void HexagonFrameLowering::optimizeSpillSlots(MachineFunction &MF, 2166bdd1243dSDimitry Andric SmallVectorImpl<Register> &VRegs) const { 21670b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 21680b57cec5SDimitry Andric auto &HII = *HST.getInstrInfo(); 21690b57cec5SDimitry Andric auto &HRI = *HST.getRegisterInfo(); 21700b57cec5SDimitry Andric auto &MRI = MF.getRegInfo(); 21710b57cec5SDimitry Andric HexagonBlockRanges HBR(MF); 21720b57cec5SDimitry Andric 21730b57cec5SDimitry Andric using BlockIndexMap = 21740b57cec5SDimitry Andric std::map<MachineBasicBlock *, HexagonBlockRanges::InstrIndexMap>; 21750b57cec5SDimitry Andric using BlockRangeMap = 21760b57cec5SDimitry Andric std::map<MachineBasicBlock *, HexagonBlockRanges::RangeList>; 21770b57cec5SDimitry Andric using IndexType = HexagonBlockRanges::IndexType; 21780b57cec5SDimitry Andric 21790b57cec5SDimitry Andric struct SlotInfo { 21800b57cec5SDimitry Andric BlockRangeMap Map; 21810b57cec5SDimitry Andric unsigned Size = 0; 21820b57cec5SDimitry Andric const TargetRegisterClass *RC = nullptr; 21830b57cec5SDimitry Andric 21840b57cec5SDimitry Andric SlotInfo() = default; 21850b57cec5SDimitry Andric }; 21860b57cec5SDimitry Andric 21870b57cec5SDimitry Andric BlockIndexMap BlockIndexes; 21880b57cec5SDimitry Andric SmallSet<int,4> BadFIs; 21890b57cec5SDimitry Andric std::map<int,SlotInfo> FIRangeMap; 21900b57cec5SDimitry Andric 21910b57cec5SDimitry Andric // Accumulate register classes: get a common class for a pre-existing 21920b57cec5SDimitry Andric // class HaveRC and a new class NewRC. Return nullptr if a common class 21930b57cec5SDimitry Andric // cannot be found, otherwise return the resulting class. If HaveRC is 21940b57cec5SDimitry Andric // nullptr, assume that it is still unset. 21950b57cec5SDimitry Andric auto getCommonRC = 21960b57cec5SDimitry Andric [](const TargetRegisterClass *HaveRC, 21970b57cec5SDimitry Andric const TargetRegisterClass *NewRC) -> const TargetRegisterClass * { 21980b57cec5SDimitry Andric if (HaveRC == nullptr || HaveRC == NewRC) 21990b57cec5SDimitry Andric return NewRC; 22000b57cec5SDimitry Andric // Different classes, both non-null. Pick the more general one. 22010b57cec5SDimitry Andric if (HaveRC->hasSubClassEq(NewRC)) 22020b57cec5SDimitry Andric return HaveRC; 22030b57cec5SDimitry Andric if (NewRC->hasSubClassEq(HaveRC)) 22040b57cec5SDimitry Andric return NewRC; 22050b57cec5SDimitry Andric return nullptr; 22060b57cec5SDimitry Andric }; 22070b57cec5SDimitry Andric 22080b57cec5SDimitry Andric // Scan all blocks in the function. Check all occurrences of frame indexes, 22090b57cec5SDimitry Andric // and collect relevant information. 22100b57cec5SDimitry Andric for (auto &B : MF) { 22110b57cec5SDimitry Andric std::map<int,IndexType> LastStore, LastLoad; 22120b57cec5SDimitry Andric // Emplace appears not to be supported in gcc 4.7.2-4. 22130b57cec5SDimitry Andric //auto P = BlockIndexes.emplace(&B, HexagonBlockRanges::InstrIndexMap(B)); 22140b57cec5SDimitry Andric auto P = BlockIndexes.insert( 22150b57cec5SDimitry Andric std::make_pair(&B, HexagonBlockRanges::InstrIndexMap(B))); 22160b57cec5SDimitry Andric auto &IndexMap = P.first->second; 22170b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Index map for " << printMBBReference(B) << "\n" 22180b57cec5SDimitry Andric << IndexMap << '\n'); 22190b57cec5SDimitry Andric 22200b57cec5SDimitry Andric for (auto &In : B) { 22210b57cec5SDimitry Andric int LFI, SFI; 22220b57cec5SDimitry Andric bool Load = HII.isLoadFromStackSlot(In, LFI) && !HII.isPredicated(In); 22230b57cec5SDimitry Andric bool Store = HII.isStoreToStackSlot(In, SFI) && !HII.isPredicated(In); 22240b57cec5SDimitry Andric if (Load && Store) { 22250b57cec5SDimitry Andric // If it's both a load and a store, then we won't handle it. 22260b57cec5SDimitry Andric BadFIs.insert(LFI); 22270b57cec5SDimitry Andric BadFIs.insert(SFI); 22280b57cec5SDimitry Andric continue; 22290b57cec5SDimitry Andric } 22300b57cec5SDimitry Andric // Check for register classes of the register used as the source for 22310b57cec5SDimitry Andric // the store, and the register used as the destination for the load. 22320b57cec5SDimitry Andric // Also, only accept base+imm_offset addressing modes. Other addressing 22330b57cec5SDimitry Andric // modes can have side-effects (post-increments, etc.). For stack 22340b57cec5SDimitry Andric // slots they are very unlikely, so there is not much loss due to 22350b57cec5SDimitry Andric // this restriction. 22360b57cec5SDimitry Andric if (Load || Store) { 22370b57cec5SDimitry Andric int TFI = Load ? LFI : SFI; 22380b57cec5SDimitry Andric unsigned AM = HII.getAddrMode(In); 22390b57cec5SDimitry Andric SlotInfo &SI = FIRangeMap[TFI]; 22400b57cec5SDimitry Andric bool Bad = (AM != HexagonII::BaseImmOffset); 22410b57cec5SDimitry Andric if (!Bad) { 22420b57cec5SDimitry Andric // If the addressing mode is ok, check the register class. 22430b57cec5SDimitry Andric unsigned OpNum = Load ? 0 : 2; 22440b57cec5SDimitry Andric auto *RC = HII.getRegClass(In.getDesc(), OpNum, &HRI, MF); 22450b57cec5SDimitry Andric RC = getCommonRC(SI.RC, RC); 22460b57cec5SDimitry Andric if (RC == nullptr) 22470b57cec5SDimitry Andric Bad = true; 22480b57cec5SDimitry Andric else 22490b57cec5SDimitry Andric SI.RC = RC; 22500b57cec5SDimitry Andric } 22510b57cec5SDimitry Andric if (!Bad) { 22520b57cec5SDimitry Andric // Check sizes. 22530b57cec5SDimitry Andric unsigned S = HII.getMemAccessSize(In); 22540b57cec5SDimitry Andric if (SI.Size != 0 && SI.Size != S) 22550b57cec5SDimitry Andric Bad = true; 22560b57cec5SDimitry Andric else 22570b57cec5SDimitry Andric SI.Size = S; 22580b57cec5SDimitry Andric } 22590b57cec5SDimitry Andric if (!Bad) { 22600b57cec5SDimitry Andric for (auto *Mo : In.memoperands()) { 22610b57cec5SDimitry Andric if (!Mo->isVolatile() && !Mo->isAtomic()) 22620b57cec5SDimitry Andric continue; 22630b57cec5SDimitry Andric Bad = true; 22640b57cec5SDimitry Andric break; 22650b57cec5SDimitry Andric } 22660b57cec5SDimitry Andric } 22670b57cec5SDimitry Andric if (Bad) 22680b57cec5SDimitry Andric BadFIs.insert(TFI); 22690b57cec5SDimitry Andric } 22700b57cec5SDimitry Andric 22710b57cec5SDimitry Andric // Locate uses of frame indices. 22720b57cec5SDimitry Andric for (unsigned i = 0, n = In.getNumOperands(); i < n; ++i) { 22730b57cec5SDimitry Andric const MachineOperand &Op = In.getOperand(i); 22740b57cec5SDimitry Andric if (!Op.isFI()) 22750b57cec5SDimitry Andric continue; 22760b57cec5SDimitry Andric int FI = Op.getIndex(); 22770b57cec5SDimitry Andric // Make sure that the following operand is an immediate and that 22780b57cec5SDimitry Andric // it is 0. This is the offset in the stack object. 22790b57cec5SDimitry Andric if (i+1 >= n || !In.getOperand(i+1).isImm() || 22800b57cec5SDimitry Andric In.getOperand(i+1).getImm() != 0) 22810b57cec5SDimitry Andric BadFIs.insert(FI); 22820b57cec5SDimitry Andric if (BadFIs.count(FI)) 22830b57cec5SDimitry Andric continue; 22840b57cec5SDimitry Andric 22850b57cec5SDimitry Andric IndexType Index = IndexMap.getIndex(&In); 22860b57cec5SDimitry Andric if (Load) { 22870b57cec5SDimitry Andric if (LastStore[FI] == IndexType::None) 22880b57cec5SDimitry Andric LastStore[FI] = IndexType::Entry; 22890b57cec5SDimitry Andric LastLoad[FI] = Index; 22900b57cec5SDimitry Andric } else if (Store) { 22910b57cec5SDimitry Andric HexagonBlockRanges::RangeList &RL = FIRangeMap[FI].Map[&B]; 22920b57cec5SDimitry Andric if (LastStore[FI] != IndexType::None) 22930b57cec5SDimitry Andric RL.add(LastStore[FI], LastLoad[FI], false, false); 22940b57cec5SDimitry Andric else if (LastLoad[FI] != IndexType::None) 22950b57cec5SDimitry Andric RL.add(IndexType::Entry, LastLoad[FI], false, false); 22960b57cec5SDimitry Andric LastLoad[FI] = IndexType::None; 22970b57cec5SDimitry Andric LastStore[FI] = Index; 22980b57cec5SDimitry Andric } else { 22990b57cec5SDimitry Andric BadFIs.insert(FI); 23000b57cec5SDimitry Andric } 23010b57cec5SDimitry Andric } 23020b57cec5SDimitry Andric } 23030b57cec5SDimitry Andric 23040b57cec5SDimitry Andric for (auto &I : LastLoad) { 23050b57cec5SDimitry Andric IndexType LL = I.second; 23060b57cec5SDimitry Andric if (LL == IndexType::None) 23070b57cec5SDimitry Andric continue; 23080b57cec5SDimitry Andric auto &RL = FIRangeMap[I.first].Map[&B]; 23090b57cec5SDimitry Andric IndexType &LS = LastStore[I.first]; 23100b57cec5SDimitry Andric if (LS != IndexType::None) 23110b57cec5SDimitry Andric RL.add(LS, LL, false, false); 23120b57cec5SDimitry Andric else 23130b57cec5SDimitry Andric RL.add(IndexType::Entry, LL, false, false); 23140b57cec5SDimitry Andric LS = IndexType::None; 23150b57cec5SDimitry Andric } 23160b57cec5SDimitry Andric for (auto &I : LastStore) { 23170b57cec5SDimitry Andric IndexType LS = I.second; 23180b57cec5SDimitry Andric if (LS == IndexType::None) 23190b57cec5SDimitry Andric continue; 23200b57cec5SDimitry Andric auto &RL = FIRangeMap[I.first].Map[&B]; 23210b57cec5SDimitry Andric RL.add(LS, IndexType::None, false, false); 23220b57cec5SDimitry Andric } 23230b57cec5SDimitry Andric } 23240b57cec5SDimitry Andric 23250b57cec5SDimitry Andric LLVM_DEBUG({ 23260b57cec5SDimitry Andric for (auto &P : FIRangeMap) { 23270b57cec5SDimitry Andric dbgs() << "fi#" << P.first; 23280b57cec5SDimitry Andric if (BadFIs.count(P.first)) 23290b57cec5SDimitry Andric dbgs() << " (bad)"; 23300b57cec5SDimitry Andric dbgs() << " RC: "; 23310b57cec5SDimitry Andric if (P.second.RC != nullptr) 23320b57cec5SDimitry Andric dbgs() << HRI.getRegClassName(P.second.RC) << '\n'; 23330b57cec5SDimitry Andric else 23340b57cec5SDimitry Andric dbgs() << "<null>\n"; 23350b57cec5SDimitry Andric for (auto &R : P.second.Map) 23360b57cec5SDimitry Andric dbgs() << " " << printMBBReference(*R.first) << " { " << R.second 23370b57cec5SDimitry Andric << "}\n"; 23380b57cec5SDimitry Andric } 23390b57cec5SDimitry Andric }); 23400b57cec5SDimitry Andric 23410b57cec5SDimitry Andric // When a slot is loaded from in a block without being stored to in the 23420b57cec5SDimitry Andric // same block, it is live-on-entry to this block. To avoid CFG analysis, 23430b57cec5SDimitry Andric // consider this slot to be live-on-exit from all blocks. 23440b57cec5SDimitry Andric SmallSet<int,4> LoxFIs; 23450b57cec5SDimitry Andric 23460b57cec5SDimitry Andric std::map<MachineBasicBlock*,std::vector<int>> BlockFIMap; 23470b57cec5SDimitry Andric 23480b57cec5SDimitry Andric for (auto &P : FIRangeMap) { 23490b57cec5SDimitry Andric // P = pair(FI, map: BB->RangeList) 23500b57cec5SDimitry Andric if (BadFIs.count(P.first)) 23510b57cec5SDimitry Andric continue; 23520b57cec5SDimitry Andric for (auto &B : MF) { 23530b57cec5SDimitry Andric auto F = P.second.Map.find(&B); 23540b57cec5SDimitry Andric // F = pair(BB, RangeList) 23550b57cec5SDimitry Andric if (F == P.second.Map.end() || F->second.empty()) 23560b57cec5SDimitry Andric continue; 23570b57cec5SDimitry Andric HexagonBlockRanges::IndexRange &IR = F->second.front(); 23580b57cec5SDimitry Andric if (IR.start() == IndexType::Entry) 23590b57cec5SDimitry Andric LoxFIs.insert(P.first); 23600b57cec5SDimitry Andric BlockFIMap[&B].push_back(P.first); 23610b57cec5SDimitry Andric } 23620b57cec5SDimitry Andric } 23630b57cec5SDimitry Andric 23640b57cec5SDimitry Andric LLVM_DEBUG({ 23650b57cec5SDimitry Andric dbgs() << "Block-to-FI map (* -- live-on-exit):\n"; 23660b57cec5SDimitry Andric for (auto &P : BlockFIMap) { 23670b57cec5SDimitry Andric auto &FIs = P.second; 23680b57cec5SDimitry Andric if (FIs.empty()) 23690b57cec5SDimitry Andric continue; 23700b57cec5SDimitry Andric dbgs() << " " << printMBBReference(*P.first) << ": {"; 23710b57cec5SDimitry Andric for (auto I : FIs) { 23720b57cec5SDimitry Andric dbgs() << " fi#" << I; 23730b57cec5SDimitry Andric if (LoxFIs.count(I)) 23740b57cec5SDimitry Andric dbgs() << '*'; 23750b57cec5SDimitry Andric } 23760b57cec5SDimitry Andric dbgs() << " }\n"; 23770b57cec5SDimitry Andric } 23780b57cec5SDimitry Andric }); 23790b57cec5SDimitry Andric 23800b57cec5SDimitry Andric #ifndef NDEBUG 23810b57cec5SDimitry Andric bool HasOptLimit = SpillOptMax.getPosition(); 23820b57cec5SDimitry Andric #endif 23830b57cec5SDimitry Andric 23840b57cec5SDimitry Andric // eliminate loads, when all loads eliminated, eliminate all stores. 23850b57cec5SDimitry Andric for (auto &B : MF) { 23860b57cec5SDimitry Andric auto F = BlockIndexes.find(&B); 23870b57cec5SDimitry Andric assert(F != BlockIndexes.end()); 23880b57cec5SDimitry Andric HexagonBlockRanges::InstrIndexMap &IM = F->second; 23890b57cec5SDimitry Andric HexagonBlockRanges::RegToRangeMap LM = HBR.computeLiveMap(IM); 23900b57cec5SDimitry Andric HexagonBlockRanges::RegToRangeMap DM = HBR.computeDeadMap(IM, LM); 23910b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << printMBBReference(B) << " dead map\n" 23920b57cec5SDimitry Andric << HexagonBlockRanges::PrintRangeMap(DM, HRI)); 23930b57cec5SDimitry Andric 23940b57cec5SDimitry Andric for (auto FI : BlockFIMap[&B]) { 23950b57cec5SDimitry Andric if (BadFIs.count(FI)) 23960b57cec5SDimitry Andric continue; 23970b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Working on fi#" << FI << '\n'); 23980b57cec5SDimitry Andric HexagonBlockRanges::RangeList &RL = FIRangeMap[FI].Map[&B]; 23990b57cec5SDimitry Andric for (auto &Range : RL) { 24000b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "--Examining range:" << RL << '\n'); 24010b57cec5SDimitry Andric if (!IndexType::isInstr(Range.start()) || 24020b57cec5SDimitry Andric !IndexType::isInstr(Range.end())) 24030b57cec5SDimitry Andric continue; 24040b57cec5SDimitry Andric MachineInstr &SI = *IM.getInstr(Range.start()); 24050b57cec5SDimitry Andric MachineInstr &EI = *IM.getInstr(Range.end()); 24060b57cec5SDimitry Andric assert(SI.mayStore() && "Unexpected start instruction"); 24070b57cec5SDimitry Andric assert(EI.mayLoad() && "Unexpected end instruction"); 24080b57cec5SDimitry Andric MachineOperand &SrcOp = SI.getOperand(2); 24090b57cec5SDimitry Andric 24100b57cec5SDimitry Andric HexagonBlockRanges::RegisterRef SrcRR = { SrcOp.getReg(), 24110b57cec5SDimitry Andric SrcOp.getSubReg() }; 24120b57cec5SDimitry Andric auto *RC = HII.getRegClass(SI.getDesc(), 2, &HRI, MF); 24130b57cec5SDimitry Andric // The this-> is needed to unconfuse MSVC. 2414bdd1243dSDimitry Andric Register FoundR = this->findPhysReg(MF, Range, IM, DM, RC); 24150b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Replacement reg:" << printReg(FoundR, &HRI) 24160b57cec5SDimitry Andric << '\n'); 24170b57cec5SDimitry Andric if (FoundR == 0) 24180b57cec5SDimitry Andric continue; 24190b57cec5SDimitry Andric #ifndef NDEBUG 24200b57cec5SDimitry Andric if (HasOptLimit) { 24210b57cec5SDimitry Andric if (SpillOptCount >= SpillOptMax) 24220b57cec5SDimitry Andric return; 24230b57cec5SDimitry Andric SpillOptCount++; 24240b57cec5SDimitry Andric } 24250b57cec5SDimitry Andric #endif 24260b57cec5SDimitry Andric 24270b57cec5SDimitry Andric // Generate the copy-in: "FoundR = COPY SrcR" at the store location. 24280b57cec5SDimitry Andric MachineBasicBlock::iterator StartIt = SI.getIterator(), NextIt; 24290b57cec5SDimitry Andric MachineInstr *CopyIn = nullptr; 24300b57cec5SDimitry Andric if (SrcRR.Reg != FoundR || SrcRR.Sub != 0) { 24310b57cec5SDimitry Andric const DebugLoc &DL = SI.getDebugLoc(); 24320b57cec5SDimitry Andric CopyIn = BuildMI(B, StartIt, DL, HII.get(TargetOpcode::COPY), FoundR) 24330b57cec5SDimitry Andric .add(SrcOp); 24340b57cec5SDimitry Andric } 24350b57cec5SDimitry Andric 24360b57cec5SDimitry Andric ++StartIt; 24370b57cec5SDimitry Andric // Check if this is a last store and the FI is live-on-exit. 24380b57cec5SDimitry Andric if (LoxFIs.count(FI) && (&Range == &RL.back())) { 24390b57cec5SDimitry Andric // Update store's source register. 24400b57cec5SDimitry Andric if (unsigned SR = SrcOp.getSubReg()) 24410b57cec5SDimitry Andric SrcOp.setReg(HRI.getSubReg(FoundR, SR)); 24420b57cec5SDimitry Andric else 24430b57cec5SDimitry Andric SrcOp.setReg(FoundR); 24440b57cec5SDimitry Andric SrcOp.setSubReg(0); 24450b57cec5SDimitry Andric // We are keeping this register live. 24460b57cec5SDimitry Andric SrcOp.setIsKill(false); 24470b57cec5SDimitry Andric } else { 24480b57cec5SDimitry Andric B.erase(&SI); 24490b57cec5SDimitry Andric IM.replaceInstr(&SI, CopyIn); 24500b57cec5SDimitry Andric } 24510b57cec5SDimitry Andric 24520b57cec5SDimitry Andric auto EndIt = std::next(EI.getIterator()); 24530b57cec5SDimitry Andric for (auto It = StartIt; It != EndIt; It = NextIt) { 24540b57cec5SDimitry Andric MachineInstr &MI = *It; 24550b57cec5SDimitry Andric NextIt = std::next(It); 24560b57cec5SDimitry Andric int TFI; 24570b57cec5SDimitry Andric if (!HII.isLoadFromStackSlot(MI, TFI) || TFI != FI) 24580b57cec5SDimitry Andric continue; 24598bcb0991SDimitry Andric Register DstR = MI.getOperand(0).getReg(); 24600b57cec5SDimitry Andric assert(MI.getOperand(0).getSubReg() == 0); 24610b57cec5SDimitry Andric MachineInstr *CopyOut = nullptr; 24620b57cec5SDimitry Andric if (DstR != FoundR) { 24630b57cec5SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 24640b57cec5SDimitry Andric unsigned MemSize = HII.getMemAccessSize(MI); 24650b57cec5SDimitry Andric assert(HII.getAddrMode(MI) == HexagonII::BaseImmOffset); 24660b57cec5SDimitry Andric unsigned CopyOpc = TargetOpcode::COPY; 24670b57cec5SDimitry Andric if (HII.isSignExtendingLoad(MI)) 24680b57cec5SDimitry Andric CopyOpc = (MemSize == 1) ? Hexagon::A2_sxtb : Hexagon::A2_sxth; 24690b57cec5SDimitry Andric else if (HII.isZeroExtendingLoad(MI)) 24700b57cec5SDimitry Andric CopyOpc = (MemSize == 1) ? Hexagon::A2_zxtb : Hexagon::A2_zxth; 24710b57cec5SDimitry Andric CopyOut = BuildMI(B, It, DL, HII.get(CopyOpc), DstR) 24720b57cec5SDimitry Andric .addReg(FoundR, getKillRegState(&MI == &EI)); 24730b57cec5SDimitry Andric } 24740b57cec5SDimitry Andric IM.replaceInstr(&MI, CopyOut); 24750b57cec5SDimitry Andric B.erase(It); 24760b57cec5SDimitry Andric } 24770b57cec5SDimitry Andric 24780b57cec5SDimitry Andric // Update the dead map. 24790b57cec5SDimitry Andric HexagonBlockRanges::RegisterRef FoundRR = { FoundR, 0 }; 24800b57cec5SDimitry Andric for (auto RR : HexagonBlockRanges::expandToSubRegs(FoundRR, MRI, HRI)) 24810b57cec5SDimitry Andric DM[RR].subtract(Range); 24820b57cec5SDimitry Andric } // for Range in range list 24830b57cec5SDimitry Andric } 24840b57cec5SDimitry Andric } 24850b57cec5SDimitry Andric } 24860b57cec5SDimitry Andric 24870b57cec5SDimitry Andric void HexagonFrameLowering::expandAlloca(MachineInstr *AI, 2488bdd1243dSDimitry Andric const HexagonInstrInfo &HII, Register SP, unsigned CF) const { 24890b57cec5SDimitry Andric MachineBasicBlock &MB = *AI->getParent(); 24900b57cec5SDimitry Andric DebugLoc DL = AI->getDebugLoc(); 24910b57cec5SDimitry Andric unsigned A = AI->getOperand(2).getImm(); 24920b57cec5SDimitry Andric 24930b57cec5SDimitry Andric // Have 24940b57cec5SDimitry Andric // Rd = alloca Rs, #A 24950b57cec5SDimitry Andric // 24960b57cec5SDimitry Andric // If Rs and Rd are different registers, use this sequence: 24970b57cec5SDimitry Andric // Rd = sub(r29, Rs) 24980b57cec5SDimitry Andric // r29 = sub(r29, Rs) 24990b57cec5SDimitry Andric // Rd = and(Rd, #-A) ; if necessary 25000b57cec5SDimitry Andric // r29 = and(r29, #-A) ; if necessary 25010b57cec5SDimitry Andric // Rd = add(Rd, #CF) ; CF size aligned to at most A 25020b57cec5SDimitry Andric // otherwise, do 25030b57cec5SDimitry Andric // Rd = sub(r29, Rs) 25040b57cec5SDimitry Andric // Rd = and(Rd, #-A) ; if necessary 25050b57cec5SDimitry Andric // r29 = Rd 25060b57cec5SDimitry Andric // Rd = add(Rd, #CF) ; CF size aligned to at most A 25070b57cec5SDimitry Andric 25080b57cec5SDimitry Andric MachineOperand &RdOp = AI->getOperand(0); 25090b57cec5SDimitry Andric MachineOperand &RsOp = AI->getOperand(1); 2510bdd1243dSDimitry Andric Register Rd = RdOp.getReg(), Rs = RsOp.getReg(); 25110b57cec5SDimitry Andric 25120b57cec5SDimitry Andric // Rd = sub(r29, Rs) 25130b57cec5SDimitry Andric BuildMI(MB, AI, DL, HII.get(Hexagon::A2_sub), Rd) 25140b57cec5SDimitry Andric .addReg(SP) 25150b57cec5SDimitry Andric .addReg(Rs); 25160b57cec5SDimitry Andric if (Rs != Rd) { 25170b57cec5SDimitry Andric // r29 = sub(r29, Rs) 25180b57cec5SDimitry Andric BuildMI(MB, AI, DL, HII.get(Hexagon::A2_sub), SP) 25190b57cec5SDimitry Andric .addReg(SP) 25200b57cec5SDimitry Andric .addReg(Rs); 25210b57cec5SDimitry Andric } 25220b57cec5SDimitry Andric if (A > 8) { 25230b57cec5SDimitry Andric // Rd = and(Rd, #-A) 25240b57cec5SDimitry Andric BuildMI(MB, AI, DL, HII.get(Hexagon::A2_andir), Rd) 25250b57cec5SDimitry Andric .addReg(Rd) 25260b57cec5SDimitry Andric .addImm(-int64_t(A)); 25270b57cec5SDimitry Andric if (Rs != Rd) 25280b57cec5SDimitry Andric BuildMI(MB, AI, DL, HII.get(Hexagon::A2_andir), SP) 25290b57cec5SDimitry Andric .addReg(SP) 25300b57cec5SDimitry Andric .addImm(-int64_t(A)); 25310b57cec5SDimitry Andric } 25320b57cec5SDimitry Andric if (Rs == Rd) { 25330b57cec5SDimitry Andric // r29 = Rd 25340b57cec5SDimitry Andric BuildMI(MB, AI, DL, HII.get(TargetOpcode::COPY), SP) 25350b57cec5SDimitry Andric .addReg(Rd); 25360b57cec5SDimitry Andric } 25370b57cec5SDimitry Andric if (CF > 0) { 25380b57cec5SDimitry Andric // Rd = add(Rd, #CF) 25390b57cec5SDimitry Andric BuildMI(MB, AI, DL, HII.get(Hexagon::A2_addi), Rd) 25400b57cec5SDimitry Andric .addReg(Rd) 25410b57cec5SDimitry Andric .addImm(CF); 25420b57cec5SDimitry Andric } 25430b57cec5SDimitry Andric } 25440b57cec5SDimitry Andric 25450b57cec5SDimitry Andric bool HexagonFrameLowering::needsAligna(const MachineFunction &MF) const { 25460b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 25470b57cec5SDimitry Andric if (!MFI.hasVarSizedObjects()) 25480b57cec5SDimitry Andric return false; 2549480093f4SDimitry Andric // Do not check for max stack object alignment here, because the stack 2550480093f4SDimitry Andric // may not be complete yet. Assume that we will need PS_aligna if there 2551480093f4SDimitry Andric // are variable-sized objects. 25520b57cec5SDimitry Andric return true; 25530b57cec5SDimitry Andric } 25540b57cec5SDimitry Andric 25550b57cec5SDimitry Andric const MachineInstr *HexagonFrameLowering::getAlignaInstr( 25560b57cec5SDimitry Andric const MachineFunction &MF) const { 25570b57cec5SDimitry Andric for (auto &B : MF) 25580b57cec5SDimitry Andric for (auto &I : B) 25590b57cec5SDimitry Andric if (I.getOpcode() == Hexagon::PS_aligna) 25600b57cec5SDimitry Andric return &I; 25610b57cec5SDimitry Andric return nullptr; 25620b57cec5SDimitry Andric } 25630b57cec5SDimitry Andric 25640b57cec5SDimitry Andric /// Adds all callee-saved registers as implicit uses or defs to the 25650b57cec5SDimitry Andric /// instruction. 25660b57cec5SDimitry Andric void HexagonFrameLowering::addCalleeSaveRegistersAsImpOperand(MachineInstr *MI, 25670b57cec5SDimitry Andric const CSIVect &CSI, bool IsDef, bool IsKill) const { 25680b57cec5SDimitry Andric // Add the callee-saved registers as implicit uses. 25690b57cec5SDimitry Andric for (auto &R : CSI) 25700b57cec5SDimitry Andric MI->addOperand(MachineOperand::CreateReg(R.getReg(), IsDef, true, IsKill)); 25710b57cec5SDimitry Andric } 25720b57cec5SDimitry Andric 25730b57cec5SDimitry Andric /// Determine whether the callee-saved register saves and restores should 25740b57cec5SDimitry Andric /// be generated via inline code. If this function returns "true", inline 25750b57cec5SDimitry Andric /// code will be generated. If this function returns "false", additional 25760b57cec5SDimitry Andric /// checks are performed, which may still lead to the inline code. 25770b57cec5SDimitry Andric bool HexagonFrameLowering::shouldInlineCSR(const MachineFunction &MF, 25780b57cec5SDimitry Andric const CSIVect &CSI) const { 25795ffd83dbSDimitry Andric if (MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl()) 25805ffd83dbSDimitry Andric return true; 25810b57cec5SDimitry Andric if (MF.getInfo<HexagonMachineFunctionInfo>()->hasEHReturn()) 25820b57cec5SDimitry Andric return true; 25830b57cec5SDimitry Andric if (!hasFP(MF)) 25840b57cec5SDimitry Andric return true; 25850b57cec5SDimitry Andric if (!isOptSize(MF) && !isMinSize(MF)) 25865f757f3fSDimitry Andric if (MF.getTarget().getOptLevel() > CodeGenOptLevel::Default) 25870b57cec5SDimitry Andric return true; 25880b57cec5SDimitry Andric 25890b57cec5SDimitry Andric // Check if CSI only has double registers, and if the registers form 25900b57cec5SDimitry Andric // a contiguous block starting from D8. 25910b57cec5SDimitry Andric BitVector Regs(Hexagon::NUM_TARGET_REGS); 25924824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 259304eeddc0SDimitry Andric Register R = I.getReg(); 25940b57cec5SDimitry Andric if (!Hexagon::DoubleRegsRegClass.contains(R)) 25950b57cec5SDimitry Andric return true; 25960b57cec5SDimitry Andric Regs[R] = true; 25970b57cec5SDimitry Andric } 25980b57cec5SDimitry Andric int F = Regs.find_first(); 25990b57cec5SDimitry Andric if (F != Hexagon::D8) 26000b57cec5SDimitry Andric return true; 26010b57cec5SDimitry Andric while (F >= 0) { 26020b57cec5SDimitry Andric int N = Regs.find_next(F); 26030b57cec5SDimitry Andric if (N >= 0 && N != F+1) 26040b57cec5SDimitry Andric return true; 26050b57cec5SDimitry Andric F = N; 26060b57cec5SDimitry Andric } 26070b57cec5SDimitry Andric 26080b57cec5SDimitry Andric return false; 26090b57cec5SDimitry Andric } 26100b57cec5SDimitry Andric 26110b57cec5SDimitry Andric bool HexagonFrameLowering::useSpillFunction(const MachineFunction &MF, 26120b57cec5SDimitry Andric const CSIVect &CSI) const { 26130b57cec5SDimitry Andric if (shouldInlineCSR(MF, CSI)) 26140b57cec5SDimitry Andric return false; 26150b57cec5SDimitry Andric unsigned NumCSI = CSI.size(); 26160b57cec5SDimitry Andric if (NumCSI <= 1) 26170b57cec5SDimitry Andric return false; 26180b57cec5SDimitry Andric 26190b57cec5SDimitry Andric unsigned Threshold = isOptSize(MF) ? SpillFuncThresholdOs 26200b57cec5SDimitry Andric : SpillFuncThreshold; 26210b57cec5SDimitry Andric return Threshold < NumCSI; 26220b57cec5SDimitry Andric } 26230b57cec5SDimitry Andric 26240b57cec5SDimitry Andric bool HexagonFrameLowering::useRestoreFunction(const MachineFunction &MF, 26250b57cec5SDimitry Andric const CSIVect &CSI) const { 26260b57cec5SDimitry Andric if (shouldInlineCSR(MF, CSI)) 26270b57cec5SDimitry Andric return false; 26280b57cec5SDimitry Andric // The restore functions do a bit more than just restoring registers. 26290b57cec5SDimitry Andric // The non-returning versions will go back directly to the caller's 26300b57cec5SDimitry Andric // caller, others will clean up the stack frame in preparation for 26310b57cec5SDimitry Andric // a tail call. Using them can still save code size even if only one 26320b57cec5SDimitry Andric // register is getting restores. Make the decision based on -Oz: 26330b57cec5SDimitry Andric // using -Os will use inline restore for a single register. 26340b57cec5SDimitry Andric if (isMinSize(MF)) 26350b57cec5SDimitry Andric return true; 26360b57cec5SDimitry Andric unsigned NumCSI = CSI.size(); 26370b57cec5SDimitry Andric if (NumCSI <= 1) 26380b57cec5SDimitry Andric return false; 26390b57cec5SDimitry Andric 26400b57cec5SDimitry Andric unsigned Threshold = isOptSize(MF) ? SpillFuncThresholdOs-1 26410b57cec5SDimitry Andric : SpillFuncThreshold; 26420b57cec5SDimitry Andric return Threshold < NumCSI; 26430b57cec5SDimitry Andric } 26440b57cec5SDimitry Andric 26450b57cec5SDimitry Andric bool HexagonFrameLowering::mayOverflowFrameOffset(MachineFunction &MF) const { 26460b57cec5SDimitry Andric unsigned StackSize = MF.getFrameInfo().estimateStackSize(MF); 26470b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 26480b57cec5SDimitry Andric // A fairly simplistic guess as to whether a potential load/store to a 26490b57cec5SDimitry Andric // stack location could require an extra register. 26500b57cec5SDimitry Andric if (HST.useHVXOps() && StackSize > 256) 26510b57cec5SDimitry Andric return true; 26520b57cec5SDimitry Andric 26530b57cec5SDimitry Andric // Check if the function has store-immediate instructions that access 26540b57cec5SDimitry Andric // the stack. Since the offset field is not extendable, if the stack 26550b57cec5SDimitry Andric // size exceeds the offset limit (6 bits, shifted), the stores will 26560b57cec5SDimitry Andric // require a new base register. 26570b57cec5SDimitry Andric bool HasImmStack = false; 26580b57cec5SDimitry Andric unsigned MinLS = ~0u; // Log_2 of the memory access size. 26590b57cec5SDimitry Andric 26600b57cec5SDimitry Andric for (const MachineBasicBlock &B : MF) { 26610b57cec5SDimitry Andric for (const MachineInstr &MI : B) { 26620b57cec5SDimitry Andric unsigned LS = 0; 26630b57cec5SDimitry Andric switch (MI.getOpcode()) { 26640b57cec5SDimitry Andric case Hexagon::S4_storeirit_io: 26650b57cec5SDimitry Andric case Hexagon::S4_storeirif_io: 26660b57cec5SDimitry Andric case Hexagon::S4_storeiri_io: 26670b57cec5SDimitry Andric ++LS; 2668bdd1243dSDimitry Andric [[fallthrough]]; 26690b57cec5SDimitry Andric case Hexagon::S4_storeirht_io: 26700b57cec5SDimitry Andric case Hexagon::S4_storeirhf_io: 26710b57cec5SDimitry Andric case Hexagon::S4_storeirh_io: 26720b57cec5SDimitry Andric ++LS; 2673bdd1243dSDimitry Andric [[fallthrough]]; 26740b57cec5SDimitry Andric case Hexagon::S4_storeirbt_io: 26750b57cec5SDimitry Andric case Hexagon::S4_storeirbf_io: 26760b57cec5SDimitry Andric case Hexagon::S4_storeirb_io: 26770b57cec5SDimitry Andric if (MI.getOperand(0).isFI()) 26780b57cec5SDimitry Andric HasImmStack = true; 26790b57cec5SDimitry Andric MinLS = std::min(MinLS, LS); 26800b57cec5SDimitry Andric break; 26810b57cec5SDimitry Andric } 26820b57cec5SDimitry Andric } 26830b57cec5SDimitry Andric } 26840b57cec5SDimitry Andric 26850b57cec5SDimitry Andric if (HasImmStack) 26860b57cec5SDimitry Andric return !isUInt<6>(StackSize >> MinLS); 26870b57cec5SDimitry Andric 26880b57cec5SDimitry Andric return false; 26890b57cec5SDimitry Andric } 26900fca6ea1SDimitry Andric 26910fca6ea1SDimitry Andric namespace { 26920fca6ea1SDimitry Andric // Struct used by orderFrameObjects to help sort the stack objects. 26930fca6ea1SDimitry Andric struct HexagonFrameSortingObject { 26940fca6ea1SDimitry Andric bool IsValid = false; 26950fca6ea1SDimitry Andric unsigned Index = 0; // Index of Object into MFI list. 26960fca6ea1SDimitry Andric unsigned Size = 0; 26970fca6ea1SDimitry Andric Align ObjectAlignment = Align(1); // Alignment of Object in bytes. 26980fca6ea1SDimitry Andric }; 26990fca6ea1SDimitry Andric 27000fca6ea1SDimitry Andric struct HexagonFrameSortingComparator { 27010fca6ea1SDimitry Andric inline bool operator()(const HexagonFrameSortingObject &A, 27020fca6ea1SDimitry Andric const HexagonFrameSortingObject &B) const { 27030fca6ea1SDimitry Andric return std::make_tuple(!A.IsValid, A.ObjectAlignment, A.Size) < 27040fca6ea1SDimitry Andric std::make_tuple(!B.IsValid, B.ObjectAlignment, B.Size); 27050fca6ea1SDimitry Andric } 27060fca6ea1SDimitry Andric }; 27070fca6ea1SDimitry Andric } // namespace 27080fca6ea1SDimitry Andric 27090fca6ea1SDimitry Andric // Sort objects on the stack by alignment value and then by size to minimize 27100fca6ea1SDimitry Andric // padding. 27110fca6ea1SDimitry Andric void HexagonFrameLowering::orderFrameObjects( 27120fca6ea1SDimitry Andric const MachineFunction &MF, SmallVectorImpl<int> &ObjectsToAllocate) const { 27130fca6ea1SDimitry Andric 27140fca6ea1SDimitry Andric if (ObjectsToAllocate.empty()) 27150fca6ea1SDimitry Andric return; 27160fca6ea1SDimitry Andric 27170fca6ea1SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 27180fca6ea1SDimitry Andric int NObjects = ObjectsToAllocate.size(); 27190fca6ea1SDimitry Andric 27200fca6ea1SDimitry Andric // Create an array of all MFI objects. 27210fca6ea1SDimitry Andric SmallVector<HexagonFrameSortingObject> SortingObjects( 27220fca6ea1SDimitry Andric MFI.getObjectIndexEnd()); 27230fca6ea1SDimitry Andric 27240fca6ea1SDimitry Andric for (int i = 0, j = 0, e = MFI.getObjectIndexEnd(); i < e && j != NObjects; 27250fca6ea1SDimitry Andric ++i) { 27260fca6ea1SDimitry Andric if (i != ObjectsToAllocate[j]) 27270fca6ea1SDimitry Andric continue; 27280fca6ea1SDimitry Andric j++; 27290fca6ea1SDimitry Andric 27300fca6ea1SDimitry Andric // A variable size object has size equal to 0. Since Hexagon sets 27310fca6ea1SDimitry Andric // getUseLocalStackAllocationBlock() to true, a local block is allocated 27320fca6ea1SDimitry Andric // earlier. This case is not handled here for now. 27330fca6ea1SDimitry Andric int Size = MFI.getObjectSize(i); 27340fca6ea1SDimitry Andric if (Size == 0) 27350fca6ea1SDimitry Andric return; 27360fca6ea1SDimitry Andric 27370fca6ea1SDimitry Andric SortingObjects[i].IsValid = true; 27380fca6ea1SDimitry Andric SortingObjects[i].Index = i; 27390fca6ea1SDimitry Andric SortingObjects[i].Size = Size; 27400fca6ea1SDimitry Andric SortingObjects[i].ObjectAlignment = MFI.getObjectAlign(i); 27410fca6ea1SDimitry Andric } 27420fca6ea1SDimitry Andric 27430fca6ea1SDimitry Andric // Sort objects by alignment and then by size. 27440fca6ea1SDimitry Andric llvm::stable_sort(SortingObjects, HexagonFrameSortingComparator()); 27450fca6ea1SDimitry Andric 27460fca6ea1SDimitry Andric // Modify the original list to represent the final order. 27470fca6ea1SDimitry Andric int i = NObjects; 27480fca6ea1SDimitry Andric for (auto &Obj : SortingObjects) { 27490fca6ea1SDimitry Andric if (i == 0) 27500fca6ea1SDimitry Andric break; 27510fca6ea1SDimitry Andric ObjectsToAllocate[--i] = Obj.Index; 27520fca6ea1SDimitry Andric } 27530fca6ea1SDimitry Andric } 2754