xref: /llvm-project/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp (revision 2f09f445b2d6b3ef197aecd8d1e06d08140380f3)
1*2f09f445SMaksim Panchenko //===- bolt/Target/AArch64/AArch64MCPlusBuilder.cpp -----------------------===//
2a34c753fSRafael Auler //
3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information.
5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a34c753fSRafael Auler //
7a34c753fSRafael Auler //===----------------------------------------------------------------------===//
8a34c753fSRafael Auler //
9*2f09f445SMaksim Panchenko // This file provides AArch64-specific MCPlus builder.
10a34c753fSRafael Auler //
11a34c753fSRafael Auler //===----------------------------------------------------------------------===//
12a34c753fSRafael Auler 
13a34c753fSRafael Auler #include "MCTargetDesc/AArch64AddressingModes.h"
14a34c753fSRafael Auler #include "MCTargetDesc/AArch64MCExpr.h"
15a34c753fSRafael Auler #include "MCTargetDesc/AArch64MCTargetDesc.h"
16a34c753fSRafael Auler #include "Utils/AArch64BaseInfo.h"
17a34c753fSRafael Auler #include "bolt/Core/MCPlusBuilder.h"
18a34c753fSRafael Auler #include "llvm/BinaryFormat/ELF.h"
19a34c753fSRafael Auler #include "llvm/MC/MCInstrInfo.h"
20a34c753fSRafael Auler #include "llvm/MC/MCRegisterInfo.h"
21a34c753fSRafael Auler #include "llvm/Support/Debug.h"
22a34c753fSRafael Auler #include "llvm/Support/ErrorHandling.h"
23a34c753fSRafael Auler 
24a34c753fSRafael Auler #define DEBUG_TYPE "bolt-aarch64"
25a34c753fSRafael Auler 
26a34c753fSRafael Auler using namespace llvm;
27a34c753fSRafael Auler using namespace bolt;
28a34c753fSRafael Auler 
29a34c753fSRafael Auler namespace {
30a34c753fSRafael Auler 
31a34c753fSRafael Auler class AArch64MCPlusBuilder : public MCPlusBuilder {
32a34c753fSRafael Auler public:
33a34c753fSRafael Auler   AArch64MCPlusBuilder(const MCInstrAnalysis *Analysis, const MCInstrInfo *Info,
34a34c753fSRafael Auler                        const MCRegisterInfo *RegInfo)
35a34c753fSRafael Auler       : MCPlusBuilder(Analysis, Info, RegInfo) {}
36a34c753fSRafael Auler 
37a34c753fSRafael Auler   bool equals(const MCTargetExpr &A, const MCTargetExpr &B,
38a34c753fSRafael Auler               CompFuncTy Comp) const override {
39a34c753fSRafael Auler     const auto &AArch64ExprA = cast<AArch64MCExpr>(A);
40a34c753fSRafael Auler     const auto &AArch64ExprB = cast<AArch64MCExpr>(B);
41a34c753fSRafael Auler     if (AArch64ExprA.getKind() != AArch64ExprB.getKind())
42a34c753fSRafael Auler       return false;
43a34c753fSRafael Auler 
44a34c753fSRafael Auler     return MCPlusBuilder::equals(*AArch64ExprA.getSubExpr(),
45a34c753fSRafael Auler                                  *AArch64ExprB.getSubExpr(), Comp);
46a34c753fSRafael Auler   }
47a34c753fSRafael Auler 
4840c2e0faSMaksim Panchenko   bool hasEVEXEncoding(const MCInst &) const override { return false; }
49a34c753fSRafael Auler 
50a34c753fSRafael Auler   bool isMacroOpFusionPair(ArrayRef<MCInst> Insts) const override {
51a34c753fSRafael Auler     return false;
52a34c753fSRafael Auler   }
53a34c753fSRafael Auler 
5440c2e0faSMaksim Panchenko   bool shortenInstruction(MCInst &) const override { return false; }
55a34c753fSRafael Auler 
56a34c753fSRafael Auler   bool isADRP(const MCInst &Inst) const override {
57a34c753fSRafael Auler     return Inst.getOpcode() == AArch64::ADRP;
58a34c753fSRafael Auler   }
59a34c753fSRafael Auler 
60a34c753fSRafael Auler   bool isADR(const MCInst &Inst) const override {
61a34c753fSRafael Auler     return Inst.getOpcode() == AArch64::ADR;
62a34c753fSRafael Auler   }
63a34c753fSRafael Auler 
64a34c753fSRafael Auler   void getADRReg(const MCInst &Inst, MCPhysReg &RegName) const override {
65a34c753fSRafael Auler     assert((isADR(Inst) || isADRP(Inst)) && "Not an ADR instruction");
66a34c753fSRafael Auler     assert(MCPlus::getNumPrimeOperands(Inst) != 0 &&
67a34c753fSRafael Auler            "No operands for ADR instruction");
68a34c753fSRafael Auler     assert(Inst.getOperand(0).isReg() &&
69a34c753fSRafael Auler            "Unexpected operand in ADR instruction");
70a34c753fSRafael Auler     RegName = Inst.getOperand(0).getReg();
71a34c753fSRafael Auler   }
72a34c753fSRafael Auler 
73a34c753fSRafael Auler   bool isTB(const MCInst &Inst) const {
74a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::TBNZW ||
75a34c753fSRafael Auler             Inst.getOpcode() == AArch64::TBNZX ||
76a34c753fSRafael Auler             Inst.getOpcode() == AArch64::TBZW ||
77a34c753fSRafael Auler             Inst.getOpcode() == AArch64::TBZX);
78a34c753fSRafael Auler   }
79a34c753fSRafael Auler 
80a34c753fSRafael Auler   bool isCB(const MCInst &Inst) const {
81a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::CBNZW ||
82a34c753fSRafael Auler             Inst.getOpcode() == AArch64::CBNZX ||
83a34c753fSRafael Auler             Inst.getOpcode() == AArch64::CBZW ||
84a34c753fSRafael Auler             Inst.getOpcode() == AArch64::CBZX);
85a34c753fSRafael Auler   }
86a34c753fSRafael Auler 
87a34c753fSRafael Auler   bool isMOVW(const MCInst &Inst) const {
88a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::MOVKWi ||
89a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVKXi ||
90a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVNWi ||
91a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVNXi ||
92a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVZXi ||
93a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVZWi);
94a34c753fSRafael Auler   }
95a34c753fSRafael Auler 
96a34c753fSRafael Auler   bool isADD(const MCInst &Inst) const {
97a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::ADDSWri ||
98a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSWrr ||
99a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSWrs ||
100a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSWrx ||
101a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXri ||
102a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXrr ||
103a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXrs ||
104a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXrx ||
105a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXrx64 ||
106a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDWri ||
107a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDWrr ||
108a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDWrs ||
109a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDWrx ||
110a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXri ||
111a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXrr ||
112a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXrs ||
113a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXrx ||
114a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXrx64);
115a34c753fSRafael Auler   }
116a34c753fSRafael Auler 
117a34c753fSRafael Auler   bool isLDRB(const MCInst &Inst) const {
118a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::LDRBBpost ||
119a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRBBpre ||
120a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRBBroW ||
121a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRBBroX ||
122a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRBBui ||
123a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBWpost ||
124a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBWpre ||
125a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBWroW ||
126a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBWroX ||
127a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBWui ||
128a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBXpost ||
129a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBXpre ||
130a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBXroW ||
131a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBXroX ||
132a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBXui);
133a34c753fSRafael Auler   }
134a34c753fSRafael Auler 
135a34c753fSRafael Auler   bool isLDRH(const MCInst &Inst) const {
136a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::LDRHHpost ||
137a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRHHpre ||
138a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRHHroW ||
139a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRHHroX ||
140a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRHHui ||
141a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHWpost ||
142a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHWpre ||
143a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHWroW ||
144a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHWroX ||
145a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHWui ||
146a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHXpost ||
147a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHXpre ||
148a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHXroW ||
149a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHXroX ||
150a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHXui);
151a34c753fSRafael Auler   }
152a34c753fSRafael Auler 
153a34c753fSRafael Auler   bool isLDRW(const MCInst &Inst) const {
154a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::LDRWpost ||
155a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRWpre ||
156a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRWroW ||
157a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRWroX ||
158a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRWui);
159a34c753fSRafael Auler   }
160a34c753fSRafael Auler 
161a34c753fSRafael Auler   bool isLDRX(const MCInst &Inst) const {
162a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::LDRXpost ||
163a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRXpre ||
164a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRXroW ||
165a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRXroX ||
166a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRXui);
167a34c753fSRafael Auler   }
168a34c753fSRafael Auler 
169a34c753fSRafael Auler   bool isLoad(const MCInst &Inst) const override {
170a34c753fSRafael Auler     return isLDRB(Inst) || isLDRH(Inst) || isLDRW(Inst) || isLDRX(Inst);
171a34c753fSRafael Auler   }
172a34c753fSRafael Auler 
173a34c753fSRafael Auler   bool isLoadFromStack(const MCInst &Inst) const {
174a34c753fSRafael Auler     if (!isLoad(Inst))
175a34c753fSRafael Auler       return false;
176a34c753fSRafael Auler     const MCInstrDesc &InstInfo = Info->get(Inst.getOpcode());
177a34c753fSRafael Auler     unsigned NumDefs = InstInfo.getNumDefs();
178a34c753fSRafael Auler     for (unsigned I = NumDefs, E = InstInfo.getNumOperands(); I < E; ++I) {
179a34c753fSRafael Auler       const MCOperand &Operand = Inst.getOperand(I);
180a34c753fSRafael Auler       if (!Operand.isReg())
181a34c753fSRafael Auler         continue;
182a34c753fSRafael Auler       unsigned Reg = Operand.getReg();
18340c2e0faSMaksim Panchenko       if (Reg == AArch64::SP || Reg == AArch64::WSP || Reg == AArch64::FP ||
18440c2e0faSMaksim Panchenko           Reg == AArch64::W29)
185a34c753fSRafael Auler         return true;
186a34c753fSRafael Auler     }
187a34c753fSRafael Auler     return false;
188a34c753fSRafael Auler   }
189a34c753fSRafael Auler 
190a34c753fSRafael Auler   bool isRegToRegMove(const MCInst &Inst, MCPhysReg &From,
191a34c753fSRafael Auler                       MCPhysReg &To) const override {
192a34c753fSRafael Auler     if (Inst.getOpcode() != AArch64::ORRXrs)
193a34c753fSRafael Auler       return false;
194a34c753fSRafael Auler     if (Inst.getOperand(1).getReg() != AArch64::XZR)
195a34c753fSRafael Auler       return false;
196a34c753fSRafael Auler     if (Inst.getOperand(3).getImm() != 0)
197a34c753fSRafael Auler       return false;
198a34c753fSRafael Auler     From = Inst.getOperand(2).getReg();
199a34c753fSRafael Auler     To = Inst.getOperand(0).getReg();
200a34c753fSRafael Auler     return true;
201a34c753fSRafael Auler   }
202a34c753fSRafael Auler 
203a34c753fSRafael Auler   bool isIndirectCall(const MCInst &Inst) const override {
204a34c753fSRafael Auler     return Inst.getOpcode() == AArch64::BLR;
205a34c753fSRafael Auler   }
206a34c753fSRafael Auler 
20740c2e0faSMaksim Panchenko   MCPhysReg getNoRegister() const override { return AArch64::NoRegister; }
208a34c753fSRafael Auler 
209a34c753fSRafael Auler   bool hasPCRelOperand(const MCInst &Inst) const override {
210a34c753fSRafael Auler     // ADRP is blacklisted and is an exception. Even though it has a
211a34c753fSRafael Auler     // PC-relative operand, this operand is not a complete symbol reference
212a34c753fSRafael Auler     // and BOLT shouldn't try to process it in isolation.
213a34c753fSRafael Auler     if (isADRP(Inst))
214a34c753fSRafael Auler       return false;
215a34c753fSRafael Auler 
216a34c753fSRafael Auler     if (isADR(Inst))
217a34c753fSRafael Auler       return true;
218a34c753fSRafael Auler 
219a34c753fSRafael Auler     // Look for literal addressing mode (see C1-143 ARM DDI 0487B.a)
220a34c753fSRafael Auler     const MCInstrDesc &MCII = Info->get(Inst.getOpcode());
221a34c753fSRafael Auler     for (unsigned I = 0, E = MCII.getNumOperands(); I != E; ++I) {
222a34c753fSRafael Auler       if (MCII.OpInfo[I].OperandType == MCOI::OPERAND_PCREL)
223a34c753fSRafael Auler         return true;
224a34c753fSRafael Auler     }
225a34c753fSRafael Auler     return false;
226a34c753fSRafael Auler   }
227a34c753fSRafael Auler 
228a34c753fSRafael Auler   bool evaluateADR(const MCInst &Inst, int64_t &Imm,
229a34c753fSRafael Auler                    const MCExpr **DispExpr) const {
230a34c753fSRafael Auler     assert((isADR(Inst) || isADRP(Inst)) && "Not an ADR instruction");
231a34c753fSRafael Auler 
232a34c753fSRafael Auler     const MCOperand &Label = Inst.getOperand(1);
233a34c753fSRafael Auler     if (!Label.isImm()) {
234a34c753fSRafael Auler       assert(Label.isExpr() && "Unexpected ADR operand");
235a34c753fSRafael Auler       assert(DispExpr && "DispExpr must be set");
236a34c753fSRafael Auler       *DispExpr = Label.getExpr();
237a34c753fSRafael Auler       return false;
238a34c753fSRafael Auler     }
239a34c753fSRafael Auler 
240a34c753fSRafael Auler     if (Inst.getOpcode() == AArch64::ADR) {
241a34c753fSRafael Auler       Imm = Label.getImm();
242a34c753fSRafael Auler       return true;
243a34c753fSRafael Auler     }
244a34c753fSRafael Auler     Imm = Label.getImm() << 12;
245a34c753fSRafael Auler     return true;
246a34c753fSRafael Auler   }
247a34c753fSRafael Auler 
24840c2e0faSMaksim Panchenko   bool evaluateAArch64MemoryOperand(const MCInst &Inst, int64_t &DispImm,
24940c2e0faSMaksim Panchenko                                     const MCExpr **DispExpr = nullptr) const {
250a34c753fSRafael Auler     if (isADR(Inst) || isADRP(Inst))
251a34c753fSRafael Auler       return evaluateADR(Inst, DispImm, DispExpr);
252a34c753fSRafael Auler 
253a34c753fSRafael Auler     // Literal addressing mode
254a34c753fSRafael Auler     const MCInstrDesc &MCII = Info->get(Inst.getOpcode());
255a34c753fSRafael Auler     for (unsigned I = 0, E = MCII.getNumOperands(); I != E; ++I) {
256a34c753fSRafael Auler       if (MCII.OpInfo[I].OperandType != MCOI::OPERAND_PCREL)
257a34c753fSRafael Auler         continue;
258a34c753fSRafael Auler 
259a34c753fSRafael Auler       if (!Inst.getOperand(I).isImm()) {
260a34c753fSRafael Auler         assert(Inst.getOperand(I).isExpr() && "Unexpected PCREL operand");
261a34c753fSRafael Auler         assert(DispExpr && "DispExpr must be set");
262a34c753fSRafael Auler         *DispExpr = Inst.getOperand(I).getExpr();
263a34c753fSRafael Auler         return true;
264a34c753fSRafael Auler       }
265a34c753fSRafael Auler 
266a34c753fSRafael Auler       DispImm = Inst.getOperand(I).getImm() << 2;
267a34c753fSRafael Auler       return true;
268a34c753fSRafael Auler     }
269a34c753fSRafael Auler     return false;
270a34c753fSRafael Auler   }
271a34c753fSRafael Auler 
272a34c753fSRafael Auler   bool evaluateMemOperandTarget(const MCInst &Inst, uint64_t &Target,
273a34c753fSRafael Auler                                 uint64_t Address,
274a34c753fSRafael Auler                                 uint64_t Size) const override {
275a34c753fSRafael Auler     int64_t DispValue;
276a34c753fSRafael Auler     const MCExpr *DispExpr = nullptr;
277a34c753fSRafael Auler     if (!evaluateAArch64MemoryOperand(Inst, DispValue, &DispExpr))
278a34c753fSRafael Auler       return false;
279a34c753fSRafael Auler 
280a34c753fSRafael Auler     // Make sure it's a well-formed addressing we can statically evaluate.
281a34c753fSRafael Auler     if (DispExpr)
282a34c753fSRafael Auler       return false;
283a34c753fSRafael Auler 
284a34c753fSRafael Auler     Target = DispValue;
285a34c753fSRafael Auler     if (Inst.getOpcode() == AArch64::ADRP)
286a34c753fSRafael Auler       Target += Address & ~0xFFFULL;
287a34c753fSRafael Auler     else
288a34c753fSRafael Auler       Target += Address;
289a34c753fSRafael Auler     return true;
290a34c753fSRafael Auler   }
291a34c753fSRafael Auler 
292a34c753fSRafael Auler   bool replaceMemOperandDisp(MCInst &Inst, MCOperand Operand) const override {
293a34c753fSRafael Auler     MCInst::iterator OI = Inst.begin();
294a34c753fSRafael Auler     if (isADR(Inst) || isADRP(Inst)) {
295a34c753fSRafael Auler       assert(MCPlus::getNumPrimeOperands(Inst) >= 2 &&
296a34c753fSRafael Auler              "Unexpected number of operands");
297a34c753fSRafael Auler       ++OI;
298a34c753fSRafael Auler     } else {
299a34c753fSRafael Auler       const MCInstrDesc &MCII = Info->get(Inst.getOpcode());
300a34c753fSRafael Auler       for (unsigned I = 0, E = MCII.getNumOperands(); I != E; ++I) {
301a34c753fSRafael Auler         if (MCII.OpInfo[I].OperandType == MCOI::OPERAND_PCREL) {
302a34c753fSRafael Auler           break;
303a34c753fSRafael Auler         }
304a34c753fSRafael Auler         ++OI;
305a34c753fSRafael Auler       }
306a34c753fSRafael Auler       assert(OI != Inst.end() && "Literal operand not found");
307a34c753fSRafael Auler     }
308a34c753fSRafael Auler     *OI = Operand;
309a34c753fSRafael Auler     return true;
310a34c753fSRafael Auler   }
311a34c753fSRafael Auler 
312a34c753fSRafael Auler   const MCExpr *getTargetExprFor(MCInst &Inst, const MCExpr *Expr,
313a34c753fSRafael Auler                                  MCContext &Ctx,
314a34c753fSRafael Auler                                  uint64_t RelType) const override {
315a34c753fSRafael Auler 
316a34c753fSRafael Auler     if (isADR(Inst) || RelType == ELF::R_AARCH64_ADR_PREL_LO21 ||
317a34c753fSRafael Auler         RelType == ELF::R_AARCH64_TLSDESC_ADR_PREL21) {
318a34c753fSRafael Auler       return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS, Ctx);
319a34c753fSRafael Auler     } else if (isADRP(Inst) || RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21 ||
320a34c753fSRafael Auler                RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21_NC ||
321a34c753fSRafael Auler                RelType == ELF::R_AARCH64_TLSDESC_ADR_PAGE21 ||
322a34c753fSRafael Auler                RelType == ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
323a34c753fSRafael Auler                RelType == ELF::R_AARCH64_ADR_GOT_PAGE) {
324a34c753fSRafael Auler       // Never emit a GOT reloc, we handled this in
325a34c753fSRafael Auler       // RewriteInstance::readRelocations().
326a34c753fSRafael Auler       return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_PAGE, Ctx);
327a34c753fSRafael Auler     } else {
328a34c753fSRafael Auler       switch (RelType) {
329a34c753fSRafael Auler       case ELF::R_AARCH64_ADD_ABS_LO12_NC:
330a34c753fSRafael Auler       case ELF::R_AARCH64_LD64_GOT_LO12_NC:
331a34c753fSRafael Auler       case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
332a34c753fSRafael Auler       case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
333a34c753fSRafael Auler       case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
334a34c753fSRafael Auler       case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
335a34c753fSRafael Auler       case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
336a34c753fSRafael Auler       case ELF::R_AARCH64_TLSDESC_ADD_LO12:
337a34c753fSRafael Auler       case ELF::R_AARCH64_TLSDESC_LD64_LO12:
338a34c753fSRafael Auler       case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
339a34c753fSRafael Auler       case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
340a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_LO12, Ctx);
341a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G3:
342a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G3, Ctx);
343a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G2:
344a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G2_NC:
345a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G2_NC, Ctx);
346a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G1:
347a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G1_NC:
348a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G1_NC, Ctx);
349a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G0:
350a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G0_NC:
351a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G0_NC, Ctx);
352a34c753fSRafael Auler       default:
353a34c753fSRafael Auler         break;
354a34c753fSRafael Auler       }
355a34c753fSRafael Auler     }
356a34c753fSRafael Auler     return Expr;
357a34c753fSRafael Auler   }
358a34c753fSRafael Auler 
359a34c753fSRafael Auler   bool getSymbolRefOperandNum(const MCInst &Inst, unsigned &OpNum) const {
360a34c753fSRafael Auler     if (OpNum >= MCPlus::getNumPrimeOperands(Inst))
361a34c753fSRafael Auler       return false;
362a34c753fSRafael Auler 
363a34c753fSRafael Auler     // Auto-select correct operand number
364a34c753fSRafael Auler     if (OpNum == 0) {
365a34c753fSRafael Auler       if (isConditionalBranch(Inst) || isADR(Inst) || isADRP(Inst))
366a34c753fSRafael Auler         OpNum = 1;
367a34c753fSRafael Auler       if (isTB(Inst))
368a34c753fSRafael Auler         OpNum = 2;
369a34c753fSRafael Auler       if (isMOVW(Inst))
370a34c753fSRafael Auler         OpNum = 1;
371a34c753fSRafael Auler     }
372a34c753fSRafael Auler 
373a34c753fSRafael Auler     return true;
374a34c753fSRafael Auler   }
375a34c753fSRafael Auler 
376a34c753fSRafael Auler   const MCSymbol *getTargetSymbol(const MCExpr *Expr) const override {
377a34c753fSRafael Auler     auto *AArchExpr = dyn_cast<AArch64MCExpr>(Expr);
378a34c753fSRafael Auler     if (AArchExpr && AArchExpr->getSubExpr())
379a34c753fSRafael Auler       return getTargetSymbol(AArchExpr->getSubExpr());
380a34c753fSRafael Auler 
381a34c753fSRafael Auler     auto *BinExpr = dyn_cast<MCBinaryExpr>(Expr);
382a34c753fSRafael Auler     if (BinExpr)
383a34c753fSRafael Auler       return getTargetSymbol(BinExpr->getLHS());
384a34c753fSRafael Auler 
385a34c753fSRafael Auler     auto *SymExpr = dyn_cast<MCSymbolRefExpr>(Expr);
386a34c753fSRafael Auler     if (SymExpr && SymExpr->getKind() == MCSymbolRefExpr::VK_None)
387a34c753fSRafael Auler       return &SymExpr->getSymbol();
388a34c753fSRafael Auler 
389a34c753fSRafael Auler     return nullptr;
390a34c753fSRafael Auler   }
391a34c753fSRafael Auler 
392a34c753fSRafael Auler   const MCSymbol *getTargetSymbol(const MCInst &Inst,
393a34c753fSRafael Auler                                   unsigned OpNum = 0) const override {
394a34c753fSRafael Auler     if (!getSymbolRefOperandNum(Inst, OpNum))
395a34c753fSRafael Auler       return nullptr;
396a34c753fSRafael Auler 
397a34c753fSRafael Auler     const MCOperand &Op = Inst.getOperand(OpNum);
398a34c753fSRafael Auler     if (!Op.isExpr())
399a34c753fSRafael Auler       return nullptr;
400a34c753fSRafael Auler 
401a34c753fSRafael Auler     return getTargetSymbol(Op.getExpr());
402a34c753fSRafael Auler   }
403a34c753fSRafael Auler 
404a34c753fSRafael Auler   int64_t getTargetAddend(const MCExpr *Expr) const override {
405a34c753fSRafael Auler     auto *AArchExpr = dyn_cast<AArch64MCExpr>(Expr);
406a34c753fSRafael Auler     if (AArchExpr && AArchExpr->getSubExpr())
407a34c753fSRafael Auler       return getTargetAddend(AArchExpr->getSubExpr());
408a34c753fSRafael Auler 
409a34c753fSRafael Auler     auto *BinExpr = dyn_cast<MCBinaryExpr>(Expr);
410a34c753fSRafael Auler     if (BinExpr && BinExpr->getOpcode() == MCBinaryExpr::Add)
411a34c753fSRafael Auler       return getTargetAddend(BinExpr->getRHS());
412a34c753fSRafael Auler 
413a34c753fSRafael Auler     auto *ConstExpr = dyn_cast<MCConstantExpr>(Expr);
414a34c753fSRafael Auler     if (ConstExpr)
415a34c753fSRafael Auler       return ConstExpr->getValue();
416a34c753fSRafael Auler 
417a34c753fSRafael Auler     return 0;
418a34c753fSRafael Auler   }
419a34c753fSRafael Auler 
420a34c753fSRafael Auler   int64_t getTargetAddend(const MCInst &Inst,
421a34c753fSRafael Auler                           unsigned OpNum = 0) const override {
422a34c753fSRafael Auler     if (!getSymbolRefOperandNum(Inst, OpNum))
423a34c753fSRafael Auler       return 0;
424a34c753fSRafael Auler 
425a34c753fSRafael Auler     const MCOperand &Op = Inst.getOperand(OpNum);
426a34c753fSRafael Auler     if (!Op.isExpr())
427a34c753fSRafael Auler       return 0;
428a34c753fSRafael Auler 
429a34c753fSRafael Auler     return getTargetAddend(Op.getExpr());
430a34c753fSRafael Auler   }
431a34c753fSRafael Auler 
432a34c753fSRafael Auler   bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size,
433a34c753fSRafael Auler                       uint64_t &Target) const override {
434a34c753fSRafael Auler     size_t OpNum = 0;
435a34c753fSRafael Auler 
436a34c753fSRafael Auler     if (isConditionalBranch(Inst)) {
437a34c753fSRafael Auler       assert(MCPlus::getNumPrimeOperands(Inst) >= 2 &&
438a34c753fSRafael Auler              "Invalid number of operands");
439a34c753fSRafael Auler       OpNum = 1;
440a34c753fSRafael Auler     }
441a34c753fSRafael Auler 
442a34c753fSRafael Auler     if (isTB(Inst)) {
443a34c753fSRafael Auler       assert(MCPlus::getNumPrimeOperands(Inst) >= 3 &&
444a34c753fSRafael Auler              "Invalid number of operands");
445a34c753fSRafael Auler       OpNum = 2;
446a34c753fSRafael Auler     }
447a34c753fSRafael Auler 
448a34c753fSRafael Auler     if (Info->get(Inst.getOpcode()).OpInfo[OpNum].OperandType !=
449a34c753fSRafael Auler         MCOI::OPERAND_PCREL) {
450a34c753fSRafael Auler       assert((isIndirectBranch(Inst) || isIndirectCall(Inst)) &&
451a34c753fSRafael Auler              "FAILED evaluateBranch");
452a34c753fSRafael Auler       return false;
453a34c753fSRafael Auler     }
454a34c753fSRafael Auler 
455a34c753fSRafael Auler     int64_t Imm = Inst.getOperand(OpNum).getImm() << 2;
456a34c753fSRafael Auler     Target = Addr + Imm;
457a34c753fSRafael Auler     return true;
458a34c753fSRafael Auler   }
459a34c753fSRafael Auler 
460a34c753fSRafael Auler   bool replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,
461a34c753fSRafael Auler                            MCContext *Ctx) const override {
462a34c753fSRafael Auler     assert((isCall(Inst) || isBranch(Inst)) && !isIndirectBranch(Inst) &&
463a34c753fSRafael Auler            "Invalid instruction");
464a34c753fSRafael Auler     assert(MCPlus::getNumPrimeOperands(Inst) >= 1 &&
465a34c753fSRafael Auler            "Invalid number of operands");
466a34c753fSRafael Auler     MCInst::iterator OI = Inst.begin();
467a34c753fSRafael Auler 
468a34c753fSRafael Auler     if (isConditionalBranch(Inst)) {
469a34c753fSRafael Auler       assert(MCPlus::getNumPrimeOperands(Inst) >= 2 &&
470a34c753fSRafael Auler              "Invalid number of operands");
471a34c753fSRafael Auler       ++OI;
472a34c753fSRafael Auler     }
473a34c753fSRafael Auler 
474a34c753fSRafael Auler     if (isTB(Inst)) {
475a34c753fSRafael Auler       assert(MCPlus::getNumPrimeOperands(Inst) >= 3 &&
476a34c753fSRafael Auler              "Invalid number of operands");
477a34c753fSRafael Auler       OI = Inst.begin() + 2;
478a34c753fSRafael Auler     }
479a34c753fSRafael Auler 
480a34c753fSRafael Auler     *OI = MCOperand::createExpr(
481a34c753fSRafael Auler         MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx));
482a34c753fSRafael Auler     return true;
483a34c753fSRafael Auler   }
484a34c753fSRafael Auler 
485a34c753fSRafael Auler   /// Matches indirect branch patterns in AArch64 related to a jump table (JT),
486a34c753fSRafael Auler   /// helping us to build the complete CFG. A typical indirect branch to
487a34c753fSRafael Auler   /// a jump table entry in AArch64 looks like the following:
488a34c753fSRafael Auler   ///
489a34c753fSRafael Auler   ///   adrp    x1, #-7585792           # Get JT Page location
490a34c753fSRafael Auler   ///   add     x1, x1, #692            # Complement with JT Page offset
491a34c753fSRafael Auler   ///   ldrh    w0, [x1, w0, uxtw #1]   # Loads JT entry
492a34c753fSRafael Auler   ///   adr     x1, #12                 # Get PC + 12 (end of this BB) used next
493a34c753fSRafael Auler   ///   add     x0, x1, w0, sxth #2     # Finish building branch target
494a34c753fSRafael Auler   ///                                   # (entries in JT are relative to the end
495a34c753fSRafael Auler   ///                                   #  of this BB)
496a34c753fSRafael Auler   ///   br      x0                      # Indirect jump instruction
497a34c753fSRafael Auler   ///
498a34c753fSRafael Auler   bool analyzeIndirectBranchFragment(
499a34c753fSRafael Auler       const MCInst &Inst,
500a34c753fSRafael Auler       DenseMap<const MCInst *, SmallVector<MCInst *, 4>> &UDChain,
501a34c753fSRafael Auler       const MCExpr *&JumpTable, int64_t &Offset, int64_t &ScaleValue,
502a34c753fSRafael Auler       MCInst *&PCRelBase) const {
503a34c753fSRafael Auler     // Expect AArch64 BR
504a34c753fSRafael Auler     assert(Inst.getOpcode() == AArch64::BR && "Unexpected opcode");
505a34c753fSRafael Auler 
506a34c753fSRafael Auler     // Match the indirect branch pattern for aarch64
507a34c753fSRafael Auler     SmallVector<MCInst *, 4> &UsesRoot = UDChain[&Inst];
508a34c753fSRafael Auler     if (UsesRoot.size() == 0 || UsesRoot[0] == nullptr) {
509a34c753fSRafael Auler       return false;
510a34c753fSRafael Auler     }
511a34c753fSRafael Auler     const MCInst *DefAdd = UsesRoot[0];
512a34c753fSRafael Auler 
513a34c753fSRafael Auler     // Now we match an ADD
514a34c753fSRafael Auler     if (!isADD(*DefAdd)) {
515a34c753fSRafael Auler       // If the address is not broken up in two parts, this is not branching
516a34c753fSRafael Auler       // according to a jump table entry. Fail.
517a34c753fSRafael Auler       return false;
518a34c753fSRafael Auler     }
519a34c753fSRafael Auler     if (DefAdd->getOpcode() == AArch64::ADDXri) {
520a34c753fSRafael Auler       // This can happen when there is no offset, but a direct jump that was
521a34c753fSRafael Auler       // transformed into an indirect one  (indirect tail call) :
522a34c753fSRafael Auler       //   ADRP   x2, Perl_re_compiler
523a34c753fSRafael Auler       //   ADD    x2, x2, :lo12:Perl_re_compiler
524a34c753fSRafael Auler       //   BR     x2
525a34c753fSRafael Auler       return false;
526a34c753fSRafael Auler     }
527a34c753fSRafael Auler     if (DefAdd->getOpcode() == AArch64::ADDXrs) {
528a34c753fSRafael Auler       // Covers the less common pattern where JT entries are relative to
529a34c753fSRafael Auler       // the JT itself (like x86). Seems less efficient since we can't
530a34c753fSRafael Auler       // assume the JT is aligned at 4B boundary and thus drop 2 bits from
531a34c753fSRafael Auler       // JT values.
532a34c753fSRafael Auler       // cde264:
533a34c753fSRafael Auler       //    adrp    x12, #21544960  ; 216a000
534a34c753fSRafael Auler       //    add     x12, x12, #1696 ; 216a6a0  (JT object in .rodata)
535a34c753fSRafael Auler       //    ldrsw   x8, [x12, x8, lsl #2]   --> loads e.g. 0xfeb73bd8
536a34c753fSRafael Auler       //  * add     x8, x8, x12   --> = cde278, next block
537a34c753fSRafael Auler       //    br      x8
538a34c753fSRafael Auler       // cde278:
539a34c753fSRafael Auler       //
540a34c753fSRafael Auler       // Parsed as ADDXrs reg:x8 reg:x8 reg:x12 imm:0
541a34c753fSRafael Auler       return false;
542a34c753fSRafael Auler     }
543a34c753fSRafael Auler     assert(DefAdd->getOpcode() == AArch64::ADDXrx &&
544a34c753fSRafael Auler            "Failed to match indirect branch!");
545a34c753fSRafael Auler 
546a34c753fSRafael Auler     // Validate ADD operands
547a34c753fSRafael Auler     int64_t OperandExtension = DefAdd->getOperand(3).getImm();
548a34c753fSRafael Auler     unsigned ShiftVal = AArch64_AM::getArithShiftValue(OperandExtension);
549a34c753fSRafael Auler     AArch64_AM::ShiftExtendType ExtendType =
550a34c753fSRafael Auler         AArch64_AM::getArithExtendType(OperandExtension);
551a34c753fSRafael Auler     if (ShiftVal != 2) {
552a34c753fSRafael Auler       llvm_unreachable("Failed to match indirect branch! (fragment 2)");
553a34c753fSRafael Auler     }
554a34c753fSRafael Auler     if (ExtendType == AArch64_AM::SXTB) {
555a34c753fSRafael Auler       ScaleValue = 1LL;
556a34c753fSRafael Auler     } else if (ExtendType == AArch64_AM::SXTH) {
557a34c753fSRafael Auler       ScaleValue = 2LL;
558a34c753fSRafael Auler     } else if (ExtendType == AArch64_AM::SXTW) {
559a34c753fSRafael Auler       ScaleValue = 4LL;
560a34c753fSRafael Auler     } else {
561a34c753fSRafael Auler       llvm_unreachable("Failed to match indirect branch! (fragment 3)");
562a34c753fSRafael Auler     }
563a34c753fSRafael Auler 
564a34c753fSRafael Auler     // Match an ADR to load base address to be used when addressing JT targets
565a34c753fSRafael Auler     SmallVector<MCInst *, 4> &UsesAdd = UDChain[DefAdd];
566a34c753fSRafael Auler     if (UsesAdd.size() <= 1 || UsesAdd[1] == nullptr || UsesAdd[2] == nullptr) {
567a34c753fSRafael Auler       // This happens when we don't have enough context about this jump table
568a34c753fSRafael Auler       // because the jumping code sequence was split in multiple basic blocks.
569a34c753fSRafael Auler       // This was observed in the wild in HHVM code (dispatchImpl).
570a34c753fSRafael Auler       return false;
571a34c753fSRafael Auler     }
572a34c753fSRafael Auler     MCInst *DefBaseAddr = UsesAdd[1];
573a34c753fSRafael Auler     assert(DefBaseAddr->getOpcode() == AArch64::ADR &&
574a34c753fSRafael Auler            "Failed to match indirect branch pattern! (fragment 3)");
575a34c753fSRafael Auler 
576a34c753fSRafael Auler     PCRelBase = DefBaseAddr;
577a34c753fSRafael Auler     // Match LOAD to load the jump table (relative) target
578a34c753fSRafael Auler     const MCInst *DefLoad = UsesAdd[2];
579a34c753fSRafael Auler     assert(isLoad(*DefLoad) &&
580a34c753fSRafael Auler            "Failed to match indirect branch load pattern! (1)");
581a34c753fSRafael Auler     assert((ScaleValue != 1LL || isLDRB(*DefLoad)) &&
582a34c753fSRafael Auler            "Failed to match indirect branch load pattern! (2)");
583a34c753fSRafael Auler     assert((ScaleValue != 2LL || isLDRH(*DefLoad)) &&
584a34c753fSRafael Auler            "Failed to match indirect branch load pattern! (3)");
585a34c753fSRafael Auler 
586a34c753fSRafael Auler     // Match ADD that calculates the JumpTable Base Address (not the offset)
587a34c753fSRafael Auler     SmallVector<MCInst *, 4> &UsesLoad = UDChain[DefLoad];
588a34c753fSRafael Auler     const MCInst *DefJTBaseAdd = UsesLoad[1];
589a34c753fSRafael Auler     MCPhysReg From, To;
590a34c753fSRafael Auler     if (DefJTBaseAdd == nullptr || isLoadFromStack(*DefJTBaseAdd) ||
591a34c753fSRafael Auler         isRegToRegMove(*DefJTBaseAdd, From, To)) {
592a34c753fSRafael Auler       // Sometimes base address may have been defined in another basic block
593a34c753fSRafael Auler       // (hoisted). Return with no jump table info.
594a34c753fSRafael Auler       JumpTable = nullptr;
595a34c753fSRafael Auler       return true;
596a34c753fSRafael Auler     }
597a34c753fSRafael Auler 
598a34c753fSRafael Auler     assert(DefJTBaseAdd->getOpcode() == AArch64::ADDXri &&
599a34c753fSRafael Auler            "Failed to match jump table base address pattern! (1)");
600a34c753fSRafael Auler 
601a34c753fSRafael Auler     if (DefJTBaseAdd->getOperand(2).isImm())
602a34c753fSRafael Auler       Offset = DefJTBaseAdd->getOperand(2).getImm();
603a34c753fSRafael Auler     SmallVector<MCInst *, 4> &UsesJTBaseAdd = UDChain[DefJTBaseAdd];
604a34c753fSRafael Auler     const MCInst *DefJTBasePage = UsesJTBaseAdd[1];
605a34c753fSRafael Auler     if (DefJTBasePage == nullptr || isLoadFromStack(*DefJTBasePage)) {
606a34c753fSRafael Auler       JumpTable = nullptr;
607a34c753fSRafael Auler       return true;
608a34c753fSRafael Auler     }
609a34c753fSRafael Auler     assert(DefJTBasePage->getOpcode() == AArch64::ADRP &&
610a34c753fSRafael Auler            "Failed to match jump table base page pattern! (2)");
611a34c753fSRafael Auler     if (DefJTBasePage->getOperand(1).isExpr())
612a34c753fSRafael Auler       JumpTable = DefJTBasePage->getOperand(1).getExpr();
613a34c753fSRafael Auler     return true;
614a34c753fSRafael Auler   }
615a34c753fSRafael Auler 
616a34c753fSRafael Auler   DenseMap<const MCInst *, SmallVector<MCInst *, 4>>
61740c2e0faSMaksim Panchenko   computeLocalUDChain(const MCInst *CurInstr, InstructionIterator Begin,
618a34c753fSRafael Auler                       InstructionIterator End) const {
619a34c753fSRafael Auler     DenseMap<int, MCInst *> RegAliasTable;
620a34c753fSRafael Auler     DenseMap<const MCInst *, SmallVector<MCInst *, 4>> Uses;
621a34c753fSRafael Auler 
622a34c753fSRafael Auler     auto addInstrOperands = [&](const MCInst &Instr) {
623a34c753fSRafael Auler       // Update Uses table
624a34c753fSRafael Auler       for (unsigned OpNum = 0, OpEnd = MCPlus::getNumPrimeOperands(Instr);
625a34c753fSRafael Auler            OpNum != OpEnd; ++OpNum) {
626a34c753fSRafael Auler         if (!Instr.getOperand(OpNum).isReg())
627a34c753fSRafael Auler           continue;
628a34c753fSRafael Auler         unsigned Reg = Instr.getOperand(OpNum).getReg();
629a34c753fSRafael Auler         MCInst *AliasInst = RegAliasTable[Reg];
630a34c753fSRafael Auler         Uses[&Instr].push_back(AliasInst);
631a34c753fSRafael Auler         LLVM_DEBUG({
632a34c753fSRafael Auler           dbgs() << "Adding reg operand " << Reg << " refs ";
633a34c753fSRafael Auler           if (AliasInst != nullptr)
634a34c753fSRafael Auler             AliasInst->dump();
635a34c753fSRafael Auler           else
636a34c753fSRafael Auler             dbgs() << "\n";
637a34c753fSRafael Auler         });
638a34c753fSRafael Auler       }
639a34c753fSRafael Auler     };
640a34c753fSRafael Auler 
641a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "computeLocalUDChain\n");
642a34c753fSRafael Auler     bool TerminatorSeen = false;
643a34c753fSRafael Auler     for (auto II = Begin; II != End; ++II) {
644a34c753fSRafael Auler       MCInst &Instr = *II;
645a34c753fSRafael Auler       // Ignore nops and CFIs
646a34c753fSRafael Auler       if (isPseudo(Instr) || isNoop(Instr))
647a34c753fSRafael Auler         continue;
648a34c753fSRafael Auler       if (TerminatorSeen) {
649a34c753fSRafael Auler         RegAliasTable.clear();
650a34c753fSRafael Auler         Uses.clear();
651a34c753fSRafael Auler       }
652a34c753fSRafael Auler 
653a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "Now updating for:\n ");
654a34c753fSRafael Auler       LLVM_DEBUG(Instr.dump());
655a34c753fSRafael Auler       addInstrOperands(Instr);
656a34c753fSRafael Auler 
657a34c753fSRafael Auler       BitVector Regs = BitVector(RegInfo->getNumRegs(), false);
658a34c753fSRafael Auler       getWrittenRegs(Instr, Regs);
659a34c753fSRafael Auler 
660a34c753fSRafael Auler       // Update register definitions after this point
661a34c753fSRafael Auler       int Idx = Regs.find_first();
662a34c753fSRafael Auler       while (Idx != -1) {
663a34c753fSRafael Auler         RegAliasTable[Idx] = &Instr;
664a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "Setting reg " << Idx
665a34c753fSRafael Auler                           << " def to current instr.\n");
666a34c753fSRafael Auler         Idx = Regs.find_next(Idx);
667a34c753fSRafael Auler       }
668a34c753fSRafael Auler 
669a34c753fSRafael Auler       TerminatorSeen = isTerminator(Instr);
670a34c753fSRafael Auler     }
671a34c753fSRafael Auler 
672a34c753fSRafael Auler     // Process the last instruction, which is not currently added into the
673a34c753fSRafael Auler     // instruction stream
674a34c753fSRafael Auler     if (CurInstr) {
675a34c753fSRafael Auler       addInstrOperands(*CurInstr);
676a34c753fSRafael Auler     }
677a34c753fSRafael Auler     return Uses;
678a34c753fSRafael Auler   }
679a34c753fSRafael Auler 
680a34c753fSRafael Auler   IndirectBranchType analyzeIndirectBranch(
681a34c753fSRafael Auler      MCInst &Instruction,
682a34c753fSRafael Auler      InstructionIterator Begin,
683a34c753fSRafael Auler      InstructionIterator End,
684a34c753fSRafael Auler      const unsigned PtrSize,
685a34c753fSRafael Auler      MCInst *&MemLocInstrOut,
686a34c753fSRafael Auler      unsigned &BaseRegNumOut,
687a34c753fSRafael Auler      unsigned &IndexRegNumOut,
688a34c753fSRafael Auler      int64_t &DispValueOut,
689a34c753fSRafael Auler      const MCExpr *&DispExprOut,
690a34c753fSRafael Auler      MCInst *&PCRelBaseOut
691a34c753fSRafael Auler   ) const override {
692a34c753fSRafael Auler     MemLocInstrOut = nullptr;
693a34c753fSRafael Auler     BaseRegNumOut = AArch64::NoRegister;
694a34c753fSRafael Auler     IndexRegNumOut = AArch64::NoRegister;
695a34c753fSRafael Auler     DispValueOut = 0;
696a34c753fSRafael Auler     DispExprOut = nullptr;
697a34c753fSRafael Auler 
698a34c753fSRafael Auler     // An instruction referencing memory used by jump instruction (directly or
699a34c753fSRafael Auler     // via register). This location could be an array of function pointers
700a34c753fSRafael Auler     // in case of indirect tail call, or a jump table.
701a34c753fSRafael Auler     MCInst *MemLocInstr = nullptr;
702a34c753fSRafael Auler 
703a34c753fSRafael Auler     // Analyze the memory location.
704a34c753fSRafael Auler     int64_t       ScaleValue, DispValue;
705a34c753fSRafael Auler     const MCExpr *DispExpr;
706a34c753fSRafael Auler 
707a34c753fSRafael Auler     DenseMap<const MCInst *, SmallVector<llvm::MCInst *, 4>> UDChain =
708a34c753fSRafael Auler         computeLocalUDChain(&Instruction, Begin, End);
709a34c753fSRafael Auler     MCInst *PCRelBase;
710a34c753fSRafael Auler     if (!analyzeIndirectBranchFragment(Instruction, UDChain, DispExpr,
711a34c753fSRafael Auler                                        DispValue, ScaleValue, PCRelBase)) {
712a34c753fSRafael Auler       return IndirectBranchType::UNKNOWN;
713a34c753fSRafael Auler     }
714a34c753fSRafael Auler 
715a34c753fSRafael Auler     MemLocInstrOut = MemLocInstr;
716a34c753fSRafael Auler     DispValueOut = DispValue;
717a34c753fSRafael Auler     DispExprOut = DispExpr;
718a34c753fSRafael Auler     PCRelBaseOut = PCRelBase;
719a34c753fSRafael Auler     return IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE;
720a34c753fSRafael Auler   }
721a34c753fSRafael Auler 
722a34c753fSRafael Auler   unsigned getInvertedBranchOpcode(unsigned Opcode) const {
723a34c753fSRafael Auler     switch (Opcode) {
724a34c753fSRafael Auler     default:
725a34c753fSRafael Auler       llvm_unreachable("Failed to invert branch opcode");
726a34c753fSRafael Auler       return Opcode;
727a34c753fSRafael Auler     case AArch64::TBZW:     return AArch64::TBNZW;
728a34c753fSRafael Auler     case AArch64::TBZX:     return AArch64::TBNZX;
729a34c753fSRafael Auler     case AArch64::TBNZW:    return AArch64::TBZW;
730a34c753fSRafael Auler     case AArch64::TBNZX:    return AArch64::TBZX;
731a34c753fSRafael Auler     case AArch64::CBZW:     return AArch64::CBNZW;
732a34c753fSRafael Auler     case AArch64::CBZX:     return AArch64::CBNZX;
733a34c753fSRafael Auler     case AArch64::CBNZW:    return AArch64::CBZW;
734a34c753fSRafael Auler     case AArch64::CBNZX:    return AArch64::CBZX;
735a34c753fSRafael Auler     }
736a34c753fSRafael Auler   }
737a34c753fSRafael Auler 
738a34c753fSRafael Auler   unsigned getCondCode(const MCInst &Inst) const override {
739a34c753fSRafael Auler     // AArch64 does not use conditional codes, so we just return the opcode
740a34c753fSRafael Auler     // of the conditional branch here.
741a34c753fSRafael Auler     return Inst.getOpcode();
742a34c753fSRafael Auler   }
743a34c753fSRafael Auler 
744a34c753fSRafael Auler   unsigned getCanonicalBranchCondCode(unsigned Opcode) const override {
745a34c753fSRafael Auler     switch (Opcode) {
746a34c753fSRafael Auler     default:
747a34c753fSRafael Auler       return Opcode;
748a34c753fSRafael Auler     case AArch64::TBNZW:    return AArch64::TBZW;
749a34c753fSRafael Auler     case AArch64::TBNZX:    return AArch64::TBZX;
750a34c753fSRafael Auler     case AArch64::CBNZW:    return AArch64::CBZW;
751a34c753fSRafael Auler     case AArch64::CBNZX:    return AArch64::CBZX;
752a34c753fSRafael Auler     }
753a34c753fSRafael Auler   }
754a34c753fSRafael Auler 
755a34c753fSRafael Auler   bool reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,
756a34c753fSRafael Auler                               MCContext *Ctx) const override {
757a34c753fSRafael Auler     if (isTB(Inst) || isCB(Inst)) {
758a34c753fSRafael Auler       Inst.setOpcode(getInvertedBranchOpcode(Inst.getOpcode()));
759a34c753fSRafael Auler       assert(Inst.getOpcode() != 0 && "Invalid branch instruction");
760a34c753fSRafael Auler     } else if (Inst.getOpcode() == AArch64::Bcc) {
761a34c753fSRafael Auler       Inst.getOperand(0).setImm(AArch64CC::getInvertedCondCode(
762a34c753fSRafael Auler           static_cast<AArch64CC::CondCode>(Inst.getOperand(0).getImm())));
763a34c753fSRafael Auler       assert(Inst.getOperand(0).getImm() != AArch64CC::AL &&
764a34c753fSRafael Auler              Inst.getOperand(0).getImm() != AArch64CC::NV &&
765a34c753fSRafael Auler              "Can't reverse ALWAYS cond code");
766a34c753fSRafael Auler     } else {
767a34c753fSRafael Auler       LLVM_DEBUG(Inst.dump());
768a34c753fSRafael Auler       llvm_unreachable("Unrecognized branch instruction");
769a34c753fSRafael Auler     }
770a34c753fSRafael Auler     return replaceBranchTarget(Inst, TBB, Ctx);
771a34c753fSRafael Auler   }
772a34c753fSRafael Auler 
773a34c753fSRafael Auler   int getPCRelEncodingSize(const MCInst &Inst) const override {
774a34c753fSRafael Auler     switch (Inst.getOpcode()) {
775a34c753fSRafael Auler     default:
776a34c753fSRafael Auler       llvm_unreachable("Failed to get pcrel encoding size");
777a34c753fSRafael Auler       return 0;
778a34c753fSRafael Auler     case AArch64::TBZW:     return 16;
779a34c753fSRafael Auler     case AArch64::TBZX:     return 16;
780a34c753fSRafael Auler     case AArch64::TBNZW:    return 16;
781a34c753fSRafael Auler     case AArch64::TBNZX:    return 16;
782a34c753fSRafael Auler     case AArch64::CBZW:     return 21;
783a34c753fSRafael Auler     case AArch64::CBZX:     return 21;
784a34c753fSRafael Auler     case AArch64::CBNZW:    return 21;
785a34c753fSRafael Auler     case AArch64::CBNZX:    return 21;
786a34c753fSRafael Auler     case AArch64::B:        return 28;
787a34c753fSRafael Auler     case AArch64::BL:       return 28;
788a34c753fSRafael Auler     case AArch64::Bcc:      return 21;
789a34c753fSRafael Auler     }
790a34c753fSRafael Auler   }
791a34c753fSRafael Auler 
79240c2e0faSMaksim Panchenko   int getShortJmpEncodingSize() const override { return 33; }
793a34c753fSRafael Auler 
79440c2e0faSMaksim Panchenko   int getUncondBranchEncodingSize() const override { return 28; }
795a34c753fSRafael Auler 
796a34c753fSRafael Auler   bool createTailCall(MCInst &Inst, const MCSymbol *Target,
797a34c753fSRafael Auler                       MCContext *Ctx) override {
798a34c753fSRafael Auler     Inst.setOpcode(AArch64::B);
799a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(getTargetExprFor(
800a34c753fSRafael Auler         Inst, MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
801a34c753fSRafael Auler         *Ctx, 0)));
802a34c753fSRafael Auler     setTailCall(Inst);
803a34c753fSRafael Auler     return true;
804a34c753fSRafael Auler   }
805a34c753fSRafael Auler 
80669706eafSMaksim Panchenko   void createLongTailCall(InstructionListType &Seq, const MCSymbol *Target,
807a34c753fSRafael Auler                           MCContext *Ctx) override {
808a34c753fSRafael Auler     createShortJmp(Seq, Target, Ctx, /*IsTailCall*/ true);
809a34c753fSRafael Auler   }
810a34c753fSRafael Auler 
811a34c753fSRafael Auler   bool convertJmpToTailCall(MCInst &Inst) override {
812a34c753fSRafael Auler     setTailCall(Inst);
813a34c753fSRafael Auler     return true;
814a34c753fSRafael Auler   }
815a34c753fSRafael Auler 
816a34c753fSRafael Auler   bool convertTailCallToJmp(MCInst &Inst) override {
817a34c753fSRafael Auler     removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
818a34c753fSRafael Auler     removeAnnotation(Inst, "Offset");
819a34c753fSRafael Auler     if (getConditionalTailCall(Inst))
820a34c753fSRafael Auler       unsetConditionalTailCall(Inst);
821a34c753fSRafael Auler     return true;
822a34c753fSRafael Auler   }
823a34c753fSRafael Auler 
824a34c753fSRafael Auler   bool lowerTailCall(MCInst &Inst) override {
825a34c753fSRafael Auler     removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
826a34c753fSRafael Auler     if (getConditionalTailCall(Inst))
827a34c753fSRafael Auler       unsetConditionalTailCall(Inst);
828a34c753fSRafael Auler     return true;
829a34c753fSRafael Auler   }
830a34c753fSRafael Auler 
831a34c753fSRafael Auler   bool isNoop(const MCInst &Inst) const override {
832a34c753fSRafael Auler     return Inst.getOpcode() == AArch64::HINT &&
833a34c753fSRafael Auler            Inst.getOperand(0).getImm() == 0;
834a34c753fSRafael Auler   }
835a34c753fSRafael Auler 
836a34c753fSRafael Auler   bool createNoop(MCInst &Inst) const override {
837a34c753fSRafael Auler     Inst.setOpcode(AArch64::HINT);
838a34c753fSRafael Auler     Inst.clear();
839a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0));
840a34c753fSRafael Auler     return true;
841a34c753fSRafael Auler   }
842a34c753fSRafael Auler 
84340c2e0faSMaksim Panchenko   bool isStore(const MCInst &Inst) const override { return false; }
844a34c753fSRafael Auler 
84540c2e0faSMaksim Panchenko   bool analyzeBranch(InstructionIterator Begin, InstructionIterator End,
84640c2e0faSMaksim Panchenko                      const MCSymbol *&TBB, const MCSymbol *&FBB,
847a34c753fSRafael Auler                      MCInst *&CondBranch,
848a34c753fSRafael Auler                      MCInst *&UncondBranch) const override {
849a34c753fSRafael Auler     auto I = End;
850a34c753fSRafael Auler 
851a34c753fSRafael Auler     while (I != Begin) {
852a34c753fSRafael Auler       --I;
853a34c753fSRafael Auler 
854a34c753fSRafael Auler       // Ignore nops and CFIs
855a34c753fSRafael Auler       if (isPseudo(*I) || isNoop(*I))
856a34c753fSRafael Auler         continue;
857a34c753fSRafael Auler 
858a34c753fSRafael Auler       // Stop when we find the first non-terminator
859a34c753fSRafael Auler       if (!isTerminator(*I) || isTailCall(*I) || !isBranch(*I))
860a34c753fSRafael Auler         break;
861a34c753fSRafael Auler 
862a34c753fSRafael Auler       // Handle unconditional branches.
863a34c753fSRafael Auler       if (isUnconditionalBranch(*I)) {
864a34c753fSRafael Auler         // If any code was seen after this unconditional branch, we've seen
865a34c753fSRafael Auler         // unreachable code. Ignore them.
866a34c753fSRafael Auler         CondBranch = nullptr;
867a34c753fSRafael Auler         UncondBranch = &*I;
868a34c753fSRafael Auler         const MCSymbol *Sym = getTargetSymbol(*I);
869a34c753fSRafael Auler         assert(Sym != nullptr &&
870a34c753fSRafael Auler                "Couldn't extract BB symbol from jump operand");
871a34c753fSRafael Auler         TBB = Sym;
872a34c753fSRafael Auler         continue;
873a34c753fSRafael Auler       }
874a34c753fSRafael Auler 
875a34c753fSRafael Auler       // Handle conditional branches and ignore indirect branches
876a34c753fSRafael Auler       if (isIndirectBranch(*I)) {
877a34c753fSRafael Auler         return false;
878a34c753fSRafael Auler       }
879a34c753fSRafael Auler 
880a34c753fSRafael Auler       if (CondBranch == nullptr) {
881a34c753fSRafael Auler         const MCSymbol *TargetBB = getTargetSymbol(*I);
882a34c753fSRafael Auler         if (TargetBB == nullptr) {
883a34c753fSRafael Auler           // Unrecognized branch target
884a34c753fSRafael Auler           return false;
885a34c753fSRafael Auler         }
886a34c753fSRafael Auler         FBB = TBB;
887a34c753fSRafael Auler         TBB = TargetBB;
888a34c753fSRafael Auler         CondBranch = &*I;
889a34c753fSRafael Auler         continue;
890a34c753fSRafael Auler       }
891a34c753fSRafael Auler 
892a34c753fSRafael Auler       llvm_unreachable("multiple conditional branches in one BB");
893a34c753fSRafael Auler     }
894a34c753fSRafael Auler     return true;
895a34c753fSRafael Auler   }
896a34c753fSRafael Auler 
89769706eafSMaksim Panchenko   void createLongJmp(InstructionListType &Seq, const MCSymbol *Target,
898a34c753fSRafael Auler                      MCContext *Ctx, bool IsTailCall) override {
899a34c753fSRafael Auler     // ip0 (r16) is reserved to the linker (refer to 5.3.1.1 of "Procedure Call
900a34c753fSRafael Auler     //   Standard for the ARM 64-bit Architecture (AArch64)".
901a34c753fSRafael Auler     // The sequence of instructions we create here is the following:
902a34c753fSRafael Auler     //  movz ip0, #:abs_g3:<addr>
903a34c753fSRafael Auler     //  movk ip0, #:abs_g2_nc:<addr>
904a34c753fSRafael Auler     //  movk ip0, #:abs_g1_nc:<addr>
905a34c753fSRafael Auler     //  movk ip0, #:abs_g0_nc:<addr>
906a34c753fSRafael Auler     //  br ip0
907a34c753fSRafael Auler     MCInst Inst;
908a34c753fSRafael Auler     Inst.setOpcode(AArch64::MOVZXi);
909a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
910a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
911a34c753fSRafael Auler         MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
912a34c753fSRafael Auler         AArch64MCExpr::VK_ABS_G3, *Ctx)));
913a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0x30));
914a34c753fSRafael Auler     Seq.emplace_back(Inst);
915a34c753fSRafael Auler 
916a34c753fSRafael Auler     Inst.clear();
917a34c753fSRafael Auler     Inst.setOpcode(AArch64::MOVKXi);
918a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
919a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
920a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
921a34c753fSRafael Auler         MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
922a34c753fSRafael Auler         AArch64MCExpr::VK_ABS_G2_NC, *Ctx)));
923a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0x20));
924a34c753fSRafael Auler     Seq.emplace_back(Inst);
925a34c753fSRafael Auler 
926a34c753fSRafael Auler     Inst.clear();
927a34c753fSRafael Auler     Inst.setOpcode(AArch64::MOVKXi);
928a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
929a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
930a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
931a34c753fSRafael Auler         MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
932a34c753fSRafael Auler         AArch64MCExpr::VK_ABS_G1_NC, *Ctx)));
933a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0x10));
934a34c753fSRafael Auler     Seq.emplace_back(Inst);
935a34c753fSRafael Auler 
936a34c753fSRafael Auler     Inst.clear();
937a34c753fSRafael Auler     Inst.setOpcode(AArch64::MOVKXi);
938a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
939a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
940a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
941a34c753fSRafael Auler         MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
942a34c753fSRafael Auler         AArch64MCExpr::VK_ABS_G0_NC, *Ctx)));
943a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0));
944a34c753fSRafael Auler     Seq.emplace_back(Inst);
945a34c753fSRafael Auler 
946a34c753fSRafael Auler     Inst.clear();
947a34c753fSRafael Auler     Inst.setOpcode(AArch64::BR);
948a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
949a34c753fSRafael Auler     if (IsTailCall)
950a34c753fSRafael Auler       setTailCall(Inst);
951a34c753fSRafael Auler     Seq.emplace_back(Inst);
952a34c753fSRafael Auler   }
953a34c753fSRafael Auler 
95469706eafSMaksim Panchenko   void createShortJmp(InstructionListType &Seq, const MCSymbol *Target,
955a34c753fSRafael Auler                       MCContext *Ctx, bool IsTailCall) override {
956a34c753fSRafael Auler     // ip0 (r16) is reserved to the linker (refer to 5.3.1.1 of "Procedure Call
957a34c753fSRafael Auler     //   Standard for the ARM 64-bit Architecture (AArch64)".
958a34c753fSRafael Auler     // The sequence of instructions we create here is the following:
959a34c753fSRafael Auler     //  adrp ip0, imm
960a34c753fSRafael Auler     //  add ip0, ip0, imm
961a34c753fSRafael Auler     //  br ip0
962a34c753fSRafael Auler     MCPhysReg Reg = AArch64::X16;
96369706eafSMaksim Panchenko     InstructionListType Insts = materializeAddress(Target, Ctx, Reg);
964a34c753fSRafael Auler     Insts.emplace_back();
965a34c753fSRafael Auler     MCInst &Inst = Insts.back();
966a34c753fSRafael Auler     Inst.clear();
967a34c753fSRafael Auler     Inst.setOpcode(AArch64::BR);
968a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(Reg));
969a34c753fSRafael Auler     if (IsTailCall)
970a34c753fSRafael Auler       setTailCall(Inst);
971a34c753fSRafael Auler     Seq.swap(Insts);
972a34c753fSRafael Auler   }
973a34c753fSRafael Auler 
974a34c753fSRafael Auler   /// Matching pattern here is
975a34c753fSRafael Auler   ///
976a34c753fSRafael Auler   ///    ADRP  x16, imm
977a34c753fSRafael Auler   ///    ADD   x16, x16, imm
978a34c753fSRafael Auler   ///    BR    x16
979a34c753fSRafael Auler   ///
980a34c753fSRafael Auler   bool matchLinkerVeneer(InstructionIterator Begin, InstructionIterator End,
981a34c753fSRafael Auler                          uint64_t Address, const MCInst &CurInst,
982a34c753fSRafael Auler                          MCInst *&TargetHiBits, MCInst *&TargetLowBits,
983a34c753fSRafael Auler                          uint64_t &Target) const override {
984a34c753fSRafael Auler     if (CurInst.getOpcode() != AArch64::BR || !CurInst.getOperand(0).isReg() ||
985a34c753fSRafael Auler         CurInst.getOperand(0).getReg() != AArch64::X16)
986a34c753fSRafael Auler       return false;
987a34c753fSRafael Auler 
988a34c753fSRafael Auler     auto I = End;
989a34c753fSRafael Auler     if (I == Begin)
990a34c753fSRafael Auler       return false;
991a34c753fSRafael Auler 
992a34c753fSRafael Auler     --I;
993a34c753fSRafael Auler     Address -= 4;
994a34c753fSRafael Auler     if (I == Begin ||
995a34c753fSRafael Auler         I->getOpcode() != AArch64::ADDXri ||
996a34c753fSRafael Auler         MCPlus::getNumPrimeOperands(*I) < 3 ||
997a34c753fSRafael Auler         !I->getOperand(0).isReg() ||
998a34c753fSRafael Auler         !I->getOperand(1).isReg() ||
999a34c753fSRafael Auler         I->getOperand(0).getReg() != AArch64::X16 ||
1000a34c753fSRafael Auler         I->getOperand(1).getReg() != AArch64::X16 ||
1001a34c753fSRafael Auler         !I->getOperand(2).isImm())
1002a34c753fSRafael Auler       return false;
1003a34c753fSRafael Auler     TargetLowBits = &*I;
1004a34c753fSRafael Auler     uint64_t Addr = I->getOperand(2).getImm() & 0xFFF;
1005a34c753fSRafael Auler 
1006a34c753fSRafael Auler     --I;
1007a34c753fSRafael Auler     Address -= 4;
1008a34c753fSRafael Auler     if (I->getOpcode() != AArch64::ADRP ||
1009a34c753fSRafael Auler         MCPlus::getNumPrimeOperands(*I) < 2 ||
1010a34c753fSRafael Auler         !I->getOperand(0).isReg() ||
1011a34c753fSRafael Auler         !I->getOperand(1).isImm() ||
1012a34c753fSRafael Auler         I->getOperand(0).getReg() != AArch64::X16)
1013a34c753fSRafael Auler       return false;
1014a34c753fSRafael Auler     TargetHiBits = &*I;
1015a34c753fSRafael Auler     Addr |= (Address + ((int64_t)I->getOperand(1).getImm() << 12)) &
1016a34c753fSRafael Auler             0xFFFFFFFFFFFFF000ULL;
1017a34c753fSRafael Auler     Target = Addr;
1018a34c753fSRafael Auler     return true;
1019a34c753fSRafael Auler   }
1020a34c753fSRafael Auler 
1021a34c753fSRafael Auler   bool replaceImmWithSymbolRef(MCInst &Inst, const MCSymbol *Symbol,
1022a34c753fSRafael Auler                                int64_t Addend, MCContext *Ctx, int64_t &Value,
1023a34c753fSRafael Auler                                uint64_t RelType) const override {
1024a34c753fSRafael Auler     unsigned ImmOpNo = -1U;
1025a34c753fSRafael Auler     for (unsigned Index = 0; Index < MCPlus::getNumPrimeOperands(Inst);
1026a34c753fSRafael Auler          ++Index) {
1027a34c753fSRafael Auler       if (Inst.getOperand(Index).isImm()) {
1028a34c753fSRafael Auler         ImmOpNo = Index;
1029a34c753fSRafael Auler         break;
1030a34c753fSRafael Auler       }
1031a34c753fSRafael Auler     }
1032a34c753fSRafael Auler     if (ImmOpNo == -1U)
1033a34c753fSRafael Auler       return false;
1034a34c753fSRafael Auler 
1035a34c753fSRafael Auler     Value = Inst.getOperand(ImmOpNo).getImm();
1036a34c753fSRafael Auler 
1037a34c753fSRafael Auler     setOperandToSymbolRef(Inst, ImmOpNo, Symbol, Addend, Ctx, RelType);
1038a34c753fSRafael Auler 
1039a34c753fSRafael Auler     return true;
1040a34c753fSRafael Auler   }
1041a34c753fSRafael Auler 
1042a34c753fSRafael Auler   bool createUncondBranch(MCInst &Inst, const MCSymbol *TBB,
1043a34c753fSRafael Auler                           MCContext *Ctx) const override {
1044a34c753fSRafael Auler     Inst.setOpcode(AArch64::B);
1045a34c753fSRafael Auler     Inst.clear();
1046a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(getTargetExprFor(
1047a34c753fSRafael Auler         Inst, MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx),
1048a34c753fSRafael Auler         *Ctx, 0)));
1049a34c753fSRafael Auler     return true;
1050a34c753fSRafael Auler   }
1051a34c753fSRafael Auler 
105240c2e0faSMaksim Panchenko   bool isMoveMem2Reg(const MCInst &Inst) const override { return false; }
1053a34c753fSRafael Auler 
105440c2e0faSMaksim Panchenko   bool isADD64rr(const MCInst &Inst) const override { return false; }
1055a34c753fSRafael Auler 
105640c2e0faSMaksim Panchenko   bool isLeave(const MCInst &Inst) const override { return false; }
1057a34c753fSRafael Auler 
105840c2e0faSMaksim Panchenko   bool isPop(const MCInst &Inst) const override { return false; }
1059a34c753fSRafael Auler 
106040c2e0faSMaksim Panchenko   bool isPrefix(const MCInst &Inst) const override { return false; }
1061a34c753fSRafael Auler 
106240c2e0faSMaksim Panchenko   bool deleteREPPrefix(MCInst &Inst) const override { return false; }
1063a34c753fSRafael Auler 
1064a34c753fSRafael Auler   bool createReturn(MCInst &Inst) const override {
1065a34c753fSRafael Auler     Inst.setOpcode(AArch64::RET);
1066a34c753fSRafael Auler     Inst.clear();
1067a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::LR));
1068a34c753fSRafael Auler     return true;
1069a34c753fSRafael Auler   }
1070a34c753fSRafael Auler 
107169706eafSMaksim Panchenko   InstructionListType materializeAddress(const MCSymbol *Target, MCContext *Ctx,
1072a34c753fSRafael Auler                                          MCPhysReg RegName,
1073a34c753fSRafael Auler                                          int64_t Addend = 0) const override {
1074a34c753fSRafael Auler     // Get page-aligned address and add page offset
107569706eafSMaksim Panchenko     InstructionListType Insts(2);
1076a34c753fSRafael Auler     Insts[0].setOpcode(AArch64::ADRP);
1077a34c753fSRafael Auler     Insts[0].clear();
1078a34c753fSRafael Auler     Insts[0].addOperand(MCOperand::createReg(RegName));
1079a34c753fSRafael Auler     Insts[0].addOperand(MCOperand::createImm(0));
1080a34c753fSRafael Auler     setOperandToSymbolRef(Insts[0], /* OpNum */ 1, Target, Addend, Ctx,
1081a34c753fSRafael Auler                           ELF::R_AARCH64_NONE);
1082a34c753fSRafael Auler     Insts[1].setOpcode(AArch64::ADDXri);
1083a34c753fSRafael Auler     Insts[1].clear();
1084a34c753fSRafael Auler     Insts[1].addOperand(MCOperand::createReg(RegName));
1085a34c753fSRafael Auler     Insts[1].addOperand(MCOperand::createReg(RegName));
1086a34c753fSRafael Auler     Insts[1].addOperand(MCOperand::createImm(0));
1087a34c753fSRafael Auler     Insts[1].addOperand(MCOperand::createImm(0));
1088a34c753fSRafael Auler     setOperandToSymbolRef(Insts[1], /* OpNum */ 2, Target, Addend, Ctx,
1089a34c753fSRafael Auler                           ELF::R_AARCH64_ADD_ABS_LO12_NC);
1090a34c753fSRafael Auler     return Insts;
1091a34c753fSRafael Auler   }
1092a34c753fSRafael Auler };
1093a34c753fSRafael Auler 
1094a34c753fSRafael Auler } // end anonymous namespace
1095a34c753fSRafael Auler 
1096a34c753fSRafael Auler namespace llvm {
1097a34c753fSRafael Auler namespace bolt {
1098a34c753fSRafael Auler 
1099a34c753fSRafael Auler MCPlusBuilder *createAArch64MCPlusBuilder(const MCInstrAnalysis *Analysis,
1100a34c753fSRafael Auler                                           const MCInstrInfo *Info,
1101a34c753fSRafael Auler                                           const MCRegisterInfo *RegInfo) {
1102a34c753fSRafael Auler   return new AArch64MCPlusBuilder(Analysis, Info, RegInfo);
1103a34c753fSRafael Auler }
1104a34c753fSRafael Auler 
110540c2e0faSMaksim Panchenko } // namespace bolt
110640c2e0faSMaksim Panchenko } // namespace llvm
1107