1 //===-- AArch64A57FPLoadBalancing.cpp - Balance FP ops statically on A57---===// 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 // For best-case performance on Cortex-A57, we should try to use a balanced 10 // mix of odd and even D-registers when performing a critical sequence of 11 // independent, non-quadword FP/ASIMD floating-point multiply or 12 // multiply-accumulate operations. 13 // 14 // This pass attempts to detect situations where the register allocation may 15 // adversely affect this load balancing and to change the registers used so as 16 // to better utilize the CPU. 17 // 18 // Ideally we'd just take each multiply or multiply-accumulate in turn and 19 // allocate it alternating even or odd registers. However, multiply-accumulates 20 // are most efficiently performed in the same functional unit as their 21 // accumulation operand. Therefore this pass tries to find maximal sequences 22 // ("Chains") of multiply-accumulates linked via their accumulation operand, 23 // and assign them all the same "color" (oddness/evenness). 24 // 25 // This optimization affects S-register and D-register floating point 26 // multiplies and FMADD/FMAs, as well as vector (floating point only) muls and 27 // FMADD/FMA. Q register instructions (and 128-bit vector instructions) are 28 // not affected. 29 //===----------------------------------------------------------------------===// 30 31 #include "AArch64.h" 32 #include "AArch64InstrInfo.h" 33 #include "AArch64Subtarget.h" 34 #include "llvm/ADT/BitVector.h" 35 #include "llvm/ADT/EquivalenceClasses.h" 36 #include "llvm/CodeGen/MachineFunction.h" 37 #include "llvm/CodeGen/MachineFunctionPass.h" 38 #include "llvm/CodeGen/MachineInstr.h" 39 #include "llvm/CodeGen/MachineInstrBuilder.h" 40 #include "llvm/CodeGen/MachineRegisterInfo.h" 41 #include "llvm/CodeGen/RegisterScavenging.h" 42 #include "llvm/CodeGen/RegisterClassInfo.h" 43 #include "llvm/Support/CommandLine.h" 44 #include "llvm/Support/Debug.h" 45 #include "llvm/Support/raw_ostream.h" 46 #include <list> 47 using namespace llvm; 48 49 #define DEBUG_TYPE "aarch64-a57-fp-load-balancing" 50 51 // Enforce the algorithm to use the scavenged register even when the original 52 // destination register is the correct color. Used for testing. 53 static cl::opt<bool> 54 TransformAll("aarch64-a57-fp-load-balancing-force-all", 55 cl::desc("Always modify dest registers regardless of color"), 56 cl::init(false), cl::Hidden); 57 58 // Never use the balance information obtained from chains - return a specific 59 // color always. Used for testing. 60 static cl::opt<unsigned> 61 OverrideBalance("aarch64-a57-fp-load-balancing-override", 62 cl::desc("Ignore balance information, always return " 63 "(1: Even, 2: Odd)."), 64 cl::init(0), cl::Hidden); 65 66 //===----------------------------------------------------------------------===// 67 // Helper functions 68 69 // Is the instruction a type of multiply on 64-bit (or 32-bit) FPRs? 70 static bool isMul(MachineInstr *MI) { 71 switch (MI->getOpcode()) { 72 case AArch64::FMULSrr: 73 case AArch64::FNMULSrr: 74 case AArch64::FMULDrr: 75 case AArch64::FNMULDrr: 76 77 case AArch64::FMULv2f32: 78 return true; 79 default: 80 return false; 81 } 82 } 83 84 // Is the instruction a type of FP multiply-accumulate on 64-bit (or 32-bit) FPRs? 85 static bool isMla(MachineInstr *MI) { 86 switch (MI->getOpcode()) { 87 case AArch64::FMSUBSrrr: 88 case AArch64::FMADDSrrr: 89 case AArch64::FNMSUBSrrr: 90 case AArch64::FNMADDSrrr: 91 case AArch64::FMSUBDrrr: 92 case AArch64::FMADDDrrr: 93 case AArch64::FNMSUBDrrr: 94 case AArch64::FNMADDDrrr: 95 96 case AArch64::FMLAv2f32: 97 case AArch64::FMLSv2f32: 98 return true; 99 default: 100 return false; 101 } 102 } 103 104 //===----------------------------------------------------------------------===// 105 106 namespace { 107 /// A "color", which is either even or odd. Yes, these aren't really colors 108 /// but the algorithm is conceptually doing two-color graph coloring. 109 enum class Color { Even, Odd }; 110 #ifndef NDEBUG 111 static const char *ColorNames[2] = { "Even", "Odd" }; 112 #endif 113 114 class Chain; 115 116 class AArch64A57FPLoadBalancing : public MachineFunctionPass { 117 const AArch64InstrInfo *TII; 118 MachineRegisterInfo *MRI; 119 const TargetRegisterInfo *TRI; 120 RegisterClassInfo RCI; 121 122 public: 123 static char ID; 124 explicit AArch64A57FPLoadBalancing() : MachineFunctionPass(ID) {} 125 126 bool runOnMachineFunction(MachineFunction &F) override; 127 128 const char *getPassName() const override { 129 return "A57 FP Anti-dependency breaker"; 130 } 131 132 void getAnalysisUsage(AnalysisUsage &AU) const override { 133 AU.setPreservesCFG(); 134 MachineFunctionPass::getAnalysisUsage(AU); 135 } 136 137 private: 138 bool runOnBasicBlock(MachineBasicBlock &MBB); 139 bool colorChainSet(std::vector<Chain*> GV, MachineBasicBlock &MBB, 140 int &Balance); 141 bool colorChain(Chain *G, Color C, MachineBasicBlock &MBB); 142 int scavengeRegister(Chain *G, Color C, MachineBasicBlock &MBB); 143 void scanInstruction(MachineInstr *MI, unsigned Idx, 144 std::map<unsigned, Chain*> &Chains, 145 std::set<Chain*> &ChainSet); 146 void maybeKillChain(MachineOperand &MO, unsigned Idx, 147 std::map<unsigned, Chain*> &RegChains); 148 Color getColor(unsigned Register); 149 Chain *getAndEraseNext(Color PreferredColor, std::vector<Chain*> &L); 150 }; 151 char AArch64A57FPLoadBalancing::ID = 0; 152 153 /// A Chain is a sequence of instructions that are linked together by 154 /// an accumulation operand. For example: 155 /// 156 /// fmul d0<def>, ? 157 /// fmla d1<def>, ?, ?, d0<kill> 158 /// fmla d2<def>, ?, ?, d1<kill> 159 /// 160 /// There may be other instructions interleaved in the sequence that 161 /// do not belong to the chain. These other instructions must not use 162 /// the "chain" register at any point. 163 /// 164 /// We currently only support chains where the "chain" operand is killed 165 /// at each link in the chain for simplicity. 166 /// A chain has three important instructions - Start, Last and Kill. 167 /// * The start instruction is the first instruction in the chain. 168 /// * Last is the final instruction in the chain. 169 /// * Kill may or may not be defined. If defined, Kill is the instruction 170 /// where the outgoing value of the Last instruction is killed. 171 /// This information is important as if we know the outgoing value is 172 /// killed with no intervening uses, we can safely change its register. 173 /// 174 /// Without a kill instruction, we must assume the outgoing value escapes 175 /// beyond our model and either must not change its register or must 176 /// create a fixup FMOV to keep the old register value consistent. 177 /// 178 class Chain { 179 public: 180 /// The important (marker) instructions. 181 MachineInstr *StartInst, *LastInst, *KillInst; 182 /// The index, from the start of the basic block, that each marker 183 /// appears. These are stored so we can do quick interval tests. 184 unsigned StartInstIdx, LastInstIdx, KillInstIdx; 185 /// All instructions in the chain. 186 std::set<MachineInstr*> Insts; 187 /// True if KillInst cannot be modified. If this is true, 188 /// we cannot change LastInst's outgoing register. 189 /// This will be true for tied values and regmasks. 190 bool KillIsImmutable; 191 /// The "color" of LastInst. This will be the preferred chain color, 192 /// as changing intermediate nodes is easy but changing the last 193 /// instruction can be more tricky. 194 Color LastColor; 195 196 Chain(MachineInstr *MI, unsigned Idx, Color C) : 197 StartInst(MI), LastInst(MI), KillInst(NULL), 198 StartInstIdx(Idx), LastInstIdx(Idx), KillInstIdx(0), 199 LastColor(C) { 200 Insts.insert(MI); 201 } 202 203 /// Add a new instruction into the chain. The instruction's dest operand 204 /// has the given color. 205 void add(MachineInstr *MI, unsigned Idx, Color C) { 206 LastInst = MI; 207 LastInstIdx = Idx; 208 LastColor = C; 209 210 Insts.insert(MI); 211 } 212 213 /// Return true if MI is a member of the chain. 214 bool contains(MachineInstr *MI) { return Insts.count(MI) > 0; } 215 216 /// Return the number of instructions in the chain. 217 unsigned size() const { 218 return Insts.size(); 219 } 220 221 /// Inform the chain that its last active register (the dest register of 222 /// LastInst) is killed by MI with no intervening uses or defs. 223 void setKill(MachineInstr *MI, unsigned Idx, bool Immutable) { 224 KillInst = MI; 225 KillInstIdx = Idx; 226 KillIsImmutable = Immutable; 227 } 228 229 /// Return the first instruction in the chain. 230 MachineInstr *getStart() const { return StartInst; } 231 /// Return the last instruction in the chain. 232 MachineInstr *getLast() const { return LastInst; } 233 /// Return the "kill" instruction (as set with setKill()) or NULL. 234 MachineInstr *getKill() const { return KillInst; } 235 /// Return an instruction that can be used as an iterator for the end 236 /// of the chain. This is the maximum of KillInst (if set) and LastInst. 237 MachineInstr *getEnd() const { 238 return ++MachineBasicBlock::iterator(KillInst ? KillInst : LastInst); 239 } 240 241 /// Can the Kill instruction (assuming one exists) be modified? 242 bool isKillImmutable() const { return KillIsImmutable; } 243 244 /// Return the preferred color of this chain. 245 Color getPreferredColor() { 246 if (OverrideBalance != 0) 247 return OverrideBalance == 1 ? Color::Even : Color::Odd; 248 return LastColor; 249 } 250 251 /// Return true if this chain (StartInst..KillInst) overlaps with Other. 252 bool rangeOverlapsWith(Chain *Other) { 253 unsigned End = KillInst ? KillInstIdx : LastInstIdx; 254 unsigned OtherEnd = Other->KillInst ? 255 Other->KillInstIdx : Other->LastInstIdx; 256 257 return StartInstIdx <= OtherEnd && Other->StartInstIdx <= End; 258 } 259 260 /// Return true if this chain starts before Other. 261 bool startsBefore(Chain *Other) { 262 return StartInstIdx < Other->StartInstIdx; 263 } 264 265 /// Return true if the group will require a fixup MOV at the end. 266 bool requiresFixup() const { 267 return (getKill() && isKillImmutable()) || !getKill(); 268 } 269 270 /// Return a simple string representation of the chain. 271 std::string str() const { 272 std::string S; 273 raw_string_ostream OS(S); 274 275 OS << "{"; 276 StartInst->print(OS, NULL, true); 277 OS << " -> "; 278 LastInst->print(OS, NULL, true); 279 if (KillInst) { 280 OS << " (kill @ "; 281 KillInst->print(OS, NULL, true); 282 OS << ")"; 283 } 284 OS << "}"; 285 286 return OS.str(); 287 } 288 289 }; 290 291 } // end anonymous namespace 292 293 //===----------------------------------------------------------------------===// 294 295 bool AArch64A57FPLoadBalancing::runOnMachineFunction(MachineFunction &F) { 296 bool Changed = false; 297 DEBUG(dbgs() << "***** AArch64A57FPLoadBalancing *****\n"); 298 299 const TargetMachine &TM = F.getTarget(); 300 MRI = &F.getRegInfo(); 301 TRI = F.getRegInfo().getTargetRegisterInfo(); 302 TII = TM.getSubtarget<AArch64Subtarget>().getInstrInfo(); 303 RCI.runOnMachineFunction(F); 304 305 for (auto &MBB : F) { 306 Changed |= runOnBasicBlock(MBB); 307 } 308 309 return Changed; 310 } 311 312 bool AArch64A57FPLoadBalancing::runOnBasicBlock(MachineBasicBlock &MBB) { 313 bool Changed = false; 314 DEBUG(dbgs() << "Running on MBB: " << MBB << " - scanning instructions...\n"); 315 316 // First, scan the basic block producing a set of chains. 317 318 // The currently "active" chains - chains that can be added to and haven't 319 // been killed yet. This is keyed by register - all chains can only have one 320 // "link" register between each inst in the chain. 321 std::map<unsigned, Chain*> ActiveChains; 322 std::set<Chain*> AllChains; 323 unsigned Idx = 0; 324 for (auto &MI : MBB) 325 scanInstruction(&MI, Idx++, ActiveChains, AllChains); 326 327 DEBUG(dbgs() << "Scan complete, "<< AllChains.size() << " chains created.\n"); 328 329 // Group the chains into disjoint sets based on their liveness range. This is 330 // a poor-man's version of graph coloring. Ideally we'd create an interference 331 // graph and perform full-on graph coloring on that, but; 332 // (a) That's rather heavyweight for only two colors. 333 // (b) We expect multiple disjoint interference regions - in practice the live 334 // range of chains is quite small and they are clustered between loads 335 // and stores. 336 EquivalenceClasses<Chain*> EC; 337 for (auto *I : AllChains) 338 EC.insert(I); 339 340 for (auto *I : AllChains) { 341 for (auto *J : AllChains) { 342 if (I != J && I->rangeOverlapsWith(J)) 343 EC.unionSets(I, J); 344 } 345 } 346 DEBUG(dbgs() << "Created " << EC.getNumClasses() << " disjoint sets.\n"); 347 348 // Now we assume that every member of an equivalence class interferes 349 // with every other member of that class, and with no members of other classes. 350 351 // Convert the EquivalenceClasses to a simpler set of sets. 352 std::vector<std::vector<Chain*> > V; 353 for (auto I = EC.begin(), E = EC.end(); I != E; ++I) { 354 std::vector<Chain*> Cs(EC.member_begin(I), EC.member_end()); 355 if (Cs.empty()) continue; 356 V.push_back(Cs); 357 } 358 359 // Now we have a set of sets, order them by start address so 360 // we can iterate over them sequentially. 361 std::sort(V.begin(), V.end(), 362 [](const std::vector<Chain*> &A, 363 const std::vector<Chain*> &B) { 364 return A.front()->startsBefore(B.front()); 365 }); 366 367 // As we only have two colors, we can track the global (BB-level) balance of 368 // odds versus evens. We aim to keep this near zero to keep both execution 369 // units fed. 370 // Positive means we're even-heavy, negative we're odd-heavy. 371 // 372 // FIXME: If chains have interdependencies, for example: 373 // mul r0, r1, r2 374 // mul r3, r0, r1 375 // We do not model this and may color each one differently, assuming we'll 376 // get ILP when we obviously can't. This hasn't been seen to be a problem 377 // in practice so far, so we simplify the algorithm by ignoring it. 378 int Parity = 0; 379 380 for (auto &I : V) 381 Changed |= colorChainSet(I, MBB, Parity); 382 383 for (auto *C : AllChains) 384 delete C; 385 386 return Changed; 387 } 388 389 Chain *AArch64A57FPLoadBalancing::getAndEraseNext(Color PreferredColor, 390 std::vector<Chain*> &L) { 391 if (L.empty()) 392 return nullptr; 393 394 // We try and get the best candidate from L to color next, given that our 395 // preferred color is "PreferredColor". L is ordered from larger to smaller 396 // chains. It is beneficial to color the large chains before the small chains, 397 // but if we can't find a chain of the maximum length with the preferred color, 398 // we fuzz the size and look for slightly smaller chains before giving up and 399 // returning a chain that must be recolored. 400 401 // FIXME: Does this need to be configurable? 402 const unsigned SizeFuzz = 1; 403 unsigned MinSize = L.front()->size() - SizeFuzz; 404 for (auto I = L.begin(), E = L.end(); I != E; ++I) { 405 if ((*I)->size() <= MinSize) { 406 // We've gone past the size limit. Return the previous item. 407 Chain *Ch = *--I; 408 L.erase(I); 409 return Ch; 410 } 411 412 if ((*I)->getPreferredColor() == PreferredColor) { 413 Chain *Ch = *I; 414 L.erase(I); 415 return Ch; 416 } 417 } 418 419 // Bailout case - just return the first item. 420 Chain *Ch = L.front(); 421 L.erase(L.begin()); 422 return Ch; 423 } 424 425 bool AArch64A57FPLoadBalancing::colorChainSet(std::vector<Chain*> GV, 426 MachineBasicBlock &MBB, 427 int &Parity) { 428 bool Changed = false; 429 DEBUG(dbgs() << "colorChainSet(): #sets=" << GV.size() << "\n"); 430 431 // Sort by descending size order so that we allocate the most important 432 // sets first. 433 // Tie-break equivalent sizes by sorting chains requiring fixups before 434 // those without fixups. The logic here is that we should look at the 435 // chains that we cannot change before we look at those we can, 436 // so the parity counter is updated and we know what color we should 437 // change them to! 438 std::sort(GV.begin(), GV.end(), [](const Chain *G1, const Chain *G2) { 439 if (G1->size() != G2->size()) 440 return G1->size() > G2->size(); 441 return G1->requiresFixup() > G2->requiresFixup(); 442 }); 443 444 Color PreferredColor = Parity < 0 ? Color::Even : Color::Odd; 445 while (Chain *G = getAndEraseNext(PreferredColor, GV)) { 446 // Start off by assuming we'll color to our own preferred color. 447 Color C = PreferredColor; 448 if (Parity == 0) 449 // But if we really don't care, use the chain's preferred color. 450 C = G->getPreferredColor(); 451 452 DEBUG(dbgs() << " - Parity=" << Parity << ", Color=" 453 << ColorNames[(int)C] << "\n"); 454 455 // If we'll need a fixup FMOV, don't bother. Testing has shown that this 456 // happens infrequently and when it does it has at least a 50% chance of 457 // slowing code down instead of speeding it up. 458 if (G->requiresFixup() && C != G->getPreferredColor()) { 459 C = G->getPreferredColor(); 460 DEBUG(dbgs() << " - " << G->str() << " - not worthwhile changing; " 461 "color remains " << ColorNames[(int)C] << "\n"); 462 } 463 464 Changed |= colorChain(G, C, MBB); 465 466 Parity += (C == Color::Even) ? G->size() : -G->size(); 467 PreferredColor = Parity < 0 ? Color::Even : Color::Odd; 468 } 469 470 return Changed; 471 } 472 473 int AArch64A57FPLoadBalancing::scavengeRegister(Chain *G, Color C, 474 MachineBasicBlock &MBB) { 475 RegScavenger RS; 476 RS.enterBasicBlock(&MBB); 477 RS.forward(MachineBasicBlock::iterator(G->getStart())); 478 479 // Can we find an appropriate register that is available throughout the life 480 // of the chain? 481 unsigned RegClassID = G->getStart()->getDesc().OpInfo[0].RegClass; 482 BitVector AvailableRegs = RS.getRegsAvailable(TRI->getRegClass(RegClassID)); 483 for (MachineBasicBlock::iterator I = G->getStart(), E = G->getEnd(); 484 I != E; ++I) { 485 RS.forward(I); 486 AvailableRegs &= RS.getRegsAvailable(TRI->getRegClass(RegClassID)); 487 488 // Remove any registers clobbered by a regmask. 489 for (auto J : I->operands()) { 490 if (J.isRegMask()) 491 AvailableRegs.clearBitsNotInMask(J.getRegMask()); 492 } 493 } 494 495 // Make sure we allocate in-order, to get the cheapest registers first. 496 auto Ord = RCI.getOrder(TRI->getRegClass(RegClassID)); 497 for (auto Reg : Ord) { 498 if (!AvailableRegs[Reg]) 499 continue; 500 if ((C == Color::Even && (Reg % 2) == 0) || 501 (C == Color::Odd && (Reg % 2) == 1)) 502 return Reg; 503 } 504 505 return -1; 506 } 507 508 bool AArch64A57FPLoadBalancing::colorChain(Chain *G, Color C, 509 MachineBasicBlock &MBB) { 510 bool Changed = false; 511 DEBUG(dbgs() << " - colorChain(" << G->str() << ", " 512 << ColorNames[(int)C] << ")\n"); 513 514 // Try and obtain a free register of the right class. Without a register 515 // to play with we cannot continue. 516 int Reg = scavengeRegister(G, C, MBB); 517 if (Reg == -1) { 518 DEBUG(dbgs() << "Scavenging (thus coloring) failed!\n"); 519 return false; 520 } 521 DEBUG(dbgs() << " - Scavenged register: " << TRI->getName(Reg) << "\n"); 522 523 std::map<unsigned, unsigned> Substs; 524 for (MachineBasicBlock::iterator I = G->getStart(), E = G->getEnd(); 525 I != E; ++I) { 526 if (!G->contains(I) && 527 (&*I != G->getKill() || G->isKillImmutable())) 528 continue; 529 530 // I is a member of G, or I is a mutable instruction that kills G. 531 532 std::vector<unsigned> ToErase; 533 for (auto &U : I->operands()) { 534 if (U.isReg() && U.isUse() && Substs.find(U.getReg()) != Substs.end()) { 535 unsigned OrigReg = U.getReg(); 536 U.setReg(Substs[OrigReg]); 537 if (U.isKill()) 538 // Don't erase straight away, because there may be other operands 539 // that also reference this substitution! 540 ToErase.push_back(OrigReg); 541 } else if (U.isRegMask()) { 542 for (auto J : Substs) { 543 if (U.clobbersPhysReg(J.first)) 544 ToErase.push_back(J.first); 545 } 546 } 547 } 548 // Now it's safe to remove the substs identified earlier. 549 for (auto J : ToErase) 550 Substs.erase(J); 551 552 // Only change the def if this isn't the last instruction. 553 if (&*I != G->getKill()) { 554 MachineOperand &MO = I->getOperand(0); 555 556 bool Change = TransformAll || getColor(MO.getReg()) != C; 557 if (G->requiresFixup() && &*I == G->getLast()) 558 Change = false; 559 560 if (Change) { 561 Substs[MO.getReg()] = Reg; 562 MO.setReg(Reg); 563 MRI->setPhysRegUsed(Reg); 564 565 Changed = true; 566 } 567 } 568 } 569 assert(Substs.size() == 0 && "No substitutions should be left active!"); 570 571 if (G->getKill()) { 572 DEBUG(dbgs() << " - Kill instruction seen.\n"); 573 } else { 574 // We didn't have a kill instruction, but we didn't seem to need to change 575 // the destination register anyway. 576 DEBUG(dbgs() << " - Destination register not changed.\n"); 577 } 578 return Changed; 579 } 580 581 void AArch64A57FPLoadBalancing:: 582 scanInstruction(MachineInstr *MI, unsigned Idx, 583 std::map<unsigned, Chain*> &ActiveChains, 584 std::set<Chain*> &AllChains) { 585 // Inspect "MI", updating ActiveChains and AllChains. 586 587 if (isMul(MI)) { 588 589 for (auto &I : MI->operands()) 590 maybeKillChain(I, Idx, ActiveChains); 591 592 // Create a new chain. Multiplies don't require forwarding so can go on any 593 // unit. 594 unsigned DestReg = MI->getOperand(0).getReg(); 595 596 DEBUG(dbgs() << "New chain started for register " 597 << TRI->getName(DestReg) << " at " << *MI); 598 599 Chain *G = new Chain(MI, Idx, getColor(DestReg)); 600 ActiveChains[DestReg] = G; 601 AllChains.insert(G); 602 603 } else if (isMla(MI)) { 604 605 // It is beneficial to keep MLAs on the same functional unit as their 606 // accumulator operand. 607 unsigned DestReg = MI->getOperand(0).getReg(); 608 unsigned AccumReg = MI->getOperand(3).getReg(); 609 610 maybeKillChain(MI->getOperand(1), Idx, ActiveChains); 611 maybeKillChain(MI->getOperand(2), Idx, ActiveChains); 612 if (DestReg != AccumReg) 613 maybeKillChain(MI->getOperand(0), Idx, ActiveChains); 614 615 if (ActiveChains.find(AccumReg) != ActiveChains.end()) { 616 DEBUG(dbgs() << "Chain found for accumulator register " 617 << TRI->getName(AccumReg) << " in MI " << *MI); 618 619 // For simplicity we only chain together sequences of MULs/MLAs where the 620 // accumulator register is killed on each instruction. This means we don't 621 // need to track other uses of the registers we want to rewrite. 622 // 623 // FIXME: We could extend to handle the non-kill cases for more coverage. 624 if (MI->getOperand(3).isKill()) { 625 // Add to chain. 626 DEBUG(dbgs() << "Instruction was successfully added to chain.\n"); 627 ActiveChains[AccumReg]->add(MI, Idx, getColor(DestReg)); 628 // Handle cases where the destination is not the same as the accumulator. 629 ActiveChains[DestReg] = ActiveChains[AccumReg]; 630 return; 631 } 632 633 DEBUG(dbgs() << "Cannot add to chain because accumulator operand wasn't " 634 << "marked <kill>!\n"); 635 maybeKillChain(MI->getOperand(3), Idx, ActiveChains); 636 } 637 638 DEBUG(dbgs() << "Creating new chain for dest register " 639 << TRI->getName(DestReg) << "\n"); 640 Chain *G = new Chain(MI, Idx, getColor(DestReg)); 641 ActiveChains[DestReg] = G; 642 AllChains.insert(G); 643 644 } else { 645 646 // Non-MUL or MLA instruction. Invalidate any chain in the uses or defs 647 // lists. 648 for (auto &I : MI->operands()) 649 maybeKillChain(I, Idx, ActiveChains); 650 651 } 652 } 653 654 void AArch64A57FPLoadBalancing:: 655 maybeKillChain(MachineOperand &MO, unsigned Idx, 656 std::map<unsigned, Chain*> &ActiveChains) { 657 // Given an operand and the set of active chains (keyed by register), 658 // determine if a chain should be ended and remove from ActiveChains. 659 MachineInstr *MI = MO.getParent(); 660 661 if (MO.isReg()) { 662 663 // If this is a KILL of a current chain, record it. 664 if (MO.isKill() && ActiveChains.find(MO.getReg()) != ActiveChains.end()) { 665 DEBUG(dbgs() << "Kill seen for chain " << TRI->getName(MO.getReg()) 666 << "\n"); 667 ActiveChains[MO.getReg()]->setKill(MI, Idx, /*Immutable=*/MO.isTied()); 668 } 669 ActiveChains.erase(MO.getReg()); 670 671 } else if (MO.isRegMask()) { 672 673 for (auto I = ActiveChains.begin(), E = ActiveChains.end(); 674 I != E;) { 675 if (MO.clobbersPhysReg(I->first)) { 676 DEBUG(dbgs() << "Kill (regmask) seen for chain " 677 << TRI->getName(I->first) << "\n"); 678 I->second->setKill(MI, Idx, /*Immutable=*/true); 679 ActiveChains.erase(I++); 680 } else 681 ++I; 682 } 683 684 } 685 } 686 687 Color AArch64A57FPLoadBalancing::getColor(unsigned Reg) { 688 if ((TRI->getEncodingValue(Reg) % 2) == 0) 689 return Color::Even; 690 else 691 return Color::Odd; 692 } 693 694 // Factory function used by AArch64TargetMachine to add the pass to the passmanager. 695 FunctionPass *llvm::createAArch64A57FPLoadBalancing() { 696 return new AArch64A57FPLoadBalancing(); 697 } 698