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