LLVM 24.0.0git
AArch64A57FPLoadBalancing.cpp
Go to the documentation of this file.
1//===-- AArch64A57FPLoadBalancing.cpp - Balance FP ops statically on A57---===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8// For best-case performance on Cortex-A57, we should try to use a balanced
9// mix of odd and even D-registers when performing a critical sequence of
10// independent, non-quadword FP/ASIMD floating-point multiply or
11// multiply-accumulate operations.
12//
13// This pass attempts to detect situations where the register allocation may
14// adversely affect this load balancing and to change the registers used so as
15// to better utilize the CPU.
16//
17// Ideally we'd just take each multiply or multiply-accumulate in turn and
18// allocate it alternating even or odd registers. However, multiply-accumulates
19// are most efficiently performed in the same functional unit as their
20// accumulation operand. Therefore this pass tries to find maximal sequences
21// ("Chains") of multiply-accumulates linked via their accumulation operand,
22// and assign them all the same "color" (oddness/evenness).
23//
24// This optimization affects S-register and D-register floating point
25// multiplies and FMADD/FMAs, as well as vector (floating point only) muls and
26// FMADD/FMA. Q register instructions (and 128-bit vector instructions) are
27// not affected.
28//===----------------------------------------------------------------------===//
29
30#include "AArch64.h"
31#include "AArch64InstrInfo.h"
32#include "AArch64Subtarget.h"
43#include "llvm/Support/Debug.h"
45using namespace llvm;
46
47#define DEBUG_TYPE "aarch64-a57-fp-load-balancing"
48
49// Enforce the algorithm to use the scavenged register even when the original
50// destination register is the correct color. Used for testing.
51static cl::opt<bool>
52TransformAll("aarch64-a57-fp-load-balancing-force-all",
53 cl::desc("Always modify dest registers regardless of color"),
54 cl::init(false), cl::Hidden);
55
56// Never use the balance information obtained from chains - return a specific
57// color always. Used for testing.
59OverrideBalance("aarch64-a57-fp-load-balancing-override",
60 cl::desc("Ignore balance information, always return "
61 "(1: Even, 2: Odd)."),
63
64//===----------------------------------------------------------------------===//
65// Helper functions
66
67// Is the instruction a type of multiply on 64-bit (or 32-bit) FPRs?
68static bool isMul(MachineInstr *MI) {
69 switch (MI->getOpcode()) {
70 case AArch64::FMULSrr:
71 case AArch64::FNMULSrr:
72 case AArch64::FMULDrr:
73 case AArch64::FNMULDrr:
74 return true;
75 default:
76 return false;
77 }
78}
79
80// Is the instruction a type of FP multiply-accumulate on 64-bit (or 32-bit) FPRs?
81static bool isMla(MachineInstr *MI) {
82 switch (MI->getOpcode()) {
83 case AArch64::FMSUBSrrr:
84 case AArch64::FMADDSrrr:
85 case AArch64::FNMSUBSrrr:
86 case AArch64::FNMADDSrrr:
87 case AArch64::FMSUBDrrr:
88 case AArch64::FMADDDrrr:
89 case AArch64::FNMSUBDrrr:
90 case AArch64::FNMADDDrrr:
91 return true;
92 default:
93 return false;
94 }
95}
96
97//===----------------------------------------------------------------------===//
98
99namespace {
100/// A "color", which is either even or odd. Yes, these aren't really colors
101/// but the algorithm is conceptually doing two-color graph coloring.
102enum class Color { Even, Odd };
103#ifndef NDEBUG
104static const char *ColorNames[2] = { "Even", "Odd" };
105#endif
106
107class Chain;
108
109class AArch64A57FPLoadBalancingImpl {
110public:
111 explicit AArch64A57FPLoadBalancingImpl(RegisterClassInfo *RCI) : RCI(RCI) {}
112
113 bool run(MachineFunction &MF);
114
115private:
116 MachineRegisterInfo *MRI;
117 const TargetRegisterInfo *TRI;
118 RegisterClassInfo *RCI = nullptr;
119
120 bool runOnBasicBlock(MachineBasicBlock &MBB);
121 bool colorChainSet(std::vector<Chain *> GV, MachineBasicBlock &MBB,
122 int &Balance);
123 bool colorChain(Chain *G, Color C, MachineBasicBlock &MBB);
124 int scavengeRegister(Chain *G, Color C, MachineBasicBlock &MBB);
125 void scanInstruction(MachineInstr *MI, unsigned Idx,
126 std::map<unsigned, Chain *> &Active,
127 std::vector<std::unique_ptr<Chain>> &AllChains);
128 void maybeKillChain(MachineOperand &MO, unsigned Idx,
129 std::map<unsigned, Chain *> &RegChains);
130 Color getColor(unsigned Register);
131 Chain *getAndEraseNext(Color PreferredColor, std::vector<Chain *> &L);
132};
133
134class AArch64A57FPLoadBalancingLegacy : public MachineFunctionPass {
135public:
136 static char ID;
137 explicit AArch64A57FPLoadBalancingLegacy() : MachineFunctionPass(ID) {}
138
139 bool runOnMachineFunction(MachineFunction &MF) override;
140
141 MachineFunctionProperties getRequiredProperties() const override {
142 return MachineFunctionProperties().setNoVRegs();
143 }
144
145 StringRef getPassName() const override {
146 return "A57 FP Anti-dependency breaker";
147 }
148
149 void getAnalysisUsage(AnalysisUsage &AU) const override {
150 AU.setPreservesCFG();
151 AU.addRequired<MachineRegisterClassInfoWrapperPass>();
152 AU.addPreserved<MachineRegisterClassInfoWrapperPass>();
154 }
155};
156}
157
158char AArch64A57FPLoadBalancingLegacy::ID = 0;
159
160INITIALIZE_PASS_BEGIN(AArch64A57FPLoadBalancingLegacy, DEBUG_TYPE,
161 "AArch64 A57 FP Load-Balancing", false, false)
163INITIALIZE_PASS_END(AArch64A57FPLoadBalancingLegacy, DEBUG_TYPE,
164 "AArch64 A57 FP Load-Balancing", false, false)
165
166namespace {
167/// A Chain is a sequence of instructions that are linked together by
168/// an accumulation operand. For example:
169///
170/// fmul def d0, ?
171/// fmla def d1, ?, ?, killed d0
172/// fmla def d2, ?, ?, killed d1
173///
174/// There may be other instructions interleaved in the sequence that
175/// do not belong to the chain. These other instructions must not use
176/// the "chain" register at any point.
177///
178/// We currently only support chains where the "chain" operand is killed
179/// at each link in the chain for simplicity.
180/// A chain has three important instructions - Start, Last and Kill.
181/// * The start instruction is the first instruction in the chain.
182/// * Last is the final instruction in the chain.
183/// * Kill may or may not be defined. If defined, Kill is the instruction
184/// where the outgoing value of the Last instruction is killed.
185/// This information is important as if we know the outgoing value is
186/// killed with no intervening uses, we can safely change its register.
187///
188/// Without a kill instruction, we must assume the outgoing value escapes
189/// beyond our model and either must not change its register or must
190/// create a fixup FMOV to keep the old register value consistent.
191///
192class Chain {
193public:
194 /// The important (marker) instructions.
196 /// The index, from the start of the basic block, that each marker
197 /// appears. These are stored so we can do quick interval tests.
199 /// All instructions in the chain.
200 std::set<MachineInstr*> Insts;
201 /// True if KillInst cannot be modified. If this is true,
202 /// we cannot change LastInst's outgoing register.
203 /// This will be true for tied values and regmasks.
205 /// The "color" of LastInst. This will be the preferred chain color,
206 /// as changing intermediate nodes is easy but changing the last
207 /// instruction can be more tricky.
209
210 Chain(MachineInstr *MI, unsigned Idx, Color C)
211 : StartInst(MI), LastInst(MI), KillInst(nullptr),
212 StartInstIdx(Idx), LastInstIdx(Idx), KillInstIdx(0),
213 LastColor(C) {
214 Insts.insert(MI);
215 }
216
217 /// Add a new instruction into the chain. The instruction's dest operand
218 /// has the given color.
219 void add(MachineInstr *MI, unsigned Idx, Color C) {
220 LastInst = MI;
221 LastInstIdx = Idx;
222 LastColor = C;
224 "Chain: broken invariant. A Chain can only be killed after its last "
225 "def");
226
227 Insts.insert(MI);
228 }
229
230 /// Return true if MI is a member of the chain.
231 bool contains(MachineInstr &MI) { return Insts.count(&MI) > 0; }
232
233 /// Return the number of instructions in the chain.
234 unsigned size() const {
235 return Insts.size();
236 }
237
238 /// Inform the chain that its last active register (the dest register of
239 /// LastInst) is killed by MI with no intervening uses or defs.
240 void setKill(MachineInstr *MI, unsigned Idx, bool Immutable) {
241 KillInst = MI;
242 KillInstIdx = Idx;
243 KillIsImmutable = Immutable;
245 "Chain: broken invariant. A Chain can only be killed after its last "
246 "def");
247 }
248
249 /// Return the first instruction in the chain.
250 MachineInstr *getStart() const { return StartInst; }
251 /// Return the last instruction in the chain.
252 MachineInstr *getLast() const { return LastInst; }
253 /// Return the "kill" instruction (as set with setKill()) or NULL.
254 MachineInstr *getKill() const { return KillInst; }
255 /// Return an instruction that can be used as an iterator for the end
256 /// of the chain. This is the maximum of KillInst (if set) and LastInst.
261
262 /// Can the Kill instruction (assuming one exists) be modified?
263 bool isKillImmutable() const { return KillIsImmutable; }
264
265 /// Return the preferred color of this chain.
267 if (OverrideBalance != 0)
268 return OverrideBalance == 1 ? Color::Even : Color::Odd;
269 return LastColor;
270 }
271
272 /// Return true if this chain (StartInst..KillInst) overlaps with Other.
273 bool rangeOverlapsWith(const Chain &Other) const {
274 unsigned End = KillInst ? KillInstIdx : LastInstIdx;
275 unsigned OtherEnd = Other.KillInst ?
276 Other.KillInstIdx : Other.LastInstIdx;
277
278 return StartInstIdx <= OtherEnd && Other.StartInstIdx <= End;
279 }
280
281 /// Return true if this chain starts before Other.
282 bool startsBefore(const Chain *Other) const {
283 return StartInstIdx < Other->StartInstIdx;
284 }
285
286 /// Return true if the group will require a fixup MOV at the end.
287 bool requiresFixup() const {
288 return (getKill() && isKillImmutable()) || !getKill();
289 }
290
291 /// Return a simple string representation of the chain.
292 std::string str() const {
293 std::string S;
294 raw_string_ostream OS(S);
295
296 OS << "{";
297 StartInst->print(OS, /* SkipOpers= */true);
298 OS << " -> ";
299 LastInst->print(OS, /* SkipOpers= */true);
300 if (KillInst) {
301 OS << " (kill @ ";
302 KillInst->print(OS, /* SkipOpers= */true);
303 OS << ")";
304 }
305 OS << "}";
306
307 return OS.str();
308 }
309
310};
311
312} // end anonymous namespace
313
314//===----------------------------------------------------------------------===//
315
316bool AArch64A57FPLoadBalancingImpl::run(MachineFunction &MF) {
317 if (!MF.getSubtarget<AArch64Subtarget>().balanceFPOps())
318 return false;
319
320 bool Changed = false;
321 LLVM_DEBUG(dbgs() << "***** AArch64A57FPLoadBalancing *****\n");
322
323 MRI = &MF.getRegInfo();
325
326 for (auto &MBB : MF) {
328 }
329
330 return Changed;
331}
332
333bool AArch64A57FPLoadBalancingLegacy::runOnMachineFunction(
334 MachineFunction &MF) {
335 if (skipFunction(MF.getFunction()))
336 return false;
337 RegisterClassInfo *RCI =
338 &getAnalysis<MachineRegisterClassInfoWrapperPass>().getRCI();
339 return AArch64A57FPLoadBalancingImpl(RCI).run(MF);
340}
341
342PreservedAnalyses
346 if (AArch64A57FPLoadBalancingImpl(RCI).run(MF)) {
349 return PA;
350 }
351 return PreservedAnalyses::all();
352}
353
354bool AArch64A57FPLoadBalancingImpl::runOnBasicBlock(MachineBasicBlock &MBB) {
355 bool Changed = false;
356 LLVM_DEBUG(dbgs() << "Running on MBB: " << MBB
357 << " - scanning instructions...\n");
358
359 // First, scan the basic block producing a set of chains.
360
361 // The currently "active" chains - chains that can be added to and haven't
362 // been killed yet. This is keyed by register - all chains can only have one
363 // "link" register between each inst in the chain.
364 std::map<unsigned, Chain*> ActiveChains;
365 std::vector<std::unique_ptr<Chain>> AllChains;
366 unsigned Idx = 0;
367 for (auto &MI : MBB)
368 scanInstruction(&MI, Idx++, ActiveChains, AllChains);
369
370 LLVM_DEBUG(dbgs() << "Scan complete, " << AllChains.size()
371 << " chains created.\n");
372
373 // Group the chains into disjoint sets based on their liveness range. This is
374 // a poor-man's version of graph coloring. Ideally we'd create an interference
375 // graph and perform full-on graph coloring on that, but;
376 // (a) That's rather heavyweight for only two colors.
377 // (b) We expect multiple disjoint interference regions - in practice the live
378 // range of chains is quite small and they are clustered between loads
379 // and stores.
381 for (auto &I : AllChains)
382 EC.insert(I.get());
383
384 for (auto &I : AllChains)
385 for (auto &J : AllChains)
386 if (I != J && I->rangeOverlapsWith(*J))
387 EC.unionSets(I.get(), J.get());
388 LLVM_DEBUG(dbgs() << "Created " << EC.getNumClasses() << " disjoint sets.\n");
389
390 // Now we assume that every member of an equivalence class interferes
391 // with every other member of that class, and with no members of other classes.
392
393 // Convert the EquivalenceClasses to a simpler set of sets.
394 std::vector<std::vector<Chain*> > V;
395 for (const auto &E : EC) {
396 if (!E->isLeader())
397 continue;
398 std::vector<Chain *> Cs(EC.member_begin(*E), EC.member_end());
399 if (Cs.empty()) continue;
400 V.push_back(std::move(Cs));
401 }
402
403 // Now we have a set of sets, order them by start address so
404 // we can iterate over them sequentially.
405 llvm::sort(V,
406 [](const std::vector<Chain *> &A, const std::vector<Chain *> &B) {
407 return A.front()->startsBefore(B.front());
408 });
409
410 // As we only have two colors, we can track the global (BB-level) balance of
411 // odds versus evens. We aim to keep this near zero to keep both execution
412 // units fed.
413 // Positive means we're even-heavy, negative we're odd-heavy.
414 //
415 // FIXME: If chains have interdependencies, for example:
416 // mul r0, r1, r2
417 // mul r3, r0, r1
418 // We do not model this and may color each one differently, assuming we'll
419 // get ILP when we obviously can't. This hasn't been seen to be a problem
420 // in practice so far, so we simplify the algorithm by ignoring it.
421 int Parity = 0;
422
423 for (auto &I : V)
424 Changed |= colorChainSet(std::move(I), MBB, Parity);
425
426 return Changed;
427}
428
429Chain *AArch64A57FPLoadBalancingImpl::getAndEraseNext(Color PreferredColor,
430 std::vector<Chain *> &L) {
431 if (L.empty())
432 return nullptr;
433
434 // We try and get the best candidate from L to color next, given that our
435 // preferred color is "PreferredColor". L is ordered from larger to smaller
436 // chains. It is beneficial to color the large chains before the small chains,
437 // but if we can't find a chain of the maximum length with the preferred color,
438 // we fuzz the size and look for slightly smaller chains before giving up and
439 // returning a chain that must be recolored.
440
441 // FIXME: Does this need to be configurable?
442 const unsigned SizeFuzz = 1;
443 unsigned MinSize = L.front()->size() - SizeFuzz;
444 for (auto I = L.begin(), E = L.end(); I != E; ++I) {
445 if ((*I)->size() <= MinSize) {
446 // We've gone past the size limit. Return the previous item.
447 Chain *Ch = *--I;
448 L.erase(I);
449 return Ch;
450 }
451
452 if ((*I)->getPreferredColor() == PreferredColor) {
453 Chain *Ch = *I;
454 L.erase(I);
455 return Ch;
456 }
457 }
458
459 // Bailout case - just return the first item.
460 Chain *Ch = L.front();
461 L.erase(L.begin());
462 return Ch;
463}
464
465bool AArch64A57FPLoadBalancingImpl::colorChainSet(std::vector<Chain *> GV,
466 MachineBasicBlock &MBB,
467 int &Parity) {
468 bool Changed = false;
469 LLVM_DEBUG(dbgs() << "colorChainSet(): #sets=" << GV.size() << "\n");
470
471 // Sort by descending size order so that we allocate the most important
472 // sets first.
473 // Tie-break equivalent sizes by sorting chains requiring fixups before
474 // those without fixups. The logic here is that we should look at the
475 // chains that we cannot change before we look at those we can,
476 // so the parity counter is updated and we know what color we should
477 // change them to!
478 // Final tie-break with instruction order so pass output is stable (i.e. not
479 // dependent on malloc'd pointer values).
480 llvm::sort(GV, [](const Chain *G1, const Chain *G2) {
481 if (G1->size() != G2->size())
482 return G1->size() > G2->size();
483 if (G1->requiresFixup() != G2->requiresFixup())
484 return G1->requiresFixup() > G2->requiresFixup();
485 // Make sure startsBefore() produces a stable final order.
486 assert((G1 == G2 || (G1->startsBefore(G2) ^ G2->startsBefore(G1))) &&
487 "Starts before not total order!");
488 return G1->startsBefore(G2);
489 });
490
491 Color PreferredColor = Parity < 0 ? Color::Even : Color::Odd;
492 while (Chain *G = getAndEraseNext(PreferredColor, GV)) {
493 // Start off by assuming we'll color to our own preferred color.
494 Color C = PreferredColor;
495 if (Parity == 0)
496 // But if we really don't care, use the chain's preferred color.
497 C = G->getPreferredColor();
498
499 LLVM_DEBUG(dbgs() << " - Parity=" << Parity
500 << ", Color=" << ColorNames[(int)C] << "\n");
501
502 // If we'll need a fixup FMOV, don't bother. Testing has shown that this
503 // happens infrequently and when it does it has at least a 50% chance of
504 // slowing code down instead of speeding it up.
505 if (G->requiresFixup() && C != G->getPreferredColor()) {
506 C = G->getPreferredColor();
507 LLVM_DEBUG(dbgs() << " - " << G->str()
508 << " - not worthwhile changing; "
509 "color remains "
510 << ColorNames[(int)C] << "\n");
511 }
512
513 Changed |= colorChain(G, C, MBB);
514
515 Parity += (C == Color::Even) ? G->size() : -G->size();
516 PreferredColor = Parity < 0 ? Color::Even : Color::Odd;
517 }
518
519 return Changed;
520}
521
522int AArch64A57FPLoadBalancingImpl::scavengeRegister(Chain *G, Color C,
523 MachineBasicBlock &MBB) {
524 // Can we find an appropriate register that is available throughout the life
525 // of the chain? Simulate liveness backwards until the end of the chain.
526 LiveRegUnits Units(*TRI);
527 Units.addLiveOuts(MBB);
529 MachineBasicBlock::iterator ChainEnd = G->end();
530 while (I != ChainEnd) {
531 --I;
532 if (!I->isDebugInstr())
533 Units.stepBackward(*I);
534 }
535
536 // Check which register units are alive throughout the chain.
537 MachineBasicBlock::iterator ChainBegin = G->begin();
538 assert(ChainBegin != ChainEnd && "Chain should contain instructions");
539 do {
540 --I;
541 Units.accumulate(*I);
542 } while (I != ChainBegin);
543
544 // Make sure we allocate in-order, to get the cheapest registers first.
545 unsigned RegClassID = ChainBegin->getDesc().operands()[0].RegClass;
546 auto Ord = RCI->getOrder(TRI->getRegClass(RegClassID));
547 for (auto Reg : Ord) {
548 if (!Units.available(Reg))
549 continue;
550 if (C == getColor(Reg))
551 return Reg;
552 }
553
554 return -1;
555}
556
557bool AArch64A57FPLoadBalancingImpl::colorChain(Chain *G, Color C,
558 MachineBasicBlock &MBB) {
559 bool Changed = false;
560 LLVM_DEBUG(dbgs() << " - colorChain(" << G->str() << ", "
561 << ColorNames[(int)C] << ")\n");
562
563 // Try and obtain a free register of the right class. Without a register
564 // to play with we cannot continue.
565 int Reg = scavengeRegister(G, C, MBB);
566 if (Reg == -1) {
567 LLVM_DEBUG(dbgs() << "Scavenging (thus coloring) failed!\n");
568 return false;
569 }
570 LLVM_DEBUG(dbgs() << " - Scavenged register: " << printReg(Reg, TRI) << "\n");
571
572 std::map<unsigned, unsigned> Substs;
573 for (MachineInstr &I : *G) {
574 if (!G->contains(I) && (&I != G->getKill() || G->isKillImmutable()))
575 continue;
576
577 // I is a member of G, or I is a mutable instruction that kills G.
578
579 std::vector<unsigned> ToErase;
580 for (auto &U : I.operands()) {
581 if (U.isReg() && U.isUse() && Substs.find(U.getReg()) != Substs.end()) {
582 Register OrigReg = U.getReg();
583 U.setReg(Substs[OrigReg]);
584 if (U.isKill())
585 // Don't erase straight away, because there may be other operands
586 // that also reference this substitution!
587 ToErase.push_back(OrigReg);
588 } else if (U.isRegMask()) {
589 for (auto J : Substs) {
590 if (U.clobbersPhysReg(J.first))
591 ToErase.push_back(J.first);
592 }
593 }
594 }
595 // Now it's safe to remove the substs identified earlier.
596 for (auto J : ToErase)
597 Substs.erase(J);
598
599 // Only change the def if this isn't the last instruction.
600 if (&I != G->getKill()) {
601 MachineOperand &MO = I.getOperand(0);
602
603 bool Change = TransformAll || getColor(MO.getReg()) != C;
604 if (G->requiresFixup() && &I == G->getLast())
605 Change = false;
606
607 if (Change) {
608 Substs[MO.getReg()] = Reg;
609 MO.setReg(Reg);
610
611 Changed = true;
612 }
613 }
614 }
615 assert(Substs.size() == 0 && "No substitutions should be left active!");
616
617 if (G->getKill()) {
618 LLVM_DEBUG(dbgs() << " - Kill instruction seen.\n");
619 } else {
620 // We didn't have a kill instruction, but we didn't seem to need to change
621 // the destination register anyway.
622 LLVM_DEBUG(dbgs() << " - Destination register not changed.\n");
623 }
624 return Changed;
625}
626
627void AArch64A57FPLoadBalancingImpl::scanInstruction(
628 MachineInstr *MI, unsigned Idx, std::map<unsigned, Chain *> &ActiveChains,
629 std::vector<std::unique_ptr<Chain>> &AllChains) {
630 // Inspect "MI", updating ActiveChains and AllChains.
631
632 if (isMul(MI)) {
633
634 for (auto &I : MI->uses())
635 maybeKillChain(I, Idx, ActiveChains);
636 for (auto &I : MI->defs())
637 maybeKillChain(I, Idx, ActiveChains);
638
639 // Create a new chain. Multiplies don't require forwarding so can go on any
640 // unit.
641 Register DestReg = MI->getOperand(0).getReg();
642
643 LLVM_DEBUG(dbgs() << "New chain started for register "
644 << printReg(DestReg, TRI) << " at " << *MI);
645
646 auto G = std::make_unique<Chain>(MI, Idx, getColor(DestReg));
647 ActiveChains[DestReg] = G.get();
648 AllChains.push_back(std::move(G));
649
650 } else if (isMla(MI)) {
651
652 // It is beneficial to keep MLAs on the same functional unit as their
653 // accumulator operand.
654 Register DestReg = MI->getOperand(0).getReg();
655 Register AccumReg = MI->getOperand(3).getReg();
656
657 maybeKillChain(MI->getOperand(1), Idx, ActiveChains);
658 maybeKillChain(MI->getOperand(2), Idx, ActiveChains);
659 if (DestReg != AccumReg)
660 maybeKillChain(MI->getOperand(0), Idx, ActiveChains);
661
662 if (ActiveChains.find(AccumReg) != ActiveChains.end()) {
663 LLVM_DEBUG(dbgs() << "Chain found for accumulator register "
664 << printReg(AccumReg, TRI) << " in MI " << *MI);
665
666 // For simplicity we only chain together sequences of MULs/MLAs where the
667 // accumulator register is killed on each instruction. This means we don't
668 // need to track other uses of the registers we want to rewrite.
669 //
670 // FIXME: We could extend to handle the non-kill cases for more coverage.
671 if (MI->getOperand(3).isKill()) {
672 // Add to chain.
673 LLVM_DEBUG(dbgs() << "Instruction was successfully added to chain.\n");
674 ActiveChains[AccumReg]->add(MI, Idx, getColor(DestReg));
675 // Handle cases where the destination is not the same as the accumulator.
676 if (DestReg != AccumReg) {
677 ActiveChains[DestReg] = ActiveChains[AccumReg];
678 ActiveChains.erase(AccumReg);
679 }
680 return;
681 }
682
684 dbgs() << "Cannot add to chain because accumulator operand wasn't "
685 << "marked <kill>!\n");
686 maybeKillChain(MI->getOperand(3), Idx, ActiveChains);
687 }
688
689 LLVM_DEBUG(dbgs() << "Creating new chain for dest register "
690 << printReg(DestReg, TRI) << "\n");
691 auto G = std::make_unique<Chain>(MI, Idx, getColor(DestReg));
692 ActiveChains[DestReg] = G.get();
693 AllChains.push_back(std::move(G));
694
695 } else {
696
697 // Non-MUL or MLA instruction. Invalidate any chain in the uses or defs
698 // lists.
699 for (auto &I : MI->uses())
700 maybeKillChain(I, Idx, ActiveChains);
701 for (auto &I : MI->defs())
702 maybeKillChain(I, Idx, ActiveChains);
703
704 }
705}
706
707void AArch64A57FPLoadBalancingImpl::maybeKillChain(
708 MachineOperand &MO, unsigned Idx,
709 std::map<unsigned, Chain *> &ActiveChains) {
710 // Given an operand and the set of active chains (keyed by register),
711 // determine if a chain should be ended and remove from ActiveChains.
712 MachineInstr *MI = MO.getParent();
713
714 if (MO.isReg()) {
715
716 // If this is a KILL of a current chain, record it.
717 if (MO.isKill() && ActiveChains.find(MO.getReg()) != ActiveChains.end()) {
718 LLVM_DEBUG(dbgs() << "Kill seen for chain " << printReg(MO.getReg(), TRI)
719 << "\n");
720 ActiveChains[MO.getReg()]->setKill(MI, Idx, /*Immutable=*/MO.isTied());
721 }
722 ActiveChains.erase(MO.getReg());
723
724 } else if (MO.isRegMask()) {
725
726 for (auto I = ActiveChains.begin(), E = ActiveChains.end();
727 I != E;) {
728 if (MO.clobbersPhysReg(I->first)) {
729 LLVM_DEBUG(dbgs() << "Kill (regmask) seen for chain "
730 << printReg(I->first, TRI) << "\n");
731 I->second->setKill(MI, Idx, /*Immutable=*/true);
732 ActiveChains.erase(I++);
733 } else
734 ++I;
735 }
736
737 }
738}
739
740Color AArch64A57FPLoadBalancingImpl::getColor(unsigned Reg) {
741 if ((TRI->getEncodingValue(Reg) % 2) == 0)
742 return Color::Even;
743 else
744 return Color::Odd;
745}
746
747// Factory function used by AArch64TargetMachine to add the pass to the passmanager.
749 return new AArch64A57FPLoadBalancingLegacy();
750}
static bool isMul(MachineInstr *MI)
static cl::opt< unsigned > OverrideBalance("aarch64-a57-fp-load-balancing-override", cl::desc("Ignore balance information, always return " "(1: Even, 2: Odd)."), cl::init(0), cl::Hidden)
static cl::opt< bool > TransformAll("aarch64-a57-fp-load-balancing-force-all", cl::desc("Always modify dest registers regardless of color"), cl::init(false), cl::Hidden)
static bool isMla(MachineInstr *MI)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Generic implementation of equivalence classes through the use Tarjan's efficient union-find algorithm...
#define DEBUG_TYPE
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
static bool runOnBasicBlock(MachineBasicBlock *MBB, unsigned BasicBlockNum, VRegRenamer &Renamer)
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
This file declares the machine register scavenger class.
#define LLVM_DEBUG(...)
Definition Debug.h:119
MachineInstr * StartInst
The important (marker) instructions.
MachineBasicBlock::iterator begin() const
bool isKillImmutable() const
Can the Kill instruction (assuming one exists) be modified?
void add(MachineInstr *MI, unsigned Idx, Color C)
Add a new instruction into the chain.
bool contains(MachineInstr &MI)
Return true if MI is a member of the chain.
Color LastColor
The "color" of LastInst.
bool requiresFixup() const
Return true if the group will require a fixup MOV at the end.
MachineInstr * getLast() const
Return the last instruction in the chain.
bool KillIsImmutable
True if KillInst cannot be modified.
bool rangeOverlapsWith(const Chain &Other) const
Return true if this chain (StartInst..KillInst) overlaps with Other.
MachineInstr * getStart() const
Return the first instruction in the chain.
unsigned size() const
Return the number of instructions in the chain.
MachineBasicBlock::iterator end() const
Return an instruction that can be used as an iterator for the end of the chain.
void setKill(MachineInstr *MI, unsigned Idx, bool Immutable)
Inform the chain that its last active register (the dest register of LastInst) is killed by MI with n...
MachineInstr * getKill() const
Return the "kill" instruction (as set with setKill()) or NULL.
unsigned StartInstIdx
The index, from the start of the basic block, that each marker appears.
Color getPreferredColor()
Return the preferred color of this chain.
std::string str() const
Return a simple string representation of the chain.
std::set< MachineInstr * > Insts
All instructions in the chain.
Chain(MachineInstr *MI, unsigned Idx, Color C)
bool startsBefore(const Chain *Other) const
Return true if this chain starts before Other.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:275
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
This represents a collection of equivalence classes and supports three efficient operations: insert a...
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Representation of each machine instruction.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isRegMask() const
isRegMask - Tests if this is a MO_RegisterMask operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
Register getReg() const
getReg - Returns the register number.
static bool clobbersPhysReg(const uint32_t *RegMask, MCRegister PhysReg)
clobbersPhysReg - Returns true if this RegMask clobbers PhysReg.
const TargetRegisterInfo * getTargetRegisterInfo() const
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
ArrayRef< MCPhysReg > getOrder(const TargetRegisterClass *RC) const
getOrder - Returns the preferred allocation order for RC.
A raw_ostream that writes to an std::string.
std::string & str()
Returns the string's reference.
Changed
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
initializer< Ty > init(const Ty &Val)
DXILDebugInfoMap run(Module &M)
This is an optimization pass for GlobalISel generic memory operations.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
FunctionPass * createAArch64A57FPLoadBalancingLegacyPass()
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1636
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
@ Other
Any other memory.
Definition ModRef.h:68
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.