1 //===---------- AArch64CollectLOH.cpp - AArch64 collect LOH pass --*- C++ -*-=// 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 // 9 // This file contains a pass that collect the Linker Optimization Hint (LOH). 10 // This pass should be run at the very end of the compilation flow, just before 11 // assembly printer. 12 // To be useful for the linker, the LOH must be printed into the assembly file. 13 // 14 // A LOH describes a sequence of instructions that may be optimized by the 15 // linker. 16 // This same sequence cannot be optimized by the compiler because some of 17 // the information will be known at link time. 18 // For instance, consider the following sequence: 19 // L1: adrp xA, sym@PAGE 20 // L2: add xB, xA, sym@PAGEOFF 21 // L3: ldr xC, [xB, #imm] 22 // This sequence can be turned into: 23 // A literal load if sym@PAGE + sym@PAGEOFF + #imm - address(L3) is < 1MB: 24 // L3: ldr xC, sym+#imm 25 // It may also be turned into either the following more efficient 26 // code sequences: 27 // - If sym@PAGEOFF + #imm fits the encoding space of L3. 28 // L1: adrp xA, sym@PAGE 29 // L3: ldr xC, [xB, sym@PAGEOFF + #imm] 30 // - If sym@PAGE + sym@PAGEOFF - address(L1) < 1MB: 31 // L1: adr xA, sym 32 // L3: ldr xC, [xB, #imm] 33 // 34 // To be valid a LOH must meet all the requirements needed by all the related 35 // possible linker transformations. 36 // For instance, using the running example, the constraints to emit 37 // ".loh AdrpAddLdr" are: 38 // - L1, L2, and L3 instructions are of the expected type, i.e., 39 // respectively ADRP, ADD (immediate), and LD. 40 // - The result of L1 is used only by L2. 41 // - The register argument (xA) used in the ADD instruction is defined 42 // only by L1. 43 // - The result of L2 is used only by L3. 44 // - The base address (xB) in L3 is defined only L2. 45 // - The ADRP in L1 and the ADD in L2 must reference the same symbol using 46 // @PAGE/@PAGEOFF with no additional constants 47 // 48 // Currently supported LOHs are: 49 // * So called non-ADRP-related: 50 // - .loh AdrpAddLdr L1, L2, L3: 51 // L1: adrp xA, sym@PAGE 52 // L2: add xB, xA, sym@PAGEOFF 53 // L3: ldr xC, [xB, #imm] 54 // - .loh AdrpLdrGotLdr L1, L2, L3: 55 // L1: adrp xA, sym@GOTPAGE 56 // L2: ldr xB, [xA, sym@GOTPAGEOFF] 57 // L3: ldr xC, [xB, #imm] 58 // - .loh AdrpLdr L1, L3: 59 // L1: adrp xA, sym@PAGE 60 // L3: ldr xC, [xA, sym@PAGEOFF] 61 // - .loh AdrpAddStr L1, L2, L3: 62 // L1: adrp xA, sym@PAGE 63 // L2: add xB, xA, sym@PAGEOFF 64 // L3: str xC, [xB, #imm] 65 // - .loh AdrpLdrGotStr L1, L2, L3: 66 // L1: adrp xA, sym@GOTPAGE 67 // L2: ldr xB, [xA, sym@GOTPAGEOFF] 68 // L3: str xC, [xB, #imm] 69 // - .loh AdrpAdd L1, L2: 70 // L1: adrp xA, sym@PAGE 71 // L2: add xB, xA, sym@PAGEOFF 72 // For all these LOHs, L1, L2, L3 form a simple chain: 73 // L1 result is used only by L2 and L2 result by L3. 74 // L3 LOH-related argument is defined only by L2 and L2 LOH-related argument 75 // by L1. 76 // All these LOHs aim at using more efficient load/store patterns by folding 77 // some instructions used to compute the address directly into the load/store. 78 // 79 // * So called ADRP-related: 80 // - .loh AdrpAdrp L2, L1: 81 // L2: ADRP xA, sym1@PAGE 82 // L1: ADRP xA, sym2@PAGE 83 // L2 dominates L1 and xA is not redifined between L2 and L1 84 // This LOH aims at getting rid of redundant ADRP instructions. 85 // 86 // The overall design for emitting the LOHs is: 87 // 1. AArch64CollectLOH (this pass) records the LOHs in the AArch64FunctionInfo. 88 // 2. AArch64AsmPrinter reads the LOHs from AArch64FunctionInfo and it: 89 // 1. Associates them a label. 90 // 2. Emits them in a MCStreamer (EmitLOHDirective). 91 // - The MCMachOStreamer records them into the MCAssembler. 92 // - The MCAsmStreamer prints them. 93 // - Other MCStreamers ignore them. 94 // 3. Closes the MCStreamer: 95 // - The MachObjectWriter gets them from the MCAssembler and writes 96 // them in the object file. 97 // - Other ObjectWriters ignore them. 98 //===----------------------------------------------------------------------===// 99 100 #include "AArch64.h" 101 #include "AArch64InstrInfo.h" 102 #include "AArch64MachineFunctionInfo.h" 103 #include "llvm/ADT/BitVector.h" 104 #include "llvm/ADT/DenseMap.h" 105 #include "llvm/ADT/MapVector.h" 106 #include "llvm/ADT/SmallSet.h" 107 #include "llvm/ADT/SmallVector.h" 108 #include "llvm/ADT/Statistic.h" 109 #include "llvm/CodeGen/MachineBasicBlock.h" 110 #include "llvm/CodeGen/MachineFunctionPass.h" 111 #include "llvm/CodeGen/MachineInstr.h" 112 #include "llvm/CodeGen/TargetRegisterInfo.h" 113 #include "llvm/Support/Debug.h" 114 #include "llvm/Support/ErrorHandling.h" 115 #include "llvm/Support/raw_ostream.h" 116 #include "llvm/Target/TargetMachine.h" 117 using namespace llvm; 118 119 #define DEBUG_TYPE "aarch64-collect-loh" 120 121 STATISTIC(NumADRPSimpleCandidate, 122 "Number of simplifiable ADRP dominate by another"); 123 STATISTIC(NumADDToSTR, "Number of simplifiable STR reachable by ADD"); 124 STATISTIC(NumLDRToSTR, "Number of simplifiable STR reachable by LDR"); 125 STATISTIC(NumADDToLDR, "Number of simplifiable LDR reachable by ADD"); 126 STATISTIC(NumLDRToLDR, "Number of simplifiable LDR reachable by LDR"); 127 STATISTIC(NumADRPToLDR, "Number of simplifiable LDR reachable by ADRP"); 128 STATISTIC(NumADRSimpleCandidate, "Number of simplifiable ADRP + ADD"); 129 130 #define AARCH64_COLLECT_LOH_NAME "AArch64 Collect Linker Optimization Hint (LOH)" 131 132 namespace { 133 134 struct AArch64CollectLOH : public MachineFunctionPass { 135 static char ID; 136 AArch64CollectLOH() : MachineFunctionPass(ID) {} 137 138 bool runOnMachineFunction(MachineFunction &MF) override; 139 140 MachineFunctionProperties getRequiredProperties() const override { 141 return MachineFunctionProperties().set( 142 MachineFunctionProperties::Property::NoVRegs); 143 } 144 145 StringRef getPassName() const override { return AARCH64_COLLECT_LOH_NAME; } 146 147 void getAnalysisUsage(AnalysisUsage &AU) const override { 148 MachineFunctionPass::getAnalysisUsage(AU); 149 AU.setPreservesAll(); 150 } 151 }; 152 153 char AArch64CollectLOH::ID = 0; 154 155 } // end anonymous namespace. 156 157 INITIALIZE_PASS(AArch64CollectLOH, "aarch64-collect-loh", 158 AARCH64_COLLECT_LOH_NAME, false, false) 159 160 static bool canAddBePartOfLOH(const MachineInstr &MI) { 161 // Check immediate to see if the immediate is an address. 162 switch (MI.getOperand(2).getType()) { 163 default: 164 return false; 165 case MachineOperand::MO_GlobalAddress: 166 case MachineOperand::MO_JumpTableIndex: 167 case MachineOperand::MO_ConstantPoolIndex: 168 case MachineOperand::MO_BlockAddress: 169 return true; 170 } 171 } 172 173 /// Answer the following question: Can Def be one of the definition 174 /// involved in a part of a LOH? 175 static bool canDefBePartOfLOH(const MachineInstr &MI) { 176 // Accept ADRP, ADDLow and LOADGot. 177 switch (MI.getOpcode()) { 178 default: 179 return false; 180 case AArch64::ADRP: 181 return true; 182 case AArch64::ADDXri: 183 return canAddBePartOfLOH(MI); 184 case AArch64::LDRXui: 185 case AArch64::LDRWui: 186 // Check immediate to see if the immediate is an address. 187 switch (MI.getOperand(2).getType()) { 188 default: 189 return false; 190 case MachineOperand::MO_GlobalAddress: 191 return MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT; 192 } 193 } 194 } 195 196 /// Check whether the given instruction can the end of a LOH chain involving a 197 /// store. 198 static bool isCandidateStore(const MachineInstr &MI, const MachineOperand &MO) { 199 switch (MI.getOpcode()) { 200 default: 201 return false; 202 case AArch64::STRBBui: 203 case AArch64::STRHHui: 204 case AArch64::STRBui: 205 case AArch64::STRHui: 206 case AArch64::STRWui: 207 case AArch64::STRXui: 208 case AArch64::STRSui: 209 case AArch64::STRDui: 210 case AArch64::STRQui: 211 // We can only optimize the index operand. 212 // In case we have str xA, [xA, #imm], this is two different uses 213 // of xA and we cannot fold, otherwise the xA stored may be wrong, 214 // even if #imm == 0. 215 return MO.getOperandNo() == 1 && 216 MI.getOperand(0).getReg() != MI.getOperand(1).getReg(); 217 } 218 } 219 220 /// Check whether the given instruction can be the end of a LOH chain 221 /// involving a load. 222 static bool isCandidateLoad(const MachineInstr &MI) { 223 switch (MI.getOpcode()) { 224 default: 225 return false; 226 case AArch64::LDRSBWui: 227 case AArch64::LDRSBXui: 228 case AArch64::LDRSHWui: 229 case AArch64::LDRSHXui: 230 case AArch64::LDRSWui: 231 case AArch64::LDRBui: 232 case AArch64::LDRHui: 233 case AArch64::LDRWui: 234 case AArch64::LDRXui: 235 case AArch64::LDRSui: 236 case AArch64::LDRDui: 237 case AArch64::LDRQui: 238 return !(MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT); 239 } 240 } 241 242 /// Check whether the given instruction can load a litteral. 243 static bool supportLoadFromLiteral(const MachineInstr &MI) { 244 switch (MI.getOpcode()) { 245 default: 246 return false; 247 case AArch64::LDRSWui: 248 case AArch64::LDRWui: 249 case AArch64::LDRXui: 250 case AArch64::LDRSui: 251 case AArch64::LDRDui: 252 case AArch64::LDRQui: 253 return true; 254 } 255 } 256 257 /// Number of GPR registers traked by mapRegToGPRIndex() 258 static const unsigned N_GPR_REGS = 31; 259 /// Map register number to index from 0-30. 260 static int mapRegToGPRIndex(MCPhysReg Reg) { 261 static_assert(AArch64::X28 - AArch64::X0 + 3 == N_GPR_REGS, "Number of GPRs"); 262 static_assert(AArch64::W30 - AArch64::W0 + 1 == N_GPR_REGS, "Number of GPRs"); 263 if (AArch64::X0 <= Reg && Reg <= AArch64::X28) 264 return Reg - AArch64::X0; 265 if (AArch64::W0 <= Reg && Reg <= AArch64::W30) 266 return Reg - AArch64::W0; 267 // TableGen gives "FP" and "LR" an index not adjacent to X28 so we have to 268 // handle them as special cases. 269 if (Reg == AArch64::FP) 270 return 29; 271 if (Reg == AArch64::LR) 272 return 30; 273 return -1; 274 } 275 276 /// State tracked per register. 277 /// The main algorithm walks backwards over a basic block maintaining this 278 /// datastructure for each tracked general purpose register. 279 struct LOHInfo { 280 MCLOHType Type : 8; ///< "Best" type of LOH possible. 281 bool IsCandidate : 1; ///< Possible LOH candidate. 282 bool OneUser : 1; ///< Found exactly one user (yet). 283 bool MultiUsers : 1; ///< Found multiple users. 284 const MachineInstr *MI0; ///< First instruction involved in the LOH. 285 const MachineInstr *MI1; ///< Second instruction involved in the LOH 286 /// (if any). 287 const MachineInstr *LastADRP; ///< Last ADRP in same register. 288 }; 289 290 /// Update state \p Info given \p MI uses the tracked register. 291 static void handleUse(const MachineInstr &MI, const MachineOperand &MO, 292 LOHInfo &Info) { 293 // We have multiple uses if we already found one before. 294 if (Info.MultiUsers || Info.OneUser) { 295 Info.IsCandidate = false; 296 Info.MultiUsers = true; 297 return; 298 } 299 Info.OneUser = true; 300 301 // Start new LOHInfo if applicable. 302 if (isCandidateLoad(MI)) { 303 Info.Type = MCLOH_AdrpLdr; 304 Info.IsCandidate = true; 305 Info.MI0 = &MI; 306 // Note that even this is AdrpLdr now, we can switch to a Ldr variant 307 // later. 308 } else if (isCandidateStore(MI, MO)) { 309 Info.Type = MCLOH_AdrpAddStr; 310 Info.IsCandidate = true; 311 Info.MI0 = &MI; 312 Info.MI1 = nullptr; 313 } else if (MI.getOpcode() == AArch64::ADDXri) { 314 Info.Type = MCLOH_AdrpAdd; 315 Info.IsCandidate = true; 316 Info.MI0 = &MI; 317 } else if ((MI.getOpcode() == AArch64::LDRXui || 318 MI.getOpcode() == AArch64::LDRWui) && 319 MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT) { 320 Info.Type = MCLOH_AdrpLdrGot; 321 Info.IsCandidate = true; 322 Info.MI0 = &MI; 323 } 324 } 325 326 /// Update state \p Info given the tracked register is clobbered. 327 static void handleClobber(LOHInfo &Info) { 328 Info.IsCandidate = false; 329 Info.OneUser = false; 330 Info.MultiUsers = false; 331 Info.LastADRP = nullptr; 332 } 333 334 /// Update state \p Info given that \p MI is possibly the middle instruction 335 /// of an LOH involving 3 instructions. 336 static bool handleMiddleInst(const MachineInstr &MI, LOHInfo &DefInfo, 337 LOHInfo &OpInfo) { 338 if (!DefInfo.IsCandidate || (&DefInfo != &OpInfo && OpInfo.OneUser)) 339 return false; 340 // Copy LOHInfo for dest register to LOHInfo for source register. 341 if (&DefInfo != &OpInfo) { 342 OpInfo = DefInfo; 343 // Invalidate \p DefInfo because we track it in \p OpInfo now. 344 handleClobber(DefInfo); 345 } else 346 DefInfo.LastADRP = nullptr; 347 348 // Advance state machine. 349 assert(OpInfo.IsCandidate && "Expect valid state"); 350 if (MI.getOpcode() == AArch64::ADDXri && canAddBePartOfLOH(MI)) { 351 if (OpInfo.Type == MCLOH_AdrpLdr) { 352 OpInfo.Type = MCLOH_AdrpAddLdr; 353 OpInfo.IsCandidate = true; 354 OpInfo.MI1 = &MI; 355 return true; 356 } else if (OpInfo.Type == MCLOH_AdrpAddStr && OpInfo.MI1 == nullptr) { 357 OpInfo.Type = MCLOH_AdrpAddStr; 358 OpInfo.IsCandidate = true; 359 OpInfo.MI1 = &MI; 360 return true; 361 } 362 } else { 363 assert((MI.getOpcode() == AArch64::LDRXui || 364 MI.getOpcode() == AArch64::LDRWui) && 365 "Expect LDRXui or LDRWui"); 366 assert((MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT) && 367 "Expected GOT relocation"); 368 if (OpInfo.Type == MCLOH_AdrpAddStr && OpInfo.MI1 == nullptr) { 369 OpInfo.Type = MCLOH_AdrpLdrGotStr; 370 OpInfo.IsCandidate = true; 371 OpInfo.MI1 = &MI; 372 return true; 373 } else if (OpInfo.Type == MCLOH_AdrpLdr) { 374 OpInfo.Type = MCLOH_AdrpLdrGotLdr; 375 OpInfo.IsCandidate = true; 376 OpInfo.MI1 = &MI; 377 return true; 378 } 379 } 380 return false; 381 } 382 383 /// Update state when seeing and ADRP instruction. 384 static void handleADRP(const MachineInstr &MI, AArch64FunctionInfo &AFI, 385 LOHInfo &Info, LOHInfo *LOHInfos) { 386 if (Info.LastADRP != nullptr) { 387 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAdrp:\n" 388 << '\t' << MI << '\t' << *Info.LastADRP); 389 AFI.addLOHDirective(MCLOH_AdrpAdrp, {&MI, Info.LastADRP}); 390 ++NumADRPSimpleCandidate; 391 } 392 393 // Produce LOH directive if possible. 394 if (Info.IsCandidate) { 395 switch (Info.Type) { 396 case MCLOH_AdrpAdd: { 397 // ADRPs and ADDs for this candidate may be split apart if using 398 // GlobalISel instead of pseudo-expanded. If that happens, the 399 // def register of the ADD may have a use in between. Adding an LOH in 400 // this case can cause the linker to rewrite the ADRP to write to that 401 // register, clobbering the use. 402 const MachineInstr *AddMI = Info.MI0; 403 int DefIdx = mapRegToGPRIndex(MI.getOperand(0).getReg()); 404 int OpIdx = mapRegToGPRIndex(AddMI->getOperand(0).getReg()); 405 LOHInfo DefInfo = LOHInfos[OpIdx]; 406 if (DefIdx != OpIdx && (DefInfo.OneUser || DefInfo.MultiUsers)) 407 break; 408 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAdd:\n" 409 << '\t' << MI << '\t' << *Info.MI0); 410 AFI.addLOHDirective(MCLOH_AdrpAdd, {&MI, Info.MI0}); 411 ++NumADRSimpleCandidate; 412 break; 413 } 414 case MCLOH_AdrpLdr: 415 if (supportLoadFromLiteral(*Info.MI0)) { 416 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpLdr:\n" 417 << '\t' << MI << '\t' << *Info.MI0); 418 AFI.addLOHDirective(MCLOH_AdrpLdr, {&MI, Info.MI0}); 419 ++NumADRPToLDR; 420 } 421 break; 422 case MCLOH_AdrpAddLdr: { 423 // There is a possibility that the linker may try to rewrite: 424 // adrp x0, @sym@PAGE 425 // add x1, x0, @sym@PAGEOFF 426 // [x0 = some other def] 427 // ldr x2, [x1] 428 // ...into... 429 // adrp x0, @sym 430 // nop 431 // [x0 = some other def] 432 // ldr x2, [x0] 433 // ...if the offset to the symbol won't fit within a literal load. 434 // This causes the load to use the result of the adrp, which in this 435 // case has already been clobbered. 436 // FIXME: Implement proper liveness tracking for all registers. For now, 437 // don't emit the LOH if there are any instructions between the add and 438 // the ldr. 439 MachineInstr *AddMI = const_cast<MachineInstr *>(Info.MI1); 440 const MachineInstr *LdrMI = Info.MI0; 441 auto AddIt = MachineBasicBlock::iterator(AddMI); 442 auto EndIt = AddMI->getParent()->end(); 443 if (AddMI->getIterator() == EndIt || LdrMI != &*next_nodbg(AddIt, EndIt)) 444 break; 445 446 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAddLdr:\n" 447 << '\t' << MI << '\t' << *Info.MI1 << '\t' 448 << *Info.MI0); 449 AFI.addLOHDirective(MCLOH_AdrpAddLdr, {&MI, Info.MI1, Info.MI0}); 450 ++NumADDToLDR; 451 break; 452 } 453 case MCLOH_AdrpAddStr: 454 if (Info.MI1 != nullptr) { 455 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAddStr:\n" 456 << '\t' << MI << '\t' << *Info.MI1 << '\t' 457 << *Info.MI0); 458 AFI.addLOHDirective(MCLOH_AdrpAddStr, {&MI, Info.MI1, Info.MI0}); 459 ++NumADDToSTR; 460 } 461 break; 462 case MCLOH_AdrpLdrGotLdr: 463 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpLdrGotLdr:\n" 464 << '\t' << MI << '\t' << *Info.MI1 << '\t' 465 << *Info.MI0); 466 AFI.addLOHDirective(MCLOH_AdrpLdrGotLdr, {&MI, Info.MI1, Info.MI0}); 467 ++NumLDRToLDR; 468 break; 469 case MCLOH_AdrpLdrGotStr: 470 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpLdrGotStr:\n" 471 << '\t' << MI << '\t' << *Info.MI1 << '\t' 472 << *Info.MI0); 473 AFI.addLOHDirective(MCLOH_AdrpLdrGotStr, {&MI, Info.MI1, Info.MI0}); 474 ++NumLDRToSTR; 475 break; 476 case MCLOH_AdrpLdrGot: 477 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpLdrGot:\n" 478 << '\t' << MI << '\t' << *Info.MI0); 479 AFI.addLOHDirective(MCLOH_AdrpLdrGot, {&MI, Info.MI0}); 480 break; 481 case MCLOH_AdrpAdrp: 482 llvm_unreachable("MCLOH_AdrpAdrp not used in state machine"); 483 } 484 } 485 486 handleClobber(Info); 487 Info.LastADRP = &MI; 488 } 489 490 static void handleRegMaskClobber(const uint32_t *RegMask, MCPhysReg Reg, 491 LOHInfo *LOHInfos) { 492 if (!MachineOperand::clobbersPhysReg(RegMask, Reg)) 493 return; 494 int Idx = mapRegToGPRIndex(Reg); 495 if (Idx >= 0) 496 handleClobber(LOHInfos[Idx]); 497 } 498 499 static void handleNormalInst(const MachineInstr &MI, LOHInfo *LOHInfos) { 500 // Handle defs and regmasks. 501 for (const MachineOperand &MO : MI.operands()) { 502 if (MO.isRegMask()) { 503 const uint32_t *RegMask = MO.getRegMask(); 504 for (MCPhysReg Reg : AArch64::GPR32RegClass) 505 handleRegMaskClobber(RegMask, Reg, LOHInfos); 506 for (MCPhysReg Reg : AArch64::GPR64RegClass) 507 handleRegMaskClobber(RegMask, Reg, LOHInfos); 508 continue; 509 } 510 if (!MO.isReg() || !MO.isDef()) 511 continue; 512 int Idx = mapRegToGPRIndex(MO.getReg()); 513 if (Idx < 0) 514 continue; 515 handleClobber(LOHInfos[Idx]); 516 } 517 // Handle uses. 518 519 SmallSet<int, 4> UsesSeen; 520 for (const MachineOperand &MO : MI.uses()) { 521 if (!MO.isReg() || !MO.readsReg()) 522 continue; 523 int Idx = mapRegToGPRIndex(MO.getReg()); 524 if (Idx < 0) 525 continue; 526 527 // Multiple uses of the same register within a single instruction don't 528 // count as MultiUser or block optimization. This is especially important on 529 // arm64_32, where any memory operation is likely to be an explicit use of 530 // xN and an implicit use of wN (the base address register). 531 if (UsesSeen.insert(Idx).second) 532 handleUse(MI, MO, LOHInfos[Idx]); 533 } 534 } 535 536 bool AArch64CollectLOH::runOnMachineFunction(MachineFunction &MF) { 537 if (skipFunction(MF.getFunction())) 538 return false; 539 540 LLVM_DEBUG(dbgs() << "********** AArch64 Collect LOH **********\n" 541 << "Looking in function " << MF.getName() << '\n'); 542 543 LOHInfo LOHInfos[N_GPR_REGS]; 544 AArch64FunctionInfo &AFI = *MF.getInfo<AArch64FunctionInfo>(); 545 for (const MachineBasicBlock &MBB : MF) { 546 // Reset register tracking state. 547 memset(LOHInfos, 0, sizeof(LOHInfos)); 548 // Live-out registers are used. 549 for (const MachineBasicBlock *Succ : MBB.successors()) { 550 for (const auto &LI : Succ->liveins()) { 551 int RegIdx = mapRegToGPRIndex(LI.PhysReg); 552 if (RegIdx >= 0) 553 LOHInfos[RegIdx].OneUser = true; 554 } 555 } 556 557 // Walk the basic block backwards and update the per register state machine 558 // in the process. 559 for (const MachineInstr &MI : 560 instructionsWithoutDebug(MBB.instr_rbegin(), MBB.instr_rend())) { 561 unsigned Opcode = MI.getOpcode(); 562 switch (Opcode) { 563 case AArch64::ADDXri: 564 case AArch64::LDRXui: 565 case AArch64::LDRWui: 566 if (canDefBePartOfLOH(MI)) { 567 const MachineOperand &Def = MI.getOperand(0); 568 const MachineOperand &Op = MI.getOperand(1); 569 assert(Def.isReg() && Def.isDef() && "Expected reg def"); 570 assert(Op.isReg() && Op.isUse() && "Expected reg use"); 571 int DefIdx = mapRegToGPRIndex(Def.getReg()); 572 int OpIdx = mapRegToGPRIndex(Op.getReg()); 573 if (DefIdx >= 0 && OpIdx >= 0 && 574 handleMiddleInst(MI, LOHInfos[DefIdx], LOHInfos[OpIdx])) 575 continue; 576 } 577 break; 578 case AArch64::ADRP: 579 const MachineOperand &Op0 = MI.getOperand(0); 580 int Idx = mapRegToGPRIndex(Op0.getReg()); 581 if (Idx >= 0) { 582 handleADRP(MI, AFI, LOHInfos[Idx], LOHInfos); 583 continue; 584 } 585 break; 586 } 587 handleNormalInst(MI, LOHInfos); 588 } 589 } 590 591 // Return "no change": The pass only collects information. 592 return false; 593 } 594 595 FunctionPass *llvm::createAArch64CollectLOHPass() { 596 return new AArch64CollectLOH(); 597 } 598