10b57cec5SDimitry Andric //===- HexagonFrameLowering.cpp - Define frame lowering -------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric // 80b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 90b57cec5SDimitry Andric 100b57cec5SDimitry Andric #include "HexagonFrameLowering.h" 110b57cec5SDimitry Andric #include "HexagonBlockRanges.h" 120b57cec5SDimitry Andric #include "HexagonInstrInfo.h" 130b57cec5SDimitry Andric #include "HexagonMachineFunctionInfo.h" 140b57cec5SDimitry Andric #include "HexagonRegisterInfo.h" 150b57cec5SDimitry Andric #include "HexagonSubtarget.h" 160b57cec5SDimitry Andric #include "HexagonTargetMachine.h" 170b57cec5SDimitry Andric #include "MCTargetDesc/HexagonBaseInfo.h" 180b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h" 190b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 200b57cec5SDimitry Andric #include "llvm/ADT/None.h" 210b57cec5SDimitry Andric #include "llvm/ADT/Optional.h" 220b57cec5SDimitry Andric #include "llvm/ADT/PostOrderIterator.h" 230b57cec5SDimitry Andric #include "llvm/ADT/SetVector.h" 240b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h" 250b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 260b57cec5SDimitry Andric #include "llvm/CodeGen/LivePhysRegs.h" 270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h" 290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 330b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 340b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h" 350b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 360b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 370b57cec5SDimitry Andric #include "llvm/CodeGen/MachinePostDominators.h" 380b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 39480093f4SDimitry Andric #include "llvm/CodeGen/PseudoSourceValue.h" 400b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h" 410b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 420b57cec5SDimitry Andric #include "llvm/IR/Attributes.h" 430b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h" 440b57cec5SDimitry Andric #include "llvm/IR/Function.h" 450b57cec5SDimitry Andric #include "llvm/MC/MCDwarf.h" 460b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h" 470b57cec5SDimitry Andric #include "llvm/Pass.h" 480b57cec5SDimitry Andric #include "llvm/Support/CodeGen.h" 490b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 500b57cec5SDimitry Andric #include "llvm/Support/Compiler.h" 510b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 520b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 530b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 540b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 550b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h" 560b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h" 570b57cec5SDimitry Andric #include <algorithm> 580b57cec5SDimitry Andric #include <cassert> 590b57cec5SDimitry Andric #include <cstdint> 600b57cec5SDimitry Andric #include <iterator> 610b57cec5SDimitry Andric #include <limits> 620b57cec5SDimitry Andric #include <map> 630b57cec5SDimitry Andric #include <utility> 640b57cec5SDimitry Andric #include <vector> 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric #define DEBUG_TYPE "hexagon-pei" 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric // Hexagon stack frame layout as defined by the ABI: 690b57cec5SDimitry Andric // 700b57cec5SDimitry Andric // Incoming arguments 710b57cec5SDimitry Andric // passed via stack 720b57cec5SDimitry Andric // | 730b57cec5SDimitry Andric // | 740b57cec5SDimitry Andric // SP during function's FP during function's | 750b57cec5SDimitry Andric // +-- runtime (top of stack) runtime (bottom) --+ | 760b57cec5SDimitry Andric // | | | 770b57cec5SDimitry Andric // --++---------------------+------------------+-----------------++-+------- 780b57cec5SDimitry Andric // | parameter area for | variable-size | fixed-size |LR| arg 790b57cec5SDimitry Andric // | called functions | local objects | local objects |FP| 800b57cec5SDimitry Andric // --+----------------------+------------------+-----------------+--+------- 810b57cec5SDimitry Andric // <- size known -> <- size unknown -> <- size known -> 820b57cec5SDimitry Andric // 830b57cec5SDimitry Andric // Low address High address 840b57cec5SDimitry Andric // 850b57cec5SDimitry Andric // <--- stack growth 860b57cec5SDimitry Andric // 870b57cec5SDimitry Andric // 880b57cec5SDimitry Andric // - In any circumstances, the outgoing function arguments are always accessi- 890b57cec5SDimitry Andric // ble using the SP, and the incoming arguments are accessible using the FP. 900b57cec5SDimitry Andric // - If the local objects are not aligned, they can always be accessed using 910b57cec5SDimitry Andric // the FP. 920b57cec5SDimitry Andric // - If there are no variable-sized objects, the local objects can always be 930b57cec5SDimitry Andric // accessed using the SP, regardless whether they are aligned or not. (The 940b57cec5SDimitry Andric // alignment padding will be at the bottom of the stack (highest address), 950b57cec5SDimitry Andric // and so the offset with respect to the SP will be known at the compile- 960b57cec5SDimitry Andric // -time.) 970b57cec5SDimitry Andric // 980b57cec5SDimitry Andric // The only complication occurs if there are both, local aligned objects, and 990b57cec5SDimitry Andric // dynamically allocated (variable-sized) objects. The alignment pad will be 1000b57cec5SDimitry Andric // placed between the FP and the local objects, thus preventing the use of the 1010b57cec5SDimitry Andric // FP to access the local objects. At the same time, the variable-sized objects 1020b57cec5SDimitry Andric // will be between the SP and the local objects, thus introducing an unknown 1030b57cec5SDimitry Andric // distance from the SP to the locals. 1040b57cec5SDimitry Andric // 1050b57cec5SDimitry Andric // To avoid this problem, a new register is created that holds the aligned 1060b57cec5SDimitry Andric // address of the bottom of the stack, referred in the sources as AP (aligned 1070b57cec5SDimitry Andric // pointer). The AP will be equal to "FP-p", where "p" is the smallest pad 1080b57cec5SDimitry Andric // that aligns AP to the required boundary (a maximum of the alignments of 1090b57cec5SDimitry Andric // all stack objects, fixed- and variable-sized). All local objects[1] will 1100b57cec5SDimitry Andric // then use AP as the base pointer. 1110b57cec5SDimitry Andric // [1] The exception is with "fixed" stack objects. "Fixed" stack objects get 1120b57cec5SDimitry Andric // their name from being allocated at fixed locations on the stack, relative 1130b57cec5SDimitry Andric // to the FP. In the presence of dynamic allocation and local alignment, such 1140b57cec5SDimitry Andric // objects can only be accessed through the FP. 1150b57cec5SDimitry Andric // 1160b57cec5SDimitry Andric // Illustration of the AP: 1170b57cec5SDimitry Andric // FP --+ 1180b57cec5SDimitry Andric // | 1190b57cec5SDimitry Andric // ---------------+---------------------+-----+-----------------------++-+-- 1200b57cec5SDimitry Andric // Rest of the | Local stack objects | Pad | Fixed stack objects |LR| 1210b57cec5SDimitry Andric // stack frame | (aligned) | | (CSR, spills, etc.) |FP| 1220b57cec5SDimitry Andric // ---------------+---------------------+-----+-----------------+-----+--+-- 1230b57cec5SDimitry Andric // |<-- Multiple of the -->| 1240b57cec5SDimitry Andric // stack alignment +-- AP 1250b57cec5SDimitry Andric // 1260b57cec5SDimitry Andric // The AP is set up at the beginning of the function. Since it is not a dedi- 1270b57cec5SDimitry Andric // cated (reserved) register, it needs to be kept live throughout the function 1280b57cec5SDimitry Andric // to be available as the base register for local object accesses. 1290b57cec5SDimitry Andric // Normally, an address of a stack objects is obtained by a pseudo-instruction 1300b57cec5SDimitry Andric // PS_fi. To access local objects with the AP register present, a different 1310b57cec5SDimitry Andric // pseudo-instruction needs to be used: PS_fia. The PS_fia takes one extra 1320b57cec5SDimitry Andric // argument compared to PS_fi: the first input register is the AP register. 1330b57cec5SDimitry Andric // This keeps the register live between its definition and its uses. 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric // The AP register is originally set up using pseudo-instruction PS_aligna: 1360b57cec5SDimitry Andric // AP = PS_aligna A 1370b57cec5SDimitry Andric // where 1380b57cec5SDimitry Andric // A - required stack alignment 1390b57cec5SDimitry Andric // The alignment value must be the maximum of all alignments required by 1400b57cec5SDimitry Andric // any stack object. 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric // The dynamic allocation uses a pseudo-instruction PS_alloca: 1430b57cec5SDimitry Andric // Rd = PS_alloca Rs, A 1440b57cec5SDimitry Andric // where 1450b57cec5SDimitry Andric // Rd - address of the allocated space 1460b57cec5SDimitry Andric // Rs - minimum size (the actual allocated can be larger to accommodate 1470b57cec5SDimitry Andric // alignment) 1480b57cec5SDimitry Andric // A - required alignment 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric using namespace llvm; 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric static cl::opt<bool> DisableDeallocRet("disable-hexagon-dealloc-ret", 1530b57cec5SDimitry Andric cl::Hidden, cl::desc("Disable Dealloc Return for Hexagon target")); 1540b57cec5SDimitry Andric 155*81ad6265SDimitry Andric static cl::opt<unsigned> 156*81ad6265SDimitry Andric NumberScavengerSlots("number-scavenger-slots", cl::Hidden, 157*81ad6265SDimitry Andric cl::desc("Set the number of scavenger slots"), 158*81ad6265SDimitry Andric cl::init(2)); 1590b57cec5SDimitry Andric 160*81ad6265SDimitry Andric static cl::opt<int> 161*81ad6265SDimitry Andric SpillFuncThreshold("spill-func-threshold", cl::Hidden, 162*81ad6265SDimitry Andric cl::desc("Specify O2(not Os) spill func threshold"), 163*81ad6265SDimitry Andric cl::init(6)); 1640b57cec5SDimitry Andric 165*81ad6265SDimitry Andric static cl::opt<int> 166*81ad6265SDimitry Andric SpillFuncThresholdOs("spill-func-threshold-Os", cl::Hidden, 167*81ad6265SDimitry Andric cl::desc("Specify Os spill func threshold"), 168*81ad6265SDimitry Andric cl::init(1)); 1690b57cec5SDimitry Andric 170*81ad6265SDimitry Andric static cl::opt<bool> EnableStackOVFSanitizer( 171*81ad6265SDimitry Andric "enable-stackovf-sanitizer", cl::Hidden, 172*81ad6265SDimitry Andric cl::desc("Enable runtime checks for stack overflow."), cl::init(false)); 1730b57cec5SDimitry Andric 174*81ad6265SDimitry Andric static cl::opt<bool> 175*81ad6265SDimitry Andric EnableShrinkWrapping("hexagon-shrink-frame", cl::init(true), cl::Hidden, 1760b57cec5SDimitry Andric cl::desc("Enable stack frame shrink wrapping")); 1770b57cec5SDimitry Andric 178*81ad6265SDimitry Andric static cl::opt<unsigned> 179*81ad6265SDimitry Andric ShrinkLimit("shrink-frame-limit", 180*81ad6265SDimitry Andric cl::init(std::numeric_limits<unsigned>::max()), cl::Hidden, 1810b57cec5SDimitry Andric cl::desc("Max count of stack frame shrink-wraps")); 1820b57cec5SDimitry Andric 183*81ad6265SDimitry Andric static cl::opt<bool> 184*81ad6265SDimitry Andric EnableSaveRestoreLong("enable-save-restore-long", cl::Hidden, 185*81ad6265SDimitry Andric cl::desc("Enable long calls for save-restore stubs."), 186*81ad6265SDimitry Andric cl::init(false)); 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric static cl::opt<bool> EliminateFramePointer("hexagon-fp-elim", cl::init(true), 1890b57cec5SDimitry Andric cl::Hidden, cl::desc("Refrain from using FP whenever possible")); 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric static cl::opt<bool> OptimizeSpillSlots("hexagon-opt-spill", cl::Hidden, 1920b57cec5SDimitry Andric cl::init(true), cl::desc("Optimize spill slots")); 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric #ifndef NDEBUG 1950b57cec5SDimitry Andric static cl::opt<unsigned> SpillOptMax("spill-opt-max", cl::Hidden, 1960b57cec5SDimitry Andric cl::init(std::numeric_limits<unsigned>::max())); 1970b57cec5SDimitry Andric static unsigned SpillOptCount = 0; 1980b57cec5SDimitry Andric #endif 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric namespace llvm { 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric void initializeHexagonCallFrameInformationPass(PassRegistry&); 2030b57cec5SDimitry Andric FunctionPass *createHexagonCallFrameInformation(); 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric } // end namespace llvm 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric namespace { 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric class HexagonCallFrameInformation : public MachineFunctionPass { 2100b57cec5SDimitry Andric public: 2110b57cec5SDimitry Andric static char ID; 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric HexagonCallFrameInformation() : MachineFunctionPass(ID) { 2140b57cec5SDimitry Andric PassRegistry &PR = *PassRegistry::getPassRegistry(); 2150b57cec5SDimitry Andric initializeHexagonCallFrameInformationPass(PR); 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 2210b57cec5SDimitry Andric return MachineFunctionProperties().set( 2220b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric }; 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric char HexagonCallFrameInformation::ID = 0; 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric } // end anonymous namespace 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric bool HexagonCallFrameInformation::runOnMachineFunction(MachineFunction &MF) { 2310b57cec5SDimitry Andric auto &HFI = *MF.getSubtarget<HexagonSubtarget>().getFrameLowering(); 232480093f4SDimitry Andric bool NeedCFI = MF.needsFrameMoves(); 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric if (!NeedCFI) 2350b57cec5SDimitry Andric return false; 2360b57cec5SDimitry Andric HFI.insertCFIInstructions(MF); 2370b57cec5SDimitry Andric return true; 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric INITIALIZE_PASS(HexagonCallFrameInformation, "hexagon-cfi", 2410b57cec5SDimitry Andric "Hexagon call frame information", false, false) 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric FunctionPass *llvm::createHexagonCallFrameInformation() { 2440b57cec5SDimitry Andric return new HexagonCallFrameInformation(); 2450b57cec5SDimitry Andric } 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric /// Map a register pair Reg to the subregister that has the greater "number", 2480b57cec5SDimitry Andric /// i.e. D3 (aka R7:6) will be mapped to R7, etc. 2490b57cec5SDimitry Andric static unsigned getMax32BitSubRegister(unsigned Reg, 2500b57cec5SDimitry Andric const TargetRegisterInfo &TRI, 2510b57cec5SDimitry Andric bool hireg = true) { 2520b57cec5SDimitry Andric if (Reg < Hexagon::D0 || Reg > Hexagon::D15) 2530b57cec5SDimitry Andric return Reg; 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric unsigned RegNo = 0; 2560b57cec5SDimitry Andric for (MCSubRegIterator SubRegs(Reg, &TRI); SubRegs.isValid(); ++SubRegs) { 2570b57cec5SDimitry Andric if (hireg) { 2580b57cec5SDimitry Andric if (*SubRegs > RegNo) 2590b57cec5SDimitry Andric RegNo = *SubRegs; 2600b57cec5SDimitry Andric } else { 2610b57cec5SDimitry Andric if (!RegNo || *SubRegs < RegNo) 2620b57cec5SDimitry Andric RegNo = *SubRegs; 2630b57cec5SDimitry Andric } 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric return RegNo; 2660b57cec5SDimitry Andric } 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric /// Returns the callee saved register with the largest id in the vector. 2695ffd83dbSDimitry Andric static unsigned getMaxCalleeSavedReg(ArrayRef<CalleeSavedInfo> CSI, 2700b57cec5SDimitry Andric const TargetRegisterInfo &TRI) { 2710b57cec5SDimitry Andric static_assert(Hexagon::R1 > 0, 2720b57cec5SDimitry Andric "Assume physical registers are encoded as positive integers"); 2730b57cec5SDimitry Andric if (CSI.empty()) 2740b57cec5SDimitry Andric return 0; 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric unsigned Max = getMax32BitSubRegister(CSI[0].getReg(), TRI); 2770b57cec5SDimitry Andric for (unsigned I = 1, E = CSI.size(); I < E; ++I) { 2780b57cec5SDimitry Andric unsigned Reg = getMax32BitSubRegister(CSI[I].getReg(), TRI); 2790b57cec5SDimitry Andric if (Reg > Max) 2800b57cec5SDimitry Andric Max = Reg; 2810b57cec5SDimitry Andric } 2820b57cec5SDimitry Andric return Max; 2830b57cec5SDimitry Andric } 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric /// Checks if the basic block contains any instruction that needs a stack 2860b57cec5SDimitry Andric /// frame to be already in place. 2870b57cec5SDimitry Andric static bool needsStackFrame(const MachineBasicBlock &MBB, const BitVector &CSR, 2880b57cec5SDimitry Andric const HexagonRegisterInfo &HRI) { 289349cc55cSDimitry Andric for (const MachineInstr &MI : MBB) { 290349cc55cSDimitry Andric if (MI.isCall()) 2910b57cec5SDimitry Andric return true; 292349cc55cSDimitry Andric unsigned Opc = MI.getOpcode(); 2930b57cec5SDimitry Andric switch (Opc) { 2940b57cec5SDimitry Andric case Hexagon::PS_alloca: 2950b57cec5SDimitry Andric case Hexagon::PS_aligna: 2960b57cec5SDimitry Andric return true; 2970b57cec5SDimitry Andric default: 2980b57cec5SDimitry Andric break; 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric // Check individual operands. 301349cc55cSDimitry Andric for (const MachineOperand &MO : MI.operands()) { 3020b57cec5SDimitry Andric // While the presence of a frame index does not prove that a stack 3030b57cec5SDimitry Andric // frame will be required, all frame indexes should be within alloc- 3040b57cec5SDimitry Andric // frame/deallocframe. Otherwise, the code that translates a frame 3050b57cec5SDimitry Andric // index into an offset would have to be aware of the placement of 3060b57cec5SDimitry Andric // the frame creation/destruction instructions. 3070b57cec5SDimitry Andric if (MO.isFI()) 3080b57cec5SDimitry Andric return true; 3090b57cec5SDimitry Andric if (MO.isReg()) { 3108bcb0991SDimitry Andric Register R = MO.getReg(); 3110b57cec5SDimitry Andric // Virtual registers will need scavenging, which then may require 3120b57cec5SDimitry Andric // a stack slot. 313e8d8bef9SDimitry Andric if (R.isVirtual()) 3140b57cec5SDimitry Andric return true; 3150b57cec5SDimitry Andric for (MCSubRegIterator S(R, &HRI, true); S.isValid(); ++S) 3160b57cec5SDimitry Andric if (CSR[*S]) 3170b57cec5SDimitry Andric return true; 3180b57cec5SDimitry Andric continue; 3190b57cec5SDimitry Andric } 3200b57cec5SDimitry Andric if (MO.isRegMask()) { 3210b57cec5SDimitry Andric // A regmask would normally have all callee-saved registers marked 3220b57cec5SDimitry Andric // as preserved, so this check would not be needed, but in case of 3230b57cec5SDimitry Andric // ever having other regmasks (for other calling conventions), 3240b57cec5SDimitry Andric // make sure they would be processed correctly. 3250b57cec5SDimitry Andric const uint32_t *BM = MO.getRegMask(); 3260b57cec5SDimitry Andric for (int x = CSR.find_first(); x >= 0; x = CSR.find_next(x)) { 3270b57cec5SDimitry Andric unsigned R = x; 3280b57cec5SDimitry Andric // If this regmask does not preserve a CSR, a frame will be needed. 3290b57cec5SDimitry Andric if (!(BM[R/32] & (1u << (R%32)))) 3300b57cec5SDimitry Andric return true; 3310b57cec5SDimitry Andric } 3320b57cec5SDimitry Andric } 3330b57cec5SDimitry Andric } 3340b57cec5SDimitry Andric } 3350b57cec5SDimitry Andric return false; 3360b57cec5SDimitry Andric } 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric /// Returns true if MBB has a machine instructions that indicates a tail call 3390b57cec5SDimitry Andric /// in the block. 3400b57cec5SDimitry Andric static bool hasTailCall(const MachineBasicBlock &MBB) { 3410b57cec5SDimitry Andric MachineBasicBlock::const_iterator I = MBB.getLastNonDebugInstr(); 3420b57cec5SDimitry Andric if (I == MBB.end()) 3430b57cec5SDimitry Andric return false; 3440b57cec5SDimitry Andric unsigned RetOpc = I->getOpcode(); 3450b57cec5SDimitry Andric return RetOpc == Hexagon::PS_tailcall_i || RetOpc == Hexagon::PS_tailcall_r; 3460b57cec5SDimitry Andric } 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric /// Returns true if MBB contains an instruction that returns. 3490b57cec5SDimitry Andric static bool hasReturn(const MachineBasicBlock &MBB) { 350349cc55cSDimitry Andric for (const MachineInstr &MI : MBB.terminators()) 351349cc55cSDimitry Andric if (MI.isReturn()) 3520b57cec5SDimitry Andric return true; 3530b57cec5SDimitry Andric return false; 3540b57cec5SDimitry Andric } 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric /// Returns the "return" instruction from this block, or nullptr if there 3570b57cec5SDimitry Andric /// isn't any. 3580b57cec5SDimitry Andric static MachineInstr *getReturn(MachineBasicBlock &MBB) { 3590b57cec5SDimitry Andric for (auto &I : MBB) 3600b57cec5SDimitry Andric if (I.isReturn()) 3610b57cec5SDimitry Andric return &I; 3620b57cec5SDimitry Andric return nullptr; 3630b57cec5SDimitry Andric } 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric static bool isRestoreCall(unsigned Opc) { 3660b57cec5SDimitry Andric switch (Opc) { 3670b57cec5SDimitry Andric case Hexagon::RESTORE_DEALLOC_RET_JMP_V4: 3680b57cec5SDimitry Andric case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC: 3690b57cec5SDimitry Andric case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT: 3700b57cec5SDimitry Andric case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC: 3710b57cec5SDimitry Andric case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT: 3720b57cec5SDimitry Andric case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC: 3730b57cec5SDimitry Andric case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4: 3740b57cec5SDimitry Andric case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC: 3750b57cec5SDimitry Andric return true; 3760b57cec5SDimitry Andric } 3770b57cec5SDimitry Andric return false; 3780b57cec5SDimitry Andric } 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric static inline bool isOptNone(const MachineFunction &MF) { 3810b57cec5SDimitry Andric return MF.getFunction().hasOptNone() || 3820b57cec5SDimitry Andric MF.getTarget().getOptLevel() == CodeGenOpt::None; 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric static inline bool isOptSize(const MachineFunction &MF) { 3860b57cec5SDimitry Andric const Function &F = MF.getFunction(); 3870b57cec5SDimitry Andric return F.hasOptSize() && !F.hasMinSize(); 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric static inline bool isMinSize(const MachineFunction &MF) { 3910b57cec5SDimitry Andric return MF.getFunction().hasMinSize(); 3920b57cec5SDimitry Andric } 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric /// Implements shrink-wrapping of the stack frame. By default, stack frame 3950b57cec5SDimitry Andric /// is created in the function entry block, and is cleaned up in every block 3960b57cec5SDimitry Andric /// that returns. This function finds alternate blocks: one for the frame 3970b57cec5SDimitry Andric /// setup (prolog) and one for the cleanup (epilog). 3980b57cec5SDimitry Andric void HexagonFrameLowering::findShrunkPrologEpilog(MachineFunction &MF, 3990b57cec5SDimitry Andric MachineBasicBlock *&PrologB, MachineBasicBlock *&EpilogB) const { 4000b57cec5SDimitry Andric static unsigned ShrinkCounter = 0; 4010b57cec5SDimitry Andric 4025ffd83dbSDimitry Andric if (MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl() && 4035ffd83dbSDimitry Andric MF.getFunction().isVarArg()) 4045ffd83dbSDimitry Andric return; 4050b57cec5SDimitry Andric if (ShrinkLimit.getPosition()) { 4060b57cec5SDimitry Andric if (ShrinkCounter >= ShrinkLimit) 4070b57cec5SDimitry Andric return; 4080b57cec5SDimitry Andric ShrinkCounter++; 4090b57cec5SDimitry Andric } 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 4120b57cec5SDimitry Andric 4130b57cec5SDimitry Andric MachineDominatorTree MDT; 4140b57cec5SDimitry Andric MDT.runOnMachineFunction(MF); 4150b57cec5SDimitry Andric MachinePostDominatorTree MPT; 4160b57cec5SDimitry Andric MPT.runOnMachineFunction(MF); 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric using UnsignedMap = DenseMap<unsigned, unsigned>; 4190b57cec5SDimitry Andric using RPOTType = ReversePostOrderTraversal<const MachineFunction *>; 4200b57cec5SDimitry Andric 4210b57cec5SDimitry Andric UnsignedMap RPO; 4220b57cec5SDimitry Andric RPOTType RPOT(&MF); 4230b57cec5SDimitry Andric unsigned RPON = 0; 42404eeddc0SDimitry Andric for (auto &I : RPOT) 42504eeddc0SDimitry Andric RPO[I->getNumber()] = RPON++; 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric // Don't process functions that have loops, at least for now. Placement 4280b57cec5SDimitry Andric // of prolog and epilog must take loop structure into account. For simpli- 4290b57cec5SDimitry Andric // city don't do it right now. 4300b57cec5SDimitry Andric for (auto &I : MF) { 4310b57cec5SDimitry Andric unsigned BN = RPO[I.getNumber()]; 432349cc55cSDimitry Andric for (MachineBasicBlock *Succ : I.successors()) 4330b57cec5SDimitry Andric // If found a back-edge, return. 434349cc55cSDimitry Andric if (RPO[Succ->getNumber()] <= BN) 4350b57cec5SDimitry Andric return; 4360b57cec5SDimitry Andric } 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric // Collect the set of blocks that need a stack frame to execute. Scan 4390b57cec5SDimitry Andric // each block for uses/defs of callee-saved registers, calls, etc. 4400b57cec5SDimitry Andric SmallVector<MachineBasicBlock*,16> SFBlocks; 4410b57cec5SDimitry Andric BitVector CSR(Hexagon::NUM_TARGET_REGS); 4420b57cec5SDimitry Andric for (const MCPhysReg *P = HRI.getCalleeSavedRegs(&MF); *P; ++P) 4430b57cec5SDimitry Andric for (MCSubRegIterator S(*P, &HRI, true); S.isValid(); ++S) 4440b57cec5SDimitry Andric CSR[*S] = true; 4450b57cec5SDimitry Andric 4460b57cec5SDimitry Andric for (auto &I : MF) 4470b57cec5SDimitry Andric if (needsStackFrame(I, CSR, HRI)) 4480b57cec5SDimitry Andric SFBlocks.push_back(&I); 4490b57cec5SDimitry Andric 4500b57cec5SDimitry Andric LLVM_DEBUG({ 4510b57cec5SDimitry Andric dbgs() << "Blocks needing SF: {"; 4520b57cec5SDimitry Andric for (auto &B : SFBlocks) 4530b57cec5SDimitry Andric dbgs() << " " << printMBBReference(*B); 4540b57cec5SDimitry Andric dbgs() << " }\n"; 4550b57cec5SDimitry Andric }); 4560b57cec5SDimitry Andric // No frame needed? 4570b57cec5SDimitry Andric if (SFBlocks.empty()) 4580b57cec5SDimitry Andric return; 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric // Pick a common dominator and a common post-dominator. 4610b57cec5SDimitry Andric MachineBasicBlock *DomB = SFBlocks[0]; 4620b57cec5SDimitry Andric for (unsigned i = 1, n = SFBlocks.size(); i < n; ++i) { 4630b57cec5SDimitry Andric DomB = MDT.findNearestCommonDominator(DomB, SFBlocks[i]); 4640b57cec5SDimitry Andric if (!DomB) 4650b57cec5SDimitry Andric break; 4660b57cec5SDimitry Andric } 4670b57cec5SDimitry Andric MachineBasicBlock *PDomB = SFBlocks[0]; 4680b57cec5SDimitry Andric for (unsigned i = 1, n = SFBlocks.size(); i < n; ++i) { 4690b57cec5SDimitry Andric PDomB = MPT.findNearestCommonDominator(PDomB, SFBlocks[i]); 4700b57cec5SDimitry Andric if (!PDomB) 4710b57cec5SDimitry Andric break; 4720b57cec5SDimitry Andric } 4730b57cec5SDimitry Andric LLVM_DEBUG({ 4740b57cec5SDimitry Andric dbgs() << "Computed dom block: "; 4750b57cec5SDimitry Andric if (DomB) 4760b57cec5SDimitry Andric dbgs() << printMBBReference(*DomB); 4770b57cec5SDimitry Andric else 4780b57cec5SDimitry Andric dbgs() << "<null>"; 4790b57cec5SDimitry Andric dbgs() << ", computed pdom block: "; 4800b57cec5SDimitry Andric if (PDomB) 4810b57cec5SDimitry Andric dbgs() << printMBBReference(*PDomB); 4820b57cec5SDimitry Andric else 4830b57cec5SDimitry Andric dbgs() << "<null>"; 4840b57cec5SDimitry Andric dbgs() << "\n"; 4850b57cec5SDimitry Andric }); 4860b57cec5SDimitry Andric if (!DomB || !PDomB) 4870b57cec5SDimitry Andric return; 4880b57cec5SDimitry Andric 4890b57cec5SDimitry Andric // Make sure that DomB dominates PDomB and PDomB post-dominates DomB. 4900b57cec5SDimitry Andric if (!MDT.dominates(DomB, PDomB)) { 4910b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Dom block does not dominate pdom block\n"); 4920b57cec5SDimitry Andric return; 4930b57cec5SDimitry Andric } 4940b57cec5SDimitry Andric if (!MPT.dominates(PDomB, DomB)) { 4950b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "PDom block does not post-dominate dom block\n"); 4960b57cec5SDimitry Andric return; 4970b57cec5SDimitry Andric } 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric // Finally, everything seems right. 5000b57cec5SDimitry Andric PrologB = DomB; 5010b57cec5SDimitry Andric EpilogB = PDomB; 5020b57cec5SDimitry Andric } 5030b57cec5SDimitry Andric 5040b57cec5SDimitry Andric /// Perform most of the PEI work here: 5050b57cec5SDimitry Andric /// - saving/restoring of the callee-saved registers, 5060b57cec5SDimitry Andric /// - stack frame creation and destruction. 5070b57cec5SDimitry Andric /// Normally, this work is distributed among various functions, but doing it 5080b57cec5SDimitry Andric /// in one place allows shrink-wrapping of the stack frame. 5090b57cec5SDimitry Andric void HexagonFrameLowering::emitPrologue(MachineFunction &MF, 5100b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 5110b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 5120b57cec5SDimitry Andric 5130b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 5140b57cec5SDimitry Andric const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 5150b57cec5SDimitry Andric 5160b57cec5SDimitry Andric MachineBasicBlock *PrologB = &MF.front(), *EpilogB = nullptr; 5170b57cec5SDimitry Andric if (EnableShrinkWrapping) 5180b57cec5SDimitry Andric findShrunkPrologEpilog(MF, PrologB, EpilogB); 5190b57cec5SDimitry Andric 5200b57cec5SDimitry Andric bool PrologueStubs = false; 5210b57cec5SDimitry Andric insertCSRSpillsInBlock(*PrologB, CSI, HRI, PrologueStubs); 5220b57cec5SDimitry Andric insertPrologueInBlock(*PrologB, PrologueStubs); 5230b57cec5SDimitry Andric updateEntryPaths(MF, *PrologB); 5240b57cec5SDimitry Andric 5250b57cec5SDimitry Andric if (EpilogB) { 5260b57cec5SDimitry Andric insertCSRRestoresInBlock(*EpilogB, CSI, HRI); 5270b57cec5SDimitry Andric insertEpilogueInBlock(*EpilogB); 5280b57cec5SDimitry Andric } else { 5290b57cec5SDimitry Andric for (auto &B : MF) 5300b57cec5SDimitry Andric if (B.isReturnBlock()) 5310b57cec5SDimitry Andric insertCSRRestoresInBlock(B, CSI, HRI); 5320b57cec5SDimitry Andric 5330b57cec5SDimitry Andric for (auto &B : MF) 5340b57cec5SDimitry Andric if (B.isReturnBlock()) 5350b57cec5SDimitry Andric insertEpilogueInBlock(B); 5360b57cec5SDimitry Andric 5370b57cec5SDimitry Andric for (auto &B : MF) { 5380b57cec5SDimitry Andric if (B.empty()) 5390b57cec5SDimitry Andric continue; 5400b57cec5SDimitry Andric MachineInstr *RetI = getReturn(B); 5410b57cec5SDimitry Andric if (!RetI || isRestoreCall(RetI->getOpcode())) 5420b57cec5SDimitry Andric continue; 5430b57cec5SDimitry Andric for (auto &R : CSI) 5440b57cec5SDimitry Andric RetI->addOperand(MachineOperand::CreateReg(R.getReg(), false, true)); 5450b57cec5SDimitry Andric } 5460b57cec5SDimitry Andric } 5470b57cec5SDimitry Andric 5480b57cec5SDimitry Andric if (EpilogB) { 5490b57cec5SDimitry Andric // If there is an epilog block, it may not have a return instruction. 5500b57cec5SDimitry Andric // In such case, we need to add the callee-saved registers as live-ins 5510b57cec5SDimitry Andric // in all blocks on all paths from the epilog to any return block. 5520b57cec5SDimitry Andric unsigned MaxBN = MF.getNumBlockIDs(); 5530b57cec5SDimitry Andric BitVector DoneT(MaxBN+1), DoneF(MaxBN+1), Path(MaxBN+1); 5540b57cec5SDimitry Andric updateExitPaths(*EpilogB, *EpilogB, DoneT, DoneF, Path); 5550b57cec5SDimitry Andric } 5560b57cec5SDimitry Andric } 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric /// Returns true if the target can safely skip saving callee-saved registers 5590b57cec5SDimitry Andric /// for noreturn nounwind functions. 5600b57cec5SDimitry Andric bool HexagonFrameLowering::enableCalleeSaveSkip( 5610b57cec5SDimitry Andric const MachineFunction &MF) const { 5620b57cec5SDimitry Andric const auto &F = MF.getFunction(); 5630b57cec5SDimitry Andric assert(F.hasFnAttribute(Attribute::NoReturn) && 5640b57cec5SDimitry Andric F.getFunction().hasFnAttribute(Attribute::NoUnwind) && 5650b57cec5SDimitry Andric !F.getFunction().hasFnAttribute(Attribute::UWTable)); 5660b57cec5SDimitry Andric (void)F; 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric // No need to save callee saved registers if the function does not return. 5690b57cec5SDimitry Andric return MF.getSubtarget<HexagonSubtarget>().noreturnStackElim(); 5700b57cec5SDimitry Andric } 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric // Helper function used to determine when to eliminate the stack frame for 5730b57cec5SDimitry Andric // functions marked as noreturn and when the noreturn-stack-elim options are 5740b57cec5SDimitry Andric // specified. When both these conditions are true, then a FP may not be needed 5750b57cec5SDimitry Andric // if the function makes a call. It is very similar to enableCalleeSaveSkip, 5760b57cec5SDimitry Andric // but it used to check if the allocframe can be eliminated as well. 5770b57cec5SDimitry Andric static bool enableAllocFrameElim(const MachineFunction &MF) { 5780b57cec5SDimitry Andric const auto &F = MF.getFunction(); 5790b57cec5SDimitry Andric const auto &MFI = MF.getFrameInfo(); 5800b57cec5SDimitry Andric const auto &HST = MF.getSubtarget<HexagonSubtarget>(); 5810b57cec5SDimitry Andric assert(!MFI.hasVarSizedObjects() && 582fe6060f1SDimitry Andric !HST.getRegisterInfo()->hasStackRealignment(MF)); 5830b57cec5SDimitry Andric return F.hasFnAttribute(Attribute::NoReturn) && 5840b57cec5SDimitry Andric F.hasFnAttribute(Attribute::NoUnwind) && 5850b57cec5SDimitry Andric !F.hasFnAttribute(Attribute::UWTable) && HST.noreturnStackElim() && 5860b57cec5SDimitry Andric MFI.getStackSize() == 0; 5870b57cec5SDimitry Andric } 5880b57cec5SDimitry Andric 5890b57cec5SDimitry Andric void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB, 5900b57cec5SDimitry Andric bool PrologueStubs) const { 5910b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 5920b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 5930b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 5940b57cec5SDimitry Andric auto &HII = *HST.getInstrInfo(); 5950b57cec5SDimitry Andric auto &HRI = *HST.getRegisterInfo(); 5960b57cec5SDimitry Andric 5975ffd83dbSDimitry Andric Align MaxAlign = std::max(MFI.getMaxAlign(), getStackAlign()); 5980b57cec5SDimitry Andric 5990b57cec5SDimitry Andric // Calculate the total stack frame size. 6000b57cec5SDimitry Andric // Get the number of bytes to allocate from the FrameInfo. 6010b57cec5SDimitry Andric unsigned FrameSize = MFI.getStackSize(); 6020b57cec5SDimitry Andric // Round up the max call frame size to the max alignment on the stack. 6030b57cec5SDimitry Andric unsigned MaxCFA = alignTo(MFI.getMaxCallFrameSize(), MaxAlign); 6040b57cec5SDimitry Andric MFI.setMaxCallFrameSize(MaxCFA); 6050b57cec5SDimitry Andric 6060b57cec5SDimitry Andric FrameSize = MaxCFA + alignTo(FrameSize, MaxAlign); 6070b57cec5SDimitry Andric MFI.setStackSize(FrameSize); 6080b57cec5SDimitry Andric 6095ffd83dbSDimitry Andric bool AlignStack = (MaxAlign > getStackAlign()); 6100b57cec5SDimitry Andric 6110b57cec5SDimitry Andric // Get the number of bytes to allocate from the FrameInfo. 6120b57cec5SDimitry Andric unsigned NumBytes = MFI.getStackSize(); 6130b57cec5SDimitry Andric unsigned SP = HRI.getStackRegister(); 6140b57cec5SDimitry Andric unsigned MaxCF = MFI.getMaxCallFrameSize(); 6150b57cec5SDimitry Andric MachineBasicBlock::iterator InsertPt = MBB.begin(); 6160b57cec5SDimitry Andric 6170b57cec5SDimitry Andric SmallVector<MachineInstr *, 4> AdjustRegs; 6180b57cec5SDimitry Andric for (auto &MBB : MF) 6190b57cec5SDimitry Andric for (auto &MI : MBB) 6200b57cec5SDimitry Andric if (MI.getOpcode() == Hexagon::PS_alloca) 6210b57cec5SDimitry Andric AdjustRegs.push_back(&MI); 6220b57cec5SDimitry Andric 6230b57cec5SDimitry Andric for (auto MI : AdjustRegs) { 6240b57cec5SDimitry Andric assert((MI->getOpcode() == Hexagon::PS_alloca) && "Expected alloca"); 6250b57cec5SDimitry Andric expandAlloca(MI, HII, SP, MaxCF); 6260b57cec5SDimitry Andric MI->eraseFromParent(); 6270b57cec5SDimitry Andric } 6280b57cec5SDimitry Andric 6290b57cec5SDimitry Andric DebugLoc dl = MBB.findDebugLoc(InsertPt); 6300b57cec5SDimitry Andric 6315ffd83dbSDimitry Andric if (MF.getFunction().isVarArg() && 6325ffd83dbSDimitry Andric MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl()) { 6335ffd83dbSDimitry Andric // Calculate the size of register saved area. 6345ffd83dbSDimitry Andric int NumVarArgRegs = 6 - FirstVarArgSavedReg; 6355ffd83dbSDimitry Andric int RegisterSavedAreaSizePlusPadding = (NumVarArgRegs % 2 == 0) 6365ffd83dbSDimitry Andric ? NumVarArgRegs * 4 6375ffd83dbSDimitry Andric : NumVarArgRegs * 4 + 4; 6385ffd83dbSDimitry Andric if (RegisterSavedAreaSizePlusPadding > 0) { 6395ffd83dbSDimitry Andric // Decrement the stack pointer by size of register saved area plus 6405ffd83dbSDimitry Andric // padding if any. 6415ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP) 6425ffd83dbSDimitry Andric .addReg(SP) 6435ffd83dbSDimitry Andric .addImm(-RegisterSavedAreaSizePlusPadding) 6445ffd83dbSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 6455ffd83dbSDimitry Andric 6465ffd83dbSDimitry Andric int NumBytes = 0; 6475ffd83dbSDimitry Andric // Copy all the named arguments below register saved area. 6485ffd83dbSDimitry Andric auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>(); 6495ffd83dbSDimitry Andric for (int i = HMFI.getFirstNamedArgFrameIndex(), 6505ffd83dbSDimitry Andric e = HMFI.getLastNamedArgFrameIndex(); i >= e; --i) { 6515ffd83dbSDimitry Andric uint64_t ObjSize = MFI.getObjectSize(i); 6525ffd83dbSDimitry Andric Align ObjAlign = MFI.getObjectAlign(i); 6535ffd83dbSDimitry Andric 6545ffd83dbSDimitry Andric // Determine the kind of load/store that should be used. 6555ffd83dbSDimitry Andric unsigned LDOpc, STOpc; 6565ffd83dbSDimitry Andric uint64_t OpcodeChecker = ObjAlign.value(); 6575ffd83dbSDimitry Andric 6585ffd83dbSDimitry Andric // Handle cases where alignment of an object is > its size. 6595ffd83dbSDimitry Andric if (ObjAlign > ObjSize) { 6605ffd83dbSDimitry Andric if (ObjSize <= 1) 6615ffd83dbSDimitry Andric OpcodeChecker = 1; 6625ffd83dbSDimitry Andric else if (ObjSize <= 2) 6635ffd83dbSDimitry Andric OpcodeChecker = 2; 6645ffd83dbSDimitry Andric else if (ObjSize <= 4) 6655ffd83dbSDimitry Andric OpcodeChecker = 4; 6665ffd83dbSDimitry Andric else if (ObjSize > 4) 6675ffd83dbSDimitry Andric OpcodeChecker = 8; 6685ffd83dbSDimitry Andric } 6695ffd83dbSDimitry Andric 6705ffd83dbSDimitry Andric switch (OpcodeChecker) { 6715ffd83dbSDimitry Andric case 1: 6725ffd83dbSDimitry Andric LDOpc = Hexagon::L2_loadrb_io; 6735ffd83dbSDimitry Andric STOpc = Hexagon::S2_storerb_io; 6745ffd83dbSDimitry Andric break; 6755ffd83dbSDimitry Andric case 2: 6765ffd83dbSDimitry Andric LDOpc = Hexagon::L2_loadrh_io; 6775ffd83dbSDimitry Andric STOpc = Hexagon::S2_storerh_io; 6785ffd83dbSDimitry Andric break; 6795ffd83dbSDimitry Andric case 4: 6805ffd83dbSDimitry Andric LDOpc = Hexagon::L2_loadri_io; 6815ffd83dbSDimitry Andric STOpc = Hexagon::S2_storeri_io; 6825ffd83dbSDimitry Andric break; 6835ffd83dbSDimitry Andric case 8: 6845ffd83dbSDimitry Andric default: 6855ffd83dbSDimitry Andric LDOpc = Hexagon::L2_loadrd_io; 6865ffd83dbSDimitry Andric STOpc = Hexagon::S2_storerd_io; 6875ffd83dbSDimitry Andric break; 6885ffd83dbSDimitry Andric } 6895ffd83dbSDimitry Andric 6905ffd83dbSDimitry Andric unsigned RegUsed = LDOpc == Hexagon::L2_loadrd_io ? Hexagon::D3 6915ffd83dbSDimitry Andric : Hexagon::R6; 6925ffd83dbSDimitry Andric int LoadStoreCount = ObjSize / OpcodeChecker; 6935ffd83dbSDimitry Andric 6945ffd83dbSDimitry Andric if (ObjSize % OpcodeChecker) 6955ffd83dbSDimitry Andric ++LoadStoreCount; 6965ffd83dbSDimitry Andric 6975ffd83dbSDimitry Andric // Get the start location of the load. NumBytes is basically the 6985ffd83dbSDimitry Andric // offset from the stack pointer of previous function, which would be 6995ffd83dbSDimitry Andric // the caller in this case, as this function has variable argument 7005ffd83dbSDimitry Andric // list. 7015ffd83dbSDimitry Andric if (NumBytes != 0) 7025ffd83dbSDimitry Andric NumBytes = alignTo(NumBytes, ObjAlign); 7035ffd83dbSDimitry Andric 7045ffd83dbSDimitry Andric int Count = 0; 7055ffd83dbSDimitry Andric while (Count < LoadStoreCount) { 7065ffd83dbSDimitry Andric // Load the value of the named argument on stack. 7075ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(LDOpc), RegUsed) 7085ffd83dbSDimitry Andric .addReg(SP) 7095ffd83dbSDimitry Andric .addImm(RegisterSavedAreaSizePlusPadding + 7105ffd83dbSDimitry Andric ObjAlign.value() * Count + NumBytes) 7115ffd83dbSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 7125ffd83dbSDimitry Andric 7135ffd83dbSDimitry Andric // Store it below the register saved area plus padding. 7145ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(STOpc)) 7155ffd83dbSDimitry Andric .addReg(SP) 7165ffd83dbSDimitry Andric .addImm(ObjAlign.value() * Count + NumBytes) 7175ffd83dbSDimitry Andric .addReg(RegUsed) 7185ffd83dbSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 7195ffd83dbSDimitry Andric 7205ffd83dbSDimitry Andric Count++; 7215ffd83dbSDimitry Andric } 7225ffd83dbSDimitry Andric NumBytes += MFI.getObjectSize(i); 7235ffd83dbSDimitry Andric } 7245ffd83dbSDimitry Andric 7255ffd83dbSDimitry Andric // Make NumBytes 8 byte aligned 7265ffd83dbSDimitry Andric NumBytes = alignTo(NumBytes, 8); 7275ffd83dbSDimitry Andric 7285ffd83dbSDimitry Andric // If the number of registers having variable arguments is odd, 7295ffd83dbSDimitry Andric // leave 4 bytes of padding to get to the location where first 7305ffd83dbSDimitry Andric // variable argument which was passed through register was copied. 7315ffd83dbSDimitry Andric NumBytes = (NumVarArgRegs % 2 == 0) ? NumBytes : NumBytes + 4; 7325ffd83dbSDimitry Andric 7335ffd83dbSDimitry Andric for (int j = FirstVarArgSavedReg, i = 0; j < 6; ++j, ++i) { 7345ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::S2_storeri_io)) 7355ffd83dbSDimitry Andric .addReg(SP) 7365ffd83dbSDimitry Andric .addImm(NumBytes + 4 * i) 7375ffd83dbSDimitry Andric .addReg(Hexagon::R0 + j) 7385ffd83dbSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 7395ffd83dbSDimitry Andric } 7405ffd83dbSDimitry Andric } 7415ffd83dbSDimitry Andric } 7425ffd83dbSDimitry Andric 7430b57cec5SDimitry Andric if (hasFP(MF)) { 7440b57cec5SDimitry Andric insertAllocframe(MBB, InsertPt, NumBytes); 7450b57cec5SDimitry Andric if (AlignStack) { 7460b57cec5SDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_andir), SP) 7470b57cec5SDimitry Andric .addReg(SP) 7485ffd83dbSDimitry Andric .addImm(-int64_t(MaxAlign.value())); 7490b57cec5SDimitry Andric } 7500b57cec5SDimitry Andric // If the stack-checking is enabled, and we spilled the callee-saved 7510b57cec5SDimitry Andric // registers inline (i.e. did not use a spill function), then call 7520b57cec5SDimitry Andric // the stack checker directly. 7530b57cec5SDimitry Andric if (EnableStackOVFSanitizer && !PrologueStubs) 7540b57cec5SDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::PS_call_stk)) 7550b57cec5SDimitry Andric .addExternalSymbol("__runtime_stack_check"); 7560b57cec5SDimitry Andric } else if (NumBytes > 0) { 7570b57cec5SDimitry Andric assert(alignTo(NumBytes, 8) == NumBytes); 7580b57cec5SDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP) 7590b57cec5SDimitry Andric .addReg(SP) 7600b57cec5SDimitry Andric .addImm(-int(NumBytes)); 7610b57cec5SDimitry Andric } 7620b57cec5SDimitry Andric } 7630b57cec5SDimitry Andric 7640b57cec5SDimitry Andric void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const { 7650b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 7660b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 7670b57cec5SDimitry Andric auto &HII = *HST.getInstrInfo(); 7680b57cec5SDimitry Andric auto &HRI = *HST.getRegisterInfo(); 7690b57cec5SDimitry Andric unsigned SP = HRI.getStackRegister(); 7700b57cec5SDimitry Andric 7710b57cec5SDimitry Andric MachineBasicBlock::iterator InsertPt = MBB.getFirstTerminator(); 7720b57cec5SDimitry Andric DebugLoc dl = MBB.findDebugLoc(InsertPt); 7730b57cec5SDimitry Andric 7740b57cec5SDimitry Andric if (!hasFP(MF)) { 7750b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 7765ffd83dbSDimitry Andric unsigned NumBytes = MFI.getStackSize(); 7775ffd83dbSDimitry Andric if (MF.getFunction().isVarArg() && 7785ffd83dbSDimitry Andric MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl()) { 7795ffd83dbSDimitry Andric // On Hexagon Linux, deallocate the stack for the register saved area. 7805ffd83dbSDimitry Andric int NumVarArgRegs = 6 - FirstVarArgSavedReg; 7815ffd83dbSDimitry Andric int RegisterSavedAreaSizePlusPadding = (NumVarArgRegs % 2 == 0) ? 7825ffd83dbSDimitry Andric (NumVarArgRegs * 4) : (NumVarArgRegs * 4 + 4); 7835ffd83dbSDimitry Andric NumBytes += RegisterSavedAreaSizePlusPadding; 7845ffd83dbSDimitry Andric } 7855ffd83dbSDimitry Andric if (NumBytes) { 7860b57cec5SDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP) 7870b57cec5SDimitry Andric .addReg(SP) 7880b57cec5SDimitry Andric .addImm(NumBytes); 7890b57cec5SDimitry Andric } 7900b57cec5SDimitry Andric return; 7910b57cec5SDimitry Andric } 7920b57cec5SDimitry Andric 7930b57cec5SDimitry Andric MachineInstr *RetI = getReturn(MBB); 7940b57cec5SDimitry Andric unsigned RetOpc = RetI ? RetI->getOpcode() : 0; 7950b57cec5SDimitry Andric 7960b57cec5SDimitry Andric // Handle EH_RETURN. 7970b57cec5SDimitry Andric if (RetOpc == Hexagon::EH_RETURN_JMPR) { 7980b57cec5SDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::L2_deallocframe)) 7990b57cec5SDimitry Andric .addDef(Hexagon::D15) 8000b57cec5SDimitry Andric .addReg(Hexagon::R30); 8010b57cec5SDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_add), SP) 8020b57cec5SDimitry Andric .addReg(SP) 8030b57cec5SDimitry Andric .addReg(Hexagon::R28); 8040b57cec5SDimitry Andric return; 8050b57cec5SDimitry Andric } 8060b57cec5SDimitry Andric 8070b57cec5SDimitry Andric // Check for RESTORE_DEALLOC_RET* tail call. Don't emit an extra dealloc- 8080b57cec5SDimitry Andric // frame instruction if we encounter it. 8090b57cec5SDimitry Andric if (RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4 || 8100b57cec5SDimitry Andric RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC || 8110b57cec5SDimitry Andric RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT || 8120b57cec5SDimitry Andric RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC) { 8130b57cec5SDimitry Andric MachineBasicBlock::iterator It = RetI; 8140b57cec5SDimitry Andric ++It; 8150b57cec5SDimitry Andric // Delete all instructions after the RESTORE (except labels). 8160b57cec5SDimitry Andric while (It != MBB.end()) { 8170b57cec5SDimitry Andric if (!It->isLabel()) 8180b57cec5SDimitry Andric It = MBB.erase(It); 8190b57cec5SDimitry Andric else 8200b57cec5SDimitry Andric ++It; 8210b57cec5SDimitry Andric } 8220b57cec5SDimitry Andric return; 8230b57cec5SDimitry Andric } 8240b57cec5SDimitry Andric 8250b57cec5SDimitry Andric // It is possible that the restoring code is a call to a library function. 8260b57cec5SDimitry Andric // All of the restore* functions include "deallocframe", so we need to make 8270b57cec5SDimitry Andric // sure that we don't add an extra one. 8280b57cec5SDimitry Andric bool NeedsDeallocframe = true; 8290b57cec5SDimitry Andric if (!MBB.empty() && InsertPt != MBB.begin()) { 8300b57cec5SDimitry Andric MachineBasicBlock::iterator PrevIt = std::prev(InsertPt); 8310b57cec5SDimitry Andric unsigned COpc = PrevIt->getOpcode(); 8320b57cec5SDimitry Andric if (COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4 || 8330b57cec5SDimitry Andric COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC || 8340b57cec5SDimitry Andric COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT || 8350b57cec5SDimitry Andric COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC || 8360b57cec5SDimitry Andric COpc == Hexagon::PS_call_nr || COpc == Hexagon::PS_callr_nr) 8370b57cec5SDimitry Andric NeedsDeallocframe = false; 8380b57cec5SDimitry Andric } 8390b57cec5SDimitry Andric 8405ffd83dbSDimitry Andric if (!MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl() || 8415ffd83dbSDimitry Andric !MF.getFunction().isVarArg()) { 8420b57cec5SDimitry Andric if (!NeedsDeallocframe) 8430b57cec5SDimitry Andric return; 8445ffd83dbSDimitry Andric // If the returning instruction is PS_jmpret, replace it with 8455ffd83dbSDimitry Andric // dealloc_return, otherwise just add deallocframe. The function 8465ffd83dbSDimitry Andric // could be returning via a tail call. 8470b57cec5SDimitry Andric if (RetOpc != Hexagon::PS_jmpret || DisableDeallocRet) { 8480b57cec5SDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::L2_deallocframe)) 8490b57cec5SDimitry Andric .addDef(Hexagon::D15) 8500b57cec5SDimitry Andric .addReg(Hexagon::R30); 8510b57cec5SDimitry Andric return; 8520b57cec5SDimitry Andric } 8530b57cec5SDimitry Andric unsigned NewOpc = Hexagon::L4_return; 8540b57cec5SDimitry Andric MachineInstr *NewI = BuildMI(MBB, RetI, dl, HII.get(NewOpc)) 8550b57cec5SDimitry Andric .addDef(Hexagon::D15) 8560b57cec5SDimitry Andric .addReg(Hexagon::R30); 8570b57cec5SDimitry Andric // Transfer the function live-out registers. 8580b57cec5SDimitry Andric NewI->copyImplicitOps(MF, *RetI); 8590b57cec5SDimitry Andric MBB.erase(RetI); 8605ffd83dbSDimitry Andric } else { 8615ffd83dbSDimitry Andric // L2_deallocframe instruction after it. 8625ffd83dbSDimitry Andric // Calculate the size of register saved area. 8635ffd83dbSDimitry Andric int NumVarArgRegs = 6 - FirstVarArgSavedReg; 8645ffd83dbSDimitry Andric int RegisterSavedAreaSizePlusPadding = (NumVarArgRegs % 2 == 0) ? 8655ffd83dbSDimitry Andric (NumVarArgRegs * 4) : (NumVarArgRegs * 4 + 4); 8665ffd83dbSDimitry Andric 8675ffd83dbSDimitry Andric MachineBasicBlock::iterator Term = MBB.getFirstTerminator(); 8685ffd83dbSDimitry Andric MachineBasicBlock::iterator I = (Term == MBB.begin()) ? MBB.end() 8695ffd83dbSDimitry Andric : std::prev(Term); 8705ffd83dbSDimitry Andric if (I == MBB.end() || 8715ffd83dbSDimitry Andric (I->getOpcode() != Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT && 8725ffd83dbSDimitry Andric I->getOpcode() != Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC && 8735ffd83dbSDimitry Andric I->getOpcode() != Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4 && 8745ffd83dbSDimitry Andric I->getOpcode() != Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC)) 8755ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::L2_deallocframe)) 8765ffd83dbSDimitry Andric .addDef(Hexagon::D15) 8775ffd83dbSDimitry Andric .addReg(Hexagon::R30); 8785ffd83dbSDimitry Andric if (RegisterSavedAreaSizePlusPadding != 0) 8795ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP) 8805ffd83dbSDimitry Andric .addReg(SP) 8815ffd83dbSDimitry Andric .addImm(RegisterSavedAreaSizePlusPadding); 8825ffd83dbSDimitry Andric } 8830b57cec5SDimitry Andric } 8840b57cec5SDimitry Andric 8850b57cec5SDimitry Andric void HexagonFrameLowering::insertAllocframe(MachineBasicBlock &MBB, 8860b57cec5SDimitry Andric MachineBasicBlock::iterator InsertPt, unsigned NumBytes) const { 8870b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 8880b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 8890b57cec5SDimitry Andric auto &HII = *HST.getInstrInfo(); 8900b57cec5SDimitry Andric auto &HRI = *HST.getRegisterInfo(); 8910b57cec5SDimitry Andric 8920b57cec5SDimitry Andric // Check for overflow. 8930b57cec5SDimitry Andric // Hexagon_TODO: Ugh! hardcoding. Is there an API that can be used? 8940b57cec5SDimitry Andric const unsigned int ALLOCFRAME_MAX = 16384; 8950b57cec5SDimitry Andric 8960b57cec5SDimitry Andric // Create a dummy memory operand to avoid allocframe from being treated as 8970b57cec5SDimitry Andric // a volatile memory reference. 8980b57cec5SDimitry Andric auto *MMO = MF.getMachineMemOperand(MachinePointerInfo::getStack(MF, 0), 8995ffd83dbSDimitry Andric MachineMemOperand::MOStore, 4, Align(4)); 9000b57cec5SDimitry Andric 9010b57cec5SDimitry Andric DebugLoc dl = MBB.findDebugLoc(InsertPt); 9020b57cec5SDimitry Andric unsigned SP = HRI.getStackRegister(); 9030b57cec5SDimitry Andric 9040b57cec5SDimitry Andric if (NumBytes >= ALLOCFRAME_MAX) { 9050b57cec5SDimitry Andric // Emit allocframe(#0). 9060b57cec5SDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::S2_allocframe)) 9070b57cec5SDimitry Andric .addDef(SP) 9080b57cec5SDimitry Andric .addReg(SP) 9090b57cec5SDimitry Andric .addImm(0) 9100b57cec5SDimitry Andric .addMemOperand(MMO); 9110b57cec5SDimitry Andric 9120b57cec5SDimitry Andric // Subtract the size from the stack pointer. 9130b57cec5SDimitry Andric unsigned SP = HRI.getStackRegister(); 9140b57cec5SDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_addi), SP) 9150b57cec5SDimitry Andric .addReg(SP) 9160b57cec5SDimitry Andric .addImm(-int(NumBytes)); 9170b57cec5SDimitry Andric } else { 9180b57cec5SDimitry Andric BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::S2_allocframe)) 9190b57cec5SDimitry Andric .addDef(SP) 9200b57cec5SDimitry Andric .addReg(SP) 9210b57cec5SDimitry Andric .addImm(NumBytes) 9220b57cec5SDimitry Andric .addMemOperand(MMO); 9230b57cec5SDimitry Andric } 9240b57cec5SDimitry Andric } 9250b57cec5SDimitry Andric 9260b57cec5SDimitry Andric void HexagonFrameLowering::updateEntryPaths(MachineFunction &MF, 9270b57cec5SDimitry Andric MachineBasicBlock &SaveB) const { 9280b57cec5SDimitry Andric SetVector<unsigned> Worklist; 9290b57cec5SDimitry Andric 9300b57cec5SDimitry Andric MachineBasicBlock &EntryB = MF.front(); 9310b57cec5SDimitry Andric Worklist.insert(EntryB.getNumber()); 9320b57cec5SDimitry Andric 9330b57cec5SDimitry Andric unsigned SaveN = SaveB.getNumber(); 9340b57cec5SDimitry Andric auto &CSI = MF.getFrameInfo().getCalleeSavedInfo(); 9350b57cec5SDimitry Andric 9360b57cec5SDimitry Andric for (unsigned i = 0; i < Worklist.size(); ++i) { 9370b57cec5SDimitry Andric unsigned BN = Worklist[i]; 9380b57cec5SDimitry Andric MachineBasicBlock &MBB = *MF.getBlockNumbered(BN); 9390b57cec5SDimitry Andric for (auto &R : CSI) 9400b57cec5SDimitry Andric if (!MBB.isLiveIn(R.getReg())) 9410b57cec5SDimitry Andric MBB.addLiveIn(R.getReg()); 9420b57cec5SDimitry Andric if (BN != SaveN) 9430b57cec5SDimitry Andric for (auto &SB : MBB.successors()) 9440b57cec5SDimitry Andric Worklist.insert(SB->getNumber()); 9450b57cec5SDimitry Andric } 9460b57cec5SDimitry Andric } 9470b57cec5SDimitry Andric 9480b57cec5SDimitry Andric bool HexagonFrameLowering::updateExitPaths(MachineBasicBlock &MBB, 9490b57cec5SDimitry Andric MachineBasicBlock &RestoreB, BitVector &DoneT, BitVector &DoneF, 9500b57cec5SDimitry Andric BitVector &Path) const { 9510b57cec5SDimitry Andric assert(MBB.getNumber() >= 0); 9520b57cec5SDimitry Andric unsigned BN = MBB.getNumber(); 9530b57cec5SDimitry Andric if (Path[BN] || DoneF[BN]) 9540b57cec5SDimitry Andric return false; 9550b57cec5SDimitry Andric if (DoneT[BN]) 9560b57cec5SDimitry Andric return true; 9570b57cec5SDimitry Andric 9580b57cec5SDimitry Andric auto &CSI = MBB.getParent()->getFrameInfo().getCalleeSavedInfo(); 9590b57cec5SDimitry Andric 9600b57cec5SDimitry Andric Path[BN] = true; 9610b57cec5SDimitry Andric bool ReachedExit = false; 9620b57cec5SDimitry Andric for (auto &SB : MBB.successors()) 9630b57cec5SDimitry Andric ReachedExit |= updateExitPaths(*SB, RestoreB, DoneT, DoneF, Path); 9640b57cec5SDimitry Andric 9650b57cec5SDimitry Andric if (!MBB.empty() && MBB.back().isReturn()) { 9660b57cec5SDimitry Andric // Add implicit uses of all callee-saved registers to the reached 9670b57cec5SDimitry Andric // return instructions. This is to prevent the anti-dependency breaker 9680b57cec5SDimitry Andric // from renaming these registers. 9690b57cec5SDimitry Andric MachineInstr &RetI = MBB.back(); 9700b57cec5SDimitry Andric if (!isRestoreCall(RetI.getOpcode())) 9710b57cec5SDimitry Andric for (auto &R : CSI) 9720b57cec5SDimitry Andric RetI.addOperand(MachineOperand::CreateReg(R.getReg(), false, true)); 9730b57cec5SDimitry Andric ReachedExit = true; 9740b57cec5SDimitry Andric } 9750b57cec5SDimitry Andric 9760b57cec5SDimitry Andric // We don't want to add unnecessary live-ins to the restore block: since 9770b57cec5SDimitry Andric // the callee-saved registers are being defined in it, the entry of the 9780b57cec5SDimitry Andric // restore block cannot be on the path from the definitions to any exit. 9790b57cec5SDimitry Andric if (ReachedExit && &MBB != &RestoreB) { 9800b57cec5SDimitry Andric for (auto &R : CSI) 9810b57cec5SDimitry Andric if (!MBB.isLiveIn(R.getReg())) 9820b57cec5SDimitry Andric MBB.addLiveIn(R.getReg()); 9830b57cec5SDimitry Andric DoneT[BN] = true; 9840b57cec5SDimitry Andric } 9850b57cec5SDimitry Andric if (!ReachedExit) 9860b57cec5SDimitry Andric DoneF[BN] = true; 9870b57cec5SDimitry Andric 9880b57cec5SDimitry Andric Path[BN] = false; 9890b57cec5SDimitry Andric return ReachedExit; 9900b57cec5SDimitry Andric } 9910b57cec5SDimitry Andric 9920b57cec5SDimitry Andric static Optional<MachineBasicBlock::iterator> 9930b57cec5SDimitry Andric findCFILocation(MachineBasicBlock &B) { 9940b57cec5SDimitry Andric // The CFI instructions need to be inserted right after allocframe. 9950b57cec5SDimitry Andric // An exception to this is a situation where allocframe is bundled 9960b57cec5SDimitry Andric // with a call: then the CFI instructions need to be inserted before 9970b57cec5SDimitry Andric // the packet with the allocframe+call (in case the call throws an 9980b57cec5SDimitry Andric // exception). 9990b57cec5SDimitry Andric auto End = B.instr_end(); 10000b57cec5SDimitry Andric 10010b57cec5SDimitry Andric for (MachineInstr &I : B) { 10020b57cec5SDimitry Andric MachineBasicBlock::iterator It = I.getIterator(); 10030b57cec5SDimitry Andric if (!I.isBundle()) { 10040b57cec5SDimitry Andric if (I.getOpcode() == Hexagon::S2_allocframe) 10050b57cec5SDimitry Andric return std::next(It); 10060b57cec5SDimitry Andric continue; 10070b57cec5SDimitry Andric } 10080b57cec5SDimitry Andric // I is a bundle. 10090b57cec5SDimitry Andric bool HasCall = false, HasAllocFrame = false; 10100b57cec5SDimitry Andric auto T = It.getInstrIterator(); 10110b57cec5SDimitry Andric while (++T != End && T->isBundled()) { 10120b57cec5SDimitry Andric if (T->getOpcode() == Hexagon::S2_allocframe) 10130b57cec5SDimitry Andric HasAllocFrame = true; 10140b57cec5SDimitry Andric else if (T->isCall()) 10150b57cec5SDimitry Andric HasCall = true; 10160b57cec5SDimitry Andric } 10170b57cec5SDimitry Andric if (HasAllocFrame) 10180b57cec5SDimitry Andric return HasCall ? It : std::next(It); 10190b57cec5SDimitry Andric } 10200b57cec5SDimitry Andric return None; 10210b57cec5SDimitry Andric } 10220b57cec5SDimitry Andric 10230b57cec5SDimitry Andric void HexagonFrameLowering::insertCFIInstructions(MachineFunction &MF) const { 10240b57cec5SDimitry Andric for (auto &B : MF) { 10250b57cec5SDimitry Andric auto At = findCFILocation(B); 1026*81ad6265SDimitry Andric if (At) 10270b57cec5SDimitry Andric insertCFIInstructionsAt(B, At.getValue()); 10280b57cec5SDimitry Andric } 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 MachineModuleInfo &MMI = MF.getMMI(); 10360b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 10370b57cec5SDimitry Andric auto &HII = *HST.getInstrInfo(); 10380b57cec5SDimitry Andric auto &HRI = *HST.getRegisterInfo(); 10390b57cec5SDimitry Andric 10400b57cec5SDimitry Andric // If CFI instructions have debug information attached, something goes 10410b57cec5SDimitry Andric // wrong with the final assembly generation: the prolog_end is placed 10420b57cec5SDimitry Andric // in a wrong location. 10430b57cec5SDimitry Andric DebugLoc DL; 10440b57cec5SDimitry Andric const MCInstrDesc &CFID = HII.get(TargetOpcode::CFI_INSTRUCTION); 10450b57cec5SDimitry Andric 10460b57cec5SDimitry Andric MCSymbol *FrameLabel = MMI.getContext().createTempSymbol(); 10470b57cec5SDimitry Andric bool HasFP = hasFP(MF); 10480b57cec5SDimitry Andric 10490b57cec5SDimitry Andric if (HasFP) { 10500b57cec5SDimitry Andric unsigned DwFPReg = HRI.getDwarfRegNum(HRI.getFrameRegister(), true); 10510b57cec5SDimitry Andric unsigned DwRAReg = HRI.getDwarfRegNum(HRI.getRARegister(), true); 10520b57cec5SDimitry Andric 10530b57cec5SDimitry Andric // Define CFA via an offset from the value of FP. 10540b57cec5SDimitry Andric // 10550b57cec5SDimitry Andric // -8 -4 0 (SP) 10560b57cec5SDimitry Andric // --+----+----+--------------------- 10570b57cec5SDimitry Andric // | FP | LR | increasing addresses --> 10580b57cec5SDimitry Andric // --+----+----+--------------------- 10590b57cec5SDimitry Andric // | +-- Old SP (before allocframe) 10600b57cec5SDimitry Andric // +-- New FP (after allocframe) 10610b57cec5SDimitry Andric // 10625ffd83dbSDimitry Andric // MCCFIInstruction::cfiDefCfa adds the offset from the register. 10630b57cec5SDimitry Andric // MCCFIInstruction::createOffset takes the offset without sign change. 10645ffd83dbSDimitry Andric auto DefCfa = MCCFIInstruction::cfiDefCfa(FrameLabel, DwFPReg, 8); 10650b57cec5SDimitry Andric BuildMI(MBB, At, DL, CFID) 10660b57cec5SDimitry Andric .addCFIIndex(MF.addFrameInst(DefCfa)); 10670b57cec5SDimitry Andric // R31 (return addr) = CFA - 4 10680b57cec5SDimitry Andric auto OffR31 = MCCFIInstruction::createOffset(FrameLabel, DwRAReg, -4); 10690b57cec5SDimitry Andric BuildMI(MBB, At, DL, CFID) 10700b57cec5SDimitry Andric .addCFIIndex(MF.addFrameInst(OffR31)); 10710b57cec5SDimitry Andric // R30 (frame ptr) = CFA - 8 10720b57cec5SDimitry Andric auto OffR30 = MCCFIInstruction::createOffset(FrameLabel, DwFPReg, -8); 10730b57cec5SDimitry Andric BuildMI(MBB, At, DL, CFID) 10740b57cec5SDimitry Andric .addCFIIndex(MF.addFrameInst(OffR30)); 10750b57cec5SDimitry Andric } 10760b57cec5SDimitry Andric 10770b57cec5SDimitry Andric static unsigned int RegsToMove[] = { 10780b57cec5SDimitry Andric Hexagon::R1, Hexagon::R0, Hexagon::R3, Hexagon::R2, 10790b57cec5SDimitry Andric Hexagon::R17, Hexagon::R16, Hexagon::R19, Hexagon::R18, 10800b57cec5SDimitry Andric Hexagon::R21, Hexagon::R20, Hexagon::R23, Hexagon::R22, 10810b57cec5SDimitry Andric Hexagon::R25, Hexagon::R24, Hexagon::R27, Hexagon::R26, 10820b57cec5SDimitry Andric Hexagon::D0, Hexagon::D1, Hexagon::D8, Hexagon::D9, 10830b57cec5SDimitry Andric Hexagon::D10, Hexagon::D11, Hexagon::D12, Hexagon::D13, 10840b57cec5SDimitry Andric Hexagon::NoRegister 10850b57cec5SDimitry Andric }; 10860b57cec5SDimitry Andric 10870b57cec5SDimitry Andric const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 10880b57cec5SDimitry Andric 10890b57cec5SDimitry Andric for (unsigned i = 0; RegsToMove[i] != Hexagon::NoRegister; ++i) { 10900b57cec5SDimitry Andric unsigned Reg = RegsToMove[i]; 10910b57cec5SDimitry Andric auto IfR = [Reg] (const CalleeSavedInfo &C) -> bool { 10920b57cec5SDimitry Andric return C.getReg() == Reg; 10930b57cec5SDimitry Andric }; 10940b57cec5SDimitry Andric auto F = find_if(CSI, IfR); 10950b57cec5SDimitry Andric if (F == CSI.end()) 10960b57cec5SDimitry Andric continue; 10970b57cec5SDimitry Andric 10980b57cec5SDimitry Andric int64_t Offset; 10990b57cec5SDimitry Andric if (HasFP) { 11000b57cec5SDimitry Andric // If the function has a frame pointer (i.e. has an allocframe), 11010b57cec5SDimitry Andric // then the CFA has been defined in terms of FP. Any offsets in 11020b57cec5SDimitry Andric // the following CFI instructions have to be defined relative 11030b57cec5SDimitry Andric // to FP, which points to the bottom of the stack frame. 11040b57cec5SDimitry Andric // The function getFrameIndexReference can still choose to use SP 11050b57cec5SDimitry Andric // for the offset calculation, so we cannot simply call it here. 11060b57cec5SDimitry Andric // Instead, get the offset (relative to the FP) directly. 11070b57cec5SDimitry Andric Offset = MFI.getObjectOffset(F->getFrameIdx()); 11080b57cec5SDimitry Andric } else { 11095ffd83dbSDimitry Andric Register FrameReg; 1110e8d8bef9SDimitry Andric Offset = 1111e8d8bef9SDimitry Andric getFrameIndexReference(MF, F->getFrameIdx(), FrameReg).getFixed(); 11120b57cec5SDimitry Andric } 11130b57cec5SDimitry Andric // Subtract 8 to make room for R30 and R31, which are added above. 11140b57cec5SDimitry Andric Offset -= 8; 11150b57cec5SDimitry Andric 11160b57cec5SDimitry Andric if (Reg < Hexagon::D0 || Reg > Hexagon::D15) { 11170b57cec5SDimitry Andric unsigned DwarfReg = HRI.getDwarfRegNum(Reg, true); 11180b57cec5SDimitry Andric auto OffReg = MCCFIInstruction::createOffset(FrameLabel, DwarfReg, 11190b57cec5SDimitry Andric Offset); 11200b57cec5SDimitry Andric BuildMI(MBB, At, DL, CFID) 11210b57cec5SDimitry Andric .addCFIIndex(MF.addFrameInst(OffReg)); 11220b57cec5SDimitry Andric } else { 11230b57cec5SDimitry Andric // Split the double regs into subregs, and generate appropriate 11240b57cec5SDimitry Andric // cfi_offsets. 11250b57cec5SDimitry Andric // The only reason, we are split double regs is, llvm-mc does not 11260b57cec5SDimitry Andric // understand paired registers for cfi_offset. 11270b57cec5SDimitry Andric // Eg .cfi_offset r1:0, -64 11280b57cec5SDimitry Andric 11298bcb0991SDimitry Andric Register HiReg = HRI.getSubReg(Reg, Hexagon::isub_hi); 11308bcb0991SDimitry Andric Register LoReg = HRI.getSubReg(Reg, Hexagon::isub_lo); 11310b57cec5SDimitry Andric unsigned HiDwarfReg = HRI.getDwarfRegNum(HiReg, true); 11320b57cec5SDimitry Andric unsigned LoDwarfReg = HRI.getDwarfRegNum(LoReg, true); 11330b57cec5SDimitry Andric auto OffHi = MCCFIInstruction::createOffset(FrameLabel, HiDwarfReg, 11340b57cec5SDimitry Andric Offset+4); 11350b57cec5SDimitry Andric BuildMI(MBB, At, DL, CFID) 11360b57cec5SDimitry Andric .addCFIIndex(MF.addFrameInst(OffHi)); 11370b57cec5SDimitry Andric auto OffLo = MCCFIInstruction::createOffset(FrameLabel, LoDwarfReg, 11380b57cec5SDimitry Andric Offset); 11390b57cec5SDimitry Andric BuildMI(MBB, At, DL, CFID) 11400b57cec5SDimitry Andric .addCFIIndex(MF.addFrameInst(OffLo)); 11410b57cec5SDimitry Andric } 11420b57cec5SDimitry Andric } 11430b57cec5SDimitry Andric } 11440b57cec5SDimitry Andric 11450b57cec5SDimitry Andric bool HexagonFrameLowering::hasFP(const MachineFunction &MF) const { 11460b57cec5SDimitry Andric if (MF.getFunction().hasFnAttribute(Attribute::Naked)) 11470b57cec5SDimitry Andric return false; 11480b57cec5SDimitry Andric 11490b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 11500b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 1151fe6060f1SDimitry Andric bool HasExtraAlign = HRI.hasStackRealignment(MF); 11520b57cec5SDimitry Andric bool HasAlloca = MFI.hasVarSizedObjects(); 11530b57cec5SDimitry Andric 11540b57cec5SDimitry Andric // Insert ALLOCFRAME if we need to or at -O0 for the debugger. Think 11550b57cec5SDimitry Andric // that this shouldn't be required, but doing so now because gcc does and 11560b57cec5SDimitry Andric // gdb can't break at the start of the function without it. Will remove if 11570b57cec5SDimitry Andric // this turns out to be a gdb bug. 11580b57cec5SDimitry Andric // 11590b57cec5SDimitry Andric if (MF.getTarget().getOptLevel() == CodeGenOpt::None) 11600b57cec5SDimitry Andric return true; 11610b57cec5SDimitry Andric 11620b57cec5SDimitry Andric // By default we want to use SP (since it's always there). FP requires 11630b57cec5SDimitry Andric // some setup (i.e. ALLOCFRAME). 11640b57cec5SDimitry Andric // Both, alloca and stack alignment modify the stack pointer by an 11650b57cec5SDimitry Andric // undetermined value, so we need to save it at the entry to the function 11660b57cec5SDimitry Andric // (i.e. use allocframe). 11670b57cec5SDimitry Andric if (HasAlloca || HasExtraAlign) 11680b57cec5SDimitry Andric return true; 11690b57cec5SDimitry Andric 11700b57cec5SDimitry Andric if (MFI.getStackSize() > 0) { 11710b57cec5SDimitry Andric // If FP-elimination is disabled, we have to use FP at this point. 11720b57cec5SDimitry Andric const TargetMachine &TM = MF.getTarget(); 11730b57cec5SDimitry Andric if (TM.Options.DisableFramePointerElim(MF) || !EliminateFramePointer) 11740b57cec5SDimitry Andric return true; 11750b57cec5SDimitry Andric if (EnableStackOVFSanitizer) 11760b57cec5SDimitry Andric return true; 11770b57cec5SDimitry Andric } 11780b57cec5SDimitry Andric 11790b57cec5SDimitry Andric const auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>(); 11800b57cec5SDimitry Andric if ((MFI.hasCalls() && !enableAllocFrameElim(MF)) || HMFI.hasClobberLR()) 11810b57cec5SDimitry Andric return true; 11820b57cec5SDimitry Andric 11830b57cec5SDimitry Andric return false; 11840b57cec5SDimitry Andric } 11850b57cec5SDimitry Andric 11860b57cec5SDimitry Andric enum SpillKind { 11870b57cec5SDimitry Andric SK_ToMem, 11880b57cec5SDimitry Andric SK_FromMem, 11890b57cec5SDimitry Andric SK_FromMemTailcall 11900b57cec5SDimitry Andric }; 11910b57cec5SDimitry Andric 11920b57cec5SDimitry Andric static const char *getSpillFunctionFor(unsigned MaxReg, SpillKind SpillType, 11930b57cec5SDimitry Andric bool Stkchk = false) { 11940b57cec5SDimitry Andric const char * V4SpillToMemoryFunctions[] = { 11950b57cec5SDimitry Andric "__save_r16_through_r17", 11960b57cec5SDimitry Andric "__save_r16_through_r19", 11970b57cec5SDimitry Andric "__save_r16_through_r21", 11980b57cec5SDimitry Andric "__save_r16_through_r23", 11990b57cec5SDimitry Andric "__save_r16_through_r25", 12000b57cec5SDimitry Andric "__save_r16_through_r27" }; 12010b57cec5SDimitry Andric 12020b57cec5SDimitry Andric const char * V4SpillToMemoryStkchkFunctions[] = { 12030b57cec5SDimitry Andric "__save_r16_through_r17_stkchk", 12040b57cec5SDimitry Andric "__save_r16_through_r19_stkchk", 12050b57cec5SDimitry Andric "__save_r16_through_r21_stkchk", 12060b57cec5SDimitry Andric "__save_r16_through_r23_stkchk", 12070b57cec5SDimitry Andric "__save_r16_through_r25_stkchk", 12080b57cec5SDimitry Andric "__save_r16_through_r27_stkchk" }; 12090b57cec5SDimitry Andric 12100b57cec5SDimitry Andric const char * V4SpillFromMemoryFunctions[] = { 12110b57cec5SDimitry Andric "__restore_r16_through_r17_and_deallocframe", 12120b57cec5SDimitry Andric "__restore_r16_through_r19_and_deallocframe", 12130b57cec5SDimitry Andric "__restore_r16_through_r21_and_deallocframe", 12140b57cec5SDimitry Andric "__restore_r16_through_r23_and_deallocframe", 12150b57cec5SDimitry Andric "__restore_r16_through_r25_and_deallocframe", 12160b57cec5SDimitry Andric "__restore_r16_through_r27_and_deallocframe" }; 12170b57cec5SDimitry Andric 12180b57cec5SDimitry Andric const char * V4SpillFromMemoryTailcallFunctions[] = { 12190b57cec5SDimitry Andric "__restore_r16_through_r17_and_deallocframe_before_tailcall", 12200b57cec5SDimitry Andric "__restore_r16_through_r19_and_deallocframe_before_tailcall", 12210b57cec5SDimitry Andric "__restore_r16_through_r21_and_deallocframe_before_tailcall", 12220b57cec5SDimitry Andric "__restore_r16_through_r23_and_deallocframe_before_tailcall", 12230b57cec5SDimitry Andric "__restore_r16_through_r25_and_deallocframe_before_tailcall", 12240b57cec5SDimitry Andric "__restore_r16_through_r27_and_deallocframe_before_tailcall" 12250b57cec5SDimitry Andric }; 12260b57cec5SDimitry Andric 12270b57cec5SDimitry Andric const char **SpillFunc = nullptr; 12280b57cec5SDimitry Andric 12290b57cec5SDimitry Andric switch(SpillType) { 12300b57cec5SDimitry Andric case SK_ToMem: 12310b57cec5SDimitry Andric SpillFunc = Stkchk ? V4SpillToMemoryStkchkFunctions 12320b57cec5SDimitry Andric : V4SpillToMemoryFunctions; 12330b57cec5SDimitry Andric break; 12340b57cec5SDimitry Andric case SK_FromMem: 12350b57cec5SDimitry Andric SpillFunc = V4SpillFromMemoryFunctions; 12360b57cec5SDimitry Andric break; 12370b57cec5SDimitry Andric case SK_FromMemTailcall: 12380b57cec5SDimitry Andric SpillFunc = V4SpillFromMemoryTailcallFunctions; 12390b57cec5SDimitry Andric break; 12400b57cec5SDimitry Andric } 12410b57cec5SDimitry Andric assert(SpillFunc && "Unknown spill kind"); 12420b57cec5SDimitry Andric 12430b57cec5SDimitry Andric // Spill all callee-saved registers up to the highest register used. 12440b57cec5SDimitry Andric switch (MaxReg) { 12450b57cec5SDimitry Andric case Hexagon::R17: 12460b57cec5SDimitry Andric return SpillFunc[0]; 12470b57cec5SDimitry Andric case Hexagon::R19: 12480b57cec5SDimitry Andric return SpillFunc[1]; 12490b57cec5SDimitry Andric case Hexagon::R21: 12500b57cec5SDimitry Andric return SpillFunc[2]; 12510b57cec5SDimitry Andric case Hexagon::R23: 12520b57cec5SDimitry Andric return SpillFunc[3]; 12530b57cec5SDimitry Andric case Hexagon::R25: 12540b57cec5SDimitry Andric return SpillFunc[4]; 12550b57cec5SDimitry Andric case Hexagon::R27: 12560b57cec5SDimitry Andric return SpillFunc[5]; 12570b57cec5SDimitry Andric default: 12580b57cec5SDimitry Andric llvm_unreachable("Unhandled maximum callee save register"); 12590b57cec5SDimitry Andric } 12600b57cec5SDimitry Andric return nullptr; 12610b57cec5SDimitry Andric } 12620b57cec5SDimitry Andric 1263e8d8bef9SDimitry Andric StackOffset 1264e8d8bef9SDimitry Andric HexagonFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, 12655ffd83dbSDimitry Andric Register &FrameReg) const { 12660b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 12670b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 12680b57cec5SDimitry Andric 12690b57cec5SDimitry Andric int Offset = MFI.getObjectOffset(FI); 12700b57cec5SDimitry Andric bool HasAlloca = MFI.hasVarSizedObjects(); 1271fe6060f1SDimitry Andric bool HasExtraAlign = HRI.hasStackRealignment(MF); 12720b57cec5SDimitry Andric bool NoOpt = MF.getTarget().getOptLevel() == CodeGenOpt::None; 12730b57cec5SDimitry Andric 12740b57cec5SDimitry Andric auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>(); 12750b57cec5SDimitry Andric unsigned FrameSize = MFI.getStackSize(); 12765ffd83dbSDimitry Andric Register SP = HRI.getStackRegister(); 12775ffd83dbSDimitry Andric Register FP = HRI.getFrameRegister(); 12785ffd83dbSDimitry Andric Register AP = HMFI.getStackAlignBasePhysReg(); 12790b57cec5SDimitry Andric // It may happen that AP will be absent even HasAlloca && HasExtraAlign 12800b57cec5SDimitry Andric // is true. HasExtraAlign may be set because of vector spills, without 12810b57cec5SDimitry Andric // aligned locals or aligned outgoing function arguments. Since vector 12820b57cec5SDimitry Andric // spills will ultimately be "unaligned", it is safe to use FP as the 12830b57cec5SDimitry Andric // base register. 12840b57cec5SDimitry Andric // In fact, in such a scenario the stack is actually not required to be 12850b57cec5SDimitry Andric // aligned, although it may end up being aligned anyway, since this 12860b57cec5SDimitry Andric // particular case is not easily detectable. The alignment will be 12870b57cec5SDimitry Andric // unnecessary, but not incorrect. 12880b57cec5SDimitry Andric // Unfortunately there is no quick way to verify that the above is 12890b57cec5SDimitry Andric // indeed the case (and that it's not a result of an error), so just 12900b57cec5SDimitry Andric // assume that missing AP will be replaced by FP. 12910b57cec5SDimitry Andric // (A better fix would be to rematerialize AP from FP and always align 12920b57cec5SDimitry Andric // vector spills.) 12930b57cec5SDimitry Andric if (AP == 0) 12940b57cec5SDimitry Andric AP = FP; 12950b57cec5SDimitry Andric 12960b57cec5SDimitry Andric bool UseFP = false, UseAP = false; // Default: use SP (except at -O0). 12970b57cec5SDimitry Andric // Use FP at -O0, except when there are objects with extra alignment. 12980b57cec5SDimitry Andric // That additional alignment requirement may cause a pad to be inserted, 12990b57cec5SDimitry Andric // which will make it impossible to use FP to access objects located 13000b57cec5SDimitry Andric // past the pad. 13010b57cec5SDimitry Andric if (NoOpt && !HasExtraAlign) 13020b57cec5SDimitry Andric UseFP = true; 13030b57cec5SDimitry Andric if (MFI.isFixedObjectIndex(FI) || MFI.isObjectPreAllocated(FI)) { 13040b57cec5SDimitry Andric // Fixed and preallocated objects will be located before any padding 13050b57cec5SDimitry Andric // so FP must be used to access them. 13060b57cec5SDimitry Andric UseFP |= (HasAlloca || HasExtraAlign); 13070b57cec5SDimitry Andric } else { 13080b57cec5SDimitry Andric if (HasAlloca) { 13090b57cec5SDimitry Andric if (HasExtraAlign) 13100b57cec5SDimitry Andric UseAP = true; 13110b57cec5SDimitry Andric else 13120b57cec5SDimitry Andric UseFP = true; 13130b57cec5SDimitry Andric } 13140b57cec5SDimitry Andric } 13150b57cec5SDimitry Andric 13160b57cec5SDimitry Andric // If FP was picked, then there had better be FP. 13170b57cec5SDimitry Andric bool HasFP = hasFP(MF); 13180b57cec5SDimitry Andric assert((HasFP || !UseFP) && "This function must have frame pointer"); 13190b57cec5SDimitry Andric 13200b57cec5SDimitry Andric // Having FP implies allocframe. Allocframe will store extra 8 bytes: 13210b57cec5SDimitry Andric // FP/LR. If the base register is used to access an object across these 13220b57cec5SDimitry Andric // 8 bytes, then the offset will need to be adjusted by 8. 13230b57cec5SDimitry Andric // 13240b57cec5SDimitry Andric // After allocframe: 13250b57cec5SDimitry Andric // HexagonISelLowering adds 8 to ---+ 13260b57cec5SDimitry Andric // the offsets of all stack-based | 13270b57cec5SDimitry Andric // arguments (*) | 13280b57cec5SDimitry Andric // | 13290b57cec5SDimitry Andric // getObjectOffset < 0 0 8 getObjectOffset >= 8 13300b57cec5SDimitry Andric // ------------------------+-----+------------------------> increasing 13310b57cec5SDimitry Andric // <local objects> |FP/LR| <input arguments> addresses 13320b57cec5SDimitry Andric // -----------------+------+-----+------------------------> 13330b57cec5SDimitry Andric // | | 13340b57cec5SDimitry Andric // SP/AP point --+ +-- FP points here (**) 13350b57cec5SDimitry Andric // somewhere on 13360b57cec5SDimitry Andric // this side of FP/LR 13370b57cec5SDimitry Andric // 13380b57cec5SDimitry Andric // (*) See LowerFormalArguments. The FP/LR is assumed to be present. 13390b57cec5SDimitry Andric // (**) *FP == old-FP. FP+0..7 are the bytes of FP/LR. 13400b57cec5SDimitry Andric 13410b57cec5SDimitry Andric // The lowering assumes that FP/LR is present, and so the offsets of 13420b57cec5SDimitry Andric // the formal arguments start at 8. If FP/LR is not there we need to 13430b57cec5SDimitry Andric // reduce the offset by 8. 13440b57cec5SDimitry Andric if (Offset > 0 && !HasFP) 13450b57cec5SDimitry Andric Offset -= 8; 13460b57cec5SDimitry Andric 13470b57cec5SDimitry Andric if (UseFP) 13480b57cec5SDimitry Andric FrameReg = FP; 13490b57cec5SDimitry Andric else if (UseAP) 13500b57cec5SDimitry Andric FrameReg = AP; 13510b57cec5SDimitry Andric else 13520b57cec5SDimitry Andric FrameReg = SP; 13530b57cec5SDimitry Andric 13540b57cec5SDimitry Andric // Calculate the actual offset in the instruction. If there is no FP 13550b57cec5SDimitry Andric // (in other words, no allocframe), then SP will not be adjusted (i.e. 13560b57cec5SDimitry Andric // there will be no SP -= FrameSize), so the frame size should not be 13570b57cec5SDimitry Andric // added to the calculated offset. 13580b57cec5SDimitry Andric int RealOffset = Offset; 13590b57cec5SDimitry Andric if (!UseFP && !UseAP) 13600b57cec5SDimitry Andric RealOffset = FrameSize+Offset; 1361e8d8bef9SDimitry Andric return StackOffset::getFixed(RealOffset); 13620b57cec5SDimitry Andric } 13630b57cec5SDimitry Andric 13640b57cec5SDimitry Andric bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB, 13650b57cec5SDimitry Andric const CSIVect &CSI, const HexagonRegisterInfo &HRI, 13660b57cec5SDimitry Andric bool &PrologueStubs) const { 13670b57cec5SDimitry Andric if (CSI.empty()) 13680b57cec5SDimitry Andric return true; 13690b57cec5SDimitry Andric 13700b57cec5SDimitry Andric MachineBasicBlock::iterator MI = MBB.begin(); 13710b57cec5SDimitry Andric PrologueStubs = false; 13720b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 13730b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 13740b57cec5SDimitry Andric auto &HII = *HST.getInstrInfo(); 13750b57cec5SDimitry Andric 13760b57cec5SDimitry Andric if (useSpillFunction(MF, CSI)) { 13770b57cec5SDimitry Andric PrologueStubs = true; 13780b57cec5SDimitry Andric unsigned MaxReg = getMaxCalleeSavedReg(CSI, HRI); 13790b57cec5SDimitry Andric bool StkOvrFlowEnabled = EnableStackOVFSanitizer; 13800b57cec5SDimitry Andric const char *SpillFun = getSpillFunctionFor(MaxReg, SK_ToMem, 13810b57cec5SDimitry Andric StkOvrFlowEnabled); 13820b57cec5SDimitry Andric auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget()); 13830b57cec5SDimitry Andric bool IsPIC = HTM.isPositionIndependent(); 13840b57cec5SDimitry Andric bool LongCalls = HST.useLongCalls() || EnableSaveRestoreLong; 13850b57cec5SDimitry Andric 13860b57cec5SDimitry Andric // Call spill function. 13870b57cec5SDimitry Andric DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc(); 13880b57cec5SDimitry Andric unsigned SpillOpc; 13890b57cec5SDimitry Andric if (StkOvrFlowEnabled) { 13900b57cec5SDimitry Andric if (LongCalls) 13910b57cec5SDimitry Andric SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_EXT_PIC 13920b57cec5SDimitry Andric : Hexagon::SAVE_REGISTERS_CALL_V4STK_EXT; 13930b57cec5SDimitry Andric else 13940b57cec5SDimitry Andric SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_PIC 13950b57cec5SDimitry Andric : Hexagon::SAVE_REGISTERS_CALL_V4STK; 13960b57cec5SDimitry Andric } else { 13970b57cec5SDimitry Andric if (LongCalls) 13980b57cec5SDimitry Andric SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_EXT_PIC 13990b57cec5SDimitry Andric : Hexagon::SAVE_REGISTERS_CALL_V4_EXT; 14000b57cec5SDimitry Andric else 14010b57cec5SDimitry Andric SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_PIC 14020b57cec5SDimitry Andric : Hexagon::SAVE_REGISTERS_CALL_V4; 14030b57cec5SDimitry Andric } 14040b57cec5SDimitry Andric 14050b57cec5SDimitry Andric MachineInstr *SaveRegsCall = 14060b57cec5SDimitry Andric BuildMI(MBB, MI, DL, HII.get(SpillOpc)) 14070b57cec5SDimitry Andric .addExternalSymbol(SpillFun); 14080b57cec5SDimitry Andric 14090b57cec5SDimitry Andric // Add callee-saved registers as use. 14100b57cec5SDimitry Andric addCalleeSaveRegistersAsImpOperand(SaveRegsCall, CSI, false, true); 14110b57cec5SDimitry Andric // Add live in registers. 14124824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) 14134824e7fdSDimitry Andric MBB.addLiveIn(I.getReg()); 14140b57cec5SDimitry Andric return true; 14150b57cec5SDimitry Andric } 14160b57cec5SDimitry Andric 14174824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 141804eeddc0SDimitry Andric Register Reg = I.getReg(); 14190b57cec5SDimitry Andric // Add live in registers. We treat eh_return callee saved register r0 - r3 14200b57cec5SDimitry Andric // specially. They are not really callee saved registers as they are not 14210b57cec5SDimitry Andric // supposed to be killed. 14220b57cec5SDimitry Andric bool IsKill = !HRI.isEHReturnCalleeSaveReg(Reg); 14234824e7fdSDimitry Andric int FI = I.getFrameIdx(); 14240b57cec5SDimitry Andric const TargetRegisterClass *RC = HRI.getMinimalPhysRegClass(Reg); 14250b57cec5SDimitry Andric HII.storeRegToStackSlot(MBB, MI, Reg, IsKill, FI, RC, &HRI); 14260b57cec5SDimitry Andric if (IsKill) 14270b57cec5SDimitry Andric MBB.addLiveIn(Reg); 14280b57cec5SDimitry Andric } 14290b57cec5SDimitry Andric return true; 14300b57cec5SDimitry Andric } 14310b57cec5SDimitry Andric 14320b57cec5SDimitry Andric bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB, 14330b57cec5SDimitry Andric const CSIVect &CSI, const HexagonRegisterInfo &HRI) const { 14340b57cec5SDimitry Andric if (CSI.empty()) 14350b57cec5SDimitry Andric return false; 14360b57cec5SDimitry Andric 14370b57cec5SDimitry Andric MachineBasicBlock::iterator MI = MBB.getFirstTerminator(); 14380b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 14390b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 14400b57cec5SDimitry Andric auto &HII = *HST.getInstrInfo(); 14410b57cec5SDimitry Andric 14420b57cec5SDimitry Andric if (useRestoreFunction(MF, CSI)) { 14430b57cec5SDimitry Andric bool HasTC = hasTailCall(MBB) || !hasReturn(MBB); 14440b57cec5SDimitry Andric unsigned MaxR = getMaxCalleeSavedReg(CSI, HRI); 14450b57cec5SDimitry Andric SpillKind Kind = HasTC ? SK_FromMemTailcall : SK_FromMem; 14460b57cec5SDimitry Andric const char *RestoreFn = getSpillFunctionFor(MaxR, Kind); 14470b57cec5SDimitry Andric auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget()); 14480b57cec5SDimitry Andric bool IsPIC = HTM.isPositionIndependent(); 14490b57cec5SDimitry Andric bool LongCalls = HST.useLongCalls() || EnableSaveRestoreLong; 14500b57cec5SDimitry Andric 14510b57cec5SDimitry Andric // Call spill function. 14520b57cec5SDimitry Andric DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() 14530b57cec5SDimitry Andric : MBB.findDebugLoc(MBB.end()); 14540b57cec5SDimitry Andric MachineInstr *DeallocCall = nullptr; 14550b57cec5SDimitry Andric 14560b57cec5SDimitry Andric if (HasTC) { 14570b57cec5SDimitry Andric unsigned RetOpc; 14580b57cec5SDimitry Andric if (LongCalls) 14590b57cec5SDimitry Andric RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC 14600b57cec5SDimitry Andric : Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT; 14610b57cec5SDimitry Andric else 14620b57cec5SDimitry Andric RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC 14630b57cec5SDimitry Andric : Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4; 14640b57cec5SDimitry Andric DeallocCall = BuildMI(MBB, MI, DL, HII.get(RetOpc)) 14650b57cec5SDimitry Andric .addExternalSymbol(RestoreFn); 14660b57cec5SDimitry Andric } else { 14670b57cec5SDimitry Andric // The block has a return. 14680b57cec5SDimitry Andric MachineBasicBlock::iterator It = MBB.getFirstTerminator(); 14690b57cec5SDimitry Andric assert(It->isReturn() && std::next(It) == MBB.end()); 14700b57cec5SDimitry Andric unsigned RetOpc; 14710b57cec5SDimitry Andric if (LongCalls) 14720b57cec5SDimitry Andric RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC 14730b57cec5SDimitry Andric : Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT; 14740b57cec5SDimitry Andric else 14750b57cec5SDimitry Andric RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC 14760b57cec5SDimitry Andric : Hexagon::RESTORE_DEALLOC_RET_JMP_V4; 14770b57cec5SDimitry Andric DeallocCall = BuildMI(MBB, It, DL, HII.get(RetOpc)) 14780b57cec5SDimitry Andric .addExternalSymbol(RestoreFn); 14790b57cec5SDimitry Andric // Transfer the function live-out registers. 14800b57cec5SDimitry Andric DeallocCall->copyImplicitOps(MF, *It); 14810b57cec5SDimitry Andric } 14820b57cec5SDimitry Andric addCalleeSaveRegistersAsImpOperand(DeallocCall, CSI, true, false); 14830b57cec5SDimitry Andric return true; 14840b57cec5SDimitry Andric } 14850b57cec5SDimitry Andric 14864824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 148704eeddc0SDimitry Andric Register Reg = I.getReg(); 14880b57cec5SDimitry Andric const TargetRegisterClass *RC = HRI.getMinimalPhysRegClass(Reg); 14894824e7fdSDimitry Andric int FI = I.getFrameIdx(); 14900b57cec5SDimitry Andric HII.loadRegFromStackSlot(MBB, MI, Reg, FI, RC, &HRI); 14910b57cec5SDimitry Andric } 14920b57cec5SDimitry Andric 14930b57cec5SDimitry Andric return true; 14940b57cec5SDimitry Andric } 14950b57cec5SDimitry Andric 14960b57cec5SDimitry Andric MachineBasicBlock::iterator HexagonFrameLowering::eliminateCallFramePseudoInstr( 14970b57cec5SDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB, 14980b57cec5SDimitry Andric MachineBasicBlock::iterator I) const { 14990b57cec5SDimitry Andric MachineInstr &MI = *I; 15000b57cec5SDimitry Andric unsigned Opc = MI.getOpcode(); 15010b57cec5SDimitry Andric (void)Opc; // Silence compiler warning. 15020b57cec5SDimitry Andric assert((Opc == Hexagon::ADJCALLSTACKDOWN || Opc == Hexagon::ADJCALLSTACKUP) && 15030b57cec5SDimitry Andric "Cannot handle this call frame pseudo instruction"); 15040b57cec5SDimitry Andric return MBB.erase(I); 15050b57cec5SDimitry Andric } 15060b57cec5SDimitry Andric 15070b57cec5SDimitry Andric void HexagonFrameLowering::processFunctionBeforeFrameFinalized( 15080b57cec5SDimitry Andric MachineFunction &MF, RegScavenger *RS) const { 15090b57cec5SDimitry Andric // If this function has uses aligned stack and also has variable sized stack 15100b57cec5SDimitry Andric // objects, then we need to map all spill slots to fixed positions, so that 15110b57cec5SDimitry Andric // they can be accessed through FP. Otherwise they would have to be accessed 15120b57cec5SDimitry Andric // via AP, which may not be available at the particular place in the program. 15130b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 15140b57cec5SDimitry Andric bool HasAlloca = MFI.hasVarSizedObjects(); 15155ffd83dbSDimitry Andric bool NeedsAlign = (MFI.getMaxAlign() > getStackAlign()); 15160b57cec5SDimitry Andric 15170b57cec5SDimitry Andric if (!HasAlloca || !NeedsAlign) 15180b57cec5SDimitry Andric return; 15190b57cec5SDimitry Andric 1520480093f4SDimitry Andric SmallSet<int, 4> DealignSlots; 15210b57cec5SDimitry Andric unsigned LFS = MFI.getLocalFrameSize(); 15220b57cec5SDimitry Andric for (int i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) { 15230b57cec5SDimitry Andric if (!MFI.isSpillSlotObjectIndex(i) || MFI.isDeadObjectIndex(i)) 15240b57cec5SDimitry Andric continue; 15250b57cec5SDimitry Andric unsigned S = MFI.getObjectSize(i); 15260b57cec5SDimitry Andric // Reduce the alignment to at most 8. This will require unaligned vector 15270b57cec5SDimitry Andric // stores if they happen here. 15285ffd83dbSDimitry Andric Align A = std::max(MFI.getObjectAlign(i), Align(8)); 15295ffd83dbSDimitry Andric MFI.setObjectAlignment(i, Align(8)); 15300b57cec5SDimitry Andric LFS = alignTo(LFS+S, A); 1531480093f4SDimitry Andric MFI.mapLocalFrameObject(i, -static_cast<int64_t>(LFS)); 1532480093f4SDimitry Andric DealignSlots.insert(i); 15330b57cec5SDimitry Andric } 15340b57cec5SDimitry Andric 15350b57cec5SDimitry Andric MFI.setLocalFrameSize(LFS); 15368bcb0991SDimitry Andric Align A = MFI.getLocalFrameMaxAlign(); 15370b57cec5SDimitry Andric assert(A <= 8 && "Unexpected local frame alignment"); 15388bcb0991SDimitry Andric if (A == 1) 15398bcb0991SDimitry Andric MFI.setLocalFrameMaxAlign(Align(8)); 15400b57cec5SDimitry Andric MFI.setUseLocalStackAllocationBlock(true); 15410b57cec5SDimitry Andric 1542480093f4SDimitry Andric // Go over all MachineMemOperands in the code, and change the ones that 1543480093f4SDimitry Andric // refer to the dealigned stack slots to reflect the new alignment. 1544480093f4SDimitry Andric if (!DealignSlots.empty()) { 1545480093f4SDimitry Andric for (MachineBasicBlock &BB : MF) { 1546480093f4SDimitry Andric for (MachineInstr &MI : BB) { 1547480093f4SDimitry Andric bool KeepOld = true; 1548480093f4SDimitry Andric ArrayRef<MachineMemOperand*> memops = MI.memoperands(); 1549480093f4SDimitry Andric SmallVector<MachineMemOperand*,1> new_memops; 1550480093f4SDimitry Andric for (MachineMemOperand *MMO : memops) { 1551480093f4SDimitry Andric auto *PV = MMO->getPseudoValue(); 1552480093f4SDimitry Andric if (auto *FS = dyn_cast_or_null<FixedStackPseudoSourceValue>(PV)) { 1553480093f4SDimitry Andric int FI = FS->getFrameIndex(); 1554480093f4SDimitry Andric if (DealignSlots.count(FI)) { 15555ffd83dbSDimitry Andric auto *NewMMO = MF.getMachineMemOperand( 15565ffd83dbSDimitry Andric MMO->getPointerInfo(), MMO->getFlags(), MMO->getSize(), 15575ffd83dbSDimitry Andric MFI.getObjectAlign(FI), MMO->getAAInfo(), MMO->getRanges(), 1558fe6060f1SDimitry Andric MMO->getSyncScopeID(), MMO->getSuccessOrdering(), 1559480093f4SDimitry Andric MMO->getFailureOrdering()); 1560480093f4SDimitry Andric new_memops.push_back(NewMMO); 1561480093f4SDimitry Andric KeepOld = false; 1562480093f4SDimitry Andric continue; 1563480093f4SDimitry Andric } 1564480093f4SDimitry Andric } 1565480093f4SDimitry Andric new_memops.push_back(MMO); 1566480093f4SDimitry Andric } 1567480093f4SDimitry Andric if (!KeepOld) 1568480093f4SDimitry Andric MI.setMemRefs(MF, new_memops); 1569480093f4SDimitry Andric } 1570480093f4SDimitry Andric } 1571480093f4SDimitry Andric } 1572480093f4SDimitry Andric 15730b57cec5SDimitry Andric // Set the physical aligned-stack base address register. 15740b57cec5SDimitry Andric unsigned AP = 0; 15750b57cec5SDimitry Andric if (const MachineInstr *AI = getAlignaInstr(MF)) 15760b57cec5SDimitry Andric AP = AI->getOperand(0).getReg(); 15770b57cec5SDimitry Andric auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>(); 15780b57cec5SDimitry Andric HMFI.setStackAlignBasePhysReg(AP); 15790b57cec5SDimitry Andric } 15800b57cec5SDimitry Andric 15810b57cec5SDimitry Andric /// Returns true if there are no caller-saved registers available in class RC. 15820b57cec5SDimitry Andric static bool needToReserveScavengingSpillSlots(MachineFunction &MF, 15830b57cec5SDimitry Andric const HexagonRegisterInfo &HRI, const TargetRegisterClass *RC) { 15840b57cec5SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 15850b57cec5SDimitry Andric 15860b57cec5SDimitry Andric auto IsUsed = [&HRI,&MRI] (unsigned Reg) -> bool { 15870b57cec5SDimitry Andric for (MCRegAliasIterator AI(Reg, &HRI, true); AI.isValid(); ++AI) 15880b57cec5SDimitry Andric if (MRI.isPhysRegUsed(*AI)) 15890b57cec5SDimitry Andric return true; 15900b57cec5SDimitry Andric return false; 15910b57cec5SDimitry Andric }; 15920b57cec5SDimitry Andric 15930b57cec5SDimitry Andric // Check for an unused caller-saved register. Callee-saved registers 15940b57cec5SDimitry Andric // have become pristine by now. 15950b57cec5SDimitry Andric for (const MCPhysReg *P = HRI.getCallerSavedRegs(&MF, RC); *P; ++P) 15960b57cec5SDimitry Andric if (!IsUsed(*P)) 15970b57cec5SDimitry Andric return false; 15980b57cec5SDimitry Andric 15990b57cec5SDimitry Andric // All caller-saved registers are used. 16000b57cec5SDimitry Andric return true; 16010b57cec5SDimitry Andric } 16020b57cec5SDimitry Andric 16030b57cec5SDimitry Andric #ifndef NDEBUG 16040b57cec5SDimitry Andric static void dump_registers(BitVector &Regs, const TargetRegisterInfo &TRI) { 16050b57cec5SDimitry Andric dbgs() << '{'; 16060b57cec5SDimitry Andric for (int x = Regs.find_first(); x >= 0; x = Regs.find_next(x)) { 16070b57cec5SDimitry Andric unsigned R = x; 16080b57cec5SDimitry Andric dbgs() << ' ' << printReg(R, &TRI); 16090b57cec5SDimitry Andric } 16100b57cec5SDimitry Andric dbgs() << " }"; 16110b57cec5SDimitry Andric } 16120b57cec5SDimitry Andric #endif 16130b57cec5SDimitry Andric 16140b57cec5SDimitry Andric bool HexagonFrameLowering::assignCalleeSavedSpillSlots(MachineFunction &MF, 16150b57cec5SDimitry Andric const TargetRegisterInfo *TRI, std::vector<CalleeSavedInfo> &CSI) const { 16160b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << __func__ << " on " << MF.getName() << '\n'); 16170b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 16180b57cec5SDimitry Andric BitVector SRegs(Hexagon::NUM_TARGET_REGS); 16190b57cec5SDimitry Andric 16200b57cec5SDimitry Andric // Generate a set of unique, callee-saved registers (SRegs), where each 16210b57cec5SDimitry Andric // register in the set is maximal in terms of sub-/super-register relation, 16220b57cec5SDimitry Andric // i.e. for each R in SRegs, no proper super-register of R is also in SRegs. 16230b57cec5SDimitry Andric 16240b57cec5SDimitry Andric // (1) For each callee-saved register, add that register and all of its 16250b57cec5SDimitry Andric // sub-registers to SRegs. 16260b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Initial CS registers: {"); 16274824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 162804eeddc0SDimitry Andric Register R = I.getReg(); 16290b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << ' ' << printReg(R, TRI)); 16300b57cec5SDimitry Andric for (MCSubRegIterator SR(R, TRI, true); SR.isValid(); ++SR) 16310b57cec5SDimitry Andric SRegs[*SR] = true; 16320b57cec5SDimitry Andric } 16330b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " }\n"); 16340b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "SRegs.1: "; dump_registers(SRegs, *TRI); 16350b57cec5SDimitry Andric dbgs() << "\n"); 16360b57cec5SDimitry Andric 16370b57cec5SDimitry Andric // (2) For each reserved register, remove that register and all of its 16380b57cec5SDimitry Andric // sub- and super-registers from SRegs. 16390b57cec5SDimitry Andric BitVector Reserved = TRI->getReservedRegs(MF); 16400b57cec5SDimitry Andric for (int x = Reserved.find_first(); x >= 0; x = Reserved.find_next(x)) { 16410b57cec5SDimitry Andric unsigned R = x; 16420b57cec5SDimitry Andric for (MCSuperRegIterator SR(R, TRI, true); SR.isValid(); ++SR) 16430b57cec5SDimitry Andric SRegs[*SR] = false; 16440b57cec5SDimitry Andric } 16450b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Res: "; dump_registers(Reserved, *TRI); 16460b57cec5SDimitry Andric dbgs() << "\n"); 16470b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "SRegs.2: "; dump_registers(SRegs, *TRI); 16480b57cec5SDimitry Andric dbgs() << "\n"); 16490b57cec5SDimitry Andric 16500b57cec5SDimitry Andric // (3) Collect all registers that have at least one sub-register in SRegs, 16510b57cec5SDimitry Andric // and also have no sub-registers that are reserved. These will be the can- 16520b57cec5SDimitry Andric // didates for saving as a whole instead of their individual sub-registers. 16530b57cec5SDimitry Andric // (Saving R17:16 instead of R16 is fine, but only if R17 was not reserved.) 16540b57cec5SDimitry Andric BitVector TmpSup(Hexagon::NUM_TARGET_REGS); 16550b57cec5SDimitry Andric for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) { 16560b57cec5SDimitry Andric unsigned R = x; 16570b57cec5SDimitry Andric for (MCSuperRegIterator SR(R, TRI); SR.isValid(); ++SR) 16580b57cec5SDimitry Andric TmpSup[*SR] = true; 16590b57cec5SDimitry Andric } 16600b57cec5SDimitry Andric for (int x = TmpSup.find_first(); x >= 0; x = TmpSup.find_next(x)) { 16610b57cec5SDimitry Andric unsigned R = x; 16620b57cec5SDimitry Andric for (MCSubRegIterator SR(R, TRI, true); SR.isValid(); ++SR) { 16630b57cec5SDimitry Andric if (!Reserved[*SR]) 16640b57cec5SDimitry Andric continue; 16650b57cec5SDimitry Andric TmpSup[R] = false; 16660b57cec5SDimitry Andric break; 16670b57cec5SDimitry Andric } 16680b57cec5SDimitry Andric } 16690b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "TmpSup: "; dump_registers(TmpSup, *TRI); 16700b57cec5SDimitry Andric dbgs() << "\n"); 16710b57cec5SDimitry Andric 16720b57cec5SDimitry Andric // (4) Include all super-registers found in (3) into SRegs. 16730b57cec5SDimitry Andric SRegs |= TmpSup; 16740b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "SRegs.4: "; dump_registers(SRegs, *TRI); 16750b57cec5SDimitry Andric dbgs() << "\n"); 16760b57cec5SDimitry Andric 16770b57cec5SDimitry Andric // (5) For each register R in SRegs, if any super-register of R is in SRegs, 16780b57cec5SDimitry Andric // remove R from SRegs. 16790b57cec5SDimitry Andric for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) { 16800b57cec5SDimitry Andric unsigned R = x; 16810b57cec5SDimitry Andric for (MCSuperRegIterator SR(R, TRI); SR.isValid(); ++SR) { 16820b57cec5SDimitry Andric if (!SRegs[*SR]) 16830b57cec5SDimitry Andric continue; 16840b57cec5SDimitry Andric SRegs[R] = false; 16850b57cec5SDimitry Andric break; 16860b57cec5SDimitry Andric } 16870b57cec5SDimitry Andric } 16880b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "SRegs.5: "; dump_registers(SRegs, *TRI); 16890b57cec5SDimitry Andric dbgs() << "\n"); 16900b57cec5SDimitry Andric 16910b57cec5SDimitry Andric // Now, for each register that has a fixed stack slot, create the stack 16920b57cec5SDimitry Andric // object for it. 16930b57cec5SDimitry Andric CSI.clear(); 16940b57cec5SDimitry Andric 16950b57cec5SDimitry Andric using SpillSlot = TargetFrameLowering::SpillSlot; 16960b57cec5SDimitry Andric 16970b57cec5SDimitry Andric unsigned NumFixed; 16980b57cec5SDimitry Andric int MinOffset = 0; // CS offsets are negative. 16990b57cec5SDimitry Andric const SpillSlot *FixedSlots = getCalleeSavedSpillSlots(NumFixed); 17000b57cec5SDimitry Andric for (const SpillSlot *S = FixedSlots; S != FixedSlots+NumFixed; ++S) { 17010b57cec5SDimitry Andric if (!SRegs[S->Reg]) 17020b57cec5SDimitry Andric continue; 17030b57cec5SDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(S->Reg); 17040b57cec5SDimitry Andric int FI = MFI.CreateFixedSpillStackObject(TRI->getSpillSize(*RC), S->Offset); 17050b57cec5SDimitry Andric MinOffset = std::min(MinOffset, S->Offset); 17060b57cec5SDimitry Andric CSI.push_back(CalleeSavedInfo(S->Reg, FI)); 17070b57cec5SDimitry Andric SRegs[S->Reg] = false; 17080b57cec5SDimitry Andric } 17090b57cec5SDimitry Andric 17100b57cec5SDimitry Andric // There can be some registers that don't have fixed slots. For example, 17110b57cec5SDimitry Andric // we need to store R0-R3 in functions with exception handling. For each 17120b57cec5SDimitry Andric // such register, create a non-fixed stack object. 17130b57cec5SDimitry Andric for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) { 17140b57cec5SDimitry Andric unsigned R = x; 17150b57cec5SDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(R); 17160b57cec5SDimitry Andric unsigned Size = TRI->getSpillSize(*RC); 17170b57cec5SDimitry Andric int Off = MinOffset - Size; 17185ffd83dbSDimitry Andric Align Alignment = std::min(TRI->getSpillAlign(*RC), getStackAlign()); 17195ffd83dbSDimitry Andric Off &= -Alignment.value(); 17200b57cec5SDimitry Andric int FI = MFI.CreateFixedSpillStackObject(Size, Off); 17210b57cec5SDimitry Andric MinOffset = std::min(MinOffset, Off); 17220b57cec5SDimitry Andric CSI.push_back(CalleeSavedInfo(R, FI)); 17230b57cec5SDimitry Andric SRegs[R] = false; 17240b57cec5SDimitry Andric } 17250b57cec5SDimitry Andric 17260b57cec5SDimitry Andric LLVM_DEBUG({ 17270b57cec5SDimitry Andric dbgs() << "CS information: {"; 17284824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 17294824e7fdSDimitry Andric int FI = I.getFrameIdx(); 17300b57cec5SDimitry Andric int Off = MFI.getObjectOffset(FI); 17314824e7fdSDimitry Andric dbgs() << ' ' << printReg(I.getReg(), TRI) << ":fi#" << FI << ":sp"; 17320b57cec5SDimitry Andric if (Off >= 0) 17330b57cec5SDimitry Andric dbgs() << '+'; 17340b57cec5SDimitry Andric dbgs() << Off; 17350b57cec5SDimitry Andric } 17360b57cec5SDimitry Andric dbgs() << " }\n"; 17370b57cec5SDimitry Andric }); 17380b57cec5SDimitry Andric 17390b57cec5SDimitry Andric #ifndef NDEBUG 17400b57cec5SDimitry Andric // Verify that all registers were handled. 17410b57cec5SDimitry Andric bool MissedReg = false; 17420b57cec5SDimitry Andric for (int x = SRegs.find_first(); x >= 0; x = SRegs.find_next(x)) { 17430b57cec5SDimitry Andric unsigned R = x; 17440b57cec5SDimitry Andric dbgs() << printReg(R, TRI) << ' '; 17450b57cec5SDimitry Andric MissedReg = true; 17460b57cec5SDimitry Andric } 17470b57cec5SDimitry Andric if (MissedReg) 17480b57cec5SDimitry Andric llvm_unreachable("...there are unhandled callee-saved registers!"); 17490b57cec5SDimitry Andric #endif 17500b57cec5SDimitry Andric 17510b57cec5SDimitry Andric return true; 17520b57cec5SDimitry Andric } 17530b57cec5SDimitry Andric 17540b57cec5SDimitry Andric bool HexagonFrameLowering::expandCopy(MachineBasicBlock &B, 17550b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 17560b57cec5SDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const { 17570b57cec5SDimitry Andric MachineInstr *MI = &*It; 17580b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 17598bcb0991SDimitry Andric Register DstR = MI->getOperand(0).getReg(); 17608bcb0991SDimitry Andric Register SrcR = MI->getOperand(1).getReg(); 17610b57cec5SDimitry Andric if (!Hexagon::ModRegsRegClass.contains(DstR) || 17620b57cec5SDimitry Andric !Hexagon::ModRegsRegClass.contains(SrcR)) 17630b57cec5SDimitry Andric return false; 17640b57cec5SDimitry Andric 17658bcb0991SDimitry Andric Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); 17660b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(TargetOpcode::COPY), TmpR).add(MI->getOperand(1)); 17670b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(TargetOpcode::COPY), DstR) 17680b57cec5SDimitry Andric .addReg(TmpR, RegState::Kill); 17690b57cec5SDimitry Andric 17700b57cec5SDimitry Andric NewRegs.push_back(TmpR); 17710b57cec5SDimitry Andric B.erase(It); 17720b57cec5SDimitry Andric return true; 17730b57cec5SDimitry Andric } 17740b57cec5SDimitry Andric 17750b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreInt(MachineBasicBlock &B, 17760b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 17770b57cec5SDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const { 17780b57cec5SDimitry Andric MachineInstr *MI = &*It; 17790b57cec5SDimitry Andric if (!MI->getOperand(0).isFI()) 17800b57cec5SDimitry Andric return false; 17810b57cec5SDimitry Andric 17820b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 17830b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 17848bcb0991SDimitry Andric Register SrcR = MI->getOperand(2).getReg(); 17850b57cec5SDimitry Andric bool IsKill = MI->getOperand(2).isKill(); 17860b57cec5SDimitry Andric int FI = MI->getOperand(0).getIndex(); 17870b57cec5SDimitry Andric 17880b57cec5SDimitry Andric // TmpR = C2_tfrpr SrcR if SrcR is a predicate register 17890b57cec5SDimitry Andric // TmpR = A2_tfrcrr SrcR if SrcR is a modifier register 17908bcb0991SDimitry Andric Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); 17910b57cec5SDimitry Andric unsigned TfrOpc = (Opc == Hexagon::STriw_pred) ? Hexagon::C2_tfrpr 17920b57cec5SDimitry Andric : Hexagon::A2_tfrcrr; 17930b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(TfrOpc), TmpR) 17940b57cec5SDimitry Andric .addReg(SrcR, getKillRegState(IsKill)); 17950b57cec5SDimitry Andric 17960b57cec5SDimitry Andric // S2_storeri_io FI, 0, TmpR 17970b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(Hexagon::S2_storeri_io)) 17980b57cec5SDimitry Andric .addFrameIndex(FI) 17990b57cec5SDimitry Andric .addImm(0) 18000b57cec5SDimitry Andric .addReg(TmpR, RegState::Kill) 18010b57cec5SDimitry Andric .cloneMemRefs(*MI); 18020b57cec5SDimitry Andric 18030b57cec5SDimitry Andric NewRegs.push_back(TmpR); 18040b57cec5SDimitry Andric B.erase(It); 18050b57cec5SDimitry Andric return true; 18060b57cec5SDimitry Andric } 18070b57cec5SDimitry Andric 18080b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadInt(MachineBasicBlock &B, 18090b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 18100b57cec5SDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const { 18110b57cec5SDimitry Andric MachineInstr *MI = &*It; 18120b57cec5SDimitry Andric if (!MI->getOperand(1).isFI()) 18130b57cec5SDimitry Andric return false; 18140b57cec5SDimitry Andric 18150b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 18160b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 18178bcb0991SDimitry Andric Register DstR = MI->getOperand(0).getReg(); 18180b57cec5SDimitry Andric int FI = MI->getOperand(1).getIndex(); 18190b57cec5SDimitry Andric 18200b57cec5SDimitry Andric // TmpR = L2_loadri_io FI, 0 18218bcb0991SDimitry Andric Register TmpR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); 18220b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(Hexagon::L2_loadri_io), TmpR) 18230b57cec5SDimitry Andric .addFrameIndex(FI) 18240b57cec5SDimitry Andric .addImm(0) 18250b57cec5SDimitry Andric .cloneMemRefs(*MI); 18260b57cec5SDimitry Andric 18270b57cec5SDimitry Andric // DstR = C2_tfrrp TmpR if DstR is a predicate register 18280b57cec5SDimitry Andric // DstR = A2_tfrrcr TmpR if DstR is a modifier register 18290b57cec5SDimitry Andric unsigned TfrOpc = (Opc == Hexagon::LDriw_pred) ? Hexagon::C2_tfrrp 18300b57cec5SDimitry Andric : Hexagon::A2_tfrrcr; 18310b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(TfrOpc), DstR) 18320b57cec5SDimitry Andric .addReg(TmpR, RegState::Kill); 18330b57cec5SDimitry Andric 18340b57cec5SDimitry Andric NewRegs.push_back(TmpR); 18350b57cec5SDimitry Andric B.erase(It); 18360b57cec5SDimitry Andric return true; 18370b57cec5SDimitry Andric } 18380b57cec5SDimitry Andric 18390b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVecPred(MachineBasicBlock &B, 18400b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 18410b57cec5SDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const { 18420b57cec5SDimitry Andric MachineInstr *MI = &*It; 18430b57cec5SDimitry Andric if (!MI->getOperand(0).isFI()) 18440b57cec5SDimitry Andric return false; 18450b57cec5SDimitry Andric 18460b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 18478bcb0991SDimitry Andric Register SrcR = MI->getOperand(2).getReg(); 18480b57cec5SDimitry Andric bool IsKill = MI->getOperand(2).isKill(); 18490b57cec5SDimitry Andric int FI = MI->getOperand(0).getIndex(); 18500b57cec5SDimitry Andric auto *RC = &Hexagon::HvxVRRegClass; 18510b57cec5SDimitry Andric 18520b57cec5SDimitry Andric // Insert transfer to general vector register. 18530b57cec5SDimitry Andric // TmpR0 = A2_tfrsi 0x01010101 18540b57cec5SDimitry Andric // TmpR1 = V6_vandqrt Qx, TmpR0 18550b57cec5SDimitry Andric // store FI, 0, TmpR1 18568bcb0991SDimitry Andric Register TmpR0 = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); 18578bcb0991SDimitry Andric Register TmpR1 = MRI.createVirtualRegister(RC); 18580b57cec5SDimitry Andric 18590b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(Hexagon::A2_tfrsi), TmpR0) 18600b57cec5SDimitry Andric .addImm(0x01010101); 18610b57cec5SDimitry Andric 18620b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(Hexagon::V6_vandqrt), TmpR1) 18630b57cec5SDimitry Andric .addReg(SrcR, getKillRegState(IsKill)) 18640b57cec5SDimitry Andric .addReg(TmpR0, RegState::Kill); 18650b57cec5SDimitry Andric 18660b57cec5SDimitry Andric auto *HRI = B.getParent()->getSubtarget<HexagonSubtarget>().getRegisterInfo(); 18670b57cec5SDimitry Andric HII.storeRegToStackSlot(B, It, TmpR1, true, FI, RC, HRI); 18680b57cec5SDimitry Andric expandStoreVec(B, std::prev(It), MRI, HII, NewRegs); 18690b57cec5SDimitry Andric 18700b57cec5SDimitry Andric NewRegs.push_back(TmpR0); 18710b57cec5SDimitry Andric NewRegs.push_back(TmpR1); 18720b57cec5SDimitry Andric B.erase(It); 18730b57cec5SDimitry Andric return true; 18740b57cec5SDimitry Andric } 18750b57cec5SDimitry Andric 18760b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVecPred(MachineBasicBlock &B, 18770b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 18780b57cec5SDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const { 18790b57cec5SDimitry Andric MachineInstr *MI = &*It; 18800b57cec5SDimitry Andric if (!MI->getOperand(1).isFI()) 18810b57cec5SDimitry Andric return false; 18820b57cec5SDimitry Andric 18830b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 18848bcb0991SDimitry Andric Register DstR = MI->getOperand(0).getReg(); 18850b57cec5SDimitry Andric int FI = MI->getOperand(1).getIndex(); 18860b57cec5SDimitry Andric auto *RC = &Hexagon::HvxVRRegClass; 18870b57cec5SDimitry Andric 18880b57cec5SDimitry Andric // TmpR0 = A2_tfrsi 0x01010101 18890b57cec5SDimitry Andric // TmpR1 = load FI, 0 18900b57cec5SDimitry Andric // DstR = V6_vandvrt TmpR1, TmpR0 18918bcb0991SDimitry Andric Register TmpR0 = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); 18928bcb0991SDimitry Andric Register TmpR1 = MRI.createVirtualRegister(RC); 18930b57cec5SDimitry Andric 18940b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(Hexagon::A2_tfrsi), TmpR0) 18950b57cec5SDimitry Andric .addImm(0x01010101); 18960b57cec5SDimitry Andric MachineFunction &MF = *B.getParent(); 18970b57cec5SDimitry Andric auto *HRI = MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 18980b57cec5SDimitry Andric HII.loadRegFromStackSlot(B, It, TmpR1, FI, RC, HRI); 18990b57cec5SDimitry Andric expandLoadVec(B, std::prev(It), MRI, HII, NewRegs); 19000b57cec5SDimitry Andric 19010b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(Hexagon::V6_vandvrt), DstR) 19020b57cec5SDimitry Andric .addReg(TmpR1, RegState::Kill) 19030b57cec5SDimitry Andric .addReg(TmpR0, RegState::Kill); 19040b57cec5SDimitry Andric 19050b57cec5SDimitry Andric NewRegs.push_back(TmpR0); 19060b57cec5SDimitry Andric NewRegs.push_back(TmpR1); 19070b57cec5SDimitry Andric B.erase(It); 19080b57cec5SDimitry Andric return true; 19090b57cec5SDimitry Andric } 19100b57cec5SDimitry Andric 19110b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVec2(MachineBasicBlock &B, 19120b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 19130b57cec5SDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const { 19140b57cec5SDimitry Andric MachineFunction &MF = *B.getParent(); 19150b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 19160b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 19170b57cec5SDimitry Andric MachineInstr *MI = &*It; 19180b57cec5SDimitry Andric if (!MI->getOperand(0).isFI()) 19190b57cec5SDimitry Andric return false; 19200b57cec5SDimitry Andric 19210b57cec5SDimitry Andric // It is possible that the double vector being stored is only partially 19220b57cec5SDimitry Andric // defined. From the point of view of the liveness tracking, it is ok to 19230b57cec5SDimitry Andric // store it as a whole, but if we break it up we may end up storing a 19240b57cec5SDimitry Andric // register that is entirely undefined. 19250b57cec5SDimitry Andric LivePhysRegs LPR(HRI); 19260b57cec5SDimitry Andric LPR.addLiveIns(B); 19270b57cec5SDimitry Andric SmallVector<std::pair<MCPhysReg, const MachineOperand*>,2> Clobbers; 19280b57cec5SDimitry Andric for (auto R = B.begin(); R != It; ++R) { 19290b57cec5SDimitry Andric Clobbers.clear(); 19300b57cec5SDimitry Andric LPR.stepForward(*R, Clobbers); 19310b57cec5SDimitry Andric } 19320b57cec5SDimitry Andric 19330b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 19348bcb0991SDimitry Andric Register SrcR = MI->getOperand(2).getReg(); 19358bcb0991SDimitry Andric Register SrcLo = HRI.getSubReg(SrcR, Hexagon::vsub_lo); 19368bcb0991SDimitry Andric Register SrcHi = HRI.getSubReg(SrcR, Hexagon::vsub_hi); 19370b57cec5SDimitry Andric bool IsKill = MI->getOperand(2).isKill(); 19380b57cec5SDimitry Andric int FI = MI->getOperand(0).getIndex(); 1939480093f4SDimitry Andric bool NeedsAligna = needsAligna(MF); 19400b57cec5SDimitry Andric 19410b57cec5SDimitry Andric unsigned Size = HRI.getSpillSize(Hexagon::HvxVRRegClass); 19425ffd83dbSDimitry Andric Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass); 19435ffd83dbSDimitry Andric Align HasAlign = MFI.getObjectAlign(FI); 19440b57cec5SDimitry Andric unsigned StoreOpc; 19450b57cec5SDimitry Andric 19465ffd83dbSDimitry Andric auto UseAligned = [&](Align NeedAlign, Align HasAlign) { 1947480093f4SDimitry Andric return !NeedsAligna && (NeedAlign <= HasAlign); 1948480093f4SDimitry Andric }; 1949480093f4SDimitry Andric 19500b57cec5SDimitry Andric // Store low part. 19510b57cec5SDimitry Andric if (LPR.contains(SrcLo)) { 1952480093f4SDimitry Andric StoreOpc = UseAligned(NeedAlign, HasAlign) ? Hexagon::V6_vS32b_ai 19530b57cec5SDimitry Andric : Hexagon::V6_vS32Ub_ai; 19540b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(StoreOpc)) 19550b57cec5SDimitry Andric .addFrameIndex(FI) 19560b57cec5SDimitry Andric .addImm(0) 19570b57cec5SDimitry Andric .addReg(SrcLo, getKillRegState(IsKill)) 19580b57cec5SDimitry Andric .cloneMemRefs(*MI); 19590b57cec5SDimitry Andric } 19600b57cec5SDimitry Andric 19610b57cec5SDimitry Andric // Store high part. 19620b57cec5SDimitry Andric if (LPR.contains(SrcHi)) { 1963480093f4SDimitry Andric StoreOpc = UseAligned(NeedAlign, HasAlign) ? Hexagon::V6_vS32b_ai 19640b57cec5SDimitry Andric : Hexagon::V6_vS32Ub_ai; 19650b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(StoreOpc)) 19660b57cec5SDimitry Andric .addFrameIndex(FI) 19670b57cec5SDimitry Andric .addImm(Size) 19680b57cec5SDimitry Andric .addReg(SrcHi, getKillRegState(IsKill)) 19690b57cec5SDimitry Andric .cloneMemRefs(*MI); 19700b57cec5SDimitry Andric } 19710b57cec5SDimitry Andric 19720b57cec5SDimitry Andric B.erase(It); 19730b57cec5SDimitry Andric return true; 19740b57cec5SDimitry Andric } 19750b57cec5SDimitry Andric 19760b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVec2(MachineBasicBlock &B, 19770b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 19780b57cec5SDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const { 19790b57cec5SDimitry Andric MachineFunction &MF = *B.getParent(); 19800b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 19810b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 19820b57cec5SDimitry Andric MachineInstr *MI = &*It; 19830b57cec5SDimitry Andric if (!MI->getOperand(1).isFI()) 19840b57cec5SDimitry Andric return false; 19850b57cec5SDimitry Andric 19860b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 19878bcb0991SDimitry Andric Register DstR = MI->getOperand(0).getReg(); 19888bcb0991SDimitry Andric Register DstHi = HRI.getSubReg(DstR, Hexagon::vsub_hi); 19898bcb0991SDimitry Andric Register DstLo = HRI.getSubReg(DstR, Hexagon::vsub_lo); 19900b57cec5SDimitry Andric int FI = MI->getOperand(1).getIndex(); 1991480093f4SDimitry Andric bool NeedsAligna = needsAligna(MF); 19920b57cec5SDimitry Andric 19930b57cec5SDimitry Andric unsigned Size = HRI.getSpillSize(Hexagon::HvxVRRegClass); 19945ffd83dbSDimitry Andric Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass); 19955ffd83dbSDimitry Andric Align HasAlign = MFI.getObjectAlign(FI); 19960b57cec5SDimitry Andric unsigned LoadOpc; 19970b57cec5SDimitry Andric 19985ffd83dbSDimitry Andric auto UseAligned = [&](Align NeedAlign, Align HasAlign) { 1999480093f4SDimitry Andric return !NeedsAligna && (NeedAlign <= HasAlign); 2000480093f4SDimitry Andric }; 2001480093f4SDimitry Andric 20020b57cec5SDimitry Andric // Load low part. 2003480093f4SDimitry Andric LoadOpc = UseAligned(NeedAlign, HasAlign) ? Hexagon::V6_vL32b_ai 20040b57cec5SDimitry Andric : Hexagon::V6_vL32Ub_ai; 20050b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(LoadOpc), DstLo) 20060b57cec5SDimitry Andric .addFrameIndex(FI) 20070b57cec5SDimitry Andric .addImm(0) 20080b57cec5SDimitry Andric .cloneMemRefs(*MI); 20090b57cec5SDimitry Andric 20100b57cec5SDimitry Andric // Load high part. 2011480093f4SDimitry Andric LoadOpc = UseAligned(NeedAlign, HasAlign) ? Hexagon::V6_vL32b_ai 20120b57cec5SDimitry Andric : Hexagon::V6_vL32Ub_ai; 20130b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(LoadOpc), DstHi) 20140b57cec5SDimitry Andric .addFrameIndex(FI) 20150b57cec5SDimitry Andric .addImm(Size) 20160b57cec5SDimitry Andric .cloneMemRefs(*MI); 20170b57cec5SDimitry Andric 20180b57cec5SDimitry Andric B.erase(It); 20190b57cec5SDimitry Andric return true; 20200b57cec5SDimitry Andric } 20210b57cec5SDimitry Andric 20220b57cec5SDimitry Andric bool HexagonFrameLowering::expandStoreVec(MachineBasicBlock &B, 20230b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 20240b57cec5SDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const { 20250b57cec5SDimitry Andric MachineFunction &MF = *B.getParent(); 20260b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 20270b57cec5SDimitry Andric MachineInstr *MI = &*It; 20280b57cec5SDimitry Andric if (!MI->getOperand(0).isFI()) 20290b57cec5SDimitry Andric return false; 20300b57cec5SDimitry Andric 2031480093f4SDimitry Andric bool NeedsAligna = needsAligna(MF); 20320b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 20330b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 20348bcb0991SDimitry Andric Register SrcR = MI->getOperand(2).getReg(); 20350b57cec5SDimitry Andric bool IsKill = MI->getOperand(2).isKill(); 20360b57cec5SDimitry Andric int FI = MI->getOperand(0).getIndex(); 20370b57cec5SDimitry Andric 20385ffd83dbSDimitry Andric Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass); 20395ffd83dbSDimitry Andric Align HasAlign = MFI.getObjectAlign(FI); 2040480093f4SDimitry Andric bool UseAligned = !NeedsAligna && (NeedAlign <= HasAlign); 2041480093f4SDimitry Andric unsigned StoreOpc = UseAligned ? Hexagon::V6_vS32b_ai 20420b57cec5SDimitry Andric : Hexagon::V6_vS32Ub_ai; 20430b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(StoreOpc)) 20440b57cec5SDimitry Andric .addFrameIndex(FI) 20450b57cec5SDimitry Andric .addImm(0) 20460b57cec5SDimitry Andric .addReg(SrcR, getKillRegState(IsKill)) 20470b57cec5SDimitry Andric .cloneMemRefs(*MI); 20480b57cec5SDimitry Andric 20490b57cec5SDimitry Andric B.erase(It); 20500b57cec5SDimitry Andric return true; 20510b57cec5SDimitry Andric } 20520b57cec5SDimitry Andric 20530b57cec5SDimitry Andric bool HexagonFrameLowering::expandLoadVec(MachineBasicBlock &B, 20540b57cec5SDimitry Andric MachineBasicBlock::iterator It, MachineRegisterInfo &MRI, 20550b57cec5SDimitry Andric const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const { 20560b57cec5SDimitry Andric MachineFunction &MF = *B.getParent(); 20570b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 20580b57cec5SDimitry Andric MachineInstr *MI = &*It; 20590b57cec5SDimitry Andric if (!MI->getOperand(1).isFI()) 20600b57cec5SDimitry Andric return false; 20610b57cec5SDimitry Andric 2062480093f4SDimitry Andric bool NeedsAligna = needsAligna(MF); 20630b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 20640b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 20658bcb0991SDimitry Andric Register DstR = MI->getOperand(0).getReg(); 20660b57cec5SDimitry Andric int FI = MI->getOperand(1).getIndex(); 20670b57cec5SDimitry Andric 20685ffd83dbSDimitry Andric Align NeedAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass); 20695ffd83dbSDimitry Andric Align HasAlign = MFI.getObjectAlign(FI); 2070480093f4SDimitry Andric bool UseAligned = !NeedsAligna && (NeedAlign <= HasAlign); 2071480093f4SDimitry Andric unsigned LoadOpc = UseAligned ? Hexagon::V6_vL32b_ai 20720b57cec5SDimitry Andric : Hexagon::V6_vL32Ub_ai; 20730b57cec5SDimitry Andric BuildMI(B, It, DL, HII.get(LoadOpc), DstR) 20740b57cec5SDimitry Andric .addFrameIndex(FI) 20750b57cec5SDimitry Andric .addImm(0) 20760b57cec5SDimitry Andric .cloneMemRefs(*MI); 20770b57cec5SDimitry Andric 20780b57cec5SDimitry Andric B.erase(It); 20790b57cec5SDimitry Andric return true; 20800b57cec5SDimitry Andric } 20810b57cec5SDimitry Andric 20820b57cec5SDimitry Andric bool HexagonFrameLowering::expandSpillMacros(MachineFunction &MF, 20830b57cec5SDimitry Andric SmallVectorImpl<unsigned> &NewRegs) const { 20840b57cec5SDimitry Andric auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo(); 20850b57cec5SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 20860b57cec5SDimitry Andric bool Changed = false; 20870b57cec5SDimitry Andric 20880b57cec5SDimitry Andric for (auto &B : MF) { 20890b57cec5SDimitry Andric // Traverse the basic block. 20900b57cec5SDimitry Andric MachineBasicBlock::iterator NextI; 20910b57cec5SDimitry Andric for (auto I = B.begin(), E = B.end(); I != E; I = NextI) { 20920b57cec5SDimitry Andric MachineInstr *MI = &*I; 20930b57cec5SDimitry Andric NextI = std::next(I); 20940b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 20950b57cec5SDimitry Andric 20960b57cec5SDimitry Andric switch (Opc) { 20970b57cec5SDimitry Andric case TargetOpcode::COPY: 20980b57cec5SDimitry Andric Changed |= expandCopy(B, I, MRI, HII, NewRegs); 20990b57cec5SDimitry Andric break; 21000b57cec5SDimitry Andric case Hexagon::STriw_pred: 21010b57cec5SDimitry Andric case Hexagon::STriw_ctr: 21020b57cec5SDimitry Andric Changed |= expandStoreInt(B, I, MRI, HII, NewRegs); 21030b57cec5SDimitry Andric break; 21040b57cec5SDimitry Andric case Hexagon::LDriw_pred: 21050b57cec5SDimitry Andric case Hexagon::LDriw_ctr: 21060b57cec5SDimitry Andric Changed |= expandLoadInt(B, I, MRI, HII, NewRegs); 21070b57cec5SDimitry Andric break; 21080b57cec5SDimitry Andric case Hexagon::PS_vstorerq_ai: 21090b57cec5SDimitry Andric Changed |= expandStoreVecPred(B, I, MRI, HII, NewRegs); 21100b57cec5SDimitry Andric break; 21110b57cec5SDimitry Andric case Hexagon::PS_vloadrq_ai: 21120b57cec5SDimitry Andric Changed |= expandLoadVecPred(B, I, MRI, HII, NewRegs); 21130b57cec5SDimitry Andric break; 21140b57cec5SDimitry Andric case Hexagon::PS_vloadrw_ai: 21150b57cec5SDimitry Andric Changed |= expandLoadVec2(B, I, MRI, HII, NewRegs); 21160b57cec5SDimitry Andric break; 21170b57cec5SDimitry Andric case Hexagon::PS_vstorerw_ai: 21180b57cec5SDimitry Andric Changed |= expandStoreVec2(B, I, MRI, HII, NewRegs); 21190b57cec5SDimitry Andric break; 21200b57cec5SDimitry Andric } 21210b57cec5SDimitry Andric } 21220b57cec5SDimitry Andric } 21230b57cec5SDimitry Andric 21240b57cec5SDimitry Andric return Changed; 21250b57cec5SDimitry Andric } 21260b57cec5SDimitry Andric 21270b57cec5SDimitry Andric void HexagonFrameLowering::determineCalleeSaves(MachineFunction &MF, 21280b57cec5SDimitry Andric BitVector &SavedRegs, 21290b57cec5SDimitry Andric RegScavenger *RS) const { 21300b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 21310b57cec5SDimitry Andric 21320b57cec5SDimitry Andric SavedRegs.resize(HRI.getNumRegs()); 21330b57cec5SDimitry Andric 21340b57cec5SDimitry Andric // If we have a function containing __builtin_eh_return we want to spill and 21350b57cec5SDimitry Andric // restore all callee saved registers. Pretend that they are used. 21360b57cec5SDimitry Andric if (MF.getInfo<HexagonMachineFunctionInfo>()->hasEHReturn()) 21370b57cec5SDimitry Andric for (const MCPhysReg *R = HRI.getCalleeSavedRegs(&MF); *R; ++R) 21380b57cec5SDimitry Andric SavedRegs.set(*R); 21390b57cec5SDimitry Andric 21400b57cec5SDimitry Andric // Replace predicate register pseudo spill code. 21410b57cec5SDimitry Andric SmallVector<unsigned,8> NewRegs; 21420b57cec5SDimitry Andric expandSpillMacros(MF, NewRegs); 21430b57cec5SDimitry Andric if (OptimizeSpillSlots && !isOptNone(MF)) 21440b57cec5SDimitry Andric optimizeSpillSlots(MF, NewRegs); 21450b57cec5SDimitry Andric 21460b57cec5SDimitry Andric // We need to reserve a spill slot if scavenging could potentially require 21470b57cec5SDimitry Andric // spilling a scavenged register. 21480b57cec5SDimitry Andric if (!NewRegs.empty() || mayOverflowFrameOffset(MF)) { 21490b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 21500b57cec5SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 21510b57cec5SDimitry Andric SetVector<const TargetRegisterClass*> SpillRCs; 21520b57cec5SDimitry Andric // Reserve an int register in any case, because it could be used to hold 21530b57cec5SDimitry Andric // the stack offset in case it does not fit into a spill instruction. 21540b57cec5SDimitry Andric SpillRCs.insert(&Hexagon::IntRegsRegClass); 21550b57cec5SDimitry Andric 21560b57cec5SDimitry Andric for (unsigned VR : NewRegs) 21570b57cec5SDimitry Andric SpillRCs.insert(MRI.getRegClass(VR)); 21580b57cec5SDimitry Andric 21590b57cec5SDimitry Andric for (auto *RC : SpillRCs) { 21600b57cec5SDimitry Andric if (!needToReserveScavengingSpillSlots(MF, HRI, RC)) 21610b57cec5SDimitry Andric continue; 2162480093f4SDimitry Andric unsigned Num = 1; 2163480093f4SDimitry Andric switch (RC->getID()) { 2164480093f4SDimitry Andric case Hexagon::IntRegsRegClassID: 2165480093f4SDimitry Andric Num = NumberScavengerSlots; 2166480093f4SDimitry Andric break; 2167480093f4SDimitry Andric case Hexagon::HvxQRRegClassID: 2168480093f4SDimitry Andric Num = 2; // Vector predicate spills also need a vector register. 2169480093f4SDimitry Andric break; 2170480093f4SDimitry Andric } 21715ffd83dbSDimitry Andric unsigned S = HRI.getSpillSize(*RC); 21725ffd83dbSDimitry Andric Align A = HRI.getSpillAlign(*RC); 21730b57cec5SDimitry Andric for (unsigned i = 0; i < Num; i++) { 21740b57cec5SDimitry Andric int NewFI = MFI.CreateSpillStackObject(S, A); 21750b57cec5SDimitry Andric RS->addScavengingFrameIndex(NewFI); 21760b57cec5SDimitry Andric } 21770b57cec5SDimitry Andric } 21780b57cec5SDimitry Andric } 21790b57cec5SDimitry Andric 21800b57cec5SDimitry Andric TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 21810b57cec5SDimitry Andric } 21820b57cec5SDimitry Andric 21830b57cec5SDimitry Andric unsigned HexagonFrameLowering::findPhysReg(MachineFunction &MF, 21840b57cec5SDimitry Andric HexagonBlockRanges::IndexRange &FIR, 21850b57cec5SDimitry Andric HexagonBlockRanges::InstrIndexMap &IndexMap, 21860b57cec5SDimitry Andric HexagonBlockRanges::RegToRangeMap &DeadMap, 21870b57cec5SDimitry Andric const TargetRegisterClass *RC) const { 21880b57cec5SDimitry Andric auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 21890b57cec5SDimitry Andric auto &MRI = MF.getRegInfo(); 21900b57cec5SDimitry Andric 21910b57cec5SDimitry Andric auto isDead = [&FIR,&DeadMap] (unsigned Reg) -> bool { 21920b57cec5SDimitry Andric auto F = DeadMap.find({Reg,0}); 21930b57cec5SDimitry Andric if (F == DeadMap.end()) 21940b57cec5SDimitry Andric return false; 21950b57cec5SDimitry Andric for (auto &DR : F->second) 21960b57cec5SDimitry Andric if (DR.contains(FIR)) 21970b57cec5SDimitry Andric return true; 21980b57cec5SDimitry Andric return false; 21990b57cec5SDimitry Andric }; 22000b57cec5SDimitry Andric 22010b57cec5SDimitry Andric for (unsigned Reg : RC->getRawAllocationOrder(MF)) { 22020b57cec5SDimitry Andric bool Dead = true; 22030b57cec5SDimitry Andric for (auto R : HexagonBlockRanges::expandToSubRegs({Reg,0}, MRI, HRI)) { 22040b57cec5SDimitry Andric if (isDead(R.Reg)) 22050b57cec5SDimitry Andric continue; 22060b57cec5SDimitry Andric Dead = false; 22070b57cec5SDimitry Andric break; 22080b57cec5SDimitry Andric } 22090b57cec5SDimitry Andric if (Dead) 22100b57cec5SDimitry Andric return Reg; 22110b57cec5SDimitry Andric } 22120b57cec5SDimitry Andric return 0; 22130b57cec5SDimitry Andric } 22140b57cec5SDimitry Andric 22150b57cec5SDimitry Andric void HexagonFrameLowering::optimizeSpillSlots(MachineFunction &MF, 22160b57cec5SDimitry Andric SmallVectorImpl<unsigned> &VRegs) const { 22170b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 22180b57cec5SDimitry Andric auto &HII = *HST.getInstrInfo(); 22190b57cec5SDimitry Andric auto &HRI = *HST.getRegisterInfo(); 22200b57cec5SDimitry Andric auto &MRI = MF.getRegInfo(); 22210b57cec5SDimitry Andric HexagonBlockRanges HBR(MF); 22220b57cec5SDimitry Andric 22230b57cec5SDimitry Andric using BlockIndexMap = 22240b57cec5SDimitry Andric std::map<MachineBasicBlock *, HexagonBlockRanges::InstrIndexMap>; 22250b57cec5SDimitry Andric using BlockRangeMap = 22260b57cec5SDimitry Andric std::map<MachineBasicBlock *, HexagonBlockRanges::RangeList>; 22270b57cec5SDimitry Andric using IndexType = HexagonBlockRanges::IndexType; 22280b57cec5SDimitry Andric 22290b57cec5SDimitry Andric struct SlotInfo { 22300b57cec5SDimitry Andric BlockRangeMap Map; 22310b57cec5SDimitry Andric unsigned Size = 0; 22320b57cec5SDimitry Andric const TargetRegisterClass *RC = nullptr; 22330b57cec5SDimitry Andric 22340b57cec5SDimitry Andric SlotInfo() = default; 22350b57cec5SDimitry Andric }; 22360b57cec5SDimitry Andric 22370b57cec5SDimitry Andric BlockIndexMap BlockIndexes; 22380b57cec5SDimitry Andric SmallSet<int,4> BadFIs; 22390b57cec5SDimitry Andric std::map<int,SlotInfo> FIRangeMap; 22400b57cec5SDimitry Andric 22410b57cec5SDimitry Andric // Accumulate register classes: get a common class for a pre-existing 22420b57cec5SDimitry Andric // class HaveRC and a new class NewRC. Return nullptr if a common class 22430b57cec5SDimitry Andric // cannot be found, otherwise return the resulting class. If HaveRC is 22440b57cec5SDimitry Andric // nullptr, assume that it is still unset. 22450b57cec5SDimitry Andric auto getCommonRC = 22460b57cec5SDimitry Andric [](const TargetRegisterClass *HaveRC, 22470b57cec5SDimitry Andric const TargetRegisterClass *NewRC) -> const TargetRegisterClass * { 22480b57cec5SDimitry Andric if (HaveRC == nullptr || HaveRC == NewRC) 22490b57cec5SDimitry Andric return NewRC; 22500b57cec5SDimitry Andric // Different classes, both non-null. Pick the more general one. 22510b57cec5SDimitry Andric if (HaveRC->hasSubClassEq(NewRC)) 22520b57cec5SDimitry Andric return HaveRC; 22530b57cec5SDimitry Andric if (NewRC->hasSubClassEq(HaveRC)) 22540b57cec5SDimitry Andric return NewRC; 22550b57cec5SDimitry Andric return nullptr; 22560b57cec5SDimitry Andric }; 22570b57cec5SDimitry Andric 22580b57cec5SDimitry Andric // Scan all blocks in the function. Check all occurrences of frame indexes, 22590b57cec5SDimitry Andric // and collect relevant information. 22600b57cec5SDimitry Andric for (auto &B : MF) { 22610b57cec5SDimitry Andric std::map<int,IndexType> LastStore, LastLoad; 22620b57cec5SDimitry Andric // Emplace appears not to be supported in gcc 4.7.2-4. 22630b57cec5SDimitry Andric //auto P = BlockIndexes.emplace(&B, HexagonBlockRanges::InstrIndexMap(B)); 22640b57cec5SDimitry Andric auto P = BlockIndexes.insert( 22650b57cec5SDimitry Andric std::make_pair(&B, HexagonBlockRanges::InstrIndexMap(B))); 22660b57cec5SDimitry Andric auto &IndexMap = P.first->second; 22670b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Index map for " << printMBBReference(B) << "\n" 22680b57cec5SDimitry Andric << IndexMap << '\n'); 22690b57cec5SDimitry Andric 22700b57cec5SDimitry Andric for (auto &In : B) { 22710b57cec5SDimitry Andric int LFI, SFI; 22720b57cec5SDimitry Andric bool Load = HII.isLoadFromStackSlot(In, LFI) && !HII.isPredicated(In); 22730b57cec5SDimitry Andric bool Store = HII.isStoreToStackSlot(In, SFI) && !HII.isPredicated(In); 22740b57cec5SDimitry Andric if (Load && Store) { 22750b57cec5SDimitry Andric // If it's both a load and a store, then we won't handle it. 22760b57cec5SDimitry Andric BadFIs.insert(LFI); 22770b57cec5SDimitry Andric BadFIs.insert(SFI); 22780b57cec5SDimitry Andric continue; 22790b57cec5SDimitry Andric } 22800b57cec5SDimitry Andric // Check for register classes of the register used as the source for 22810b57cec5SDimitry Andric // the store, and the register used as the destination for the load. 22820b57cec5SDimitry Andric // Also, only accept base+imm_offset addressing modes. Other addressing 22830b57cec5SDimitry Andric // modes can have side-effects (post-increments, etc.). For stack 22840b57cec5SDimitry Andric // slots they are very unlikely, so there is not much loss due to 22850b57cec5SDimitry Andric // this restriction. 22860b57cec5SDimitry Andric if (Load || Store) { 22870b57cec5SDimitry Andric int TFI = Load ? LFI : SFI; 22880b57cec5SDimitry Andric unsigned AM = HII.getAddrMode(In); 22890b57cec5SDimitry Andric SlotInfo &SI = FIRangeMap[TFI]; 22900b57cec5SDimitry Andric bool Bad = (AM != HexagonII::BaseImmOffset); 22910b57cec5SDimitry Andric if (!Bad) { 22920b57cec5SDimitry Andric // If the addressing mode is ok, check the register class. 22930b57cec5SDimitry Andric unsigned OpNum = Load ? 0 : 2; 22940b57cec5SDimitry Andric auto *RC = HII.getRegClass(In.getDesc(), OpNum, &HRI, MF); 22950b57cec5SDimitry Andric RC = getCommonRC(SI.RC, RC); 22960b57cec5SDimitry Andric if (RC == nullptr) 22970b57cec5SDimitry Andric Bad = true; 22980b57cec5SDimitry Andric else 22990b57cec5SDimitry Andric SI.RC = RC; 23000b57cec5SDimitry Andric } 23010b57cec5SDimitry Andric if (!Bad) { 23020b57cec5SDimitry Andric // Check sizes. 23030b57cec5SDimitry Andric unsigned S = HII.getMemAccessSize(In); 23040b57cec5SDimitry Andric if (SI.Size != 0 && SI.Size != S) 23050b57cec5SDimitry Andric Bad = true; 23060b57cec5SDimitry Andric else 23070b57cec5SDimitry Andric SI.Size = S; 23080b57cec5SDimitry Andric } 23090b57cec5SDimitry Andric if (!Bad) { 23100b57cec5SDimitry Andric for (auto *Mo : In.memoperands()) { 23110b57cec5SDimitry Andric if (!Mo->isVolatile() && !Mo->isAtomic()) 23120b57cec5SDimitry Andric continue; 23130b57cec5SDimitry Andric Bad = true; 23140b57cec5SDimitry Andric break; 23150b57cec5SDimitry Andric } 23160b57cec5SDimitry Andric } 23170b57cec5SDimitry Andric if (Bad) 23180b57cec5SDimitry Andric BadFIs.insert(TFI); 23190b57cec5SDimitry Andric } 23200b57cec5SDimitry Andric 23210b57cec5SDimitry Andric // Locate uses of frame indices. 23220b57cec5SDimitry Andric for (unsigned i = 0, n = In.getNumOperands(); i < n; ++i) { 23230b57cec5SDimitry Andric const MachineOperand &Op = In.getOperand(i); 23240b57cec5SDimitry Andric if (!Op.isFI()) 23250b57cec5SDimitry Andric continue; 23260b57cec5SDimitry Andric int FI = Op.getIndex(); 23270b57cec5SDimitry Andric // Make sure that the following operand is an immediate and that 23280b57cec5SDimitry Andric // it is 0. This is the offset in the stack object. 23290b57cec5SDimitry Andric if (i+1 >= n || !In.getOperand(i+1).isImm() || 23300b57cec5SDimitry Andric In.getOperand(i+1).getImm() != 0) 23310b57cec5SDimitry Andric BadFIs.insert(FI); 23320b57cec5SDimitry Andric if (BadFIs.count(FI)) 23330b57cec5SDimitry Andric continue; 23340b57cec5SDimitry Andric 23350b57cec5SDimitry Andric IndexType Index = IndexMap.getIndex(&In); 23360b57cec5SDimitry Andric if (Load) { 23370b57cec5SDimitry Andric if (LastStore[FI] == IndexType::None) 23380b57cec5SDimitry Andric LastStore[FI] = IndexType::Entry; 23390b57cec5SDimitry Andric LastLoad[FI] = Index; 23400b57cec5SDimitry Andric } else if (Store) { 23410b57cec5SDimitry Andric HexagonBlockRanges::RangeList &RL = FIRangeMap[FI].Map[&B]; 23420b57cec5SDimitry Andric if (LastStore[FI] != IndexType::None) 23430b57cec5SDimitry Andric RL.add(LastStore[FI], LastLoad[FI], false, false); 23440b57cec5SDimitry Andric else if (LastLoad[FI] != IndexType::None) 23450b57cec5SDimitry Andric RL.add(IndexType::Entry, LastLoad[FI], false, false); 23460b57cec5SDimitry Andric LastLoad[FI] = IndexType::None; 23470b57cec5SDimitry Andric LastStore[FI] = Index; 23480b57cec5SDimitry Andric } else { 23490b57cec5SDimitry Andric BadFIs.insert(FI); 23500b57cec5SDimitry Andric } 23510b57cec5SDimitry Andric } 23520b57cec5SDimitry Andric } 23530b57cec5SDimitry Andric 23540b57cec5SDimitry Andric for (auto &I : LastLoad) { 23550b57cec5SDimitry Andric IndexType LL = I.second; 23560b57cec5SDimitry Andric if (LL == IndexType::None) 23570b57cec5SDimitry Andric continue; 23580b57cec5SDimitry Andric auto &RL = FIRangeMap[I.first].Map[&B]; 23590b57cec5SDimitry Andric IndexType &LS = LastStore[I.first]; 23600b57cec5SDimitry Andric if (LS != IndexType::None) 23610b57cec5SDimitry Andric RL.add(LS, LL, false, false); 23620b57cec5SDimitry Andric else 23630b57cec5SDimitry Andric RL.add(IndexType::Entry, LL, false, false); 23640b57cec5SDimitry Andric LS = IndexType::None; 23650b57cec5SDimitry Andric } 23660b57cec5SDimitry Andric for (auto &I : LastStore) { 23670b57cec5SDimitry Andric IndexType LS = I.second; 23680b57cec5SDimitry Andric if (LS == IndexType::None) 23690b57cec5SDimitry Andric continue; 23700b57cec5SDimitry Andric auto &RL = FIRangeMap[I.first].Map[&B]; 23710b57cec5SDimitry Andric RL.add(LS, IndexType::None, false, false); 23720b57cec5SDimitry Andric } 23730b57cec5SDimitry Andric } 23740b57cec5SDimitry Andric 23750b57cec5SDimitry Andric LLVM_DEBUG({ 23760b57cec5SDimitry Andric for (auto &P : FIRangeMap) { 23770b57cec5SDimitry Andric dbgs() << "fi#" << P.first; 23780b57cec5SDimitry Andric if (BadFIs.count(P.first)) 23790b57cec5SDimitry Andric dbgs() << " (bad)"; 23800b57cec5SDimitry Andric dbgs() << " RC: "; 23810b57cec5SDimitry Andric if (P.second.RC != nullptr) 23820b57cec5SDimitry Andric dbgs() << HRI.getRegClassName(P.second.RC) << '\n'; 23830b57cec5SDimitry Andric else 23840b57cec5SDimitry Andric dbgs() << "<null>\n"; 23850b57cec5SDimitry Andric for (auto &R : P.second.Map) 23860b57cec5SDimitry Andric dbgs() << " " << printMBBReference(*R.first) << " { " << R.second 23870b57cec5SDimitry Andric << "}\n"; 23880b57cec5SDimitry Andric } 23890b57cec5SDimitry Andric }); 23900b57cec5SDimitry Andric 23910b57cec5SDimitry Andric // When a slot is loaded from in a block without being stored to in the 23920b57cec5SDimitry Andric // same block, it is live-on-entry to this block. To avoid CFG analysis, 23930b57cec5SDimitry Andric // consider this slot to be live-on-exit from all blocks. 23940b57cec5SDimitry Andric SmallSet<int,4> LoxFIs; 23950b57cec5SDimitry Andric 23960b57cec5SDimitry Andric std::map<MachineBasicBlock*,std::vector<int>> BlockFIMap; 23970b57cec5SDimitry Andric 23980b57cec5SDimitry Andric for (auto &P : FIRangeMap) { 23990b57cec5SDimitry Andric // P = pair(FI, map: BB->RangeList) 24000b57cec5SDimitry Andric if (BadFIs.count(P.first)) 24010b57cec5SDimitry Andric continue; 24020b57cec5SDimitry Andric for (auto &B : MF) { 24030b57cec5SDimitry Andric auto F = P.second.Map.find(&B); 24040b57cec5SDimitry Andric // F = pair(BB, RangeList) 24050b57cec5SDimitry Andric if (F == P.second.Map.end() || F->second.empty()) 24060b57cec5SDimitry Andric continue; 24070b57cec5SDimitry Andric HexagonBlockRanges::IndexRange &IR = F->second.front(); 24080b57cec5SDimitry Andric if (IR.start() == IndexType::Entry) 24090b57cec5SDimitry Andric LoxFIs.insert(P.first); 24100b57cec5SDimitry Andric BlockFIMap[&B].push_back(P.first); 24110b57cec5SDimitry Andric } 24120b57cec5SDimitry Andric } 24130b57cec5SDimitry Andric 24140b57cec5SDimitry Andric LLVM_DEBUG({ 24150b57cec5SDimitry Andric dbgs() << "Block-to-FI map (* -- live-on-exit):\n"; 24160b57cec5SDimitry Andric for (auto &P : BlockFIMap) { 24170b57cec5SDimitry Andric auto &FIs = P.second; 24180b57cec5SDimitry Andric if (FIs.empty()) 24190b57cec5SDimitry Andric continue; 24200b57cec5SDimitry Andric dbgs() << " " << printMBBReference(*P.first) << ": {"; 24210b57cec5SDimitry Andric for (auto I : FIs) { 24220b57cec5SDimitry Andric dbgs() << " fi#" << I; 24230b57cec5SDimitry Andric if (LoxFIs.count(I)) 24240b57cec5SDimitry Andric dbgs() << '*'; 24250b57cec5SDimitry Andric } 24260b57cec5SDimitry Andric dbgs() << " }\n"; 24270b57cec5SDimitry Andric } 24280b57cec5SDimitry Andric }); 24290b57cec5SDimitry Andric 24300b57cec5SDimitry Andric #ifndef NDEBUG 24310b57cec5SDimitry Andric bool HasOptLimit = SpillOptMax.getPosition(); 24320b57cec5SDimitry Andric #endif 24330b57cec5SDimitry Andric 24340b57cec5SDimitry Andric // eliminate loads, when all loads eliminated, eliminate all stores. 24350b57cec5SDimitry Andric for (auto &B : MF) { 24360b57cec5SDimitry Andric auto F = BlockIndexes.find(&B); 24370b57cec5SDimitry Andric assert(F != BlockIndexes.end()); 24380b57cec5SDimitry Andric HexagonBlockRanges::InstrIndexMap &IM = F->second; 24390b57cec5SDimitry Andric HexagonBlockRanges::RegToRangeMap LM = HBR.computeLiveMap(IM); 24400b57cec5SDimitry Andric HexagonBlockRanges::RegToRangeMap DM = HBR.computeDeadMap(IM, LM); 24410b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << printMBBReference(B) << " dead map\n" 24420b57cec5SDimitry Andric << HexagonBlockRanges::PrintRangeMap(DM, HRI)); 24430b57cec5SDimitry Andric 24440b57cec5SDimitry Andric for (auto FI : BlockFIMap[&B]) { 24450b57cec5SDimitry Andric if (BadFIs.count(FI)) 24460b57cec5SDimitry Andric continue; 24470b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Working on fi#" << FI << '\n'); 24480b57cec5SDimitry Andric HexagonBlockRanges::RangeList &RL = FIRangeMap[FI].Map[&B]; 24490b57cec5SDimitry Andric for (auto &Range : RL) { 24500b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "--Examining range:" << RL << '\n'); 24510b57cec5SDimitry Andric if (!IndexType::isInstr(Range.start()) || 24520b57cec5SDimitry Andric !IndexType::isInstr(Range.end())) 24530b57cec5SDimitry Andric continue; 24540b57cec5SDimitry Andric MachineInstr &SI = *IM.getInstr(Range.start()); 24550b57cec5SDimitry Andric MachineInstr &EI = *IM.getInstr(Range.end()); 24560b57cec5SDimitry Andric assert(SI.mayStore() && "Unexpected start instruction"); 24570b57cec5SDimitry Andric assert(EI.mayLoad() && "Unexpected end instruction"); 24580b57cec5SDimitry Andric MachineOperand &SrcOp = SI.getOperand(2); 24590b57cec5SDimitry Andric 24600b57cec5SDimitry Andric HexagonBlockRanges::RegisterRef SrcRR = { SrcOp.getReg(), 24610b57cec5SDimitry Andric SrcOp.getSubReg() }; 24620b57cec5SDimitry Andric auto *RC = HII.getRegClass(SI.getDesc(), 2, &HRI, MF); 24630b57cec5SDimitry Andric // The this-> is needed to unconfuse MSVC. 24640b57cec5SDimitry Andric unsigned FoundR = this->findPhysReg(MF, Range, IM, DM, RC); 24650b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Replacement reg:" << printReg(FoundR, &HRI) 24660b57cec5SDimitry Andric << '\n'); 24670b57cec5SDimitry Andric if (FoundR == 0) 24680b57cec5SDimitry Andric continue; 24690b57cec5SDimitry Andric #ifndef NDEBUG 24700b57cec5SDimitry Andric if (HasOptLimit) { 24710b57cec5SDimitry Andric if (SpillOptCount >= SpillOptMax) 24720b57cec5SDimitry Andric return; 24730b57cec5SDimitry Andric SpillOptCount++; 24740b57cec5SDimitry Andric } 24750b57cec5SDimitry Andric #endif 24760b57cec5SDimitry Andric 24770b57cec5SDimitry Andric // Generate the copy-in: "FoundR = COPY SrcR" at the store location. 24780b57cec5SDimitry Andric MachineBasicBlock::iterator StartIt = SI.getIterator(), NextIt; 24790b57cec5SDimitry Andric MachineInstr *CopyIn = nullptr; 24800b57cec5SDimitry Andric if (SrcRR.Reg != FoundR || SrcRR.Sub != 0) { 24810b57cec5SDimitry Andric const DebugLoc &DL = SI.getDebugLoc(); 24820b57cec5SDimitry Andric CopyIn = BuildMI(B, StartIt, DL, HII.get(TargetOpcode::COPY), FoundR) 24830b57cec5SDimitry Andric .add(SrcOp); 24840b57cec5SDimitry Andric } 24850b57cec5SDimitry Andric 24860b57cec5SDimitry Andric ++StartIt; 24870b57cec5SDimitry Andric // Check if this is a last store and the FI is live-on-exit. 24880b57cec5SDimitry Andric if (LoxFIs.count(FI) && (&Range == &RL.back())) { 24890b57cec5SDimitry Andric // Update store's source register. 24900b57cec5SDimitry Andric if (unsigned SR = SrcOp.getSubReg()) 24910b57cec5SDimitry Andric SrcOp.setReg(HRI.getSubReg(FoundR, SR)); 24920b57cec5SDimitry Andric else 24930b57cec5SDimitry Andric SrcOp.setReg(FoundR); 24940b57cec5SDimitry Andric SrcOp.setSubReg(0); 24950b57cec5SDimitry Andric // We are keeping this register live. 24960b57cec5SDimitry Andric SrcOp.setIsKill(false); 24970b57cec5SDimitry Andric } else { 24980b57cec5SDimitry Andric B.erase(&SI); 24990b57cec5SDimitry Andric IM.replaceInstr(&SI, CopyIn); 25000b57cec5SDimitry Andric } 25010b57cec5SDimitry Andric 25020b57cec5SDimitry Andric auto EndIt = std::next(EI.getIterator()); 25030b57cec5SDimitry Andric for (auto It = StartIt; It != EndIt; It = NextIt) { 25040b57cec5SDimitry Andric MachineInstr &MI = *It; 25050b57cec5SDimitry Andric NextIt = std::next(It); 25060b57cec5SDimitry Andric int TFI; 25070b57cec5SDimitry Andric if (!HII.isLoadFromStackSlot(MI, TFI) || TFI != FI) 25080b57cec5SDimitry Andric continue; 25098bcb0991SDimitry Andric Register DstR = MI.getOperand(0).getReg(); 25100b57cec5SDimitry Andric assert(MI.getOperand(0).getSubReg() == 0); 25110b57cec5SDimitry Andric MachineInstr *CopyOut = nullptr; 25120b57cec5SDimitry Andric if (DstR != FoundR) { 25130b57cec5SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 25140b57cec5SDimitry Andric unsigned MemSize = HII.getMemAccessSize(MI); 25150b57cec5SDimitry Andric assert(HII.getAddrMode(MI) == HexagonII::BaseImmOffset); 25160b57cec5SDimitry Andric unsigned CopyOpc = TargetOpcode::COPY; 25170b57cec5SDimitry Andric if (HII.isSignExtendingLoad(MI)) 25180b57cec5SDimitry Andric CopyOpc = (MemSize == 1) ? Hexagon::A2_sxtb : Hexagon::A2_sxth; 25190b57cec5SDimitry Andric else if (HII.isZeroExtendingLoad(MI)) 25200b57cec5SDimitry Andric CopyOpc = (MemSize == 1) ? Hexagon::A2_zxtb : Hexagon::A2_zxth; 25210b57cec5SDimitry Andric CopyOut = BuildMI(B, It, DL, HII.get(CopyOpc), DstR) 25220b57cec5SDimitry Andric .addReg(FoundR, getKillRegState(&MI == &EI)); 25230b57cec5SDimitry Andric } 25240b57cec5SDimitry Andric IM.replaceInstr(&MI, CopyOut); 25250b57cec5SDimitry Andric B.erase(It); 25260b57cec5SDimitry Andric } 25270b57cec5SDimitry Andric 25280b57cec5SDimitry Andric // Update the dead map. 25290b57cec5SDimitry Andric HexagonBlockRanges::RegisterRef FoundRR = { FoundR, 0 }; 25300b57cec5SDimitry Andric for (auto RR : HexagonBlockRanges::expandToSubRegs(FoundRR, MRI, HRI)) 25310b57cec5SDimitry Andric DM[RR].subtract(Range); 25320b57cec5SDimitry Andric } // for Range in range list 25330b57cec5SDimitry Andric } 25340b57cec5SDimitry Andric } 25350b57cec5SDimitry Andric } 25360b57cec5SDimitry Andric 25370b57cec5SDimitry Andric void HexagonFrameLowering::expandAlloca(MachineInstr *AI, 25380b57cec5SDimitry Andric const HexagonInstrInfo &HII, unsigned SP, unsigned CF) const { 25390b57cec5SDimitry Andric MachineBasicBlock &MB = *AI->getParent(); 25400b57cec5SDimitry Andric DebugLoc DL = AI->getDebugLoc(); 25410b57cec5SDimitry Andric unsigned A = AI->getOperand(2).getImm(); 25420b57cec5SDimitry Andric 25430b57cec5SDimitry Andric // Have 25440b57cec5SDimitry Andric // Rd = alloca Rs, #A 25450b57cec5SDimitry Andric // 25460b57cec5SDimitry Andric // If Rs and Rd are different registers, use this sequence: 25470b57cec5SDimitry Andric // Rd = sub(r29, Rs) 25480b57cec5SDimitry Andric // r29 = sub(r29, Rs) 25490b57cec5SDimitry Andric // Rd = and(Rd, #-A) ; if necessary 25500b57cec5SDimitry Andric // r29 = and(r29, #-A) ; if necessary 25510b57cec5SDimitry Andric // Rd = add(Rd, #CF) ; CF size aligned to at most A 25520b57cec5SDimitry Andric // otherwise, do 25530b57cec5SDimitry Andric // Rd = sub(r29, Rs) 25540b57cec5SDimitry Andric // Rd = and(Rd, #-A) ; if necessary 25550b57cec5SDimitry Andric // r29 = Rd 25560b57cec5SDimitry Andric // Rd = add(Rd, #CF) ; CF size aligned to at most A 25570b57cec5SDimitry Andric 25580b57cec5SDimitry Andric MachineOperand &RdOp = AI->getOperand(0); 25590b57cec5SDimitry Andric MachineOperand &RsOp = AI->getOperand(1); 25600b57cec5SDimitry Andric unsigned Rd = RdOp.getReg(), Rs = RsOp.getReg(); 25610b57cec5SDimitry Andric 25620b57cec5SDimitry Andric // Rd = sub(r29, Rs) 25630b57cec5SDimitry Andric BuildMI(MB, AI, DL, HII.get(Hexagon::A2_sub), Rd) 25640b57cec5SDimitry Andric .addReg(SP) 25650b57cec5SDimitry Andric .addReg(Rs); 25660b57cec5SDimitry Andric if (Rs != Rd) { 25670b57cec5SDimitry Andric // r29 = sub(r29, Rs) 25680b57cec5SDimitry Andric BuildMI(MB, AI, DL, HII.get(Hexagon::A2_sub), SP) 25690b57cec5SDimitry Andric .addReg(SP) 25700b57cec5SDimitry Andric .addReg(Rs); 25710b57cec5SDimitry Andric } 25720b57cec5SDimitry Andric if (A > 8) { 25730b57cec5SDimitry Andric // Rd = and(Rd, #-A) 25740b57cec5SDimitry Andric BuildMI(MB, AI, DL, HII.get(Hexagon::A2_andir), Rd) 25750b57cec5SDimitry Andric .addReg(Rd) 25760b57cec5SDimitry Andric .addImm(-int64_t(A)); 25770b57cec5SDimitry Andric if (Rs != Rd) 25780b57cec5SDimitry Andric BuildMI(MB, AI, DL, HII.get(Hexagon::A2_andir), SP) 25790b57cec5SDimitry Andric .addReg(SP) 25800b57cec5SDimitry Andric .addImm(-int64_t(A)); 25810b57cec5SDimitry Andric } 25820b57cec5SDimitry Andric if (Rs == Rd) { 25830b57cec5SDimitry Andric // r29 = Rd 25840b57cec5SDimitry Andric BuildMI(MB, AI, DL, HII.get(TargetOpcode::COPY), SP) 25850b57cec5SDimitry Andric .addReg(Rd); 25860b57cec5SDimitry Andric } 25870b57cec5SDimitry Andric if (CF > 0) { 25880b57cec5SDimitry Andric // Rd = add(Rd, #CF) 25890b57cec5SDimitry Andric BuildMI(MB, AI, DL, HII.get(Hexagon::A2_addi), Rd) 25900b57cec5SDimitry Andric .addReg(Rd) 25910b57cec5SDimitry Andric .addImm(CF); 25920b57cec5SDimitry Andric } 25930b57cec5SDimitry Andric } 25940b57cec5SDimitry Andric 25950b57cec5SDimitry Andric bool HexagonFrameLowering::needsAligna(const MachineFunction &MF) const { 25960b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 25970b57cec5SDimitry Andric if (!MFI.hasVarSizedObjects()) 25980b57cec5SDimitry Andric return false; 2599480093f4SDimitry Andric // Do not check for max stack object alignment here, because the stack 2600480093f4SDimitry Andric // may not be complete yet. Assume that we will need PS_aligna if there 2601480093f4SDimitry Andric // are variable-sized objects. 26020b57cec5SDimitry Andric return true; 26030b57cec5SDimitry Andric } 26040b57cec5SDimitry Andric 26050b57cec5SDimitry Andric const MachineInstr *HexagonFrameLowering::getAlignaInstr( 26060b57cec5SDimitry Andric const MachineFunction &MF) const { 26070b57cec5SDimitry Andric for (auto &B : MF) 26080b57cec5SDimitry Andric for (auto &I : B) 26090b57cec5SDimitry Andric if (I.getOpcode() == Hexagon::PS_aligna) 26100b57cec5SDimitry Andric return &I; 26110b57cec5SDimitry Andric return nullptr; 26120b57cec5SDimitry Andric } 26130b57cec5SDimitry Andric 26140b57cec5SDimitry Andric /// Adds all callee-saved registers as implicit uses or defs to the 26150b57cec5SDimitry Andric /// instruction. 26160b57cec5SDimitry Andric void HexagonFrameLowering::addCalleeSaveRegistersAsImpOperand(MachineInstr *MI, 26170b57cec5SDimitry Andric const CSIVect &CSI, bool IsDef, bool IsKill) const { 26180b57cec5SDimitry Andric // Add the callee-saved registers as implicit uses. 26190b57cec5SDimitry Andric for (auto &R : CSI) 26200b57cec5SDimitry Andric MI->addOperand(MachineOperand::CreateReg(R.getReg(), IsDef, true, IsKill)); 26210b57cec5SDimitry Andric } 26220b57cec5SDimitry Andric 26230b57cec5SDimitry Andric /// Determine whether the callee-saved register saves and restores should 26240b57cec5SDimitry Andric /// be generated via inline code. If this function returns "true", inline 26250b57cec5SDimitry Andric /// code will be generated. If this function returns "false", additional 26260b57cec5SDimitry Andric /// checks are performed, which may still lead to the inline code. 26270b57cec5SDimitry Andric bool HexagonFrameLowering::shouldInlineCSR(const MachineFunction &MF, 26280b57cec5SDimitry Andric const CSIVect &CSI) const { 26295ffd83dbSDimitry Andric if (MF.getSubtarget<HexagonSubtarget>().isEnvironmentMusl()) 26305ffd83dbSDimitry Andric return true; 26310b57cec5SDimitry Andric if (MF.getInfo<HexagonMachineFunctionInfo>()->hasEHReturn()) 26320b57cec5SDimitry Andric return true; 26330b57cec5SDimitry Andric if (!hasFP(MF)) 26340b57cec5SDimitry Andric return true; 26350b57cec5SDimitry Andric if (!isOptSize(MF) && !isMinSize(MF)) 26360b57cec5SDimitry Andric if (MF.getTarget().getOptLevel() > CodeGenOpt::Default) 26370b57cec5SDimitry Andric return true; 26380b57cec5SDimitry Andric 26390b57cec5SDimitry Andric // Check if CSI only has double registers, and if the registers form 26400b57cec5SDimitry Andric // a contiguous block starting from D8. 26410b57cec5SDimitry Andric BitVector Regs(Hexagon::NUM_TARGET_REGS); 26424824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 264304eeddc0SDimitry Andric Register R = I.getReg(); 26440b57cec5SDimitry Andric if (!Hexagon::DoubleRegsRegClass.contains(R)) 26450b57cec5SDimitry Andric return true; 26460b57cec5SDimitry Andric Regs[R] = true; 26470b57cec5SDimitry Andric } 26480b57cec5SDimitry Andric int F = Regs.find_first(); 26490b57cec5SDimitry Andric if (F != Hexagon::D8) 26500b57cec5SDimitry Andric return true; 26510b57cec5SDimitry Andric while (F >= 0) { 26520b57cec5SDimitry Andric int N = Regs.find_next(F); 26530b57cec5SDimitry Andric if (N >= 0 && N != F+1) 26540b57cec5SDimitry Andric return true; 26550b57cec5SDimitry Andric F = N; 26560b57cec5SDimitry Andric } 26570b57cec5SDimitry Andric 26580b57cec5SDimitry Andric return false; 26590b57cec5SDimitry Andric } 26600b57cec5SDimitry Andric 26610b57cec5SDimitry Andric bool HexagonFrameLowering::useSpillFunction(const MachineFunction &MF, 26620b57cec5SDimitry Andric const CSIVect &CSI) const { 26630b57cec5SDimitry Andric if (shouldInlineCSR(MF, CSI)) 26640b57cec5SDimitry Andric return false; 26650b57cec5SDimitry Andric unsigned NumCSI = CSI.size(); 26660b57cec5SDimitry Andric if (NumCSI <= 1) 26670b57cec5SDimitry Andric return false; 26680b57cec5SDimitry Andric 26690b57cec5SDimitry Andric unsigned Threshold = isOptSize(MF) ? SpillFuncThresholdOs 26700b57cec5SDimitry Andric : SpillFuncThreshold; 26710b57cec5SDimitry Andric return Threshold < NumCSI; 26720b57cec5SDimitry Andric } 26730b57cec5SDimitry Andric 26740b57cec5SDimitry Andric bool HexagonFrameLowering::useRestoreFunction(const MachineFunction &MF, 26750b57cec5SDimitry Andric const CSIVect &CSI) const { 26760b57cec5SDimitry Andric if (shouldInlineCSR(MF, CSI)) 26770b57cec5SDimitry Andric return false; 26780b57cec5SDimitry Andric // The restore functions do a bit more than just restoring registers. 26790b57cec5SDimitry Andric // The non-returning versions will go back directly to the caller's 26800b57cec5SDimitry Andric // caller, others will clean up the stack frame in preparation for 26810b57cec5SDimitry Andric // a tail call. Using them can still save code size even if only one 26820b57cec5SDimitry Andric // register is getting restores. Make the decision based on -Oz: 26830b57cec5SDimitry Andric // using -Os will use inline restore for a single register. 26840b57cec5SDimitry Andric if (isMinSize(MF)) 26850b57cec5SDimitry Andric return true; 26860b57cec5SDimitry Andric unsigned NumCSI = CSI.size(); 26870b57cec5SDimitry Andric if (NumCSI <= 1) 26880b57cec5SDimitry Andric return false; 26890b57cec5SDimitry Andric 26900b57cec5SDimitry Andric unsigned Threshold = isOptSize(MF) ? SpillFuncThresholdOs-1 26910b57cec5SDimitry Andric : SpillFuncThreshold; 26920b57cec5SDimitry Andric return Threshold < NumCSI; 26930b57cec5SDimitry Andric } 26940b57cec5SDimitry Andric 26950b57cec5SDimitry Andric bool HexagonFrameLowering::mayOverflowFrameOffset(MachineFunction &MF) const { 26960b57cec5SDimitry Andric unsigned StackSize = MF.getFrameInfo().estimateStackSize(MF); 26970b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 26980b57cec5SDimitry Andric // A fairly simplistic guess as to whether a potential load/store to a 26990b57cec5SDimitry Andric // stack location could require an extra register. 27000b57cec5SDimitry Andric if (HST.useHVXOps() && StackSize > 256) 27010b57cec5SDimitry Andric return true; 27020b57cec5SDimitry Andric 27030b57cec5SDimitry Andric // Check if the function has store-immediate instructions that access 27040b57cec5SDimitry Andric // the stack. Since the offset field is not extendable, if the stack 27050b57cec5SDimitry Andric // size exceeds the offset limit (6 bits, shifted), the stores will 27060b57cec5SDimitry Andric // require a new base register. 27070b57cec5SDimitry Andric bool HasImmStack = false; 27080b57cec5SDimitry Andric unsigned MinLS = ~0u; // Log_2 of the memory access size. 27090b57cec5SDimitry Andric 27100b57cec5SDimitry Andric for (const MachineBasicBlock &B : MF) { 27110b57cec5SDimitry Andric for (const MachineInstr &MI : B) { 27120b57cec5SDimitry Andric unsigned LS = 0; 27130b57cec5SDimitry Andric switch (MI.getOpcode()) { 27140b57cec5SDimitry Andric case Hexagon::S4_storeirit_io: 27150b57cec5SDimitry Andric case Hexagon::S4_storeirif_io: 27160b57cec5SDimitry Andric case Hexagon::S4_storeiri_io: 27170b57cec5SDimitry Andric ++LS; 27180b57cec5SDimitry Andric LLVM_FALLTHROUGH; 27190b57cec5SDimitry Andric case Hexagon::S4_storeirht_io: 27200b57cec5SDimitry Andric case Hexagon::S4_storeirhf_io: 27210b57cec5SDimitry Andric case Hexagon::S4_storeirh_io: 27220b57cec5SDimitry Andric ++LS; 27230b57cec5SDimitry Andric LLVM_FALLTHROUGH; 27240b57cec5SDimitry Andric case Hexagon::S4_storeirbt_io: 27250b57cec5SDimitry Andric case Hexagon::S4_storeirbf_io: 27260b57cec5SDimitry Andric case Hexagon::S4_storeirb_io: 27270b57cec5SDimitry Andric if (MI.getOperand(0).isFI()) 27280b57cec5SDimitry Andric HasImmStack = true; 27290b57cec5SDimitry Andric MinLS = std::min(MinLS, LS); 27300b57cec5SDimitry Andric break; 27310b57cec5SDimitry Andric } 27320b57cec5SDimitry Andric } 27330b57cec5SDimitry Andric } 27340b57cec5SDimitry Andric 27350b57cec5SDimitry Andric if (HasImmStack) 27360b57cec5SDimitry Andric return !isUInt<6>(StackSize >> MinLS); 27370b57cec5SDimitry Andric 27380b57cec5SDimitry Andric return false; 27390b57cec5SDimitry Andric } 2740