xref: /llvm-project/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp (revision b6b492880f5ac6357d85ba2f3ad8e41fded1d97c)
12f09f445SMaksim 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 //
92f09f445SMaksim Panchenko // This file provides AArch64-specific MCPlus builder.
10a34c753fSRafael Auler //
11a34c753fSRafael Auler //===----------------------------------------------------------------------===//
12a34c753fSRafael Auler 
13a34c753fSRafael Auler #include "MCTargetDesc/AArch64AddressingModes.h"
1462020a3aSzhoujiapeng #include "MCTargetDesc/AArch64FixupKinds.h"
15a34c753fSRafael Auler #include "MCTargetDesc/AArch64MCExpr.h"
16a34c753fSRafael Auler #include "MCTargetDesc/AArch64MCTargetDesc.h"
17a34c753fSRafael Auler #include "Utils/AArch64BaseInfo.h"
18a34c753fSRafael Auler #include "bolt/Core/MCPlusBuilder.h"
19a34c753fSRafael Auler #include "llvm/BinaryFormat/ELF.h"
206e4c2305SElvina Yakubova #include "llvm/MC/MCContext.h"
2162020a3aSzhoujiapeng #include "llvm/MC/MCFixupKindInfo.h"
226e4c2305SElvina Yakubova #include "llvm/MC/MCInstBuilder.h"
23a34c753fSRafael Auler #include "llvm/MC/MCInstrInfo.h"
24a34c753fSRafael Auler #include "llvm/MC/MCRegisterInfo.h"
25a34c753fSRafael Auler #include "llvm/Support/Debug.h"
26a34c753fSRafael Auler #include "llvm/Support/ErrorHandling.h"
27a34c753fSRafael Auler 
28bc9032c7SMaksim Panchenko #define DEBUG_TYPE "mcplus"
29a34c753fSRafael Auler 
30a34c753fSRafael Auler using namespace llvm;
31a34c753fSRafael Auler using namespace bolt;
32a34c753fSRafael Auler 
33a34c753fSRafael Auler namespace {
34a34c753fSRafael Auler 
356e4c2305SElvina Yakubova static void getSystemFlag(MCInst &Inst, MCPhysReg RegName) {
366e4c2305SElvina Yakubova   Inst.setOpcode(AArch64::MRS);
376e4c2305SElvina Yakubova   Inst.clear();
386e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(RegName));
396e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createImm(AArch64SysReg::NZCV));
406e4c2305SElvina Yakubova }
416e4c2305SElvina Yakubova 
426e4c2305SElvina Yakubova static void setSystemFlag(MCInst &Inst, MCPhysReg RegName) {
436e4c2305SElvina Yakubova   Inst.setOpcode(AArch64::MSR);
446e4c2305SElvina Yakubova   Inst.clear();
456e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createImm(AArch64SysReg::NZCV));
466e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(RegName));
476e4c2305SElvina Yakubova }
486e4c2305SElvina Yakubova 
496e4c2305SElvina Yakubova static void createPushRegisters(MCInst &Inst, MCPhysReg Reg1, MCPhysReg Reg2) {
506e4c2305SElvina Yakubova   Inst.clear();
516e4c2305SElvina Yakubova   unsigned NewOpcode = AArch64::STPXpre;
526e4c2305SElvina Yakubova   Inst.setOpcode(NewOpcode);
536e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(AArch64::SP));
546e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(Reg1));
556e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(Reg2));
566e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(AArch64::SP));
576e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createImm(-2));
586e4c2305SElvina Yakubova }
596e4c2305SElvina Yakubova 
606e4c2305SElvina Yakubova static void createPopRegisters(MCInst &Inst, MCPhysReg Reg1, MCPhysReg Reg2) {
616e4c2305SElvina Yakubova   Inst.clear();
626e4c2305SElvina Yakubova   unsigned NewOpcode = AArch64::LDPXpost;
636e4c2305SElvina Yakubova   Inst.setOpcode(NewOpcode);
646e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(AArch64::SP));
656e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(Reg1));
666e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(Reg2));
676e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(AArch64::SP));
686e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createImm(2));
696e4c2305SElvina Yakubova }
706e4c2305SElvina Yakubova 
716e4c2305SElvina Yakubova static void loadReg(MCInst &Inst, MCPhysReg To, MCPhysReg From) {
726e4c2305SElvina Yakubova   Inst.setOpcode(AArch64::LDRXui);
736e4c2305SElvina Yakubova   Inst.clear();
746e4c2305SElvina Yakubova   if (From == AArch64::SP) {
756e4c2305SElvina Yakubova     Inst.setOpcode(AArch64::LDRXpost);
766e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(From));
776e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(To));
786e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(From));
796e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(16));
806e4c2305SElvina Yakubova   } else {
816e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(To));
826e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(From));
836e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(0));
846e4c2305SElvina Yakubova   }
856e4c2305SElvina Yakubova }
866e4c2305SElvina Yakubova 
876e4c2305SElvina Yakubova static void storeReg(MCInst &Inst, MCPhysReg From, MCPhysReg To) {
886e4c2305SElvina Yakubova   Inst.setOpcode(AArch64::STRXui);
896e4c2305SElvina Yakubova   Inst.clear();
906e4c2305SElvina Yakubova   if (To == AArch64::SP) {
916e4c2305SElvina Yakubova     Inst.setOpcode(AArch64::STRXpre);
926e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(To));
936e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(From));
946e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(To));
956e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(-16));
966e4c2305SElvina Yakubova   } else {
976e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(From));
986e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(To));
996e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(0));
1006e4c2305SElvina Yakubova   }
1016e4c2305SElvina Yakubova }
1026e4c2305SElvina Yakubova 
1036e4c2305SElvina Yakubova static void atomicAdd(MCInst &Inst, MCPhysReg RegTo, MCPhysReg RegCnt) {
1046e4c2305SElvina Yakubova   // NOTE: Supports only ARM with LSE extension
1056e4c2305SElvina Yakubova   Inst.setOpcode(AArch64::LDADDX);
1066e4c2305SElvina Yakubova   Inst.clear();
1076e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(AArch64::XZR));
1086e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(RegCnt));
1096e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(RegTo));
1106e4c2305SElvina Yakubova }
1116e4c2305SElvina Yakubova 
1126e4c2305SElvina Yakubova static void createMovz(MCInst &Inst, MCPhysReg Reg, uint64_t Imm) {
1136e4c2305SElvina Yakubova   assert(Imm <= UINT16_MAX && "Invalid Imm size");
1146e4c2305SElvina Yakubova   Inst.clear();
1156e4c2305SElvina Yakubova   Inst.setOpcode(AArch64::MOVZXi);
1166e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(Reg));
1176e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createImm(Imm & 0xFFFF));
1186e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createImm(0));
1196e4c2305SElvina Yakubova }
1206e4c2305SElvina Yakubova 
1216e4c2305SElvina Yakubova static InstructionListType createIncMemory(MCPhysReg RegTo, MCPhysReg RegTmp) {
1226e4c2305SElvina Yakubova   InstructionListType Insts;
1236e4c2305SElvina Yakubova   Insts.emplace_back();
1246e4c2305SElvina Yakubova   createMovz(Insts.back(), RegTmp, 1);
1256e4c2305SElvina Yakubova   Insts.emplace_back();
1266e4c2305SElvina Yakubova   atomicAdd(Insts.back(), RegTo, RegTmp);
1276e4c2305SElvina Yakubova   return Insts;
1286e4c2305SElvina Yakubova }
129a34c753fSRafael Auler class AArch64MCPlusBuilder : public MCPlusBuilder {
130a34c753fSRafael Auler public:
1318fb83bf5SJob Noorman   using MCPlusBuilder::MCPlusBuilder;
132a34c753fSRafael Auler 
133a34c753fSRafael Auler   bool equals(const MCTargetExpr &A, const MCTargetExpr &B,
134a34c753fSRafael Auler               CompFuncTy Comp) const override {
135a34c753fSRafael Auler     const auto &AArch64ExprA = cast<AArch64MCExpr>(A);
136a34c753fSRafael Auler     const auto &AArch64ExprB = cast<AArch64MCExpr>(B);
137a34c753fSRafael Auler     if (AArch64ExprA.getKind() != AArch64ExprB.getKind())
138a34c753fSRafael Auler       return false;
139a34c753fSRafael Auler 
140a34c753fSRafael Auler     return MCPlusBuilder::equals(*AArch64ExprA.getSubExpr(),
141a34c753fSRafael Auler                                  *AArch64ExprB.getSubExpr(), Comp);
142a34c753fSRafael Auler   }
143a34c753fSRafael Auler 
144a34c753fSRafael Auler   bool isMacroOpFusionPair(ArrayRef<MCInst> Insts) const override {
145a34c753fSRafael Auler     return false;
146a34c753fSRafael Auler   }
147a34c753fSRafael Auler 
148dc1cf838SAmir Ayupov   bool shortenInstruction(MCInst &, const MCSubtargetInfo &) const override {
149dc1cf838SAmir Ayupov     return false;
150dc1cf838SAmir Ayupov   }
151a34c753fSRafael Auler 
152a34c753fSRafael Auler   bool isADRP(const MCInst &Inst) const override {
153a34c753fSRafael Auler     return Inst.getOpcode() == AArch64::ADRP;
154a34c753fSRafael Auler   }
155a34c753fSRafael Auler 
156a34c753fSRafael Auler   bool isADR(const MCInst &Inst) const override {
157a34c753fSRafael Auler     return Inst.getOpcode() == AArch64::ADR;
158a34c753fSRafael Auler   }
159a34c753fSRafael Auler 
16017ed8f29SVladislav Khmelevsky   bool isAddXri(const MCInst &Inst) const {
16117ed8f29SVladislav Khmelevsky     return Inst.getOpcode() == AArch64::ADDXri;
16217ed8f29SVladislav Khmelevsky   }
16317ed8f29SVladislav Khmelevsky 
164a34c753fSRafael Auler   void getADRReg(const MCInst &Inst, MCPhysReg &RegName) const override {
165a34c753fSRafael Auler     assert((isADR(Inst) || isADRP(Inst)) && "Not an ADR instruction");
166a34c753fSRafael Auler     assert(MCPlus::getNumPrimeOperands(Inst) != 0 &&
167a34c753fSRafael Auler            "No operands for ADR instruction");
168a34c753fSRafael Auler     assert(Inst.getOperand(0).isReg() &&
169a34c753fSRafael Auler            "Unexpected operand in ADR instruction");
170a34c753fSRafael Auler     RegName = Inst.getOperand(0).getReg();
171a34c753fSRafael Auler   }
172a34c753fSRafael Auler 
173a34c753fSRafael Auler   bool isTB(const MCInst &Inst) const {
174a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::TBNZW ||
175a34c753fSRafael Auler             Inst.getOpcode() == AArch64::TBNZX ||
176a34c753fSRafael Auler             Inst.getOpcode() == AArch64::TBZW ||
177a34c753fSRafael Auler             Inst.getOpcode() == AArch64::TBZX);
178a34c753fSRafael Auler   }
179a34c753fSRafael Auler 
180a34c753fSRafael Auler   bool isCB(const MCInst &Inst) const {
181a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::CBNZW ||
182a34c753fSRafael Auler             Inst.getOpcode() == AArch64::CBNZX ||
183a34c753fSRafael Auler             Inst.getOpcode() == AArch64::CBZW ||
184a34c753fSRafael Auler             Inst.getOpcode() == AArch64::CBZX);
185a34c753fSRafael Auler   }
186a34c753fSRafael Auler 
187a34c753fSRafael Auler   bool isMOVW(const MCInst &Inst) const {
188a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::MOVKWi ||
189a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVKXi ||
190a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVNWi ||
191a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVNXi ||
192a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVZXi ||
193a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVZWi);
194a34c753fSRafael Auler   }
195a34c753fSRafael Auler 
196a34c753fSRafael Auler   bool isADD(const MCInst &Inst) const {
197a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::ADDSWri ||
198a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSWrr ||
199a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSWrs ||
200a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSWrx ||
201a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXri ||
202a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXrr ||
203a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXrs ||
204a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXrx ||
205a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXrx64 ||
206a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDWri ||
207a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDWrr ||
208a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDWrs ||
209a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDWrx ||
210a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXri ||
211a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXrr ||
212a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXrs ||
213a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXrx ||
214a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXrx64);
215a34c753fSRafael Auler   }
216a34c753fSRafael Auler 
217a34c753fSRafael Auler   bool isLDRB(const MCInst &Inst) const {
218a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::LDRBBpost ||
219a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRBBpre ||
220a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRBBroW ||
221a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRBBroX ||
222a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRBBui ||
223a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBWpost ||
224a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBWpre ||
225a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBWroW ||
226a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBWroX ||
227a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBWui ||
228a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBXpost ||
229a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBXpre ||
230a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBXroW ||
231a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBXroX ||
232a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSBXui);
233a34c753fSRafael Auler   }
234a34c753fSRafael Auler 
235a34c753fSRafael Auler   bool isLDRH(const MCInst &Inst) const {
236a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::LDRHHpost ||
237a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRHHpre ||
238a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRHHroW ||
239a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRHHroX ||
240a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRHHui ||
241a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHWpost ||
242a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHWpre ||
243a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHWroW ||
244a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHWroX ||
245a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHWui ||
246a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHXpost ||
247a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHXpre ||
248a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHXroW ||
249a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHXroX ||
250a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRSHXui);
251a34c753fSRafael Auler   }
252a34c753fSRafael Auler 
253a34c753fSRafael Auler   bool isLDRW(const MCInst &Inst) const {
254a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::LDRWpost ||
255a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRWpre ||
256a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRWroW ||
257a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRWroX ||
258a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRWui);
259a34c753fSRafael Auler   }
260a34c753fSRafael Auler 
261a34c753fSRafael Auler   bool isLDRX(const MCInst &Inst) const {
262a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::LDRXpost ||
263a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRXpre ||
264a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRXroW ||
265a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRXroX ||
266a34c753fSRafael Auler             Inst.getOpcode() == AArch64::LDRXui);
267a34c753fSRafael Auler   }
268a34c753fSRafael Auler 
269eafe4ee2SJob Noorman   bool mayLoad(const MCInst &Inst) const override {
270a34c753fSRafael Auler     return isLDRB(Inst) || isLDRH(Inst) || isLDRW(Inst) || isLDRX(Inst);
271a34c753fSRafael Auler   }
272a34c753fSRafael Auler 
273846eb767SVladislav Khmelevsky   bool isAArch64Exclusive(const MCInst &Inst) const override {
274846eb767SVladislav Khmelevsky     return (Inst.getOpcode() == AArch64::LDXPX ||
275846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDXPW ||
276846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDXRX ||
277846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDXRW ||
278846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDXRH ||
279846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDXRB ||
280846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STXPX ||
281846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STXPW ||
282846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STXRX ||
283846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STXRW ||
284846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STXRH ||
285846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STXRB ||
286846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDAXPX ||
287846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDAXPW ||
288846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDAXRX ||
289846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDAXRW ||
290846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDAXRH ||
291846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDAXRB ||
292846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STLXPX ||
293846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STLXPW ||
294846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STLXRX ||
295846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STLXRW ||
296846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STLXRH ||
297846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STLXRB ||
298846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::CLREX);
299846eb767SVladislav Khmelevsky   }
300846eb767SVladislav Khmelevsky 
301a34c753fSRafael Auler   bool isLoadFromStack(const MCInst &Inst) const {
302eafe4ee2SJob Noorman     if (!mayLoad(Inst))
303a34c753fSRafael Auler       return false;
304b6f07d3aSAmir Ayupov     for (const MCOperand &Operand : useOperands(Inst)) {
305a34c753fSRafael Auler       if (!Operand.isReg())
306a34c753fSRafael Auler         continue;
307a34c753fSRafael Auler       unsigned Reg = Operand.getReg();
30840c2e0faSMaksim Panchenko       if (Reg == AArch64::SP || Reg == AArch64::WSP || Reg == AArch64::FP ||
30940c2e0faSMaksim Panchenko           Reg == AArch64::W29)
310a34c753fSRafael Auler         return true;
311a34c753fSRafael Auler     }
312a34c753fSRafael Auler     return false;
313a34c753fSRafael Auler   }
314a34c753fSRafael Auler 
315a34c753fSRafael Auler   bool isRegToRegMove(const MCInst &Inst, MCPhysReg &From,
316a34c753fSRafael Auler                       MCPhysReg &To) const override {
317a34c753fSRafael Auler     if (Inst.getOpcode() != AArch64::ORRXrs)
318a34c753fSRafael Auler       return false;
319a34c753fSRafael Auler     if (Inst.getOperand(1).getReg() != AArch64::XZR)
320a34c753fSRafael Auler       return false;
321a34c753fSRafael Auler     if (Inst.getOperand(3).getImm() != 0)
322a34c753fSRafael Auler       return false;
323a34c753fSRafael Auler     From = Inst.getOperand(2).getReg();
324a34c753fSRafael Auler     To = Inst.getOperand(0).getReg();
325a34c753fSRafael Auler     return true;
326a34c753fSRafael Auler   }
327a34c753fSRafael Auler 
328a34c753fSRafael Auler   bool isIndirectCall(const MCInst &Inst) const override {
329a34c753fSRafael Auler     return Inst.getOpcode() == AArch64::BLR;
330a34c753fSRafael Auler   }
331a34c753fSRafael Auler 
3326e4c2305SElvina Yakubova   MCPhysReg getSpRegister(int Size) const {
3336e4c2305SElvina Yakubova     switch (Size) {
3346e4c2305SElvina Yakubova     case 4:
3356e4c2305SElvina Yakubova       return AArch64::WSP;
3366e4c2305SElvina Yakubova     case 8:
3376e4c2305SElvina Yakubova       return AArch64::SP;
3386e4c2305SElvina Yakubova     default:
3396e4c2305SElvina Yakubova       llvm_unreachable("Unexpected size");
3406e4c2305SElvina Yakubova     }
3416e4c2305SElvina Yakubova   }
3426e4c2305SElvina Yakubova 
3436e4c2305SElvina Yakubova   MCPhysReg getIntArgRegister(unsigned ArgNo) const override {
3446e4c2305SElvina Yakubova     switch (ArgNo) {
3456e4c2305SElvina Yakubova     case 0:
3466e4c2305SElvina Yakubova       return AArch64::X0;
3476e4c2305SElvina Yakubova     case 1:
3486e4c2305SElvina Yakubova       return AArch64::X1;
3496e4c2305SElvina Yakubova     case 2:
3506e4c2305SElvina Yakubova       return AArch64::X2;
3516e4c2305SElvina Yakubova     case 3:
3526e4c2305SElvina Yakubova       return AArch64::X3;
3536e4c2305SElvina Yakubova     case 4:
3546e4c2305SElvina Yakubova       return AArch64::X4;
3556e4c2305SElvina Yakubova     case 5:
3566e4c2305SElvina Yakubova       return AArch64::X5;
3576e4c2305SElvina Yakubova     case 6:
3586e4c2305SElvina Yakubova       return AArch64::X6;
3596e4c2305SElvina Yakubova     case 7:
3606e4c2305SElvina Yakubova       return AArch64::X7;
3616e4c2305SElvina Yakubova     default:
3626e4c2305SElvina Yakubova       return getNoRegister();
3636e4c2305SElvina Yakubova     }
3646e4c2305SElvina Yakubova   }
3656e4c2305SElvina Yakubova 
366a34c753fSRafael Auler   bool hasPCRelOperand(const MCInst &Inst) const override {
367a34c753fSRafael Auler     // ADRP is blacklisted and is an exception. Even though it has a
368a34c753fSRafael Auler     // PC-relative operand, this operand is not a complete symbol reference
369a34c753fSRafael Auler     // and BOLT shouldn't try to process it in isolation.
370a34c753fSRafael Auler     if (isADRP(Inst))
371a34c753fSRafael Auler       return false;
372a34c753fSRafael Auler 
373a34c753fSRafael Auler     if (isADR(Inst))
374a34c753fSRafael Auler       return true;
375a34c753fSRafael Auler 
376a34c753fSRafael Auler     // Look for literal addressing mode (see C1-143 ARM DDI 0487B.a)
377a34c753fSRafael Auler     const MCInstrDesc &MCII = Info->get(Inst.getOpcode());
37889ceb779SAmir Ayupov     for (unsigned I = 0, E = MCII.getNumOperands(); I != E; ++I)
379fbb00337SJay Foad       if (MCII.operands()[I].OperandType == MCOI::OPERAND_PCREL)
380a34c753fSRafael Auler         return true;
38189ceb779SAmir Ayupov 
382a34c753fSRafael Auler     return false;
383a34c753fSRafael Auler   }
384a34c753fSRafael Auler 
385a34c753fSRafael Auler   bool evaluateADR(const MCInst &Inst, int64_t &Imm,
386a34c753fSRafael Auler                    const MCExpr **DispExpr) const {
387a34c753fSRafael Auler     assert((isADR(Inst) || isADRP(Inst)) && "Not an ADR instruction");
388a34c753fSRafael Auler 
389a34c753fSRafael Auler     const MCOperand &Label = Inst.getOperand(1);
390a34c753fSRafael Auler     if (!Label.isImm()) {
391a34c753fSRafael Auler       assert(Label.isExpr() && "Unexpected ADR operand");
392a34c753fSRafael Auler       assert(DispExpr && "DispExpr must be set");
393a34c753fSRafael Auler       *DispExpr = Label.getExpr();
394a34c753fSRafael Auler       return false;
395a34c753fSRafael Auler     }
396a34c753fSRafael Auler 
397a34c753fSRafael Auler     if (Inst.getOpcode() == AArch64::ADR) {
398a34c753fSRafael Auler       Imm = Label.getImm();
399a34c753fSRafael Auler       return true;
400a34c753fSRafael Auler     }
401a34c753fSRafael Auler     Imm = Label.getImm() << 12;
402a34c753fSRafael Auler     return true;
403a34c753fSRafael Auler   }
404a34c753fSRafael Auler 
40540c2e0faSMaksim Panchenko   bool evaluateAArch64MemoryOperand(const MCInst &Inst, int64_t &DispImm,
40640c2e0faSMaksim Panchenko                                     const MCExpr **DispExpr = nullptr) const {
407a34c753fSRafael Auler     if (isADR(Inst) || isADRP(Inst))
408a34c753fSRafael Auler       return evaluateADR(Inst, DispImm, DispExpr);
409a34c753fSRafael Auler 
410a34c753fSRafael Auler     // Literal addressing mode
411a34c753fSRafael Auler     const MCInstrDesc &MCII = Info->get(Inst.getOpcode());
412a34c753fSRafael Auler     for (unsigned I = 0, E = MCII.getNumOperands(); I != E; ++I) {
413fbb00337SJay Foad       if (MCII.operands()[I].OperandType != MCOI::OPERAND_PCREL)
414a34c753fSRafael Auler         continue;
415a34c753fSRafael Auler 
416a34c753fSRafael Auler       if (!Inst.getOperand(I).isImm()) {
417a34c753fSRafael Auler         assert(Inst.getOperand(I).isExpr() && "Unexpected PCREL operand");
418a34c753fSRafael Auler         assert(DispExpr && "DispExpr must be set");
419a34c753fSRafael Auler         *DispExpr = Inst.getOperand(I).getExpr();
420a34c753fSRafael Auler         return true;
421a34c753fSRafael Auler       }
422a34c753fSRafael Auler 
423df3f1e2fSJob Noorman       DispImm = Inst.getOperand(I).getImm() * 4;
424a34c753fSRafael Auler       return true;
425a34c753fSRafael Auler     }
426a34c753fSRafael Auler     return false;
427a34c753fSRafael Auler   }
428a34c753fSRafael Auler 
429a34c753fSRafael Auler   bool evaluateMemOperandTarget(const MCInst &Inst, uint64_t &Target,
430a34c753fSRafael Auler                                 uint64_t Address,
431a34c753fSRafael Auler                                 uint64_t Size) const override {
432a34c753fSRafael Auler     int64_t DispValue;
433a34c753fSRafael Auler     const MCExpr *DispExpr = nullptr;
434a34c753fSRafael Auler     if (!evaluateAArch64MemoryOperand(Inst, DispValue, &DispExpr))
435a34c753fSRafael Auler       return false;
436a34c753fSRafael Auler 
437a34c753fSRafael Auler     // Make sure it's a well-formed addressing we can statically evaluate.
438a34c753fSRafael Auler     if (DispExpr)
439a34c753fSRafael Auler       return false;
440a34c753fSRafael Auler 
441a34c753fSRafael Auler     Target = DispValue;
442a34c753fSRafael Auler     if (Inst.getOpcode() == AArch64::ADRP)
443a34c753fSRafael Auler       Target += Address & ~0xFFFULL;
444a34c753fSRafael Auler     else
445a34c753fSRafael Auler       Target += Address;
446a34c753fSRafael Auler     return true;
447a34c753fSRafael Auler   }
448a34c753fSRafael Auler 
4498d1fc45dSRafael Auler   MCInst::iterator getMemOperandDisp(MCInst &Inst) const override {
450a34c753fSRafael Auler     MCInst::iterator OI = Inst.begin();
451a34c753fSRafael Auler     if (isADR(Inst) || isADRP(Inst)) {
452a34c753fSRafael Auler       assert(MCPlus::getNumPrimeOperands(Inst) >= 2 &&
453a34c753fSRafael Auler              "Unexpected number of operands");
4548d1fc45dSRafael Auler       return ++OI;
4558d1fc45dSRafael Auler     }
456a34c753fSRafael Auler     const MCInstrDesc &MCII = Info->get(Inst.getOpcode());
457a34c753fSRafael Auler     for (unsigned I = 0, E = MCII.getNumOperands(); I != E; ++I) {
458fbb00337SJay Foad       if (MCII.operands()[I].OperandType == MCOI::OPERAND_PCREL)
459a34c753fSRafael Auler         break;
460a34c753fSRafael Auler       ++OI;
461a34c753fSRafael Auler     }
462a34c753fSRafael Auler     assert(OI != Inst.end() && "Literal operand not found");
4638d1fc45dSRafael Auler     return OI;
464a34c753fSRafael Auler   }
4658d1fc45dSRafael Auler 
4668d1fc45dSRafael Auler   bool replaceMemOperandDisp(MCInst &Inst, MCOperand Operand) const override {
4678d1fc45dSRafael Auler     MCInst::iterator OI = getMemOperandDisp(Inst);
468a34c753fSRafael Auler     *OI = Operand;
469a34c753fSRafael Auler     return true;
470a34c753fSRafael Auler   }
471a34c753fSRafael Auler 
4722d902d0fSKepontry   void getCalleeSavedRegs(BitVector &Regs) const override {
4732d902d0fSKepontry     Regs |= getAliases(AArch64::X18);
4742d902d0fSKepontry     Regs |= getAliases(AArch64::X19);
4752d902d0fSKepontry     Regs |= getAliases(AArch64::X20);
4762d902d0fSKepontry     Regs |= getAliases(AArch64::X21);
4772d902d0fSKepontry     Regs |= getAliases(AArch64::X22);
4782d902d0fSKepontry     Regs |= getAliases(AArch64::X23);
4792d902d0fSKepontry     Regs |= getAliases(AArch64::X24);
4802d902d0fSKepontry     Regs |= getAliases(AArch64::X25);
4812d902d0fSKepontry     Regs |= getAliases(AArch64::X26);
4822d902d0fSKepontry     Regs |= getAliases(AArch64::X27);
4832d902d0fSKepontry     Regs |= getAliases(AArch64::X28);
4842d902d0fSKepontry     Regs |= getAliases(AArch64::LR);
4852d902d0fSKepontry     Regs |= getAliases(AArch64::FP);
4862d902d0fSKepontry   }
4872d902d0fSKepontry 
488a34c753fSRafael Auler   const MCExpr *getTargetExprFor(MCInst &Inst, const MCExpr *Expr,
489a34c753fSRafael Auler                                  MCContext &Ctx,
490a34c753fSRafael Auler                                  uint64_t RelType) const override {
491a34c753fSRafael Auler 
492a34c753fSRafael Auler     if (isADR(Inst) || RelType == ELF::R_AARCH64_ADR_PREL_LO21 ||
493a34c753fSRafael Auler         RelType == ELF::R_AARCH64_TLSDESC_ADR_PREL21) {
494a34c753fSRafael Auler       return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS, Ctx);
495a34c753fSRafael Auler     } else if (isADRP(Inst) || RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21 ||
496a34c753fSRafael Auler                RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21_NC ||
497a34c753fSRafael Auler                RelType == ELF::R_AARCH64_TLSDESC_ADR_PAGE21 ||
498a34c753fSRafael Auler                RelType == ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
499a34c753fSRafael Auler                RelType == ELF::R_AARCH64_ADR_GOT_PAGE) {
500a34c753fSRafael Auler       // Never emit a GOT reloc, we handled this in
501a34c753fSRafael Auler       // RewriteInstance::readRelocations().
502a34c753fSRafael Auler       return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_PAGE, Ctx);
503a34c753fSRafael Auler     } else {
504a34c753fSRafael Auler       switch (RelType) {
505a34c753fSRafael Auler       case ELF::R_AARCH64_ADD_ABS_LO12_NC:
506a34c753fSRafael Auler       case ELF::R_AARCH64_LD64_GOT_LO12_NC:
507a34c753fSRafael Auler       case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
508a34c753fSRafael Auler       case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
509a34c753fSRafael Auler       case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
510a34c753fSRafael Auler       case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
511a34c753fSRafael Auler       case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
512a34c753fSRafael Auler       case ELF::R_AARCH64_TLSDESC_ADD_LO12:
513a34c753fSRafael Auler       case ELF::R_AARCH64_TLSDESC_LD64_LO12:
514a34c753fSRafael Auler       case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
515a34c753fSRafael Auler       case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
516a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_LO12, Ctx);
517a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G3:
518a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G3, Ctx);
519a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G2:
520a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G2_NC:
521a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G2_NC, Ctx);
522a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G1:
523a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G1_NC:
524a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G1_NC, Ctx);
525a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G0:
526a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G0_NC:
527a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G0_NC, Ctx);
528a34c753fSRafael Auler       default:
529a34c753fSRafael Auler         break;
530a34c753fSRafael Auler       }
531a34c753fSRafael Auler     }
532a34c753fSRafael Auler     return Expr;
533a34c753fSRafael Auler   }
534a34c753fSRafael Auler 
535a34c753fSRafael Auler   bool getSymbolRefOperandNum(const MCInst &Inst, unsigned &OpNum) const {
536a34c753fSRafael Auler     if (OpNum >= MCPlus::getNumPrimeOperands(Inst))
537a34c753fSRafael Auler       return false;
538a34c753fSRafael Auler 
539a34c753fSRafael Auler     // Auto-select correct operand number
540a34c753fSRafael Auler     if (OpNum == 0) {
54117ed8f29SVladislav Khmelevsky       if (isConditionalBranch(Inst) || isADR(Inst) || isADRP(Inst) ||
54217ed8f29SVladislav Khmelevsky           isMOVW(Inst))
543a34c753fSRafael Auler         OpNum = 1;
54417ed8f29SVladislav Khmelevsky       if (isTB(Inst) || isAddXri(Inst))
545a34c753fSRafael Auler         OpNum = 2;
546a34c753fSRafael Auler     }
547a34c753fSRafael Auler 
548a34c753fSRafael Auler     return true;
549a34c753fSRafael Auler   }
550a34c753fSRafael Auler 
551a34c753fSRafael Auler   const MCSymbol *getTargetSymbol(const MCExpr *Expr) const override {
552a34c753fSRafael Auler     auto *AArchExpr = dyn_cast<AArch64MCExpr>(Expr);
553a34c753fSRafael Auler     if (AArchExpr && AArchExpr->getSubExpr())
554a34c753fSRafael Auler       return getTargetSymbol(AArchExpr->getSubExpr());
555a34c753fSRafael Auler 
556a34c753fSRafael Auler     auto *BinExpr = dyn_cast<MCBinaryExpr>(Expr);
557a34c753fSRafael Auler     if (BinExpr)
558a34c753fSRafael Auler       return getTargetSymbol(BinExpr->getLHS());
559a34c753fSRafael Auler 
560a34c753fSRafael Auler     auto *SymExpr = dyn_cast<MCSymbolRefExpr>(Expr);
561a34c753fSRafael Auler     if (SymExpr && SymExpr->getKind() == MCSymbolRefExpr::VK_None)
562a34c753fSRafael Auler       return &SymExpr->getSymbol();
563a34c753fSRafael Auler 
564a34c753fSRafael Auler     return nullptr;
565a34c753fSRafael Auler   }
566a34c753fSRafael Auler 
567a34c753fSRafael Auler   const MCSymbol *getTargetSymbol(const MCInst &Inst,
568a34c753fSRafael Auler                                   unsigned OpNum = 0) const override {
569a34c753fSRafael Auler     if (!getSymbolRefOperandNum(Inst, OpNum))
570a34c753fSRafael Auler       return nullptr;
571a34c753fSRafael Auler 
572a34c753fSRafael Auler     const MCOperand &Op = Inst.getOperand(OpNum);
573a34c753fSRafael Auler     if (!Op.isExpr())
574a34c753fSRafael Auler       return nullptr;
575a34c753fSRafael Auler 
576a34c753fSRafael Auler     return getTargetSymbol(Op.getExpr());
577a34c753fSRafael Auler   }
578a34c753fSRafael Auler 
579a34c753fSRafael Auler   int64_t getTargetAddend(const MCExpr *Expr) const override {
580a34c753fSRafael Auler     auto *AArchExpr = dyn_cast<AArch64MCExpr>(Expr);
581a34c753fSRafael Auler     if (AArchExpr && AArchExpr->getSubExpr())
582a34c753fSRafael Auler       return getTargetAddend(AArchExpr->getSubExpr());
583a34c753fSRafael Auler 
584a34c753fSRafael Auler     auto *BinExpr = dyn_cast<MCBinaryExpr>(Expr);
585a34c753fSRafael Auler     if (BinExpr && BinExpr->getOpcode() == MCBinaryExpr::Add)
586a34c753fSRafael Auler       return getTargetAddend(BinExpr->getRHS());
587a34c753fSRafael Auler 
588a34c753fSRafael Auler     auto *ConstExpr = dyn_cast<MCConstantExpr>(Expr);
589a34c753fSRafael Auler     if (ConstExpr)
590a34c753fSRafael Auler       return ConstExpr->getValue();
591a34c753fSRafael Auler 
592a34c753fSRafael Auler     return 0;
593a34c753fSRafael Auler   }
594a34c753fSRafael Auler 
595a34c753fSRafael Auler   int64_t getTargetAddend(const MCInst &Inst,
596a34c753fSRafael Auler                           unsigned OpNum = 0) const override {
597a34c753fSRafael Auler     if (!getSymbolRefOperandNum(Inst, OpNum))
598a34c753fSRafael Auler       return 0;
599a34c753fSRafael Auler 
600a34c753fSRafael Auler     const MCOperand &Op = Inst.getOperand(OpNum);
601a34c753fSRafael Auler     if (!Op.isExpr())
602a34c753fSRafael Auler       return 0;
603a34c753fSRafael Auler 
604a34c753fSRafael Auler     return getTargetAddend(Op.getExpr());
605a34c753fSRafael Auler   }
606a34c753fSRafael Auler 
607a34c753fSRafael Auler   bool replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,
608a34c753fSRafael Auler                            MCContext *Ctx) const override {
609a34c753fSRafael Auler     assert((isCall(Inst) || isBranch(Inst)) && !isIndirectBranch(Inst) &&
610a34c753fSRafael Auler            "Invalid instruction");
611a34c753fSRafael Auler     assert(MCPlus::getNumPrimeOperands(Inst) >= 1 &&
612a34c753fSRafael Auler            "Invalid number of operands");
613a34c753fSRafael Auler     MCInst::iterator OI = Inst.begin();
614a34c753fSRafael Auler 
615a34c753fSRafael Auler     if (isConditionalBranch(Inst)) {
616a34c753fSRafael Auler       assert(MCPlus::getNumPrimeOperands(Inst) >= 2 &&
617a34c753fSRafael Auler              "Invalid number of operands");
618a34c753fSRafael Auler       ++OI;
619a34c753fSRafael Auler     }
620a34c753fSRafael Auler 
621a34c753fSRafael Auler     if (isTB(Inst)) {
622a34c753fSRafael Auler       assert(MCPlus::getNumPrimeOperands(Inst) >= 3 &&
623a34c753fSRafael Auler              "Invalid number of operands");
624a34c753fSRafael Auler       OI = Inst.begin() + 2;
625a34c753fSRafael Auler     }
626a34c753fSRafael Auler 
627a34c753fSRafael Auler     *OI = MCOperand::createExpr(
628a34c753fSRafael Auler         MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx));
629a34c753fSRafael Auler     return true;
630a34c753fSRafael Auler   }
631a34c753fSRafael Auler 
632a34c753fSRafael Auler   /// Matches indirect branch patterns in AArch64 related to a jump table (JT),
633a34c753fSRafael Auler   /// helping us to build the complete CFG. A typical indirect branch to
634a34c753fSRafael Auler   /// a jump table entry in AArch64 looks like the following:
635a34c753fSRafael Auler   ///
636a34c753fSRafael Auler   ///   adrp    x1, #-7585792           # Get JT Page location
637a34c753fSRafael Auler   ///   add     x1, x1, #692            # Complement with JT Page offset
638a34c753fSRafael Auler   ///   ldrh    w0, [x1, w0, uxtw #1]   # Loads JT entry
639a34c753fSRafael Auler   ///   adr     x1, #12                 # Get PC + 12 (end of this BB) used next
640a34c753fSRafael Auler   ///   add     x0, x1, w0, sxth #2     # Finish building branch target
641a34c753fSRafael Auler   ///                                   # (entries in JT are relative to the end
642a34c753fSRafael Auler   ///                                   #  of this BB)
643a34c753fSRafael Auler   ///   br      x0                      # Indirect jump instruction
644a34c753fSRafael Auler   ///
645a34c753fSRafael Auler   bool analyzeIndirectBranchFragment(
646a34c753fSRafael Auler       const MCInst &Inst,
647a34c753fSRafael Auler       DenseMap<const MCInst *, SmallVector<MCInst *, 4>> &UDChain,
648a34c753fSRafael Auler       const MCExpr *&JumpTable, int64_t &Offset, int64_t &ScaleValue,
649a34c753fSRafael Auler       MCInst *&PCRelBase) const {
650a34c753fSRafael Auler     // Expect AArch64 BR
651a34c753fSRafael Auler     assert(Inst.getOpcode() == AArch64::BR && "Unexpected opcode");
652a34c753fSRafael Auler 
653a34c753fSRafael Auler     // Match the indirect branch pattern for aarch64
654a34c753fSRafael Auler     SmallVector<MCInst *, 4> &UsesRoot = UDChain[&Inst];
65589ceb779SAmir Ayupov     if (UsesRoot.size() == 0 || UsesRoot[0] == nullptr)
656a34c753fSRafael Auler       return false;
65789ceb779SAmir Ayupov 
658a34c753fSRafael Auler     const MCInst *DefAdd = UsesRoot[0];
659a34c753fSRafael Auler 
660a34c753fSRafael Auler     // Now we match an ADD
661a34c753fSRafael Auler     if (!isADD(*DefAdd)) {
662a34c753fSRafael Auler       // If the address is not broken up in two parts, this is not branching
663a34c753fSRafael Auler       // according to a jump table entry. Fail.
664a34c753fSRafael Auler       return false;
665a34c753fSRafael Auler     }
666a34c753fSRafael Auler     if (DefAdd->getOpcode() == AArch64::ADDXri) {
667a34c753fSRafael Auler       // This can happen when there is no offset, but a direct jump that was
668a34c753fSRafael Auler       // transformed into an indirect one  (indirect tail call) :
669a34c753fSRafael Auler       //   ADRP   x2, Perl_re_compiler
670a34c753fSRafael Auler       //   ADD    x2, x2, :lo12:Perl_re_compiler
671a34c753fSRafael Auler       //   BR     x2
672a34c753fSRafael Auler       return false;
673a34c753fSRafael Auler     }
674a34c753fSRafael Auler     if (DefAdd->getOpcode() == AArch64::ADDXrs) {
675a34c753fSRafael Auler       // Covers the less common pattern where JT entries are relative to
676a34c753fSRafael Auler       // the JT itself (like x86). Seems less efficient since we can't
677a34c753fSRafael Auler       // assume the JT is aligned at 4B boundary and thus drop 2 bits from
678a34c753fSRafael Auler       // JT values.
679a34c753fSRafael Auler       // cde264:
680a34c753fSRafael Auler       //    adrp    x12, #21544960  ; 216a000
681a34c753fSRafael Auler       //    add     x12, x12, #1696 ; 216a6a0  (JT object in .rodata)
682a34c753fSRafael Auler       //    ldrsw   x8, [x12, x8, lsl #2]   --> loads e.g. 0xfeb73bd8
683a34c753fSRafael Auler       //  * add     x8, x8, x12   --> = cde278, next block
684a34c753fSRafael Auler       //    br      x8
685a34c753fSRafael Auler       // cde278:
686a34c753fSRafael Auler       //
687a34c753fSRafael Auler       // Parsed as ADDXrs reg:x8 reg:x8 reg:x12 imm:0
688a34c753fSRafael Auler       return false;
689a34c753fSRafael Auler     }
690a34c753fSRafael Auler     assert(DefAdd->getOpcode() == AArch64::ADDXrx &&
691a34c753fSRafael Auler            "Failed to match indirect branch!");
692a34c753fSRafael Auler 
693a34c753fSRafael Auler     // Validate ADD operands
694a34c753fSRafael Auler     int64_t OperandExtension = DefAdd->getOperand(3).getImm();
695a34c753fSRafael Auler     unsigned ShiftVal = AArch64_AM::getArithShiftValue(OperandExtension);
696a34c753fSRafael Auler     AArch64_AM::ShiftExtendType ExtendType =
697a34c753fSRafael Auler         AArch64_AM::getArithExtendType(OperandExtension);
69889ceb779SAmir Ayupov     if (ShiftVal != 2)
699a34c753fSRafael Auler       llvm_unreachable("Failed to match indirect branch! (fragment 2)");
70089ceb779SAmir Ayupov 
70189ceb779SAmir Ayupov     if (ExtendType == AArch64_AM::SXTB)
702a34c753fSRafael Auler       ScaleValue = 1LL;
70389ceb779SAmir Ayupov     else if (ExtendType == AArch64_AM::SXTH)
704a34c753fSRafael Auler       ScaleValue = 2LL;
70589ceb779SAmir Ayupov     else if (ExtendType == AArch64_AM::SXTW)
706a34c753fSRafael Auler       ScaleValue = 4LL;
70789ceb779SAmir Ayupov     else
708a34c753fSRafael Auler       llvm_unreachable("Failed to match indirect branch! (fragment 3)");
709a34c753fSRafael Auler 
710a34c753fSRafael Auler     // Match an ADR to load base address to be used when addressing JT targets
711a34c753fSRafael Auler     SmallVector<MCInst *, 4> &UsesAdd = UDChain[DefAdd];
712a34c753fSRafael Auler     if (UsesAdd.size() <= 1 || UsesAdd[1] == nullptr || UsesAdd[2] == nullptr) {
713a34c753fSRafael Auler       // This happens when we don't have enough context about this jump table
714a34c753fSRafael Auler       // because the jumping code sequence was split in multiple basic blocks.
715a34c753fSRafael Auler       // This was observed in the wild in HHVM code (dispatchImpl).
716a34c753fSRafael Auler       return false;
717a34c753fSRafael Auler     }
718a34c753fSRafael Auler     MCInst *DefBaseAddr = UsesAdd[1];
719a34c753fSRafael Auler     assert(DefBaseAddr->getOpcode() == AArch64::ADR &&
720a34c753fSRafael Auler            "Failed to match indirect branch pattern! (fragment 3)");
721a34c753fSRafael Auler 
722a34c753fSRafael Auler     PCRelBase = DefBaseAddr;
723a34c753fSRafael Auler     // Match LOAD to load the jump table (relative) target
724a34c753fSRafael Auler     const MCInst *DefLoad = UsesAdd[2];
725eafe4ee2SJob Noorman     assert(mayLoad(*DefLoad) &&
726a34c753fSRafael Auler            "Failed to match indirect branch load pattern! (1)");
727a34c753fSRafael Auler     assert((ScaleValue != 1LL || isLDRB(*DefLoad)) &&
728a34c753fSRafael Auler            "Failed to match indirect branch load pattern! (2)");
729a34c753fSRafael Auler     assert((ScaleValue != 2LL || isLDRH(*DefLoad)) &&
730a34c753fSRafael Auler            "Failed to match indirect branch load pattern! (3)");
731a34c753fSRafael Auler 
732a34c753fSRafael Auler     // Match ADD that calculates the JumpTable Base Address (not the offset)
733a34c753fSRafael Auler     SmallVector<MCInst *, 4> &UsesLoad = UDChain[DefLoad];
734a34c753fSRafael Auler     const MCInst *DefJTBaseAdd = UsesLoad[1];
735a34c753fSRafael Auler     MCPhysReg From, To;
736a34c753fSRafael Auler     if (DefJTBaseAdd == nullptr || isLoadFromStack(*DefJTBaseAdd) ||
737a34c753fSRafael Auler         isRegToRegMove(*DefJTBaseAdd, From, To)) {
738a34c753fSRafael Auler       // Sometimes base address may have been defined in another basic block
739a34c753fSRafael Auler       // (hoisted). Return with no jump table info.
740a34c753fSRafael Auler       JumpTable = nullptr;
741a34c753fSRafael Auler       return true;
742a34c753fSRafael Auler     }
743a34c753fSRafael Auler 
744a34c753fSRafael Auler     assert(DefJTBaseAdd->getOpcode() == AArch64::ADDXri &&
745a34c753fSRafael Auler            "Failed to match jump table base address pattern! (1)");
746a34c753fSRafael Auler 
747a34c753fSRafael Auler     if (DefJTBaseAdd->getOperand(2).isImm())
748a34c753fSRafael Auler       Offset = DefJTBaseAdd->getOperand(2).getImm();
749a34c753fSRafael Auler     SmallVector<MCInst *, 4> &UsesJTBaseAdd = UDChain[DefJTBaseAdd];
750a34c753fSRafael Auler     const MCInst *DefJTBasePage = UsesJTBaseAdd[1];
751a34c753fSRafael Auler     if (DefJTBasePage == nullptr || isLoadFromStack(*DefJTBasePage)) {
752a34c753fSRafael Auler       JumpTable = nullptr;
753a34c753fSRafael Auler       return true;
754a34c753fSRafael Auler     }
755a34c753fSRafael Auler     assert(DefJTBasePage->getOpcode() == AArch64::ADRP &&
756a34c753fSRafael Auler            "Failed to match jump table base page pattern! (2)");
757a34c753fSRafael Auler     if (DefJTBasePage->getOperand(1).isExpr())
758a34c753fSRafael Auler       JumpTable = DefJTBasePage->getOperand(1).getExpr();
759a34c753fSRafael Auler     return true;
760a34c753fSRafael Auler   }
761a34c753fSRafael Auler 
762a34c753fSRafael Auler   DenseMap<const MCInst *, SmallVector<MCInst *, 4>>
76340c2e0faSMaksim Panchenko   computeLocalUDChain(const MCInst *CurInstr, InstructionIterator Begin,
764a34c753fSRafael Auler                       InstructionIterator End) const {
765a34c753fSRafael Auler     DenseMap<int, MCInst *> RegAliasTable;
766a34c753fSRafael Auler     DenseMap<const MCInst *, SmallVector<MCInst *, 4>> Uses;
767a34c753fSRafael Auler 
768a34c753fSRafael Auler     auto addInstrOperands = [&](const MCInst &Instr) {
769a34c753fSRafael Auler       // Update Uses table
7708cb7a873SAmir Ayupov       for (const MCOperand &Operand : MCPlus::primeOperands(Instr)) {
7718cb7a873SAmir Ayupov         if (!Operand.isReg())
772a34c753fSRafael Auler           continue;
7738cb7a873SAmir Ayupov         unsigned Reg = Operand.getReg();
774a34c753fSRafael Auler         MCInst *AliasInst = RegAliasTable[Reg];
775a34c753fSRafael Auler         Uses[&Instr].push_back(AliasInst);
776a34c753fSRafael Auler         LLVM_DEBUG({
777a34c753fSRafael Auler           dbgs() << "Adding reg operand " << Reg << " refs ";
778a34c753fSRafael Auler           if (AliasInst != nullptr)
779a34c753fSRafael Auler             AliasInst->dump();
780a34c753fSRafael Auler           else
781a34c753fSRafael Auler             dbgs() << "\n";
782a34c753fSRafael Auler         });
783a34c753fSRafael Auler       }
784a34c753fSRafael Auler     };
785a34c753fSRafael Auler 
786a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "computeLocalUDChain\n");
787a34c753fSRafael Auler     bool TerminatorSeen = false;
788a34c753fSRafael Auler     for (auto II = Begin; II != End; ++II) {
789a34c753fSRafael Auler       MCInst &Instr = *II;
790a34c753fSRafael Auler       // Ignore nops and CFIs
791a34c753fSRafael Auler       if (isPseudo(Instr) || isNoop(Instr))
792a34c753fSRafael Auler         continue;
793a34c753fSRafael Auler       if (TerminatorSeen) {
794a34c753fSRafael Auler         RegAliasTable.clear();
795a34c753fSRafael Auler         Uses.clear();
796a34c753fSRafael Auler       }
797a34c753fSRafael Auler 
798a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "Now updating for:\n ");
799a34c753fSRafael Auler       LLVM_DEBUG(Instr.dump());
800a34c753fSRafael Auler       addInstrOperands(Instr);
801a34c753fSRafael Auler 
802a34c753fSRafael Auler       BitVector Regs = BitVector(RegInfo->getNumRegs(), false);
803a34c753fSRafael Auler       getWrittenRegs(Instr, Regs);
804a34c753fSRafael Auler 
805a34c753fSRafael Auler       // Update register definitions after this point
806d63c5a38SAmir Ayupov       for (int Idx : Regs.set_bits()) {
807a34c753fSRafael Auler         RegAliasTable[Idx] = &Instr;
808a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "Setting reg " << Idx
809a34c753fSRafael Auler                           << " def to current instr.\n");
810a34c753fSRafael Auler       }
811a34c753fSRafael Auler 
812a34c753fSRafael Auler       TerminatorSeen = isTerminator(Instr);
813a34c753fSRafael Auler     }
814a34c753fSRafael Auler 
815a34c753fSRafael Auler     // Process the last instruction, which is not currently added into the
816a34c753fSRafael Auler     // instruction stream
81789ceb779SAmir Ayupov     if (CurInstr)
818a34c753fSRafael Auler       addInstrOperands(*CurInstr);
81989ceb779SAmir Ayupov 
820a34c753fSRafael Auler     return Uses;
821a34c753fSRafael Auler   }
822a34c753fSRafael Auler 
823a34c753fSRafael Auler   IndirectBranchType analyzeIndirectBranch(
8248aab58baSMaksim Panchenko       MCInst &Instruction, InstructionIterator Begin, InstructionIterator End,
8258aab58baSMaksim Panchenko       const unsigned PtrSize, MCInst *&MemLocInstrOut, unsigned &BaseRegNumOut,
8268aab58baSMaksim Panchenko       unsigned &IndexRegNumOut, int64_t &DispValueOut,
8278aab58baSMaksim Panchenko       const MCExpr *&DispExprOut, MCInst *&PCRelBaseOut) const override {
828a34c753fSRafael Auler     MemLocInstrOut = nullptr;
829a34c753fSRafael Auler     BaseRegNumOut = AArch64::NoRegister;
830a34c753fSRafael Auler     IndexRegNumOut = AArch64::NoRegister;
831a34c753fSRafael Auler     DispValueOut = 0;
832a34c753fSRafael Auler     DispExprOut = nullptr;
833a34c753fSRafael Auler 
834a34c753fSRafael Auler     // An instruction referencing memory used by jump instruction (directly or
835a34c753fSRafael Auler     // via register). This location could be an array of function pointers
836a34c753fSRafael Auler     // in case of indirect tail call, or a jump table.
837a34c753fSRafael Auler     MCInst *MemLocInstr = nullptr;
838a34c753fSRafael Auler 
839a34c753fSRafael Auler     // Analyze the memory location.
840a34c753fSRafael Auler     int64_t ScaleValue, DispValue;
841a34c753fSRafael Auler     const MCExpr *DispExpr;
842a34c753fSRafael Auler 
843a34c753fSRafael Auler     DenseMap<const MCInst *, SmallVector<llvm::MCInst *, 4>> UDChain =
844a34c753fSRafael Auler         computeLocalUDChain(&Instruction, Begin, End);
845a34c753fSRafael Auler     MCInst *PCRelBase;
846a34c753fSRafael Auler     if (!analyzeIndirectBranchFragment(Instruction, UDChain, DispExpr,
84789ceb779SAmir Ayupov                                        DispValue, ScaleValue, PCRelBase))
848a34c753fSRafael Auler       return IndirectBranchType::UNKNOWN;
849a34c753fSRafael Auler 
850a34c753fSRafael Auler     MemLocInstrOut = MemLocInstr;
851a34c753fSRafael Auler     DispValueOut = DispValue;
852a34c753fSRafael Auler     DispExprOut = DispExpr;
853a34c753fSRafael Auler     PCRelBaseOut = PCRelBase;
854a34c753fSRafael Auler     return IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE;
855a34c753fSRafael Auler   }
856a34c753fSRafael Auler 
85700b6efc8SVladislav Khmelevsky   ///  Matches PLT entry pattern and returns the associated GOT entry address.
85800b6efc8SVladislav Khmelevsky   ///  Typical PLT entry looks like the following:
85900b6efc8SVladislav Khmelevsky   ///
86000b6efc8SVladislav Khmelevsky   ///    adrp    x16, 230000
86100b6efc8SVladislav Khmelevsky   ///    ldr     x17, [x16, #3040]
86200b6efc8SVladislav Khmelevsky   ///    add     x16, x16, #0xbe0
86300b6efc8SVladislav Khmelevsky   ///    br      x17
86400b6efc8SVladislav Khmelevsky   ///
86500b6efc8SVladislav Khmelevsky   uint64_t analyzePLTEntry(MCInst &Instruction, InstructionIterator Begin,
86600b6efc8SVladislav Khmelevsky                            InstructionIterator End,
86700b6efc8SVladislav Khmelevsky                            uint64_t BeginPC) const override {
86800b6efc8SVladislav Khmelevsky     // Check branch instruction
86900b6efc8SVladislav Khmelevsky     MCInst *Branch = &Instruction;
87000b6efc8SVladislav Khmelevsky     assert(Branch->getOpcode() == AArch64::BR && "Unexpected opcode");
87100b6efc8SVladislav Khmelevsky 
87200b6efc8SVladislav Khmelevsky     DenseMap<const MCInst *, SmallVector<llvm::MCInst *, 4>> UDChain =
87300b6efc8SVladislav Khmelevsky         computeLocalUDChain(Branch, Begin, End);
87400b6efc8SVladislav Khmelevsky 
87500b6efc8SVladislav Khmelevsky     // Match ldr instruction
87600b6efc8SVladislav Khmelevsky     SmallVector<MCInst *, 4> &BranchUses = UDChain[Branch];
87700b6efc8SVladislav Khmelevsky     if (BranchUses.size() < 1 || BranchUses[0] == nullptr)
87800b6efc8SVladislav Khmelevsky       return 0;
87900b6efc8SVladislav Khmelevsky 
88000b6efc8SVladislav Khmelevsky     // Check ldr instruction
88100b6efc8SVladislav Khmelevsky     const MCInst *Ldr = BranchUses[0];
88200b6efc8SVladislav Khmelevsky     if (Ldr->getOpcode() != AArch64::LDRXui)
88300b6efc8SVladislav Khmelevsky       return 0;
88400b6efc8SVladislav Khmelevsky 
88500b6efc8SVladislav Khmelevsky     // Get ldr value
88600b6efc8SVladislav Khmelevsky     const unsigned ScaleLdr = 8; // LDRX operates on 8 bytes segments
88700b6efc8SVladislav Khmelevsky     assert(Ldr->getOperand(2).isImm() && "Unexpected ldr operand");
88800b6efc8SVladislav Khmelevsky     const uint64_t Offset = Ldr->getOperand(2).getImm() * ScaleLdr;
88900b6efc8SVladislav Khmelevsky 
89000b6efc8SVladislav Khmelevsky     // Match adrp instruction
89100b6efc8SVladislav Khmelevsky     SmallVector<MCInst *, 4> &LdrUses = UDChain[Ldr];
89200b6efc8SVladislav Khmelevsky     if (LdrUses.size() < 2 || LdrUses[1] == nullptr)
89300b6efc8SVladislav Khmelevsky       return 0;
89400b6efc8SVladislav Khmelevsky 
89500b6efc8SVladislav Khmelevsky     // Check adrp instruction
89600b6efc8SVladislav Khmelevsky     MCInst *Adrp = LdrUses[1];
89700b6efc8SVladislav Khmelevsky     if (Adrp->getOpcode() != AArch64::ADRP)
89800b6efc8SVladislav Khmelevsky       return 0;
89900b6efc8SVladislav Khmelevsky 
90000b6efc8SVladislav Khmelevsky     // Get adrp instruction PC
90100b6efc8SVladislav Khmelevsky     const unsigned InstSize = 4;
90200b6efc8SVladislav Khmelevsky     uint64_t AdrpPC = BeginPC;
90300b6efc8SVladislav Khmelevsky     for (InstructionIterator It = Begin; It != End; ++It) {
90400b6efc8SVladislav Khmelevsky       if (&(*It) == Adrp)
90500b6efc8SVladislav Khmelevsky         break;
90600b6efc8SVladislav Khmelevsky       AdrpPC += InstSize;
90700b6efc8SVladislav Khmelevsky     }
90800b6efc8SVladislav Khmelevsky 
90900b6efc8SVladislav Khmelevsky     // Get adrp value
91000b6efc8SVladislav Khmelevsky     uint64_t Base;
91100b6efc8SVladislav Khmelevsky     assert(Adrp->getOperand(1).isImm() && "Unexpected adrp operand");
91200b6efc8SVladislav Khmelevsky     bool Ret = evaluateMemOperandTarget(*Adrp, Base, AdrpPC, InstSize);
91300b6efc8SVladislav Khmelevsky     assert(Ret && "Failed to evaluate adrp");
914139744acSAmir Ayupov     (void)Ret;
91500b6efc8SVladislav Khmelevsky 
91600b6efc8SVladislav Khmelevsky     return Base + Offset;
91700b6efc8SVladislav Khmelevsky   }
91800b6efc8SVladislav Khmelevsky 
919a34c753fSRafael Auler   unsigned getInvertedBranchOpcode(unsigned Opcode) const {
920a34c753fSRafael Auler     switch (Opcode) {
921a34c753fSRafael Auler     default:
922a34c753fSRafael Auler       llvm_unreachable("Failed to invert branch opcode");
923a34c753fSRafael Auler       return Opcode;
924a34c753fSRafael Auler     case AArch64::TBZW:     return AArch64::TBNZW;
925a34c753fSRafael Auler     case AArch64::TBZX:     return AArch64::TBNZX;
926a34c753fSRafael Auler     case AArch64::TBNZW:    return AArch64::TBZW;
927a34c753fSRafael Auler     case AArch64::TBNZX:    return AArch64::TBZX;
928a34c753fSRafael Auler     case AArch64::CBZW:     return AArch64::CBNZW;
929a34c753fSRafael Auler     case AArch64::CBZX:     return AArch64::CBNZX;
930a34c753fSRafael Auler     case AArch64::CBNZW:    return AArch64::CBZW;
931a34c753fSRafael Auler     case AArch64::CBNZX:    return AArch64::CBZX;
932a34c753fSRafael Auler     }
933a34c753fSRafael Auler   }
934a34c753fSRafael Auler 
935a34c753fSRafael Auler   unsigned getCondCode(const MCInst &Inst) const override {
936a34c753fSRafael Auler     // AArch64 does not use conditional codes, so we just return the opcode
937a34c753fSRafael Auler     // of the conditional branch here.
938a34c753fSRafael Auler     return Inst.getOpcode();
939a34c753fSRafael Auler   }
940a34c753fSRafael Auler 
941a34c753fSRafael Auler   unsigned getCanonicalBranchCondCode(unsigned Opcode) const override {
942a34c753fSRafael Auler     switch (Opcode) {
943a34c753fSRafael Auler     default:
944a34c753fSRafael Auler       return Opcode;
945a34c753fSRafael Auler     case AArch64::TBNZW:    return AArch64::TBZW;
946a34c753fSRafael Auler     case AArch64::TBNZX:    return AArch64::TBZX;
947a34c753fSRafael Auler     case AArch64::CBNZW:    return AArch64::CBZW;
948a34c753fSRafael Auler     case AArch64::CBNZX:    return AArch64::CBZX;
949a34c753fSRafael Auler     }
950a34c753fSRafael Auler   }
951a34c753fSRafael Auler 
952a34c753fSRafael Auler   bool reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,
953a34c753fSRafael Auler                               MCContext *Ctx) const override {
954a34c753fSRafael Auler     if (isTB(Inst) || isCB(Inst)) {
955a34c753fSRafael Auler       Inst.setOpcode(getInvertedBranchOpcode(Inst.getOpcode()));
956a34c753fSRafael Auler       assert(Inst.getOpcode() != 0 && "Invalid branch instruction");
957a34c753fSRafael Auler     } else if (Inst.getOpcode() == AArch64::Bcc) {
958a34c753fSRafael Auler       Inst.getOperand(0).setImm(AArch64CC::getInvertedCondCode(
959a34c753fSRafael Auler           static_cast<AArch64CC::CondCode>(Inst.getOperand(0).getImm())));
960a34c753fSRafael Auler       assert(Inst.getOperand(0).getImm() != AArch64CC::AL &&
961a34c753fSRafael Auler              Inst.getOperand(0).getImm() != AArch64CC::NV &&
962a34c753fSRafael Auler              "Can't reverse ALWAYS cond code");
963a34c753fSRafael Auler     } else {
964a34c753fSRafael Auler       LLVM_DEBUG(Inst.dump());
965a34c753fSRafael Auler       llvm_unreachable("Unrecognized branch instruction");
966a34c753fSRafael Auler     }
967a34c753fSRafael Auler     return replaceBranchTarget(Inst, TBB, Ctx);
968a34c753fSRafael Auler   }
969a34c753fSRafael Auler 
970a34c753fSRafael Auler   int getPCRelEncodingSize(const MCInst &Inst) const override {
971a34c753fSRafael Auler     switch (Inst.getOpcode()) {
972a34c753fSRafael Auler     default:
973a34c753fSRafael Auler       llvm_unreachable("Failed to get pcrel encoding size");
974a34c753fSRafael Auler       return 0;
975a34c753fSRafael Auler     case AArch64::TBZW:     return 16;
976a34c753fSRafael Auler     case AArch64::TBZX:     return 16;
977a34c753fSRafael Auler     case AArch64::TBNZW:    return 16;
978a34c753fSRafael Auler     case AArch64::TBNZX:    return 16;
979a34c753fSRafael Auler     case AArch64::CBZW:     return 21;
980a34c753fSRafael Auler     case AArch64::CBZX:     return 21;
981a34c753fSRafael Auler     case AArch64::CBNZW:    return 21;
982a34c753fSRafael Auler     case AArch64::CBNZX:    return 21;
983a34c753fSRafael Auler     case AArch64::B:        return 28;
984a34c753fSRafael Auler     case AArch64::BL:       return 28;
985a34c753fSRafael Auler     case AArch64::Bcc:      return 21;
986a34c753fSRafael Auler     }
987a34c753fSRafael Auler   }
988a34c753fSRafael Auler 
98940c2e0faSMaksim Panchenko   int getShortJmpEncodingSize() const override { return 33; }
990a34c753fSRafael Auler 
99140c2e0faSMaksim Panchenko   int getUncondBranchEncodingSize() const override { return 28; }
992a34c753fSRafael Auler 
9936e4c2305SElvina Yakubova   InstructionListType createCmpJE(MCPhysReg RegNo, int64_t Imm,
9946e4c2305SElvina Yakubova                                   const MCSymbol *Target,
9956e4c2305SElvina Yakubova                                   MCContext *Ctx) const override {
9966e4c2305SElvina Yakubova     InstructionListType Code;
9976e4c2305SElvina Yakubova     Code.emplace_back(MCInstBuilder(AArch64::SUBSXri)
9986e4c2305SElvina Yakubova                           .addReg(RegNo)
9996e4c2305SElvina Yakubova                           .addReg(RegNo)
10006e4c2305SElvina Yakubova                           .addImm(Imm)
10016e4c2305SElvina Yakubova                           .addImm(0));
10026e4c2305SElvina Yakubova     Code.emplace_back(MCInstBuilder(AArch64::Bcc)
10036e4c2305SElvina Yakubova                           .addImm(Imm)
10046e4c2305SElvina Yakubova                           .addExpr(MCSymbolRefExpr::create(
10056e4c2305SElvina Yakubova                               Target, MCSymbolRefExpr::VK_None, *Ctx)));
10066e4c2305SElvina Yakubova     return Code;
10076e4c2305SElvina Yakubova   }
10086e4c2305SElvina Yakubova 
1009a34c753fSRafael Auler   bool createTailCall(MCInst &Inst, const MCSymbol *Target,
1010a34c753fSRafael Auler                       MCContext *Ctx) override {
10116e4c2305SElvina Yakubova     return createDirectCall(Inst, Target, Ctx, /*IsTailCall*/ true);
1012a34c753fSRafael Auler   }
1013a34c753fSRafael Auler 
101469706eafSMaksim Panchenko   void createLongTailCall(InstructionListType &Seq, const MCSymbol *Target,
1015a34c753fSRafael Auler                           MCContext *Ctx) override {
1016a34c753fSRafael Auler     createShortJmp(Seq, Target, Ctx, /*IsTailCall*/ true);
1017a34c753fSRafael Auler   }
1018a34c753fSRafael Auler 
101919fb5a21SVladislav Khmelevsky   bool createTrap(MCInst &Inst) const override {
102019fb5a21SVladislav Khmelevsky     Inst.clear();
102119fb5a21SVladislav Khmelevsky     Inst.setOpcode(AArch64::BRK);
102219fb5a21SVladislav Khmelevsky     Inst.addOperand(MCOperand::createImm(1));
102319fb5a21SVladislav Khmelevsky     return true;
102419fb5a21SVladislav Khmelevsky   }
102519fb5a21SVladislav Khmelevsky 
1026a34c753fSRafael Auler   bool convertJmpToTailCall(MCInst &Inst) override {
1027a34c753fSRafael Auler     setTailCall(Inst);
1028a34c753fSRafael Auler     return true;
1029a34c753fSRafael Auler   }
1030a34c753fSRafael Auler 
1031a34c753fSRafael Auler   bool convertTailCallToJmp(MCInst &Inst) override {
1032a34c753fSRafael Auler     removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
1033a9cd49d5SAmir Ayupov     clearOffset(Inst);
1034a34c753fSRafael Auler     if (getConditionalTailCall(Inst))
1035a34c753fSRafael Auler       unsetConditionalTailCall(Inst);
1036a34c753fSRafael Auler     return true;
1037a34c753fSRafael Auler   }
1038a34c753fSRafael Auler 
1039a34c753fSRafael Auler   bool lowerTailCall(MCInst &Inst) override {
1040a34c753fSRafael Auler     removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
1041a34c753fSRafael Auler     if (getConditionalTailCall(Inst))
1042a34c753fSRafael Auler       unsetConditionalTailCall(Inst);
1043a34c753fSRafael Auler     return true;
1044a34c753fSRafael Auler   }
1045a34c753fSRafael Auler 
1046a34c753fSRafael Auler   bool isNoop(const MCInst &Inst) const override {
1047a34c753fSRafael Auler     return Inst.getOpcode() == AArch64::HINT &&
1048a34c753fSRafael Auler            Inst.getOperand(0).getImm() == 0;
1049a34c753fSRafael Auler   }
1050a34c753fSRafael Auler 
1051a34c753fSRafael Auler   bool createNoop(MCInst &Inst) const override {
1052a34c753fSRafael Auler     Inst.setOpcode(AArch64::HINT);
1053a34c753fSRafael Auler     Inst.clear();
1054a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0));
1055a34c753fSRafael Auler     return true;
1056a34c753fSRafael Auler   }
1057a34c753fSRafael Auler 
1058eafe4ee2SJob Noorman   bool mayStore(const MCInst &Inst) const override { return false; }
1059a34c753fSRafael Auler 
10606e4c2305SElvina Yakubova   bool createDirectCall(MCInst &Inst, const MCSymbol *Target, MCContext *Ctx,
10616e4c2305SElvina Yakubova                         bool IsTailCall) override {
10626e4c2305SElvina Yakubova     Inst.setOpcode(IsTailCall ? AArch64::B : AArch64::BL);
10636e4c2305SElvina Yakubova     Inst.clear();
10646e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createExpr(getTargetExprFor(
10656e4c2305SElvina Yakubova         Inst, MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
10666e4c2305SElvina Yakubova         *Ctx, 0)));
10676e4c2305SElvina Yakubova     if (IsTailCall)
10686e4c2305SElvina Yakubova       convertJmpToTailCall(Inst);
10696e4c2305SElvina Yakubova     return true;
10706e4c2305SElvina Yakubova   }
10716e4c2305SElvina Yakubova 
107240c2e0faSMaksim Panchenko   bool analyzeBranch(InstructionIterator Begin, InstructionIterator End,
107340c2e0faSMaksim Panchenko                      const MCSymbol *&TBB, const MCSymbol *&FBB,
1074a34c753fSRafael Auler                      MCInst *&CondBranch,
1075a34c753fSRafael Auler                      MCInst *&UncondBranch) const override {
1076a34c753fSRafael Auler     auto I = End;
1077a34c753fSRafael Auler 
1078a34c753fSRafael Auler     while (I != Begin) {
1079a34c753fSRafael Auler       --I;
1080a34c753fSRafael Auler 
1081a34c753fSRafael Auler       // Ignore nops and CFIs
1082a34c753fSRafael Auler       if (isPseudo(*I) || isNoop(*I))
1083a34c753fSRafael Auler         continue;
1084a34c753fSRafael Auler 
1085a34c753fSRafael Auler       // Stop when we find the first non-terminator
1086a34c753fSRafael Auler       if (!isTerminator(*I) || isTailCall(*I) || !isBranch(*I))
1087a34c753fSRafael Auler         break;
1088a34c753fSRafael Auler 
1089a34c753fSRafael Auler       // Handle unconditional branches.
1090a34c753fSRafael Auler       if (isUnconditionalBranch(*I)) {
1091a34c753fSRafael Auler         // If any code was seen after this unconditional branch, we've seen
1092a34c753fSRafael Auler         // unreachable code. Ignore them.
1093a34c753fSRafael Auler         CondBranch = nullptr;
1094a34c753fSRafael Auler         UncondBranch = &*I;
1095a34c753fSRafael Auler         const MCSymbol *Sym = getTargetSymbol(*I);
1096a34c753fSRafael Auler         assert(Sym != nullptr &&
1097a34c753fSRafael Auler                "Couldn't extract BB symbol from jump operand");
1098a34c753fSRafael Auler         TBB = Sym;
1099a34c753fSRafael Auler         continue;
1100a34c753fSRafael Auler       }
1101a34c753fSRafael Auler 
1102a34c753fSRafael Auler       // Handle conditional branches and ignore indirect branches
110389ceb779SAmir Ayupov       if (isIndirectBranch(*I))
1104a34c753fSRafael Auler         return false;
1105a34c753fSRafael Auler 
1106a34c753fSRafael Auler       if (CondBranch == nullptr) {
1107a34c753fSRafael Auler         const MCSymbol *TargetBB = getTargetSymbol(*I);
1108a34c753fSRafael Auler         if (TargetBB == nullptr) {
1109a34c753fSRafael Auler           // Unrecognized branch target
1110a34c753fSRafael Auler           return false;
1111a34c753fSRafael Auler         }
1112a34c753fSRafael Auler         FBB = TBB;
1113a34c753fSRafael Auler         TBB = TargetBB;
1114a34c753fSRafael Auler         CondBranch = &*I;
1115a34c753fSRafael Auler         continue;
1116a34c753fSRafael Auler       }
1117a34c753fSRafael Auler 
1118a34c753fSRafael Auler       llvm_unreachable("multiple conditional branches in one BB");
1119a34c753fSRafael Auler     }
1120a34c753fSRafael Auler     return true;
1121a34c753fSRafael Auler   }
1122a34c753fSRafael Auler 
112369706eafSMaksim Panchenko   void createLongJmp(InstructionListType &Seq, const MCSymbol *Target,
1124a34c753fSRafael Auler                      MCContext *Ctx, bool IsTailCall) override {
1125a34c753fSRafael Auler     // ip0 (r16) is reserved to the linker (refer to 5.3.1.1 of "Procedure Call
1126a34c753fSRafael Auler     //   Standard for the ARM 64-bit Architecture (AArch64)".
1127a34c753fSRafael Auler     // The sequence of instructions we create here is the following:
1128a34c753fSRafael Auler     //  movz ip0, #:abs_g3:<addr>
1129a34c753fSRafael Auler     //  movk ip0, #:abs_g2_nc:<addr>
1130a34c753fSRafael Auler     //  movk ip0, #:abs_g1_nc:<addr>
1131a34c753fSRafael Auler     //  movk ip0, #:abs_g0_nc:<addr>
1132a34c753fSRafael Auler     //  br ip0
1133a34c753fSRafael Auler     MCInst Inst;
1134a34c753fSRafael Auler     Inst.setOpcode(AArch64::MOVZXi);
1135a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1136a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
1137a34c753fSRafael Auler         MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
1138a34c753fSRafael Auler         AArch64MCExpr::VK_ABS_G3, *Ctx)));
1139a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0x30));
1140a34c753fSRafael Auler     Seq.emplace_back(Inst);
1141a34c753fSRafael Auler 
1142a34c753fSRafael Auler     Inst.clear();
1143a34c753fSRafael Auler     Inst.setOpcode(AArch64::MOVKXi);
1144a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1145a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1146a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
1147a34c753fSRafael Auler         MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
1148a34c753fSRafael Auler         AArch64MCExpr::VK_ABS_G2_NC, *Ctx)));
1149a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0x20));
1150a34c753fSRafael Auler     Seq.emplace_back(Inst);
1151a34c753fSRafael Auler 
1152a34c753fSRafael Auler     Inst.clear();
1153a34c753fSRafael Auler     Inst.setOpcode(AArch64::MOVKXi);
1154a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1155a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1156a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
1157a34c753fSRafael Auler         MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
1158a34c753fSRafael Auler         AArch64MCExpr::VK_ABS_G1_NC, *Ctx)));
1159a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0x10));
1160a34c753fSRafael Auler     Seq.emplace_back(Inst);
1161a34c753fSRafael Auler 
1162a34c753fSRafael Auler     Inst.clear();
1163a34c753fSRafael Auler     Inst.setOpcode(AArch64::MOVKXi);
1164a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1165a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1166a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
1167a34c753fSRafael Auler         MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
1168a34c753fSRafael Auler         AArch64MCExpr::VK_ABS_G0_NC, *Ctx)));
1169a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0));
1170a34c753fSRafael Auler     Seq.emplace_back(Inst);
1171a34c753fSRafael Auler 
1172a34c753fSRafael Auler     Inst.clear();
1173a34c753fSRafael Auler     Inst.setOpcode(AArch64::BR);
1174a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1175a34c753fSRafael Auler     if (IsTailCall)
1176a34c753fSRafael Auler       setTailCall(Inst);
1177a34c753fSRafael Auler     Seq.emplace_back(Inst);
1178a34c753fSRafael Auler   }
1179a34c753fSRafael Auler 
118069706eafSMaksim Panchenko   void createShortJmp(InstructionListType &Seq, const MCSymbol *Target,
1181a34c753fSRafael Auler                       MCContext *Ctx, bool IsTailCall) override {
1182a34c753fSRafael Auler     // ip0 (r16) is reserved to the linker (refer to 5.3.1.1 of "Procedure Call
1183a34c753fSRafael Auler     //   Standard for the ARM 64-bit Architecture (AArch64)".
1184a34c753fSRafael Auler     // The sequence of instructions we create here is the following:
1185a34c753fSRafael Auler     //  adrp ip0, imm
1186a34c753fSRafael Auler     //  add ip0, ip0, imm
1187a34c753fSRafael Auler     //  br ip0
1188a34c753fSRafael Auler     MCPhysReg Reg = AArch64::X16;
118969706eafSMaksim Panchenko     InstructionListType Insts = materializeAddress(Target, Ctx, Reg);
1190a34c753fSRafael Auler     Insts.emplace_back();
1191a34c753fSRafael Auler     MCInst &Inst = Insts.back();
1192a34c753fSRafael Auler     Inst.clear();
1193a34c753fSRafael Auler     Inst.setOpcode(AArch64::BR);
1194a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(Reg));
1195a34c753fSRafael Auler     if (IsTailCall)
1196a34c753fSRafael Auler       setTailCall(Inst);
1197a34c753fSRafael Auler     Seq.swap(Insts);
1198a34c753fSRafael Auler   }
1199a34c753fSRafael Auler 
1200a34c753fSRafael Auler   /// Matching pattern here is
1201a34c753fSRafael Auler   ///
1202a34c753fSRafael Auler   ///    ADRP  x16, imm
1203a34c753fSRafael Auler   ///    ADD   x16, x16, imm
1204a34c753fSRafael Auler   ///    BR    x16
1205a34c753fSRafael Auler   ///
120635efe1d8SVladislav Khmelevsky   uint64_t matchLinkerVeneer(InstructionIterator Begin, InstructionIterator End,
1207a34c753fSRafael Auler                              uint64_t Address, const MCInst &CurInst,
1208a34c753fSRafael Auler                              MCInst *&TargetHiBits, MCInst *&TargetLowBits,
1209a34c753fSRafael Auler                              uint64_t &Target) const override {
1210a34c753fSRafael Auler     if (CurInst.getOpcode() != AArch64::BR || !CurInst.getOperand(0).isReg() ||
1211a34c753fSRafael Auler         CurInst.getOperand(0).getReg() != AArch64::X16)
121235efe1d8SVladislav Khmelevsky       return 0;
1213a34c753fSRafael Auler 
1214a34c753fSRafael Auler     auto I = End;
1215a34c753fSRafael Auler     if (I == Begin)
121635efe1d8SVladislav Khmelevsky       return 0;
1217a34c753fSRafael Auler 
1218a34c753fSRafael Auler     --I;
1219a34c753fSRafael Auler     Address -= 4;
12208aab58baSMaksim Panchenko     if (I == Begin || I->getOpcode() != AArch64::ADDXri ||
12218aab58baSMaksim Panchenko         MCPlus::getNumPrimeOperands(*I) < 3 || !I->getOperand(0).isReg() ||
1222a34c753fSRafael Auler         !I->getOperand(1).isReg() ||
1223a34c753fSRafael Auler         I->getOperand(0).getReg() != AArch64::X16 ||
12248aab58baSMaksim Panchenko         I->getOperand(1).getReg() != AArch64::X16 || !I->getOperand(2).isImm())
122535efe1d8SVladislav Khmelevsky       return 0;
1226a34c753fSRafael Auler     TargetLowBits = &*I;
1227a34c753fSRafael Auler     uint64_t Addr = I->getOperand(2).getImm() & 0xFFF;
1228a34c753fSRafael Auler 
1229a34c753fSRafael Auler     --I;
1230a34c753fSRafael Auler     Address -= 4;
1231a34c753fSRafael Auler     if (I->getOpcode() != AArch64::ADRP ||
12328aab58baSMaksim Panchenko         MCPlus::getNumPrimeOperands(*I) < 2 || !I->getOperand(0).isReg() ||
12338aab58baSMaksim Panchenko         !I->getOperand(1).isImm() || I->getOperand(0).getReg() != AArch64::X16)
123435efe1d8SVladislav Khmelevsky       return 0;
1235a34c753fSRafael Auler     TargetHiBits = &*I;
1236a34c753fSRafael Auler     Addr |= (Address + ((int64_t)I->getOperand(1).getImm() << 12)) &
1237a34c753fSRafael Auler             0xFFFFFFFFFFFFF000ULL;
1238a34c753fSRafael Auler     Target = Addr;
123935efe1d8SVladislav Khmelevsky     return 3;
1240a34c753fSRafael Auler   }
1241a34c753fSRafael Auler 
124217ed8f29SVladislav Khmelevsky   bool matchAdrpAddPair(const MCInst &Adrp, const MCInst &Add) const override {
124317ed8f29SVladislav Khmelevsky     if (!isADRP(Adrp) || !isAddXri(Add))
124417ed8f29SVladislav Khmelevsky       return false;
124517ed8f29SVladislav Khmelevsky 
124617ed8f29SVladislav Khmelevsky     assert(Adrp.getOperand(0).isReg() &&
124717ed8f29SVladislav Khmelevsky            "Unexpected operand in ADRP instruction");
124817ed8f29SVladislav Khmelevsky     MCPhysReg AdrpReg = Adrp.getOperand(0).getReg();
124917ed8f29SVladislav Khmelevsky     assert(Add.getOperand(1).isReg() &&
125017ed8f29SVladislav Khmelevsky            "Unexpected operand in ADDXri instruction");
125117ed8f29SVladislav Khmelevsky     MCPhysReg AddReg = Add.getOperand(1).getReg();
125217ed8f29SVladislav Khmelevsky     return AdrpReg == AddReg;
125317ed8f29SVladislav Khmelevsky   }
125417ed8f29SVladislav Khmelevsky 
1255a34c753fSRafael Auler   bool replaceImmWithSymbolRef(MCInst &Inst, const MCSymbol *Symbol,
1256a34c753fSRafael Auler                                int64_t Addend, MCContext *Ctx, int64_t &Value,
1257a34c753fSRafael Auler                                uint64_t RelType) const override {
1258a34c753fSRafael Auler     unsigned ImmOpNo = -1U;
1259a34c753fSRafael Auler     for (unsigned Index = 0; Index < MCPlus::getNumPrimeOperands(Inst);
1260a34c753fSRafael Auler          ++Index) {
1261a34c753fSRafael Auler       if (Inst.getOperand(Index).isImm()) {
1262a34c753fSRafael Auler         ImmOpNo = Index;
1263a34c753fSRafael Auler         break;
1264a34c753fSRafael Auler       }
1265a34c753fSRafael Auler     }
1266a34c753fSRafael Auler     if (ImmOpNo == -1U)
1267a34c753fSRafael Auler       return false;
1268a34c753fSRafael Auler 
1269a34c753fSRafael Auler     Value = Inst.getOperand(ImmOpNo).getImm();
1270a34c753fSRafael Auler 
1271a34c753fSRafael Auler     setOperandToSymbolRef(Inst, ImmOpNo, Symbol, Addend, Ctx, RelType);
1272a34c753fSRafael Auler 
1273a34c753fSRafael Auler     return true;
1274a34c753fSRafael Auler   }
1275a34c753fSRafael Auler 
1276a34c753fSRafael Auler   bool createUncondBranch(MCInst &Inst, const MCSymbol *TBB,
1277a34c753fSRafael Auler                           MCContext *Ctx) const override {
1278a34c753fSRafael Auler     Inst.setOpcode(AArch64::B);
1279a34c753fSRafael Auler     Inst.clear();
1280a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(getTargetExprFor(
1281a34c753fSRafael Auler         Inst, MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx),
1282a34c753fSRafael Auler         *Ctx, 0)));
1283a34c753fSRafael Auler     return true;
1284a34c753fSRafael Auler   }
1285a34c753fSRafael Auler 
1286edda8577SAmir Ayupov   bool shouldRecordCodeRelocation(uint64_t RelType) const override {
1287edda8577SAmir Ayupov     switch (RelType) {
1288edda8577SAmir Ayupov     case ELF::R_AARCH64_ABS64:
1289edda8577SAmir Ayupov     case ELF::R_AARCH64_ABS32:
1290edda8577SAmir Ayupov     case ELF::R_AARCH64_ABS16:
1291edda8577SAmir Ayupov     case ELF::R_AARCH64_ADD_ABS_LO12_NC:
1292edda8577SAmir Ayupov     case ELF::R_AARCH64_ADR_GOT_PAGE:
1293edda8577SAmir Ayupov     case ELF::R_AARCH64_ADR_PREL_LO21:
1294edda8577SAmir Ayupov     case ELF::R_AARCH64_ADR_PREL_PG_HI21:
1295edda8577SAmir Ayupov     case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC:
1296edda8577SAmir Ayupov     case ELF::R_AARCH64_LD64_GOT_LO12_NC:
1297edda8577SAmir Ayupov     case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
1298edda8577SAmir Ayupov     case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
1299edda8577SAmir Ayupov     case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
1300edda8577SAmir Ayupov     case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
1301edda8577SAmir Ayupov     case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
1302edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSDESC_ADD_LO12:
1303edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
1304edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
1305edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSDESC_LD64_LO12:
1306edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
1307edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
1308edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G0:
1309edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G0_NC:
1310edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G1:
1311edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G1_NC:
1312edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G2:
1313edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G2_NC:
1314edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G3:
1315edda8577SAmir Ayupov     case ELF::R_AARCH64_PREL16:
1316edda8577SAmir Ayupov     case ELF::R_AARCH64_PREL32:
1317edda8577SAmir Ayupov     case ELF::R_AARCH64_PREL64:
1318edda8577SAmir Ayupov       return true;
1319edda8577SAmir Ayupov     case ELF::R_AARCH64_CALL26:
1320edda8577SAmir Ayupov     case ELF::R_AARCH64_JUMP26:
1321edda8577SAmir Ayupov     case ELF::R_AARCH64_TSTBR14:
1322edda8577SAmir Ayupov     case ELF::R_AARCH64_CONDBR19:
1323edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSDESC_CALL:
1324edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
1325edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
1326edda8577SAmir Ayupov       return false;
1327edda8577SAmir Ayupov     default:
1328edda8577SAmir Ayupov       llvm_unreachable("Unexpected AArch64 relocation type in code");
1329edda8577SAmir Ayupov     }
1330edda8577SAmir Ayupov   }
1331edda8577SAmir Ayupov 
133228fd2ca1SDenis Revunov   StringRef getTrapFillValue() const override {
133328fd2ca1SDenis Revunov     return StringRef("\0\0\0\0", 4);
133428fd2ca1SDenis Revunov   }
133528fd2ca1SDenis Revunov 
1336a34c753fSRafael Auler   bool createReturn(MCInst &Inst) const override {
1337a34c753fSRafael Auler     Inst.setOpcode(AArch64::RET);
1338a34c753fSRafael Auler     Inst.clear();
1339a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::LR));
1340a34c753fSRafael Auler     return true;
1341a34c753fSRafael Auler   }
1342a34c753fSRafael Auler 
13436e4c2305SElvina Yakubova   bool createStackPointerIncrement(
13446e4c2305SElvina Yakubova       MCInst &Inst, int Size,
13456e4c2305SElvina Yakubova       bool NoFlagsClobber = false /*unused for AArch64*/) const override {
13466e4c2305SElvina Yakubova     Inst.setOpcode(AArch64::SUBXri);
13476e4c2305SElvina Yakubova     Inst.clear();
13486e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(AArch64::SP));
13496e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(AArch64::SP));
13506e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(Size));
13516e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(0));
13526e4c2305SElvina Yakubova     return true;
13536e4c2305SElvina Yakubova   }
13546e4c2305SElvina Yakubova 
13556e4c2305SElvina Yakubova   bool createStackPointerDecrement(
13566e4c2305SElvina Yakubova       MCInst &Inst, int Size,
13576e4c2305SElvina Yakubova       bool NoFlagsClobber = false /*unused for AArch64*/) const override {
13586e4c2305SElvina Yakubova     Inst.setOpcode(AArch64::ADDXri);
13596e4c2305SElvina Yakubova     Inst.clear();
13606e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(AArch64::SP));
13616e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(AArch64::SP));
13626e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(Size));
13636e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(0));
13646e4c2305SElvina Yakubova     return true;
13656e4c2305SElvina Yakubova   }
13666e4c2305SElvina Yakubova 
13676e4c2305SElvina Yakubova   void createIndirectBranch(MCInst &Inst, MCPhysReg MemBaseReg,
13686e4c2305SElvina Yakubova                             int64_t Disp) const {
13696e4c2305SElvina Yakubova     Inst.setOpcode(AArch64::BR);
13706e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(MemBaseReg));
13716e4c2305SElvina Yakubova   }
13726e4c2305SElvina Yakubova 
13736e4c2305SElvina Yakubova   InstructionListType createInstrumentedIndCallHandlerExitBB() const override {
13746e4c2305SElvina Yakubova     InstructionListType Insts(5);
13756e4c2305SElvina Yakubova     // Code sequence for instrumented indirect call handler:
13766e4c2305SElvina Yakubova     //   msr  nzcv, x1
13776e4c2305SElvina Yakubova     //   ldp  x0, x1, [sp], #16
13786e4c2305SElvina Yakubova     //   ldr  x16, [sp], #16
13796e4c2305SElvina Yakubova     //   ldp  x0, x1, [sp], #16
13806e4c2305SElvina Yakubova     //   br   x16
13816e4c2305SElvina Yakubova     setSystemFlag(Insts[0], AArch64::X1);
13826e4c2305SElvina Yakubova     createPopRegisters(Insts[1], AArch64::X0, AArch64::X1);
13836e4c2305SElvina Yakubova     // Here we load address of the next function which should be called in the
13846e4c2305SElvina Yakubova     // original binary to X16 register. Writing to X16 is permitted without
13856e4c2305SElvina Yakubova     // needing to restore.
13866e4c2305SElvina Yakubova     loadReg(Insts[2], AArch64::X16, AArch64::SP);
13876e4c2305SElvina Yakubova     createPopRegisters(Insts[3], AArch64::X0, AArch64::X1);
13886e4c2305SElvina Yakubova     createIndirectBranch(Insts[4], AArch64::X16, 0);
13896e4c2305SElvina Yakubova     return Insts;
13906e4c2305SElvina Yakubova   }
13916e4c2305SElvina Yakubova 
13926e4c2305SElvina Yakubova   InstructionListType
13936e4c2305SElvina Yakubova   createInstrumentedIndTailCallHandlerExitBB() const override {
13946e4c2305SElvina Yakubova     return createInstrumentedIndCallHandlerExitBB();
13956e4c2305SElvina Yakubova   }
13966e4c2305SElvina Yakubova 
139770405a0bSElvina Yakubova   InstructionListType createGetter(MCContext *Ctx, const char *name) const {
139870405a0bSElvina Yakubova     InstructionListType Insts(4);
139970405a0bSElvina Yakubova     MCSymbol *Locs = Ctx->getOrCreateSymbol(name);
140070405a0bSElvina Yakubova     InstructionListType Addr = materializeAddress(Locs, Ctx, AArch64::X0);
140170405a0bSElvina Yakubova     std::copy(Addr.begin(), Addr.end(), Insts.begin());
140270405a0bSElvina Yakubova     assert(Addr.size() == 2 && "Invalid Addr size");
140370405a0bSElvina Yakubova     loadReg(Insts[2], AArch64::X0, AArch64::X0);
140470405a0bSElvina Yakubova     createReturn(Insts[3]);
140570405a0bSElvina Yakubova     return Insts;
140670405a0bSElvina Yakubova   }
140770405a0bSElvina Yakubova 
140870405a0bSElvina Yakubova   InstructionListType createNumCountersGetter(MCContext *Ctx) const override {
140970405a0bSElvina Yakubova     return createGetter(Ctx, "__bolt_num_counters");
141070405a0bSElvina Yakubova   }
141170405a0bSElvina Yakubova 
141270405a0bSElvina Yakubova   InstructionListType
141370405a0bSElvina Yakubova   createInstrLocationsGetter(MCContext *Ctx) const override {
141470405a0bSElvina Yakubova     return createGetter(Ctx, "__bolt_instr_locations");
141570405a0bSElvina Yakubova   }
141670405a0bSElvina Yakubova 
141770405a0bSElvina Yakubova   InstructionListType createInstrTablesGetter(MCContext *Ctx) const override {
141870405a0bSElvina Yakubova     return createGetter(Ctx, "__bolt_instr_tables");
141970405a0bSElvina Yakubova   }
142070405a0bSElvina Yakubova 
142170405a0bSElvina Yakubova   InstructionListType createInstrNumFuncsGetter(MCContext *Ctx) const override {
142270405a0bSElvina Yakubova     return createGetter(Ctx, "__bolt_instr_num_funcs");
142370405a0bSElvina Yakubova   }
142470405a0bSElvina Yakubova 
14256e4c2305SElvina Yakubova   void convertIndirectCallToLoad(MCInst &Inst, MCPhysReg Reg) override {
14266e4c2305SElvina Yakubova     bool IsTailCall = isTailCall(Inst);
14276e4c2305SElvina Yakubova     if (IsTailCall)
14286e4c2305SElvina Yakubova       removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
14296e4c2305SElvina Yakubova     if (Inst.getOpcode() == AArch64::BR || Inst.getOpcode() == AArch64::BLR) {
14306e4c2305SElvina Yakubova       Inst.setOpcode(AArch64::ORRXrs);
14316e4c2305SElvina Yakubova       Inst.insert(Inst.begin(), MCOperand::createReg(Reg));
14326e4c2305SElvina Yakubova       Inst.insert(Inst.begin() + 1, MCOperand::createReg(AArch64::XZR));
14336e4c2305SElvina Yakubova       Inst.insert(Inst.begin() + 3, MCOperand::createImm(0));
14346e4c2305SElvina Yakubova       return;
14356e4c2305SElvina Yakubova     }
14366e4c2305SElvina Yakubova     llvm_unreachable("not implemented");
14376e4c2305SElvina Yakubova   }
14386e4c2305SElvina Yakubova 
14396e4c2305SElvina Yakubova   InstructionListType createLoadImmediate(const MCPhysReg Dest,
14406e4c2305SElvina Yakubova                                           uint64_t Imm) const override {
14416e4c2305SElvina Yakubova     InstructionListType Insts(4);
14426e4c2305SElvina Yakubova     int Shift = 48;
14436e4c2305SElvina Yakubova     for (int I = 0; I < 4; I++, Shift -= 16) {
14446e4c2305SElvina Yakubova       Insts[I].setOpcode(AArch64::MOVKXi);
14456e4c2305SElvina Yakubova       Insts[I].addOperand(MCOperand::createReg(Dest));
14466e4c2305SElvina Yakubova       Insts[I].addOperand(MCOperand::createReg(Dest));
14476e4c2305SElvina Yakubova       Insts[I].addOperand(MCOperand::createImm((Imm >> Shift) & 0xFFFF));
14486e4c2305SElvina Yakubova       Insts[I].addOperand(MCOperand::createImm(Shift));
14496e4c2305SElvina Yakubova     }
14506e4c2305SElvina Yakubova     return Insts;
14516e4c2305SElvina Yakubova   }
14526e4c2305SElvina Yakubova 
14536e4c2305SElvina Yakubova   void createIndirectCallInst(MCInst &Inst, bool IsTailCall,
14546e4c2305SElvina Yakubova                               MCPhysReg Reg) const {
14556e4c2305SElvina Yakubova     Inst.clear();
14566e4c2305SElvina Yakubova     Inst.setOpcode(IsTailCall ? AArch64::BR : AArch64::BLR);
14576e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(Reg));
14586e4c2305SElvina Yakubova   }
14596e4c2305SElvina Yakubova 
14606e4c2305SElvina Yakubova   InstructionListType createInstrumentedIndirectCall(MCInst &&CallInst,
14616e4c2305SElvina Yakubova                                                      MCSymbol *HandlerFuncAddr,
14626e4c2305SElvina Yakubova                                                      int CallSiteID,
14636e4c2305SElvina Yakubova                                                      MCContext *Ctx) override {
14646e4c2305SElvina Yakubova     InstructionListType Insts;
14656e4c2305SElvina Yakubova     // Code sequence used to enter indirect call instrumentation helper:
14666e4c2305SElvina Yakubova     //   stp x0, x1, [sp, #-16]! createPushRegisters
14676e4c2305SElvina Yakubova     //   mov target x0  convertIndirectCallToLoad -> orr x0 target xzr
14686e4c2305SElvina Yakubova     //   mov x1 CallSiteID createLoadImmediate ->
14696e4c2305SElvina Yakubova     //   movk    x1, #0x0, lsl #48
14706e4c2305SElvina Yakubova     //   movk    x1, #0x0, lsl #32
14716e4c2305SElvina Yakubova     //   movk    x1, #0x0, lsl #16
14726e4c2305SElvina Yakubova     //   movk    x1, #0x0
14736e4c2305SElvina Yakubova     //   stp x0, x1, [sp, #-16]!
14746e4c2305SElvina Yakubova     //   bl *HandlerFuncAddr createIndirectCall ->
14756e4c2305SElvina Yakubova     //   adr x0 *HandlerFuncAddr -> adrp + add
14766e4c2305SElvina Yakubova     //   blr x0
14776e4c2305SElvina Yakubova     Insts.emplace_back();
14786e4c2305SElvina Yakubova     createPushRegisters(Insts.back(), AArch64::X0, AArch64::X1);
14796e4c2305SElvina Yakubova     Insts.emplace_back(CallInst);
14806e4c2305SElvina Yakubova     convertIndirectCallToLoad(Insts.back(), AArch64::X0);
14816e4c2305SElvina Yakubova     InstructionListType LoadImm =
14826e4c2305SElvina Yakubova         createLoadImmediate(getIntArgRegister(1), CallSiteID);
14836e4c2305SElvina Yakubova     Insts.insert(Insts.end(), LoadImm.begin(), LoadImm.end());
14846e4c2305SElvina Yakubova     Insts.emplace_back();
14856e4c2305SElvina Yakubova     createPushRegisters(Insts.back(), AArch64::X0, AArch64::X1);
14866e4c2305SElvina Yakubova     Insts.resize(Insts.size() + 2);
14876e4c2305SElvina Yakubova     InstructionListType Addr =
14886e4c2305SElvina Yakubova         materializeAddress(HandlerFuncAddr, Ctx, AArch64::X0);
14896e4c2305SElvina Yakubova     assert(Addr.size() == 2 && "Invalid Addr size");
14906e4c2305SElvina Yakubova     std::copy(Addr.begin(), Addr.end(), Insts.end() - Addr.size());
14916e4c2305SElvina Yakubova     Insts.emplace_back();
14926e4c2305SElvina Yakubova     createIndirectCallInst(Insts.back(), isTailCall(CallInst), AArch64::X0);
14936e4c2305SElvina Yakubova 
14946e4c2305SElvina Yakubova     // Carry over metadata including tail call marker if present.
14956e4c2305SElvina Yakubova     stripAnnotations(Insts.back());
14966e4c2305SElvina Yakubova     moveAnnotations(std::move(CallInst), Insts.back());
14976e4c2305SElvina Yakubova 
14986e4c2305SElvina Yakubova     return Insts;
14996e4c2305SElvina Yakubova   }
15006e4c2305SElvina Yakubova 
15016e4c2305SElvina Yakubova   InstructionListType
15026e4c2305SElvina Yakubova   createInstrumentedIndCallHandlerEntryBB(const MCSymbol *InstrTrampoline,
15036e4c2305SElvina Yakubova                                           const MCSymbol *IndCallHandler,
15046e4c2305SElvina Yakubova                                           MCContext *Ctx) override {
15056e4c2305SElvina Yakubova     // Code sequence used to check whether InstrTampoline was initialized
15066e4c2305SElvina Yakubova     // and call it if so, returns via IndCallHandler
15076e4c2305SElvina Yakubova     //   stp     x0, x1, [sp, #-16]!
15086e4c2305SElvina Yakubova     //   mrs     x1, nzcv
15096e4c2305SElvina Yakubova     //   adr     x0, InstrTrampoline -> adrp + add
15106e4c2305SElvina Yakubova     //   ldr     x0, [x0]
15116e4c2305SElvina Yakubova     //   subs    x0, x0, #0x0
15126e4c2305SElvina Yakubova     //   b.eq    IndCallHandler
15136e4c2305SElvina Yakubova     //   str     x30, [sp, #-16]!
15146e4c2305SElvina Yakubova     //   blr     x0
15156e4c2305SElvina Yakubova     //   ldr     x30, [sp], #16
15166e4c2305SElvina Yakubova     //   b       IndCallHandler
15176e4c2305SElvina Yakubova     InstructionListType Insts;
15186e4c2305SElvina Yakubova     Insts.emplace_back();
15196e4c2305SElvina Yakubova     createPushRegisters(Insts.back(), AArch64::X0, AArch64::X1);
15206e4c2305SElvina Yakubova     Insts.emplace_back();
15216e4c2305SElvina Yakubova     getSystemFlag(Insts.back(), getIntArgRegister(1));
15226e4c2305SElvina Yakubova     Insts.emplace_back();
15236e4c2305SElvina Yakubova     Insts.emplace_back();
15246e4c2305SElvina Yakubova     InstructionListType Addr =
15256e4c2305SElvina Yakubova         materializeAddress(InstrTrampoline, Ctx, AArch64::X0);
15266e4c2305SElvina Yakubova     std::copy(Addr.begin(), Addr.end(), Insts.end() - Addr.size());
15276e4c2305SElvina Yakubova     assert(Addr.size() == 2 && "Invalid Addr size");
15286e4c2305SElvina Yakubova     Insts.emplace_back();
15296e4c2305SElvina Yakubova     loadReg(Insts.back(), AArch64::X0, AArch64::X0);
15306e4c2305SElvina Yakubova     InstructionListType cmpJmp =
15316e4c2305SElvina Yakubova         createCmpJE(AArch64::X0, 0, IndCallHandler, Ctx);
15326e4c2305SElvina Yakubova     Insts.insert(Insts.end(), cmpJmp.begin(), cmpJmp.end());
15336e4c2305SElvina Yakubova     Insts.emplace_back();
15346e4c2305SElvina Yakubova     storeReg(Insts.back(), AArch64::LR, AArch64::SP);
15356e4c2305SElvina Yakubova     Insts.emplace_back();
15366e4c2305SElvina Yakubova     Insts.back().setOpcode(AArch64::BLR);
15376e4c2305SElvina Yakubova     Insts.back().addOperand(MCOperand::createReg(AArch64::X0));
15386e4c2305SElvina Yakubova     Insts.emplace_back();
15396e4c2305SElvina Yakubova     loadReg(Insts.back(), AArch64::LR, AArch64::SP);
15406e4c2305SElvina Yakubova     Insts.emplace_back();
15416e4c2305SElvina Yakubova     createDirectCall(Insts.back(), IndCallHandler, Ctx, /*IsTailCall*/ true);
15426e4c2305SElvina Yakubova     return Insts;
15436e4c2305SElvina Yakubova   }
15446e4c2305SElvina Yakubova 
15456e4c2305SElvina Yakubova   InstructionListType
15466e4c2305SElvina Yakubova   createInstrIncMemory(const MCSymbol *Target, MCContext *Ctx, bool IsLeaf,
15476e4c2305SElvina Yakubova                        unsigned CodePointerSize) const override {
15486e4c2305SElvina Yakubova     unsigned int I = 0;
15496e4c2305SElvina Yakubova     InstructionListType Instrs(IsLeaf ? 12 : 10);
15506e4c2305SElvina Yakubova 
15516e4c2305SElvina Yakubova     if (IsLeaf)
15526e4c2305SElvina Yakubova       createStackPointerIncrement(Instrs[I++], 128);
15536e4c2305SElvina Yakubova     createPushRegisters(Instrs[I++], AArch64::X0, AArch64::X1);
15546e4c2305SElvina Yakubova     getSystemFlag(Instrs[I++], AArch64::X1);
15556e4c2305SElvina Yakubova     InstructionListType Addr = materializeAddress(Target, Ctx, AArch64::X0);
15566e4c2305SElvina Yakubova     assert(Addr.size() == 2 && "Invalid Addr size");
15576e4c2305SElvina Yakubova     std::copy(Addr.begin(), Addr.end(), Instrs.begin() + I);
15586e4c2305SElvina Yakubova     I += Addr.size();
15596e4c2305SElvina Yakubova     storeReg(Instrs[I++], AArch64::X2, AArch64::SP);
15606e4c2305SElvina Yakubova     InstructionListType Insts = createIncMemory(AArch64::X0, AArch64::X2);
15616e4c2305SElvina Yakubova     assert(Insts.size() == 2 && "Invalid Insts size");
15626e4c2305SElvina Yakubova     std::copy(Insts.begin(), Insts.end(), Instrs.begin() + I);
15636e4c2305SElvina Yakubova     I += Insts.size();
15646e4c2305SElvina Yakubova     loadReg(Instrs[I++], AArch64::X2, AArch64::SP);
15656e4c2305SElvina Yakubova     setSystemFlag(Instrs[I++], AArch64::X1);
15666e4c2305SElvina Yakubova     createPopRegisters(Instrs[I++], AArch64::X0, AArch64::X1);
15676e4c2305SElvina Yakubova     if (IsLeaf)
15686e4c2305SElvina Yakubova       createStackPointerDecrement(Instrs[I++], 128);
15696e4c2305SElvina Yakubova     return Instrs;
15706e4c2305SElvina Yakubova   }
15716e4c2305SElvina Yakubova 
15726e4c2305SElvina Yakubova   std::vector<MCInst> createSymbolTrampoline(const MCSymbol *TgtSym,
15736e4c2305SElvina Yakubova                                              MCContext *Ctx) override {
15746e4c2305SElvina Yakubova     std::vector<MCInst> Insts;
15756e4c2305SElvina Yakubova     createShortJmp(Insts, TgtSym, Ctx, /*IsTailCall*/ true);
15766e4c2305SElvina Yakubova     return Insts;
15776e4c2305SElvina Yakubova   }
15786e4c2305SElvina Yakubova 
157969706eafSMaksim Panchenko   InstructionListType materializeAddress(const MCSymbol *Target, MCContext *Ctx,
1580a34c753fSRafael Auler                                          MCPhysReg RegName,
1581a34c753fSRafael Auler                                          int64_t Addend = 0) const override {
1582a34c753fSRafael Auler     // Get page-aligned address and add page offset
158369706eafSMaksim Panchenko     InstructionListType Insts(2);
1584a34c753fSRafael Auler     Insts[0].setOpcode(AArch64::ADRP);
1585a34c753fSRafael Auler     Insts[0].clear();
1586a34c753fSRafael Auler     Insts[0].addOperand(MCOperand::createReg(RegName));
1587a34c753fSRafael Auler     Insts[0].addOperand(MCOperand::createImm(0));
1588a34c753fSRafael Auler     setOperandToSymbolRef(Insts[0], /* OpNum */ 1, Target, Addend, Ctx,
1589a34c753fSRafael Auler                           ELF::R_AARCH64_NONE);
1590a34c753fSRafael Auler     Insts[1].setOpcode(AArch64::ADDXri);
1591a34c753fSRafael Auler     Insts[1].clear();
1592a34c753fSRafael Auler     Insts[1].addOperand(MCOperand::createReg(RegName));
1593a34c753fSRafael Auler     Insts[1].addOperand(MCOperand::createReg(RegName));
1594a34c753fSRafael Auler     Insts[1].addOperand(MCOperand::createImm(0));
1595a34c753fSRafael Auler     Insts[1].addOperand(MCOperand::createImm(0));
1596a34c753fSRafael Auler     setOperandToSymbolRef(Insts[1], /* OpNum */ 2, Target, Addend, Ctx,
1597a34c753fSRafael Auler                           ELF::R_AARCH64_ADD_ABS_LO12_NC);
1598a34c753fSRafael Auler     return Insts;
1599a34c753fSRafael Auler   }
160062020a3aSzhoujiapeng 
160162020a3aSzhoujiapeng   std::optional<Relocation>
160262020a3aSzhoujiapeng   createRelocation(const MCFixup &Fixup,
160362020a3aSzhoujiapeng                    const MCAsmBackend &MAB) const override {
160462020a3aSzhoujiapeng     const MCFixupKindInfo &FKI = MAB.getFixupKindInfo(Fixup.getKind());
160562020a3aSzhoujiapeng 
160662020a3aSzhoujiapeng     assert(FKI.TargetOffset == 0 && "0-bit relocation offset expected");
160762020a3aSzhoujiapeng     const uint64_t RelOffset = Fixup.getOffset();
160862020a3aSzhoujiapeng 
160962020a3aSzhoujiapeng     uint64_t RelType;
161062020a3aSzhoujiapeng     if (Fixup.getKind() == MCFixupKind(AArch64::fixup_aarch64_pcrel_call26))
161162020a3aSzhoujiapeng       RelType = ELF::R_AARCH64_CALL26;
161262020a3aSzhoujiapeng     else if (FKI.Flags & MCFixupKindInfo::FKF_IsPCRel) {
161362020a3aSzhoujiapeng       switch (FKI.TargetSize) {
161462020a3aSzhoujiapeng       default:
161562020a3aSzhoujiapeng         return std::nullopt;
161662020a3aSzhoujiapeng       case 16:
161762020a3aSzhoujiapeng         RelType = ELF::R_AARCH64_PREL16;
161862020a3aSzhoujiapeng         break;
161962020a3aSzhoujiapeng       case 32:
162062020a3aSzhoujiapeng         RelType = ELF::R_AARCH64_PREL32;
162162020a3aSzhoujiapeng         break;
162262020a3aSzhoujiapeng       case 64:
162362020a3aSzhoujiapeng         RelType = ELF::R_AARCH64_PREL64;
162462020a3aSzhoujiapeng         break;
162562020a3aSzhoujiapeng       }
162662020a3aSzhoujiapeng     } else {
162762020a3aSzhoujiapeng       switch (FKI.TargetSize) {
162862020a3aSzhoujiapeng       default:
162962020a3aSzhoujiapeng         return std::nullopt;
163062020a3aSzhoujiapeng       case 16:
163162020a3aSzhoujiapeng         RelType = ELF::R_AARCH64_ABS16;
163262020a3aSzhoujiapeng         break;
163362020a3aSzhoujiapeng       case 32:
163462020a3aSzhoujiapeng         RelType = ELF::R_AARCH64_ABS32;
163562020a3aSzhoujiapeng         break;
163662020a3aSzhoujiapeng       case 64:
163762020a3aSzhoujiapeng         RelType = ELF::R_AARCH64_ABS64;
163862020a3aSzhoujiapeng         break;
163962020a3aSzhoujiapeng       }
164062020a3aSzhoujiapeng     }
164162020a3aSzhoujiapeng 
164262020a3aSzhoujiapeng     auto [RelSymbol, RelAddend] = extractFixupExpr(Fixup);
164362020a3aSzhoujiapeng 
164462020a3aSzhoujiapeng     return Relocation({RelOffset, RelSymbol, RelType, RelAddend, 0});
164562020a3aSzhoujiapeng   }
1646*b6b49288SJob Noorman 
1647*b6b49288SJob Noorman   uint16_t getMinFunctionAlignment() const override { return 4; }
1648a34c753fSRafael Auler };
1649a34c753fSRafael Auler 
1650a34c753fSRafael Auler } // end anonymous namespace
1651a34c753fSRafael Auler 
1652a34c753fSRafael Auler namespace llvm {
1653a34c753fSRafael Auler namespace bolt {
1654a34c753fSRafael Auler 
1655a34c753fSRafael Auler MCPlusBuilder *createAArch64MCPlusBuilder(const MCInstrAnalysis *Analysis,
1656a34c753fSRafael Auler                                           const MCInstrInfo *Info,
16578fb83bf5SJob Noorman                                           const MCRegisterInfo *RegInfo,
16588fb83bf5SJob Noorman                                           const MCSubtargetInfo *STI) {
16598fb83bf5SJob Noorman   return new AArch64MCPlusBuilder(Analysis, Info, RegInfo, STI);
1660a34c753fSRafael Auler }
1661a34c753fSRafael Auler 
166240c2e0faSMaksim Panchenko } // namespace bolt
166340c2e0faSMaksim Panchenko } // namespace llvm
1664