1*0b57cec5SDimitry Andric //===-- MLxExpansionPass.cpp - Expand MLx instrs to avoid hazards ---------===// 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 // Expand VFP / NEON floating point MLA / MLS instructions (each to a pair of 10*0b57cec5SDimitry Andric // multiple and add / sub instructions) when special VMLx hazards are detected. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "ARM.h" 15*0b57cec5SDimitry Andric #include "ARMBaseInstrInfo.h" 16*0b57cec5SDimitry Andric #include "ARMSubtarget.h" 17*0b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 18*0b57cec5SDimitry Andric #include "llvm/ADT/Statistic.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/MachineRegisterInfo.h" 23*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 24*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 25*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 26*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 27*0b57cec5SDimitry Andric using namespace llvm; 28*0b57cec5SDimitry Andric 29*0b57cec5SDimitry Andric #define DEBUG_TYPE "mlx-expansion" 30*0b57cec5SDimitry Andric 31*0b57cec5SDimitry Andric static cl::opt<bool> 32*0b57cec5SDimitry Andric ForceExapnd("expand-all-fp-mlx", cl::init(false), cl::Hidden); 33*0b57cec5SDimitry Andric static cl::opt<unsigned> 34*0b57cec5SDimitry Andric ExpandLimit("expand-limit", cl::init(~0U), cl::Hidden); 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric STATISTIC(NumExpand, "Number of fp MLA / MLS instructions expanded"); 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric namespace { 39*0b57cec5SDimitry Andric struct MLxExpansion : public MachineFunctionPass { 40*0b57cec5SDimitry Andric static char ID; 41*0b57cec5SDimitry Andric MLxExpansion() : MachineFunctionPass(ID) {} 42*0b57cec5SDimitry Andric 43*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override; 44*0b57cec5SDimitry Andric 45*0b57cec5SDimitry Andric StringRef getPassName() const override { 46*0b57cec5SDimitry Andric return "ARM MLA / MLS expansion pass"; 47*0b57cec5SDimitry Andric } 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric private: 50*0b57cec5SDimitry Andric const ARMBaseInstrInfo *TII; 51*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI; 52*0b57cec5SDimitry Andric MachineRegisterInfo *MRI; 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric bool isLikeA9; 55*0b57cec5SDimitry Andric bool isSwift; 56*0b57cec5SDimitry Andric unsigned MIIdx; 57*0b57cec5SDimitry Andric MachineInstr* LastMIs[4]; 58*0b57cec5SDimitry Andric SmallPtrSet<MachineInstr*, 4> IgnoreStall; 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric void clearStack(); 61*0b57cec5SDimitry Andric void pushStack(MachineInstr *MI); 62*0b57cec5SDimitry Andric MachineInstr *getAccDefMI(MachineInstr *MI) const; 63*0b57cec5SDimitry Andric unsigned getDefReg(MachineInstr *MI) const; 64*0b57cec5SDimitry Andric bool hasLoopHazard(MachineInstr *MI) const; 65*0b57cec5SDimitry Andric bool hasRAWHazard(unsigned Reg, MachineInstr *MI) const; 66*0b57cec5SDimitry Andric bool FindMLxHazard(MachineInstr *MI); 67*0b57cec5SDimitry Andric void ExpandFPMLxInstruction(MachineBasicBlock &MBB, MachineInstr *MI, 68*0b57cec5SDimitry Andric unsigned MulOpc, unsigned AddSubOpc, 69*0b57cec5SDimitry Andric bool NegAcc, bool HasLane); 70*0b57cec5SDimitry Andric bool ExpandFPMLxInstructions(MachineBasicBlock &MBB); 71*0b57cec5SDimitry Andric }; 72*0b57cec5SDimitry Andric char MLxExpansion::ID = 0; 73*0b57cec5SDimitry Andric } 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric void MLxExpansion::clearStack() { 76*0b57cec5SDimitry Andric std::fill(LastMIs, LastMIs + 4, nullptr); 77*0b57cec5SDimitry Andric MIIdx = 0; 78*0b57cec5SDimitry Andric } 79*0b57cec5SDimitry Andric 80*0b57cec5SDimitry Andric void MLxExpansion::pushStack(MachineInstr *MI) { 81*0b57cec5SDimitry Andric LastMIs[MIIdx] = MI; 82*0b57cec5SDimitry Andric if (++MIIdx == 4) 83*0b57cec5SDimitry Andric MIIdx = 0; 84*0b57cec5SDimitry Andric } 85*0b57cec5SDimitry Andric 86*0b57cec5SDimitry Andric MachineInstr *MLxExpansion::getAccDefMI(MachineInstr *MI) const { 87*0b57cec5SDimitry Andric // Look past COPY and INSERT_SUBREG instructions to find the 88*0b57cec5SDimitry Andric // real definition MI. This is important for _sfp instructions. 89*0b57cec5SDimitry Andric unsigned Reg = MI->getOperand(1).getReg(); 90*0b57cec5SDimitry Andric if (TargetRegisterInfo::isPhysicalRegister(Reg)) 91*0b57cec5SDimitry Andric return nullptr; 92*0b57cec5SDimitry Andric 93*0b57cec5SDimitry Andric MachineBasicBlock *MBB = MI->getParent(); 94*0b57cec5SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(Reg); 95*0b57cec5SDimitry Andric while (true) { 96*0b57cec5SDimitry Andric if (DefMI->getParent() != MBB) 97*0b57cec5SDimitry Andric break; 98*0b57cec5SDimitry Andric if (DefMI->isCopyLike()) { 99*0b57cec5SDimitry Andric Reg = DefMI->getOperand(1).getReg(); 100*0b57cec5SDimitry Andric if (TargetRegisterInfo::isVirtualRegister(Reg)) { 101*0b57cec5SDimitry Andric DefMI = MRI->getVRegDef(Reg); 102*0b57cec5SDimitry Andric continue; 103*0b57cec5SDimitry Andric } 104*0b57cec5SDimitry Andric } else if (DefMI->isInsertSubreg()) { 105*0b57cec5SDimitry Andric Reg = DefMI->getOperand(2).getReg(); 106*0b57cec5SDimitry Andric if (TargetRegisterInfo::isVirtualRegister(Reg)) { 107*0b57cec5SDimitry Andric DefMI = MRI->getVRegDef(Reg); 108*0b57cec5SDimitry Andric continue; 109*0b57cec5SDimitry Andric } 110*0b57cec5SDimitry Andric } 111*0b57cec5SDimitry Andric break; 112*0b57cec5SDimitry Andric } 113*0b57cec5SDimitry Andric return DefMI; 114*0b57cec5SDimitry Andric } 115*0b57cec5SDimitry Andric 116*0b57cec5SDimitry Andric unsigned MLxExpansion::getDefReg(MachineInstr *MI) const { 117*0b57cec5SDimitry Andric unsigned Reg = MI->getOperand(0).getReg(); 118*0b57cec5SDimitry Andric if (TargetRegisterInfo::isPhysicalRegister(Reg) || 119*0b57cec5SDimitry Andric !MRI->hasOneNonDBGUse(Reg)) 120*0b57cec5SDimitry Andric return Reg; 121*0b57cec5SDimitry Andric 122*0b57cec5SDimitry Andric MachineBasicBlock *MBB = MI->getParent(); 123*0b57cec5SDimitry Andric MachineInstr *UseMI = &*MRI->use_instr_nodbg_begin(Reg); 124*0b57cec5SDimitry Andric if (UseMI->getParent() != MBB) 125*0b57cec5SDimitry Andric return Reg; 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric while (UseMI->isCopy() || UseMI->isInsertSubreg()) { 128*0b57cec5SDimitry Andric Reg = UseMI->getOperand(0).getReg(); 129*0b57cec5SDimitry Andric if (TargetRegisterInfo::isPhysicalRegister(Reg) || 130*0b57cec5SDimitry Andric !MRI->hasOneNonDBGUse(Reg)) 131*0b57cec5SDimitry Andric return Reg; 132*0b57cec5SDimitry Andric UseMI = &*MRI->use_instr_nodbg_begin(Reg); 133*0b57cec5SDimitry Andric if (UseMI->getParent() != MBB) 134*0b57cec5SDimitry Andric return Reg; 135*0b57cec5SDimitry Andric } 136*0b57cec5SDimitry Andric 137*0b57cec5SDimitry Andric return Reg; 138*0b57cec5SDimitry Andric } 139*0b57cec5SDimitry Andric 140*0b57cec5SDimitry Andric /// hasLoopHazard - Check whether an MLx instruction is chained to itself across 141*0b57cec5SDimitry Andric /// a single-MBB loop. 142*0b57cec5SDimitry Andric bool MLxExpansion::hasLoopHazard(MachineInstr *MI) const { 143*0b57cec5SDimitry Andric unsigned Reg = MI->getOperand(1).getReg(); 144*0b57cec5SDimitry Andric if (TargetRegisterInfo::isPhysicalRegister(Reg)) 145*0b57cec5SDimitry Andric return false; 146*0b57cec5SDimitry Andric 147*0b57cec5SDimitry Andric MachineBasicBlock *MBB = MI->getParent(); 148*0b57cec5SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(Reg); 149*0b57cec5SDimitry Andric while (true) { 150*0b57cec5SDimitry Andric outer_continue: 151*0b57cec5SDimitry Andric if (DefMI->getParent() != MBB) 152*0b57cec5SDimitry Andric break; 153*0b57cec5SDimitry Andric 154*0b57cec5SDimitry Andric if (DefMI->isPHI()) { 155*0b57cec5SDimitry Andric for (unsigned i = 1, e = DefMI->getNumOperands(); i < e; i += 2) { 156*0b57cec5SDimitry Andric if (DefMI->getOperand(i + 1).getMBB() == MBB) { 157*0b57cec5SDimitry Andric unsigned SrcReg = DefMI->getOperand(i).getReg(); 158*0b57cec5SDimitry Andric if (TargetRegisterInfo::isVirtualRegister(SrcReg)) { 159*0b57cec5SDimitry Andric DefMI = MRI->getVRegDef(SrcReg); 160*0b57cec5SDimitry Andric goto outer_continue; 161*0b57cec5SDimitry Andric } 162*0b57cec5SDimitry Andric } 163*0b57cec5SDimitry Andric } 164*0b57cec5SDimitry Andric } else if (DefMI->isCopyLike()) { 165*0b57cec5SDimitry Andric Reg = DefMI->getOperand(1).getReg(); 166*0b57cec5SDimitry Andric if (TargetRegisterInfo::isVirtualRegister(Reg)) { 167*0b57cec5SDimitry Andric DefMI = MRI->getVRegDef(Reg); 168*0b57cec5SDimitry Andric continue; 169*0b57cec5SDimitry Andric } 170*0b57cec5SDimitry Andric } else if (DefMI->isInsertSubreg()) { 171*0b57cec5SDimitry Andric Reg = DefMI->getOperand(2).getReg(); 172*0b57cec5SDimitry Andric if (TargetRegisterInfo::isVirtualRegister(Reg)) { 173*0b57cec5SDimitry Andric DefMI = MRI->getVRegDef(Reg); 174*0b57cec5SDimitry Andric continue; 175*0b57cec5SDimitry Andric } 176*0b57cec5SDimitry Andric } 177*0b57cec5SDimitry Andric 178*0b57cec5SDimitry Andric break; 179*0b57cec5SDimitry Andric } 180*0b57cec5SDimitry Andric 181*0b57cec5SDimitry Andric return DefMI == MI; 182*0b57cec5SDimitry Andric } 183*0b57cec5SDimitry Andric 184*0b57cec5SDimitry Andric bool MLxExpansion::hasRAWHazard(unsigned Reg, MachineInstr *MI) const { 185*0b57cec5SDimitry Andric // FIXME: Detect integer instructions properly. 186*0b57cec5SDimitry Andric const MCInstrDesc &MCID = MI->getDesc(); 187*0b57cec5SDimitry Andric unsigned Domain = MCID.TSFlags & ARMII::DomainMask; 188*0b57cec5SDimitry Andric if (MI->mayStore()) 189*0b57cec5SDimitry Andric return false; 190*0b57cec5SDimitry Andric unsigned Opcode = MCID.getOpcode(); 191*0b57cec5SDimitry Andric if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD) 192*0b57cec5SDimitry Andric return false; 193*0b57cec5SDimitry Andric if ((Domain & ARMII::DomainVFP) || (Domain & ARMII::DomainNEON)) 194*0b57cec5SDimitry Andric return MI->readsRegister(Reg, TRI); 195*0b57cec5SDimitry Andric return false; 196*0b57cec5SDimitry Andric } 197*0b57cec5SDimitry Andric 198*0b57cec5SDimitry Andric static bool isFpMulInstruction(unsigned Opcode) { 199*0b57cec5SDimitry Andric switch (Opcode) { 200*0b57cec5SDimitry Andric case ARM::VMULS: 201*0b57cec5SDimitry Andric case ARM::VMULfd: 202*0b57cec5SDimitry Andric case ARM::VMULfq: 203*0b57cec5SDimitry Andric case ARM::VMULD: 204*0b57cec5SDimitry Andric case ARM::VMULslfd: 205*0b57cec5SDimitry Andric case ARM::VMULslfq: 206*0b57cec5SDimitry Andric return true; 207*0b57cec5SDimitry Andric default: 208*0b57cec5SDimitry Andric return false; 209*0b57cec5SDimitry Andric } 210*0b57cec5SDimitry Andric } 211*0b57cec5SDimitry Andric 212*0b57cec5SDimitry Andric bool MLxExpansion::FindMLxHazard(MachineInstr *MI) { 213*0b57cec5SDimitry Andric if (NumExpand >= ExpandLimit) 214*0b57cec5SDimitry Andric return false; 215*0b57cec5SDimitry Andric 216*0b57cec5SDimitry Andric if (ForceExapnd) 217*0b57cec5SDimitry Andric return true; 218*0b57cec5SDimitry Andric 219*0b57cec5SDimitry Andric MachineInstr *DefMI = getAccDefMI(MI); 220*0b57cec5SDimitry Andric if (TII->isFpMLxInstruction(DefMI->getOpcode())) { 221*0b57cec5SDimitry Andric // r0 = vmla 222*0b57cec5SDimitry Andric // r3 = vmla r0, r1, r2 223*0b57cec5SDimitry Andric // takes 16 - 17 cycles 224*0b57cec5SDimitry Andric // 225*0b57cec5SDimitry Andric // r0 = vmla 226*0b57cec5SDimitry Andric // r4 = vmul r1, r2 227*0b57cec5SDimitry Andric // r3 = vadd r0, r4 228*0b57cec5SDimitry Andric // takes about 14 - 15 cycles even with vmul stalling for 4 cycles. 229*0b57cec5SDimitry Andric IgnoreStall.insert(DefMI); 230*0b57cec5SDimitry Andric return true; 231*0b57cec5SDimitry Andric } 232*0b57cec5SDimitry Andric 233*0b57cec5SDimitry Andric // On Swift, we mostly care about hazards from multiplication instructions 234*0b57cec5SDimitry Andric // writing the accumulator and the pipelining of loop iterations by out-of- 235*0b57cec5SDimitry Andric // order execution. 236*0b57cec5SDimitry Andric if (isSwift) 237*0b57cec5SDimitry Andric return isFpMulInstruction(DefMI->getOpcode()) || hasLoopHazard(MI); 238*0b57cec5SDimitry Andric 239*0b57cec5SDimitry Andric if (IgnoreStall.count(MI)) 240*0b57cec5SDimitry Andric return false; 241*0b57cec5SDimitry Andric 242*0b57cec5SDimitry Andric // If a VMLA.F is followed by an VADD.F or VMUL.F with no RAW hazard, the 243*0b57cec5SDimitry Andric // VADD.F or VMUL.F will stall 4 cycles before issue. The 4 cycle stall 244*0b57cec5SDimitry Andric // preserves the in-order retirement of the instructions. 245*0b57cec5SDimitry Andric // Look at the next few instructions, if *most* of them can cause hazards, 246*0b57cec5SDimitry Andric // then the scheduler can't *fix* this, we'd better break up the VMLA. 247*0b57cec5SDimitry Andric unsigned Limit1 = isLikeA9 ? 1 : 4; 248*0b57cec5SDimitry Andric unsigned Limit2 = isLikeA9 ? 1 : 4; 249*0b57cec5SDimitry Andric for (unsigned i = 1; i <= 4; ++i) { 250*0b57cec5SDimitry Andric int Idx = ((int)MIIdx - i + 4) % 4; 251*0b57cec5SDimitry Andric MachineInstr *NextMI = LastMIs[Idx]; 252*0b57cec5SDimitry Andric if (!NextMI) 253*0b57cec5SDimitry Andric continue; 254*0b57cec5SDimitry Andric 255*0b57cec5SDimitry Andric if (TII->canCauseFpMLxStall(NextMI->getOpcode())) { 256*0b57cec5SDimitry Andric if (i <= Limit1) 257*0b57cec5SDimitry Andric return true; 258*0b57cec5SDimitry Andric } 259*0b57cec5SDimitry Andric 260*0b57cec5SDimitry Andric // Look for VMLx RAW hazard. 261*0b57cec5SDimitry Andric if (i <= Limit2 && hasRAWHazard(getDefReg(MI), NextMI)) 262*0b57cec5SDimitry Andric return true; 263*0b57cec5SDimitry Andric } 264*0b57cec5SDimitry Andric 265*0b57cec5SDimitry Andric return false; 266*0b57cec5SDimitry Andric } 267*0b57cec5SDimitry Andric 268*0b57cec5SDimitry Andric /// ExpandFPMLxInstructions - Expand a MLA / MLS instruction into a pair 269*0b57cec5SDimitry Andric /// of MUL + ADD / SUB instructions. 270*0b57cec5SDimitry Andric void 271*0b57cec5SDimitry Andric MLxExpansion::ExpandFPMLxInstruction(MachineBasicBlock &MBB, MachineInstr *MI, 272*0b57cec5SDimitry Andric unsigned MulOpc, unsigned AddSubOpc, 273*0b57cec5SDimitry Andric bool NegAcc, bool HasLane) { 274*0b57cec5SDimitry Andric unsigned DstReg = MI->getOperand(0).getReg(); 275*0b57cec5SDimitry Andric bool DstDead = MI->getOperand(0).isDead(); 276*0b57cec5SDimitry Andric unsigned AccReg = MI->getOperand(1).getReg(); 277*0b57cec5SDimitry Andric unsigned Src1Reg = MI->getOperand(2).getReg(); 278*0b57cec5SDimitry Andric unsigned Src2Reg = MI->getOperand(3).getReg(); 279*0b57cec5SDimitry Andric bool Src1Kill = MI->getOperand(2).isKill(); 280*0b57cec5SDimitry Andric bool Src2Kill = MI->getOperand(3).isKill(); 281*0b57cec5SDimitry Andric unsigned LaneImm = HasLane ? MI->getOperand(4).getImm() : 0; 282*0b57cec5SDimitry Andric unsigned NextOp = HasLane ? 5 : 4; 283*0b57cec5SDimitry Andric ARMCC::CondCodes Pred = (ARMCC::CondCodes)MI->getOperand(NextOp).getImm(); 284*0b57cec5SDimitry Andric unsigned PredReg = MI->getOperand(++NextOp).getReg(); 285*0b57cec5SDimitry Andric 286*0b57cec5SDimitry Andric const MCInstrDesc &MCID1 = TII->get(MulOpc); 287*0b57cec5SDimitry Andric const MCInstrDesc &MCID2 = TII->get(AddSubOpc); 288*0b57cec5SDimitry Andric const MachineFunction &MF = *MI->getParent()->getParent(); 289*0b57cec5SDimitry Andric unsigned TmpReg = MRI->createVirtualRegister( 290*0b57cec5SDimitry Andric TII->getRegClass(MCID1, 0, TRI, MF)); 291*0b57cec5SDimitry Andric 292*0b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MI, MI->getDebugLoc(), MCID1, TmpReg) 293*0b57cec5SDimitry Andric .addReg(Src1Reg, getKillRegState(Src1Kill)) 294*0b57cec5SDimitry Andric .addReg(Src2Reg, getKillRegState(Src2Kill)); 295*0b57cec5SDimitry Andric if (HasLane) 296*0b57cec5SDimitry Andric MIB.addImm(LaneImm); 297*0b57cec5SDimitry Andric MIB.addImm(Pred).addReg(PredReg); 298*0b57cec5SDimitry Andric 299*0b57cec5SDimitry Andric MIB = BuildMI(MBB, MI, MI->getDebugLoc(), MCID2) 300*0b57cec5SDimitry Andric .addReg(DstReg, getDefRegState(true) | getDeadRegState(DstDead)); 301*0b57cec5SDimitry Andric 302*0b57cec5SDimitry Andric if (NegAcc) { 303*0b57cec5SDimitry Andric bool AccKill = MRI->hasOneNonDBGUse(AccReg); 304*0b57cec5SDimitry Andric MIB.addReg(TmpReg, getKillRegState(true)) 305*0b57cec5SDimitry Andric .addReg(AccReg, getKillRegState(AccKill)); 306*0b57cec5SDimitry Andric } else { 307*0b57cec5SDimitry Andric MIB.addReg(AccReg).addReg(TmpReg, getKillRegState(true)); 308*0b57cec5SDimitry Andric } 309*0b57cec5SDimitry Andric MIB.addImm(Pred).addReg(PredReg); 310*0b57cec5SDimitry Andric 311*0b57cec5SDimitry Andric LLVM_DEBUG({ 312*0b57cec5SDimitry Andric dbgs() << "Expanding: " << *MI; 313*0b57cec5SDimitry Andric dbgs() << " to:\n"; 314*0b57cec5SDimitry Andric MachineBasicBlock::iterator MII = MI; 315*0b57cec5SDimitry Andric MII = std::prev(MII); 316*0b57cec5SDimitry Andric MachineInstr &MI2 = *MII; 317*0b57cec5SDimitry Andric MII = std::prev(MII); 318*0b57cec5SDimitry Andric MachineInstr &MI1 = *MII; 319*0b57cec5SDimitry Andric dbgs() << " " << MI1; 320*0b57cec5SDimitry Andric dbgs() << " " << MI2; 321*0b57cec5SDimitry Andric }); 322*0b57cec5SDimitry Andric 323*0b57cec5SDimitry Andric MI->eraseFromParent(); 324*0b57cec5SDimitry Andric ++NumExpand; 325*0b57cec5SDimitry Andric } 326*0b57cec5SDimitry Andric 327*0b57cec5SDimitry Andric bool MLxExpansion::ExpandFPMLxInstructions(MachineBasicBlock &MBB) { 328*0b57cec5SDimitry Andric bool Changed = false; 329*0b57cec5SDimitry Andric 330*0b57cec5SDimitry Andric clearStack(); 331*0b57cec5SDimitry Andric IgnoreStall.clear(); 332*0b57cec5SDimitry Andric 333*0b57cec5SDimitry Andric unsigned Skip = 0; 334*0b57cec5SDimitry Andric MachineBasicBlock::reverse_iterator MII = MBB.rbegin(), E = MBB.rend(); 335*0b57cec5SDimitry Andric while (MII != E) { 336*0b57cec5SDimitry Andric MachineInstr *MI = &*MII++; 337*0b57cec5SDimitry Andric 338*0b57cec5SDimitry Andric if (MI->isPosition() || MI->isImplicitDef() || MI->isCopy()) 339*0b57cec5SDimitry Andric continue; 340*0b57cec5SDimitry Andric 341*0b57cec5SDimitry Andric const MCInstrDesc &MCID = MI->getDesc(); 342*0b57cec5SDimitry Andric if (MI->isBarrier()) { 343*0b57cec5SDimitry Andric clearStack(); 344*0b57cec5SDimitry Andric Skip = 0; 345*0b57cec5SDimitry Andric continue; 346*0b57cec5SDimitry Andric } 347*0b57cec5SDimitry Andric 348*0b57cec5SDimitry Andric unsigned Domain = MCID.TSFlags & ARMII::DomainMask; 349*0b57cec5SDimitry Andric if (Domain == ARMII::DomainGeneral) { 350*0b57cec5SDimitry Andric if (++Skip == 2) 351*0b57cec5SDimitry Andric // Assume dual issues of non-VFP / NEON instructions. 352*0b57cec5SDimitry Andric pushStack(nullptr); 353*0b57cec5SDimitry Andric } else { 354*0b57cec5SDimitry Andric Skip = 0; 355*0b57cec5SDimitry Andric 356*0b57cec5SDimitry Andric unsigned MulOpc, AddSubOpc; 357*0b57cec5SDimitry Andric bool NegAcc, HasLane; 358*0b57cec5SDimitry Andric if (!TII->isFpMLxInstruction(MCID.getOpcode(), 359*0b57cec5SDimitry Andric MulOpc, AddSubOpc, NegAcc, HasLane) || 360*0b57cec5SDimitry Andric !FindMLxHazard(MI)) 361*0b57cec5SDimitry Andric pushStack(MI); 362*0b57cec5SDimitry Andric else { 363*0b57cec5SDimitry Andric ExpandFPMLxInstruction(MBB, MI, MulOpc, AddSubOpc, NegAcc, HasLane); 364*0b57cec5SDimitry Andric Changed = true; 365*0b57cec5SDimitry Andric } 366*0b57cec5SDimitry Andric } 367*0b57cec5SDimitry Andric } 368*0b57cec5SDimitry Andric 369*0b57cec5SDimitry Andric return Changed; 370*0b57cec5SDimitry Andric } 371*0b57cec5SDimitry Andric 372*0b57cec5SDimitry Andric bool MLxExpansion::runOnMachineFunction(MachineFunction &Fn) { 373*0b57cec5SDimitry Andric if (skipFunction(Fn.getFunction())) 374*0b57cec5SDimitry Andric return false; 375*0b57cec5SDimitry Andric 376*0b57cec5SDimitry Andric TII = static_cast<const ARMBaseInstrInfo *>(Fn.getSubtarget().getInstrInfo()); 377*0b57cec5SDimitry Andric TRI = Fn.getSubtarget().getRegisterInfo(); 378*0b57cec5SDimitry Andric MRI = &Fn.getRegInfo(); 379*0b57cec5SDimitry Andric const ARMSubtarget *STI = &Fn.getSubtarget<ARMSubtarget>(); 380*0b57cec5SDimitry Andric if (!STI->expandMLx()) 381*0b57cec5SDimitry Andric return false; 382*0b57cec5SDimitry Andric isLikeA9 = STI->isLikeA9() || STI->isSwift(); 383*0b57cec5SDimitry Andric isSwift = STI->isSwift(); 384*0b57cec5SDimitry Andric 385*0b57cec5SDimitry Andric bool Modified = false; 386*0b57cec5SDimitry Andric for (MachineBasicBlock &MBB : Fn) 387*0b57cec5SDimitry Andric Modified |= ExpandFPMLxInstructions(MBB); 388*0b57cec5SDimitry Andric 389*0b57cec5SDimitry Andric return Modified; 390*0b57cec5SDimitry Andric } 391*0b57cec5SDimitry Andric 392*0b57cec5SDimitry Andric FunctionPass *llvm::createMLxExpansionPass() { 393*0b57cec5SDimitry Andric return new MLxExpansion(); 394*0b57cec5SDimitry Andric } 395