xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/ARM/MLxExpansionPass.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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;
MLxExpansion__anon6779f5040111::MLxExpansion410b57cec5SDimitry Andric     MLxExpansion() : MachineFunctionPass(ID) {}
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric     bool runOnMachineFunction(MachineFunction &Fn) override;
440b57cec5SDimitry Andric 
getPassName__anon6779f5040111::MLxExpansion450b57cec5SDimitry 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 
clearStack()750b57cec5SDimitry Andric void MLxExpansion::clearStack() {
760b57cec5SDimitry Andric   std::fill(LastMIs, LastMIs + 4, nullptr);
770b57cec5SDimitry Andric   MIIdx = 0;
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
pushStack(MachineInstr * MI)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 
getAccDefMI(MachineInstr * MI) const860b57cec5SDimitry 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.
898bcb0991SDimitry Andric   Register Reg = MI->getOperand(1).getReg();
90*bdd1243dSDimitry Andric   if (Reg.isPhysical())
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*bdd1243dSDimitry Andric       if (Reg.isVirtual()) {
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*bdd1243dSDimitry Andric       if (Reg.isVirtual()) {
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 
getDefReg(MachineInstr * MI) const1160b57cec5SDimitry Andric unsigned MLxExpansion::getDefReg(MachineInstr *MI) const {
1178bcb0991SDimitry Andric   Register Reg = MI->getOperand(0).getReg();
118*bdd1243dSDimitry Andric   if (Reg.isPhysical() || !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*bdd1243dSDimitry Andric     if (Reg.isPhysical() || !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.
hasLoopHazard(MachineInstr * MI) const1400b57cec5SDimitry Andric bool MLxExpansion::hasLoopHazard(MachineInstr *MI) const {
1418bcb0991SDimitry Andric   Register Reg = MI->getOperand(1).getReg();
142*bdd1243dSDimitry Andric   if (Reg.isPhysical())
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) {
1558bcb0991SDimitry Andric           Register SrcReg = DefMI->getOperand(i).getReg();
156*bdd1243dSDimitry Andric           if (SrcReg.isVirtual()) {
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*bdd1243dSDimitry Andric       if (Reg.isVirtual()) {
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*bdd1243dSDimitry Andric       if (Reg.isVirtual()) {
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 
hasRAWHazard(unsigned Reg,MachineInstr * MI) const1820b57cec5SDimitry 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 
isFpMulInstruction(unsigned Opcode)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 
FindMLxHazard(MachineInstr * MI)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
ExpandFPMLxInstruction(MachineBasicBlock & MBB,MachineInstr * MI,unsigned MulOpc,unsigned AddSubOpc,bool NegAcc,bool HasLane)2690b57cec5SDimitry Andric MLxExpansion::ExpandFPMLxInstruction(MachineBasicBlock &MBB, MachineInstr *MI,
2700b57cec5SDimitry Andric                                      unsigned MulOpc, unsigned AddSubOpc,
2710b57cec5SDimitry Andric                                      bool NegAcc, bool HasLane) {
2728bcb0991SDimitry Andric   Register DstReg = MI->getOperand(0).getReg();
2730b57cec5SDimitry Andric   bool DstDead = MI->getOperand(0).isDead();
2748bcb0991SDimitry Andric   Register AccReg = MI->getOperand(1).getReg();
2758bcb0991SDimitry Andric   Register Src1Reg = MI->getOperand(2).getReg();
2768bcb0991SDimitry 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();
2828bcb0991SDimitry 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();
2878bcb0991SDimitry Andric   Register TmpReg =
2888bcb0991SDimitry 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 
ExpandFPMLxInstructions(MachineBasicBlock & MBB)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 
runOnMachineFunction(MachineFunction & Fn)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 
createMLxExpansionPass()3900b57cec5SDimitry Andric FunctionPass *llvm::createMLxExpansionPass() {
3910b57cec5SDimitry Andric   return new MLxExpansion();
3920b57cec5SDimitry Andric }
393