1*0b57cec5SDimitry Andric //===- HexagonSplitDouble.cpp ---------------------------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #define DEBUG_TYPE "hsdr" 10*0b57cec5SDimitry Andric 11*0b57cec5SDimitry Andric #include "HexagonInstrInfo.h" 12*0b57cec5SDimitry Andric #include "HexagonRegisterInfo.h" 13*0b57cec5SDimitry Andric #include "HexagonSubtarget.h" 14*0b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h" 15*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 16*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 17*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 18*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 19*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 20*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 22*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 23*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h" 24*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h" 25*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 26*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 27*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 28*0b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h" 29*0b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h" 30*0b57cec5SDimitry Andric #include "llvm/Pass.h" 31*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 32*0b57cec5SDimitry Andric #include "llvm/Support/Compiler.h" 33*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 34*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 35*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 36*0b57cec5SDimitry Andric #include <algorithm> 37*0b57cec5SDimitry Andric #include <cassert> 38*0b57cec5SDimitry Andric #include <cstdint> 39*0b57cec5SDimitry Andric #include <limits> 40*0b57cec5SDimitry Andric #include <map> 41*0b57cec5SDimitry Andric #include <set> 42*0b57cec5SDimitry Andric #include <utility> 43*0b57cec5SDimitry Andric #include <vector> 44*0b57cec5SDimitry Andric 45*0b57cec5SDimitry Andric using namespace llvm; 46*0b57cec5SDimitry Andric 47*0b57cec5SDimitry Andric namespace llvm { 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric FunctionPass *createHexagonSplitDoubleRegs(); 50*0b57cec5SDimitry Andric void initializeHexagonSplitDoubleRegsPass(PassRegistry&); 51*0b57cec5SDimitry Andric 52*0b57cec5SDimitry Andric } // end namespace llvm 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric static cl::opt<int> MaxHSDR("max-hsdr", cl::Hidden, cl::init(-1), 55*0b57cec5SDimitry Andric cl::desc("Maximum number of split partitions")); 56*0b57cec5SDimitry Andric static cl::opt<bool> MemRefsFixed("hsdr-no-mem", cl::Hidden, cl::init(true), 57*0b57cec5SDimitry Andric cl::desc("Do not split loads or stores")); 58*0b57cec5SDimitry Andric static cl::opt<bool> SplitAll("hsdr-split-all", cl::Hidden, cl::init(false), 59*0b57cec5SDimitry Andric cl::desc("Split all partitions")); 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric namespace { 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric class HexagonSplitDoubleRegs : public MachineFunctionPass { 64*0b57cec5SDimitry Andric public: 65*0b57cec5SDimitry Andric static char ID; 66*0b57cec5SDimitry Andric 67*0b57cec5SDimitry Andric HexagonSplitDoubleRegs() : MachineFunctionPass(ID) {} 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric StringRef getPassName() const override { 70*0b57cec5SDimitry Andric return "Hexagon Split Double Registers"; 71*0b57cec5SDimitry Andric } 72*0b57cec5SDimitry Andric 73*0b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 74*0b57cec5SDimitry Andric AU.addRequired<MachineLoopInfo>(); 75*0b57cec5SDimitry Andric AU.addPreserved<MachineLoopInfo>(); 76*0b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 77*0b57cec5SDimitry Andric } 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric private: 82*0b57cec5SDimitry Andric static const TargetRegisterClass *const DoubleRC; 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric const HexagonRegisterInfo *TRI = nullptr; 85*0b57cec5SDimitry Andric const HexagonInstrInfo *TII = nullptr; 86*0b57cec5SDimitry Andric const MachineLoopInfo *MLI; 87*0b57cec5SDimitry Andric MachineRegisterInfo *MRI; 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric using USet = std::set<unsigned>; 90*0b57cec5SDimitry Andric using UUSetMap = std::map<unsigned, USet>; 91*0b57cec5SDimitry Andric using UUPair = std::pair<unsigned, unsigned>; 92*0b57cec5SDimitry Andric using UUPairMap = std::map<unsigned, UUPair>; 93*0b57cec5SDimitry Andric using LoopRegMap = std::map<const MachineLoop *, USet>; 94*0b57cec5SDimitry Andric 95*0b57cec5SDimitry Andric bool isInduction(unsigned Reg, LoopRegMap &IRM) const; 96*0b57cec5SDimitry Andric bool isVolatileInstr(const MachineInstr *MI) const; 97*0b57cec5SDimitry Andric bool isFixedInstr(const MachineInstr *MI) const; 98*0b57cec5SDimitry Andric void partitionRegisters(UUSetMap &P2Rs); 99*0b57cec5SDimitry Andric int32_t profit(const MachineInstr *MI) const; 100*0b57cec5SDimitry Andric int32_t profit(unsigned Reg) const; 101*0b57cec5SDimitry Andric bool isProfitable(const USet &Part, LoopRegMap &IRM) const; 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric void collectIndRegsForLoop(const MachineLoop *L, USet &Rs); 104*0b57cec5SDimitry Andric void collectIndRegs(LoopRegMap &IRM); 105*0b57cec5SDimitry Andric 106*0b57cec5SDimitry Andric void createHalfInstr(unsigned Opc, MachineInstr *MI, 107*0b57cec5SDimitry Andric const UUPairMap &PairMap, unsigned SubR); 108*0b57cec5SDimitry Andric void splitMemRef(MachineInstr *MI, const UUPairMap &PairMap); 109*0b57cec5SDimitry Andric void splitImmediate(MachineInstr *MI, const UUPairMap &PairMap); 110*0b57cec5SDimitry Andric void splitCombine(MachineInstr *MI, const UUPairMap &PairMap); 111*0b57cec5SDimitry Andric void splitExt(MachineInstr *MI, const UUPairMap &PairMap); 112*0b57cec5SDimitry Andric void splitShift(MachineInstr *MI, const UUPairMap &PairMap); 113*0b57cec5SDimitry Andric void splitAslOr(MachineInstr *MI, const UUPairMap &PairMap); 114*0b57cec5SDimitry Andric bool splitInstr(MachineInstr *MI, const UUPairMap &PairMap); 115*0b57cec5SDimitry Andric void replaceSubregUses(MachineInstr *MI, const UUPairMap &PairMap); 116*0b57cec5SDimitry Andric void collapseRegPairs(MachineInstr *MI, const UUPairMap &PairMap); 117*0b57cec5SDimitry Andric bool splitPartition(const USet &Part); 118*0b57cec5SDimitry Andric 119*0b57cec5SDimitry Andric static int Counter; 120*0b57cec5SDimitry Andric 121*0b57cec5SDimitry Andric static void dump_partition(raw_ostream&, const USet&, 122*0b57cec5SDimitry Andric const TargetRegisterInfo&); 123*0b57cec5SDimitry Andric }; 124*0b57cec5SDimitry Andric 125*0b57cec5SDimitry Andric } // end anonymous namespace 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric char HexagonSplitDoubleRegs::ID; 128*0b57cec5SDimitry Andric int HexagonSplitDoubleRegs::Counter = 0; 129*0b57cec5SDimitry Andric const TargetRegisterClass *const HexagonSplitDoubleRegs::DoubleRC = 130*0b57cec5SDimitry Andric &Hexagon::DoubleRegsRegClass; 131*0b57cec5SDimitry Andric 132*0b57cec5SDimitry Andric INITIALIZE_PASS(HexagonSplitDoubleRegs, "hexagon-split-double", 133*0b57cec5SDimitry Andric "Hexagon Split Double Registers", false, false) 134*0b57cec5SDimitry Andric 135*0b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 136*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void HexagonSplitDoubleRegs::dump_partition(raw_ostream &os, 137*0b57cec5SDimitry Andric const USet &Part, const TargetRegisterInfo &TRI) { 138*0b57cec5SDimitry Andric dbgs() << '{'; 139*0b57cec5SDimitry Andric for (auto I : Part) 140*0b57cec5SDimitry Andric dbgs() << ' ' << printReg(I, &TRI); 141*0b57cec5SDimitry Andric dbgs() << " }"; 142*0b57cec5SDimitry Andric } 143*0b57cec5SDimitry Andric #endif 144*0b57cec5SDimitry Andric 145*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::isInduction(unsigned Reg, LoopRegMap &IRM) const { 146*0b57cec5SDimitry Andric for (auto I : IRM) { 147*0b57cec5SDimitry Andric const USet &Rs = I.second; 148*0b57cec5SDimitry Andric if (Rs.find(Reg) != Rs.end()) 149*0b57cec5SDimitry Andric return true; 150*0b57cec5SDimitry Andric } 151*0b57cec5SDimitry Andric return false; 152*0b57cec5SDimitry Andric } 153*0b57cec5SDimitry Andric 154*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::isVolatileInstr(const MachineInstr *MI) const { 155*0b57cec5SDimitry Andric for (auto &MO : MI->memoperands()) 156*0b57cec5SDimitry Andric if (MO->isVolatile() || MO->isAtomic()) 157*0b57cec5SDimitry Andric return true; 158*0b57cec5SDimitry Andric return false; 159*0b57cec5SDimitry Andric } 160*0b57cec5SDimitry Andric 161*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::isFixedInstr(const MachineInstr *MI) const { 162*0b57cec5SDimitry Andric if (MI->mayLoad() || MI->mayStore()) 163*0b57cec5SDimitry Andric if (MemRefsFixed || isVolatileInstr(MI)) 164*0b57cec5SDimitry Andric return true; 165*0b57cec5SDimitry Andric if (MI->isDebugInstr()) 166*0b57cec5SDimitry Andric return false; 167*0b57cec5SDimitry Andric 168*0b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 169*0b57cec5SDimitry Andric switch (Opc) { 170*0b57cec5SDimitry Andric default: 171*0b57cec5SDimitry Andric return true; 172*0b57cec5SDimitry Andric 173*0b57cec5SDimitry Andric case TargetOpcode::PHI: 174*0b57cec5SDimitry Andric case TargetOpcode::COPY: 175*0b57cec5SDimitry Andric break; 176*0b57cec5SDimitry Andric 177*0b57cec5SDimitry Andric case Hexagon::L2_loadrd_io: 178*0b57cec5SDimitry Andric // Not handling stack stores (only reg-based addresses). 179*0b57cec5SDimitry Andric if (MI->getOperand(1).isReg()) 180*0b57cec5SDimitry Andric break; 181*0b57cec5SDimitry Andric return true; 182*0b57cec5SDimitry Andric case Hexagon::S2_storerd_io: 183*0b57cec5SDimitry Andric // Not handling stack stores (only reg-based addresses). 184*0b57cec5SDimitry Andric if (MI->getOperand(0).isReg()) 185*0b57cec5SDimitry Andric break; 186*0b57cec5SDimitry Andric return true; 187*0b57cec5SDimitry Andric case Hexagon::L2_loadrd_pi: 188*0b57cec5SDimitry Andric case Hexagon::S2_storerd_pi: 189*0b57cec5SDimitry Andric 190*0b57cec5SDimitry Andric case Hexagon::A2_tfrpi: 191*0b57cec5SDimitry Andric case Hexagon::A2_combineii: 192*0b57cec5SDimitry Andric case Hexagon::A4_combineir: 193*0b57cec5SDimitry Andric case Hexagon::A4_combineii: 194*0b57cec5SDimitry Andric case Hexagon::A4_combineri: 195*0b57cec5SDimitry Andric case Hexagon::A2_combinew: 196*0b57cec5SDimitry Andric case Hexagon::CONST64: 197*0b57cec5SDimitry Andric 198*0b57cec5SDimitry Andric case Hexagon::A2_sxtw: 199*0b57cec5SDimitry Andric 200*0b57cec5SDimitry Andric case Hexagon::A2_andp: 201*0b57cec5SDimitry Andric case Hexagon::A2_orp: 202*0b57cec5SDimitry Andric case Hexagon::A2_xorp: 203*0b57cec5SDimitry Andric case Hexagon::S2_asl_i_p_or: 204*0b57cec5SDimitry Andric case Hexagon::S2_asl_i_p: 205*0b57cec5SDimitry Andric case Hexagon::S2_asr_i_p: 206*0b57cec5SDimitry Andric case Hexagon::S2_lsr_i_p: 207*0b57cec5SDimitry Andric break; 208*0b57cec5SDimitry Andric } 209*0b57cec5SDimitry Andric 210*0b57cec5SDimitry Andric for (auto &Op : MI->operands()) { 211*0b57cec5SDimitry Andric if (!Op.isReg()) 212*0b57cec5SDimitry Andric continue; 213*0b57cec5SDimitry Andric unsigned R = Op.getReg(); 214*0b57cec5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(R)) 215*0b57cec5SDimitry Andric return true; 216*0b57cec5SDimitry Andric } 217*0b57cec5SDimitry Andric return false; 218*0b57cec5SDimitry Andric } 219*0b57cec5SDimitry Andric 220*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::partitionRegisters(UUSetMap &P2Rs) { 221*0b57cec5SDimitry Andric using UUMap = std::map<unsigned, unsigned>; 222*0b57cec5SDimitry Andric using UVect = std::vector<unsigned>; 223*0b57cec5SDimitry Andric 224*0b57cec5SDimitry Andric unsigned NumRegs = MRI->getNumVirtRegs(); 225*0b57cec5SDimitry Andric BitVector DoubleRegs(NumRegs); 226*0b57cec5SDimitry Andric for (unsigned i = 0; i < NumRegs; ++i) { 227*0b57cec5SDimitry Andric unsigned R = TargetRegisterInfo::index2VirtReg(i); 228*0b57cec5SDimitry Andric if (MRI->getRegClass(R) == DoubleRC) 229*0b57cec5SDimitry Andric DoubleRegs.set(i); 230*0b57cec5SDimitry Andric } 231*0b57cec5SDimitry Andric 232*0b57cec5SDimitry Andric BitVector FixedRegs(NumRegs); 233*0b57cec5SDimitry Andric for (int x = DoubleRegs.find_first(); x >= 0; x = DoubleRegs.find_next(x)) { 234*0b57cec5SDimitry Andric unsigned R = TargetRegisterInfo::index2VirtReg(x); 235*0b57cec5SDimitry Andric MachineInstr *DefI = MRI->getVRegDef(R); 236*0b57cec5SDimitry Andric // In some cases a register may exist, but never be defined or used. 237*0b57cec5SDimitry Andric // It should never appear anywhere, but mark it as "fixed", just to be 238*0b57cec5SDimitry Andric // safe. 239*0b57cec5SDimitry Andric if (!DefI || isFixedInstr(DefI)) 240*0b57cec5SDimitry Andric FixedRegs.set(x); 241*0b57cec5SDimitry Andric } 242*0b57cec5SDimitry Andric 243*0b57cec5SDimitry Andric UUSetMap AssocMap; 244*0b57cec5SDimitry Andric for (int x = DoubleRegs.find_first(); x >= 0; x = DoubleRegs.find_next(x)) { 245*0b57cec5SDimitry Andric if (FixedRegs[x]) 246*0b57cec5SDimitry Andric continue; 247*0b57cec5SDimitry Andric unsigned R = TargetRegisterInfo::index2VirtReg(x); 248*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << printReg(R, TRI) << " ~~"); 249*0b57cec5SDimitry Andric USet &Asc = AssocMap[R]; 250*0b57cec5SDimitry Andric for (auto U = MRI->use_nodbg_begin(R), Z = MRI->use_nodbg_end(); 251*0b57cec5SDimitry Andric U != Z; ++U) { 252*0b57cec5SDimitry Andric MachineOperand &Op = *U; 253*0b57cec5SDimitry Andric MachineInstr *UseI = Op.getParent(); 254*0b57cec5SDimitry Andric if (isFixedInstr(UseI)) 255*0b57cec5SDimitry Andric continue; 256*0b57cec5SDimitry Andric for (unsigned i = 0, n = UseI->getNumOperands(); i < n; ++i) { 257*0b57cec5SDimitry Andric MachineOperand &MO = UseI->getOperand(i); 258*0b57cec5SDimitry Andric // Skip non-registers or registers with subregisters. 259*0b57cec5SDimitry Andric if (&MO == &Op || !MO.isReg() || MO.getSubReg()) 260*0b57cec5SDimitry Andric continue; 261*0b57cec5SDimitry Andric unsigned T = MO.getReg(); 262*0b57cec5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(T)) { 263*0b57cec5SDimitry Andric FixedRegs.set(x); 264*0b57cec5SDimitry Andric continue; 265*0b57cec5SDimitry Andric } 266*0b57cec5SDimitry Andric if (MRI->getRegClass(T) != DoubleRC) 267*0b57cec5SDimitry Andric continue; 268*0b57cec5SDimitry Andric unsigned u = TargetRegisterInfo::virtReg2Index(T); 269*0b57cec5SDimitry Andric if (FixedRegs[u]) 270*0b57cec5SDimitry Andric continue; 271*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << ' ' << printReg(T, TRI)); 272*0b57cec5SDimitry Andric Asc.insert(T); 273*0b57cec5SDimitry Andric // Make it symmetric. 274*0b57cec5SDimitry Andric AssocMap[T].insert(R); 275*0b57cec5SDimitry Andric } 276*0b57cec5SDimitry Andric } 277*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << '\n'); 278*0b57cec5SDimitry Andric } 279*0b57cec5SDimitry Andric 280*0b57cec5SDimitry Andric UUMap R2P; 281*0b57cec5SDimitry Andric unsigned NextP = 1; 282*0b57cec5SDimitry Andric USet Visited; 283*0b57cec5SDimitry Andric for (int x = DoubleRegs.find_first(); x >= 0; x = DoubleRegs.find_next(x)) { 284*0b57cec5SDimitry Andric unsigned R = TargetRegisterInfo::index2VirtReg(x); 285*0b57cec5SDimitry Andric if (Visited.count(R)) 286*0b57cec5SDimitry Andric continue; 287*0b57cec5SDimitry Andric // Create a new partition for R. 288*0b57cec5SDimitry Andric unsigned ThisP = FixedRegs[x] ? 0 : NextP++; 289*0b57cec5SDimitry Andric UVect WorkQ; 290*0b57cec5SDimitry Andric WorkQ.push_back(R); 291*0b57cec5SDimitry Andric for (unsigned i = 0; i < WorkQ.size(); ++i) { 292*0b57cec5SDimitry Andric unsigned T = WorkQ[i]; 293*0b57cec5SDimitry Andric if (Visited.count(T)) 294*0b57cec5SDimitry Andric continue; 295*0b57cec5SDimitry Andric R2P[T] = ThisP; 296*0b57cec5SDimitry Andric Visited.insert(T); 297*0b57cec5SDimitry Andric // Add all registers associated with T. 298*0b57cec5SDimitry Andric USet &Asc = AssocMap[T]; 299*0b57cec5SDimitry Andric for (USet::iterator J = Asc.begin(), F = Asc.end(); J != F; ++J) 300*0b57cec5SDimitry Andric WorkQ.push_back(*J); 301*0b57cec5SDimitry Andric } 302*0b57cec5SDimitry Andric } 303*0b57cec5SDimitry Andric 304*0b57cec5SDimitry Andric for (auto I : R2P) 305*0b57cec5SDimitry Andric P2Rs[I.second].insert(I.first); 306*0b57cec5SDimitry Andric } 307*0b57cec5SDimitry Andric 308*0b57cec5SDimitry Andric static inline int32_t profitImm(unsigned Imm) { 309*0b57cec5SDimitry Andric int32_t P = 0; 310*0b57cec5SDimitry Andric if (Imm == 0 || Imm == 0xFFFFFFFF) 311*0b57cec5SDimitry Andric P += 10; 312*0b57cec5SDimitry Andric return P; 313*0b57cec5SDimitry Andric } 314*0b57cec5SDimitry Andric 315*0b57cec5SDimitry Andric int32_t HexagonSplitDoubleRegs::profit(const MachineInstr *MI) const { 316*0b57cec5SDimitry Andric unsigned ImmX = 0; 317*0b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 318*0b57cec5SDimitry Andric switch (Opc) { 319*0b57cec5SDimitry Andric case TargetOpcode::PHI: 320*0b57cec5SDimitry Andric for (const auto &Op : MI->operands()) 321*0b57cec5SDimitry Andric if (!Op.getSubReg()) 322*0b57cec5SDimitry Andric return 0; 323*0b57cec5SDimitry Andric return 10; 324*0b57cec5SDimitry Andric case TargetOpcode::COPY: 325*0b57cec5SDimitry Andric if (MI->getOperand(1).getSubReg() != 0) 326*0b57cec5SDimitry Andric return 10; 327*0b57cec5SDimitry Andric return 0; 328*0b57cec5SDimitry Andric 329*0b57cec5SDimitry Andric case Hexagon::L2_loadrd_io: 330*0b57cec5SDimitry Andric case Hexagon::S2_storerd_io: 331*0b57cec5SDimitry Andric return -1; 332*0b57cec5SDimitry Andric case Hexagon::L2_loadrd_pi: 333*0b57cec5SDimitry Andric case Hexagon::S2_storerd_pi: 334*0b57cec5SDimitry Andric return 2; 335*0b57cec5SDimitry Andric 336*0b57cec5SDimitry Andric case Hexagon::A2_tfrpi: 337*0b57cec5SDimitry Andric case Hexagon::CONST64: { 338*0b57cec5SDimitry Andric uint64_t D = MI->getOperand(1).getImm(); 339*0b57cec5SDimitry Andric unsigned Lo = D & 0xFFFFFFFFULL; 340*0b57cec5SDimitry Andric unsigned Hi = D >> 32; 341*0b57cec5SDimitry Andric return profitImm(Lo) + profitImm(Hi); 342*0b57cec5SDimitry Andric } 343*0b57cec5SDimitry Andric case Hexagon::A2_combineii: 344*0b57cec5SDimitry Andric case Hexagon::A4_combineii: { 345*0b57cec5SDimitry Andric const MachineOperand &Op1 = MI->getOperand(1); 346*0b57cec5SDimitry Andric const MachineOperand &Op2 = MI->getOperand(2); 347*0b57cec5SDimitry Andric int32_t Prof1 = Op1.isImm() ? profitImm(Op1.getImm()) : 0; 348*0b57cec5SDimitry Andric int32_t Prof2 = Op2.isImm() ? profitImm(Op2.getImm()) : 0; 349*0b57cec5SDimitry Andric return Prof1 + Prof2; 350*0b57cec5SDimitry Andric } 351*0b57cec5SDimitry Andric case Hexagon::A4_combineri: 352*0b57cec5SDimitry Andric ImmX++; 353*0b57cec5SDimitry Andric // Fall through into A4_combineir. 354*0b57cec5SDimitry Andric LLVM_FALLTHROUGH; 355*0b57cec5SDimitry Andric case Hexagon::A4_combineir: { 356*0b57cec5SDimitry Andric ImmX++; 357*0b57cec5SDimitry Andric const MachineOperand &OpX = MI->getOperand(ImmX); 358*0b57cec5SDimitry Andric if (OpX.isImm()) { 359*0b57cec5SDimitry Andric int64_t V = OpX.getImm(); 360*0b57cec5SDimitry Andric if (V == 0 || V == -1) 361*0b57cec5SDimitry Andric return 10; 362*0b57cec5SDimitry Andric } 363*0b57cec5SDimitry Andric // Fall through into A2_combinew. 364*0b57cec5SDimitry Andric LLVM_FALLTHROUGH; 365*0b57cec5SDimitry Andric } 366*0b57cec5SDimitry Andric case Hexagon::A2_combinew: 367*0b57cec5SDimitry Andric return 2; 368*0b57cec5SDimitry Andric 369*0b57cec5SDimitry Andric case Hexagon::A2_sxtw: 370*0b57cec5SDimitry Andric return 3; 371*0b57cec5SDimitry Andric 372*0b57cec5SDimitry Andric case Hexagon::A2_andp: 373*0b57cec5SDimitry Andric case Hexagon::A2_orp: 374*0b57cec5SDimitry Andric case Hexagon::A2_xorp: { 375*0b57cec5SDimitry Andric unsigned Rs = MI->getOperand(1).getReg(); 376*0b57cec5SDimitry Andric unsigned Rt = MI->getOperand(2).getReg(); 377*0b57cec5SDimitry Andric return profit(Rs) + profit(Rt); 378*0b57cec5SDimitry Andric } 379*0b57cec5SDimitry Andric 380*0b57cec5SDimitry Andric case Hexagon::S2_asl_i_p_or: { 381*0b57cec5SDimitry Andric unsigned S = MI->getOperand(3).getImm(); 382*0b57cec5SDimitry Andric if (S == 0 || S == 32) 383*0b57cec5SDimitry Andric return 10; 384*0b57cec5SDimitry Andric return -1; 385*0b57cec5SDimitry Andric } 386*0b57cec5SDimitry Andric case Hexagon::S2_asl_i_p: 387*0b57cec5SDimitry Andric case Hexagon::S2_asr_i_p: 388*0b57cec5SDimitry Andric case Hexagon::S2_lsr_i_p: 389*0b57cec5SDimitry Andric unsigned S = MI->getOperand(2).getImm(); 390*0b57cec5SDimitry Andric if (S == 0 || S == 32) 391*0b57cec5SDimitry Andric return 10; 392*0b57cec5SDimitry Andric if (S == 16) 393*0b57cec5SDimitry Andric return 5; 394*0b57cec5SDimitry Andric if (S == 48) 395*0b57cec5SDimitry Andric return 7; 396*0b57cec5SDimitry Andric return -10; 397*0b57cec5SDimitry Andric } 398*0b57cec5SDimitry Andric 399*0b57cec5SDimitry Andric return 0; 400*0b57cec5SDimitry Andric } 401*0b57cec5SDimitry Andric 402*0b57cec5SDimitry Andric int32_t HexagonSplitDoubleRegs::profit(unsigned Reg) const { 403*0b57cec5SDimitry Andric assert(TargetRegisterInfo::isVirtualRegister(Reg)); 404*0b57cec5SDimitry Andric 405*0b57cec5SDimitry Andric const MachineInstr *DefI = MRI->getVRegDef(Reg); 406*0b57cec5SDimitry Andric switch (DefI->getOpcode()) { 407*0b57cec5SDimitry Andric case Hexagon::A2_tfrpi: 408*0b57cec5SDimitry Andric case Hexagon::CONST64: 409*0b57cec5SDimitry Andric case Hexagon::A2_combineii: 410*0b57cec5SDimitry Andric case Hexagon::A4_combineii: 411*0b57cec5SDimitry Andric case Hexagon::A4_combineri: 412*0b57cec5SDimitry Andric case Hexagon::A4_combineir: 413*0b57cec5SDimitry Andric case Hexagon::A2_combinew: 414*0b57cec5SDimitry Andric return profit(DefI); 415*0b57cec5SDimitry Andric default: 416*0b57cec5SDimitry Andric break; 417*0b57cec5SDimitry Andric } 418*0b57cec5SDimitry Andric return 0; 419*0b57cec5SDimitry Andric } 420*0b57cec5SDimitry Andric 421*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::isProfitable(const USet &Part, LoopRegMap &IRM) 422*0b57cec5SDimitry Andric const { 423*0b57cec5SDimitry Andric unsigned FixedNum = 0, LoopPhiNum = 0; 424*0b57cec5SDimitry Andric int32_t TotalP = 0; 425*0b57cec5SDimitry Andric 426*0b57cec5SDimitry Andric for (unsigned DR : Part) { 427*0b57cec5SDimitry Andric MachineInstr *DefI = MRI->getVRegDef(DR); 428*0b57cec5SDimitry Andric int32_t P = profit(DefI); 429*0b57cec5SDimitry Andric if (P == std::numeric_limits<int>::min()) 430*0b57cec5SDimitry Andric return false; 431*0b57cec5SDimitry Andric TotalP += P; 432*0b57cec5SDimitry Andric // Reduce the profitability of splitting induction registers. 433*0b57cec5SDimitry Andric if (isInduction(DR, IRM)) 434*0b57cec5SDimitry Andric TotalP -= 30; 435*0b57cec5SDimitry Andric 436*0b57cec5SDimitry Andric for (auto U = MRI->use_nodbg_begin(DR), W = MRI->use_nodbg_end(); 437*0b57cec5SDimitry Andric U != W; ++U) { 438*0b57cec5SDimitry Andric MachineInstr *UseI = U->getParent(); 439*0b57cec5SDimitry Andric if (isFixedInstr(UseI)) { 440*0b57cec5SDimitry Andric FixedNum++; 441*0b57cec5SDimitry Andric // Calculate the cost of generating REG_SEQUENCE instructions. 442*0b57cec5SDimitry Andric for (auto &Op : UseI->operands()) { 443*0b57cec5SDimitry Andric if (Op.isReg() && Part.count(Op.getReg())) 444*0b57cec5SDimitry Andric if (Op.getSubReg()) 445*0b57cec5SDimitry Andric TotalP -= 2; 446*0b57cec5SDimitry Andric } 447*0b57cec5SDimitry Andric continue; 448*0b57cec5SDimitry Andric } 449*0b57cec5SDimitry Andric // If a register from this partition is used in a fixed instruction, 450*0b57cec5SDimitry Andric // and there is also a register in this partition that is used in 451*0b57cec5SDimitry Andric // a loop phi node, then decrease the splitting profit as this can 452*0b57cec5SDimitry Andric // confuse the modulo scheduler. 453*0b57cec5SDimitry Andric if (UseI->isPHI()) { 454*0b57cec5SDimitry Andric const MachineBasicBlock *PB = UseI->getParent(); 455*0b57cec5SDimitry Andric const MachineLoop *L = MLI->getLoopFor(PB); 456*0b57cec5SDimitry Andric if (L && L->getHeader() == PB) 457*0b57cec5SDimitry Andric LoopPhiNum++; 458*0b57cec5SDimitry Andric } 459*0b57cec5SDimitry Andric // Splittable instruction. 460*0b57cec5SDimitry Andric int32_t P = profit(UseI); 461*0b57cec5SDimitry Andric if (P == std::numeric_limits<int>::min()) 462*0b57cec5SDimitry Andric return false; 463*0b57cec5SDimitry Andric TotalP += P; 464*0b57cec5SDimitry Andric } 465*0b57cec5SDimitry Andric } 466*0b57cec5SDimitry Andric 467*0b57cec5SDimitry Andric if (FixedNum > 0 && LoopPhiNum > 0) 468*0b57cec5SDimitry Andric TotalP -= 20*LoopPhiNum; 469*0b57cec5SDimitry Andric 470*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Partition profit: " << TotalP << '\n'); 471*0b57cec5SDimitry Andric if (SplitAll) 472*0b57cec5SDimitry Andric return true; 473*0b57cec5SDimitry Andric return TotalP > 0; 474*0b57cec5SDimitry Andric } 475*0b57cec5SDimitry Andric 476*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::collectIndRegsForLoop(const MachineLoop *L, 477*0b57cec5SDimitry Andric USet &Rs) { 478*0b57cec5SDimitry Andric const MachineBasicBlock *HB = L->getHeader(); 479*0b57cec5SDimitry Andric const MachineBasicBlock *LB = L->getLoopLatch(); 480*0b57cec5SDimitry Andric if (!HB || !LB) 481*0b57cec5SDimitry Andric return; 482*0b57cec5SDimitry Andric 483*0b57cec5SDimitry Andric // Examine the latch branch. Expect it to be a conditional branch to 484*0b57cec5SDimitry Andric // the header (either "br-cond header" or "br-cond exit; br header"). 485*0b57cec5SDimitry Andric MachineBasicBlock *TB = nullptr, *FB = nullptr; 486*0b57cec5SDimitry Andric MachineBasicBlock *TmpLB = const_cast<MachineBasicBlock*>(LB); 487*0b57cec5SDimitry Andric SmallVector<MachineOperand,2> Cond; 488*0b57cec5SDimitry Andric bool BadLB = TII->analyzeBranch(*TmpLB, TB, FB, Cond, false); 489*0b57cec5SDimitry Andric // Only analyzable conditional branches. HII::analyzeBranch will put 490*0b57cec5SDimitry Andric // the branch opcode as the first element of Cond, and the predicate 491*0b57cec5SDimitry Andric // operand as the second. 492*0b57cec5SDimitry Andric if (BadLB || Cond.size() != 2) 493*0b57cec5SDimitry Andric return; 494*0b57cec5SDimitry Andric // Only simple jump-conditional (with or without negation). 495*0b57cec5SDimitry Andric if (!TII->PredOpcodeHasJMP_c(Cond[0].getImm())) 496*0b57cec5SDimitry Andric return; 497*0b57cec5SDimitry Andric // Must go to the header. 498*0b57cec5SDimitry Andric if (TB != HB && FB != HB) 499*0b57cec5SDimitry Andric return; 500*0b57cec5SDimitry Andric assert(Cond[1].isReg() && "Unexpected Cond vector from analyzeBranch"); 501*0b57cec5SDimitry Andric // Expect a predicate register. 502*0b57cec5SDimitry Andric unsigned PR = Cond[1].getReg(); 503*0b57cec5SDimitry Andric assert(MRI->getRegClass(PR) == &Hexagon::PredRegsRegClass); 504*0b57cec5SDimitry Andric 505*0b57cec5SDimitry Andric // Get the registers on which the loop controlling compare instruction 506*0b57cec5SDimitry Andric // depends. 507*0b57cec5SDimitry Andric unsigned CmpR1 = 0, CmpR2 = 0; 508*0b57cec5SDimitry Andric const MachineInstr *CmpI = MRI->getVRegDef(PR); 509*0b57cec5SDimitry Andric while (CmpI->getOpcode() == Hexagon::C2_not) 510*0b57cec5SDimitry Andric CmpI = MRI->getVRegDef(CmpI->getOperand(1).getReg()); 511*0b57cec5SDimitry Andric 512*0b57cec5SDimitry Andric int Mask = 0, Val = 0; 513*0b57cec5SDimitry Andric bool OkCI = TII->analyzeCompare(*CmpI, CmpR1, CmpR2, Mask, Val); 514*0b57cec5SDimitry Andric if (!OkCI) 515*0b57cec5SDimitry Andric return; 516*0b57cec5SDimitry Andric // Eliminate non-double input registers. 517*0b57cec5SDimitry Andric if (CmpR1 && MRI->getRegClass(CmpR1) != DoubleRC) 518*0b57cec5SDimitry Andric CmpR1 = 0; 519*0b57cec5SDimitry Andric if (CmpR2 && MRI->getRegClass(CmpR2) != DoubleRC) 520*0b57cec5SDimitry Andric CmpR2 = 0; 521*0b57cec5SDimitry Andric if (!CmpR1 && !CmpR2) 522*0b57cec5SDimitry Andric return; 523*0b57cec5SDimitry Andric 524*0b57cec5SDimitry Andric // Now examine the top of the loop: the phi nodes that could poten- 525*0b57cec5SDimitry Andric // tially define loop induction registers. The registers defined by 526*0b57cec5SDimitry Andric // such a phi node would be used in a 64-bit add, which then would 527*0b57cec5SDimitry Andric // be used in the loop compare instruction. 528*0b57cec5SDimitry Andric 529*0b57cec5SDimitry Andric // Get the set of all double registers defined by phi nodes in the 530*0b57cec5SDimitry Andric // loop header. 531*0b57cec5SDimitry Andric using UVect = std::vector<unsigned>; 532*0b57cec5SDimitry Andric 533*0b57cec5SDimitry Andric UVect DP; 534*0b57cec5SDimitry Andric for (auto &MI : *HB) { 535*0b57cec5SDimitry Andric if (!MI.isPHI()) 536*0b57cec5SDimitry Andric break; 537*0b57cec5SDimitry Andric const MachineOperand &MD = MI.getOperand(0); 538*0b57cec5SDimitry Andric unsigned R = MD.getReg(); 539*0b57cec5SDimitry Andric if (MRI->getRegClass(R) == DoubleRC) 540*0b57cec5SDimitry Andric DP.push_back(R); 541*0b57cec5SDimitry Andric } 542*0b57cec5SDimitry Andric if (DP.empty()) 543*0b57cec5SDimitry Andric return; 544*0b57cec5SDimitry Andric 545*0b57cec5SDimitry Andric auto NoIndOp = [this, CmpR1, CmpR2] (unsigned R) -> bool { 546*0b57cec5SDimitry Andric for (auto I = MRI->use_nodbg_begin(R), E = MRI->use_nodbg_end(); 547*0b57cec5SDimitry Andric I != E; ++I) { 548*0b57cec5SDimitry Andric const MachineInstr *UseI = I->getParent(); 549*0b57cec5SDimitry Andric if (UseI->getOpcode() != Hexagon::A2_addp) 550*0b57cec5SDimitry Andric continue; 551*0b57cec5SDimitry Andric // Get the output from the add. If it is one of the inputs to the 552*0b57cec5SDimitry Andric // loop-controlling compare instruction, then R is likely an induc- 553*0b57cec5SDimitry Andric // tion register. 554*0b57cec5SDimitry Andric unsigned T = UseI->getOperand(0).getReg(); 555*0b57cec5SDimitry Andric if (T == CmpR1 || T == CmpR2) 556*0b57cec5SDimitry Andric return false; 557*0b57cec5SDimitry Andric } 558*0b57cec5SDimitry Andric return true; 559*0b57cec5SDimitry Andric }; 560*0b57cec5SDimitry Andric UVect::iterator End = llvm::remove_if(DP, NoIndOp); 561*0b57cec5SDimitry Andric Rs.insert(DP.begin(), End); 562*0b57cec5SDimitry Andric Rs.insert(CmpR1); 563*0b57cec5SDimitry Andric Rs.insert(CmpR2); 564*0b57cec5SDimitry Andric 565*0b57cec5SDimitry Andric LLVM_DEBUG({ 566*0b57cec5SDimitry Andric dbgs() << "For loop at " << printMBBReference(*HB) << " ind regs: "; 567*0b57cec5SDimitry Andric dump_partition(dbgs(), Rs, *TRI); 568*0b57cec5SDimitry Andric dbgs() << '\n'; 569*0b57cec5SDimitry Andric }); 570*0b57cec5SDimitry Andric } 571*0b57cec5SDimitry Andric 572*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::collectIndRegs(LoopRegMap &IRM) { 573*0b57cec5SDimitry Andric using LoopVector = std::vector<MachineLoop *>; 574*0b57cec5SDimitry Andric 575*0b57cec5SDimitry Andric LoopVector WorkQ; 576*0b57cec5SDimitry Andric 577*0b57cec5SDimitry Andric for (auto I : *MLI) 578*0b57cec5SDimitry Andric WorkQ.push_back(I); 579*0b57cec5SDimitry Andric for (unsigned i = 0; i < WorkQ.size(); ++i) { 580*0b57cec5SDimitry Andric for (auto I : *WorkQ[i]) 581*0b57cec5SDimitry Andric WorkQ.push_back(I); 582*0b57cec5SDimitry Andric } 583*0b57cec5SDimitry Andric 584*0b57cec5SDimitry Andric USet Rs; 585*0b57cec5SDimitry Andric for (unsigned i = 0, n = WorkQ.size(); i < n; ++i) { 586*0b57cec5SDimitry Andric MachineLoop *L = WorkQ[i]; 587*0b57cec5SDimitry Andric Rs.clear(); 588*0b57cec5SDimitry Andric collectIndRegsForLoop(L, Rs); 589*0b57cec5SDimitry Andric if (!Rs.empty()) 590*0b57cec5SDimitry Andric IRM.insert(std::make_pair(L, Rs)); 591*0b57cec5SDimitry Andric } 592*0b57cec5SDimitry Andric } 593*0b57cec5SDimitry Andric 594*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::createHalfInstr(unsigned Opc, MachineInstr *MI, 595*0b57cec5SDimitry Andric const UUPairMap &PairMap, unsigned SubR) { 596*0b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 597*0b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 598*0b57cec5SDimitry Andric MachineInstr *NewI = BuildMI(B, MI, DL, TII->get(Opc)); 599*0b57cec5SDimitry Andric 600*0b57cec5SDimitry Andric for (auto &Op : MI->operands()) { 601*0b57cec5SDimitry Andric if (!Op.isReg()) { 602*0b57cec5SDimitry Andric NewI->addOperand(Op); 603*0b57cec5SDimitry Andric continue; 604*0b57cec5SDimitry Andric } 605*0b57cec5SDimitry Andric // For register operands, set the subregister. 606*0b57cec5SDimitry Andric unsigned R = Op.getReg(); 607*0b57cec5SDimitry Andric unsigned SR = Op.getSubReg(); 608*0b57cec5SDimitry Andric bool isVirtReg = TargetRegisterInfo::isVirtualRegister(R); 609*0b57cec5SDimitry Andric bool isKill = Op.isKill(); 610*0b57cec5SDimitry Andric if (isVirtReg && MRI->getRegClass(R) == DoubleRC) { 611*0b57cec5SDimitry Andric isKill = false; 612*0b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(R); 613*0b57cec5SDimitry Andric if (F == PairMap.end()) { 614*0b57cec5SDimitry Andric SR = SubR; 615*0b57cec5SDimitry Andric } else { 616*0b57cec5SDimitry Andric const UUPair &P = F->second; 617*0b57cec5SDimitry Andric R = (SubR == Hexagon::isub_lo) ? P.first : P.second; 618*0b57cec5SDimitry Andric SR = 0; 619*0b57cec5SDimitry Andric } 620*0b57cec5SDimitry Andric } 621*0b57cec5SDimitry Andric auto CO = MachineOperand::CreateReg(R, Op.isDef(), Op.isImplicit(), isKill, 622*0b57cec5SDimitry Andric Op.isDead(), Op.isUndef(), Op.isEarlyClobber(), SR, Op.isDebug(), 623*0b57cec5SDimitry Andric Op.isInternalRead()); 624*0b57cec5SDimitry Andric NewI->addOperand(CO); 625*0b57cec5SDimitry Andric } 626*0b57cec5SDimitry Andric } 627*0b57cec5SDimitry Andric 628*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitMemRef(MachineInstr *MI, 629*0b57cec5SDimitry Andric const UUPairMap &PairMap) { 630*0b57cec5SDimitry Andric bool Load = MI->mayLoad(); 631*0b57cec5SDimitry Andric unsigned OrigOpc = MI->getOpcode(); 632*0b57cec5SDimitry Andric bool PostInc = (OrigOpc == Hexagon::L2_loadrd_pi || 633*0b57cec5SDimitry Andric OrigOpc == Hexagon::S2_storerd_pi); 634*0b57cec5SDimitry Andric MachineInstr *LowI, *HighI; 635*0b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 636*0b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 637*0b57cec5SDimitry Andric 638*0b57cec5SDimitry Andric // Index of the base-address-register operand. 639*0b57cec5SDimitry Andric unsigned AdrX = PostInc ? (Load ? 2 : 1) 640*0b57cec5SDimitry Andric : (Load ? 1 : 0); 641*0b57cec5SDimitry Andric MachineOperand &AdrOp = MI->getOperand(AdrX); 642*0b57cec5SDimitry Andric unsigned RSA = getRegState(AdrOp); 643*0b57cec5SDimitry Andric MachineOperand &ValOp = Load ? MI->getOperand(0) 644*0b57cec5SDimitry Andric : (PostInc ? MI->getOperand(3) 645*0b57cec5SDimitry Andric : MI->getOperand(2)); 646*0b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(ValOp.getReg()); 647*0b57cec5SDimitry Andric assert(F != PairMap.end()); 648*0b57cec5SDimitry Andric 649*0b57cec5SDimitry Andric if (Load) { 650*0b57cec5SDimitry Andric const UUPair &P = F->second; 651*0b57cec5SDimitry Andric int64_t Off = PostInc ? 0 : MI->getOperand(2).getImm(); 652*0b57cec5SDimitry Andric LowI = BuildMI(B, MI, DL, TII->get(Hexagon::L2_loadri_io), P.first) 653*0b57cec5SDimitry Andric .addReg(AdrOp.getReg(), RSA & ~RegState::Kill, AdrOp.getSubReg()) 654*0b57cec5SDimitry Andric .addImm(Off); 655*0b57cec5SDimitry Andric HighI = BuildMI(B, MI, DL, TII->get(Hexagon::L2_loadri_io), P.second) 656*0b57cec5SDimitry Andric .addReg(AdrOp.getReg(), RSA & ~RegState::Kill, AdrOp.getSubReg()) 657*0b57cec5SDimitry Andric .addImm(Off+4); 658*0b57cec5SDimitry Andric } else { 659*0b57cec5SDimitry Andric const UUPair &P = F->second; 660*0b57cec5SDimitry Andric int64_t Off = PostInc ? 0 : MI->getOperand(1).getImm(); 661*0b57cec5SDimitry Andric LowI = BuildMI(B, MI, DL, TII->get(Hexagon::S2_storeri_io)) 662*0b57cec5SDimitry Andric .addReg(AdrOp.getReg(), RSA & ~RegState::Kill, AdrOp.getSubReg()) 663*0b57cec5SDimitry Andric .addImm(Off) 664*0b57cec5SDimitry Andric .addReg(P.first); 665*0b57cec5SDimitry Andric HighI = BuildMI(B, MI, DL, TII->get(Hexagon::S2_storeri_io)) 666*0b57cec5SDimitry Andric .addReg(AdrOp.getReg(), RSA & ~RegState::Kill, AdrOp.getSubReg()) 667*0b57cec5SDimitry Andric .addImm(Off+4) 668*0b57cec5SDimitry Andric .addReg(P.second); 669*0b57cec5SDimitry Andric } 670*0b57cec5SDimitry Andric 671*0b57cec5SDimitry Andric if (PostInc) { 672*0b57cec5SDimitry Andric // Create the increment of the address register. 673*0b57cec5SDimitry Andric int64_t Inc = Load ? MI->getOperand(3).getImm() 674*0b57cec5SDimitry Andric : MI->getOperand(2).getImm(); 675*0b57cec5SDimitry Andric MachineOperand &UpdOp = Load ? MI->getOperand(1) : MI->getOperand(0); 676*0b57cec5SDimitry Andric const TargetRegisterClass *RC = MRI->getRegClass(UpdOp.getReg()); 677*0b57cec5SDimitry Andric unsigned NewR = MRI->createVirtualRegister(RC); 678*0b57cec5SDimitry Andric assert(!UpdOp.getSubReg() && "Def operand with subreg"); 679*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(Hexagon::A2_addi), NewR) 680*0b57cec5SDimitry Andric .addReg(AdrOp.getReg(), RSA) 681*0b57cec5SDimitry Andric .addImm(Inc); 682*0b57cec5SDimitry Andric MRI->replaceRegWith(UpdOp.getReg(), NewR); 683*0b57cec5SDimitry Andric // The original instruction will be deleted later. 684*0b57cec5SDimitry Andric } 685*0b57cec5SDimitry Andric 686*0b57cec5SDimitry Andric // Generate a new pair of memory-operands. 687*0b57cec5SDimitry Andric MachineFunction &MF = *B.getParent(); 688*0b57cec5SDimitry Andric for (auto &MO : MI->memoperands()) { 689*0b57cec5SDimitry Andric const MachinePointerInfo &Ptr = MO->getPointerInfo(); 690*0b57cec5SDimitry Andric MachineMemOperand::Flags F = MO->getFlags(); 691*0b57cec5SDimitry Andric int A = MO->getAlignment(); 692*0b57cec5SDimitry Andric 693*0b57cec5SDimitry Andric auto *Tmp1 = MF.getMachineMemOperand(Ptr, F, 4/*size*/, A); 694*0b57cec5SDimitry Andric LowI->addMemOperand(MF, Tmp1); 695*0b57cec5SDimitry Andric auto *Tmp2 = MF.getMachineMemOperand(Ptr, F, 4/*size*/, std::min(A, 4)); 696*0b57cec5SDimitry Andric HighI->addMemOperand(MF, Tmp2); 697*0b57cec5SDimitry Andric } 698*0b57cec5SDimitry Andric } 699*0b57cec5SDimitry Andric 700*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitImmediate(MachineInstr *MI, 701*0b57cec5SDimitry Andric const UUPairMap &PairMap) { 702*0b57cec5SDimitry Andric MachineOperand &Op0 = MI->getOperand(0); 703*0b57cec5SDimitry Andric MachineOperand &Op1 = MI->getOperand(1); 704*0b57cec5SDimitry Andric assert(Op0.isReg() && Op1.isImm()); 705*0b57cec5SDimitry Andric uint64_t V = Op1.getImm(); 706*0b57cec5SDimitry Andric 707*0b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 708*0b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 709*0b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(Op0.getReg()); 710*0b57cec5SDimitry Andric assert(F != PairMap.end()); 711*0b57cec5SDimitry Andric const UUPair &P = F->second; 712*0b57cec5SDimitry Andric 713*0b57cec5SDimitry Andric // The operand to A2_tfrsi can only have 32 significant bits. Immediate 714*0b57cec5SDimitry Andric // values in MachineOperand are stored as 64-bit integers, and so the 715*0b57cec5SDimitry Andric // value -1 may be represented either as 64-bit -1, or 4294967295. Both 716*0b57cec5SDimitry Andric // will have the 32 higher bits truncated in the end, but -1 will remain 717*0b57cec5SDimitry Andric // as -1, while the latter may appear to be a large unsigned value 718*0b57cec5SDimitry Andric // requiring a constant extender. The casting to int32_t will select the 719*0b57cec5SDimitry Andric // former representation. (The same reasoning applies to all 32-bit 720*0b57cec5SDimitry Andric // values.) 721*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), P.first) 722*0b57cec5SDimitry Andric .addImm(int32_t(V & 0xFFFFFFFFULL)); 723*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), P.second) 724*0b57cec5SDimitry Andric .addImm(int32_t(V >> 32)); 725*0b57cec5SDimitry Andric } 726*0b57cec5SDimitry Andric 727*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitCombine(MachineInstr *MI, 728*0b57cec5SDimitry Andric const UUPairMap &PairMap) { 729*0b57cec5SDimitry Andric MachineOperand &Op0 = MI->getOperand(0); 730*0b57cec5SDimitry Andric MachineOperand &Op1 = MI->getOperand(1); 731*0b57cec5SDimitry Andric MachineOperand &Op2 = MI->getOperand(2); 732*0b57cec5SDimitry Andric assert(Op0.isReg()); 733*0b57cec5SDimitry Andric 734*0b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 735*0b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 736*0b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(Op0.getReg()); 737*0b57cec5SDimitry Andric assert(F != PairMap.end()); 738*0b57cec5SDimitry Andric const UUPair &P = F->second; 739*0b57cec5SDimitry Andric 740*0b57cec5SDimitry Andric if (!Op1.isReg()) { 741*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), P.second) 742*0b57cec5SDimitry Andric .add(Op1); 743*0b57cec5SDimitry Andric } else { 744*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), P.second) 745*0b57cec5SDimitry Andric .addReg(Op1.getReg(), getRegState(Op1), Op1.getSubReg()); 746*0b57cec5SDimitry Andric } 747*0b57cec5SDimitry Andric 748*0b57cec5SDimitry Andric if (!Op2.isReg()) { 749*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), P.first) 750*0b57cec5SDimitry Andric .add(Op2); 751*0b57cec5SDimitry Andric } else { 752*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), P.first) 753*0b57cec5SDimitry Andric .addReg(Op2.getReg(), getRegState(Op2), Op2.getSubReg()); 754*0b57cec5SDimitry Andric } 755*0b57cec5SDimitry Andric } 756*0b57cec5SDimitry Andric 757*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitExt(MachineInstr *MI, 758*0b57cec5SDimitry Andric const UUPairMap &PairMap) { 759*0b57cec5SDimitry Andric MachineOperand &Op0 = MI->getOperand(0); 760*0b57cec5SDimitry Andric MachineOperand &Op1 = MI->getOperand(1); 761*0b57cec5SDimitry Andric assert(Op0.isReg() && Op1.isReg()); 762*0b57cec5SDimitry Andric 763*0b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 764*0b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 765*0b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(Op0.getReg()); 766*0b57cec5SDimitry Andric assert(F != PairMap.end()); 767*0b57cec5SDimitry Andric const UUPair &P = F->second; 768*0b57cec5SDimitry Andric unsigned RS = getRegState(Op1); 769*0b57cec5SDimitry Andric 770*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), P.first) 771*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, Op1.getSubReg()); 772*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(Hexagon::S2_asr_i_r), P.second) 773*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS, Op1.getSubReg()) 774*0b57cec5SDimitry Andric .addImm(31); 775*0b57cec5SDimitry Andric } 776*0b57cec5SDimitry Andric 777*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitShift(MachineInstr *MI, 778*0b57cec5SDimitry Andric const UUPairMap &PairMap) { 779*0b57cec5SDimitry Andric using namespace Hexagon; 780*0b57cec5SDimitry Andric 781*0b57cec5SDimitry Andric MachineOperand &Op0 = MI->getOperand(0); 782*0b57cec5SDimitry Andric MachineOperand &Op1 = MI->getOperand(1); 783*0b57cec5SDimitry Andric MachineOperand &Op2 = MI->getOperand(2); 784*0b57cec5SDimitry Andric assert(Op0.isReg() && Op1.isReg() && Op2.isImm()); 785*0b57cec5SDimitry Andric int64_t Sh64 = Op2.getImm(); 786*0b57cec5SDimitry Andric assert(Sh64 >= 0 && Sh64 < 64); 787*0b57cec5SDimitry Andric unsigned S = Sh64; 788*0b57cec5SDimitry Andric 789*0b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(Op0.getReg()); 790*0b57cec5SDimitry Andric assert(F != PairMap.end()); 791*0b57cec5SDimitry Andric const UUPair &P = F->second; 792*0b57cec5SDimitry Andric unsigned LoR = P.first; 793*0b57cec5SDimitry Andric unsigned HiR = P.second; 794*0b57cec5SDimitry Andric 795*0b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 796*0b57cec5SDimitry Andric bool Right = (Opc == S2_lsr_i_p || Opc == S2_asr_i_p); 797*0b57cec5SDimitry Andric bool Left = !Right; 798*0b57cec5SDimitry Andric bool Signed = (Opc == S2_asr_i_p); 799*0b57cec5SDimitry Andric 800*0b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 801*0b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 802*0b57cec5SDimitry Andric unsigned RS = getRegState(Op1); 803*0b57cec5SDimitry Andric unsigned ShiftOpc = Left ? S2_asl_i_r 804*0b57cec5SDimitry Andric : (Signed ? S2_asr_i_r : S2_lsr_i_r); 805*0b57cec5SDimitry Andric unsigned LoSR = isub_lo; 806*0b57cec5SDimitry Andric unsigned HiSR = isub_hi; 807*0b57cec5SDimitry Andric 808*0b57cec5SDimitry Andric if (S == 0) { 809*0b57cec5SDimitry Andric // No shift, subregister copy. 810*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), LoR) 811*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR); 812*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), HiR) 813*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS, HiSR); 814*0b57cec5SDimitry Andric } else if (S < 32) { 815*0b57cec5SDimitry Andric const TargetRegisterClass *IntRC = &IntRegsRegClass; 816*0b57cec5SDimitry Andric unsigned TmpR = MRI->createVirtualRegister(IntRC); 817*0b57cec5SDimitry Andric // Expansion: 818*0b57cec5SDimitry Andric // Shift left: DR = shl R, #s 819*0b57cec5SDimitry Andric // LoR = shl R.lo, #s 820*0b57cec5SDimitry Andric // TmpR = extractu R.lo, #s, #32-s 821*0b57cec5SDimitry Andric // HiR = or (TmpR, asl(R.hi, #s)) 822*0b57cec5SDimitry Andric // Shift right: DR = shr R, #s 823*0b57cec5SDimitry Andric // HiR = shr R.hi, #s 824*0b57cec5SDimitry Andric // TmpR = shr R.lo, #s 825*0b57cec5SDimitry Andric // LoR = insert TmpR, R.hi, #s, #32-s 826*0b57cec5SDimitry Andric 827*0b57cec5SDimitry Andric // Shift left: 828*0b57cec5SDimitry Andric // LoR = shl R.lo, #s 829*0b57cec5SDimitry Andric // Shift right: 830*0b57cec5SDimitry Andric // TmpR = shr R.lo, #s 831*0b57cec5SDimitry Andric 832*0b57cec5SDimitry Andric // Make a special case for A2_aslh and A2_asrh (they are predicable as 833*0b57cec5SDimitry Andric // opposed to S2_asl_i_r/S2_asr_i_r). 834*0b57cec5SDimitry Andric if (S == 16 && Left) 835*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_aslh), LoR) 836*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR); 837*0b57cec5SDimitry Andric else if (S == 16 && Signed) 838*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_asrh), TmpR) 839*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR); 840*0b57cec5SDimitry Andric else 841*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(ShiftOpc), (Left ? LoR : TmpR)) 842*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR) 843*0b57cec5SDimitry Andric .addImm(S); 844*0b57cec5SDimitry Andric 845*0b57cec5SDimitry Andric if (Left) { 846*0b57cec5SDimitry Andric // TmpR = extractu R.lo, #s, #32-s 847*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_extractu), TmpR) 848*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR) 849*0b57cec5SDimitry Andric .addImm(S) 850*0b57cec5SDimitry Andric .addImm(32-S); 851*0b57cec5SDimitry Andric // HiR = or (TmpR, asl(R.hi, #s)) 852*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_asl_i_r_or), HiR) 853*0b57cec5SDimitry Andric .addReg(TmpR) 854*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS, HiSR) 855*0b57cec5SDimitry Andric .addImm(S); 856*0b57cec5SDimitry Andric } else { 857*0b57cec5SDimitry Andric // HiR = shr R.hi, #s 858*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(ShiftOpc), HiR) 859*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, HiSR) 860*0b57cec5SDimitry Andric .addImm(S); 861*0b57cec5SDimitry Andric // LoR = insert TmpR, R.hi, #s, #32-s 862*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_insert), LoR) 863*0b57cec5SDimitry Andric .addReg(TmpR) 864*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS, HiSR) 865*0b57cec5SDimitry Andric .addImm(S) 866*0b57cec5SDimitry Andric .addImm(32-S); 867*0b57cec5SDimitry Andric } 868*0b57cec5SDimitry Andric } else if (S == 32) { 869*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), (Left ? HiR : LoR)) 870*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, (Left ? LoSR : HiSR)); 871*0b57cec5SDimitry Andric if (!Signed) 872*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_tfrsi), (Left ? LoR : HiR)) 873*0b57cec5SDimitry Andric .addImm(0); 874*0b57cec5SDimitry Andric else // Must be right shift. 875*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_asr_i_r), HiR) 876*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS, HiSR) 877*0b57cec5SDimitry Andric .addImm(31); 878*0b57cec5SDimitry Andric } else if (S < 64) { 879*0b57cec5SDimitry Andric S -= 32; 880*0b57cec5SDimitry Andric if (S == 16 && Left) 881*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_aslh), HiR) 882*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR); 883*0b57cec5SDimitry Andric else if (S == 16 && Signed) 884*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_asrh), LoR) 885*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, HiSR); 886*0b57cec5SDimitry Andric else 887*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(ShiftOpc), (Left ? HiR : LoR)) 888*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS & ~RegState::Kill, (Left ? LoSR : HiSR)) 889*0b57cec5SDimitry Andric .addImm(S); 890*0b57cec5SDimitry Andric 891*0b57cec5SDimitry Andric if (Signed) 892*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_asr_i_r), HiR) 893*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS, HiSR) 894*0b57cec5SDimitry Andric .addImm(31); 895*0b57cec5SDimitry Andric else 896*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_tfrsi), (Left ? LoR : HiR)) 897*0b57cec5SDimitry Andric .addImm(0); 898*0b57cec5SDimitry Andric } 899*0b57cec5SDimitry Andric } 900*0b57cec5SDimitry Andric 901*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitAslOr(MachineInstr *MI, 902*0b57cec5SDimitry Andric const UUPairMap &PairMap) { 903*0b57cec5SDimitry Andric using namespace Hexagon; 904*0b57cec5SDimitry Andric 905*0b57cec5SDimitry Andric MachineOperand &Op0 = MI->getOperand(0); 906*0b57cec5SDimitry Andric MachineOperand &Op1 = MI->getOperand(1); 907*0b57cec5SDimitry Andric MachineOperand &Op2 = MI->getOperand(2); 908*0b57cec5SDimitry Andric MachineOperand &Op3 = MI->getOperand(3); 909*0b57cec5SDimitry Andric assert(Op0.isReg() && Op1.isReg() && Op2.isReg() && Op3.isImm()); 910*0b57cec5SDimitry Andric int64_t Sh64 = Op3.getImm(); 911*0b57cec5SDimitry Andric assert(Sh64 >= 0 && Sh64 < 64); 912*0b57cec5SDimitry Andric unsigned S = Sh64; 913*0b57cec5SDimitry Andric 914*0b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(Op0.getReg()); 915*0b57cec5SDimitry Andric assert(F != PairMap.end()); 916*0b57cec5SDimitry Andric const UUPair &P = F->second; 917*0b57cec5SDimitry Andric unsigned LoR = P.first; 918*0b57cec5SDimitry Andric unsigned HiR = P.second; 919*0b57cec5SDimitry Andric 920*0b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 921*0b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 922*0b57cec5SDimitry Andric unsigned RS1 = getRegState(Op1); 923*0b57cec5SDimitry Andric unsigned RS2 = getRegState(Op2); 924*0b57cec5SDimitry Andric const TargetRegisterClass *IntRC = &IntRegsRegClass; 925*0b57cec5SDimitry Andric 926*0b57cec5SDimitry Andric unsigned LoSR = isub_lo; 927*0b57cec5SDimitry Andric unsigned HiSR = isub_hi; 928*0b57cec5SDimitry Andric 929*0b57cec5SDimitry Andric // Op0 = S2_asl_i_p_or Op1, Op2, Op3 930*0b57cec5SDimitry Andric // means: Op0 = or (Op1, asl(Op2, Op3)) 931*0b57cec5SDimitry Andric 932*0b57cec5SDimitry Andric // Expansion of 933*0b57cec5SDimitry Andric // DR = or (R1, asl(R2, #s)) 934*0b57cec5SDimitry Andric // 935*0b57cec5SDimitry Andric // LoR = or (R1.lo, asl(R2.lo, #s)) 936*0b57cec5SDimitry Andric // Tmp1 = extractu R2.lo, #s, #32-s 937*0b57cec5SDimitry Andric // Tmp2 = or R1.hi, Tmp1 938*0b57cec5SDimitry Andric // HiR = or (Tmp2, asl(R2.hi, #s)) 939*0b57cec5SDimitry Andric 940*0b57cec5SDimitry Andric if (S == 0) { 941*0b57cec5SDimitry Andric // DR = or (R1, asl(R2, #0)) 942*0b57cec5SDimitry Andric // -> or (R1, R2) 943*0b57cec5SDimitry Andric // i.e. LoR = or R1.lo, R2.lo 944*0b57cec5SDimitry Andric // HiR = or R1.hi, R2.hi 945*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_or), LoR) 946*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1 & ~RegState::Kill, LoSR) 947*0b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2 & ~RegState::Kill, LoSR); 948*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_or), HiR) 949*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1, HiSR) 950*0b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2, HiSR); 951*0b57cec5SDimitry Andric } else if (S < 32) { 952*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_asl_i_r_or), LoR) 953*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1 & ~RegState::Kill, LoSR) 954*0b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2 & ~RegState::Kill, LoSR) 955*0b57cec5SDimitry Andric .addImm(S); 956*0b57cec5SDimitry Andric unsigned TmpR1 = MRI->createVirtualRegister(IntRC); 957*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_extractu), TmpR1) 958*0b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2 & ~RegState::Kill, LoSR) 959*0b57cec5SDimitry Andric .addImm(S) 960*0b57cec5SDimitry Andric .addImm(32-S); 961*0b57cec5SDimitry Andric unsigned TmpR2 = MRI->createVirtualRegister(IntRC); 962*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_or), TmpR2) 963*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1, HiSR) 964*0b57cec5SDimitry Andric .addReg(TmpR1); 965*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_asl_i_r_or), HiR) 966*0b57cec5SDimitry Andric .addReg(TmpR2) 967*0b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2, HiSR) 968*0b57cec5SDimitry Andric .addImm(S); 969*0b57cec5SDimitry Andric } else if (S == 32) { 970*0b57cec5SDimitry Andric // DR = or (R1, asl(R2, #32)) 971*0b57cec5SDimitry Andric // -> or R1, R2.lo 972*0b57cec5SDimitry Andric // LoR = R1.lo 973*0b57cec5SDimitry Andric // HiR = or R1.hi, R2.lo 974*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), LoR) 975*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1 & ~RegState::Kill, LoSR); 976*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(A2_or), HiR) 977*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1, HiSR) 978*0b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2, LoSR); 979*0b57cec5SDimitry Andric } else if (S < 64) { 980*0b57cec5SDimitry Andric // DR = or (R1, asl(R2, #s)) 981*0b57cec5SDimitry Andric // 982*0b57cec5SDimitry Andric // LoR = R1:lo 983*0b57cec5SDimitry Andric // HiR = or (R1:hi, asl(R2:lo, #s-32)) 984*0b57cec5SDimitry Andric S -= 32; 985*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), LoR) 986*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1 & ~RegState::Kill, LoSR); 987*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(S2_asl_i_r_or), HiR) 988*0b57cec5SDimitry Andric .addReg(Op1.getReg(), RS1, HiSR) 989*0b57cec5SDimitry Andric .addReg(Op2.getReg(), RS2, LoSR) 990*0b57cec5SDimitry Andric .addImm(S); 991*0b57cec5SDimitry Andric } 992*0b57cec5SDimitry Andric } 993*0b57cec5SDimitry Andric 994*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::splitInstr(MachineInstr *MI, 995*0b57cec5SDimitry Andric const UUPairMap &PairMap) { 996*0b57cec5SDimitry Andric using namespace Hexagon; 997*0b57cec5SDimitry Andric 998*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Splitting: " << *MI); 999*0b57cec5SDimitry Andric bool Split = false; 1000*0b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 1001*0b57cec5SDimitry Andric 1002*0b57cec5SDimitry Andric switch (Opc) { 1003*0b57cec5SDimitry Andric case TargetOpcode::PHI: 1004*0b57cec5SDimitry Andric case TargetOpcode::COPY: { 1005*0b57cec5SDimitry Andric unsigned DstR = MI->getOperand(0).getReg(); 1006*0b57cec5SDimitry Andric if (MRI->getRegClass(DstR) == DoubleRC) { 1007*0b57cec5SDimitry Andric createHalfInstr(Opc, MI, PairMap, isub_lo); 1008*0b57cec5SDimitry Andric createHalfInstr(Opc, MI, PairMap, isub_hi); 1009*0b57cec5SDimitry Andric Split = true; 1010*0b57cec5SDimitry Andric } 1011*0b57cec5SDimitry Andric break; 1012*0b57cec5SDimitry Andric } 1013*0b57cec5SDimitry Andric case A2_andp: 1014*0b57cec5SDimitry Andric createHalfInstr(A2_and, MI, PairMap, isub_lo); 1015*0b57cec5SDimitry Andric createHalfInstr(A2_and, MI, PairMap, isub_hi); 1016*0b57cec5SDimitry Andric Split = true; 1017*0b57cec5SDimitry Andric break; 1018*0b57cec5SDimitry Andric case A2_orp: 1019*0b57cec5SDimitry Andric createHalfInstr(A2_or, MI, PairMap, isub_lo); 1020*0b57cec5SDimitry Andric createHalfInstr(A2_or, MI, PairMap, isub_hi); 1021*0b57cec5SDimitry Andric Split = true; 1022*0b57cec5SDimitry Andric break; 1023*0b57cec5SDimitry Andric case A2_xorp: 1024*0b57cec5SDimitry Andric createHalfInstr(A2_xor, MI, PairMap, isub_lo); 1025*0b57cec5SDimitry Andric createHalfInstr(A2_xor, MI, PairMap, isub_hi); 1026*0b57cec5SDimitry Andric Split = true; 1027*0b57cec5SDimitry Andric break; 1028*0b57cec5SDimitry Andric 1029*0b57cec5SDimitry Andric case L2_loadrd_io: 1030*0b57cec5SDimitry Andric case L2_loadrd_pi: 1031*0b57cec5SDimitry Andric case S2_storerd_io: 1032*0b57cec5SDimitry Andric case S2_storerd_pi: 1033*0b57cec5SDimitry Andric splitMemRef(MI, PairMap); 1034*0b57cec5SDimitry Andric Split = true; 1035*0b57cec5SDimitry Andric break; 1036*0b57cec5SDimitry Andric 1037*0b57cec5SDimitry Andric case A2_tfrpi: 1038*0b57cec5SDimitry Andric case CONST64: 1039*0b57cec5SDimitry Andric splitImmediate(MI, PairMap); 1040*0b57cec5SDimitry Andric Split = true; 1041*0b57cec5SDimitry Andric break; 1042*0b57cec5SDimitry Andric 1043*0b57cec5SDimitry Andric case A2_combineii: 1044*0b57cec5SDimitry Andric case A4_combineir: 1045*0b57cec5SDimitry Andric case A4_combineii: 1046*0b57cec5SDimitry Andric case A4_combineri: 1047*0b57cec5SDimitry Andric case A2_combinew: 1048*0b57cec5SDimitry Andric splitCombine(MI, PairMap); 1049*0b57cec5SDimitry Andric Split = true; 1050*0b57cec5SDimitry Andric break; 1051*0b57cec5SDimitry Andric 1052*0b57cec5SDimitry Andric case A2_sxtw: 1053*0b57cec5SDimitry Andric splitExt(MI, PairMap); 1054*0b57cec5SDimitry Andric Split = true; 1055*0b57cec5SDimitry Andric break; 1056*0b57cec5SDimitry Andric 1057*0b57cec5SDimitry Andric case S2_asl_i_p: 1058*0b57cec5SDimitry Andric case S2_asr_i_p: 1059*0b57cec5SDimitry Andric case S2_lsr_i_p: 1060*0b57cec5SDimitry Andric splitShift(MI, PairMap); 1061*0b57cec5SDimitry Andric Split = true; 1062*0b57cec5SDimitry Andric break; 1063*0b57cec5SDimitry Andric 1064*0b57cec5SDimitry Andric case S2_asl_i_p_or: 1065*0b57cec5SDimitry Andric splitAslOr(MI, PairMap); 1066*0b57cec5SDimitry Andric Split = true; 1067*0b57cec5SDimitry Andric break; 1068*0b57cec5SDimitry Andric 1069*0b57cec5SDimitry Andric default: 1070*0b57cec5SDimitry Andric llvm_unreachable("Instruction not splitable"); 1071*0b57cec5SDimitry Andric return false; 1072*0b57cec5SDimitry Andric } 1073*0b57cec5SDimitry Andric 1074*0b57cec5SDimitry Andric return Split; 1075*0b57cec5SDimitry Andric } 1076*0b57cec5SDimitry Andric 1077*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::replaceSubregUses(MachineInstr *MI, 1078*0b57cec5SDimitry Andric const UUPairMap &PairMap) { 1079*0b57cec5SDimitry Andric for (auto &Op : MI->operands()) { 1080*0b57cec5SDimitry Andric if (!Op.isReg() || !Op.isUse() || !Op.getSubReg()) 1081*0b57cec5SDimitry Andric continue; 1082*0b57cec5SDimitry Andric unsigned R = Op.getReg(); 1083*0b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(R); 1084*0b57cec5SDimitry Andric if (F == PairMap.end()) 1085*0b57cec5SDimitry Andric continue; 1086*0b57cec5SDimitry Andric const UUPair &P = F->second; 1087*0b57cec5SDimitry Andric switch (Op.getSubReg()) { 1088*0b57cec5SDimitry Andric case Hexagon::isub_lo: 1089*0b57cec5SDimitry Andric Op.setReg(P.first); 1090*0b57cec5SDimitry Andric break; 1091*0b57cec5SDimitry Andric case Hexagon::isub_hi: 1092*0b57cec5SDimitry Andric Op.setReg(P.second); 1093*0b57cec5SDimitry Andric break; 1094*0b57cec5SDimitry Andric } 1095*0b57cec5SDimitry Andric Op.setSubReg(0); 1096*0b57cec5SDimitry Andric } 1097*0b57cec5SDimitry Andric } 1098*0b57cec5SDimitry Andric 1099*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::collapseRegPairs(MachineInstr *MI, 1100*0b57cec5SDimitry Andric const UUPairMap &PairMap) { 1101*0b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 1102*0b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 1103*0b57cec5SDimitry Andric 1104*0b57cec5SDimitry Andric for (auto &Op : MI->operands()) { 1105*0b57cec5SDimitry Andric if (!Op.isReg() || !Op.isUse()) 1106*0b57cec5SDimitry Andric continue; 1107*0b57cec5SDimitry Andric unsigned R = Op.getReg(); 1108*0b57cec5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(R)) 1109*0b57cec5SDimitry Andric continue; 1110*0b57cec5SDimitry Andric if (MRI->getRegClass(R) != DoubleRC || Op.getSubReg()) 1111*0b57cec5SDimitry Andric continue; 1112*0b57cec5SDimitry Andric UUPairMap::const_iterator F = PairMap.find(R); 1113*0b57cec5SDimitry Andric if (F == PairMap.end()) 1114*0b57cec5SDimitry Andric continue; 1115*0b57cec5SDimitry Andric const UUPair &Pr = F->second; 1116*0b57cec5SDimitry Andric unsigned NewDR = MRI->createVirtualRegister(DoubleRC); 1117*0b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::REG_SEQUENCE), NewDR) 1118*0b57cec5SDimitry Andric .addReg(Pr.first) 1119*0b57cec5SDimitry Andric .addImm(Hexagon::isub_lo) 1120*0b57cec5SDimitry Andric .addReg(Pr.second) 1121*0b57cec5SDimitry Andric .addImm(Hexagon::isub_hi); 1122*0b57cec5SDimitry Andric Op.setReg(NewDR); 1123*0b57cec5SDimitry Andric } 1124*0b57cec5SDimitry Andric } 1125*0b57cec5SDimitry Andric 1126*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::splitPartition(const USet &Part) { 1127*0b57cec5SDimitry Andric using MISet = std::set<MachineInstr *>; 1128*0b57cec5SDimitry Andric 1129*0b57cec5SDimitry Andric const TargetRegisterClass *IntRC = &Hexagon::IntRegsRegClass; 1130*0b57cec5SDimitry Andric bool Changed = false; 1131*0b57cec5SDimitry Andric 1132*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Splitting partition: "; 1133*0b57cec5SDimitry Andric dump_partition(dbgs(), Part, *TRI); dbgs() << '\n'); 1134*0b57cec5SDimitry Andric 1135*0b57cec5SDimitry Andric UUPairMap PairMap; 1136*0b57cec5SDimitry Andric 1137*0b57cec5SDimitry Andric MISet SplitIns; 1138*0b57cec5SDimitry Andric for (unsigned DR : Part) { 1139*0b57cec5SDimitry Andric MachineInstr *DefI = MRI->getVRegDef(DR); 1140*0b57cec5SDimitry Andric SplitIns.insert(DefI); 1141*0b57cec5SDimitry Andric 1142*0b57cec5SDimitry Andric // Collect all instructions, including fixed ones. We won't split them, 1143*0b57cec5SDimitry Andric // but we need to visit them again to insert the REG_SEQUENCE instructions. 1144*0b57cec5SDimitry Andric for (auto U = MRI->use_nodbg_begin(DR), W = MRI->use_nodbg_end(); 1145*0b57cec5SDimitry Andric U != W; ++U) 1146*0b57cec5SDimitry Andric SplitIns.insert(U->getParent()); 1147*0b57cec5SDimitry Andric 1148*0b57cec5SDimitry Andric unsigned LoR = MRI->createVirtualRegister(IntRC); 1149*0b57cec5SDimitry Andric unsigned HiR = MRI->createVirtualRegister(IntRC); 1150*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Created mapping: " << printReg(DR, TRI) << " -> " 1151*0b57cec5SDimitry Andric << printReg(HiR, TRI) << ':' << printReg(LoR, TRI) 1152*0b57cec5SDimitry Andric << '\n'); 1153*0b57cec5SDimitry Andric PairMap.insert(std::make_pair(DR, UUPair(LoR, HiR))); 1154*0b57cec5SDimitry Andric } 1155*0b57cec5SDimitry Andric 1156*0b57cec5SDimitry Andric MISet Erase; 1157*0b57cec5SDimitry Andric for (auto MI : SplitIns) { 1158*0b57cec5SDimitry Andric if (isFixedInstr(MI)) { 1159*0b57cec5SDimitry Andric collapseRegPairs(MI, PairMap); 1160*0b57cec5SDimitry Andric } else { 1161*0b57cec5SDimitry Andric bool Done = splitInstr(MI, PairMap); 1162*0b57cec5SDimitry Andric if (Done) 1163*0b57cec5SDimitry Andric Erase.insert(MI); 1164*0b57cec5SDimitry Andric Changed |= Done; 1165*0b57cec5SDimitry Andric } 1166*0b57cec5SDimitry Andric } 1167*0b57cec5SDimitry Andric 1168*0b57cec5SDimitry Andric for (unsigned DR : Part) { 1169*0b57cec5SDimitry Andric // Before erasing "double" instructions, revisit all uses of the double 1170*0b57cec5SDimitry Andric // registers in this partition, and replace all uses of them with subre- 1171*0b57cec5SDimitry Andric // gisters, with the corresponding single registers. 1172*0b57cec5SDimitry Andric MISet Uses; 1173*0b57cec5SDimitry Andric for (auto U = MRI->use_nodbg_begin(DR), W = MRI->use_nodbg_end(); 1174*0b57cec5SDimitry Andric U != W; ++U) 1175*0b57cec5SDimitry Andric Uses.insert(U->getParent()); 1176*0b57cec5SDimitry Andric for (auto M : Uses) 1177*0b57cec5SDimitry Andric replaceSubregUses(M, PairMap); 1178*0b57cec5SDimitry Andric } 1179*0b57cec5SDimitry Andric 1180*0b57cec5SDimitry Andric for (auto MI : Erase) { 1181*0b57cec5SDimitry Andric MachineBasicBlock *B = MI->getParent(); 1182*0b57cec5SDimitry Andric B->erase(MI); 1183*0b57cec5SDimitry Andric } 1184*0b57cec5SDimitry Andric 1185*0b57cec5SDimitry Andric return Changed; 1186*0b57cec5SDimitry Andric } 1187*0b57cec5SDimitry Andric 1188*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::runOnMachineFunction(MachineFunction &MF) { 1189*0b57cec5SDimitry Andric if (skipFunction(MF.getFunction())) 1190*0b57cec5SDimitry Andric return false; 1191*0b57cec5SDimitry Andric 1192*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Splitting double registers in function: " 1193*0b57cec5SDimitry Andric << MF.getName() << '\n'); 1194*0b57cec5SDimitry Andric 1195*0b57cec5SDimitry Andric auto &ST = MF.getSubtarget<HexagonSubtarget>(); 1196*0b57cec5SDimitry Andric TRI = ST.getRegisterInfo(); 1197*0b57cec5SDimitry Andric TII = ST.getInstrInfo(); 1198*0b57cec5SDimitry Andric MRI = &MF.getRegInfo(); 1199*0b57cec5SDimitry Andric MLI = &getAnalysis<MachineLoopInfo>(); 1200*0b57cec5SDimitry Andric 1201*0b57cec5SDimitry Andric UUSetMap P2Rs; 1202*0b57cec5SDimitry Andric LoopRegMap IRM; 1203*0b57cec5SDimitry Andric 1204*0b57cec5SDimitry Andric collectIndRegs(IRM); 1205*0b57cec5SDimitry Andric partitionRegisters(P2Rs); 1206*0b57cec5SDimitry Andric 1207*0b57cec5SDimitry Andric LLVM_DEBUG({ 1208*0b57cec5SDimitry Andric dbgs() << "Register partitioning: (partition #0 is fixed)\n"; 1209*0b57cec5SDimitry Andric for (UUSetMap::iterator I = P2Rs.begin(), E = P2Rs.end(); I != E; ++I) { 1210*0b57cec5SDimitry Andric dbgs() << '#' << I->first << " -> "; 1211*0b57cec5SDimitry Andric dump_partition(dbgs(), I->second, *TRI); 1212*0b57cec5SDimitry Andric dbgs() << '\n'; 1213*0b57cec5SDimitry Andric } 1214*0b57cec5SDimitry Andric }); 1215*0b57cec5SDimitry Andric 1216*0b57cec5SDimitry Andric bool Changed = false; 1217*0b57cec5SDimitry Andric int Limit = MaxHSDR; 1218*0b57cec5SDimitry Andric 1219*0b57cec5SDimitry Andric for (UUSetMap::iterator I = P2Rs.begin(), E = P2Rs.end(); I != E; ++I) { 1220*0b57cec5SDimitry Andric if (I->first == 0) 1221*0b57cec5SDimitry Andric continue; 1222*0b57cec5SDimitry Andric if (Limit >= 0 && Counter >= Limit) 1223*0b57cec5SDimitry Andric break; 1224*0b57cec5SDimitry Andric USet &Part = I->second; 1225*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Calculating profit for partition #" << I->first 1226*0b57cec5SDimitry Andric << '\n'); 1227*0b57cec5SDimitry Andric if (!isProfitable(Part, IRM)) 1228*0b57cec5SDimitry Andric continue; 1229*0b57cec5SDimitry Andric Counter++; 1230*0b57cec5SDimitry Andric Changed |= splitPartition(Part); 1231*0b57cec5SDimitry Andric } 1232*0b57cec5SDimitry Andric 1233*0b57cec5SDimitry Andric return Changed; 1234*0b57cec5SDimitry Andric } 1235*0b57cec5SDimitry Andric 1236*0b57cec5SDimitry Andric FunctionPass *llvm::createHexagonSplitDoubleRegs() { 1237*0b57cec5SDimitry Andric return new HexagonSplitDoubleRegs(); 1238*0b57cec5SDimitry Andric } 1239