brintos

brintos / llvm-project-archived public Read only

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