blob: 720323f81d29ca4ce047a59dc5792c659c1f63a2 [file] [log] [blame]
Tim Northover3b0846e2014-05-24 12:50:23 +00001//===---------- AArch64CollectLOH.cpp - AArch64 collect LOH pass --*- C++ -*-=//
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//
10// This file contains a pass that collect the Linker Optimization Hint (LOH).
11// This pass should be run at the very end of the compilation flow, just before
12// assembly printer.
13// To be useful for the linker, the LOH must be printed into the assembly file.
14//
15// A LOH describes a sequence of instructions that may be optimized by the
16// linker.
17// This same sequence cannot be optimized by the compiler because some of
18// the information will be known at link time.
19// For instance, consider the following sequence:
20// L1: adrp xA, sym@PAGE
21// L2: add xB, xA, sym@PAGEOFF
22// L3: ldr xC, [xB, #imm]
23// This sequence can be turned into:
24// A literal load if sym@PAGE + sym@PAGEOFF + #imm - address(L3) is < 1MB:
25// L3: ldr xC, sym+#imm
26// It may also be turned into either the following more efficient
27// code sequences:
28// - If sym@PAGEOFF + #imm fits the encoding space of L3.
29// L1: adrp xA, sym@PAGE
30// L3: ldr xC, [xB, sym@PAGEOFF + #imm]
31// - If sym@PAGE + sym@PAGEOFF - address(L1) < 1MB:
32// L1: adr xA, sym
33// L3: ldr xC, [xB, #imm]
34//
35// To be valid a LOH must meet all the requirements needed by all the related
36// possible linker transformations.
37// For instance, using the running example, the constraints to emit
38// ".loh AdrpAddLdr" are:
39// - L1, L2, and L3 instructions are of the expected type, i.e.,
40// respectively ADRP, ADD (immediate), and LD.
41// - The result of L1 is used only by L2.
42// - The register argument (xA) used in the ADD instruction is defined
43// only by L1.
44// - The result of L2 is used only by L3.
45// - The base address (xB) in L3 is defined only L2.
46// - The ADRP in L1 and the ADD in L2 must reference the same symbol using
47// @PAGE/@PAGEOFF with no additional constants
48//
49// Currently supported LOHs are:
50// * So called non-ADRP-related:
51// - .loh AdrpAddLdr L1, L2, L3:
52// L1: adrp xA, sym@PAGE
53// L2: add xB, xA, sym@PAGEOFF
54// L3: ldr xC, [xB, #imm]
55// - .loh AdrpLdrGotLdr L1, L2, L3:
56// L1: adrp xA, sym@GOTPAGE
57// L2: ldr xB, [xA, sym@GOTPAGEOFF]
58// L3: ldr xC, [xB, #imm]
59// - .loh AdrpLdr L1, L3:
60// L1: adrp xA, sym@PAGE
61// L3: ldr xC, [xA, sym@PAGEOFF]
62// - .loh AdrpAddStr L1, L2, L3:
63// L1: adrp xA, sym@PAGE
64// L2: add xB, xA, sym@PAGEOFF
65// L3: str xC, [xB, #imm]
66// - .loh AdrpLdrGotStr L1, L2, L3:
67// L1: adrp xA, sym@GOTPAGE
68// L2: ldr xB, [xA, sym@GOTPAGEOFF]
69// L3: str xC, [xB, #imm]
70// - .loh AdrpAdd L1, L2:
71// L1: adrp xA, sym@PAGE
72// L2: add xB, xA, sym@PAGEOFF
73// For all these LOHs, L1, L2, L3 form a simple chain:
74// L1 result is used only by L2 and L2 result by L3.
75// L3 LOH-related argument is defined only by L2 and L2 LOH-related argument
76// by L1.
77// All these LOHs aim at using more efficient load/store patterns by folding
78// some instructions used to compute the address directly into the load/store.
79//
80// * So called ADRP-related:
81// - .loh AdrpAdrp L2, L1:
82// L2: ADRP xA, sym1@PAGE
83// L1: ADRP xA, sym2@PAGE
84// L2 dominates L1 and xA is not redifined between L2 and L1
85// This LOH aims at getting rid of redundant ADRP instructions.
86//
87// The overall design for emitting the LOHs is:
88// 1. AArch64CollectLOH (this pass) records the LOHs in the AArch64FunctionInfo.
89// 2. AArch64AsmPrinter reads the LOHs from AArch64FunctionInfo and it:
90// 1. Associates them a label.
91// 2. Emits them in a MCStreamer (EmitLOHDirective).
92// - The MCMachOStreamer records them into the MCAssembler.
93// - The MCAsmStreamer prints them.
94// - Other MCStreamers ignore them.
95// 3. Closes the MCStreamer:
96// - The MachObjectWriter gets them from the MCAssembler and writes
97// them in the object file.
98// - Other ObjectWriters ignore them.
99//===----------------------------------------------------------------------===//
100
101#include "AArch64.h"
102#include "AArch64InstrInfo.h"
103#include "AArch64MachineFunctionInfo.h"
Tim Northover3b0846e2014-05-24 12:50:23 +0000104#include "llvm/ADT/BitVector.h"
105#include "llvm/ADT/DenseMap.h"
106#include "llvm/ADT/MapVector.h"
Tim Northover3b0846e2014-05-24 12:50:23 +0000107#include "llvm/ADT/SmallVector.h"
Benjamin Kramer1f8930e2014-07-25 11:42:14 +0000108#include "llvm/ADT/Statistic.h"
Tim Northover3b0846e2014-05-24 12:50:23 +0000109#include "llvm/CodeGen/MachineBasicBlock.h"
Tim Northover3b0846e2014-05-24 12:50:23 +0000110#include "llvm/CodeGen/MachineFunctionPass.h"
111#include "llvm/CodeGen/MachineInstr.h"
David Blaikieb3bde2e2017-11-17 01:07:10 +0000112#include "llvm/CodeGen/TargetRegisterInfo.h"
Tim Northover3b0846e2014-05-24 12:50:23 +0000113#include "llvm/Support/Debug.h"
114#include "llvm/Support/ErrorHandling.h"
115#include "llvm/Support/raw_ostream.h"
Benjamin Kramer1f8930e2014-07-25 11:42:14 +0000116#include "llvm/Target/TargetMachine.h"
Tim Northover3b0846e2014-05-24 12:50:23 +0000117using namespace llvm;
118
119#define DEBUG_TYPE "aarch64-collect-loh"
120
Tim Northover3b0846e2014-05-24 12:50:23 +0000121STATISTIC(NumADRPSimpleCandidate,
122 "Number of simplifiable ADRP dominate by another");
Tim Northover3b0846e2014-05-24 12:50:23 +0000123STATISTIC(NumADDToSTR, "Number of simplifiable STR reachable by ADD");
124STATISTIC(NumLDRToSTR, "Number of simplifiable STR reachable by LDR");
Tim Northover3b0846e2014-05-24 12:50:23 +0000125STATISTIC(NumADDToLDR, "Number of simplifiable LDR reachable by ADD");
126STATISTIC(NumLDRToLDR, "Number of simplifiable LDR reachable by LDR");
127STATISTIC(NumADRPToLDR, "Number of simplifiable LDR reachable by ADRP");
Tim Northover3b0846e2014-05-24 12:50:23 +0000128STATISTIC(NumADRSimpleCandidate, "Number of simplifiable ADRP + ADD");
Tim Northover3b0846e2014-05-24 12:50:23 +0000129
Chad Rosier084b7862015-08-05 14:48:44 +0000130#define AARCH64_COLLECT_LOH_NAME "AArch64 Collect Linker Optimization Hint (LOH)"
131
Tim Northover3b0846e2014-05-24 12:50:23 +0000132namespace {
Matthias Braun258b847c2017-01-06 19:22:01 +0000133
Tim Northover3b0846e2014-05-24 12:50:23 +0000134struct AArch64CollectLOH : public MachineFunctionPass {
135 static char ID;
Matthias Braun258b847c2017-01-06 19:22:01 +0000136 AArch64CollectLOH() : MachineFunctionPass(ID) {}
Tim Northover3b0846e2014-05-24 12:50:23 +0000137
138 bool runOnMachineFunction(MachineFunction &MF) override;
139
Derek Schuff1dbf7a52016-04-04 17:09:25 +0000140 MachineFunctionProperties getRequiredProperties() const override {
141 return MachineFunctionProperties().set(
Matthias Braun1eb47362016-08-25 01:27:13 +0000142 MachineFunctionProperties::Property::NoVRegs);
Derek Schuff1dbf7a52016-04-04 17:09:25 +0000143 }
144
Mehdi Amini117296c2016-10-01 02:56:57 +0000145 StringRef getPassName() const override { return AARCH64_COLLECT_LOH_NAME; }
Tim Northover3b0846e2014-05-24 12:50:23 +0000146
147 void getAnalysisUsage(AnalysisUsage &AU) const override {
Matthias Braun15b56e62016-12-17 18:53:11 +0000148 MachineFunctionPass::getAnalysisUsage(AU);
Matthias Braun258b847c2017-01-06 19:22:01 +0000149 AU.setPreservesAll();
Tim Northover3b0846e2014-05-24 12:50:23 +0000150 }
Tim Northover3b0846e2014-05-24 12:50:23 +0000151};
152
Tim Northover3b0846e2014-05-24 12:50:23 +0000153char AArch64CollectLOH::ID = 0;
154
Matthias Braun258b847c2017-01-06 19:22:01 +0000155} // end anonymous namespace.
Tim Northover3b0846e2014-05-24 12:50:23 +0000156
Matthias Braun258b847c2017-01-06 19:22:01 +0000157INITIALIZE_PASS(AArch64CollectLOH, "aarch64-collect-loh",
158 AARCH64_COLLECT_LOH_NAME, false, false)
Tim Northover3b0846e2014-05-24 12:50:23 +0000159
Matthias Braun258b847c2017-01-06 19:22:01 +0000160static 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;
Tim Northover3b0846e2014-05-24 12:50:23 +0000170 }
171}
172
Tim Northover3b0846e2014-05-24 12:50:23 +0000173/// Answer the following question: Can Def be one of the definition
174/// involved in a part of a LOH?
Matthias Braun258b847c2017-01-06 19:22:01 +0000175static bool canDefBePartOfLOH(const MachineInstr &MI) {
Tim Northover3b0846e2014-05-24 12:50:23 +0000176 // Accept ADRP, ADDLow and LOADGot.
Matthias Braun258b847c2017-01-06 19:22:01 +0000177 switch (MI.getOpcode()) {
Tim Northover3b0846e2014-05-24 12:50:23 +0000178 default:
179 return false;
180 case AArch64::ADRP:
181 return true;
182 case AArch64::ADDXri:
Matthias Braun258b847c2017-01-06 19:22:01 +0000183 return canAddBePartOfLOH(MI);
Matthias Braun15b56e62016-12-17 18:53:11 +0000184 case AArch64::LDRXui:
185 // Check immediate to see if the immediate is an address.
Matthias Braun258b847c2017-01-06 19:22:01 +0000186 switch (MI.getOperand(2).getType()) {
Matthias Braun15b56e62016-12-17 18:53:11 +0000187 default:
188 return false;
189 case MachineOperand::MO_GlobalAddress:
Matthias Braun258b847c2017-01-06 19:22:01 +0000190 return MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT;
Tim Northover3b0846e2014-05-24 12:50:23 +0000191 }
192 }
Tim Northover3b0846e2014-05-24 12:50:23 +0000193}
194
195/// Check whether the given instruction can the end of a LOH chain involving a
196/// store.
Matthias Braun258b847c2017-01-06 19:22:01 +0000197static bool isCandidateStore(const MachineInstr &MI, const MachineOperand &MO) {
198 switch (MI.getOpcode()) {
Tim Northover3b0846e2014-05-24 12:50:23 +0000199 default:
200 return false;
Quentin Colombetfa4ecb42015-08-27 23:47:10 +0000201 case AArch64::STRBBui:
202 case AArch64::STRHHui:
Tim Northover3b0846e2014-05-24 12:50:23 +0000203 case AArch64::STRBui:
204 case AArch64::STRHui:
205 case AArch64::STRWui:
206 case AArch64::STRXui:
207 case AArch64::STRSui:
208 case AArch64::STRDui:
209 case AArch64::STRQui:
Matthias Braun258b847c2017-01-06 19:22:01 +0000210 // We can only optimize the index operand.
Tim Northover3b0846e2014-05-24 12:50:23 +0000211 // In case we have str xA, [xA, #imm], this is two different uses
212 // of xA and we cannot fold, otherwise the xA stored may be wrong,
213 // even if #imm == 0.
Matthias Braun258b847c2017-01-06 19:22:01 +0000214 return MI.getOperandNo(&MO) == 1 &&
215 MI.getOperand(0).getReg() != MI.getOperand(1).getReg();
Tim Northover3b0846e2014-05-24 12:50:23 +0000216 }
217}
218
219/// Check whether the given instruction can be the end of a LOH chain
220/// involving a load.
Matthias Braun258b847c2017-01-06 19:22:01 +0000221static bool isCandidateLoad(const MachineInstr &MI) {
222 switch (MI.getOpcode()) {
Tim Northover3b0846e2014-05-24 12:50:23 +0000223 default:
224 return false;
225 case AArch64::LDRSBWui:
226 case AArch64::LDRSBXui:
227 case AArch64::LDRSHWui:
228 case AArch64::LDRSHXui:
229 case AArch64::LDRSWui:
230 case AArch64::LDRBui:
231 case AArch64::LDRHui:
232 case AArch64::LDRWui:
233 case AArch64::LDRXui:
234 case AArch64::LDRSui:
235 case AArch64::LDRDui:
236 case AArch64::LDRQui:
Matthias Braun258b847c2017-01-06 19:22:01 +0000237 return !(MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT);
Tim Northover3b0846e2014-05-24 12:50:23 +0000238 }
Tim Northover3b0846e2014-05-24 12:50:23 +0000239}
240
241/// Check whether the given instruction can load a litteral.
Matthias Braun258b847c2017-01-06 19:22:01 +0000242static bool supportLoadFromLiteral(const MachineInstr &MI) {
243 switch (MI.getOpcode()) {
Tim Northover3b0846e2014-05-24 12:50:23 +0000244 default:
245 return false;
246 case AArch64::LDRSWui:
247 case AArch64::LDRWui:
248 case AArch64::LDRXui:
249 case AArch64::LDRSui:
250 case AArch64::LDRDui:
251 case AArch64::LDRQui:
252 return true;
253 }
Matthias Braune813cf42016-12-17 01:15:59 +0000254}
255
Matthias Braun258b847c2017-01-06 19:22:01 +0000256/// Number of GPR registers traked by mapRegToGPRIndex()
257static const unsigned N_GPR_REGS = 31;
258/// Map register number to index from 0-30.
259static int mapRegToGPRIndex(MCPhysReg Reg) {
260 static_assert(AArch64::X28 - AArch64::X0 + 3 == N_GPR_REGS, "Number of GPRs");
261 static_assert(AArch64::W30 - AArch64::W0 + 1 == N_GPR_REGS, "Number of GPRs");
262 if (AArch64::X0 <= Reg && Reg <= AArch64::X28)
263 return Reg - AArch64::X0;
264 if (AArch64::W0 <= Reg && Reg <= AArch64::W30)
265 return Reg - AArch64::W0;
266 // TableGen gives "FP" and "LR" an index not adjacent to X28 so we have to
267 // handle them as special cases.
268 if (Reg == AArch64::FP)
269 return 29;
270 if (Reg == AArch64::LR)
271 return 30;
272 return -1;
Matthias Braun15b56e62016-12-17 18:53:11 +0000273}
274
Matthias Braun258b847c2017-01-06 19:22:01 +0000275/// State tracked per register.
276/// The main algorithm walks backwards over a basic block maintaining this
277/// datastructure for each tracked general purpose register.
278struct LOHInfo {
279 MCLOHType Type : 8; ///< "Best" type of LOH possible.
280 bool IsCandidate : 1; ///< Possible LOH candidate.
281 bool OneUser : 1; ///< Found exactly one user (yet).
282 bool MultiUsers : 1; ///< Found multiple users.
283 const MachineInstr *MI0; ///< First instruction involved in the LOH.
284 const MachineInstr *MI1; ///< Second instruction involved in the LOH
285 /// (if any).
286 const MachineInstr *LastADRP; ///< Last ADRP in same register.
287};
Matthias Braun15b56e62016-12-17 18:53:11 +0000288
Matthias Braun258b847c2017-01-06 19:22:01 +0000289/// Update state \p Info given \p MI uses the tracked register.
290static void handleUse(const MachineInstr &MI, const MachineOperand &MO,
291 LOHInfo &Info) {
292 // We have multiple uses if we already found one before.
293 if (Info.MultiUsers || Info.OneUser) {
294 Info.IsCandidate = false;
295 Info.MultiUsers = true;
Matthias Braune813cf42016-12-17 01:15:59 +0000296 return;
Matthias Braune813cf42016-12-17 01:15:59 +0000297 }
Matthias Braun258b847c2017-01-06 19:22:01 +0000298 Info.OneUser = true;
Matthias Braun15b56e62016-12-17 18:53:11 +0000299
Matthias Braun258b847c2017-01-06 19:22:01 +0000300 // Start new LOHInfo if applicable.
301 if (isCandidateLoad(MI)) {
302 Info.Type = MCLOH_AdrpLdr;
303 Info.IsCandidate = true;
304 Info.MI0 = &MI;
305 // Note that even this is AdrpLdr now, we can switch to a Ldr variant
306 // later.
307 } else if (isCandidateStore(MI, MO)) {
308 Info.Type = MCLOH_AdrpAddStr;
309 Info.IsCandidate = true;
310 Info.MI0 = &MI;
311 Info.MI1 = nullptr;
312 } else if (MI.getOpcode() == AArch64::ADDXri) {
313 Info.Type = MCLOH_AdrpAdd;
314 Info.IsCandidate = true;
315 Info.MI0 = &MI;
316 } else if (MI.getOpcode() == AArch64::LDRXui &&
317 MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT) {
318 Info.Type = MCLOH_AdrpLdrGot;
319 Info.IsCandidate = true;
320 Info.MI0 = &MI;
321 }
322}
Matthias Braun15b56e62016-12-17 18:53:11 +0000323
Matthias Braun258b847c2017-01-06 19:22:01 +0000324/// Update state \p Info given the tracked register is clobbered.
325static void handleClobber(LOHInfo &Info) {
326 Info.IsCandidate = false;
327 Info.OneUser = false;
328 Info.MultiUsers = false;
329 Info.LastADRP = nullptr;
330}
331
332/// Update state \p Info given that \p MI is possibly the middle instruction
333/// of an LOH involving 3 instructions.
334static bool handleMiddleInst(const MachineInstr &MI, LOHInfo &DefInfo,
335 LOHInfo &OpInfo) {
336 if (!DefInfo.IsCandidate || (&DefInfo != &OpInfo && OpInfo.OneUser))
337 return false;
338 // Copy LOHInfo for dest register to LOHInfo for source register.
339 if (&DefInfo != &OpInfo) {
340 OpInfo = DefInfo;
341 // Invalidate \p DefInfo because we track it in \p OpInfo now.
342 handleClobber(DefInfo);
343 } else
344 DefInfo.LastADRP = nullptr;
345
346 // Advance state machine.
347 assert(OpInfo.IsCandidate && "Expect valid state");
348 if (MI.getOpcode() == AArch64::ADDXri && canAddBePartOfLOH(MI)) {
349 if (OpInfo.Type == MCLOH_AdrpLdr) {
350 OpInfo.Type = MCLOH_AdrpAddLdr;
351 OpInfo.IsCandidate = true;
352 OpInfo.MI1 = &MI;
353 return true;
354 } else if (OpInfo.Type == MCLOH_AdrpAddStr && OpInfo.MI1 == nullptr) {
355 OpInfo.Type = MCLOH_AdrpAddStr;
356 OpInfo.IsCandidate = true;
357 OpInfo.MI1 = &MI;
358 return true;
Matthias Braun15b56e62016-12-17 18:53:11 +0000359 }
Matthias Braun258b847c2017-01-06 19:22:01 +0000360 } else {
361 assert(MI.getOpcode() == AArch64::LDRXui && "Expect LDRXui");
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.
380static void handleADRP(const MachineInstr &MI, AArch64FunctionInfo &AFI,
381 LOHInfo &Info) {
382 if (Info.LastADRP != nullptr) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000383 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAdrp:\n"
384 << '\t' << MI << '\t' << *Info.LastADRP);
Matthias Braun258b847c2017-01-06 19:22:01 +0000385 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:
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000393 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAdd:\n"
394 << '\t' << MI << '\t' << *Info.MI0);
Matthias Braun258b847c2017-01-06 19:22:01 +0000395 AFI.addLOHDirective(MCLOH_AdrpAdd, {&MI, Info.MI0});
396 ++NumADRSimpleCandidate;
397 break;
398 case MCLOH_AdrpLdr:
399 if (supportLoadFromLiteral(*Info.MI0)) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000400 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpLdr:\n"
401 << '\t' << MI << '\t' << *Info.MI0);
Matthias Braun258b847c2017-01-06 19:22:01 +0000402 AFI.addLOHDirective(MCLOH_AdrpLdr, {&MI, Info.MI0});
403 ++NumADRPToLDR;
404 }
405 break;
406 case MCLOH_AdrpAddLdr:
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000407 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAddLdr:\n"
408 << '\t' << MI << '\t' << *Info.MI1 << '\t'
409 << *Info.MI0);
Matthias Braun258b847c2017-01-06 19:22:01 +0000410 AFI.addLOHDirective(MCLOH_AdrpAddLdr, {&MI, Info.MI1, Info.MI0});
411 ++NumADDToLDR;
412 break;
413 case MCLOH_AdrpAddStr:
414 if (Info.MI1 != nullptr) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000415 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAddStr:\n"
416 << '\t' << MI << '\t' << *Info.MI1 << '\t'
417 << *Info.MI0);
Matthias Braun258b847c2017-01-06 19:22:01 +0000418 AFI.addLOHDirective(MCLOH_AdrpAddStr, {&MI, Info.MI1, Info.MI0});
419 ++NumADDToSTR;
420 }
421 break;
422 case MCLOH_AdrpLdrGotLdr:
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000423 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpLdrGotLdr:\n"
424 << '\t' << MI << '\t' << *Info.MI1 << '\t'
425 << *Info.MI0);
Matthias Braun258b847c2017-01-06 19:22:01 +0000426 AFI.addLOHDirective(MCLOH_AdrpLdrGotLdr, {&MI, Info.MI1, Info.MI0});
427 ++NumLDRToLDR;
428 break;
429 case MCLOH_AdrpLdrGotStr:
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000430 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpLdrGotStr:\n"
431 << '\t' << MI << '\t' << *Info.MI1 << '\t'
432 << *Info.MI0);
Matthias Braun258b847c2017-01-06 19:22:01 +0000433 AFI.addLOHDirective(MCLOH_AdrpLdrGotStr, {&MI, Info.MI1, Info.MI0});
434 ++NumLDRToSTR;
435 break;
436 case MCLOH_AdrpLdrGot:
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000437 LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpLdrGot:\n"
438 << '\t' << MI << '\t' << *Info.MI0);
Matthias Braun258b847c2017-01-06 19:22:01 +0000439 AFI.addLOHDirective(MCLOH_AdrpLdrGot, {&MI, Info.MI0});
440 break;
441 case MCLOH_AdrpAdrp:
442 llvm_unreachable("MCLOH_AdrpAdrp not used in state machine");
443 }
444 }
445
446 handleClobber(Info);
447 Info.LastADRP = &MI;
448}
449
450static void handleRegMaskClobber(const uint32_t *RegMask, MCPhysReg Reg,
451 LOHInfo *LOHInfos) {
452 if (!MachineOperand::clobbersPhysReg(RegMask, Reg))
453 return;
454 int Idx = mapRegToGPRIndex(Reg);
455 if (Idx >= 0)
456 handleClobber(LOHInfos[Idx]);
457}
458
459static void handleNormalInst(const MachineInstr &MI, LOHInfo *LOHInfos) {
460 // Handle defs and regmasks.
461 for (const MachineOperand &MO : MI.operands()) {
462 if (MO.isRegMask()) {
463 const uint32_t *RegMask = MO.getRegMask();
464 for (MCPhysReg Reg : AArch64::GPR32RegClass)
465 handleRegMaskClobber(RegMask, Reg, LOHInfos);
466 for (MCPhysReg Reg : AArch64::GPR64RegClass)
467 handleRegMaskClobber(RegMask, Reg, LOHInfos);
468 continue;
469 }
470 if (!MO.isReg() || !MO.isDef())
471 continue;
472 int Idx = mapRegToGPRIndex(MO.getReg());
473 if (Idx < 0)
474 continue;
475 handleClobber(LOHInfos[Idx]);
476 }
477 // Handle uses.
478 for (const MachineOperand &MO : MI.uses()) {
479 if (!MO.isReg() || !MO.readsReg())
480 continue;
481 int Idx = mapRegToGPRIndex(MO.getReg());
482 if (Idx < 0)
483 continue;
484 handleUse(MI, MO, LOHInfos[Idx]);
Tim Northover3b0846e2014-05-24 12:50:23 +0000485 }
486}
487
488bool AArch64CollectLOH::runOnMachineFunction(MachineFunction &MF) {
Matthias Braunf1caa282017-12-15 22:22:58 +0000489 if (skipFunction(MF.getFunction()))
Andrew Kaylor1ac98bb2016-04-25 21:58:52 +0000490 return false;
491
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000492 LLVM_DEBUG(dbgs() << "********** AArch64 Collect LOH **********\n"
493 << "Looking in function " << MF.getName() << '\n');
Tim Northover3b0846e2014-05-24 12:50:23 +0000494
Matthias Braun258b847c2017-01-06 19:22:01 +0000495 LOHInfo LOHInfos[N_GPR_REGS];
496 AArch64FunctionInfo &AFI = *MF.getInfo<AArch64FunctionInfo>();
497 for (const MachineBasicBlock &MBB : MF) {
498 // Reset register tracking state.
499 memset(LOHInfos, 0, sizeof(LOHInfos));
500 // Live-out registers are used.
501 for (const MachineBasicBlock *Succ : MBB.successors()) {
502 for (const auto &LI : Succ->liveins()) {
503 int RegIdx = mapRegToGPRIndex(LI.PhysReg);
504 if (RegIdx >= 0)
505 LOHInfos[RegIdx].OneUser = true;
506 }
507 }
Tim Northover3b0846e2014-05-24 12:50:23 +0000508
Matthias Braun258b847c2017-01-06 19:22:01 +0000509 // Walk the basic block backwards and update the per register state machine
510 // in the process.
511 for (const MachineInstr &MI : make_range(MBB.rbegin(), MBB.rend())) {
512 unsigned Opcode = MI.getOpcode();
513 switch (Opcode) {
514 case AArch64::ADDXri:
515 case AArch64::LDRXui:
516 if (canDefBePartOfLOH(MI)) {
517 const MachineOperand &Def = MI.getOperand(0);
518 const MachineOperand &Op = MI.getOperand(1);
519 assert(Def.isReg() && Def.isDef() && "Expected reg def");
520 assert(Op.isReg() && Op.isUse() && "Expected reg use");
521 int DefIdx = mapRegToGPRIndex(Def.getReg());
522 int OpIdx = mapRegToGPRIndex(Op.getReg());
523 if (DefIdx >= 0 && OpIdx >= 0 &&
524 handleMiddleInst(MI, LOHInfos[DefIdx], LOHInfos[OpIdx]))
525 continue;
526 }
527 break;
528 case AArch64::ADRP:
529 const MachineOperand &Op0 = MI.getOperand(0);
530 int Idx = mapRegToGPRIndex(Op0.getReg());
531 if (Idx >= 0) {
532 handleADRP(MI, AFI, LOHInfos[Idx]);
533 continue;
534 }
535 break;
536 }
537 handleNormalInst(MI, LOHInfos);
538 }
Tim Northover3b0846e2014-05-24 12:50:23 +0000539 }
540
Matthias Braun258b847c2017-01-06 19:22:01 +0000541 // Return "no change": The pass only collects information.
542 return false;
Tim Northover3b0846e2014-05-24 12:50:23 +0000543}
544
Tim Northover3b0846e2014-05-24 12:50:23 +0000545FunctionPass *llvm::createAArch64CollectLOHPass() {
546 return new AArch64CollectLOH();
547}