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