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