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