1*0b57cec5SDimitry Andric //===------- HexagonCopyToCombine.cpp - Hexagon Copy-To-Combine Pass ------===// 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 // This pass replaces transfer instructions by combine instructions. 9*0b57cec5SDimitry Andric // We walk along a basic block and look for two combinable instructions and try 10*0b57cec5SDimitry Andric // to move them together. If we can move them next to each other we do so and 11*0b57cec5SDimitry Andric // replace them with a combine instruction. 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric #include "HexagonInstrInfo.h" 14*0b57cec5SDimitry Andric #include "HexagonSubtarget.h" 15*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 16*0b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h" 17*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 18*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 19*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 20*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 22*0b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 23*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 24*0b57cec5SDimitry Andric #include "llvm/PassSupport.h" 25*0b57cec5SDimitry Andric #include "llvm/Support/CodeGen.h" 26*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 27*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 28*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 29*0b57cec5SDimitry Andric 30*0b57cec5SDimitry Andric using namespace llvm; 31*0b57cec5SDimitry Andric 32*0b57cec5SDimitry Andric #define DEBUG_TYPE "hexagon-copy-combine" 33*0b57cec5SDimitry Andric 34*0b57cec5SDimitry Andric static 35*0b57cec5SDimitry Andric cl::opt<bool> IsCombinesDisabled("disable-merge-into-combines", 36*0b57cec5SDimitry Andric cl::Hidden, cl::ZeroOrMore, 37*0b57cec5SDimitry Andric cl::init(false), 38*0b57cec5SDimitry Andric cl::desc("Disable merging into combines")); 39*0b57cec5SDimitry Andric static 40*0b57cec5SDimitry Andric cl::opt<bool> IsConst64Disabled("disable-const64", 41*0b57cec5SDimitry Andric cl::Hidden, cl::ZeroOrMore, 42*0b57cec5SDimitry Andric cl::init(false), 43*0b57cec5SDimitry Andric cl::desc("Disable generation of const64")); 44*0b57cec5SDimitry Andric static 45*0b57cec5SDimitry Andric cl::opt<unsigned> 46*0b57cec5SDimitry Andric MaxNumOfInstsBetweenNewValueStoreAndTFR("max-num-inst-between-tfr-and-nv-store", 47*0b57cec5SDimitry Andric cl::Hidden, cl::init(4), 48*0b57cec5SDimitry Andric cl::desc("Maximum distance between a tfr feeding a store we " 49*0b57cec5SDimitry Andric "consider the store still to be newifiable")); 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric namespace llvm { 52*0b57cec5SDimitry Andric FunctionPass *createHexagonCopyToCombine(); 53*0b57cec5SDimitry Andric void initializeHexagonCopyToCombinePass(PassRegistry&); 54*0b57cec5SDimitry Andric } 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric 57*0b57cec5SDimitry Andric namespace { 58*0b57cec5SDimitry Andric 59*0b57cec5SDimitry Andric class HexagonCopyToCombine : public MachineFunctionPass { 60*0b57cec5SDimitry Andric const HexagonInstrInfo *TII; 61*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI; 62*0b57cec5SDimitry Andric const HexagonSubtarget *ST; 63*0b57cec5SDimitry Andric bool ShouldCombineAggressively; 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric DenseSet<MachineInstr *> PotentiallyNewifiableTFR; 66*0b57cec5SDimitry Andric SmallVector<MachineInstr *, 8> DbgMItoMove; 67*0b57cec5SDimitry Andric 68*0b57cec5SDimitry Andric public: 69*0b57cec5SDimitry Andric static char ID; 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric HexagonCopyToCombine() : MachineFunctionPass(ID) { 72*0b57cec5SDimitry Andric initializeHexagonCopyToCombinePass(*PassRegistry::getPassRegistry()); 73*0b57cec5SDimitry Andric } 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 76*0b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 77*0b57cec5SDimitry Andric } 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric StringRef getPassName() const override { 80*0b57cec5SDimitry Andric return "Hexagon Copy-To-Combine Pass"; 81*0b57cec5SDimitry Andric } 82*0b57cec5SDimitry Andric 83*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override; 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 86*0b57cec5SDimitry Andric return MachineFunctionProperties().set( 87*0b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 88*0b57cec5SDimitry Andric } 89*0b57cec5SDimitry Andric 90*0b57cec5SDimitry Andric private: 91*0b57cec5SDimitry Andric MachineInstr *findPairable(MachineInstr &I1, bool &DoInsertAtI1, 92*0b57cec5SDimitry Andric bool AllowC64); 93*0b57cec5SDimitry Andric 94*0b57cec5SDimitry Andric void findPotentialNewifiableTFRs(MachineBasicBlock &); 95*0b57cec5SDimitry Andric 96*0b57cec5SDimitry Andric void combine(MachineInstr &I1, MachineInstr &I2, 97*0b57cec5SDimitry Andric MachineBasicBlock::iterator &MI, bool DoInsertAtI1, 98*0b57cec5SDimitry Andric bool OptForSize); 99*0b57cec5SDimitry Andric 100*0b57cec5SDimitry Andric bool isSafeToMoveTogether(MachineInstr &I1, MachineInstr &I2, 101*0b57cec5SDimitry Andric unsigned I1DestReg, unsigned I2DestReg, 102*0b57cec5SDimitry Andric bool &DoInsertAtI1); 103*0b57cec5SDimitry Andric 104*0b57cec5SDimitry Andric void emitCombineRR(MachineBasicBlock::iterator &Before, unsigned DestReg, 105*0b57cec5SDimitry Andric MachineOperand &HiOperand, MachineOperand &LoOperand); 106*0b57cec5SDimitry Andric 107*0b57cec5SDimitry Andric void emitCombineRI(MachineBasicBlock::iterator &Before, unsigned DestReg, 108*0b57cec5SDimitry Andric MachineOperand &HiOperand, MachineOperand &LoOperand); 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric void emitCombineIR(MachineBasicBlock::iterator &Before, unsigned DestReg, 111*0b57cec5SDimitry Andric MachineOperand &HiOperand, MachineOperand &LoOperand); 112*0b57cec5SDimitry Andric 113*0b57cec5SDimitry Andric void emitCombineII(MachineBasicBlock::iterator &Before, unsigned DestReg, 114*0b57cec5SDimitry Andric MachineOperand &HiOperand, MachineOperand &LoOperand); 115*0b57cec5SDimitry Andric 116*0b57cec5SDimitry Andric void emitConst64(MachineBasicBlock::iterator &Before, unsigned DestReg, 117*0b57cec5SDimitry Andric MachineOperand &HiOperand, MachineOperand &LoOperand); 118*0b57cec5SDimitry Andric }; 119*0b57cec5SDimitry Andric 120*0b57cec5SDimitry Andric } // End anonymous namespace. 121*0b57cec5SDimitry Andric 122*0b57cec5SDimitry Andric char HexagonCopyToCombine::ID = 0; 123*0b57cec5SDimitry Andric 124*0b57cec5SDimitry Andric INITIALIZE_PASS(HexagonCopyToCombine, "hexagon-copy-combine", 125*0b57cec5SDimitry Andric "Hexagon Copy-To-Combine Pass", false, false) 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric static bool isCombinableInstType(MachineInstr &MI, const HexagonInstrInfo *TII, 128*0b57cec5SDimitry Andric bool ShouldCombineAggressively) { 129*0b57cec5SDimitry Andric switch (MI.getOpcode()) { 130*0b57cec5SDimitry Andric case Hexagon::A2_tfr: { 131*0b57cec5SDimitry Andric // A COPY instruction can be combined if its arguments are IntRegs (32bit). 132*0b57cec5SDimitry Andric const MachineOperand &Op0 = MI.getOperand(0); 133*0b57cec5SDimitry Andric const MachineOperand &Op1 = MI.getOperand(1); 134*0b57cec5SDimitry Andric assert(Op0.isReg() && Op1.isReg()); 135*0b57cec5SDimitry Andric 136*0b57cec5SDimitry Andric unsigned DestReg = Op0.getReg(); 137*0b57cec5SDimitry Andric unsigned SrcReg = Op1.getReg(); 138*0b57cec5SDimitry Andric return Hexagon::IntRegsRegClass.contains(DestReg) && 139*0b57cec5SDimitry Andric Hexagon::IntRegsRegClass.contains(SrcReg); 140*0b57cec5SDimitry Andric } 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric case Hexagon::A2_tfrsi: { 143*0b57cec5SDimitry Andric // A transfer-immediate can be combined if its argument is a signed 8bit 144*0b57cec5SDimitry Andric // value. 145*0b57cec5SDimitry Andric const MachineOperand &Op0 = MI.getOperand(0); 146*0b57cec5SDimitry Andric const MachineOperand &Op1 = MI.getOperand(1); 147*0b57cec5SDimitry Andric assert(Op0.isReg()); 148*0b57cec5SDimitry Andric 149*0b57cec5SDimitry Andric unsigned DestReg = Op0.getReg(); 150*0b57cec5SDimitry Andric // Ensure that TargetFlags are MO_NO_FLAG for a global. This is a 151*0b57cec5SDimitry Andric // workaround for an ABI bug that prevents GOT relocations on combine 152*0b57cec5SDimitry Andric // instructions 153*0b57cec5SDimitry Andric if (!Op1.isImm() && Op1.getTargetFlags() != HexagonII::MO_NO_FLAG) 154*0b57cec5SDimitry Andric return false; 155*0b57cec5SDimitry Andric 156*0b57cec5SDimitry Andric // Only combine constant extended A2_tfrsi if we are in aggressive mode. 157*0b57cec5SDimitry Andric bool NotExt = Op1.isImm() && isInt<8>(Op1.getImm()); 158*0b57cec5SDimitry Andric return Hexagon::IntRegsRegClass.contains(DestReg) && 159*0b57cec5SDimitry Andric (ShouldCombineAggressively || NotExt); 160*0b57cec5SDimitry Andric } 161*0b57cec5SDimitry Andric 162*0b57cec5SDimitry Andric case Hexagon::V6_vassign: 163*0b57cec5SDimitry Andric return true; 164*0b57cec5SDimitry Andric 165*0b57cec5SDimitry Andric default: 166*0b57cec5SDimitry Andric break; 167*0b57cec5SDimitry Andric } 168*0b57cec5SDimitry Andric 169*0b57cec5SDimitry Andric return false; 170*0b57cec5SDimitry Andric } 171*0b57cec5SDimitry Andric 172*0b57cec5SDimitry Andric template <unsigned N> static bool isGreaterThanNBitTFRI(const MachineInstr &I) { 173*0b57cec5SDimitry Andric if (I.getOpcode() == Hexagon::TFRI64_V4 || 174*0b57cec5SDimitry Andric I.getOpcode() == Hexagon::A2_tfrsi) { 175*0b57cec5SDimitry Andric const MachineOperand &Op = I.getOperand(1); 176*0b57cec5SDimitry Andric return !Op.isImm() || !isInt<N>(Op.getImm()); 177*0b57cec5SDimitry Andric } 178*0b57cec5SDimitry Andric return false; 179*0b57cec5SDimitry Andric } 180*0b57cec5SDimitry Andric 181*0b57cec5SDimitry Andric /// areCombinableOperations - Returns true if the two instruction can be merge 182*0b57cec5SDimitry Andric /// into a combine (ignoring register constraints). 183*0b57cec5SDimitry Andric static bool areCombinableOperations(const TargetRegisterInfo *TRI, 184*0b57cec5SDimitry Andric MachineInstr &HighRegInst, 185*0b57cec5SDimitry Andric MachineInstr &LowRegInst, bool AllowC64) { 186*0b57cec5SDimitry Andric unsigned HiOpc = HighRegInst.getOpcode(); 187*0b57cec5SDimitry Andric unsigned LoOpc = LowRegInst.getOpcode(); 188*0b57cec5SDimitry Andric 189*0b57cec5SDimitry Andric auto verifyOpc = [](unsigned Opc) -> void { 190*0b57cec5SDimitry Andric switch (Opc) { 191*0b57cec5SDimitry Andric case Hexagon::A2_tfr: 192*0b57cec5SDimitry Andric case Hexagon::A2_tfrsi: 193*0b57cec5SDimitry Andric case Hexagon::V6_vassign: 194*0b57cec5SDimitry Andric break; 195*0b57cec5SDimitry Andric default: 196*0b57cec5SDimitry Andric llvm_unreachable("Unexpected opcode"); 197*0b57cec5SDimitry Andric } 198*0b57cec5SDimitry Andric }; 199*0b57cec5SDimitry Andric verifyOpc(HiOpc); 200*0b57cec5SDimitry Andric verifyOpc(LoOpc); 201*0b57cec5SDimitry Andric 202*0b57cec5SDimitry Andric if (HiOpc == Hexagon::V6_vassign || LoOpc == Hexagon::V6_vassign) 203*0b57cec5SDimitry Andric return HiOpc == LoOpc; 204*0b57cec5SDimitry Andric 205*0b57cec5SDimitry Andric if (!AllowC64) { 206*0b57cec5SDimitry Andric // There is no combine of two constant extended values. 207*0b57cec5SDimitry Andric if (isGreaterThanNBitTFRI<8>(HighRegInst) && 208*0b57cec5SDimitry Andric isGreaterThanNBitTFRI<6>(LowRegInst)) 209*0b57cec5SDimitry Andric return false; 210*0b57cec5SDimitry Andric } 211*0b57cec5SDimitry Andric 212*0b57cec5SDimitry Andric // There is a combine of two constant extended values into CONST64, 213*0b57cec5SDimitry Andric // provided both constants are true immediates. 214*0b57cec5SDimitry Andric if (isGreaterThanNBitTFRI<16>(HighRegInst) && 215*0b57cec5SDimitry Andric isGreaterThanNBitTFRI<16>(LowRegInst)) 216*0b57cec5SDimitry Andric return (HighRegInst.getOperand(1).isImm() && 217*0b57cec5SDimitry Andric LowRegInst.getOperand(1).isImm()); 218*0b57cec5SDimitry Andric 219*0b57cec5SDimitry Andric // There is no combine of two constant extended values, unless handled above 220*0b57cec5SDimitry Andric // Make both 8-bit size checks to allow both combine (#,##) and combine(##,#) 221*0b57cec5SDimitry Andric if (isGreaterThanNBitTFRI<8>(HighRegInst) && 222*0b57cec5SDimitry Andric isGreaterThanNBitTFRI<8>(LowRegInst)) 223*0b57cec5SDimitry Andric return false; 224*0b57cec5SDimitry Andric 225*0b57cec5SDimitry Andric return true; 226*0b57cec5SDimitry Andric } 227*0b57cec5SDimitry Andric 228*0b57cec5SDimitry Andric static bool isEvenReg(unsigned Reg) { 229*0b57cec5SDimitry Andric assert(TargetRegisterInfo::isPhysicalRegister(Reg)); 230*0b57cec5SDimitry Andric if (Hexagon::IntRegsRegClass.contains(Reg)) 231*0b57cec5SDimitry Andric return (Reg - Hexagon::R0) % 2 == 0; 232*0b57cec5SDimitry Andric if (Hexagon::HvxVRRegClass.contains(Reg)) 233*0b57cec5SDimitry Andric return (Reg - Hexagon::V0) % 2 == 0; 234*0b57cec5SDimitry Andric llvm_unreachable("Invalid register"); 235*0b57cec5SDimitry Andric } 236*0b57cec5SDimitry Andric 237*0b57cec5SDimitry Andric static void removeKillInfo(MachineInstr &MI, unsigned RegNotKilled) { 238*0b57cec5SDimitry Andric for (unsigned I = 0, E = MI.getNumOperands(); I != E; ++I) { 239*0b57cec5SDimitry Andric MachineOperand &Op = MI.getOperand(I); 240*0b57cec5SDimitry Andric if (!Op.isReg() || Op.getReg() != RegNotKilled || !Op.isKill()) 241*0b57cec5SDimitry Andric continue; 242*0b57cec5SDimitry Andric Op.setIsKill(false); 243*0b57cec5SDimitry Andric } 244*0b57cec5SDimitry Andric } 245*0b57cec5SDimitry Andric 246*0b57cec5SDimitry Andric /// Returns true if it is unsafe to move a copy instruction from \p UseReg to 247*0b57cec5SDimitry Andric /// \p DestReg over the instruction \p MI. 248*0b57cec5SDimitry Andric static bool isUnsafeToMoveAcross(MachineInstr &MI, unsigned UseReg, 249*0b57cec5SDimitry Andric unsigned DestReg, 250*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI) { 251*0b57cec5SDimitry Andric return (UseReg && (MI.modifiesRegister(UseReg, TRI))) || 252*0b57cec5SDimitry Andric MI.modifiesRegister(DestReg, TRI) || MI.readsRegister(DestReg, TRI) || 253*0b57cec5SDimitry Andric MI.hasUnmodeledSideEffects() || MI.isInlineAsm() || 254*0b57cec5SDimitry Andric MI.isMetaInstruction(); 255*0b57cec5SDimitry Andric } 256*0b57cec5SDimitry Andric 257*0b57cec5SDimitry Andric static Register UseReg(const MachineOperand& MO) { 258*0b57cec5SDimitry Andric return MO.isReg() ? MO.getReg() : Register(); 259*0b57cec5SDimitry Andric } 260*0b57cec5SDimitry Andric 261*0b57cec5SDimitry Andric /// isSafeToMoveTogether - Returns true if it is safe to move I1 next to I2 such 262*0b57cec5SDimitry Andric /// that the two instructions can be paired in a combine. 263*0b57cec5SDimitry Andric bool HexagonCopyToCombine::isSafeToMoveTogether(MachineInstr &I1, 264*0b57cec5SDimitry Andric MachineInstr &I2, 265*0b57cec5SDimitry Andric unsigned I1DestReg, 266*0b57cec5SDimitry Andric unsigned I2DestReg, 267*0b57cec5SDimitry Andric bool &DoInsertAtI1) { 268*0b57cec5SDimitry Andric unsigned I2UseReg = UseReg(I2.getOperand(1)); 269*0b57cec5SDimitry Andric 270*0b57cec5SDimitry Andric // It is not safe to move I1 and I2 into one combine if I2 has a true 271*0b57cec5SDimitry Andric // dependence on I1. 272*0b57cec5SDimitry Andric if (I2UseReg && I1.modifiesRegister(I2UseReg, TRI)) 273*0b57cec5SDimitry Andric return false; 274*0b57cec5SDimitry Andric 275*0b57cec5SDimitry Andric bool isSafe = true; 276*0b57cec5SDimitry Andric 277*0b57cec5SDimitry Andric // First try to move I2 towards I1. 278*0b57cec5SDimitry Andric { 279*0b57cec5SDimitry Andric // A reverse_iterator instantiated like below starts before I2, and I1 280*0b57cec5SDimitry Andric // respectively. 281*0b57cec5SDimitry Andric // Look at instructions I in between I2 and (excluding) I1. 282*0b57cec5SDimitry Andric MachineBasicBlock::reverse_iterator I(I2), 283*0b57cec5SDimitry Andric End = --(MachineBasicBlock::reverse_iterator(I1)); 284*0b57cec5SDimitry Andric // At 03 we got better results (dhrystone!) by being more conservative. 285*0b57cec5SDimitry Andric if (!ShouldCombineAggressively) 286*0b57cec5SDimitry Andric End = MachineBasicBlock::reverse_iterator(I1); 287*0b57cec5SDimitry Andric // If I2 kills its operand and we move I2 over an instruction that also 288*0b57cec5SDimitry Andric // uses I2's use reg we need to modify that (first) instruction to now kill 289*0b57cec5SDimitry Andric // this reg. 290*0b57cec5SDimitry Andric unsigned KilledOperand = 0; 291*0b57cec5SDimitry Andric if (I2.killsRegister(I2UseReg)) 292*0b57cec5SDimitry Andric KilledOperand = I2UseReg; 293*0b57cec5SDimitry Andric MachineInstr *KillingInstr = nullptr; 294*0b57cec5SDimitry Andric 295*0b57cec5SDimitry Andric for (; I != End; ++I) { 296*0b57cec5SDimitry Andric // If the intervening instruction I: 297*0b57cec5SDimitry Andric // * modifies I2's use reg 298*0b57cec5SDimitry Andric // * modifies I2's def reg 299*0b57cec5SDimitry Andric // * reads I2's def reg 300*0b57cec5SDimitry Andric // * or has unmodelled side effects 301*0b57cec5SDimitry Andric // we can't move I2 across it. 302*0b57cec5SDimitry Andric if (I->isDebugInstr()) 303*0b57cec5SDimitry Andric continue; 304*0b57cec5SDimitry Andric 305*0b57cec5SDimitry Andric if (isUnsafeToMoveAcross(*I, I2UseReg, I2DestReg, TRI)) { 306*0b57cec5SDimitry Andric isSafe = false; 307*0b57cec5SDimitry Andric break; 308*0b57cec5SDimitry Andric } 309*0b57cec5SDimitry Andric 310*0b57cec5SDimitry Andric // Update first use of the killed operand. 311*0b57cec5SDimitry Andric if (!KillingInstr && KilledOperand && 312*0b57cec5SDimitry Andric I->readsRegister(KilledOperand, TRI)) 313*0b57cec5SDimitry Andric KillingInstr = &*I; 314*0b57cec5SDimitry Andric } 315*0b57cec5SDimitry Andric if (isSafe) { 316*0b57cec5SDimitry Andric // Update the intermediate instruction to with the kill flag. 317*0b57cec5SDimitry Andric if (KillingInstr) { 318*0b57cec5SDimitry Andric bool Added = KillingInstr->addRegisterKilled(KilledOperand, TRI, true); 319*0b57cec5SDimitry Andric (void)Added; // suppress compiler warning 320*0b57cec5SDimitry Andric assert(Added && "Must successfully update kill flag"); 321*0b57cec5SDimitry Andric removeKillInfo(I2, KilledOperand); 322*0b57cec5SDimitry Andric } 323*0b57cec5SDimitry Andric DoInsertAtI1 = true; 324*0b57cec5SDimitry Andric return true; 325*0b57cec5SDimitry Andric } 326*0b57cec5SDimitry Andric } 327*0b57cec5SDimitry Andric 328*0b57cec5SDimitry Andric // Try to move I1 towards I2. 329*0b57cec5SDimitry Andric { 330*0b57cec5SDimitry Andric // Look at instructions I in between I1 and (excluding) I2. 331*0b57cec5SDimitry Andric MachineBasicBlock::iterator I(I1), End(I2); 332*0b57cec5SDimitry Andric // At O3 we got better results (dhrystone) by being more conservative here. 333*0b57cec5SDimitry Andric if (!ShouldCombineAggressively) 334*0b57cec5SDimitry Andric End = std::next(MachineBasicBlock::iterator(I2)); 335*0b57cec5SDimitry Andric unsigned I1UseReg = UseReg(I1.getOperand(1)); 336*0b57cec5SDimitry Andric // Track killed operands. If we move across an instruction that kills our 337*0b57cec5SDimitry Andric // operand, we need to update the kill information on the moved I1. It kills 338*0b57cec5SDimitry Andric // the operand now. 339*0b57cec5SDimitry Andric MachineInstr *KillingInstr = nullptr; 340*0b57cec5SDimitry Andric unsigned KilledOperand = 0; 341*0b57cec5SDimitry Andric 342*0b57cec5SDimitry Andric while(++I != End) { 343*0b57cec5SDimitry Andric MachineInstr &MI = *I; 344*0b57cec5SDimitry Andric // If the intervening instruction MI: 345*0b57cec5SDimitry Andric // * modifies I1's use reg 346*0b57cec5SDimitry Andric // * modifies I1's def reg 347*0b57cec5SDimitry Andric // * reads I1's def reg 348*0b57cec5SDimitry Andric // * or has unmodelled side effects 349*0b57cec5SDimitry Andric // We introduce this special case because llvm has no api to remove a 350*0b57cec5SDimitry Andric // kill flag for a register (a removeRegisterKilled() analogous to 351*0b57cec5SDimitry Andric // addRegisterKilled) that handles aliased register correctly. 352*0b57cec5SDimitry Andric // * or has a killed aliased register use of I1's use reg 353*0b57cec5SDimitry Andric // %d4 = A2_tfrpi 16 354*0b57cec5SDimitry Andric // %r6 = A2_tfr %r9 355*0b57cec5SDimitry Andric // %r8 = KILL %r8, implicit killed %d4 356*0b57cec5SDimitry Andric // If we want to move R6 = across the KILL instruction we would have 357*0b57cec5SDimitry Andric // to remove the implicit killed %d4 operand. For now, we are 358*0b57cec5SDimitry Andric // conservative and disallow the move. 359*0b57cec5SDimitry Andric // we can't move I1 across it. 360*0b57cec5SDimitry Andric if (MI.isDebugInstr()) { 361*0b57cec5SDimitry Andric if (MI.readsRegister(I1DestReg, TRI)) // Move this instruction after I2. 362*0b57cec5SDimitry Andric DbgMItoMove.push_back(&MI); 363*0b57cec5SDimitry Andric continue; 364*0b57cec5SDimitry Andric } 365*0b57cec5SDimitry Andric 366*0b57cec5SDimitry Andric if (isUnsafeToMoveAcross(MI, I1UseReg, I1DestReg, TRI) || 367*0b57cec5SDimitry Andric // Check for an aliased register kill. Bail out if we see one. 368*0b57cec5SDimitry Andric (!MI.killsRegister(I1UseReg) && MI.killsRegister(I1UseReg, TRI))) 369*0b57cec5SDimitry Andric return false; 370*0b57cec5SDimitry Andric 371*0b57cec5SDimitry Andric // Check for an exact kill (registers match). 372*0b57cec5SDimitry Andric if (I1UseReg && MI.killsRegister(I1UseReg)) { 373*0b57cec5SDimitry Andric assert(!KillingInstr && "Should only see one killing instruction"); 374*0b57cec5SDimitry Andric KilledOperand = I1UseReg; 375*0b57cec5SDimitry Andric KillingInstr = &MI; 376*0b57cec5SDimitry Andric } 377*0b57cec5SDimitry Andric } 378*0b57cec5SDimitry Andric if (KillingInstr) { 379*0b57cec5SDimitry Andric removeKillInfo(*KillingInstr, KilledOperand); 380*0b57cec5SDimitry Andric // Update I1 to set the kill flag. This flag will later be picked up by 381*0b57cec5SDimitry Andric // the new COMBINE instruction. 382*0b57cec5SDimitry Andric bool Added = I1.addRegisterKilled(KilledOperand, TRI); 383*0b57cec5SDimitry Andric (void)Added; // suppress compiler warning 384*0b57cec5SDimitry Andric assert(Added && "Must successfully update kill flag"); 385*0b57cec5SDimitry Andric } 386*0b57cec5SDimitry Andric DoInsertAtI1 = false; 387*0b57cec5SDimitry Andric } 388*0b57cec5SDimitry Andric 389*0b57cec5SDimitry Andric return true; 390*0b57cec5SDimitry Andric } 391*0b57cec5SDimitry Andric 392*0b57cec5SDimitry Andric /// findPotentialNewifiableTFRs - Finds tranfers that feed stores that could be 393*0b57cec5SDimitry Andric /// newified. (A use of a 64 bit register define can not be newified) 394*0b57cec5SDimitry Andric void 395*0b57cec5SDimitry Andric HexagonCopyToCombine::findPotentialNewifiableTFRs(MachineBasicBlock &BB) { 396*0b57cec5SDimitry Andric DenseMap<unsigned, MachineInstr *> LastDef; 397*0b57cec5SDimitry Andric for (MachineInstr &MI : BB) { 398*0b57cec5SDimitry Andric if (MI.isDebugInstr()) 399*0b57cec5SDimitry Andric continue; 400*0b57cec5SDimitry Andric 401*0b57cec5SDimitry Andric // Mark TFRs that feed a potential new value store as such. 402*0b57cec5SDimitry Andric if (TII->mayBeNewStore(MI)) { 403*0b57cec5SDimitry Andric // Look for uses of TFR instructions. 404*0b57cec5SDimitry Andric for (unsigned OpdIdx = 0, OpdE = MI.getNumOperands(); OpdIdx != OpdE; 405*0b57cec5SDimitry Andric ++OpdIdx) { 406*0b57cec5SDimitry Andric MachineOperand &Op = MI.getOperand(OpdIdx); 407*0b57cec5SDimitry Andric 408*0b57cec5SDimitry Andric // Skip over anything except register uses. 409*0b57cec5SDimitry Andric if (!Op.isReg() || !Op.isUse() || !Op.getReg()) 410*0b57cec5SDimitry Andric continue; 411*0b57cec5SDimitry Andric 412*0b57cec5SDimitry Andric // Look for the defining instruction. 413*0b57cec5SDimitry Andric unsigned Reg = Op.getReg(); 414*0b57cec5SDimitry Andric MachineInstr *DefInst = LastDef[Reg]; 415*0b57cec5SDimitry Andric if (!DefInst) 416*0b57cec5SDimitry Andric continue; 417*0b57cec5SDimitry Andric if (!isCombinableInstType(*DefInst, TII, ShouldCombineAggressively)) 418*0b57cec5SDimitry Andric continue; 419*0b57cec5SDimitry Andric 420*0b57cec5SDimitry Andric // Only close newifiable stores should influence the decision. 421*0b57cec5SDimitry Andric // Ignore the debug instructions in between. 422*0b57cec5SDimitry Andric MachineBasicBlock::iterator It(DefInst); 423*0b57cec5SDimitry Andric unsigned NumInstsToDef = 0; 424*0b57cec5SDimitry Andric while (&*It != &MI) { 425*0b57cec5SDimitry Andric if (!It->isDebugInstr()) 426*0b57cec5SDimitry Andric ++NumInstsToDef; 427*0b57cec5SDimitry Andric ++It; 428*0b57cec5SDimitry Andric } 429*0b57cec5SDimitry Andric 430*0b57cec5SDimitry Andric if (NumInstsToDef > MaxNumOfInstsBetweenNewValueStoreAndTFR) 431*0b57cec5SDimitry Andric continue; 432*0b57cec5SDimitry Andric 433*0b57cec5SDimitry Andric PotentiallyNewifiableTFR.insert(DefInst); 434*0b57cec5SDimitry Andric } 435*0b57cec5SDimitry Andric // Skip to next instruction. 436*0b57cec5SDimitry Andric continue; 437*0b57cec5SDimitry Andric } 438*0b57cec5SDimitry Andric 439*0b57cec5SDimitry Andric // Put instructions that last defined integer or double registers into the 440*0b57cec5SDimitry Andric // map. 441*0b57cec5SDimitry Andric for (MachineOperand &Op : MI.operands()) { 442*0b57cec5SDimitry Andric if (Op.isReg()) { 443*0b57cec5SDimitry Andric if (!Op.isDef() || !Op.getReg()) 444*0b57cec5SDimitry Andric continue; 445*0b57cec5SDimitry Andric unsigned Reg = Op.getReg(); 446*0b57cec5SDimitry Andric if (Hexagon::DoubleRegsRegClass.contains(Reg)) { 447*0b57cec5SDimitry Andric for (MCSubRegIterator SubRegs(Reg, TRI); SubRegs.isValid(); ++SubRegs) 448*0b57cec5SDimitry Andric LastDef[*SubRegs] = &MI; 449*0b57cec5SDimitry Andric } else if (Hexagon::IntRegsRegClass.contains(Reg)) 450*0b57cec5SDimitry Andric LastDef[Reg] = &MI; 451*0b57cec5SDimitry Andric } else if (Op.isRegMask()) { 452*0b57cec5SDimitry Andric for (unsigned Reg : Hexagon::IntRegsRegClass) 453*0b57cec5SDimitry Andric if (Op.clobbersPhysReg(Reg)) 454*0b57cec5SDimitry Andric LastDef[Reg] = &MI; 455*0b57cec5SDimitry Andric } 456*0b57cec5SDimitry Andric } 457*0b57cec5SDimitry Andric } 458*0b57cec5SDimitry Andric } 459*0b57cec5SDimitry Andric 460*0b57cec5SDimitry Andric bool HexagonCopyToCombine::runOnMachineFunction(MachineFunction &MF) { 461*0b57cec5SDimitry Andric if (skipFunction(MF.getFunction())) 462*0b57cec5SDimitry Andric return false; 463*0b57cec5SDimitry Andric 464*0b57cec5SDimitry Andric if (IsCombinesDisabled) return false; 465*0b57cec5SDimitry Andric 466*0b57cec5SDimitry Andric bool HasChanged = false; 467*0b57cec5SDimitry Andric 468*0b57cec5SDimitry Andric // Get target info. 469*0b57cec5SDimitry Andric ST = &MF.getSubtarget<HexagonSubtarget>(); 470*0b57cec5SDimitry Andric TRI = ST->getRegisterInfo(); 471*0b57cec5SDimitry Andric TII = ST->getInstrInfo(); 472*0b57cec5SDimitry Andric 473*0b57cec5SDimitry Andric const Function &F = MF.getFunction(); 474*0b57cec5SDimitry Andric bool OptForSize = F.hasFnAttribute(Attribute::OptimizeForSize); 475*0b57cec5SDimitry Andric 476*0b57cec5SDimitry Andric // Combine aggressively (for code size) 477*0b57cec5SDimitry Andric ShouldCombineAggressively = 478*0b57cec5SDimitry Andric MF.getTarget().getOptLevel() <= CodeGenOpt::Default; 479*0b57cec5SDimitry Andric 480*0b57cec5SDimitry Andric // Traverse basic blocks. 481*0b57cec5SDimitry Andric for (MachineFunction::iterator BI = MF.begin(), BE = MF.end(); BI != BE; 482*0b57cec5SDimitry Andric ++BI) { 483*0b57cec5SDimitry Andric PotentiallyNewifiableTFR.clear(); 484*0b57cec5SDimitry Andric findPotentialNewifiableTFRs(*BI); 485*0b57cec5SDimitry Andric 486*0b57cec5SDimitry Andric // Traverse instructions in basic block. 487*0b57cec5SDimitry Andric for(MachineBasicBlock::iterator MI = BI->begin(), End = BI->end(); 488*0b57cec5SDimitry Andric MI != End;) { 489*0b57cec5SDimitry Andric MachineInstr &I1 = *MI++; 490*0b57cec5SDimitry Andric 491*0b57cec5SDimitry Andric if (I1.isDebugInstr()) 492*0b57cec5SDimitry Andric continue; 493*0b57cec5SDimitry Andric 494*0b57cec5SDimitry Andric // Don't combine a TFR whose user could be newified (instructions that 495*0b57cec5SDimitry Andric // define double registers can not be newified - Programmer's Ref Manual 496*0b57cec5SDimitry Andric // 5.4.2 New-value stores). 497*0b57cec5SDimitry Andric if (ShouldCombineAggressively && PotentiallyNewifiableTFR.count(&I1)) 498*0b57cec5SDimitry Andric continue; 499*0b57cec5SDimitry Andric 500*0b57cec5SDimitry Andric // Ignore instructions that are not combinable. 501*0b57cec5SDimitry Andric if (!isCombinableInstType(I1, TII, ShouldCombineAggressively)) 502*0b57cec5SDimitry Andric continue; 503*0b57cec5SDimitry Andric 504*0b57cec5SDimitry Andric // Find a second instruction that can be merged into a combine 505*0b57cec5SDimitry Andric // instruction. In addition, also find all the debug instructions that 506*0b57cec5SDimitry Andric // need to be moved along with it. 507*0b57cec5SDimitry Andric bool DoInsertAtI1 = false; 508*0b57cec5SDimitry Andric DbgMItoMove.clear(); 509*0b57cec5SDimitry Andric MachineInstr *I2 = findPairable(I1, DoInsertAtI1, OptForSize); 510*0b57cec5SDimitry Andric if (I2) { 511*0b57cec5SDimitry Andric HasChanged = true; 512*0b57cec5SDimitry Andric combine(I1, *I2, MI, DoInsertAtI1, OptForSize); 513*0b57cec5SDimitry Andric } 514*0b57cec5SDimitry Andric } 515*0b57cec5SDimitry Andric } 516*0b57cec5SDimitry Andric 517*0b57cec5SDimitry Andric return HasChanged; 518*0b57cec5SDimitry Andric } 519*0b57cec5SDimitry Andric 520*0b57cec5SDimitry Andric /// findPairable - Returns an instruction that can be merged with \p I1 into a 521*0b57cec5SDimitry Andric /// COMBINE instruction or 0 if no such instruction can be found. Returns true 522*0b57cec5SDimitry Andric /// in \p DoInsertAtI1 if the combine must be inserted at instruction \p I1 523*0b57cec5SDimitry Andric /// false if the combine must be inserted at the returned instruction. 524*0b57cec5SDimitry Andric MachineInstr *HexagonCopyToCombine::findPairable(MachineInstr &I1, 525*0b57cec5SDimitry Andric bool &DoInsertAtI1, 526*0b57cec5SDimitry Andric bool AllowC64) { 527*0b57cec5SDimitry Andric MachineBasicBlock::iterator I2 = std::next(MachineBasicBlock::iterator(I1)); 528*0b57cec5SDimitry Andric while (I2 != I1.getParent()->end() && I2->isDebugInstr()) 529*0b57cec5SDimitry Andric ++I2; 530*0b57cec5SDimitry Andric 531*0b57cec5SDimitry Andric unsigned I1DestReg = I1.getOperand(0).getReg(); 532*0b57cec5SDimitry Andric 533*0b57cec5SDimitry Andric for (MachineBasicBlock::iterator End = I1.getParent()->end(); I2 != End; 534*0b57cec5SDimitry Andric ++I2) { 535*0b57cec5SDimitry Andric // Bail out early if we see a second definition of I1DestReg. 536*0b57cec5SDimitry Andric if (I2->modifiesRegister(I1DestReg, TRI)) 537*0b57cec5SDimitry Andric break; 538*0b57cec5SDimitry Andric 539*0b57cec5SDimitry Andric // Ignore non-combinable instructions. 540*0b57cec5SDimitry Andric if (!isCombinableInstType(*I2, TII, ShouldCombineAggressively)) 541*0b57cec5SDimitry Andric continue; 542*0b57cec5SDimitry Andric 543*0b57cec5SDimitry Andric // Don't combine a TFR whose user could be newified. 544*0b57cec5SDimitry Andric if (ShouldCombineAggressively && PotentiallyNewifiableTFR.count(&*I2)) 545*0b57cec5SDimitry Andric continue; 546*0b57cec5SDimitry Andric 547*0b57cec5SDimitry Andric unsigned I2DestReg = I2->getOperand(0).getReg(); 548*0b57cec5SDimitry Andric 549*0b57cec5SDimitry Andric // Check that registers are adjacent and that the first destination register 550*0b57cec5SDimitry Andric // is even. 551*0b57cec5SDimitry Andric bool IsI1LowReg = (I2DestReg - I1DestReg) == 1; 552*0b57cec5SDimitry Andric bool IsI2LowReg = (I1DestReg - I2DestReg) == 1; 553*0b57cec5SDimitry Andric unsigned FirstRegIndex = IsI1LowReg ? I1DestReg : I2DestReg; 554*0b57cec5SDimitry Andric if ((!IsI1LowReg && !IsI2LowReg) || !isEvenReg(FirstRegIndex)) 555*0b57cec5SDimitry Andric continue; 556*0b57cec5SDimitry Andric 557*0b57cec5SDimitry Andric // Check that the two instructions are combinable. 558*0b57cec5SDimitry Andric // The order matters because in a A2_tfrsi we might can encode a int8 as 559*0b57cec5SDimitry Andric // the hi reg operand but only a uint6 as the low reg operand. 560*0b57cec5SDimitry Andric if ((IsI2LowReg && !areCombinableOperations(TRI, I1, *I2, AllowC64)) || 561*0b57cec5SDimitry Andric (IsI1LowReg && !areCombinableOperations(TRI, *I2, I1, AllowC64))) 562*0b57cec5SDimitry Andric break; 563*0b57cec5SDimitry Andric 564*0b57cec5SDimitry Andric if (isSafeToMoveTogether(I1, *I2, I1DestReg, I2DestReg, DoInsertAtI1)) 565*0b57cec5SDimitry Andric return &*I2; 566*0b57cec5SDimitry Andric 567*0b57cec5SDimitry Andric // Not safe. Stop searching. 568*0b57cec5SDimitry Andric break; 569*0b57cec5SDimitry Andric } 570*0b57cec5SDimitry Andric return nullptr; 571*0b57cec5SDimitry Andric } 572*0b57cec5SDimitry Andric 573*0b57cec5SDimitry Andric void HexagonCopyToCombine::combine(MachineInstr &I1, MachineInstr &I2, 574*0b57cec5SDimitry Andric MachineBasicBlock::iterator &MI, 575*0b57cec5SDimitry Andric bool DoInsertAtI1, bool OptForSize) { 576*0b57cec5SDimitry Andric // We are going to delete I2. If MI points to I2 advance it to the next 577*0b57cec5SDimitry Andric // instruction. 578*0b57cec5SDimitry Andric if (MI == I2.getIterator()) 579*0b57cec5SDimitry Andric ++MI; 580*0b57cec5SDimitry Andric 581*0b57cec5SDimitry Andric // Figure out whether I1 or I2 goes into the lowreg part. 582*0b57cec5SDimitry Andric unsigned I1DestReg = I1.getOperand(0).getReg(); 583*0b57cec5SDimitry Andric unsigned I2DestReg = I2.getOperand(0).getReg(); 584*0b57cec5SDimitry Andric bool IsI1Loreg = (I2DestReg - I1DestReg) == 1; 585*0b57cec5SDimitry Andric unsigned LoRegDef = IsI1Loreg ? I1DestReg : I2DestReg; 586*0b57cec5SDimitry Andric unsigned SubLo; 587*0b57cec5SDimitry Andric 588*0b57cec5SDimitry Andric const TargetRegisterClass *SuperRC = nullptr; 589*0b57cec5SDimitry Andric if (Hexagon::IntRegsRegClass.contains(LoRegDef)) { 590*0b57cec5SDimitry Andric SuperRC = &Hexagon::DoubleRegsRegClass; 591*0b57cec5SDimitry Andric SubLo = Hexagon::isub_lo; 592*0b57cec5SDimitry Andric } else if (Hexagon::HvxVRRegClass.contains(LoRegDef)) { 593*0b57cec5SDimitry Andric assert(ST->useHVXOps()); 594*0b57cec5SDimitry Andric SuperRC = &Hexagon::HvxWRRegClass; 595*0b57cec5SDimitry Andric SubLo = Hexagon::vsub_lo; 596*0b57cec5SDimitry Andric } else 597*0b57cec5SDimitry Andric llvm_unreachable("Unexpected register class"); 598*0b57cec5SDimitry Andric 599*0b57cec5SDimitry Andric // Get the double word register. 600*0b57cec5SDimitry Andric unsigned DoubleRegDest = TRI->getMatchingSuperReg(LoRegDef, SubLo, SuperRC); 601*0b57cec5SDimitry Andric assert(DoubleRegDest != 0 && "Expect a valid register"); 602*0b57cec5SDimitry Andric 603*0b57cec5SDimitry Andric // Setup source operands. 604*0b57cec5SDimitry Andric MachineOperand &LoOperand = IsI1Loreg ? I1.getOperand(1) : I2.getOperand(1); 605*0b57cec5SDimitry Andric MachineOperand &HiOperand = IsI1Loreg ? I2.getOperand(1) : I1.getOperand(1); 606*0b57cec5SDimitry Andric 607*0b57cec5SDimitry Andric // Figure out which source is a register and which a constant. 608*0b57cec5SDimitry Andric bool IsHiReg = HiOperand.isReg(); 609*0b57cec5SDimitry Andric bool IsLoReg = LoOperand.isReg(); 610*0b57cec5SDimitry Andric 611*0b57cec5SDimitry Andric // There is a combine of two constant extended values into CONST64. 612*0b57cec5SDimitry Andric bool IsC64 = OptForSize && LoOperand.isImm() && HiOperand.isImm() && 613*0b57cec5SDimitry Andric isGreaterThanNBitTFRI<16>(I1) && isGreaterThanNBitTFRI<16>(I2); 614*0b57cec5SDimitry Andric 615*0b57cec5SDimitry Andric MachineBasicBlock::iterator InsertPt(DoInsertAtI1 ? I1 : I2); 616*0b57cec5SDimitry Andric // Emit combine. 617*0b57cec5SDimitry Andric if (IsHiReg && IsLoReg) 618*0b57cec5SDimitry Andric emitCombineRR(InsertPt, DoubleRegDest, HiOperand, LoOperand); 619*0b57cec5SDimitry Andric else if (IsHiReg) 620*0b57cec5SDimitry Andric emitCombineRI(InsertPt, DoubleRegDest, HiOperand, LoOperand); 621*0b57cec5SDimitry Andric else if (IsLoReg) 622*0b57cec5SDimitry Andric emitCombineIR(InsertPt, DoubleRegDest, HiOperand, LoOperand); 623*0b57cec5SDimitry Andric else if (IsC64 && !IsConst64Disabled) 624*0b57cec5SDimitry Andric emitConst64(InsertPt, DoubleRegDest, HiOperand, LoOperand); 625*0b57cec5SDimitry Andric else 626*0b57cec5SDimitry Andric emitCombineII(InsertPt, DoubleRegDest, HiOperand, LoOperand); 627*0b57cec5SDimitry Andric 628*0b57cec5SDimitry Andric // Move debug instructions along with I1 if it's being 629*0b57cec5SDimitry Andric // moved towards I2. 630*0b57cec5SDimitry Andric if (!DoInsertAtI1 && DbgMItoMove.size() != 0) { 631*0b57cec5SDimitry Andric // Insert debug instructions at the new location before I2. 632*0b57cec5SDimitry Andric MachineBasicBlock *BB = InsertPt->getParent(); 633*0b57cec5SDimitry Andric for (auto NewMI : DbgMItoMove) { 634*0b57cec5SDimitry Andric // If iterator MI is pointing to DEBUG_VAL, make sure 635*0b57cec5SDimitry Andric // MI now points to next relevant instruction. 636*0b57cec5SDimitry Andric if (NewMI == MI) 637*0b57cec5SDimitry Andric ++MI; 638*0b57cec5SDimitry Andric BB->splice(InsertPt, BB, NewMI); 639*0b57cec5SDimitry Andric } 640*0b57cec5SDimitry Andric } 641*0b57cec5SDimitry Andric 642*0b57cec5SDimitry Andric I1.eraseFromParent(); 643*0b57cec5SDimitry Andric I2.eraseFromParent(); 644*0b57cec5SDimitry Andric } 645*0b57cec5SDimitry Andric 646*0b57cec5SDimitry Andric void HexagonCopyToCombine::emitConst64(MachineBasicBlock::iterator &InsertPt, 647*0b57cec5SDimitry Andric unsigned DoubleDestReg, 648*0b57cec5SDimitry Andric MachineOperand &HiOperand, 649*0b57cec5SDimitry Andric MachineOperand &LoOperand) { 650*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Found a CONST64\n"); 651*0b57cec5SDimitry Andric 652*0b57cec5SDimitry Andric DebugLoc DL = InsertPt->getDebugLoc(); 653*0b57cec5SDimitry Andric MachineBasicBlock *BB = InsertPt->getParent(); 654*0b57cec5SDimitry Andric assert(LoOperand.isImm() && HiOperand.isImm() && 655*0b57cec5SDimitry Andric "Both operands must be immediate"); 656*0b57cec5SDimitry Andric 657*0b57cec5SDimitry Andric int64_t V = HiOperand.getImm(); 658*0b57cec5SDimitry Andric V = (V << 32) | (0x0ffffffffLL & LoOperand.getImm()); 659*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::CONST64), DoubleDestReg) 660*0b57cec5SDimitry Andric .addImm(V); 661*0b57cec5SDimitry Andric } 662*0b57cec5SDimitry Andric 663*0b57cec5SDimitry Andric void HexagonCopyToCombine::emitCombineII(MachineBasicBlock::iterator &InsertPt, 664*0b57cec5SDimitry Andric unsigned DoubleDestReg, 665*0b57cec5SDimitry Andric MachineOperand &HiOperand, 666*0b57cec5SDimitry Andric MachineOperand &LoOperand) { 667*0b57cec5SDimitry Andric DebugLoc DL = InsertPt->getDebugLoc(); 668*0b57cec5SDimitry Andric MachineBasicBlock *BB = InsertPt->getParent(); 669*0b57cec5SDimitry Andric 670*0b57cec5SDimitry Andric // Handle globals. 671*0b57cec5SDimitry Andric if (HiOperand.isGlobal()) { 672*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A2_combineii), DoubleDestReg) 673*0b57cec5SDimitry Andric .addGlobalAddress(HiOperand.getGlobal(), HiOperand.getOffset(), 674*0b57cec5SDimitry Andric HiOperand.getTargetFlags()) 675*0b57cec5SDimitry Andric .addImm(LoOperand.getImm()); 676*0b57cec5SDimitry Andric return; 677*0b57cec5SDimitry Andric } 678*0b57cec5SDimitry Andric if (LoOperand.isGlobal()) { 679*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineii), DoubleDestReg) 680*0b57cec5SDimitry Andric .addImm(HiOperand.getImm()) 681*0b57cec5SDimitry Andric .addGlobalAddress(LoOperand.getGlobal(), LoOperand.getOffset(), 682*0b57cec5SDimitry Andric LoOperand.getTargetFlags()); 683*0b57cec5SDimitry Andric return; 684*0b57cec5SDimitry Andric } 685*0b57cec5SDimitry Andric 686*0b57cec5SDimitry Andric // Handle block addresses. 687*0b57cec5SDimitry Andric if (HiOperand.isBlockAddress()) { 688*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A2_combineii), DoubleDestReg) 689*0b57cec5SDimitry Andric .addBlockAddress(HiOperand.getBlockAddress(), HiOperand.getOffset(), 690*0b57cec5SDimitry Andric HiOperand.getTargetFlags()) 691*0b57cec5SDimitry Andric .addImm(LoOperand.getImm()); 692*0b57cec5SDimitry Andric return; 693*0b57cec5SDimitry Andric } 694*0b57cec5SDimitry Andric if (LoOperand.isBlockAddress()) { 695*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineii), DoubleDestReg) 696*0b57cec5SDimitry Andric .addImm(HiOperand.getImm()) 697*0b57cec5SDimitry Andric .addBlockAddress(LoOperand.getBlockAddress(), LoOperand.getOffset(), 698*0b57cec5SDimitry Andric LoOperand.getTargetFlags()); 699*0b57cec5SDimitry Andric return; 700*0b57cec5SDimitry Andric } 701*0b57cec5SDimitry Andric 702*0b57cec5SDimitry Andric // Handle jump tables. 703*0b57cec5SDimitry Andric if (HiOperand.isJTI()) { 704*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A2_combineii), DoubleDestReg) 705*0b57cec5SDimitry Andric .addJumpTableIndex(HiOperand.getIndex(), HiOperand.getTargetFlags()) 706*0b57cec5SDimitry Andric .addImm(LoOperand.getImm()); 707*0b57cec5SDimitry Andric return; 708*0b57cec5SDimitry Andric } 709*0b57cec5SDimitry Andric if (LoOperand.isJTI()) { 710*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineii), DoubleDestReg) 711*0b57cec5SDimitry Andric .addImm(HiOperand.getImm()) 712*0b57cec5SDimitry Andric .addJumpTableIndex(LoOperand.getIndex(), LoOperand.getTargetFlags()); 713*0b57cec5SDimitry Andric return; 714*0b57cec5SDimitry Andric } 715*0b57cec5SDimitry Andric 716*0b57cec5SDimitry Andric // Handle constant pools. 717*0b57cec5SDimitry Andric if (HiOperand.isCPI()) { 718*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A2_combineii), DoubleDestReg) 719*0b57cec5SDimitry Andric .addConstantPoolIndex(HiOperand.getIndex(), HiOperand.getOffset(), 720*0b57cec5SDimitry Andric HiOperand.getTargetFlags()) 721*0b57cec5SDimitry Andric .addImm(LoOperand.getImm()); 722*0b57cec5SDimitry Andric return; 723*0b57cec5SDimitry Andric } 724*0b57cec5SDimitry Andric if (LoOperand.isCPI()) { 725*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineii), DoubleDestReg) 726*0b57cec5SDimitry Andric .addImm(HiOperand.getImm()) 727*0b57cec5SDimitry Andric .addConstantPoolIndex(LoOperand.getIndex(), LoOperand.getOffset(), 728*0b57cec5SDimitry Andric LoOperand.getTargetFlags()); 729*0b57cec5SDimitry Andric return; 730*0b57cec5SDimitry Andric } 731*0b57cec5SDimitry Andric 732*0b57cec5SDimitry Andric // First preference should be given to Hexagon::A2_combineii instruction 733*0b57cec5SDimitry Andric // as it can include U6 (in Hexagon::A4_combineii) as well. 734*0b57cec5SDimitry Andric // In this instruction, HiOperand is const extended, if required. 735*0b57cec5SDimitry Andric if (isInt<8>(LoOperand.getImm())) { 736*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A2_combineii), DoubleDestReg) 737*0b57cec5SDimitry Andric .addImm(HiOperand.getImm()) 738*0b57cec5SDimitry Andric .addImm(LoOperand.getImm()); 739*0b57cec5SDimitry Andric return; 740*0b57cec5SDimitry Andric } 741*0b57cec5SDimitry Andric 742*0b57cec5SDimitry Andric // In this instruction, LoOperand is const extended, if required. 743*0b57cec5SDimitry Andric if (isInt<8>(HiOperand.getImm())) { 744*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineii), DoubleDestReg) 745*0b57cec5SDimitry Andric .addImm(HiOperand.getImm()) 746*0b57cec5SDimitry Andric .addImm(LoOperand.getImm()); 747*0b57cec5SDimitry Andric return; 748*0b57cec5SDimitry Andric } 749*0b57cec5SDimitry Andric 750*0b57cec5SDimitry Andric // Insert new combine instruction. 751*0b57cec5SDimitry Andric // DoubleRegDest = combine #HiImm, #LoImm 752*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A2_combineii), DoubleDestReg) 753*0b57cec5SDimitry Andric .addImm(HiOperand.getImm()) 754*0b57cec5SDimitry Andric .addImm(LoOperand.getImm()); 755*0b57cec5SDimitry Andric } 756*0b57cec5SDimitry Andric 757*0b57cec5SDimitry Andric void HexagonCopyToCombine::emitCombineIR(MachineBasicBlock::iterator &InsertPt, 758*0b57cec5SDimitry Andric unsigned DoubleDestReg, 759*0b57cec5SDimitry Andric MachineOperand &HiOperand, 760*0b57cec5SDimitry Andric MachineOperand &LoOperand) { 761*0b57cec5SDimitry Andric unsigned LoReg = LoOperand.getReg(); 762*0b57cec5SDimitry Andric unsigned LoRegKillFlag = getKillRegState(LoOperand.isKill()); 763*0b57cec5SDimitry Andric 764*0b57cec5SDimitry Andric DebugLoc DL = InsertPt->getDebugLoc(); 765*0b57cec5SDimitry Andric MachineBasicBlock *BB = InsertPt->getParent(); 766*0b57cec5SDimitry Andric 767*0b57cec5SDimitry Andric // Handle globals. 768*0b57cec5SDimitry Andric if (HiOperand.isGlobal()) { 769*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineir), DoubleDestReg) 770*0b57cec5SDimitry Andric .addGlobalAddress(HiOperand.getGlobal(), HiOperand.getOffset(), 771*0b57cec5SDimitry Andric HiOperand.getTargetFlags()) 772*0b57cec5SDimitry Andric .addReg(LoReg, LoRegKillFlag); 773*0b57cec5SDimitry Andric return; 774*0b57cec5SDimitry Andric } 775*0b57cec5SDimitry Andric // Handle block addresses. 776*0b57cec5SDimitry Andric if (HiOperand.isBlockAddress()) { 777*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineir), DoubleDestReg) 778*0b57cec5SDimitry Andric .addBlockAddress(HiOperand.getBlockAddress(), HiOperand.getOffset(), 779*0b57cec5SDimitry Andric HiOperand.getTargetFlags()) 780*0b57cec5SDimitry Andric .addReg(LoReg, LoRegKillFlag); 781*0b57cec5SDimitry Andric return; 782*0b57cec5SDimitry Andric } 783*0b57cec5SDimitry Andric // Handle jump tables. 784*0b57cec5SDimitry Andric if (HiOperand.isJTI()) { 785*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineir), DoubleDestReg) 786*0b57cec5SDimitry Andric .addJumpTableIndex(HiOperand.getIndex(), HiOperand.getTargetFlags()) 787*0b57cec5SDimitry Andric .addReg(LoReg, LoRegKillFlag); 788*0b57cec5SDimitry Andric return; 789*0b57cec5SDimitry Andric } 790*0b57cec5SDimitry Andric // Handle constant pools. 791*0b57cec5SDimitry Andric if (HiOperand.isCPI()) { 792*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineir), DoubleDestReg) 793*0b57cec5SDimitry Andric .addConstantPoolIndex(HiOperand.getIndex(), HiOperand.getOffset(), 794*0b57cec5SDimitry Andric HiOperand.getTargetFlags()) 795*0b57cec5SDimitry Andric .addReg(LoReg, LoRegKillFlag); 796*0b57cec5SDimitry Andric return; 797*0b57cec5SDimitry Andric } 798*0b57cec5SDimitry Andric // Insert new combine instruction. 799*0b57cec5SDimitry Andric // DoubleRegDest = combine #HiImm, LoReg 800*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineir), DoubleDestReg) 801*0b57cec5SDimitry Andric .addImm(HiOperand.getImm()) 802*0b57cec5SDimitry Andric .addReg(LoReg, LoRegKillFlag); 803*0b57cec5SDimitry Andric } 804*0b57cec5SDimitry Andric 805*0b57cec5SDimitry Andric void HexagonCopyToCombine::emitCombineRI(MachineBasicBlock::iterator &InsertPt, 806*0b57cec5SDimitry Andric unsigned DoubleDestReg, 807*0b57cec5SDimitry Andric MachineOperand &HiOperand, 808*0b57cec5SDimitry Andric MachineOperand &LoOperand) { 809*0b57cec5SDimitry Andric unsigned HiRegKillFlag = getKillRegState(HiOperand.isKill()); 810*0b57cec5SDimitry Andric unsigned HiReg = HiOperand.getReg(); 811*0b57cec5SDimitry Andric 812*0b57cec5SDimitry Andric DebugLoc DL = InsertPt->getDebugLoc(); 813*0b57cec5SDimitry Andric MachineBasicBlock *BB = InsertPt->getParent(); 814*0b57cec5SDimitry Andric 815*0b57cec5SDimitry Andric // Handle global. 816*0b57cec5SDimitry Andric if (LoOperand.isGlobal()) { 817*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineri), DoubleDestReg) 818*0b57cec5SDimitry Andric .addReg(HiReg, HiRegKillFlag) 819*0b57cec5SDimitry Andric .addGlobalAddress(LoOperand.getGlobal(), LoOperand.getOffset(), 820*0b57cec5SDimitry Andric LoOperand.getTargetFlags()); 821*0b57cec5SDimitry Andric return; 822*0b57cec5SDimitry Andric } 823*0b57cec5SDimitry Andric // Handle block addresses. 824*0b57cec5SDimitry Andric if (LoOperand.isBlockAddress()) { 825*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineri), DoubleDestReg) 826*0b57cec5SDimitry Andric .addReg(HiReg, HiRegKillFlag) 827*0b57cec5SDimitry Andric .addBlockAddress(LoOperand.getBlockAddress(), LoOperand.getOffset(), 828*0b57cec5SDimitry Andric LoOperand.getTargetFlags()); 829*0b57cec5SDimitry Andric return; 830*0b57cec5SDimitry Andric } 831*0b57cec5SDimitry Andric // Handle jump tables. 832*0b57cec5SDimitry Andric if (LoOperand.isJTI()) { 833*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineri), DoubleDestReg) 834*0b57cec5SDimitry Andric .addReg(HiOperand.getReg(), HiRegKillFlag) 835*0b57cec5SDimitry Andric .addJumpTableIndex(LoOperand.getIndex(), LoOperand.getTargetFlags()); 836*0b57cec5SDimitry Andric return; 837*0b57cec5SDimitry Andric } 838*0b57cec5SDimitry Andric // Handle constant pools. 839*0b57cec5SDimitry Andric if (LoOperand.isCPI()) { 840*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineri), DoubleDestReg) 841*0b57cec5SDimitry Andric .addReg(HiOperand.getReg(), HiRegKillFlag) 842*0b57cec5SDimitry Andric .addConstantPoolIndex(LoOperand.getIndex(), LoOperand.getOffset(), 843*0b57cec5SDimitry Andric LoOperand.getTargetFlags()); 844*0b57cec5SDimitry Andric return; 845*0b57cec5SDimitry Andric } 846*0b57cec5SDimitry Andric 847*0b57cec5SDimitry Andric // Insert new combine instruction. 848*0b57cec5SDimitry Andric // DoubleRegDest = combine HiReg, #LoImm 849*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A4_combineri), DoubleDestReg) 850*0b57cec5SDimitry Andric .addReg(HiReg, HiRegKillFlag) 851*0b57cec5SDimitry Andric .addImm(LoOperand.getImm()); 852*0b57cec5SDimitry Andric } 853*0b57cec5SDimitry Andric 854*0b57cec5SDimitry Andric void HexagonCopyToCombine::emitCombineRR(MachineBasicBlock::iterator &InsertPt, 855*0b57cec5SDimitry Andric unsigned DoubleDestReg, 856*0b57cec5SDimitry Andric MachineOperand &HiOperand, 857*0b57cec5SDimitry Andric MachineOperand &LoOperand) { 858*0b57cec5SDimitry Andric unsigned LoRegKillFlag = getKillRegState(LoOperand.isKill()); 859*0b57cec5SDimitry Andric unsigned HiRegKillFlag = getKillRegState(HiOperand.isKill()); 860*0b57cec5SDimitry Andric unsigned LoReg = LoOperand.getReg(); 861*0b57cec5SDimitry Andric unsigned HiReg = HiOperand.getReg(); 862*0b57cec5SDimitry Andric 863*0b57cec5SDimitry Andric DebugLoc DL = InsertPt->getDebugLoc(); 864*0b57cec5SDimitry Andric MachineBasicBlock *BB = InsertPt->getParent(); 865*0b57cec5SDimitry Andric 866*0b57cec5SDimitry Andric // Insert new combine instruction. 867*0b57cec5SDimitry Andric // DoubleRegDest = combine HiReg, LoReg 868*0b57cec5SDimitry Andric unsigned NewOpc; 869*0b57cec5SDimitry Andric if (Hexagon::DoubleRegsRegClass.contains(DoubleDestReg)) { 870*0b57cec5SDimitry Andric NewOpc = Hexagon::A2_combinew; 871*0b57cec5SDimitry Andric } else if (Hexagon::HvxWRRegClass.contains(DoubleDestReg)) { 872*0b57cec5SDimitry Andric assert(ST->useHVXOps()); 873*0b57cec5SDimitry Andric NewOpc = Hexagon::V6_vcombine; 874*0b57cec5SDimitry Andric } else 875*0b57cec5SDimitry Andric llvm_unreachable("Unexpected register"); 876*0b57cec5SDimitry Andric 877*0b57cec5SDimitry Andric BuildMI(*BB, InsertPt, DL, TII->get(NewOpc), DoubleDestReg) 878*0b57cec5SDimitry Andric .addReg(HiReg, HiRegKillFlag) 879*0b57cec5SDimitry Andric .addReg(LoReg, LoRegKillFlag); 880*0b57cec5SDimitry Andric } 881*0b57cec5SDimitry Andric 882*0b57cec5SDimitry Andric FunctionPass *llvm::createHexagonCopyToCombine() { 883*0b57cec5SDimitry Andric return new HexagonCopyToCombine(); 884*0b57cec5SDimitry Andric } 885