xref: /llvm-project/llvm/lib/Target/AArch64/AArch64CollectLOH.cpp (revision f5f32cef617c0796a7d980a464786949cbf21227)
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 "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"
111 using namespace llvm;
112 
113 #define DEBUG_TYPE "aarch64-collect-loh"
114 
115 STATISTIC(NumADRPSimpleCandidate,
116           "Number of simplifiable ADRP dominate by another");
117 STATISTIC(NumADDToSTR, "Number of simplifiable STR reachable by ADD");
118 STATISTIC(NumLDRToSTR, "Number of simplifiable STR reachable by LDR");
119 STATISTIC(NumADDToLDR, "Number of simplifiable LDR reachable by ADD");
120 STATISTIC(NumLDRToLDR, "Number of simplifiable LDR reachable by LDR");
121 STATISTIC(NumADRPToLDR, "Number of simplifiable LDR reachable by ADRP");
122 STATISTIC(NumADRSimpleCandidate, "Number of simplifiable ADRP + ADD");
123 
124 #define AARCH64_COLLECT_LOH_NAME "AArch64 Collect Linker Optimization Hint (LOH)"
125 
126 namespace {
127 
128 struct 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().set(
136         MachineFunctionProperties::Property::NoVRegs);
137   }
138 
139   StringRef getPassName() const override { return AARCH64_COLLECT_LOH_NAME; }
140 
141   void getAnalysisUsage(AnalysisUsage &AU) const override {
142     MachineFunctionPass::getAnalysisUsage(AU);
143     AU.setPreservesAll();
144   }
145 };
146 
147 char AArch64CollectLOH::ID = 0;
148 
149 } // end anonymous namespace.
150 
151 INITIALIZE_PASS(AArch64CollectLOH, "aarch64-collect-loh",
152                 AARCH64_COLLECT_LOH_NAME, false, false)
153 
154 static bool canAddBePartOfLOH(const MachineInstr &MI) {
155   // Check immediate to see if the immediate is an address.
156   switch (MI.getOperand(2).getType()) {
157   default:
158     return false;
159   case MachineOperand::MO_GlobalAddress:
160   case MachineOperand::MO_JumpTableIndex:
161   case MachineOperand::MO_ConstantPoolIndex:
162   case MachineOperand::MO_BlockAddress:
163     return true;
164   }
165 }
166 
167 /// Answer the following question: Can Def be one of the definition
168 /// involved in a part of a LOH?
169 static bool canDefBePartOfLOH(const MachineInstr &MI) {
170   // Accept ADRP, ADDLow and LOADGot.
171   switch (MI.getOpcode()) {
172   default:
173     return false;
174   case AArch64::ADRP:
175     return true;
176   case AArch64::ADDXri:
177     return canAddBePartOfLOH(MI);
178   case AArch64::LDRXui:
179   case AArch64::LDRWui:
180     // Check immediate to see if the immediate is an address.
181     switch (MI.getOperand(2).getType()) {
182     default:
183       return false;
184     case MachineOperand::MO_GlobalAddress:
185       return MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT;
186     }
187   }
188 }
189 
190 /// Check whether the given instruction can the end of a LOH chain involving a
191 /// store.
192 static bool isCandidateStore(const MachineInstr &MI, const MachineOperand &MO) {
193   switch (MI.getOpcode()) {
194   default:
195     return false;
196   case AArch64::STRBBui:
197   case AArch64::STRHHui:
198   case AArch64::STRBui:
199   case AArch64::STRHui:
200   case AArch64::STRWui:
201   case AArch64::STRXui:
202   case AArch64::STRSui:
203   case AArch64::STRDui:
204   case AArch64::STRQui:
205     // We can only optimize the index operand.
206     // In case we have str xA, [xA, #imm], this is two different uses
207     // of xA and we cannot fold, otherwise the xA stored may be wrong,
208     // even if #imm == 0.
209     return MO.getOperandNo() == 1 &&
210            MI.getOperand(0).getReg() != MI.getOperand(1).getReg();
211   }
212 }
213 
214 /// Check whether the given instruction can be the end of a LOH chain
215 /// involving a load.
216 static bool isCandidateLoad(const MachineInstr &MI) {
217   switch (MI.getOpcode()) {
218   default:
219     return false;
220   case AArch64::LDRSBWui:
221   case AArch64::LDRSBXui:
222   case AArch64::LDRSHWui:
223   case AArch64::LDRSHXui:
224   case AArch64::LDRSWui:
225   case AArch64::LDRBui:
226   case AArch64::LDRHui:
227   case AArch64::LDRWui:
228   case AArch64::LDRXui:
229   case AArch64::LDRSui:
230   case AArch64::LDRDui:
231   case AArch64::LDRQui:
232     return !(MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT);
233   }
234 }
235 
236 /// Check whether the given instruction can load a litteral.
237 static bool supportLoadFromLiteral(const MachineInstr &MI) {
238   switch (MI.getOpcode()) {
239   default:
240     return false;
241   case AArch64::LDRSWui:
242   case AArch64::LDRWui:
243   case AArch64::LDRXui:
244   case AArch64::LDRSui:
245   case AArch64::LDRDui:
246   case AArch64::LDRQui:
247     return true;
248   }
249 }
250 
251 /// Number of GPR registers traked by mapRegToGPRIndex()
252 static const unsigned N_GPR_REGS = 31;
253 /// Map register number to index from 0-30.
254 static int mapRegToGPRIndex(MCRegister Reg) {
255   static_assert(AArch64::X28 - AArch64::X0 + 3 == N_GPR_REGS, "Number of GPRs");
256   static_assert(AArch64::W30 - AArch64::W0 + 1 == N_GPR_REGS, "Number of GPRs");
257   if (AArch64::X0 <= Reg && Reg <= AArch64::X28)
258     return Reg - AArch64::X0;
259   if (AArch64::W0 <= Reg && Reg <= AArch64::W30)
260     return Reg - AArch64::W0;
261   // TableGen gives "FP" and "LR" an index not adjacent to X28 so we have to
262   // handle them as special cases.
263   if (Reg == AArch64::FP)
264     return 29;
265   if (Reg == AArch64::LR)
266     return 30;
267   return -1;
268 }
269 
270 /// State tracked per register.
271 /// The main algorithm walks backwards over a basic block maintaining this
272 /// datastructure for each tracked general purpose register.
273 struct LOHInfo {
274   MCLOHType Type : 8;           ///< "Best" type of LOH possible.
275   bool IsCandidate : 1;         ///< Possible LOH candidate.
276   bool OneUser : 1;             ///< Found exactly one user (yet).
277   bool MultiUsers : 1;          ///< Found multiple users.
278   const MachineInstr *MI0;      ///< First instruction involved in the LOH.
279   const MachineInstr *MI1;      ///< Second instruction involved in the LOH
280                                 ///  (if any).
281   const MachineInstr *LastADRP; ///< Last ADRP in same register.
282 };
283 
284 /// Update state \p Info given \p MI uses the tracked register.
285 static void handleUse(const MachineInstr &MI, const MachineOperand &MO,
286                       LOHInfo &Info) {
287   // We have multiple uses if we already found one before.
288   if (Info.MultiUsers || Info.OneUser) {
289     Info.IsCandidate = false;
290     Info.MultiUsers = true;
291     return;
292   }
293   Info.OneUser = true;
294 
295   // Start new LOHInfo if applicable.
296   if (isCandidateLoad(MI)) {
297     Info.Type = MCLOH_AdrpLdr;
298     Info.IsCandidate = true;
299     Info.MI0 = &MI;
300     // Note that even this is AdrpLdr now, we can switch to a Ldr variant
301     // later.
302   } else if (isCandidateStore(MI, MO)) {
303     Info.Type = MCLOH_AdrpAddStr;
304     Info.IsCandidate = true;
305     Info.MI0 = &MI;
306     Info.MI1 = nullptr;
307   } else if (MI.getOpcode() == AArch64::ADDXri) {
308     Info.Type = MCLOH_AdrpAdd;
309     Info.IsCandidate = true;
310     Info.MI0 = &MI;
311   } else if ((MI.getOpcode() == AArch64::LDRXui ||
312               MI.getOpcode() == AArch64::LDRWui) &&
313              MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT) {
314     Info.Type = MCLOH_AdrpLdrGot;
315     Info.IsCandidate = true;
316     Info.MI0 = &MI;
317   }
318 }
319 
320 /// Update state \p Info given the tracked register is clobbered.
321 static void handleClobber(LOHInfo &Info) {
322   Info.IsCandidate = false;
323   Info.OneUser = false;
324   Info.MultiUsers = false;
325   Info.LastADRP = nullptr;
326 }
327 
328 /// Update state \p Info given that \p MI is possibly the middle instruction
329 /// of an LOH involving 3 instructions.
330 static bool handleMiddleInst(const MachineInstr &MI, LOHInfo &DefInfo,
331                              LOHInfo &OpInfo) {
332   if (!DefInfo.IsCandidate || (&DefInfo != &OpInfo && OpInfo.OneUser))
333     return false;
334   // Copy LOHInfo for dest register to LOHInfo for source register.
335   if (&DefInfo != &OpInfo) {
336     OpInfo = DefInfo;
337     // Invalidate \p DefInfo because we track it in \p OpInfo now.
338     handleClobber(DefInfo);
339   } else
340     DefInfo.LastADRP = nullptr;
341 
342   // Advance state machine.
343   assert(OpInfo.IsCandidate && "Expect valid state");
344   if (MI.getOpcode() == AArch64::ADDXri && canAddBePartOfLOH(MI)) {
345     if (OpInfo.Type == MCLOH_AdrpLdr) {
346       OpInfo.Type = MCLOH_AdrpAddLdr;
347       OpInfo.IsCandidate = true;
348       OpInfo.MI1 = &MI;
349       return true;
350     } else if (OpInfo.Type == MCLOH_AdrpAddStr && OpInfo.MI1 == nullptr) {
351       OpInfo.Type = MCLOH_AdrpAddStr;
352       OpInfo.IsCandidate = true;
353       OpInfo.MI1 = &MI;
354       return true;
355     }
356   } else {
357     assert((MI.getOpcode() == AArch64::LDRXui ||
358             MI.getOpcode() == AArch64::LDRWui) &&
359            "Expect LDRXui or LDRWui");
360     assert((MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT) &&
361            "Expected GOT relocation");
362     if (OpInfo.Type == MCLOH_AdrpAddStr && OpInfo.MI1 == nullptr) {
363       OpInfo.Type = MCLOH_AdrpLdrGotStr;
364       OpInfo.IsCandidate = true;
365       OpInfo.MI1 = &MI;
366       return true;
367     } else if (OpInfo.Type == MCLOH_AdrpLdr) {
368       OpInfo.Type = MCLOH_AdrpLdrGotLdr;
369       OpInfo.IsCandidate = true;
370       OpInfo.MI1 = &MI;
371       return true;
372     }
373   }
374   return false;
375 }
376 
377 /// Update state when seeing and ADRP instruction.
378 static void handleADRP(const MachineInstr &MI, AArch64FunctionInfo &AFI,
379                        LOHInfo &Info, LOHInfo *LOHInfos) {
380   if (Info.LastADRP != nullptr) {
381     LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAdrp:\n"
382                       << '\t' << MI << '\t' << *Info.LastADRP);
383     AFI.addLOHDirective(MCLOH_AdrpAdrp, {&MI, Info.LastADRP});
384     ++NumADRPSimpleCandidate;
385   }
386 
387   // Produce LOH directive if possible.
388   if (Info.IsCandidate) {
389     switch (Info.Type) {
390     case MCLOH_AdrpAdd: {
391       // ADRPs and ADDs for this candidate may be split apart if using
392       // GlobalISel instead of pseudo-expanded. If that happens, the
393       // def register of the ADD may have a use in between. Adding an LOH in
394       // this case can cause the linker to rewrite the ADRP to write to that
395       // register, clobbering the use.
396       const MachineInstr *AddMI = Info.MI0;
397       int DefIdx = mapRegToGPRIndex(MI.getOperand(0).getReg());
398       int OpIdx = mapRegToGPRIndex(AddMI->getOperand(0).getReg());
399       LOHInfo DefInfo = LOHInfos[OpIdx];
400       if (DefIdx != OpIdx && (DefInfo.OneUser || DefInfo.MultiUsers))
401         break;
402       LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAdd:\n"
403                         << '\t' << MI << '\t' << *Info.MI0);
404       AFI.addLOHDirective(MCLOH_AdrpAdd, {&MI, Info.MI0});
405       ++NumADRSimpleCandidate;
406       break;
407     }
408     case MCLOH_AdrpLdr:
409       if (supportLoadFromLiteral(*Info.MI0)) {
410         LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpLdr:\n"
411                           << '\t' << MI << '\t' << *Info.MI0);
412         AFI.addLOHDirective(MCLOH_AdrpLdr, {&MI, Info.MI0});
413         ++NumADRPToLDR;
414       }
415       break;
416     case MCLOH_AdrpAddLdr: {
417       // There is a possibility that the linker may try to rewrite:
418       // adrp x0, @sym@PAGE
419       // add x1, x0, @sym@PAGEOFF
420       // [x0 = some other def]
421       // ldr x2, [x1]
422       //    ...into...
423       // adrp x0, @sym
424       // nop
425       // [x0 = some other def]
426       // ldr x2, [x0]
427       // ...if the offset to the symbol won't fit within a literal load.
428       // This causes the load to use the result of the adrp, which in this
429       // case has already been clobbered.
430       // FIXME: Implement proper liveness tracking for all registers. For now,
431       // don't emit the LOH if there are any instructions between the add and
432       // the ldr.
433       MachineInstr *AddMI = const_cast<MachineInstr *>(Info.MI1);
434       const MachineInstr *LdrMI = Info.MI0;
435       auto AddIt = MachineBasicBlock::iterator(AddMI);
436       auto EndIt = AddMI->getParent()->end();
437       if (AddMI->getIterator() == EndIt || LdrMI != &*next_nodbg(AddIt, EndIt))
438         break;
439 
440       LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAddLdr:\n"
441                         << '\t' << MI << '\t' << *Info.MI1 << '\t'
442                         << *Info.MI0);
443       AFI.addLOHDirective(MCLOH_AdrpAddLdr, {&MI, Info.MI1, Info.MI0});
444       ++NumADDToLDR;
445       break;
446     }
447     case MCLOH_AdrpAddStr:
448       if (Info.MI1 != nullptr) {
449         LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAddStr:\n"
450                           << '\t' << MI << '\t' << *Info.MI1 << '\t'
451                           << *Info.MI0);
452         AFI.addLOHDirective(MCLOH_AdrpAddStr, {&MI, Info.MI1, Info.MI0});
453         ++NumADDToSTR;
454       }
455       break;
456     case MCLOH_AdrpLdrGotLdr:
457       LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpLdrGotLdr:\n"
458                         << '\t' << MI << '\t' << *Info.MI1 << '\t'
459                         << *Info.MI0);
460       AFI.addLOHDirective(MCLOH_AdrpLdrGotLdr, {&MI, Info.MI1, Info.MI0});
461       ++NumLDRToLDR;
462       break;
463     case MCLOH_AdrpLdrGotStr:
464       LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpLdrGotStr:\n"
465                         << '\t' << MI << '\t' << *Info.MI1 << '\t'
466                         << *Info.MI0);
467       AFI.addLOHDirective(MCLOH_AdrpLdrGotStr, {&MI, Info.MI1, Info.MI0});
468       ++NumLDRToSTR;
469       break;
470     case MCLOH_AdrpLdrGot:
471       LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpLdrGot:\n"
472                         << '\t' << MI << '\t' << *Info.MI0);
473       AFI.addLOHDirective(MCLOH_AdrpLdrGot, {&MI, Info.MI0});
474       break;
475     case MCLOH_AdrpAdrp:
476       llvm_unreachable("MCLOH_AdrpAdrp not used in state machine");
477     }
478   }
479 
480   handleClobber(Info);
481   Info.LastADRP = &MI;
482 }
483 
484 static void handleRegMaskClobber(const uint32_t *RegMask, MCPhysReg Reg,
485                                  LOHInfo *LOHInfos) {
486   if (!MachineOperand::clobbersPhysReg(RegMask, Reg))
487     return;
488   int Idx = mapRegToGPRIndex(Reg);
489   if (Idx >= 0)
490     handleClobber(LOHInfos[Idx]);
491 }
492 
493 static void handleNormalInst(const MachineInstr &MI, LOHInfo *LOHInfos) {
494   // Handle defs and regmasks.
495   for (const MachineOperand &MO : MI.operands()) {
496     if (MO.isRegMask()) {
497       const uint32_t *RegMask = MO.getRegMask();
498       for (MCPhysReg Reg : AArch64::GPR32RegClass)
499         handleRegMaskClobber(RegMask, Reg, LOHInfos);
500       for (MCPhysReg Reg : AArch64::GPR64RegClass)
501         handleRegMaskClobber(RegMask, Reg, LOHInfos);
502       continue;
503     }
504     if (!MO.isReg() || !MO.isDef())
505       continue;
506     int Idx = mapRegToGPRIndex(MO.getReg());
507     if (Idx < 0)
508       continue;
509     handleClobber(LOHInfos[Idx]);
510   }
511   // Handle uses.
512 
513   SmallSet<int, 4> UsesSeen;
514   for (const MachineOperand &MO : MI.uses()) {
515     if (!MO.isReg() || !MO.readsReg())
516       continue;
517     int Idx = mapRegToGPRIndex(MO.getReg());
518     if (Idx < 0)
519       continue;
520 
521     // Multiple uses of the same register within a single instruction don't
522     // count as MultiUser or block optimization. This is especially important on
523     // arm64_32, where any memory operation is likely to be an explicit use of
524     // xN and an implicit use of wN (the base address register).
525     if (UsesSeen.insert(Idx).second)
526       handleUse(MI, MO, LOHInfos[Idx]);
527   }
528 }
529 
530 bool AArch64CollectLOH::runOnMachineFunction(MachineFunction &MF) {
531   if (skipFunction(MF.getFunction()))
532     return false;
533 
534   LLVM_DEBUG(dbgs() << "********** AArch64 Collect LOH **********\n"
535                     << "Looking in function " << MF.getName() << '\n');
536 
537   LOHInfo LOHInfos[N_GPR_REGS];
538   AArch64FunctionInfo &AFI = *MF.getInfo<AArch64FunctionInfo>();
539   for (const MachineBasicBlock &MBB : MF) {
540     // Reset register tracking state.
541     memset(LOHInfos, 0, sizeof(LOHInfos));
542     // Live-out registers are used.
543     for (const MachineBasicBlock *Succ : MBB.successors()) {
544       for (const auto &LI : Succ->liveins()) {
545         int RegIdx = mapRegToGPRIndex(LI.PhysReg);
546         if (RegIdx >= 0)
547           LOHInfos[RegIdx].OneUser = true;
548       }
549     }
550 
551     // Walk the basic block backwards and update the per register state machine
552     // in the process.
553     for (const MachineInstr &MI :
554          instructionsWithoutDebug(MBB.instr_rbegin(), MBB.instr_rend())) {
555       unsigned Opcode = MI.getOpcode();
556       switch (Opcode) {
557       case AArch64::ADDXri:
558       case AArch64::LDRXui:
559       case AArch64::LDRWui:
560         if (canDefBePartOfLOH(MI)) {
561           const MachineOperand &Def = MI.getOperand(0);
562           const MachineOperand &Op = MI.getOperand(1);
563           assert(Def.isReg() && Def.isDef() && "Expected reg def");
564           assert(Op.isReg() && Op.isUse() && "Expected reg use");
565           int DefIdx = mapRegToGPRIndex(Def.getReg());
566           int OpIdx = mapRegToGPRIndex(Op.getReg());
567           if (DefIdx >= 0 && OpIdx >= 0 &&
568               handleMiddleInst(MI, LOHInfos[DefIdx], LOHInfos[OpIdx]))
569             continue;
570         }
571         break;
572       case AArch64::ADRP:
573         const MachineOperand &Op0 = MI.getOperand(0);
574         int Idx = mapRegToGPRIndex(Op0.getReg());
575         if (Idx >= 0) {
576           handleADRP(MI, AFI, LOHInfos[Idx], LOHInfos);
577           continue;
578         }
579         break;
580       }
581       handleNormalInst(MI, LOHInfos);
582     }
583   }
584 
585   // Return "no change": The pass only collects information.
586   return false;
587 }
588 
589 FunctionPass *llvm::createAArch64CollectLOHPass() {
590   return new AArch64CollectLOH();
591 }
592