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