10b57cec5SDimitry Andric //===- HexagonSplitDouble.cpp ---------------------------------------------===// 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 #include "HexagonInstrInfo.h" 100b57cec5SDimitry Andric #include "HexagonRegisterInfo.h" 110b57cec5SDimitry Andric #include "HexagonSubtarget.h" 120b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h" 130b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 140b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 150b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 250b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 260b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h" 270b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h" 280b57cec5SDimitry Andric #include "llvm/Pass.h" 290b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 300b57cec5SDimitry Andric #include "llvm/Support/Compiler.h" 310b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 320b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 330b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 340b57cec5SDimitry Andric #include <algorithm> 350b57cec5SDimitry Andric #include <cassert> 360b57cec5SDimitry Andric #include <cstdint> 370b57cec5SDimitry Andric #include <limits> 380b57cec5SDimitry Andric #include <map> 390b57cec5SDimitry Andric #include <set> 400b57cec5SDimitry Andric #include <utility> 410b57cec5SDimitry Andric #include <vector> 420b57cec5SDimitry Andric 43fe6060f1SDimitry Andric #define DEBUG_TYPE "hsdr" 44fe6060f1SDimitry Andric 450b57cec5SDimitry Andric using namespace llvm; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric namespace llvm { 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric FunctionPass *createHexagonSplitDoubleRegs(); 500b57cec5SDimitry Andric void initializeHexagonSplitDoubleRegsPass(PassRegistry&); 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric } // end namespace llvm 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric static cl::opt<int> MaxHSDR("max-hsdr", cl::Hidden, cl::init(-1), 550b57cec5SDimitry Andric cl::desc("Maximum number of split partitions")); 560b57cec5SDimitry Andric static cl::opt<bool> MemRefsFixed("hsdr-no-mem", cl::Hidden, cl::init(true), 570b57cec5SDimitry Andric cl::desc("Do not split loads or stores")); 580b57cec5SDimitry Andric static cl::opt<bool> SplitAll("hsdr-split-all", cl::Hidden, cl::init(false), 590b57cec5SDimitry Andric cl::desc("Split all partitions")); 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric namespace { 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric class HexagonSplitDoubleRegs : public MachineFunctionPass { 640b57cec5SDimitry Andric public: 650b57cec5SDimitry Andric static char ID; 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric HexagonSplitDoubleRegs() : MachineFunctionPass(ID) {} 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric StringRef getPassName() const override { 700b57cec5SDimitry Andric return "Hexagon Split Double Registers"; 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 74*0fca6ea1SDimitry Andric AU.addRequired<MachineLoopInfoWrapperPass>(); 75*0fca6ea1SDimitry Andric AU.addPreserved<MachineLoopInfoWrapperPass>(); 760b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric private: 820b57cec5SDimitry Andric static const TargetRegisterClass *const DoubleRC; 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric const HexagonRegisterInfo *TRI = nullptr; 850b57cec5SDimitry Andric const HexagonInstrInfo *TII = nullptr; 860b57cec5SDimitry Andric const MachineLoopInfo *MLI; 870b57cec5SDimitry Andric MachineRegisterInfo *MRI; 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric using USet = std::set<unsigned>; 900b57cec5SDimitry Andric using UUSetMap = std::map<unsigned, USet>; 910b57cec5SDimitry Andric using UUPair = std::pair<unsigned, unsigned>; 920b57cec5SDimitry Andric using UUPairMap = std::map<unsigned, UUPair>; 930b57cec5SDimitry Andric using LoopRegMap = std::map<const MachineLoop *, USet>; 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric bool isInduction(unsigned Reg, LoopRegMap &IRM) const; 960b57cec5SDimitry Andric bool isVolatileInstr(const MachineInstr *MI) const; 970b57cec5SDimitry Andric bool isFixedInstr(const MachineInstr *MI) const; 980b57cec5SDimitry Andric void partitionRegisters(UUSetMap &P2Rs); 990b57cec5SDimitry Andric int32_t profit(const MachineInstr *MI) const; 100e8d8bef9SDimitry Andric int32_t profit(Register Reg) const; 1010b57cec5SDimitry Andric bool isProfitable(const USet &Part, LoopRegMap &IRM) const; 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric void collectIndRegsForLoop(const MachineLoop *L, USet &Rs); 1040b57cec5SDimitry Andric void collectIndRegs(LoopRegMap &IRM); 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric void createHalfInstr(unsigned Opc, MachineInstr *MI, 1070b57cec5SDimitry Andric const UUPairMap &PairMap, unsigned SubR); 1080b57cec5SDimitry Andric void splitMemRef(MachineInstr *MI, const UUPairMap &PairMap); 1090b57cec5SDimitry Andric void splitImmediate(MachineInstr *MI, const UUPairMap &PairMap); 1100b57cec5SDimitry Andric void splitCombine(MachineInstr *MI, const UUPairMap &PairMap); 1110b57cec5SDimitry Andric void splitExt(MachineInstr *MI, const UUPairMap &PairMap); 1120b57cec5SDimitry Andric void splitShift(MachineInstr *MI, const UUPairMap &PairMap); 1130b57cec5SDimitry Andric void splitAslOr(MachineInstr *MI, const UUPairMap &PairMap); 1140b57cec5SDimitry Andric bool splitInstr(MachineInstr *MI, const UUPairMap &PairMap); 1150b57cec5SDimitry Andric void replaceSubregUses(MachineInstr *MI, const UUPairMap &PairMap); 1160b57cec5SDimitry Andric void collapseRegPairs(MachineInstr *MI, const UUPairMap &PairMap); 1170b57cec5SDimitry Andric bool splitPartition(const USet &Part); 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric static int Counter; 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric static void dump_partition(raw_ostream&, const USet&, 1220b57cec5SDimitry Andric const TargetRegisterInfo&); 1230b57cec5SDimitry Andric }; 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric } // end anonymous namespace 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric char HexagonSplitDoubleRegs::ID; 1280b57cec5SDimitry Andric int HexagonSplitDoubleRegs::Counter = 0; 1290b57cec5SDimitry Andric const TargetRegisterClass *const HexagonSplitDoubleRegs::DoubleRC = 1300b57cec5SDimitry Andric &Hexagon::DoubleRegsRegClass; 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric INITIALIZE_PASS(HexagonSplitDoubleRegs, "hexagon-split-double", 1330b57cec5SDimitry Andric "Hexagon Split Double Registers", false, false) 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 1360b57cec5SDimitry Andric LLVM_DUMP_METHOD void HexagonSplitDoubleRegs::dump_partition(raw_ostream &os, 1370b57cec5SDimitry Andric const USet &Part, const TargetRegisterInfo &TRI) { 1380b57cec5SDimitry Andric dbgs() << '{'; 1390b57cec5SDimitry Andric for (auto I : Part) 1400b57cec5SDimitry Andric dbgs() << ' ' << printReg(I, &TRI); 1410b57cec5SDimitry Andric dbgs() << " }"; 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric #endif 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::isInduction(unsigned Reg, LoopRegMap &IRM) const { 1460b57cec5SDimitry Andric for (auto I : IRM) { 1470b57cec5SDimitry Andric const USet &Rs = I.second; 1480b57cec5SDimitry Andric if (Rs.find(Reg) != Rs.end()) 1490b57cec5SDimitry Andric return true; 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric return false; 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::isVolatileInstr(const MachineInstr *MI) const { 1550b57cec5SDimitry Andric for (auto &MO : MI->memoperands()) 1560b57cec5SDimitry Andric if (MO->isVolatile() || MO->isAtomic()) 1570b57cec5SDimitry Andric return true; 1580b57cec5SDimitry Andric return false; 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::isFixedInstr(const MachineInstr *MI) const { 162480093f4SDimitry Andric if (MI->mayLoadOrStore()) 1630b57cec5SDimitry Andric if (MemRefsFixed || isVolatileInstr(MI)) 1640b57cec5SDimitry Andric return true; 1650b57cec5SDimitry Andric if (MI->isDebugInstr()) 1660b57cec5SDimitry Andric return false; 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 1690b57cec5SDimitry Andric switch (Opc) { 1700b57cec5SDimitry Andric default: 1710b57cec5SDimitry Andric return true; 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric case TargetOpcode::PHI: 1740b57cec5SDimitry Andric case TargetOpcode::COPY: 1750b57cec5SDimitry Andric break; 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric case Hexagon::L2_loadrd_io: 1780b57cec5SDimitry Andric // Not handling stack stores (only reg-based addresses). 1790b57cec5SDimitry Andric if (MI->getOperand(1).isReg()) 1800b57cec5SDimitry Andric break; 1810b57cec5SDimitry Andric return true; 1820b57cec5SDimitry Andric case Hexagon::S2_storerd_io: 1830b57cec5SDimitry Andric // Not handling stack stores (only reg-based addresses). 1840b57cec5SDimitry Andric if (MI->getOperand(0).isReg()) 1850b57cec5SDimitry Andric break; 1860b57cec5SDimitry Andric return true; 1870b57cec5SDimitry Andric case Hexagon::L2_loadrd_pi: 1880b57cec5SDimitry Andric case Hexagon::S2_storerd_pi: 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric case Hexagon::A2_tfrpi: 1910b57cec5SDimitry Andric case Hexagon::A2_combineii: 1920b57cec5SDimitry Andric case Hexagon::A4_combineir: 1930b57cec5SDimitry Andric case Hexagon::A4_combineii: 1940b57cec5SDimitry Andric case Hexagon::A4_combineri: 1950b57cec5SDimitry Andric case Hexagon::A2_combinew: 1960b57cec5SDimitry Andric case Hexagon::CONST64: 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric case Hexagon::A2_sxtw: 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric case Hexagon::A2_andp: 2010b57cec5SDimitry Andric case Hexagon::A2_orp: 2020b57cec5SDimitry Andric case Hexagon::A2_xorp: 2030b57cec5SDimitry Andric case Hexagon::S2_asl_i_p_or: 2040b57cec5SDimitry Andric case Hexagon::S2_asl_i_p: 2050b57cec5SDimitry Andric case Hexagon::S2_asr_i_p: 2060b57cec5SDimitry Andric case Hexagon::S2_lsr_i_p: 2070b57cec5SDimitry Andric break; 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric for (auto &Op : MI->operands()) { 2110b57cec5SDimitry Andric if (!Op.isReg()) 2120b57cec5SDimitry Andric continue; 2138bcb0991SDimitry Andric Register R = Op.getReg(); 214e8d8bef9SDimitry Andric if (!R.isVirtual()) 2150b57cec5SDimitry Andric return true; 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric return false; 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric void HexagonSplitDoubleRegs::partitionRegisters(UUSetMap &P2Rs) { 2210b57cec5SDimitry Andric using UUMap = std::map<unsigned, unsigned>; 2220b57cec5SDimitry Andric using UVect = std::vector<unsigned>; 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric unsigned NumRegs = MRI->getNumVirtRegs(); 2250b57cec5SDimitry Andric BitVector DoubleRegs(NumRegs); 2260b57cec5SDimitry Andric for (unsigned i = 0; i < NumRegs; ++i) { 22704eeddc0SDimitry Andric Register R = Register::index2VirtReg(i); 2280b57cec5SDimitry Andric if (MRI->getRegClass(R) == DoubleRC) 2290b57cec5SDimitry Andric DoubleRegs.set(i); 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric BitVector FixedRegs(NumRegs); 2330b57cec5SDimitry Andric for (int x = DoubleRegs.find_first(); x >= 0; x = DoubleRegs.find_next(x)) { 23404eeddc0SDimitry Andric Register R = Register::index2VirtReg(x); 2350b57cec5SDimitry Andric MachineInstr *DefI = MRI->getVRegDef(R); 2360b57cec5SDimitry Andric // In some cases a register may exist, but never be defined or used. 2370b57cec5SDimitry Andric // It should never appear anywhere, but mark it as "fixed", just to be 2380b57cec5SDimitry Andric // safe. 2390b57cec5SDimitry Andric if (!DefI || isFixedInstr(DefI)) 2400b57cec5SDimitry Andric FixedRegs.set(x); 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric UUSetMap AssocMap; 2440b57cec5SDimitry Andric for (int x = DoubleRegs.find_first(); x >= 0; x = DoubleRegs.find_next(x)) { 2450b57cec5SDimitry Andric if (FixedRegs[x]) 2460b57cec5SDimitry Andric continue; 24704eeddc0SDimitry Andric Register R = Register::index2VirtReg(x); 2480b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << printReg(R, TRI) << " ~~"); 2490b57cec5SDimitry Andric USet &Asc = AssocMap[R]; 2500b57cec5SDimitry Andric for (auto U = MRI->use_nodbg_begin(R), Z = MRI->use_nodbg_end(); 2510b57cec5SDimitry Andric U != Z; ++U) { 2520b57cec5SDimitry Andric MachineOperand &Op = *U; 2530b57cec5SDimitry Andric MachineInstr *UseI = Op.getParent(); 2540b57cec5SDimitry Andric if (isFixedInstr(UseI)) 2550b57cec5SDimitry Andric continue; 25606c3fb27SDimitry Andric for (MachineOperand &MO : UseI->operands()) { 2570b57cec5SDimitry Andric // Skip non-registers or registers with subregisters. 2580b57cec5SDimitry Andric if (&MO == &Op || !MO.isReg() || MO.getSubReg()) 2590b57cec5SDimitry Andric continue; 2608bcb0991SDimitry Andric Register T = MO.getReg(); 261e8d8bef9SDimitry Andric if (!T.isVirtual()) { 2620b57cec5SDimitry Andric FixedRegs.set(x); 2630b57cec5SDimitry Andric continue; 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric if (MRI->getRegClass(T) != DoubleRC) 2660b57cec5SDimitry Andric continue; 2678bcb0991SDimitry Andric unsigned u = Register::virtReg2Index(T); 2680b57cec5SDimitry Andric if (FixedRegs[u]) 2690b57cec5SDimitry Andric continue; 2700b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << ' ' << printReg(T, TRI)); 2710b57cec5SDimitry Andric Asc.insert(T); 2720b57cec5SDimitry Andric // Make it symmetric. 2730b57cec5SDimitry Andric AssocMap[T].insert(R); 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << '\n'); 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric UUMap R2P; 2800b57cec5SDimitry Andric unsigned NextP = 1; 2810b57cec5SDimitry Andric USet Visited; 2820b57cec5SDimitry Andric for (int x = DoubleRegs.find_first(); x >= 0; x = DoubleRegs.find_next(x)) { 28304eeddc0SDimitry Andric Register R = Register::index2VirtReg(x); 2840b57cec5SDimitry Andric if (Visited.count(R)) 2850b57cec5SDimitry Andric continue; 2860b57cec5SDimitry Andric // Create a new partition for R. 2870b57cec5SDimitry Andric unsigned ThisP = FixedRegs[x] ? 0 : NextP++; 2880b57cec5SDimitry Andric UVect WorkQ; 2890b57cec5SDimitry Andric WorkQ.push_back(R); 2900b57cec5SDimitry Andric for (unsigned i = 0; i < WorkQ.size(); ++i) { 2910b57cec5SDimitry Andric unsigned T = WorkQ[i]; 2920b57cec5SDimitry Andric if (Visited.count(T)) 2930b57cec5SDimitry Andric continue; 2940b57cec5SDimitry Andric R2P[T] = ThisP; 2950b57cec5SDimitry Andric Visited.insert(T); 2960b57cec5SDimitry Andric // Add all registers associated with T. 2970b57cec5SDimitry Andric USet &Asc = AssocMap[T]; 298fe6060f1SDimitry Andric append_range(WorkQ, Asc); 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric } 3010b57cec5SDimitry Andric 3020b57cec5SDimitry Andric for (auto I : R2P) 3030b57cec5SDimitry Andric P2Rs[I.second].insert(I.first); 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric static inline int32_t profitImm(unsigned Imm) { 3070b57cec5SDimitry Andric int32_t P = 0; 3080b57cec5SDimitry Andric if (Imm == 0 || Imm == 0xFFFFFFFF) 3090b57cec5SDimitry Andric P += 10; 3100b57cec5SDimitry Andric return P; 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric int32_t HexagonSplitDoubleRegs::profit(const MachineInstr *MI) const { 3140b57cec5SDimitry Andric unsigned ImmX = 0; 3150b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 3160b57cec5SDimitry Andric switch (Opc) { 3170b57cec5SDimitry Andric case TargetOpcode::PHI: 3180b57cec5SDimitry Andric for (const auto &Op : MI->operands()) 3190b57cec5SDimitry Andric if (!Op.getSubReg()) 3200b57cec5SDimitry Andric return 0; 3210b57cec5SDimitry Andric return 10; 3220b57cec5SDimitry Andric case TargetOpcode::COPY: 3230b57cec5SDimitry Andric if (MI->getOperand(1).getSubReg() != 0) 3240b57cec5SDimitry Andric return 10; 3250b57cec5SDimitry Andric return 0; 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric case Hexagon::L2_loadrd_io: 3280b57cec5SDimitry Andric case Hexagon::S2_storerd_io: 3290b57cec5SDimitry Andric return -1; 3300b57cec5SDimitry Andric case Hexagon::L2_loadrd_pi: 3310b57cec5SDimitry Andric case Hexagon::S2_storerd_pi: 3320b57cec5SDimitry Andric return 2; 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric case Hexagon::A2_tfrpi: 3350b57cec5SDimitry Andric case Hexagon::CONST64: { 3360b57cec5SDimitry Andric uint64_t D = MI->getOperand(1).getImm(); 3370b57cec5SDimitry Andric unsigned Lo = D & 0xFFFFFFFFULL; 3380b57cec5SDimitry Andric unsigned Hi = D >> 32; 3390b57cec5SDimitry Andric return profitImm(Lo) + profitImm(Hi); 3400b57cec5SDimitry Andric } 3410b57cec5SDimitry Andric case Hexagon::A2_combineii: 3420b57cec5SDimitry Andric case Hexagon::A4_combineii: { 3430b57cec5SDimitry Andric const MachineOperand &Op1 = MI->getOperand(1); 3440b57cec5SDimitry Andric const MachineOperand &Op2 = MI->getOperand(2); 3450b57cec5SDimitry Andric int32_t Prof1 = Op1.isImm() ? profitImm(Op1.getImm()) : 0; 3460b57cec5SDimitry Andric int32_t Prof2 = Op2.isImm() ? profitImm(Op2.getImm()) : 0; 3470b57cec5SDimitry Andric return Prof1 + Prof2; 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric case Hexagon::A4_combineri: 3500b57cec5SDimitry Andric ImmX++; 3510b57cec5SDimitry Andric // Fall through into A4_combineir. 352bdd1243dSDimitry Andric [[fallthrough]]; 3530b57cec5SDimitry Andric case Hexagon::A4_combineir: { 3540b57cec5SDimitry Andric ImmX++; 3550b57cec5SDimitry Andric const MachineOperand &OpX = MI->getOperand(ImmX); 3560b57cec5SDimitry Andric if (OpX.isImm()) { 3570b57cec5SDimitry Andric int64_t V = OpX.getImm(); 3580b57cec5SDimitry Andric if (V == 0 || V == -1) 3590b57cec5SDimitry Andric return 10; 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric // Fall through into A2_combinew. 362bdd1243dSDimitry Andric [[fallthrough]]; 3630b57cec5SDimitry Andric } 3640b57cec5SDimitry Andric case Hexagon::A2_combinew: 3650b57cec5SDimitry Andric return 2; 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric case Hexagon::A2_sxtw: 3680b57cec5SDimitry Andric return 3; 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric case Hexagon::A2_andp: 3710b57cec5SDimitry Andric case Hexagon::A2_orp: 3720b57cec5SDimitry Andric case Hexagon::A2_xorp: { 3738bcb0991SDimitry Andric Register Rs = MI->getOperand(1).getReg(); 3748bcb0991SDimitry Andric Register Rt = MI->getOperand(2).getReg(); 3750b57cec5SDimitry Andric return profit(Rs) + profit(Rt); 3760b57cec5SDimitry Andric } 3770b57cec5SDimitry Andric 3780b57cec5SDimitry Andric case Hexagon::S2_asl_i_p_or: { 3790b57cec5SDimitry Andric unsigned S = MI->getOperand(3).getImm(); 3800b57cec5SDimitry Andric if (S == 0 || S == 32) 3810b57cec5SDimitry Andric return 10; 3820b57cec5SDimitry Andric return -1; 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric case Hexagon::S2_asl_i_p: 3850b57cec5SDimitry Andric case Hexagon::S2_asr_i_p: 3860b57cec5SDimitry Andric case Hexagon::S2_lsr_i_p: 3870b57cec5SDimitry Andric unsigned S = MI->getOperand(2).getImm(); 3880b57cec5SDimitry Andric if (S == 0 || S == 32) 3890b57cec5SDimitry Andric return 10; 3900b57cec5SDimitry Andric if (S == 16) 3910b57cec5SDimitry Andric return 5; 3920b57cec5SDimitry Andric if (S == 48) 3930b57cec5SDimitry Andric return 7; 3940b57cec5SDimitry Andric return -10; 3950b57cec5SDimitry Andric } 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric return 0; 3980b57cec5SDimitry Andric } 3990b57cec5SDimitry Andric 400e8d8bef9SDimitry Andric int32_t HexagonSplitDoubleRegs::profit(Register Reg) const { 401e8d8bef9SDimitry Andric assert(Reg.isVirtual()); 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric const MachineInstr *DefI = MRI->getVRegDef(Reg); 4040b57cec5SDimitry Andric switch (DefI->getOpcode()) { 4050b57cec5SDimitry Andric case Hexagon::A2_tfrpi: 4060b57cec5SDimitry Andric case Hexagon::CONST64: 4070b57cec5SDimitry Andric case Hexagon::A2_combineii: 4080b57cec5SDimitry Andric case Hexagon::A4_combineii: 4090b57cec5SDimitry Andric case Hexagon::A4_combineri: 4100b57cec5SDimitry Andric case Hexagon::A4_combineir: 4110b57cec5SDimitry Andric case Hexagon::A2_combinew: 4120b57cec5SDimitry Andric return profit(DefI); 4130b57cec5SDimitry Andric default: 4140b57cec5SDimitry Andric break; 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric return 0; 4170b57cec5SDimitry Andric } 4180b57cec5SDimitry Andric 4190b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::isProfitable(const USet &Part, LoopRegMap &IRM) 4200b57cec5SDimitry Andric const { 4210b57cec5SDimitry Andric unsigned FixedNum = 0, LoopPhiNum = 0; 4220b57cec5SDimitry Andric int32_t TotalP = 0; 4230b57cec5SDimitry Andric 4240b57cec5SDimitry Andric for (unsigned DR : Part) { 4250b57cec5SDimitry Andric MachineInstr *DefI = MRI->getVRegDef(DR); 4260b57cec5SDimitry Andric int32_t P = profit(DefI); 4270b57cec5SDimitry Andric if (P == std::numeric_limits<int>::min()) 4280b57cec5SDimitry Andric return false; 4290b57cec5SDimitry Andric TotalP += P; 4300b57cec5SDimitry Andric // Reduce the profitability of splitting induction registers. 4310b57cec5SDimitry Andric if (isInduction(DR, IRM)) 4320b57cec5SDimitry Andric TotalP -= 30; 4330b57cec5SDimitry Andric 4340b57cec5SDimitry Andric for (auto U = MRI->use_nodbg_begin(DR), W = MRI->use_nodbg_end(); 4350b57cec5SDimitry Andric U != W; ++U) { 4360b57cec5SDimitry Andric MachineInstr *UseI = U->getParent(); 4370b57cec5SDimitry Andric if (isFixedInstr(UseI)) { 4380b57cec5SDimitry Andric FixedNum++; 4390b57cec5SDimitry Andric // Calculate the cost of generating REG_SEQUENCE instructions. 4400b57cec5SDimitry Andric for (auto &Op : UseI->operands()) { 4410b57cec5SDimitry Andric if (Op.isReg() && Part.count(Op.getReg())) 4420b57cec5SDimitry Andric if (Op.getSubReg()) 4430b57cec5SDimitry Andric TotalP -= 2; 4440b57cec5SDimitry Andric } 4450b57cec5SDimitry Andric continue; 4460b57cec5SDimitry Andric } 4470b57cec5SDimitry Andric // If a register from this partition is used in a fixed instruction, 4480b57cec5SDimitry Andric // and there is also a register in this partition that is used in 4490b57cec5SDimitry Andric // a loop phi node, then decrease the splitting profit as this can 4500b57cec5SDimitry Andric // confuse the modulo scheduler. 4510b57cec5SDimitry Andric if (UseI->isPHI()) { 4520b57cec5SDimitry Andric const MachineBasicBlock *PB = UseI->getParent(); 4530b57cec5SDimitry Andric const MachineLoop *L = MLI->getLoopFor(PB); 4540b57cec5SDimitry Andric if (L && L->getHeader() == PB) 4550b57cec5SDimitry Andric LoopPhiNum++; 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric // Splittable instruction. 4580b57cec5SDimitry Andric int32_t P = profit(UseI); 4590b57cec5SDimitry Andric if (P == std::numeric_limits<int>::min()) 4600b57cec5SDimitry Andric return false; 4610b57cec5SDimitry Andric TotalP += P; 4620b57cec5SDimitry Andric } 4630b57cec5SDimitry Andric } 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric if (FixedNum > 0 && LoopPhiNum > 0) 4660b57cec5SDimitry Andric TotalP -= 20*LoopPhiNum; 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Partition profit: " << TotalP << '\n'); 4690b57cec5SDimitry Andric if (SplitAll) 4700b57cec5SDimitry Andric return true; 4710b57cec5SDimitry Andric return TotalP > 0; 4720b57cec5SDimitry Andric } 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric void HexagonSplitDoubleRegs::collectIndRegsForLoop(const MachineLoop *L, 4750b57cec5SDimitry Andric USet &Rs) { 4760b57cec5SDimitry Andric const MachineBasicBlock *HB = L->getHeader(); 4770b57cec5SDimitry Andric const MachineBasicBlock *LB = L->getLoopLatch(); 4780b57cec5SDimitry Andric if (!HB || !LB) 4790b57cec5SDimitry Andric return; 4800b57cec5SDimitry Andric 4810b57cec5SDimitry Andric // Examine the latch branch. Expect it to be a conditional branch to 4820b57cec5SDimitry Andric // the header (either "br-cond header" or "br-cond exit; br header"). 4830b57cec5SDimitry Andric MachineBasicBlock *TB = nullptr, *FB = nullptr; 4840b57cec5SDimitry Andric MachineBasicBlock *TmpLB = const_cast<MachineBasicBlock*>(LB); 4850b57cec5SDimitry Andric SmallVector<MachineOperand,2> Cond; 4860b57cec5SDimitry Andric bool BadLB = TII->analyzeBranch(*TmpLB, TB, FB, Cond, false); 4870b57cec5SDimitry Andric // Only analyzable conditional branches. HII::analyzeBranch will put 4880b57cec5SDimitry Andric // the branch opcode as the first element of Cond, and the predicate 4890b57cec5SDimitry Andric // operand as the second. 4900b57cec5SDimitry Andric if (BadLB || Cond.size() != 2) 4910b57cec5SDimitry Andric return; 4920b57cec5SDimitry Andric // Only simple jump-conditional (with or without negation). 4930b57cec5SDimitry Andric if (!TII->PredOpcodeHasJMP_c(Cond[0].getImm())) 4940b57cec5SDimitry Andric return; 4950b57cec5SDimitry Andric // Must go to the header. 4960b57cec5SDimitry Andric if (TB != HB && FB != HB) 4970b57cec5SDimitry Andric return; 4980b57cec5SDimitry Andric assert(Cond[1].isReg() && "Unexpected Cond vector from analyzeBranch"); 4990b57cec5SDimitry Andric // Expect a predicate register. 5008bcb0991SDimitry Andric Register PR = Cond[1].getReg(); 5010b57cec5SDimitry Andric assert(MRI->getRegClass(PR) == &Hexagon::PredRegsRegClass); 5020b57cec5SDimitry Andric 5030b57cec5SDimitry Andric // Get the registers on which the loop controlling compare instruction 5040b57cec5SDimitry Andric // depends. 5055ffd83dbSDimitry Andric Register CmpR1, CmpR2; 5060b57cec5SDimitry Andric const MachineInstr *CmpI = MRI->getVRegDef(PR); 5070b57cec5SDimitry Andric while (CmpI->getOpcode() == Hexagon::C2_not) 5080b57cec5SDimitry Andric CmpI = MRI->getVRegDef(CmpI->getOperand(1).getReg()); 5090b57cec5SDimitry Andric 510349cc55cSDimitry Andric int64_t Mask = 0, Val = 0; 5110b57cec5SDimitry Andric bool OkCI = TII->analyzeCompare(*CmpI, CmpR1, CmpR2, Mask, Val); 5120b57cec5SDimitry Andric if (!OkCI) 5130b57cec5SDimitry Andric return; 5140b57cec5SDimitry Andric // Eliminate non-double input registers. 5150b57cec5SDimitry Andric if (CmpR1 && MRI->getRegClass(CmpR1) != DoubleRC) 5160b57cec5SDimitry Andric CmpR1 = 0; 5170b57cec5SDimitry Andric if (CmpR2 && MRI->getRegClass(CmpR2) != DoubleRC) 5180b57cec5SDimitry Andric CmpR2 = 0; 5190b57cec5SDimitry Andric if (!CmpR1 && !CmpR2) 5200b57cec5SDimitry Andric return; 5210b57cec5SDimitry Andric 5220b57cec5SDimitry Andric // Now examine the top of the loop: the phi nodes that could poten- 5230b57cec5SDimitry Andric // tially define loop induction registers. The registers defined by 5240b57cec5SDimitry Andric // such a phi node would be used in a 64-bit add, which then would 5250b57cec5SDimitry Andric // be used in the loop compare instruction. 5260b57cec5SDimitry Andric 5270b57cec5SDimitry Andric // Get the set of all double registers defined by phi nodes in the 5280b57cec5SDimitry Andric // loop header. 5290b57cec5SDimitry Andric using UVect = std::vector<unsigned>; 5300b57cec5SDimitry Andric 5310b57cec5SDimitry Andric UVect DP; 5320b57cec5SDimitry Andric for (auto &MI : *HB) { 5330b57cec5SDimitry Andric if (!MI.isPHI()) 5340b57cec5SDimitry Andric break; 5350b57cec5SDimitry Andric const MachineOperand &MD = MI.getOperand(0); 5368bcb0991SDimitry Andric Register R = MD.getReg(); 5370b57cec5SDimitry Andric if (MRI->getRegClass(R) == DoubleRC) 5380b57cec5SDimitry Andric DP.push_back(R); 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric if (DP.empty()) 5410b57cec5SDimitry Andric return; 5420b57cec5SDimitry Andric 5430b57cec5SDimitry Andric auto NoIndOp = [this, CmpR1, CmpR2] (unsigned R) -> bool { 5440b57cec5SDimitry Andric for (auto I = MRI->use_nodbg_begin(R), E = MRI->use_nodbg_end(); 5450b57cec5SDimitry Andric I != E; ++I) { 5460b57cec5SDimitry Andric const MachineInstr *UseI = I->getParent(); 5470b57cec5SDimitry Andric if (UseI->getOpcode() != Hexagon::A2_addp) 5480b57cec5SDimitry Andric continue; 5490b57cec5SDimitry Andric // Get the output from the add. If it is one of the inputs to the 5500b57cec5SDimitry Andric // loop-controlling compare instruction, then R is likely an induc- 5510b57cec5SDimitry Andric // tion register. 5528bcb0991SDimitry Andric Register T = UseI->getOperand(0).getReg(); 5530b57cec5SDimitry Andric if (T == CmpR1 || T == CmpR2) 5540b57cec5SDimitry Andric return false; 5550b57cec5SDimitry Andric } 5560b57cec5SDimitry Andric return true; 5570b57cec5SDimitry Andric }; 5580b57cec5SDimitry Andric UVect::iterator End = llvm::remove_if(DP, NoIndOp); 5590b57cec5SDimitry Andric Rs.insert(DP.begin(), End); 5600b57cec5SDimitry Andric Rs.insert(CmpR1); 5610b57cec5SDimitry Andric Rs.insert(CmpR2); 5620b57cec5SDimitry Andric 5630b57cec5SDimitry Andric LLVM_DEBUG({ 5640b57cec5SDimitry Andric dbgs() << "For loop at " << printMBBReference(*HB) << " ind regs: "; 5650b57cec5SDimitry Andric dump_partition(dbgs(), Rs, *TRI); 5660b57cec5SDimitry Andric dbgs() << '\n'; 5670b57cec5SDimitry Andric }); 5680b57cec5SDimitry Andric } 5690b57cec5SDimitry Andric 5700b57cec5SDimitry Andric void HexagonSplitDoubleRegs::collectIndRegs(LoopRegMap &IRM) { 5710b57cec5SDimitry Andric using LoopVector = std::vector<MachineLoop *>; 5720b57cec5SDimitry Andric 5730b57cec5SDimitry Andric LoopVector WorkQ; 5740b57cec5SDimitry Andric 575e8d8bef9SDimitry Andric append_range(WorkQ, *MLI); 576e8d8bef9SDimitry Andric for (unsigned i = 0; i < WorkQ.size(); ++i) 577e8d8bef9SDimitry Andric append_range(WorkQ, *WorkQ[i]); 5780b57cec5SDimitry Andric 5790b57cec5SDimitry Andric USet Rs; 58004eeddc0SDimitry Andric for (MachineLoop *L : WorkQ) { 5810b57cec5SDimitry Andric Rs.clear(); 5820b57cec5SDimitry Andric collectIndRegsForLoop(L, Rs); 5830b57cec5SDimitry Andric if (!Rs.empty()) 5840b57cec5SDimitry Andric IRM.insert(std::make_pair(L, Rs)); 5850b57cec5SDimitry Andric } 5860b57cec5SDimitry Andric } 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric void HexagonSplitDoubleRegs::createHalfInstr(unsigned Opc, MachineInstr *MI, 5890b57cec5SDimitry Andric const UUPairMap &PairMap, unsigned SubR) { 5900b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 5910b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 5920b57cec5SDimitry Andric MachineInstr *NewI = BuildMI(B, MI, DL, TII->get(Opc)); 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric for (auto &Op : MI->operands()) { 5950b57cec5SDimitry Andric if (!Op.isReg()) { 5960b57cec5SDimitry Andric NewI->addOperand(Op); 5970b57cec5SDimitry Andric continue; 5980b57cec5SDimitry Andric } 5990b57cec5SDimitry Andric // For register operands, set the subregister. 6008bcb0991SDimitry Andric Register R = Op.getReg(); 6010b57cec5SDimitry Andric unsigned SR = Op.getSubReg(); 602e8d8bef9SDimitry Andric bool isVirtReg = R.isVirtual(); 6030b57cec5SDimitry Andric bool isKill = Op.isKill(); 6040b57cec5SDimitry Andric if (isVirtReg && MRI->getRegClass(R) == DoubleRC) { 6050b57cec5SDimitry Andric isKill = false; 6060b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(R); 6070b57cec5SDimitry Andric if (F == PairMap.end()) { 6080b57cec5SDimitry Andric SR = SubR; 6090b57cec5SDimitry Andric } else { 6100b57cec5SDimitry Andric const UUPair &P = F->second; 6110b57cec5SDimitry Andric R = (SubR == Hexagon::isub_lo) ? P.first : P.second; 6120b57cec5SDimitry Andric SR = 0; 6130b57cec5SDimitry Andric } 6140b57cec5SDimitry Andric } 6150b57cec5SDimitry Andric auto CO = MachineOperand::CreateReg(R, Op.isDef(), Op.isImplicit(), isKill, 6160b57cec5SDimitry Andric Op.isDead(), Op.isUndef(), Op.isEarlyClobber(), SR, Op.isDebug(), 6170b57cec5SDimitry Andric Op.isInternalRead()); 6180b57cec5SDimitry Andric NewI->addOperand(CO); 6190b57cec5SDimitry Andric } 6200b57cec5SDimitry Andric } 6210b57cec5SDimitry Andric 6220b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitMemRef(MachineInstr *MI, 6230b57cec5SDimitry Andric const UUPairMap &PairMap) { 6240b57cec5SDimitry Andric bool Load = MI->mayLoad(); 6250b57cec5SDimitry Andric unsigned OrigOpc = MI->getOpcode(); 6260b57cec5SDimitry Andric bool PostInc = (OrigOpc == Hexagon::L2_loadrd_pi || 6270b57cec5SDimitry Andric OrigOpc == Hexagon::S2_storerd_pi); 6280b57cec5SDimitry Andric MachineInstr *LowI, *HighI; 6290b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 6300b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 6310b57cec5SDimitry Andric 6320b57cec5SDimitry Andric // Index of the base-address-register operand. 6330b57cec5SDimitry Andric unsigned AdrX = PostInc ? (Load ? 2 : 1) 6340b57cec5SDimitry Andric : (Load ? 1 : 0); 6350b57cec5SDimitry Andric MachineOperand &AdrOp = MI->getOperand(AdrX); 6360b57cec5SDimitry Andric unsigned RSA = getRegState(AdrOp); 6370b57cec5SDimitry Andric MachineOperand &ValOp = Load ? MI->getOperand(0) 6380b57cec5SDimitry Andric : (PostInc ? MI->getOperand(3) 6390b57cec5SDimitry Andric : MI->getOperand(2)); 6400b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(ValOp.getReg()); 6410b57cec5SDimitry Andric assert(F != PairMap.end()); 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andric if (Load) { 6440b57cec5SDimitry Andric const UUPair &P = F->second; 6450b57cec5SDimitry Andric int64_t Off = PostInc ? 0 : MI->getOperand(2).getImm(); 6460b57cec5SDimitry Andric LowI = BuildMI(B, MI, DL, TII->get(Hexagon::L2_loadri_io), P.first) 6470b57cec5SDimitry Andric .addReg(AdrOp.getReg(), RSA & ~RegState::Kill, AdrOp.getSubReg()) 6480b57cec5SDimitry Andric .addImm(Off); 6490b57cec5SDimitry Andric HighI = BuildMI(B, MI, DL, TII->get(Hexagon::L2_loadri_io), P.second) 6500b57cec5SDimitry Andric .addReg(AdrOp.getReg(), RSA & ~RegState::Kill, AdrOp.getSubReg()) 6510b57cec5SDimitry Andric .addImm(Off+4); 6520b57cec5SDimitry Andric } else { 6530b57cec5SDimitry Andric const UUPair &P = F->second; 6540b57cec5SDimitry Andric int64_t Off = PostInc ? 0 : MI->getOperand(1).getImm(); 6550b57cec5SDimitry Andric LowI = BuildMI(B, MI, DL, TII->get(Hexagon::S2_storeri_io)) 6560b57cec5SDimitry Andric .addReg(AdrOp.getReg(), RSA & ~RegState::Kill, AdrOp.getSubReg()) 6570b57cec5SDimitry Andric .addImm(Off) 6580b57cec5SDimitry Andric .addReg(P.first); 6590b57cec5SDimitry Andric HighI = BuildMI(B, MI, DL, TII->get(Hexagon::S2_storeri_io)) 6600b57cec5SDimitry Andric .addReg(AdrOp.getReg(), RSA & ~RegState::Kill, AdrOp.getSubReg()) 6610b57cec5SDimitry Andric .addImm(Off+4) 6620b57cec5SDimitry Andric .addReg(P.second); 6630b57cec5SDimitry Andric } 6640b57cec5SDimitry Andric 6650b57cec5SDimitry Andric if (PostInc) { 6660b57cec5SDimitry Andric // Create the increment of the address register. 6670b57cec5SDimitry Andric int64_t Inc = Load ? MI->getOperand(3).getImm() 6680b57cec5SDimitry Andric : MI->getOperand(2).getImm(); 6690b57cec5SDimitry Andric MachineOperand &UpdOp = Load ? MI->getOperand(1) : MI->getOperand(0); 6700b57cec5SDimitry Andric const TargetRegisterClass *RC = MRI->getRegClass(UpdOp.getReg()); 6718bcb0991SDimitry Andric Register NewR = MRI->createVirtualRegister(RC); 6720b57cec5SDimitry Andric assert(!UpdOp.getSubReg() && "Def operand with subreg"); 6730b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(Hexagon::A2_addi), NewR) 6740b57cec5SDimitry Andric .addReg(AdrOp.getReg(), RSA) 6750b57cec5SDimitry Andric .addImm(Inc); 6760b57cec5SDimitry Andric MRI->replaceRegWith(UpdOp.getReg(), NewR); 6770b57cec5SDimitry Andric // The original instruction will be deleted later. 6780b57cec5SDimitry Andric } 6790b57cec5SDimitry Andric 6800b57cec5SDimitry Andric // Generate a new pair of memory-operands. 6810b57cec5SDimitry Andric MachineFunction &MF = *B.getParent(); 6820b57cec5SDimitry Andric for (auto &MO : MI->memoperands()) { 6830b57cec5SDimitry Andric const MachinePointerInfo &Ptr = MO->getPointerInfo(); 6840b57cec5SDimitry Andric MachineMemOperand::Flags F = MO->getFlags(); 6855ffd83dbSDimitry Andric Align A = MO->getAlign(); 6860b57cec5SDimitry Andric 6870b57cec5SDimitry Andric auto *Tmp1 = MF.getMachineMemOperand(Ptr, F, 4 /*size*/, A); 6880b57cec5SDimitry Andric LowI->addMemOperand(MF, Tmp1); 6895ffd83dbSDimitry Andric auto *Tmp2 = 6905ffd83dbSDimitry Andric MF.getMachineMemOperand(Ptr, F, 4 /*size*/, std::min(A, Align(4))); 6910b57cec5SDimitry Andric HighI->addMemOperand(MF, Tmp2); 6920b57cec5SDimitry Andric } 6930b57cec5SDimitry Andric } 6940b57cec5SDimitry Andric 6950b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitImmediate(MachineInstr *MI, 6960b57cec5SDimitry Andric const UUPairMap &PairMap) { 6970b57cec5SDimitry Andric MachineOperand &Op0 = MI->getOperand(0); 6980b57cec5SDimitry Andric MachineOperand &Op1 = MI->getOperand(1); 6990b57cec5SDimitry Andric assert(Op0.isReg() && Op1.isImm()); 7000b57cec5SDimitry Andric uint64_t V = Op1.getImm(); 7010b57cec5SDimitry Andric 7020b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 7030b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 7040b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(Op0.getReg()); 7050b57cec5SDimitry Andric assert(F != PairMap.end()); 7060b57cec5SDimitry Andric const UUPair &P = F->second; 7070b57cec5SDimitry Andric 7080b57cec5SDimitry Andric // The operand to A2_tfrsi can only have 32 significant bits. Immediate 7090b57cec5SDimitry Andric // values in MachineOperand are stored as 64-bit integers, and so the 7100b57cec5SDimitry Andric // value -1 may be represented either as 64-bit -1, or 4294967295. Both 7110b57cec5SDimitry Andric // will have the 32 higher bits truncated in the end, but -1 will remain 7120b57cec5SDimitry Andric // as -1, while the latter may appear to be a large unsigned value 7130b57cec5SDimitry Andric // requiring a constant extender. The casting to int32_t will select the 7140b57cec5SDimitry Andric // former representation. (The same reasoning applies to all 32-bit 7150b57cec5SDimitry Andric // values.) 7160b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), P.first) 7170b57cec5SDimitry Andric .addImm(int32_t(V & 0xFFFFFFFFULL)); 7180b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), P.second) 7190b57cec5SDimitry Andric .addImm(int32_t(V >> 32)); 7200b57cec5SDimitry Andric } 7210b57cec5SDimitry Andric 7220b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitCombine(MachineInstr *MI, 7230b57cec5SDimitry Andric const UUPairMap &PairMap) { 7240b57cec5SDimitry Andric MachineOperand &Op0 = MI->getOperand(0); 7250b57cec5SDimitry Andric MachineOperand &Op1 = MI->getOperand(1); 7260b57cec5SDimitry Andric MachineOperand &Op2 = MI->getOperand(2); 7270b57cec5SDimitry Andric assert(Op0.isReg()); 7280b57cec5SDimitry Andric 7290b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 7300b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 7310b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(Op0.getReg()); 7320b57cec5SDimitry Andric assert(F != PairMap.end()); 7330b57cec5SDimitry Andric const UUPair &P = F->second; 7340b57cec5SDimitry Andric 7350b57cec5SDimitry Andric if (!Op1.isReg()) { 7360b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), P.second) 7370b57cec5SDimitry Andric .add(Op1); 7380b57cec5SDimitry Andric } else { 7390b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), P.second) 7400b57cec5SDimitry Andric .addReg(Op1.getReg(), getRegState(Op1), Op1.getSubReg()); 7410b57cec5SDimitry Andric } 7420b57cec5SDimitry Andric 7430b57cec5SDimitry Andric if (!Op2.isReg()) { 7440b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), P.first) 7450b57cec5SDimitry Andric .add(Op2); 7460b57cec5SDimitry Andric } else { 7470b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), P.first) 7480b57cec5SDimitry Andric .addReg(Op2.getReg(), getRegState(Op2), Op2.getSubReg()); 7490b57cec5SDimitry Andric } 7500b57cec5SDimitry Andric } 7510b57cec5SDimitry Andric 7520b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitExt(MachineInstr *MI, 7530b57cec5SDimitry Andric const UUPairMap &PairMap) { 7540b57cec5SDimitry Andric MachineOperand &Op0 = MI->getOperand(0); 7550b57cec5SDimitry Andric MachineOperand &Op1 = MI->getOperand(1); 7560b57cec5SDimitry Andric assert(Op0.isReg() && Op1.isReg()); 7570b57cec5SDimitry Andric 7580b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 7590b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 7600b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(Op0.getReg()); 7610b57cec5SDimitry Andric assert(F != PairMap.end()); 7620b57cec5SDimitry Andric const UUPair &P = F->second; 7630b57cec5SDimitry Andric unsigned RS = getRegState(Op1); 7640b57cec5SDimitry Andric 7650b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), P.first) 7660b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, Op1.getSubReg()); 7670b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(Hexagon::S2_asr_i_r), P.second) 7680b57cec5SDimitry Andric .addReg(Op1.getReg(), RS, Op1.getSubReg()) 7690b57cec5SDimitry Andric .addImm(31); 7700b57cec5SDimitry Andric } 7710b57cec5SDimitry Andric 7720b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitShift(MachineInstr *MI, 7730b57cec5SDimitry Andric const UUPairMap &PairMap) { 7740b57cec5SDimitry Andric using namespace Hexagon; 7750b57cec5SDimitry Andric 7760b57cec5SDimitry Andric MachineOperand &Op0 = MI->getOperand(0); 7770b57cec5SDimitry Andric MachineOperand &Op1 = MI->getOperand(1); 7780b57cec5SDimitry Andric MachineOperand &Op2 = MI->getOperand(2); 7790b57cec5SDimitry Andric assert(Op0.isReg() && Op1.isReg() && Op2.isImm()); 7800b57cec5SDimitry Andric int64_t Sh64 = Op2.getImm(); 7810b57cec5SDimitry Andric assert(Sh64 >= 0 && Sh64 < 64); 7820b57cec5SDimitry Andric unsigned S = Sh64; 7830b57cec5SDimitry Andric 7840b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(Op0.getReg()); 7850b57cec5SDimitry Andric assert(F != PairMap.end()); 7860b57cec5SDimitry Andric const UUPair &P = F->second; 7878bcb0991SDimitry Andric Register LoR = P.first; 7888bcb0991SDimitry Andric Register HiR = P.second; 7890b57cec5SDimitry Andric 7900b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 7910b57cec5SDimitry Andric bool Right = (Opc == S2_lsr_i_p || Opc == S2_asr_i_p); 7920b57cec5SDimitry Andric bool Left = !Right; 7930b57cec5SDimitry Andric bool Signed = (Opc == S2_asr_i_p); 7940b57cec5SDimitry Andric 7950b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 7960b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 7970b57cec5SDimitry Andric unsigned RS = getRegState(Op1); 7980b57cec5SDimitry Andric unsigned ShiftOpc = Left ? S2_asl_i_r 7990b57cec5SDimitry Andric : (Signed ? S2_asr_i_r : S2_lsr_i_r); 8000b57cec5SDimitry Andric unsigned LoSR = isub_lo; 8010b57cec5SDimitry Andric unsigned HiSR = isub_hi; 8020b57cec5SDimitry Andric 8030b57cec5SDimitry Andric if (S == 0) { 8040b57cec5SDimitry Andric // No shift, subregister copy. 8050b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), LoR) 8060b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR); 8070b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), HiR) 8080b57cec5SDimitry Andric .addReg(Op1.getReg(), RS, HiSR); 8090b57cec5SDimitry Andric } else if (S < 32) { 8100b57cec5SDimitry Andric const TargetRegisterClass *IntRC = &IntRegsRegClass; 8118bcb0991SDimitry Andric Register TmpR = MRI->createVirtualRegister(IntRC); 8120b57cec5SDimitry Andric // Expansion: 8130b57cec5SDimitry Andric // Shift left: DR = shl R, #s 8140b57cec5SDimitry Andric // LoR = shl R.lo, #s 8150b57cec5SDimitry Andric // TmpR = extractu R.lo, #s, #32-s 8160b57cec5SDimitry Andric // HiR = or (TmpR, asl(R.hi, #s)) 8170b57cec5SDimitry Andric // Shift right: DR = shr R, #s 8180b57cec5SDimitry Andric // HiR = shr R.hi, #s 8190b57cec5SDimitry Andric // TmpR = shr R.lo, #s 8200b57cec5SDimitry Andric // LoR = insert TmpR, R.hi, #s, #32-s 8210b57cec5SDimitry Andric 8220b57cec5SDimitry Andric // Shift left: 8230b57cec5SDimitry Andric // LoR = shl R.lo, #s 8240b57cec5SDimitry Andric // Shift right: 8250b57cec5SDimitry Andric // TmpR = shr R.lo, #s 8260b57cec5SDimitry Andric 8270b57cec5SDimitry Andric // Make a special case for A2_aslh and A2_asrh (they are predicable as 8280b57cec5SDimitry Andric // opposed to S2_asl_i_r/S2_asr_i_r). 8290b57cec5SDimitry Andric if (S == 16 && Left) 8300b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_aslh), LoR) 8310b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR); 8320b57cec5SDimitry Andric else if (S == 16 && Signed) 8330b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_asrh), TmpR) 8340b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR); 8350b57cec5SDimitry Andric else 8360b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(ShiftOpc), (Left ? LoR : TmpR)) 8370b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR) 8380b57cec5SDimitry Andric .addImm(S); 8390b57cec5SDimitry Andric 8400b57cec5SDimitry Andric if (Left) { 8410b57cec5SDimitry Andric // TmpR = extractu R.lo, #s, #32-s 8420b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_extractu), TmpR) 8430b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR) 8440b57cec5SDimitry Andric .addImm(S) 8450b57cec5SDimitry Andric .addImm(32-S); 8460b57cec5SDimitry Andric // HiR = or (TmpR, asl(R.hi, #s)) 8470b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_asl_i_r_or), HiR) 8480b57cec5SDimitry Andric .addReg(TmpR) 8490b57cec5SDimitry Andric .addReg(Op1.getReg(), RS, HiSR) 8500b57cec5SDimitry Andric .addImm(S); 8510b57cec5SDimitry Andric } else { 8520b57cec5SDimitry Andric // HiR = shr R.hi, #s 8530b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(ShiftOpc), HiR) 8540b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, HiSR) 8550b57cec5SDimitry Andric .addImm(S); 8560b57cec5SDimitry Andric // LoR = insert TmpR, R.hi, #s, #32-s 8570b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_insert), LoR) 8580b57cec5SDimitry Andric .addReg(TmpR) 8590b57cec5SDimitry Andric .addReg(Op1.getReg(), RS, HiSR) 8600b57cec5SDimitry Andric .addImm(S) 8610b57cec5SDimitry Andric .addImm(32-S); 8620b57cec5SDimitry Andric } 8630b57cec5SDimitry Andric } else if (S == 32) { 8640b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), (Left ? HiR : LoR)) 8650b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, (Left ? LoSR : HiSR)); 8660b57cec5SDimitry Andric if (!Signed) 8670b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_tfrsi), (Left ? LoR : HiR)) 8680b57cec5SDimitry Andric .addImm(0); 8690b57cec5SDimitry Andric else // Must be right shift. 8700b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_asr_i_r), HiR) 8710b57cec5SDimitry Andric .addReg(Op1.getReg(), RS, HiSR) 8720b57cec5SDimitry Andric .addImm(31); 8730b57cec5SDimitry Andric } else if (S < 64) { 8740b57cec5SDimitry Andric S -= 32; 8750b57cec5SDimitry Andric if (S == 16 && Left) 8760b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_aslh), HiR) 8770b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR); 8780b57cec5SDimitry Andric else if (S == 16 && Signed) 8790b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_asrh), LoR) 8800b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, HiSR); 8810b57cec5SDimitry Andric else 8820b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(ShiftOpc), (Left ? HiR : LoR)) 8830b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, (Left ? LoSR : HiSR)) 8840b57cec5SDimitry Andric .addImm(S); 8850b57cec5SDimitry Andric 8860b57cec5SDimitry Andric if (Signed) 8870b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_asr_i_r), HiR) 8880b57cec5SDimitry Andric .addReg(Op1.getReg(), RS, HiSR) 8890b57cec5SDimitry Andric .addImm(31); 8900b57cec5SDimitry Andric else 8910b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_tfrsi), (Left ? LoR : HiR)) 8920b57cec5SDimitry Andric .addImm(0); 8930b57cec5SDimitry Andric } 8940b57cec5SDimitry Andric } 8950b57cec5SDimitry Andric 8960b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitAslOr(MachineInstr *MI, 8970b57cec5SDimitry Andric const UUPairMap &PairMap) { 8980b57cec5SDimitry Andric using namespace Hexagon; 8990b57cec5SDimitry Andric 9000b57cec5SDimitry Andric MachineOperand &Op0 = MI->getOperand(0); 9010b57cec5SDimitry Andric MachineOperand &Op1 = MI->getOperand(1); 9020b57cec5SDimitry Andric MachineOperand &Op2 = MI->getOperand(2); 9030b57cec5SDimitry Andric MachineOperand &Op3 = MI->getOperand(3); 9040b57cec5SDimitry Andric assert(Op0.isReg() && Op1.isReg() && Op2.isReg() && Op3.isImm()); 9050b57cec5SDimitry Andric int64_t Sh64 = Op3.getImm(); 9060b57cec5SDimitry Andric assert(Sh64 >= 0 && Sh64 < 64); 9070b57cec5SDimitry Andric unsigned S = Sh64; 9080b57cec5SDimitry Andric 9090b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(Op0.getReg()); 9100b57cec5SDimitry Andric assert(F != PairMap.end()); 9110b57cec5SDimitry Andric const UUPair &P = F->second; 9120b57cec5SDimitry Andric unsigned LoR = P.first; 9130b57cec5SDimitry Andric unsigned HiR = P.second; 9140b57cec5SDimitry Andric 9150b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 9160b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 9170b57cec5SDimitry Andric unsigned RS1 = getRegState(Op1); 9180b57cec5SDimitry Andric unsigned RS2 = getRegState(Op2); 9190b57cec5SDimitry Andric const TargetRegisterClass *IntRC = &IntRegsRegClass; 9200b57cec5SDimitry Andric 9210b57cec5SDimitry Andric unsigned LoSR = isub_lo; 9220b57cec5SDimitry Andric unsigned HiSR = isub_hi; 9230b57cec5SDimitry Andric 9240b57cec5SDimitry Andric // Op0 = S2_asl_i_p_or Op1, Op2, Op3 9250b57cec5SDimitry Andric // means: Op0 = or (Op1, asl(Op2, Op3)) 9260b57cec5SDimitry Andric 9270b57cec5SDimitry Andric // Expansion of 9280b57cec5SDimitry Andric // DR = or (R1, asl(R2, #s)) 9290b57cec5SDimitry Andric // 9300b57cec5SDimitry Andric // LoR = or (R1.lo, asl(R2.lo, #s)) 9310b57cec5SDimitry Andric // Tmp1 = extractu R2.lo, #s, #32-s 9320b57cec5SDimitry Andric // Tmp2 = or R1.hi, Tmp1 9330b57cec5SDimitry Andric // HiR = or (Tmp2, asl(R2.hi, #s)) 9340b57cec5SDimitry Andric 9350b57cec5SDimitry Andric if (S == 0) { 9360b57cec5SDimitry Andric // DR = or (R1, asl(R2, #0)) 9370b57cec5SDimitry Andric // -> or (R1, R2) 9380b57cec5SDimitry Andric // i.e. LoR = or R1.lo, R2.lo 9390b57cec5SDimitry Andric // HiR = or R1.hi, R2.hi 9400b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_or), LoR) 9410b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1 & ~RegState::Kill, LoSR) 9420b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2 & ~RegState::Kill, LoSR); 9430b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_or), HiR) 9440b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1, HiSR) 9450b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2, HiSR); 9460b57cec5SDimitry Andric } else if (S < 32) { 9470b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_asl_i_r_or), LoR) 9480b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1 & ~RegState::Kill, LoSR) 9490b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2 & ~RegState::Kill, LoSR) 9500b57cec5SDimitry Andric .addImm(S); 9518bcb0991SDimitry Andric Register TmpR1 = MRI->createVirtualRegister(IntRC); 9520b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_extractu), TmpR1) 9530b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2 & ~RegState::Kill, LoSR) 9540b57cec5SDimitry Andric .addImm(S) 9550b57cec5SDimitry Andric .addImm(32-S); 9568bcb0991SDimitry Andric Register TmpR2 = MRI->createVirtualRegister(IntRC); 9570b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_or), TmpR2) 9580b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1, HiSR) 9590b57cec5SDimitry Andric .addReg(TmpR1); 9600b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_asl_i_r_or), HiR) 9610b57cec5SDimitry Andric .addReg(TmpR2) 9620b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2, HiSR) 9630b57cec5SDimitry Andric .addImm(S); 9640b57cec5SDimitry Andric } else if (S == 32) { 9650b57cec5SDimitry Andric // DR = or (R1, asl(R2, #32)) 9660b57cec5SDimitry Andric // -> or R1, R2.lo 9670b57cec5SDimitry Andric // LoR = R1.lo 9680b57cec5SDimitry Andric // HiR = or R1.hi, R2.lo 9690b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), LoR) 9700b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1 & ~RegState::Kill, LoSR); 9710b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_or), HiR) 9720b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1, HiSR) 9730b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2, LoSR); 9740b57cec5SDimitry Andric } else if (S < 64) { 9750b57cec5SDimitry Andric // DR = or (R1, asl(R2, #s)) 9760b57cec5SDimitry Andric // 9770b57cec5SDimitry Andric // LoR = R1:lo 9780b57cec5SDimitry Andric // HiR = or (R1:hi, asl(R2:lo, #s-32)) 9790b57cec5SDimitry Andric S -= 32; 9800b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), LoR) 9810b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1 & ~RegState::Kill, LoSR); 9820b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_asl_i_r_or), HiR) 9830b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1, HiSR) 9840b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2, LoSR) 9850b57cec5SDimitry Andric .addImm(S); 9860b57cec5SDimitry Andric } 9870b57cec5SDimitry Andric } 9880b57cec5SDimitry Andric 9890b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::splitInstr(MachineInstr *MI, 9900b57cec5SDimitry Andric const UUPairMap &PairMap) { 9910b57cec5SDimitry Andric using namespace Hexagon; 9920b57cec5SDimitry Andric 9930b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Splitting: " << *MI); 9940b57cec5SDimitry Andric bool Split = false; 9950b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 9960b57cec5SDimitry Andric 9970b57cec5SDimitry Andric switch (Opc) { 9980b57cec5SDimitry Andric case TargetOpcode::PHI: 9990b57cec5SDimitry Andric case TargetOpcode::COPY: { 10008bcb0991SDimitry Andric Register DstR = MI->getOperand(0).getReg(); 10010b57cec5SDimitry Andric if (MRI->getRegClass(DstR) == DoubleRC) { 10020b57cec5SDimitry Andric createHalfInstr(Opc, MI, PairMap, isub_lo); 10030b57cec5SDimitry Andric createHalfInstr(Opc, MI, PairMap, isub_hi); 10040b57cec5SDimitry Andric Split = true; 10050b57cec5SDimitry Andric } 10060b57cec5SDimitry Andric break; 10070b57cec5SDimitry Andric } 10080b57cec5SDimitry Andric case A2_andp: 10090b57cec5SDimitry Andric createHalfInstr(A2_and, MI, PairMap, isub_lo); 10100b57cec5SDimitry Andric createHalfInstr(A2_and, MI, PairMap, isub_hi); 10110b57cec5SDimitry Andric Split = true; 10120b57cec5SDimitry Andric break; 10130b57cec5SDimitry Andric case A2_orp: 10140b57cec5SDimitry Andric createHalfInstr(A2_or, MI, PairMap, isub_lo); 10150b57cec5SDimitry Andric createHalfInstr(A2_or, MI, PairMap, isub_hi); 10160b57cec5SDimitry Andric Split = true; 10170b57cec5SDimitry Andric break; 10180b57cec5SDimitry Andric case A2_xorp: 10190b57cec5SDimitry Andric createHalfInstr(A2_xor, MI, PairMap, isub_lo); 10200b57cec5SDimitry Andric createHalfInstr(A2_xor, MI, PairMap, isub_hi); 10210b57cec5SDimitry Andric Split = true; 10220b57cec5SDimitry Andric break; 10230b57cec5SDimitry Andric 10240b57cec5SDimitry Andric case L2_loadrd_io: 10250b57cec5SDimitry Andric case L2_loadrd_pi: 10260b57cec5SDimitry Andric case S2_storerd_io: 10270b57cec5SDimitry Andric case S2_storerd_pi: 10280b57cec5SDimitry Andric splitMemRef(MI, PairMap); 10290b57cec5SDimitry Andric Split = true; 10300b57cec5SDimitry Andric break; 10310b57cec5SDimitry Andric 10320b57cec5SDimitry Andric case A2_tfrpi: 10330b57cec5SDimitry Andric case CONST64: 10340b57cec5SDimitry Andric splitImmediate(MI, PairMap); 10350b57cec5SDimitry Andric Split = true; 10360b57cec5SDimitry Andric break; 10370b57cec5SDimitry Andric 10380b57cec5SDimitry Andric case A2_combineii: 10390b57cec5SDimitry Andric case A4_combineir: 10400b57cec5SDimitry Andric case A4_combineii: 10410b57cec5SDimitry Andric case A4_combineri: 10420b57cec5SDimitry Andric case A2_combinew: 10430b57cec5SDimitry Andric splitCombine(MI, PairMap); 10440b57cec5SDimitry Andric Split = true; 10450b57cec5SDimitry Andric break; 10460b57cec5SDimitry Andric 10470b57cec5SDimitry Andric case A2_sxtw: 10480b57cec5SDimitry Andric splitExt(MI, PairMap); 10490b57cec5SDimitry Andric Split = true; 10500b57cec5SDimitry Andric break; 10510b57cec5SDimitry Andric 10520b57cec5SDimitry Andric case S2_asl_i_p: 10530b57cec5SDimitry Andric case S2_asr_i_p: 10540b57cec5SDimitry Andric case S2_lsr_i_p: 10550b57cec5SDimitry Andric splitShift(MI, PairMap); 10560b57cec5SDimitry Andric Split = true; 10570b57cec5SDimitry Andric break; 10580b57cec5SDimitry Andric 10590b57cec5SDimitry Andric case S2_asl_i_p_or: 10600b57cec5SDimitry Andric splitAslOr(MI, PairMap); 10610b57cec5SDimitry Andric Split = true; 10620b57cec5SDimitry Andric break; 10630b57cec5SDimitry Andric 10640b57cec5SDimitry Andric default: 10650b57cec5SDimitry Andric llvm_unreachable("Instruction not splitable"); 10660b57cec5SDimitry Andric return false; 10670b57cec5SDimitry Andric } 10680b57cec5SDimitry Andric 10690b57cec5SDimitry Andric return Split; 10700b57cec5SDimitry Andric } 10710b57cec5SDimitry Andric 10720b57cec5SDimitry Andric void HexagonSplitDoubleRegs::replaceSubregUses(MachineInstr *MI, 10730b57cec5SDimitry Andric const UUPairMap &PairMap) { 10740b57cec5SDimitry Andric for (auto &Op : MI->operands()) { 10750b57cec5SDimitry Andric if (!Op.isReg() || !Op.isUse() || !Op.getSubReg()) 10760b57cec5SDimitry Andric continue; 10778bcb0991SDimitry Andric Register R = Op.getReg(); 10780b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(R); 10790b57cec5SDimitry Andric if (F == PairMap.end()) 10800b57cec5SDimitry Andric continue; 10810b57cec5SDimitry Andric const UUPair &P = F->second; 10820b57cec5SDimitry Andric switch (Op.getSubReg()) { 10830b57cec5SDimitry Andric case Hexagon::isub_lo: 10840b57cec5SDimitry Andric Op.setReg(P.first); 10850b57cec5SDimitry Andric break; 10860b57cec5SDimitry Andric case Hexagon::isub_hi: 10870b57cec5SDimitry Andric Op.setReg(P.second); 10880b57cec5SDimitry Andric break; 10890b57cec5SDimitry Andric } 10900b57cec5SDimitry Andric Op.setSubReg(0); 10910b57cec5SDimitry Andric } 10920b57cec5SDimitry Andric } 10930b57cec5SDimitry Andric 10940b57cec5SDimitry Andric void HexagonSplitDoubleRegs::collapseRegPairs(MachineInstr *MI, 10950b57cec5SDimitry Andric const UUPairMap &PairMap) { 10960b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 10970b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 10980b57cec5SDimitry Andric 10990b57cec5SDimitry Andric for (auto &Op : MI->operands()) { 11000b57cec5SDimitry Andric if (!Op.isReg() || !Op.isUse()) 11010b57cec5SDimitry Andric continue; 11028bcb0991SDimitry Andric Register R = Op.getReg(); 1103e8d8bef9SDimitry Andric if (!R.isVirtual()) 11040b57cec5SDimitry Andric continue; 11050b57cec5SDimitry Andric if (MRI->getRegClass(R) != DoubleRC || Op.getSubReg()) 11060b57cec5SDimitry Andric continue; 11070b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(R); 11080b57cec5SDimitry Andric if (F == PairMap.end()) 11090b57cec5SDimitry Andric continue; 11100b57cec5SDimitry Andric const UUPair &Pr = F->second; 11118bcb0991SDimitry Andric Register NewDR = MRI->createVirtualRegister(DoubleRC); 11120b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::REG_SEQUENCE), NewDR) 11130b57cec5SDimitry Andric .addReg(Pr.first) 11140b57cec5SDimitry Andric .addImm(Hexagon::isub_lo) 11150b57cec5SDimitry Andric .addReg(Pr.second) 11160b57cec5SDimitry Andric .addImm(Hexagon::isub_hi); 11170b57cec5SDimitry Andric Op.setReg(NewDR); 11180b57cec5SDimitry Andric } 11190b57cec5SDimitry Andric } 11200b57cec5SDimitry Andric 11210b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::splitPartition(const USet &Part) { 11220b57cec5SDimitry Andric using MISet = std::set<MachineInstr *>; 11230b57cec5SDimitry Andric 11240b57cec5SDimitry Andric const TargetRegisterClass *IntRC = &Hexagon::IntRegsRegClass; 11250b57cec5SDimitry Andric bool Changed = false; 11260b57cec5SDimitry Andric 11270b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Splitting partition: "; 11280b57cec5SDimitry Andric dump_partition(dbgs(), Part, *TRI); dbgs() << '\n'); 11290b57cec5SDimitry Andric 11300b57cec5SDimitry Andric UUPairMap PairMap; 11310b57cec5SDimitry Andric 11320b57cec5SDimitry Andric MISet SplitIns; 11330b57cec5SDimitry Andric for (unsigned DR : Part) { 11340b57cec5SDimitry Andric MachineInstr *DefI = MRI->getVRegDef(DR); 11350b57cec5SDimitry Andric SplitIns.insert(DefI); 11360b57cec5SDimitry Andric 11370b57cec5SDimitry Andric // Collect all instructions, including fixed ones. We won't split them, 11380b57cec5SDimitry Andric // but we need to visit them again to insert the REG_SEQUENCE instructions. 11390b57cec5SDimitry Andric for (auto U = MRI->use_nodbg_begin(DR), W = MRI->use_nodbg_end(); 11400b57cec5SDimitry Andric U != W; ++U) 11410b57cec5SDimitry Andric SplitIns.insert(U->getParent()); 11420b57cec5SDimitry Andric 11438bcb0991SDimitry Andric Register LoR = MRI->createVirtualRegister(IntRC); 11448bcb0991SDimitry Andric Register HiR = MRI->createVirtualRegister(IntRC); 11450b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Created mapping: " << printReg(DR, TRI) << " -> " 11460b57cec5SDimitry Andric << printReg(HiR, TRI) << ':' << printReg(LoR, TRI) 11470b57cec5SDimitry Andric << '\n'); 11480b57cec5SDimitry Andric PairMap.insert(std::make_pair(DR, UUPair(LoR, HiR))); 11490b57cec5SDimitry Andric } 11500b57cec5SDimitry Andric 11510b57cec5SDimitry Andric MISet Erase; 1152bdd1243dSDimitry Andric for (auto *MI : SplitIns) { 11530b57cec5SDimitry Andric if (isFixedInstr(MI)) { 11540b57cec5SDimitry Andric collapseRegPairs(MI, PairMap); 11550b57cec5SDimitry Andric } else { 11560b57cec5SDimitry Andric bool Done = splitInstr(MI, PairMap); 11570b57cec5SDimitry Andric if (Done) 11580b57cec5SDimitry Andric Erase.insert(MI); 11590b57cec5SDimitry Andric Changed |= Done; 11600b57cec5SDimitry Andric } 11610b57cec5SDimitry Andric } 11620b57cec5SDimitry Andric 11630b57cec5SDimitry Andric for (unsigned DR : Part) { 11640b57cec5SDimitry Andric // Before erasing "double" instructions, revisit all uses of the double 11650b57cec5SDimitry Andric // registers in this partition, and replace all uses of them with subre- 11660b57cec5SDimitry Andric // gisters, with the corresponding single registers. 11670b57cec5SDimitry Andric MISet Uses; 11680b57cec5SDimitry Andric for (auto U = MRI->use_nodbg_begin(DR), W = MRI->use_nodbg_end(); 11690b57cec5SDimitry Andric U != W; ++U) 11700b57cec5SDimitry Andric Uses.insert(U->getParent()); 1171bdd1243dSDimitry Andric for (auto *M : Uses) 11720b57cec5SDimitry Andric replaceSubregUses(M, PairMap); 11730b57cec5SDimitry Andric } 11740b57cec5SDimitry Andric 1175bdd1243dSDimitry Andric for (auto *MI : Erase) { 11760b57cec5SDimitry Andric MachineBasicBlock *B = MI->getParent(); 11770b57cec5SDimitry Andric B->erase(MI); 11780b57cec5SDimitry Andric } 11790b57cec5SDimitry Andric 11800b57cec5SDimitry Andric return Changed; 11810b57cec5SDimitry Andric } 11820b57cec5SDimitry Andric 11830b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::runOnMachineFunction(MachineFunction &MF) { 11840b57cec5SDimitry Andric if (skipFunction(MF.getFunction())) 11850b57cec5SDimitry Andric return false; 11860b57cec5SDimitry Andric 11870b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Splitting double registers in function: " 11880b57cec5SDimitry Andric << MF.getName() << '\n'); 11890b57cec5SDimitry Andric 11900b57cec5SDimitry Andric auto &ST = MF.getSubtarget<HexagonSubtarget>(); 11910b57cec5SDimitry Andric TRI = ST.getRegisterInfo(); 11920b57cec5SDimitry Andric TII = ST.getInstrInfo(); 11930b57cec5SDimitry Andric MRI = &MF.getRegInfo(); 1194*0fca6ea1SDimitry Andric MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI(); 11950b57cec5SDimitry Andric 11960b57cec5SDimitry Andric UUSetMap P2Rs; 11970b57cec5SDimitry Andric LoopRegMap IRM; 11980b57cec5SDimitry Andric 11990b57cec5SDimitry Andric collectIndRegs(IRM); 12000b57cec5SDimitry Andric partitionRegisters(P2Rs); 12010b57cec5SDimitry Andric 12020b57cec5SDimitry Andric LLVM_DEBUG({ 12030b57cec5SDimitry Andric dbgs() << "Register partitioning: (partition #0 is fixed)\n"; 12040b57cec5SDimitry Andric for (UUSetMap::iterator I = P2Rs.begin(), E = P2Rs.end(); I != E; ++I) { 12050b57cec5SDimitry Andric dbgs() << '#' << I->first << " -> "; 12060b57cec5SDimitry Andric dump_partition(dbgs(), I->second, *TRI); 12070b57cec5SDimitry Andric dbgs() << '\n'; 12080b57cec5SDimitry Andric } 12090b57cec5SDimitry Andric }); 12100b57cec5SDimitry Andric 12110b57cec5SDimitry Andric bool Changed = false; 12120b57cec5SDimitry Andric int Limit = MaxHSDR; 12130b57cec5SDimitry Andric 12140b57cec5SDimitry Andric for (UUSetMap::iterator I = P2Rs.begin(), E = P2Rs.end(); I != E; ++I) { 12150b57cec5SDimitry Andric if (I->first == 0) 12160b57cec5SDimitry Andric continue; 12170b57cec5SDimitry Andric if (Limit >= 0 && Counter >= Limit) 12180b57cec5SDimitry Andric break; 12190b57cec5SDimitry Andric USet &Part = I->second; 12200b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Calculating profit for partition #" << I->first 12210b57cec5SDimitry Andric << '\n'); 12220b57cec5SDimitry Andric if (!isProfitable(Part, IRM)) 12230b57cec5SDimitry Andric continue; 12240b57cec5SDimitry Andric Counter++; 12250b57cec5SDimitry Andric Changed |= splitPartition(Part); 12260b57cec5SDimitry Andric } 12270b57cec5SDimitry Andric 12280b57cec5SDimitry Andric return Changed; 12290b57cec5SDimitry Andric } 12300b57cec5SDimitry Andric 12310b57cec5SDimitry Andric FunctionPass *llvm::createHexagonSplitDoubleRegs() { 12320b57cec5SDimitry Andric return new HexagonSplitDoubleRegs(); 12330b57cec5SDimitry Andric } 1234