10b57cec5SDimitry Andric //===-- MLxExpansionPass.cpp - Expand MLx instrs to avoid hazards ---------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // Expand VFP / NEON floating point MLA / MLS instructions (each to a pair of 100b57cec5SDimitry Andric // multiple and add / sub instructions) when special VMLx hazards are detected. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "ARM.h" 150b57cec5SDimitry Andric #include "ARMBaseInstrInfo.h" 160b57cec5SDimitry Andric #include "ARMSubtarget.h" 170b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 180b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 240b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 250b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 260b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 270b57cec5SDimitry Andric using namespace llvm; 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #define DEBUG_TYPE "mlx-expansion" 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric static cl::opt<bool> 320b57cec5SDimitry Andric ForceExapnd("expand-all-fp-mlx", cl::init(false), cl::Hidden); 330b57cec5SDimitry Andric static cl::opt<unsigned> 340b57cec5SDimitry Andric ExpandLimit("expand-limit", cl::init(~0U), cl::Hidden); 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric STATISTIC(NumExpand, "Number of fp MLA / MLS instructions expanded"); 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric namespace { 390b57cec5SDimitry Andric struct MLxExpansion : public MachineFunctionPass { 400b57cec5SDimitry Andric static char ID; 410b57cec5SDimitry Andric MLxExpansion() : MachineFunctionPass(ID) {} 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override; 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric StringRef getPassName() const override { 460b57cec5SDimitry Andric return "ARM MLA / MLS expansion pass"; 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric private: 500b57cec5SDimitry Andric const ARMBaseInstrInfo *TII; 510b57cec5SDimitry Andric const TargetRegisterInfo *TRI; 520b57cec5SDimitry Andric MachineRegisterInfo *MRI; 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric bool isLikeA9; 550b57cec5SDimitry Andric bool isSwift; 560b57cec5SDimitry Andric unsigned MIIdx; 570b57cec5SDimitry Andric MachineInstr* LastMIs[4]; 580b57cec5SDimitry Andric SmallPtrSet<MachineInstr*, 4> IgnoreStall; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric void clearStack(); 610b57cec5SDimitry Andric void pushStack(MachineInstr *MI); 620b57cec5SDimitry Andric MachineInstr *getAccDefMI(MachineInstr *MI) const; 630b57cec5SDimitry Andric unsigned getDefReg(MachineInstr *MI) const; 640b57cec5SDimitry Andric bool hasLoopHazard(MachineInstr *MI) const; 650b57cec5SDimitry Andric bool hasRAWHazard(unsigned Reg, MachineInstr *MI) const; 660b57cec5SDimitry Andric bool FindMLxHazard(MachineInstr *MI); 670b57cec5SDimitry Andric void ExpandFPMLxInstruction(MachineBasicBlock &MBB, MachineInstr *MI, 680b57cec5SDimitry Andric unsigned MulOpc, unsigned AddSubOpc, 690b57cec5SDimitry Andric bool NegAcc, bool HasLane); 700b57cec5SDimitry Andric bool ExpandFPMLxInstructions(MachineBasicBlock &MBB); 710b57cec5SDimitry Andric }; 720b57cec5SDimitry Andric char MLxExpansion::ID = 0; 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric void MLxExpansion::clearStack() { 760b57cec5SDimitry Andric std::fill(LastMIs, LastMIs + 4, nullptr); 770b57cec5SDimitry Andric MIIdx = 0; 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric void MLxExpansion::pushStack(MachineInstr *MI) { 810b57cec5SDimitry Andric LastMIs[MIIdx] = MI; 820b57cec5SDimitry Andric if (++MIIdx == 4) 830b57cec5SDimitry Andric MIIdx = 0; 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric MachineInstr *MLxExpansion::getAccDefMI(MachineInstr *MI) const { 870b57cec5SDimitry Andric // Look past COPY and INSERT_SUBREG instructions to find the 880b57cec5SDimitry Andric // real definition MI. This is important for _sfp instructions. 89*8bcb0991SDimitry Andric Register Reg = MI->getOperand(1).getReg(); 90*8bcb0991SDimitry Andric if (Register::isPhysicalRegister(Reg)) 910b57cec5SDimitry Andric return nullptr; 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric MachineBasicBlock *MBB = MI->getParent(); 940b57cec5SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(Reg); 950b57cec5SDimitry Andric while (true) { 960b57cec5SDimitry Andric if (DefMI->getParent() != MBB) 970b57cec5SDimitry Andric break; 980b57cec5SDimitry Andric if (DefMI->isCopyLike()) { 990b57cec5SDimitry Andric Reg = DefMI->getOperand(1).getReg(); 100*8bcb0991SDimitry Andric if (Register::isVirtualRegister(Reg)) { 1010b57cec5SDimitry Andric DefMI = MRI->getVRegDef(Reg); 1020b57cec5SDimitry Andric continue; 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric } else if (DefMI->isInsertSubreg()) { 1050b57cec5SDimitry Andric Reg = DefMI->getOperand(2).getReg(); 106*8bcb0991SDimitry Andric if (Register::isVirtualRegister(Reg)) { 1070b57cec5SDimitry Andric DefMI = MRI->getVRegDef(Reg); 1080b57cec5SDimitry Andric continue; 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric break; 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric return DefMI; 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric unsigned MLxExpansion::getDefReg(MachineInstr *MI) const { 117*8bcb0991SDimitry Andric Register Reg = MI->getOperand(0).getReg(); 118*8bcb0991SDimitry Andric if (Register::isPhysicalRegister(Reg) || !MRI->hasOneNonDBGUse(Reg)) 1190b57cec5SDimitry Andric return Reg; 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric MachineBasicBlock *MBB = MI->getParent(); 1220b57cec5SDimitry Andric MachineInstr *UseMI = &*MRI->use_instr_nodbg_begin(Reg); 1230b57cec5SDimitry Andric if (UseMI->getParent() != MBB) 1240b57cec5SDimitry Andric return Reg; 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric while (UseMI->isCopy() || UseMI->isInsertSubreg()) { 1270b57cec5SDimitry Andric Reg = UseMI->getOperand(0).getReg(); 128*8bcb0991SDimitry Andric if (Register::isPhysicalRegister(Reg) || !MRI->hasOneNonDBGUse(Reg)) 1290b57cec5SDimitry Andric return Reg; 1300b57cec5SDimitry Andric UseMI = &*MRI->use_instr_nodbg_begin(Reg); 1310b57cec5SDimitry Andric if (UseMI->getParent() != MBB) 1320b57cec5SDimitry Andric return Reg; 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric return Reg; 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric /// hasLoopHazard - Check whether an MLx instruction is chained to itself across 1390b57cec5SDimitry Andric /// a single-MBB loop. 1400b57cec5SDimitry Andric bool MLxExpansion::hasLoopHazard(MachineInstr *MI) const { 141*8bcb0991SDimitry Andric Register Reg = MI->getOperand(1).getReg(); 142*8bcb0991SDimitry Andric if (Register::isPhysicalRegister(Reg)) 1430b57cec5SDimitry Andric return false; 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric MachineBasicBlock *MBB = MI->getParent(); 1460b57cec5SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(Reg); 1470b57cec5SDimitry Andric while (true) { 1480b57cec5SDimitry Andric outer_continue: 1490b57cec5SDimitry Andric if (DefMI->getParent() != MBB) 1500b57cec5SDimitry Andric break; 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric if (DefMI->isPHI()) { 1530b57cec5SDimitry Andric for (unsigned i = 1, e = DefMI->getNumOperands(); i < e; i += 2) { 1540b57cec5SDimitry Andric if (DefMI->getOperand(i + 1).getMBB() == MBB) { 155*8bcb0991SDimitry Andric Register SrcReg = DefMI->getOperand(i).getReg(); 156*8bcb0991SDimitry Andric if (Register::isVirtualRegister(SrcReg)) { 1570b57cec5SDimitry Andric DefMI = MRI->getVRegDef(SrcReg); 1580b57cec5SDimitry Andric goto outer_continue; 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric } else if (DefMI->isCopyLike()) { 1630b57cec5SDimitry Andric Reg = DefMI->getOperand(1).getReg(); 164*8bcb0991SDimitry Andric if (Register::isVirtualRegister(Reg)) { 1650b57cec5SDimitry Andric DefMI = MRI->getVRegDef(Reg); 1660b57cec5SDimitry Andric continue; 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric } else if (DefMI->isInsertSubreg()) { 1690b57cec5SDimitry Andric Reg = DefMI->getOperand(2).getReg(); 170*8bcb0991SDimitry Andric if (Register::isVirtualRegister(Reg)) { 1710b57cec5SDimitry Andric DefMI = MRI->getVRegDef(Reg); 1720b57cec5SDimitry Andric continue; 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric break; 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric return DefMI == MI; 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric bool MLxExpansion::hasRAWHazard(unsigned Reg, MachineInstr *MI) const { 1830b57cec5SDimitry Andric // FIXME: Detect integer instructions properly. 1840b57cec5SDimitry Andric const MCInstrDesc &MCID = MI->getDesc(); 1850b57cec5SDimitry Andric unsigned Domain = MCID.TSFlags & ARMII::DomainMask; 1860b57cec5SDimitry Andric if (MI->mayStore()) 1870b57cec5SDimitry Andric return false; 1880b57cec5SDimitry Andric unsigned Opcode = MCID.getOpcode(); 1890b57cec5SDimitry Andric if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD) 1900b57cec5SDimitry Andric return false; 1910b57cec5SDimitry Andric if ((Domain & ARMII::DomainVFP) || (Domain & ARMII::DomainNEON)) 1920b57cec5SDimitry Andric return MI->readsRegister(Reg, TRI); 1930b57cec5SDimitry Andric return false; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric static bool isFpMulInstruction(unsigned Opcode) { 1970b57cec5SDimitry Andric switch (Opcode) { 1980b57cec5SDimitry Andric case ARM::VMULS: 1990b57cec5SDimitry Andric case ARM::VMULfd: 2000b57cec5SDimitry Andric case ARM::VMULfq: 2010b57cec5SDimitry Andric case ARM::VMULD: 2020b57cec5SDimitry Andric case ARM::VMULslfd: 2030b57cec5SDimitry Andric case ARM::VMULslfq: 2040b57cec5SDimitry Andric return true; 2050b57cec5SDimitry Andric default: 2060b57cec5SDimitry Andric return false; 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric bool MLxExpansion::FindMLxHazard(MachineInstr *MI) { 2110b57cec5SDimitry Andric if (NumExpand >= ExpandLimit) 2120b57cec5SDimitry Andric return false; 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric if (ForceExapnd) 2150b57cec5SDimitry Andric return true; 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric MachineInstr *DefMI = getAccDefMI(MI); 2180b57cec5SDimitry Andric if (TII->isFpMLxInstruction(DefMI->getOpcode())) { 2190b57cec5SDimitry Andric // r0 = vmla 2200b57cec5SDimitry Andric // r3 = vmla r0, r1, r2 2210b57cec5SDimitry Andric // takes 16 - 17 cycles 2220b57cec5SDimitry Andric // 2230b57cec5SDimitry Andric // r0 = vmla 2240b57cec5SDimitry Andric // r4 = vmul r1, r2 2250b57cec5SDimitry Andric // r3 = vadd r0, r4 2260b57cec5SDimitry Andric // takes about 14 - 15 cycles even with vmul stalling for 4 cycles. 2270b57cec5SDimitry Andric IgnoreStall.insert(DefMI); 2280b57cec5SDimitry Andric return true; 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric // On Swift, we mostly care about hazards from multiplication instructions 2320b57cec5SDimitry Andric // writing the accumulator and the pipelining of loop iterations by out-of- 2330b57cec5SDimitry Andric // order execution. 2340b57cec5SDimitry Andric if (isSwift) 2350b57cec5SDimitry Andric return isFpMulInstruction(DefMI->getOpcode()) || hasLoopHazard(MI); 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric if (IgnoreStall.count(MI)) 2380b57cec5SDimitry Andric return false; 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric // If a VMLA.F is followed by an VADD.F or VMUL.F with no RAW hazard, the 2410b57cec5SDimitry Andric // VADD.F or VMUL.F will stall 4 cycles before issue. The 4 cycle stall 2420b57cec5SDimitry Andric // preserves the in-order retirement of the instructions. 2430b57cec5SDimitry Andric // Look at the next few instructions, if *most* of them can cause hazards, 2440b57cec5SDimitry Andric // then the scheduler can't *fix* this, we'd better break up the VMLA. 2450b57cec5SDimitry Andric unsigned Limit1 = isLikeA9 ? 1 : 4; 2460b57cec5SDimitry Andric unsigned Limit2 = isLikeA9 ? 1 : 4; 2470b57cec5SDimitry Andric for (unsigned i = 1; i <= 4; ++i) { 2480b57cec5SDimitry Andric int Idx = ((int)MIIdx - i + 4) % 4; 2490b57cec5SDimitry Andric MachineInstr *NextMI = LastMIs[Idx]; 2500b57cec5SDimitry Andric if (!NextMI) 2510b57cec5SDimitry Andric continue; 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric if (TII->canCauseFpMLxStall(NextMI->getOpcode())) { 2540b57cec5SDimitry Andric if (i <= Limit1) 2550b57cec5SDimitry Andric return true; 2560b57cec5SDimitry Andric } 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric // Look for VMLx RAW hazard. 2590b57cec5SDimitry Andric if (i <= Limit2 && hasRAWHazard(getDefReg(MI), NextMI)) 2600b57cec5SDimitry Andric return true; 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric return false; 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric /// ExpandFPMLxInstructions - Expand a MLA / MLS instruction into a pair 2670b57cec5SDimitry Andric /// of MUL + ADD / SUB instructions. 2680b57cec5SDimitry Andric void 2690b57cec5SDimitry Andric MLxExpansion::ExpandFPMLxInstruction(MachineBasicBlock &MBB, MachineInstr *MI, 2700b57cec5SDimitry Andric unsigned MulOpc, unsigned AddSubOpc, 2710b57cec5SDimitry Andric bool NegAcc, bool HasLane) { 272*8bcb0991SDimitry Andric Register DstReg = MI->getOperand(0).getReg(); 2730b57cec5SDimitry Andric bool DstDead = MI->getOperand(0).isDead(); 274*8bcb0991SDimitry Andric Register AccReg = MI->getOperand(1).getReg(); 275*8bcb0991SDimitry Andric Register Src1Reg = MI->getOperand(2).getReg(); 276*8bcb0991SDimitry Andric Register Src2Reg = MI->getOperand(3).getReg(); 2770b57cec5SDimitry Andric bool Src1Kill = MI->getOperand(2).isKill(); 2780b57cec5SDimitry Andric bool Src2Kill = MI->getOperand(3).isKill(); 2790b57cec5SDimitry Andric unsigned LaneImm = HasLane ? MI->getOperand(4).getImm() : 0; 2800b57cec5SDimitry Andric unsigned NextOp = HasLane ? 5 : 4; 2810b57cec5SDimitry Andric ARMCC::CondCodes Pred = (ARMCC::CondCodes)MI->getOperand(NextOp).getImm(); 282*8bcb0991SDimitry Andric Register PredReg = MI->getOperand(++NextOp).getReg(); 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric const MCInstrDesc &MCID1 = TII->get(MulOpc); 2850b57cec5SDimitry Andric const MCInstrDesc &MCID2 = TII->get(AddSubOpc); 2860b57cec5SDimitry Andric const MachineFunction &MF = *MI->getParent()->getParent(); 287*8bcb0991SDimitry Andric Register TmpReg = 288*8bcb0991SDimitry Andric MRI->createVirtualRegister(TII->getRegClass(MCID1, 0, TRI, MF)); 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MI, MI->getDebugLoc(), MCID1, TmpReg) 2910b57cec5SDimitry Andric .addReg(Src1Reg, getKillRegState(Src1Kill)) 2920b57cec5SDimitry Andric .addReg(Src2Reg, getKillRegState(Src2Kill)); 2930b57cec5SDimitry Andric if (HasLane) 2940b57cec5SDimitry Andric MIB.addImm(LaneImm); 2950b57cec5SDimitry Andric MIB.addImm(Pred).addReg(PredReg); 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric MIB = BuildMI(MBB, MI, MI->getDebugLoc(), MCID2) 2980b57cec5SDimitry Andric .addReg(DstReg, getDefRegState(true) | getDeadRegState(DstDead)); 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric if (NegAcc) { 3010b57cec5SDimitry Andric bool AccKill = MRI->hasOneNonDBGUse(AccReg); 3020b57cec5SDimitry Andric MIB.addReg(TmpReg, getKillRegState(true)) 3030b57cec5SDimitry Andric .addReg(AccReg, getKillRegState(AccKill)); 3040b57cec5SDimitry Andric } else { 3050b57cec5SDimitry Andric MIB.addReg(AccReg).addReg(TmpReg, getKillRegState(true)); 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric MIB.addImm(Pred).addReg(PredReg); 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric LLVM_DEBUG({ 3100b57cec5SDimitry Andric dbgs() << "Expanding: " << *MI; 3110b57cec5SDimitry Andric dbgs() << " to:\n"; 3120b57cec5SDimitry Andric MachineBasicBlock::iterator MII = MI; 3130b57cec5SDimitry Andric MII = std::prev(MII); 3140b57cec5SDimitry Andric MachineInstr &MI2 = *MII; 3150b57cec5SDimitry Andric MII = std::prev(MII); 3160b57cec5SDimitry Andric MachineInstr &MI1 = *MII; 3170b57cec5SDimitry Andric dbgs() << " " << MI1; 3180b57cec5SDimitry Andric dbgs() << " " << MI2; 3190b57cec5SDimitry Andric }); 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric MI->eraseFromParent(); 3220b57cec5SDimitry Andric ++NumExpand; 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric bool MLxExpansion::ExpandFPMLxInstructions(MachineBasicBlock &MBB) { 3260b57cec5SDimitry Andric bool Changed = false; 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric clearStack(); 3290b57cec5SDimitry Andric IgnoreStall.clear(); 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric unsigned Skip = 0; 3320b57cec5SDimitry Andric MachineBasicBlock::reverse_iterator MII = MBB.rbegin(), E = MBB.rend(); 3330b57cec5SDimitry Andric while (MII != E) { 3340b57cec5SDimitry Andric MachineInstr *MI = &*MII++; 3350b57cec5SDimitry Andric 3360b57cec5SDimitry Andric if (MI->isPosition() || MI->isImplicitDef() || MI->isCopy()) 3370b57cec5SDimitry Andric continue; 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric const MCInstrDesc &MCID = MI->getDesc(); 3400b57cec5SDimitry Andric if (MI->isBarrier()) { 3410b57cec5SDimitry Andric clearStack(); 3420b57cec5SDimitry Andric Skip = 0; 3430b57cec5SDimitry Andric continue; 3440b57cec5SDimitry Andric } 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric unsigned Domain = MCID.TSFlags & ARMII::DomainMask; 3470b57cec5SDimitry Andric if (Domain == ARMII::DomainGeneral) { 3480b57cec5SDimitry Andric if (++Skip == 2) 3490b57cec5SDimitry Andric // Assume dual issues of non-VFP / NEON instructions. 3500b57cec5SDimitry Andric pushStack(nullptr); 3510b57cec5SDimitry Andric } else { 3520b57cec5SDimitry Andric Skip = 0; 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric unsigned MulOpc, AddSubOpc; 3550b57cec5SDimitry Andric bool NegAcc, HasLane; 3560b57cec5SDimitry Andric if (!TII->isFpMLxInstruction(MCID.getOpcode(), 3570b57cec5SDimitry Andric MulOpc, AddSubOpc, NegAcc, HasLane) || 3580b57cec5SDimitry Andric !FindMLxHazard(MI)) 3590b57cec5SDimitry Andric pushStack(MI); 3600b57cec5SDimitry Andric else { 3610b57cec5SDimitry Andric ExpandFPMLxInstruction(MBB, MI, MulOpc, AddSubOpc, NegAcc, HasLane); 3620b57cec5SDimitry Andric Changed = true; 3630b57cec5SDimitry Andric } 3640b57cec5SDimitry Andric } 3650b57cec5SDimitry Andric } 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric return Changed; 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric bool MLxExpansion::runOnMachineFunction(MachineFunction &Fn) { 3710b57cec5SDimitry Andric if (skipFunction(Fn.getFunction())) 3720b57cec5SDimitry Andric return false; 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric TII = static_cast<const ARMBaseInstrInfo *>(Fn.getSubtarget().getInstrInfo()); 3750b57cec5SDimitry Andric TRI = Fn.getSubtarget().getRegisterInfo(); 3760b57cec5SDimitry Andric MRI = &Fn.getRegInfo(); 3770b57cec5SDimitry Andric const ARMSubtarget *STI = &Fn.getSubtarget<ARMSubtarget>(); 3780b57cec5SDimitry Andric if (!STI->expandMLx()) 3790b57cec5SDimitry Andric return false; 3800b57cec5SDimitry Andric isLikeA9 = STI->isLikeA9() || STI->isSwift(); 3810b57cec5SDimitry Andric isSwift = STI->isSwift(); 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric bool Modified = false; 3840b57cec5SDimitry Andric for (MachineBasicBlock &MBB : Fn) 3850b57cec5SDimitry Andric Modified |= ExpandFPMLxInstructions(MBB); 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric return Modified; 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric FunctionPass *llvm::createMLxExpansionPass() { 3910b57cec5SDimitry Andric return new MLxExpansion(); 3920b57cec5SDimitry Andric } 393