xref: /llvm-project/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp (revision 1b4bd4e1a5120c8bb4daa44787a3bc4559b6b3b4)
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"
18be89e794SMaksim Panchenko #include "bolt/Core/BinaryBasicBlock.h"
19be89e794SMaksim Panchenko #include "bolt/Core/BinaryFunction.h"
20a34c753fSRafael Auler #include "bolt/Core/MCPlusBuilder.h"
21a34c753fSRafael Auler #include "llvm/BinaryFormat/ELF.h"
226e4c2305SElvina Yakubova #include "llvm/MC/MCContext.h"
2362020a3aSzhoujiapeng #include "llvm/MC/MCFixupKindInfo.h"
246e4c2305SElvina Yakubova #include "llvm/MC/MCInstBuilder.h"
25a34c753fSRafael Auler #include "llvm/MC/MCInstrInfo.h"
26a34c753fSRafael Auler #include "llvm/MC/MCRegisterInfo.h"
27be89e794SMaksim Panchenko #include "llvm/Support/DataExtractor.h"
28a34c753fSRafael Auler #include "llvm/Support/Debug.h"
29a34c753fSRafael Auler #include "llvm/Support/ErrorHandling.h"
30a34c753fSRafael Auler 
31bc9032c7SMaksim Panchenko #define DEBUG_TYPE "mcplus"
32a34c753fSRafael Auler 
33a34c753fSRafael Auler using namespace llvm;
34a34c753fSRafael Auler using namespace bolt;
35a34c753fSRafael Auler 
36a34c753fSRafael Auler namespace {
37a34c753fSRafael Auler 
386e4c2305SElvina Yakubova static void getSystemFlag(MCInst &Inst, MCPhysReg RegName) {
396e4c2305SElvina Yakubova   Inst.setOpcode(AArch64::MRS);
406e4c2305SElvina Yakubova   Inst.clear();
416e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(RegName));
426e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createImm(AArch64SysReg::NZCV));
436e4c2305SElvina Yakubova }
446e4c2305SElvina Yakubova 
456e4c2305SElvina Yakubova static void setSystemFlag(MCInst &Inst, MCPhysReg RegName) {
466e4c2305SElvina Yakubova   Inst.setOpcode(AArch64::MSR);
476e4c2305SElvina Yakubova   Inst.clear();
486e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createImm(AArch64SysReg::NZCV));
496e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(RegName));
506e4c2305SElvina Yakubova }
516e4c2305SElvina Yakubova 
526e4c2305SElvina Yakubova static void createPushRegisters(MCInst &Inst, MCPhysReg Reg1, MCPhysReg Reg2) {
536e4c2305SElvina Yakubova   Inst.clear();
546e4c2305SElvina Yakubova   unsigned NewOpcode = AArch64::STPXpre;
556e4c2305SElvina Yakubova   Inst.setOpcode(NewOpcode);
566e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(AArch64::SP));
576e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(Reg1));
586e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(Reg2));
596e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(AArch64::SP));
606e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createImm(-2));
616e4c2305SElvina Yakubova }
626e4c2305SElvina Yakubova 
636e4c2305SElvina Yakubova static void createPopRegisters(MCInst &Inst, MCPhysReg Reg1, MCPhysReg Reg2) {
646e4c2305SElvina Yakubova   Inst.clear();
656e4c2305SElvina Yakubova   unsigned NewOpcode = AArch64::LDPXpost;
666e4c2305SElvina Yakubova   Inst.setOpcode(NewOpcode);
676e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(AArch64::SP));
686e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(Reg1));
696e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(Reg2));
706e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(AArch64::SP));
716e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createImm(2));
726e4c2305SElvina Yakubova }
736e4c2305SElvina Yakubova 
746e4c2305SElvina Yakubova static void loadReg(MCInst &Inst, MCPhysReg To, MCPhysReg From) {
756e4c2305SElvina Yakubova   Inst.setOpcode(AArch64::LDRXui);
766e4c2305SElvina Yakubova   Inst.clear();
776e4c2305SElvina Yakubova   if (From == AArch64::SP) {
786e4c2305SElvina Yakubova     Inst.setOpcode(AArch64::LDRXpost);
796e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(From));
806e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(To));
816e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(From));
826e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(16));
836e4c2305SElvina Yakubova   } else {
846e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(To));
856e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(From));
866e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(0));
876e4c2305SElvina Yakubova   }
886e4c2305SElvina Yakubova }
896e4c2305SElvina Yakubova 
906e4c2305SElvina Yakubova static void storeReg(MCInst &Inst, MCPhysReg From, MCPhysReg To) {
916e4c2305SElvina Yakubova   Inst.setOpcode(AArch64::STRXui);
926e4c2305SElvina Yakubova   Inst.clear();
936e4c2305SElvina Yakubova   if (To == AArch64::SP) {
946e4c2305SElvina Yakubova     Inst.setOpcode(AArch64::STRXpre);
956e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(To));
966e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(From));
976e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(To));
986e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(-16));
996e4c2305SElvina Yakubova   } else {
1006e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(From));
1016e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(To));
1026e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(0));
1036e4c2305SElvina Yakubova   }
1046e4c2305SElvina Yakubova }
1056e4c2305SElvina Yakubova 
1066e4c2305SElvina Yakubova static void atomicAdd(MCInst &Inst, MCPhysReg RegTo, MCPhysReg RegCnt) {
1076e4c2305SElvina Yakubova   // NOTE: Supports only ARM with LSE extension
1086e4c2305SElvina Yakubova   Inst.setOpcode(AArch64::LDADDX);
1096e4c2305SElvina Yakubova   Inst.clear();
1106e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(AArch64::XZR));
1116e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(RegCnt));
1126e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(RegTo));
1136e4c2305SElvina Yakubova }
1146e4c2305SElvina Yakubova 
1156e4c2305SElvina Yakubova static void createMovz(MCInst &Inst, MCPhysReg Reg, uint64_t Imm) {
1166e4c2305SElvina Yakubova   assert(Imm <= UINT16_MAX && "Invalid Imm size");
1176e4c2305SElvina Yakubova   Inst.clear();
1186e4c2305SElvina Yakubova   Inst.setOpcode(AArch64::MOVZXi);
1196e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createReg(Reg));
1206e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createImm(Imm & 0xFFFF));
1216e4c2305SElvina Yakubova   Inst.addOperand(MCOperand::createImm(0));
1226e4c2305SElvina Yakubova }
1236e4c2305SElvina Yakubova 
1246e4c2305SElvina Yakubova static InstructionListType createIncMemory(MCPhysReg RegTo, MCPhysReg RegTmp) {
1256e4c2305SElvina Yakubova   InstructionListType Insts;
1266e4c2305SElvina Yakubova   Insts.emplace_back();
1276e4c2305SElvina Yakubova   createMovz(Insts.back(), RegTmp, 1);
1286e4c2305SElvina Yakubova   Insts.emplace_back();
1296e4c2305SElvina Yakubova   atomicAdd(Insts.back(), RegTo, RegTmp);
1306e4c2305SElvina Yakubova   return Insts;
1316e4c2305SElvina Yakubova }
132a34c753fSRafael Auler class AArch64MCPlusBuilder : public MCPlusBuilder {
133a34c753fSRafael Auler public:
1348fb83bf5SJob Noorman   using MCPlusBuilder::MCPlusBuilder;
135a34c753fSRafael Auler 
136ee428225SNicholas   MCPhysReg getStackPointer() const override { return AArch64::SP; }
137ad599c25SAlexey Moksyakov   MCPhysReg getFramePointer() const override { return AArch64::FP; }
138ee428225SNicholas 
139ad599c25SAlexey Moksyakov   bool isPush(const MCInst &Inst) const override {
140ad599c25SAlexey Moksyakov     return isStoreToStack(Inst);
141ad599c25SAlexey Moksyakov   };
142ee428225SNicholas 
143ad599c25SAlexey Moksyakov   bool isPop(const MCInst &Inst) const override {
144ad599c25SAlexey Moksyakov     return isLoadFromStack(Inst);
145ad599c25SAlexey Moksyakov   };
146ee428225SNicholas 
147ee428225SNicholas   void createCall(MCInst &Inst, const MCSymbol *Target,
148ee428225SNicholas                   MCContext *Ctx) override {
149ee428225SNicholas     createDirectCall(Inst, Target, Ctx, false);
150ee428225SNicholas   }
151ee428225SNicholas 
152ee428225SNicholas   bool convertTailCallToCall(MCInst &Inst) override {
153ee428225SNicholas     int NewOpcode;
154ee428225SNicholas     switch (Inst.getOpcode()) {
155ee428225SNicholas     default:
156ee428225SNicholas       return false;
157ee428225SNicholas     case AArch64::B:
158ee428225SNicholas       NewOpcode = AArch64::BL;
159ee428225SNicholas       break;
160ee428225SNicholas     case AArch64::BR:
161ee428225SNicholas       NewOpcode = AArch64::BLR;
162ee428225SNicholas       break;
163ee428225SNicholas     }
164ee428225SNicholas 
165ee428225SNicholas     Inst.setOpcode(NewOpcode);
166ee428225SNicholas     removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
167ee428225SNicholas     clearOffset(Inst);
168ee428225SNicholas     return true;
169ee428225SNicholas   }
170ee428225SNicholas 
171a34c753fSRafael Auler   bool equals(const MCTargetExpr &A, const MCTargetExpr &B,
172a34c753fSRafael Auler               CompFuncTy Comp) const override {
173a34c753fSRafael Auler     const auto &AArch64ExprA = cast<AArch64MCExpr>(A);
174a34c753fSRafael Auler     const auto &AArch64ExprB = cast<AArch64MCExpr>(B);
175a34c753fSRafael Auler     if (AArch64ExprA.getKind() != AArch64ExprB.getKind())
176a34c753fSRafael Auler       return false;
177a34c753fSRafael Auler 
178a34c753fSRafael Auler     return MCPlusBuilder::equals(*AArch64ExprA.getSubExpr(),
179a34c753fSRafael Auler                                  *AArch64ExprB.getSubExpr(), Comp);
180a34c753fSRafael Auler   }
181a34c753fSRafael Auler 
182dc1cf838SAmir Ayupov   bool shortenInstruction(MCInst &, const MCSubtargetInfo &) const override {
183dc1cf838SAmir Ayupov     return false;
184dc1cf838SAmir Ayupov   }
185a34c753fSRafael Auler 
186a34c753fSRafael Auler   bool isADRP(const MCInst &Inst) const override {
187a34c753fSRafael Auler     return Inst.getOpcode() == AArch64::ADRP;
188a34c753fSRafael Auler   }
189a34c753fSRafael Auler 
190a34c753fSRafael Auler   bool isADR(const MCInst &Inst) const override {
191a34c753fSRafael Auler     return Inst.getOpcode() == AArch64::ADR;
192a34c753fSRafael Auler   }
193a34c753fSRafael Auler 
19417ed8f29SVladislav Khmelevsky   bool isAddXri(const MCInst &Inst) const {
19517ed8f29SVladislav Khmelevsky     return Inst.getOpcode() == AArch64::ADDXri;
19617ed8f29SVladislav Khmelevsky   }
19717ed8f29SVladislav Khmelevsky 
198a34c753fSRafael Auler   void getADRReg(const MCInst &Inst, MCPhysReg &RegName) const override {
199a34c753fSRafael Auler     assert((isADR(Inst) || isADRP(Inst)) && "Not an ADR instruction");
200a34c753fSRafael Auler     assert(MCPlus::getNumPrimeOperands(Inst) != 0 &&
201a34c753fSRafael Auler            "No operands for ADR instruction");
202a34c753fSRafael Auler     assert(Inst.getOperand(0).isReg() &&
203a34c753fSRafael Auler            "Unexpected operand in ADR instruction");
204a34c753fSRafael Auler     RegName = Inst.getOperand(0).getReg();
205a34c753fSRafael Auler   }
206a34c753fSRafael Auler 
207a34c753fSRafael Auler   bool isTB(const MCInst &Inst) const {
208a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::TBNZW ||
209a34c753fSRafael Auler             Inst.getOpcode() == AArch64::TBNZX ||
210a34c753fSRafael Auler             Inst.getOpcode() == AArch64::TBZW ||
211a34c753fSRafael Auler             Inst.getOpcode() == AArch64::TBZX);
212a34c753fSRafael Auler   }
213a34c753fSRafael Auler 
214a34c753fSRafael Auler   bool isCB(const MCInst &Inst) const {
215a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::CBNZW ||
216a34c753fSRafael Auler             Inst.getOpcode() == AArch64::CBNZX ||
217a34c753fSRafael Auler             Inst.getOpcode() == AArch64::CBZW ||
218a34c753fSRafael Auler             Inst.getOpcode() == AArch64::CBZX);
219a34c753fSRafael Auler   }
220a34c753fSRafael Auler 
221a34c753fSRafael Auler   bool isMOVW(const MCInst &Inst) const {
222a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::MOVKWi ||
223a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVKXi ||
224a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVNWi ||
225a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVNXi ||
226a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVZXi ||
227a34c753fSRafael Auler             Inst.getOpcode() == AArch64::MOVZWi);
228a34c753fSRafael Auler   }
229a34c753fSRafael Auler 
230a34c753fSRafael Auler   bool isADD(const MCInst &Inst) const {
231a34c753fSRafael Auler     return (Inst.getOpcode() == AArch64::ADDSWri ||
232a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSWrr ||
233a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSWrs ||
234a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSWrx ||
235a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXri ||
236a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXrr ||
237a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXrs ||
238a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXrx ||
239a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDSXrx64 ||
240a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDWri ||
241a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDWrr ||
242a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDWrs ||
243a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDWrx ||
244a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXri ||
245a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXrr ||
246a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXrs ||
247a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXrx ||
248a34c753fSRafael Auler             Inst.getOpcode() == AArch64::ADDXrx64);
249a34c753fSRafael Auler   }
250a34c753fSRafael Auler 
251a34c753fSRafael Auler   bool isLDRB(const MCInst &Inst) const {
252ad599c25SAlexey Moksyakov     const unsigned opcode = Inst.getOpcode();
253ad599c25SAlexey Moksyakov     switch (opcode) {
254ad599c25SAlexey Moksyakov     case AArch64::LDRBpost:
255ad599c25SAlexey Moksyakov     case AArch64::LDRBBpost:
256ad599c25SAlexey Moksyakov     case AArch64::LDRBBpre:
257ad599c25SAlexey Moksyakov     case AArch64::LDRBBroW:
258ad599c25SAlexey Moksyakov     case AArch64::LDRBroW:
259ad599c25SAlexey Moksyakov     case AArch64::LDRBroX:
260ad599c25SAlexey Moksyakov     case AArch64::LDRBBroX:
261ad599c25SAlexey Moksyakov     case AArch64::LDRBBui:
262ad599c25SAlexey Moksyakov     case AArch64::LDRBui:
263ad599c25SAlexey Moksyakov     case AArch64::LDRBpre:
264ad599c25SAlexey Moksyakov     case AArch64::LDRSBWpost:
265ad599c25SAlexey Moksyakov     case AArch64::LDRSBWpre:
266ad599c25SAlexey Moksyakov     case AArch64::LDRSBWroW:
267ad599c25SAlexey Moksyakov     case AArch64::LDRSBWroX:
268ad599c25SAlexey Moksyakov     case AArch64::LDRSBWui:
269ad599c25SAlexey Moksyakov     case AArch64::LDRSBXpost:
270ad599c25SAlexey Moksyakov     case AArch64::LDRSBXpre:
271ad599c25SAlexey Moksyakov     case AArch64::LDRSBXroW:
272ad599c25SAlexey Moksyakov     case AArch64::LDRSBXroX:
273ad599c25SAlexey Moksyakov     case AArch64::LDRSBXui:
274ad599c25SAlexey Moksyakov     case AArch64::LDURBi:
275ad599c25SAlexey Moksyakov     case AArch64::LDURBBi:
276ad599c25SAlexey Moksyakov     case AArch64::LDURSBWi:
277ad599c25SAlexey Moksyakov     case AArch64::LDURSBXi:
278ad599c25SAlexey Moksyakov     case AArch64::LDTRBi:
279ad599c25SAlexey Moksyakov     case AArch64::LDTRSBWi:
280ad599c25SAlexey Moksyakov     case AArch64::LDTRSBXi:
281ad599c25SAlexey Moksyakov       return true;
282ad599c25SAlexey Moksyakov     default:
283ad599c25SAlexey Moksyakov       break;
284ad599c25SAlexey Moksyakov     }
285ad599c25SAlexey Moksyakov 
286ad599c25SAlexey Moksyakov     return false;
287a34c753fSRafael Auler   }
288a34c753fSRafael Auler 
289a34c753fSRafael Auler   bool isLDRH(const MCInst &Inst) const {
290ad599c25SAlexey Moksyakov     const unsigned opcode = Inst.getOpcode();
291ad599c25SAlexey Moksyakov     switch (opcode) {
292ad599c25SAlexey Moksyakov     case AArch64::LDRHpost:
293ad599c25SAlexey Moksyakov     case AArch64::LDRHHpost:
294ad599c25SAlexey Moksyakov     case AArch64::LDRHHpre:
295ad599c25SAlexey Moksyakov     case AArch64::LDRHroW:
296ad599c25SAlexey Moksyakov     case AArch64::LDRHHroW:
297ad599c25SAlexey Moksyakov     case AArch64::LDRHroX:
298ad599c25SAlexey Moksyakov     case AArch64::LDRHHroX:
299ad599c25SAlexey Moksyakov     case AArch64::LDRHHui:
300ad599c25SAlexey Moksyakov     case AArch64::LDRHui:
301ad599c25SAlexey Moksyakov     case AArch64::LDRHpre:
302ad599c25SAlexey Moksyakov     case AArch64::LDRSHWpost:
303ad599c25SAlexey Moksyakov     case AArch64::LDRSHWpre:
304ad599c25SAlexey Moksyakov     case AArch64::LDRSHWroW:
305ad599c25SAlexey Moksyakov     case AArch64::LDRSHWroX:
306ad599c25SAlexey Moksyakov     case AArch64::LDRSHWui:
307ad599c25SAlexey Moksyakov     case AArch64::LDRSHXpost:
308ad599c25SAlexey Moksyakov     case AArch64::LDRSHXpre:
309ad599c25SAlexey Moksyakov     case AArch64::LDRSHXroW:
310ad599c25SAlexey Moksyakov     case AArch64::LDRSHXroX:
311ad599c25SAlexey Moksyakov     case AArch64::LDRSHXui:
312ad599c25SAlexey Moksyakov     case AArch64::LDURHi:
313ad599c25SAlexey Moksyakov     case AArch64::LDURHHi:
314ad599c25SAlexey Moksyakov     case AArch64::LDURSHWi:
315ad599c25SAlexey Moksyakov     case AArch64::LDURSHXi:
316ad599c25SAlexey Moksyakov     case AArch64::LDTRHi:
317ad599c25SAlexey Moksyakov     case AArch64::LDTRSHWi:
318ad599c25SAlexey Moksyakov     case AArch64::LDTRSHXi:
319ad599c25SAlexey Moksyakov       return true;
320ad599c25SAlexey Moksyakov     default:
321ad599c25SAlexey Moksyakov       break;
322ad599c25SAlexey Moksyakov     }
323ad599c25SAlexey Moksyakov 
324ad599c25SAlexey Moksyakov     return false;
325a34c753fSRafael Auler   }
326a34c753fSRafael Auler 
327a34c753fSRafael Auler   bool isLDRW(const MCInst &Inst) const {
328ad599c25SAlexey Moksyakov     const unsigned opcode = Inst.getOpcode();
329ad599c25SAlexey Moksyakov     switch (opcode) {
330ad599c25SAlexey Moksyakov     case AArch64::LDRWpost:
331ad599c25SAlexey Moksyakov     case AArch64::LDRWpre:
332ad599c25SAlexey Moksyakov     case AArch64::LDRWroW:
333ad599c25SAlexey Moksyakov     case AArch64::LDRWroX:
334ad599c25SAlexey Moksyakov     case AArch64::LDRWui:
335ad599c25SAlexey Moksyakov     case AArch64::LDRWl:
336ad599c25SAlexey Moksyakov     case AArch64::LDRSWl:
337ad599c25SAlexey Moksyakov     case AArch64::LDURWi:
338ad599c25SAlexey Moksyakov     case AArch64::LDRSWpost:
339ad599c25SAlexey Moksyakov     case AArch64::LDRSWpre:
340ad599c25SAlexey Moksyakov     case AArch64::LDRSWroW:
341ad599c25SAlexey Moksyakov     case AArch64::LDRSWroX:
342ad599c25SAlexey Moksyakov     case AArch64::LDRSWui:
343ad599c25SAlexey Moksyakov     case AArch64::LDURSWi:
344ad599c25SAlexey Moksyakov     case AArch64::LDTRWi:
345ad599c25SAlexey Moksyakov     case AArch64::LDTRSWi:
346ad599c25SAlexey Moksyakov     case AArch64::LDPWi:
347ad599c25SAlexey Moksyakov     case AArch64::LDPWpost:
348ad599c25SAlexey Moksyakov     case AArch64::LDPWpre:
349ad599c25SAlexey Moksyakov     case AArch64::LDPSWi:
350ad599c25SAlexey Moksyakov     case AArch64::LDPSWpost:
351ad599c25SAlexey Moksyakov     case AArch64::LDPSWpre:
352ad599c25SAlexey Moksyakov     case AArch64::LDNPWi:
353ad599c25SAlexey Moksyakov       return true;
354ad599c25SAlexey Moksyakov     default:
355ad599c25SAlexey Moksyakov       break;
356ad599c25SAlexey Moksyakov     }
357ad599c25SAlexey Moksyakov 
358ad599c25SAlexey Moksyakov     return false;
359a34c753fSRafael Auler   }
360a34c753fSRafael Auler 
361a34c753fSRafael Auler   bool isLDRX(const MCInst &Inst) const {
362ad599c25SAlexey Moksyakov     const unsigned opcode = Inst.getOpcode();
363ad599c25SAlexey Moksyakov     switch (opcode) {
364ad599c25SAlexey Moksyakov     case AArch64::LDRXpost:
365ad599c25SAlexey Moksyakov     case AArch64::LDRXpre:
366ad599c25SAlexey Moksyakov     case AArch64::LDRXroW:
367ad599c25SAlexey Moksyakov     case AArch64::LDRXroX:
368ad599c25SAlexey Moksyakov     case AArch64::LDRXui:
369ad599c25SAlexey Moksyakov     case AArch64::LDRXl:
370ad599c25SAlexey Moksyakov     case AArch64::LDURXi:
371ad599c25SAlexey Moksyakov     case AArch64::LDTRXi:
372ad599c25SAlexey Moksyakov     case AArch64::LDNPXi:
373ad599c25SAlexey Moksyakov     case AArch64::LDPXi:
374ad599c25SAlexey Moksyakov     case AArch64::LDPXpost:
375ad599c25SAlexey Moksyakov     case AArch64::LDPXpre:
376ad599c25SAlexey Moksyakov       return true;
377ad599c25SAlexey Moksyakov     default:
378ad599c25SAlexey Moksyakov       break;
379ad599c25SAlexey Moksyakov     }
380ad599c25SAlexey Moksyakov 
381ad599c25SAlexey Moksyakov     return false;
382ad599c25SAlexey Moksyakov   }
383ad599c25SAlexey Moksyakov 
384ad599c25SAlexey Moksyakov   bool isLDRS(const MCInst &Inst) const {
385ad599c25SAlexey Moksyakov     const unsigned opcode = Inst.getOpcode();
386ad599c25SAlexey Moksyakov     switch (opcode) {
387ad599c25SAlexey Moksyakov     case AArch64::LDRSl:
388ad599c25SAlexey Moksyakov     case AArch64::LDRSui:
389ad599c25SAlexey Moksyakov     case AArch64::LDRSroW:
390ad599c25SAlexey Moksyakov     case AArch64::LDRSroX:
391ad599c25SAlexey Moksyakov     case AArch64::LDURSi:
392ad599c25SAlexey Moksyakov     case AArch64::LDPSi:
393ad599c25SAlexey Moksyakov     case AArch64::LDNPSi:
394ad599c25SAlexey Moksyakov     case AArch64::LDRSpre:
395ad599c25SAlexey Moksyakov     case AArch64::LDRSpost:
396ad599c25SAlexey Moksyakov     case AArch64::LDPSpost:
397ad599c25SAlexey Moksyakov     case AArch64::LDPSpre:
398ad599c25SAlexey Moksyakov       return true;
399ad599c25SAlexey Moksyakov     default:
400ad599c25SAlexey Moksyakov       break;
401ad599c25SAlexey Moksyakov     }
402ad599c25SAlexey Moksyakov 
403ad599c25SAlexey Moksyakov     return false;
404ad599c25SAlexey Moksyakov   }
405ad599c25SAlexey Moksyakov 
406ad599c25SAlexey Moksyakov   bool isLDRD(const MCInst &Inst) const {
407ad599c25SAlexey Moksyakov     const unsigned opcode = Inst.getOpcode();
408ad599c25SAlexey Moksyakov     switch (opcode) {
409ad599c25SAlexey Moksyakov     case AArch64::LDRDl:
410ad599c25SAlexey Moksyakov     case AArch64::LDRDui:
411ad599c25SAlexey Moksyakov     case AArch64::LDRDpre:
412ad599c25SAlexey Moksyakov     case AArch64::LDRDpost:
413ad599c25SAlexey Moksyakov     case AArch64::LDRDroW:
414ad599c25SAlexey Moksyakov     case AArch64::LDRDroX:
415ad599c25SAlexey Moksyakov     case AArch64::LDURDi:
416ad599c25SAlexey Moksyakov     case AArch64::LDPDi:
417ad599c25SAlexey Moksyakov     case AArch64::LDNPDi:
418ad599c25SAlexey Moksyakov     case AArch64::LDPDpost:
419ad599c25SAlexey Moksyakov     case AArch64::LDPDpre:
420ad599c25SAlexey Moksyakov       return true;
421ad599c25SAlexey Moksyakov     default:
422ad599c25SAlexey Moksyakov       break;
423ad599c25SAlexey Moksyakov     }
424ad599c25SAlexey Moksyakov 
425ad599c25SAlexey Moksyakov     return false;
426ad599c25SAlexey Moksyakov   }
427ad599c25SAlexey Moksyakov 
428ad599c25SAlexey Moksyakov   bool isLDRQ(const MCInst &Inst) const {
429ad599c25SAlexey Moksyakov     const unsigned opcode = Inst.getOpcode();
430ad599c25SAlexey Moksyakov     switch (opcode) {
431ad599c25SAlexey Moksyakov     case AArch64::LDRQui:
432ad599c25SAlexey Moksyakov     case AArch64::LDRQl:
433ad599c25SAlexey Moksyakov     case AArch64::LDRQpre:
434ad599c25SAlexey Moksyakov     case AArch64::LDRQpost:
435ad599c25SAlexey Moksyakov     case AArch64::LDRQroW:
436ad599c25SAlexey Moksyakov     case AArch64::LDRQroX:
437ad599c25SAlexey Moksyakov     case AArch64::LDURQi:
438ad599c25SAlexey Moksyakov     case AArch64::LDPQi:
439ad599c25SAlexey Moksyakov     case AArch64::LDNPQi:
440ad599c25SAlexey Moksyakov     case AArch64::LDPQpost:
441ad599c25SAlexey Moksyakov     case AArch64::LDPQpre:
442ad599c25SAlexey Moksyakov       return true;
443ad599c25SAlexey Moksyakov     default:
444ad599c25SAlexey Moksyakov       break;
445ad599c25SAlexey Moksyakov     }
446ad599c25SAlexey Moksyakov 
447ad599c25SAlexey Moksyakov     return false;
448a34c753fSRafael Auler   }
449a34c753fSRafael Auler 
450eafe4ee2SJob Noorman   bool mayLoad(const MCInst &Inst) const override {
451ad599c25SAlexey Moksyakov     return isLDRB(Inst) || isLDRH(Inst) || isLDRW(Inst) || isLDRX(Inst) ||
452ad599c25SAlexey Moksyakov            isLDRQ(Inst) || isLDRD(Inst) || isLDRS(Inst);
453a34c753fSRafael Auler   }
454a34c753fSRafael Auler 
455b98e6a5cSElvina Yakubova   bool isAArch64ExclusiveLoad(const MCInst &Inst) const override {
456846eb767SVladislav Khmelevsky     return (Inst.getOpcode() == AArch64::LDXPX ||
457846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDXPW ||
458846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDXRX ||
459846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDXRW ||
460846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDXRH ||
461846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDXRB ||
462846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDAXPX ||
463846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDAXPW ||
464846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDAXRX ||
465846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDAXRW ||
466846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::LDAXRH ||
467b98e6a5cSElvina Yakubova             Inst.getOpcode() == AArch64::LDAXRB);
468b98e6a5cSElvina Yakubova   }
469b98e6a5cSElvina Yakubova 
470b98e6a5cSElvina Yakubova   bool isAArch64ExclusiveStore(const MCInst &Inst) const override {
471b98e6a5cSElvina Yakubova     return (Inst.getOpcode() == AArch64::STXPX ||
472b98e6a5cSElvina Yakubova             Inst.getOpcode() == AArch64::STXPW ||
473b98e6a5cSElvina Yakubova             Inst.getOpcode() == AArch64::STXRX ||
474b98e6a5cSElvina Yakubova             Inst.getOpcode() == AArch64::STXRW ||
475b98e6a5cSElvina Yakubova             Inst.getOpcode() == AArch64::STXRH ||
476b98e6a5cSElvina Yakubova             Inst.getOpcode() == AArch64::STXRB ||
477846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STLXPX ||
478846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STLXPW ||
479846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STLXRX ||
480846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STLXRW ||
481846eb767SVladislav Khmelevsky             Inst.getOpcode() == AArch64::STLXRH ||
482b98e6a5cSElvina Yakubova             Inst.getOpcode() == AArch64::STLXRB);
483b98e6a5cSElvina Yakubova   }
484b98e6a5cSElvina Yakubova 
485b98e6a5cSElvina Yakubova   bool isAArch64ExclusiveClear(const MCInst &Inst) const override {
486b98e6a5cSElvina Yakubova     return (Inst.getOpcode() == AArch64::CLREX);
487846eb767SVladislav Khmelevsky   }
488846eb767SVladislav Khmelevsky 
489a34c753fSRafael Auler   bool isLoadFromStack(const MCInst &Inst) const {
490eafe4ee2SJob Noorman     if (!mayLoad(Inst))
491a34c753fSRafael Auler       return false;
492b6f07d3aSAmir Ayupov     for (const MCOperand &Operand : useOperands(Inst)) {
493a34c753fSRafael Auler       if (!Operand.isReg())
494a34c753fSRafael Auler         continue;
495a34c753fSRafael Auler       unsigned Reg = Operand.getReg();
496ad599c25SAlexey Moksyakov       if (Reg == AArch64::SP || Reg == AArch64::WSP)
497a34c753fSRafael Auler         return true;
498a34c753fSRafael Auler     }
499a34c753fSRafael Auler     return false;
500a34c753fSRafael Auler   }
501a34c753fSRafael Auler 
502a34c753fSRafael Auler   bool isRegToRegMove(const MCInst &Inst, MCPhysReg &From,
503a34c753fSRafael Auler                       MCPhysReg &To) const override {
504f20af737Seleviant     if (Inst.getOpcode() == AArch64::FMOVDXr) {
505f20af737Seleviant       From = Inst.getOperand(1).getReg();
506f20af737Seleviant       To = Inst.getOperand(0).getReg();
507f20af737Seleviant       return true;
508f20af737Seleviant     }
509f20af737Seleviant 
510a34c753fSRafael Auler     if (Inst.getOpcode() != AArch64::ORRXrs)
511a34c753fSRafael Auler       return false;
512a34c753fSRafael Auler     if (Inst.getOperand(1).getReg() != AArch64::XZR)
513a34c753fSRafael Auler       return false;
514a34c753fSRafael Auler     if (Inst.getOperand(3).getImm() != 0)
515a34c753fSRafael Auler       return false;
516a34c753fSRafael Auler     From = Inst.getOperand(2).getReg();
517a34c753fSRafael Auler     To = Inst.getOperand(0).getReg();
518a34c753fSRafael Auler     return true;
519a34c753fSRafael Auler   }
520a34c753fSRafael Auler 
521a34c753fSRafael Auler   bool isIndirectCall(const MCInst &Inst) const override {
522a34c753fSRafael Auler     return Inst.getOpcode() == AArch64::BLR;
523a34c753fSRafael Auler   }
524a34c753fSRafael Auler 
5256e4c2305SElvina Yakubova   MCPhysReg getSpRegister(int Size) const {
5266e4c2305SElvina Yakubova     switch (Size) {
5276e4c2305SElvina Yakubova     case 4:
5286e4c2305SElvina Yakubova       return AArch64::WSP;
5296e4c2305SElvina Yakubova     case 8:
5306e4c2305SElvina Yakubova       return AArch64::SP;
5316e4c2305SElvina Yakubova     default:
5326e4c2305SElvina Yakubova       llvm_unreachable("Unexpected size");
5336e4c2305SElvina Yakubova     }
5346e4c2305SElvina Yakubova   }
5356e4c2305SElvina Yakubova 
5366e4c2305SElvina Yakubova   MCPhysReg getIntArgRegister(unsigned ArgNo) const override {
5376e4c2305SElvina Yakubova     switch (ArgNo) {
5386e4c2305SElvina Yakubova     case 0:
5396e4c2305SElvina Yakubova       return AArch64::X0;
5406e4c2305SElvina Yakubova     case 1:
5416e4c2305SElvina Yakubova       return AArch64::X1;
5426e4c2305SElvina Yakubova     case 2:
5436e4c2305SElvina Yakubova       return AArch64::X2;
5446e4c2305SElvina Yakubova     case 3:
5456e4c2305SElvina Yakubova       return AArch64::X3;
5466e4c2305SElvina Yakubova     case 4:
5476e4c2305SElvina Yakubova       return AArch64::X4;
5486e4c2305SElvina Yakubova     case 5:
5496e4c2305SElvina Yakubova       return AArch64::X5;
5506e4c2305SElvina Yakubova     case 6:
5516e4c2305SElvina Yakubova       return AArch64::X6;
5526e4c2305SElvina Yakubova     case 7:
5536e4c2305SElvina Yakubova       return AArch64::X7;
5546e4c2305SElvina Yakubova     default:
5556e4c2305SElvina Yakubova       return getNoRegister();
5566e4c2305SElvina Yakubova     }
5576e4c2305SElvina Yakubova   }
5586e4c2305SElvina Yakubova 
559a34c753fSRafael Auler   bool hasPCRelOperand(const MCInst &Inst) const override {
560a34c753fSRafael Auler     // ADRP is blacklisted and is an exception. Even though it has a
561a34c753fSRafael Auler     // PC-relative operand, this operand is not a complete symbol reference
562a34c753fSRafael Auler     // and BOLT shouldn't try to process it in isolation.
563a34c753fSRafael Auler     if (isADRP(Inst))
564a34c753fSRafael Auler       return false;
565a34c753fSRafael Auler 
566a34c753fSRafael Auler     if (isADR(Inst))
567a34c753fSRafael Auler       return true;
568a34c753fSRafael Auler 
569a34c753fSRafael Auler     // Look for literal addressing mode (see C1-143 ARM DDI 0487B.a)
570a34c753fSRafael Auler     const MCInstrDesc &MCII = Info->get(Inst.getOpcode());
57189ceb779SAmir Ayupov     for (unsigned I = 0, E = MCII.getNumOperands(); I != E; ++I)
572fbb00337SJay Foad       if (MCII.operands()[I].OperandType == MCOI::OPERAND_PCREL)
573a34c753fSRafael Auler         return true;
57489ceb779SAmir Ayupov 
575a34c753fSRafael Auler     return false;
576a34c753fSRafael Auler   }
577a34c753fSRafael Auler 
578a34c753fSRafael Auler   bool evaluateADR(const MCInst &Inst, int64_t &Imm,
579a34c753fSRafael Auler                    const MCExpr **DispExpr) const {
580a34c753fSRafael Auler     assert((isADR(Inst) || isADRP(Inst)) && "Not an ADR instruction");
581a34c753fSRafael Auler 
582a34c753fSRafael Auler     const MCOperand &Label = Inst.getOperand(1);
583a34c753fSRafael Auler     if (!Label.isImm()) {
584a34c753fSRafael Auler       assert(Label.isExpr() && "Unexpected ADR operand");
585a34c753fSRafael Auler       assert(DispExpr && "DispExpr must be set");
586a34c753fSRafael Auler       *DispExpr = Label.getExpr();
587a34c753fSRafael Auler       return false;
588a34c753fSRafael Auler     }
589a34c753fSRafael Auler 
590a34c753fSRafael Auler     if (Inst.getOpcode() == AArch64::ADR) {
591a34c753fSRafael Auler       Imm = Label.getImm();
592a34c753fSRafael Auler       return true;
593a34c753fSRafael Auler     }
594a34c753fSRafael Auler     Imm = Label.getImm() << 12;
595a34c753fSRafael Auler     return true;
596a34c753fSRafael Auler   }
597a34c753fSRafael Auler 
59840c2e0faSMaksim Panchenko   bool evaluateAArch64MemoryOperand(const MCInst &Inst, int64_t &DispImm,
59940c2e0faSMaksim Panchenko                                     const MCExpr **DispExpr = nullptr) const {
600a34c753fSRafael Auler     if (isADR(Inst) || isADRP(Inst))
601a34c753fSRafael Auler       return evaluateADR(Inst, DispImm, DispExpr);
602a34c753fSRafael Auler 
603a34c753fSRafael Auler     // Literal addressing mode
604a34c753fSRafael Auler     const MCInstrDesc &MCII = Info->get(Inst.getOpcode());
605a34c753fSRafael Auler     for (unsigned I = 0, E = MCII.getNumOperands(); I != E; ++I) {
606fbb00337SJay Foad       if (MCII.operands()[I].OperandType != MCOI::OPERAND_PCREL)
607a34c753fSRafael Auler         continue;
608a34c753fSRafael Auler 
609a34c753fSRafael Auler       if (!Inst.getOperand(I).isImm()) {
610a34c753fSRafael Auler         assert(Inst.getOperand(I).isExpr() && "Unexpected PCREL operand");
611a34c753fSRafael Auler         assert(DispExpr && "DispExpr must be set");
612a34c753fSRafael Auler         *DispExpr = Inst.getOperand(I).getExpr();
613a34c753fSRafael Auler         return true;
614a34c753fSRafael Auler       }
615a34c753fSRafael Auler 
616df3f1e2fSJob Noorman       DispImm = Inst.getOperand(I).getImm() * 4;
617a34c753fSRafael Auler       return true;
618a34c753fSRafael Auler     }
619a34c753fSRafael Auler     return false;
620a34c753fSRafael Auler   }
621a34c753fSRafael Auler 
622a34c753fSRafael Auler   bool evaluateMemOperandTarget(const MCInst &Inst, uint64_t &Target,
623a34c753fSRafael Auler                                 uint64_t Address,
624a34c753fSRafael Auler                                 uint64_t Size) const override {
625a34c753fSRafael Auler     int64_t DispValue;
626a34c753fSRafael Auler     const MCExpr *DispExpr = nullptr;
627a34c753fSRafael Auler     if (!evaluateAArch64MemoryOperand(Inst, DispValue, &DispExpr))
628a34c753fSRafael Auler       return false;
629a34c753fSRafael Auler 
630a34c753fSRafael Auler     // Make sure it's a well-formed addressing we can statically evaluate.
631a34c753fSRafael Auler     if (DispExpr)
632a34c753fSRafael Auler       return false;
633a34c753fSRafael Auler 
634a34c753fSRafael Auler     Target = DispValue;
635a34c753fSRafael Auler     if (Inst.getOpcode() == AArch64::ADRP)
636a34c753fSRafael Auler       Target += Address & ~0xFFFULL;
637a34c753fSRafael Auler     else
638a34c753fSRafael Auler       Target += Address;
639a34c753fSRafael Auler     return true;
640a34c753fSRafael Auler   }
641a34c753fSRafael Auler 
6428d1fc45dSRafael Auler   MCInst::iterator getMemOperandDisp(MCInst &Inst) const override {
643a34c753fSRafael Auler     MCInst::iterator OI = Inst.begin();
644a34c753fSRafael Auler     if (isADR(Inst) || isADRP(Inst)) {
645a34c753fSRafael Auler       assert(MCPlus::getNumPrimeOperands(Inst) >= 2 &&
646a34c753fSRafael Auler              "Unexpected number of operands");
6478d1fc45dSRafael Auler       return ++OI;
6488d1fc45dSRafael Auler     }
649a34c753fSRafael Auler     const MCInstrDesc &MCII = Info->get(Inst.getOpcode());
650a34c753fSRafael Auler     for (unsigned I = 0, E = MCII.getNumOperands(); I != E; ++I) {
651fbb00337SJay Foad       if (MCII.operands()[I].OperandType == MCOI::OPERAND_PCREL)
652a34c753fSRafael Auler         break;
653a34c753fSRafael Auler       ++OI;
654a34c753fSRafael Auler     }
655a34c753fSRafael Auler     assert(OI != Inst.end() && "Literal operand not found");
6568d1fc45dSRafael Auler     return OI;
657a34c753fSRafael Auler   }
6588d1fc45dSRafael Auler 
6598d1fc45dSRafael Auler   bool replaceMemOperandDisp(MCInst &Inst, MCOperand Operand) const override {
6608d1fc45dSRafael Auler     MCInst::iterator OI = getMemOperandDisp(Inst);
661a34c753fSRafael Auler     *OI = Operand;
662a34c753fSRafael Auler     return true;
663a34c753fSRafael Auler   }
664a34c753fSRafael Auler 
6652d902d0fSKepontry   void getCalleeSavedRegs(BitVector &Regs) const override {
6662d902d0fSKepontry     Regs |= getAliases(AArch64::X18);
6672d902d0fSKepontry     Regs |= getAliases(AArch64::X19);
6682d902d0fSKepontry     Regs |= getAliases(AArch64::X20);
6692d902d0fSKepontry     Regs |= getAliases(AArch64::X21);
6702d902d0fSKepontry     Regs |= getAliases(AArch64::X22);
6712d902d0fSKepontry     Regs |= getAliases(AArch64::X23);
6722d902d0fSKepontry     Regs |= getAliases(AArch64::X24);
6732d902d0fSKepontry     Regs |= getAliases(AArch64::X25);
6742d902d0fSKepontry     Regs |= getAliases(AArch64::X26);
6752d902d0fSKepontry     Regs |= getAliases(AArch64::X27);
6762d902d0fSKepontry     Regs |= getAliases(AArch64::X28);
6772d902d0fSKepontry     Regs |= getAliases(AArch64::LR);
6782d902d0fSKepontry     Regs |= getAliases(AArch64::FP);
6792d902d0fSKepontry   }
6802d902d0fSKepontry 
681a34c753fSRafael Auler   const MCExpr *getTargetExprFor(MCInst &Inst, const MCExpr *Expr,
682a34c753fSRafael Auler                                  MCContext &Ctx,
683a34c753fSRafael Auler                                  uint64_t RelType) const override {
684a34c753fSRafael Auler 
685a34c753fSRafael Auler     if (isADR(Inst) || RelType == ELF::R_AARCH64_ADR_PREL_LO21 ||
686a34c753fSRafael Auler         RelType == ELF::R_AARCH64_TLSDESC_ADR_PREL21) {
687a34c753fSRafael Auler       return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS, Ctx);
688a34c753fSRafael Auler     } else if (isADRP(Inst) || RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21 ||
689a34c753fSRafael Auler                RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21_NC ||
690a34c753fSRafael Auler                RelType == ELF::R_AARCH64_TLSDESC_ADR_PAGE21 ||
691a34c753fSRafael Auler                RelType == ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
692a34c753fSRafael Auler                RelType == ELF::R_AARCH64_ADR_GOT_PAGE) {
693a34c753fSRafael Auler       // Never emit a GOT reloc, we handled this in
694a34c753fSRafael Auler       // RewriteInstance::readRelocations().
695a34c753fSRafael Auler       return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_PAGE, Ctx);
696a34c753fSRafael Auler     } else {
697a34c753fSRafael Auler       switch (RelType) {
698a34c753fSRafael Auler       case ELF::R_AARCH64_ADD_ABS_LO12_NC:
699a34c753fSRafael Auler       case ELF::R_AARCH64_LD64_GOT_LO12_NC:
700a34c753fSRafael Auler       case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
701a34c753fSRafael Auler       case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
702a34c753fSRafael Auler       case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
703a34c753fSRafael Auler       case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
704a34c753fSRafael Auler       case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
705a34c753fSRafael Auler       case ELF::R_AARCH64_TLSDESC_ADD_LO12:
706a34c753fSRafael Auler       case ELF::R_AARCH64_TLSDESC_LD64_LO12:
707a34c753fSRafael Auler       case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
708a34c753fSRafael Auler       case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
709a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_LO12, Ctx);
710a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G3:
711a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G3, Ctx);
712a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G2:
713a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G2_NC:
714a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G2_NC, Ctx);
715a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G1:
716a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G1_NC:
717a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G1_NC, Ctx);
718a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G0:
719a34c753fSRafael Auler       case ELF::R_AARCH64_MOVW_UABS_G0_NC:
720a34c753fSRafael Auler         return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G0_NC, Ctx);
721a34c753fSRafael Auler       default:
722a34c753fSRafael Auler         break;
723a34c753fSRafael Auler       }
724a34c753fSRafael Auler     }
725a34c753fSRafael Auler     return Expr;
726a34c753fSRafael Auler   }
727a34c753fSRafael Auler 
728a34c753fSRafael Auler   bool getSymbolRefOperandNum(const MCInst &Inst, unsigned &OpNum) const {
729a34c753fSRafael Auler     if (OpNum >= MCPlus::getNumPrimeOperands(Inst))
730a34c753fSRafael Auler       return false;
731a34c753fSRafael Auler 
732a34c753fSRafael Auler     // Auto-select correct operand number
733a34c753fSRafael Auler     if (OpNum == 0) {
73417ed8f29SVladislav Khmelevsky       if (isConditionalBranch(Inst) || isADR(Inst) || isADRP(Inst) ||
73517ed8f29SVladislav Khmelevsky           isMOVW(Inst))
736a34c753fSRafael Auler         OpNum = 1;
73717ed8f29SVladislav Khmelevsky       if (isTB(Inst) || isAddXri(Inst))
738a34c753fSRafael Auler         OpNum = 2;
739a34c753fSRafael Auler     }
740a34c753fSRafael Auler 
741a34c753fSRafael Auler     return true;
742a34c753fSRafael Auler   }
743a34c753fSRafael Auler 
744a34c753fSRafael Auler   const MCSymbol *getTargetSymbol(const MCExpr *Expr) const override {
745a34c753fSRafael Auler     auto *AArchExpr = dyn_cast<AArch64MCExpr>(Expr);
746a34c753fSRafael Auler     if (AArchExpr && AArchExpr->getSubExpr())
747a34c753fSRafael Auler       return getTargetSymbol(AArchExpr->getSubExpr());
748a34c753fSRafael Auler 
749a34c753fSRafael Auler     auto *BinExpr = dyn_cast<MCBinaryExpr>(Expr);
750a34c753fSRafael Auler     if (BinExpr)
751a34c753fSRafael Auler       return getTargetSymbol(BinExpr->getLHS());
752a34c753fSRafael Auler 
753a34c753fSRafael Auler     auto *SymExpr = dyn_cast<MCSymbolRefExpr>(Expr);
754a34c753fSRafael Auler     if (SymExpr && SymExpr->getKind() == MCSymbolRefExpr::VK_None)
755a34c753fSRafael Auler       return &SymExpr->getSymbol();
756a34c753fSRafael Auler 
757a34c753fSRafael Auler     return nullptr;
758a34c753fSRafael Auler   }
759a34c753fSRafael Auler 
760a34c753fSRafael Auler   const MCSymbol *getTargetSymbol(const MCInst &Inst,
761a34c753fSRafael Auler                                   unsigned OpNum = 0) const override {
762a34c753fSRafael Auler     if (!getSymbolRefOperandNum(Inst, OpNum))
763a34c753fSRafael Auler       return nullptr;
764a34c753fSRafael Auler 
765a34c753fSRafael Auler     const MCOperand &Op = Inst.getOperand(OpNum);
766a34c753fSRafael Auler     if (!Op.isExpr())
767a34c753fSRafael Auler       return nullptr;
768a34c753fSRafael Auler 
769a34c753fSRafael Auler     return getTargetSymbol(Op.getExpr());
770a34c753fSRafael Auler   }
771a34c753fSRafael Auler 
772a34c753fSRafael Auler   int64_t getTargetAddend(const MCExpr *Expr) const override {
773a34c753fSRafael Auler     auto *AArchExpr = dyn_cast<AArch64MCExpr>(Expr);
774a34c753fSRafael Auler     if (AArchExpr && AArchExpr->getSubExpr())
775a34c753fSRafael Auler       return getTargetAddend(AArchExpr->getSubExpr());
776a34c753fSRafael Auler 
777a34c753fSRafael Auler     auto *BinExpr = dyn_cast<MCBinaryExpr>(Expr);
778a34c753fSRafael Auler     if (BinExpr && BinExpr->getOpcode() == MCBinaryExpr::Add)
779a34c753fSRafael Auler       return getTargetAddend(BinExpr->getRHS());
780a34c753fSRafael Auler 
781a34c753fSRafael Auler     auto *ConstExpr = dyn_cast<MCConstantExpr>(Expr);
782a34c753fSRafael Auler     if (ConstExpr)
783a34c753fSRafael Auler       return ConstExpr->getValue();
784a34c753fSRafael Auler 
785a34c753fSRafael Auler     return 0;
786a34c753fSRafael Auler   }
787a34c753fSRafael Auler 
788a34c753fSRafael Auler   int64_t getTargetAddend(const MCInst &Inst,
789a34c753fSRafael Auler                           unsigned OpNum = 0) const override {
790a34c753fSRafael Auler     if (!getSymbolRefOperandNum(Inst, OpNum))
791a34c753fSRafael Auler       return 0;
792a34c753fSRafael Auler 
793a34c753fSRafael Auler     const MCOperand &Op = Inst.getOperand(OpNum);
794a34c753fSRafael Auler     if (!Op.isExpr())
795a34c753fSRafael Auler       return 0;
796a34c753fSRafael Auler 
797a34c753fSRafael Auler     return getTargetAddend(Op.getExpr());
798a34c753fSRafael Auler   }
799a34c753fSRafael Auler 
8003fefb3c5SNathan Sidwell   void replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,
801a34c753fSRafael Auler                            MCContext *Ctx) const override {
802a34c753fSRafael Auler     assert((isCall(Inst) || isBranch(Inst)) && !isIndirectBranch(Inst) &&
803a34c753fSRafael Auler            "Invalid instruction");
804a34c753fSRafael Auler     assert(MCPlus::getNumPrimeOperands(Inst) >= 1 &&
805a34c753fSRafael Auler            "Invalid number of operands");
806a34c753fSRafael Auler     MCInst::iterator OI = Inst.begin();
807a34c753fSRafael Auler 
808a34c753fSRafael Auler     if (isConditionalBranch(Inst)) {
809a34c753fSRafael Auler       assert(MCPlus::getNumPrimeOperands(Inst) >= 2 &&
810a34c753fSRafael Auler              "Invalid number of operands");
811a34c753fSRafael Auler       ++OI;
812a34c753fSRafael Auler     }
813a34c753fSRafael Auler 
814a34c753fSRafael Auler     if (isTB(Inst)) {
815a34c753fSRafael Auler       assert(MCPlus::getNumPrimeOperands(Inst) >= 3 &&
816a34c753fSRafael Auler              "Invalid number of operands");
817a34c753fSRafael Auler       OI = Inst.begin() + 2;
818a34c753fSRafael Auler     }
819a34c753fSRafael Auler 
820a34c753fSRafael Auler     *OI = MCOperand::createExpr(
821a34c753fSRafael Auler         MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx));
822a34c753fSRafael Auler   }
823a34c753fSRafael Auler 
824a34c753fSRafael Auler   /// Matches indirect branch patterns in AArch64 related to a jump table (JT),
825a34c753fSRafael Auler   /// helping us to build the complete CFG. A typical indirect branch to
826a34c753fSRafael Auler   /// a jump table entry in AArch64 looks like the following:
827a34c753fSRafael Auler   ///
828a34c753fSRafael Auler   ///   adrp    x1, #-7585792           # Get JT Page location
829a34c753fSRafael Auler   ///   add     x1, x1, #692            # Complement with JT Page offset
830a34c753fSRafael Auler   ///   ldrh    w0, [x1, w0, uxtw #1]   # Loads JT entry
831a34c753fSRafael Auler   ///   adr     x1, #12                 # Get PC + 12 (end of this BB) used next
832a34c753fSRafael Auler   ///   add     x0, x1, w0, sxth #2     # Finish building branch target
833a34c753fSRafael Auler   ///                                   # (entries in JT are relative to the end
834a34c753fSRafael Auler   ///                                   #  of this BB)
835a34c753fSRafael Auler   ///   br      x0                      # Indirect jump instruction
836a34c753fSRafael Auler   ///
837*1b4bd4e1SMaksim Panchenko   /// Return true on successful jump table instruction sequence match, false
838*1b4bd4e1SMaksim Panchenko   /// otherwise.
839a34c753fSRafael Auler   bool analyzeIndirectBranchFragment(
840a34c753fSRafael Auler       const MCInst &Inst,
841a34c753fSRafael Auler       DenseMap<const MCInst *, SmallVector<MCInst *, 4>> &UDChain,
842a34c753fSRafael Auler       const MCExpr *&JumpTable, int64_t &Offset, int64_t &ScaleValue,
843a34c753fSRafael Auler       MCInst *&PCRelBase) const {
844a34c753fSRafael Auler     // Expect AArch64 BR
845a34c753fSRafael Auler     assert(Inst.getOpcode() == AArch64::BR && "Unexpected opcode");
846a34c753fSRafael Auler 
847*1b4bd4e1SMaksim Panchenko     JumpTable = nullptr;
848*1b4bd4e1SMaksim Panchenko 
849a34c753fSRafael Auler     // Match the indirect branch pattern for aarch64
850a34c753fSRafael Auler     SmallVector<MCInst *, 4> &UsesRoot = UDChain[&Inst];
85189ceb779SAmir Ayupov     if (UsesRoot.size() == 0 || UsesRoot[0] == nullptr)
852a34c753fSRafael Auler       return false;
85389ceb779SAmir Ayupov 
854a34c753fSRafael Auler     const MCInst *DefAdd = UsesRoot[0];
855a34c753fSRafael Auler 
856a34c753fSRafael Auler     // Now we match an ADD
857a34c753fSRafael Auler     if (!isADD(*DefAdd)) {
858a34c753fSRafael Auler       // If the address is not broken up in two parts, this is not branching
859a34c753fSRafael Auler       // according to a jump table entry. Fail.
860a34c753fSRafael Auler       return false;
861a34c753fSRafael Auler     }
862a34c753fSRafael Auler     if (DefAdd->getOpcode() == AArch64::ADDXri) {
863a34c753fSRafael Auler       // This can happen when there is no offset, but a direct jump that was
864a34c753fSRafael Auler       // transformed into an indirect one  (indirect tail call) :
865a34c753fSRafael Auler       //   ADRP   x2, Perl_re_compiler
866a34c753fSRafael Auler       //   ADD    x2, x2, :lo12:Perl_re_compiler
867a34c753fSRafael Auler       //   BR     x2
868a34c753fSRafael Auler       return false;
869a34c753fSRafael Auler     }
870a34c753fSRafael Auler     if (DefAdd->getOpcode() == AArch64::ADDXrs) {
871a34c753fSRafael Auler       // Covers the less common pattern where JT entries are relative to
872a34c753fSRafael Auler       // the JT itself (like x86). Seems less efficient since we can't
873a34c753fSRafael Auler       // assume the JT is aligned at 4B boundary and thus drop 2 bits from
874a34c753fSRafael Auler       // JT values.
875a34c753fSRafael Auler       // cde264:
876a34c753fSRafael Auler       //    adrp    x12, #21544960  ; 216a000
877a34c753fSRafael Auler       //    add     x12, x12, #1696 ; 216a6a0  (JT object in .rodata)
878a34c753fSRafael Auler       //    ldrsw   x8, [x12, x8, lsl #2]   --> loads e.g. 0xfeb73bd8
879a34c753fSRafael Auler       //  * add     x8, x8, x12   --> = cde278, next block
880a34c753fSRafael Auler       //    br      x8
881a34c753fSRafael Auler       // cde278:
882a34c753fSRafael Auler       //
883a34c753fSRafael Auler       // Parsed as ADDXrs reg:x8 reg:x8 reg:x12 imm:0
884a34c753fSRafael Auler       return false;
885a34c753fSRafael Auler     }
886*1b4bd4e1SMaksim Panchenko     if (DefAdd->getOpcode() != AArch64::ADDXrx)
887*1b4bd4e1SMaksim Panchenko       return false;
888a34c753fSRafael Auler 
889a34c753fSRafael Auler     // Validate ADD operands
890a34c753fSRafael Auler     int64_t OperandExtension = DefAdd->getOperand(3).getImm();
891a34c753fSRafael Auler     unsigned ShiftVal = AArch64_AM::getArithShiftValue(OperandExtension);
892a34c753fSRafael Auler     AArch64_AM::ShiftExtendType ExtendType =
893a34c753fSRafael Auler         AArch64_AM::getArithExtendType(OperandExtension);
894e2cee2c1SÁdám Kallai     if (ShiftVal != 2) {
895e2cee2c1SÁdám Kallai       // TODO: Handle the patten where ShiftVal != 2.
896e2cee2c1SÁdám Kallai       // The following code sequence below has no shift amount,
897e2cee2c1SÁdám Kallai       // the range could be 0 to 4.
898e2cee2c1SÁdám Kallai       // The pattern comes from libc, it occurs when the binary is static.
899e2cee2c1SÁdám Kallai       //   adr     x6, 0x219fb0 <sigall_set+0x88>
900e2cee2c1SÁdám Kallai       //   add     x6, x6, x14, lsl #2
901e2cee2c1SÁdám Kallai       //   ldr     w7, [x6]
902e2cee2c1SÁdám Kallai       //   add     x6, x6, w7, sxtw => no shift amount
903e2cee2c1SÁdám Kallai       //   br      x6
904*1b4bd4e1SMaksim Panchenko       LLVM_DEBUG(dbgs() << "BOLT-DEBUG: "
905*1b4bd4e1SMaksim Panchenko                            "failed to match indirect branch: ShiftVAL != 2\n");
906e2cee2c1SÁdám Kallai       return false;
907e2cee2c1SÁdám Kallai     }
90889ceb779SAmir Ayupov 
90989ceb779SAmir Ayupov     if (ExtendType == AArch64_AM::SXTB)
910a34c753fSRafael Auler       ScaleValue = 1LL;
91189ceb779SAmir Ayupov     else if (ExtendType == AArch64_AM::SXTH)
912a34c753fSRafael Auler       ScaleValue = 2LL;
91389ceb779SAmir Ayupov     else if (ExtendType == AArch64_AM::SXTW)
914a34c753fSRafael Auler       ScaleValue = 4LL;
91589ceb779SAmir Ayupov     else
916*1b4bd4e1SMaksim Panchenko       return false;
917a34c753fSRafael Auler 
918a34c753fSRafael Auler     // Match an ADR to load base address to be used when addressing JT targets
919a34c753fSRafael Auler     SmallVector<MCInst *, 4> &UsesAdd = UDChain[DefAdd];
920a34c753fSRafael Auler     if (UsesAdd.size() <= 1 || UsesAdd[1] == nullptr || UsesAdd[2] == nullptr) {
921a34c753fSRafael Auler       // This happens when we don't have enough context about this jump table
922a34c753fSRafael Auler       // because the jumping code sequence was split in multiple basic blocks.
923a34c753fSRafael Auler       // This was observed in the wild in HHVM code (dispatchImpl).
924a34c753fSRafael Auler       return false;
925a34c753fSRafael Auler     }
926a34c753fSRafael Auler     MCInst *DefBaseAddr = UsesAdd[1];
927*1b4bd4e1SMaksim Panchenko     if (DefBaseAddr->getOpcode() != AArch64::ADR)
928*1b4bd4e1SMaksim Panchenko       return false;
929a34c753fSRafael Auler 
930a34c753fSRafael Auler     PCRelBase = DefBaseAddr;
931a34c753fSRafael Auler     // Match LOAD to load the jump table (relative) target
932a34c753fSRafael Auler     const MCInst *DefLoad = UsesAdd[2];
933*1b4bd4e1SMaksim Panchenko     if (!mayLoad(*DefLoad) || (ScaleValue == 1LL && !isLDRB(*DefLoad)) ||
934*1b4bd4e1SMaksim Panchenko         (ScaleValue == 2LL && !isLDRH(*DefLoad)))
935*1b4bd4e1SMaksim Panchenko       return false;
936a34c753fSRafael Auler 
937a34c753fSRafael Auler     // Match ADD that calculates the JumpTable Base Address (not the offset)
938a34c753fSRafael Auler     SmallVector<MCInst *, 4> &UsesLoad = UDChain[DefLoad];
939a34c753fSRafael Auler     const MCInst *DefJTBaseAdd = UsesLoad[1];
940a34c753fSRafael Auler     MCPhysReg From, To;
941a34c753fSRafael Auler     if (DefJTBaseAdd == nullptr || isLoadFromStack(*DefJTBaseAdd) ||
942a34c753fSRafael Auler         isRegToRegMove(*DefJTBaseAdd, From, To)) {
943a34c753fSRafael Auler       // Sometimes base address may have been defined in another basic block
944a34c753fSRafael Auler       // (hoisted). Return with no jump table info.
945a34c753fSRafael Auler       return true;
946a34c753fSRafael Auler     }
947a34c753fSRafael Auler 
948e2cee2c1SÁdám Kallai     if (DefJTBaseAdd->getOpcode() == AArch64::ADR) {
949e2cee2c1SÁdám Kallai       // TODO: Handle the pattern where there is no adrp/add pair.
950e2cee2c1SÁdám Kallai       // It also occurs when the binary is static.
951e2cee2c1SÁdám Kallai       //  adr     x13, 0x215a18 <_nl_value_type_LC_COLLATE+0x50>
952e2cee2c1SÁdám Kallai       //  ldrh    w13, [x13, w12, uxtw #1]
953e2cee2c1SÁdám Kallai       //  adr     x12, 0x247b30 <__gettextparse+0x5b0>
954e2cee2c1SÁdám Kallai       //  add     x13, x12, w13, sxth #2
955e2cee2c1SÁdám Kallai       //  br      x13
956*1b4bd4e1SMaksim Panchenko       LLVM_DEBUG(dbgs() << "BOLT-DEBUG: failed to match indirect branch: "
957*1b4bd4e1SMaksim Panchenko                            "nop/adr instead of adrp/add\n");
958e2cee2c1SÁdám Kallai       return false;
959e2cee2c1SÁdám Kallai     }
960e2cee2c1SÁdám Kallai 
961*1b4bd4e1SMaksim Panchenko     if (DefJTBaseAdd->getOpcode() != AArch64::ADDXri) {
962*1b4bd4e1SMaksim Panchenko       LLVM_DEBUG(dbgs() << "BOLT-DEBUG: failed to match jump table base "
963*1b4bd4e1SMaksim Panchenko                            "address pattern! (1)\n");
964*1b4bd4e1SMaksim Panchenko       return false;
965*1b4bd4e1SMaksim Panchenko     }
966a34c753fSRafael Auler 
967a34c753fSRafael Auler     if (DefJTBaseAdd->getOperand(2).isImm())
968a34c753fSRafael Auler       Offset = DefJTBaseAdd->getOperand(2).getImm();
969a34c753fSRafael Auler     SmallVector<MCInst *, 4> &UsesJTBaseAdd = UDChain[DefJTBaseAdd];
970a34c753fSRafael Auler     const MCInst *DefJTBasePage = UsesJTBaseAdd[1];
971a34c753fSRafael Auler     if (DefJTBasePage == nullptr || isLoadFromStack(*DefJTBasePage)) {
972a34c753fSRafael Auler       return true;
973a34c753fSRafael Auler     }
974*1b4bd4e1SMaksim Panchenko     if (DefJTBasePage->getOpcode() != AArch64::ADRP)
975*1b4bd4e1SMaksim Panchenko       return false;
976*1b4bd4e1SMaksim Panchenko 
977a34c753fSRafael Auler     if (DefJTBasePage->getOperand(1).isExpr())
978a34c753fSRafael Auler       JumpTable = DefJTBasePage->getOperand(1).getExpr();
979a34c753fSRafael Auler     return true;
980a34c753fSRafael Auler   }
981a34c753fSRafael Auler 
982a34c753fSRafael Auler   DenseMap<const MCInst *, SmallVector<MCInst *, 4>>
98340c2e0faSMaksim Panchenko   computeLocalUDChain(const MCInst *CurInstr, InstructionIterator Begin,
984a34c753fSRafael Auler                       InstructionIterator End) const {
985a34c753fSRafael Auler     DenseMap<int, MCInst *> RegAliasTable;
986a34c753fSRafael Auler     DenseMap<const MCInst *, SmallVector<MCInst *, 4>> Uses;
987a34c753fSRafael Auler 
988a34c753fSRafael Auler     auto addInstrOperands = [&](const MCInst &Instr) {
989a34c753fSRafael Auler       // Update Uses table
9908cb7a873SAmir Ayupov       for (const MCOperand &Operand : MCPlus::primeOperands(Instr)) {
9918cb7a873SAmir Ayupov         if (!Operand.isReg())
992a34c753fSRafael Auler           continue;
9938cb7a873SAmir Ayupov         unsigned Reg = Operand.getReg();
994a34c753fSRafael Auler         MCInst *AliasInst = RegAliasTable[Reg];
995a34c753fSRafael Auler         Uses[&Instr].push_back(AliasInst);
996a34c753fSRafael Auler         LLVM_DEBUG({
997a34c753fSRafael Auler           dbgs() << "Adding reg operand " << Reg << " refs ";
998a34c753fSRafael Auler           if (AliasInst != nullptr)
999a34c753fSRafael Auler             AliasInst->dump();
1000a34c753fSRafael Auler           else
1001a34c753fSRafael Auler             dbgs() << "\n";
1002a34c753fSRafael Auler         });
1003a34c753fSRafael Auler       }
1004a34c753fSRafael Auler     };
1005a34c753fSRafael Auler 
1006a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "computeLocalUDChain\n");
1007a34c753fSRafael Auler     bool TerminatorSeen = false;
1008a34c753fSRafael Auler     for (auto II = Begin; II != End; ++II) {
1009a34c753fSRafael Auler       MCInst &Instr = *II;
1010a34c753fSRafael Auler       // Ignore nops and CFIs
1011a34c753fSRafael Auler       if (isPseudo(Instr) || isNoop(Instr))
1012a34c753fSRafael Auler         continue;
1013a34c753fSRafael Auler       if (TerminatorSeen) {
1014a34c753fSRafael Auler         RegAliasTable.clear();
1015a34c753fSRafael Auler         Uses.clear();
1016a34c753fSRafael Auler       }
1017a34c753fSRafael Auler 
1018a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "Now updating for:\n ");
1019a34c753fSRafael Auler       LLVM_DEBUG(Instr.dump());
1020a34c753fSRafael Auler       addInstrOperands(Instr);
1021a34c753fSRafael Auler 
1022a34c753fSRafael Auler       BitVector Regs = BitVector(RegInfo->getNumRegs(), false);
1023a34c753fSRafael Auler       getWrittenRegs(Instr, Regs);
1024a34c753fSRafael Auler 
1025a34c753fSRafael Auler       // Update register definitions after this point
1026d63c5a38SAmir Ayupov       for (int Idx : Regs.set_bits()) {
1027a34c753fSRafael Auler         RegAliasTable[Idx] = &Instr;
1028a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "Setting reg " << Idx
1029a34c753fSRafael Auler                           << " def to current instr.\n");
1030a34c753fSRafael Auler       }
1031a34c753fSRafael Auler 
1032a34c753fSRafael Auler       TerminatorSeen = isTerminator(Instr);
1033a34c753fSRafael Auler     }
1034a34c753fSRafael Auler 
1035a34c753fSRafael Auler     // Process the last instruction, which is not currently added into the
1036a34c753fSRafael Auler     // instruction stream
103789ceb779SAmir Ayupov     if (CurInstr)
1038a34c753fSRafael Auler       addInstrOperands(*CurInstr);
103989ceb779SAmir Ayupov 
1040a34c753fSRafael Auler     return Uses;
1041a34c753fSRafael Auler   }
1042a34c753fSRafael Auler 
10433023b15fSAmir Ayupov   IndirectBranchType
10443023b15fSAmir Ayupov   analyzeIndirectBranch(MCInst &Instruction, InstructionIterator Begin,
10453023b15fSAmir Ayupov                         InstructionIterator End, const unsigned PtrSize,
10463023b15fSAmir Ayupov                         MCInst *&MemLocInstrOut, unsigned &BaseRegNumOut,
10478aab58baSMaksim Panchenko                         unsigned &IndexRegNumOut, int64_t &DispValueOut,
10483023b15fSAmir Ayupov                         const MCExpr *&DispExprOut, MCInst *&PCRelBaseOut,
10493023b15fSAmir Ayupov                         MCInst *&FixedEntryLoadInstr) const override {
1050a34c753fSRafael Auler     MemLocInstrOut = nullptr;
1051a34c753fSRafael Auler     BaseRegNumOut = AArch64::NoRegister;
1052a34c753fSRafael Auler     IndexRegNumOut = AArch64::NoRegister;
1053a34c753fSRafael Auler     DispValueOut = 0;
1054a34c753fSRafael Auler     DispExprOut = nullptr;
10553023b15fSAmir Ayupov     FixedEntryLoadInstr = nullptr;
1056a34c753fSRafael Auler 
1057a34c753fSRafael Auler     // An instruction referencing memory used by jump instruction (directly or
1058a34c753fSRafael Auler     // via register). This location could be an array of function pointers
1059a34c753fSRafael Auler     // in case of indirect tail call, or a jump table.
1060a34c753fSRafael Auler     MCInst *MemLocInstr = nullptr;
1061a34c753fSRafael Auler 
1062a34c753fSRafael Auler     // Analyze the memory location.
1063a34c753fSRafael Auler     int64_t ScaleValue, DispValue;
1064a34c753fSRafael Auler     const MCExpr *DispExpr;
1065a34c753fSRafael Auler 
1066a34c753fSRafael Auler     DenseMap<const MCInst *, SmallVector<llvm::MCInst *, 4>> UDChain =
1067a34c753fSRafael Auler         computeLocalUDChain(&Instruction, Begin, End);
1068a34c753fSRafael Auler     MCInst *PCRelBase;
1069a34c753fSRafael Auler     if (!analyzeIndirectBranchFragment(Instruction, UDChain, DispExpr,
107089ceb779SAmir Ayupov                                        DispValue, ScaleValue, PCRelBase))
1071a34c753fSRafael Auler       return IndirectBranchType::UNKNOWN;
1072a34c753fSRafael Auler 
1073a34c753fSRafael Auler     MemLocInstrOut = MemLocInstr;
1074a34c753fSRafael Auler     DispValueOut = DispValue;
1075a34c753fSRafael Auler     DispExprOut = DispExpr;
1076a34c753fSRafael Auler     PCRelBaseOut = PCRelBase;
1077a34c753fSRafael Auler     return IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE;
1078a34c753fSRafael Auler   }
1079a34c753fSRafael Auler 
108000b6efc8SVladislav Khmelevsky   ///  Matches PLT entry pattern and returns the associated GOT entry address.
108100b6efc8SVladislav Khmelevsky   ///  Typical PLT entry looks like the following:
108200b6efc8SVladislav Khmelevsky   ///
108300b6efc8SVladislav Khmelevsky   ///    adrp    x16, 230000
108400b6efc8SVladislav Khmelevsky   ///    ldr     x17, [x16, #3040]
108500b6efc8SVladislav Khmelevsky   ///    add     x16, x16, #0xbe0
108600b6efc8SVladislav Khmelevsky   ///    br      x17
108700b6efc8SVladislav Khmelevsky   ///
1088888742a1SVladislav Khmelevsky   ///  The other type of trampolines are located in .plt.got, that are used for
1089888742a1SVladislav Khmelevsky   ///  non-lazy bindings so doesn't use x16 arg to transfer .got entry address:
1090888742a1SVladislav Khmelevsky   ///
1091888742a1SVladislav Khmelevsky   ///    adrp    x16, 230000
1092888742a1SVladislav Khmelevsky   ///    ldr     x17, [x16, #3040]
1093888742a1SVladislav Khmelevsky   ///    br      x17
1094888742a1SVladislav Khmelevsky   ///    nop
1095888742a1SVladislav Khmelevsky   ///
109600b6efc8SVladislav Khmelevsky   uint64_t analyzePLTEntry(MCInst &Instruction, InstructionIterator Begin,
109700b6efc8SVladislav Khmelevsky                            InstructionIterator End,
109800b6efc8SVladislav Khmelevsky                            uint64_t BeginPC) const override {
109900b6efc8SVladislav Khmelevsky     // Check branch instruction
110000b6efc8SVladislav Khmelevsky     MCInst *Branch = &Instruction;
110100b6efc8SVladislav Khmelevsky     assert(Branch->getOpcode() == AArch64::BR && "Unexpected opcode");
110200b6efc8SVladislav Khmelevsky 
110300b6efc8SVladislav Khmelevsky     DenseMap<const MCInst *, SmallVector<llvm::MCInst *, 4>> UDChain =
110400b6efc8SVladislav Khmelevsky         computeLocalUDChain(Branch, Begin, End);
110500b6efc8SVladislav Khmelevsky 
110600b6efc8SVladislav Khmelevsky     // Match ldr instruction
110700b6efc8SVladislav Khmelevsky     SmallVector<MCInst *, 4> &BranchUses = UDChain[Branch];
110800b6efc8SVladislav Khmelevsky     if (BranchUses.size() < 1 || BranchUses[0] == nullptr)
110900b6efc8SVladislav Khmelevsky       return 0;
111000b6efc8SVladislav Khmelevsky 
111100b6efc8SVladislav Khmelevsky     // Check ldr instruction
111200b6efc8SVladislav Khmelevsky     const MCInst *Ldr = BranchUses[0];
111300b6efc8SVladislav Khmelevsky     if (Ldr->getOpcode() != AArch64::LDRXui)
111400b6efc8SVladislav Khmelevsky       return 0;
111500b6efc8SVladislav Khmelevsky 
111600b6efc8SVladislav Khmelevsky     // Get ldr value
111700b6efc8SVladislav Khmelevsky     const unsigned ScaleLdr = 8; // LDRX operates on 8 bytes segments
111800b6efc8SVladislav Khmelevsky     assert(Ldr->getOperand(2).isImm() && "Unexpected ldr operand");
111900b6efc8SVladislav Khmelevsky     const uint64_t Offset = Ldr->getOperand(2).getImm() * ScaleLdr;
112000b6efc8SVladislav Khmelevsky 
112100b6efc8SVladislav Khmelevsky     // Match adrp instruction
112200b6efc8SVladislav Khmelevsky     SmallVector<MCInst *, 4> &LdrUses = UDChain[Ldr];
112300b6efc8SVladislav Khmelevsky     if (LdrUses.size() < 2 || LdrUses[1] == nullptr)
112400b6efc8SVladislav Khmelevsky       return 0;
112500b6efc8SVladislav Khmelevsky 
112600b6efc8SVladislav Khmelevsky     // Check adrp instruction
112700b6efc8SVladislav Khmelevsky     MCInst *Adrp = LdrUses[1];
112800b6efc8SVladislav Khmelevsky     if (Adrp->getOpcode() != AArch64::ADRP)
112900b6efc8SVladislav Khmelevsky       return 0;
113000b6efc8SVladislav Khmelevsky 
113100b6efc8SVladislav Khmelevsky     // Get adrp instruction PC
113200b6efc8SVladislav Khmelevsky     const unsigned InstSize = 4;
113300b6efc8SVladislav Khmelevsky     uint64_t AdrpPC = BeginPC;
113400b6efc8SVladislav Khmelevsky     for (InstructionIterator It = Begin; It != End; ++It) {
113500b6efc8SVladislav Khmelevsky       if (&(*It) == Adrp)
113600b6efc8SVladislav Khmelevsky         break;
113700b6efc8SVladislav Khmelevsky       AdrpPC += InstSize;
113800b6efc8SVladislav Khmelevsky     }
113900b6efc8SVladislav Khmelevsky 
114000b6efc8SVladislav Khmelevsky     // Get adrp value
114100b6efc8SVladislav Khmelevsky     uint64_t Base;
114200b6efc8SVladislav Khmelevsky     assert(Adrp->getOperand(1).isImm() && "Unexpected adrp operand");
114300b6efc8SVladislav Khmelevsky     bool Ret = evaluateMemOperandTarget(*Adrp, Base, AdrpPC, InstSize);
114400b6efc8SVladislav Khmelevsky     assert(Ret && "Failed to evaluate adrp");
1145139744acSAmir Ayupov     (void)Ret;
114600b6efc8SVladislav Khmelevsky 
114700b6efc8SVladislav Khmelevsky     return Base + Offset;
114800b6efc8SVladislav Khmelevsky   }
114900b6efc8SVladislav Khmelevsky 
1150a34c753fSRafael Auler   unsigned getInvertedBranchOpcode(unsigned Opcode) const {
1151a34c753fSRafael Auler     switch (Opcode) {
1152a34c753fSRafael Auler     default:
1153a34c753fSRafael Auler       llvm_unreachable("Failed to invert branch opcode");
1154a34c753fSRafael Auler       return Opcode;
1155a34c753fSRafael Auler     case AArch64::TBZW:     return AArch64::TBNZW;
1156a34c753fSRafael Auler     case AArch64::TBZX:     return AArch64::TBNZX;
1157a34c753fSRafael Auler     case AArch64::TBNZW:    return AArch64::TBZW;
1158a34c753fSRafael Auler     case AArch64::TBNZX:    return AArch64::TBZX;
1159a34c753fSRafael Auler     case AArch64::CBZW:     return AArch64::CBNZW;
1160a34c753fSRafael Auler     case AArch64::CBZX:     return AArch64::CBNZX;
1161a34c753fSRafael Auler     case AArch64::CBNZW:    return AArch64::CBZW;
1162a34c753fSRafael Auler     case AArch64::CBNZX:    return AArch64::CBZX;
1163a34c753fSRafael Auler     }
1164a34c753fSRafael Auler   }
1165a34c753fSRafael Auler 
1166a34c753fSRafael Auler   unsigned getCondCode(const MCInst &Inst) const override {
1167a34c753fSRafael Auler     // AArch64 does not use conditional codes, so we just return the opcode
1168a34c753fSRafael Auler     // of the conditional branch here.
1169a34c753fSRafael Auler     return Inst.getOpcode();
1170a34c753fSRafael Auler   }
1171a34c753fSRafael Auler 
1172a34c753fSRafael Auler   unsigned getCanonicalBranchCondCode(unsigned Opcode) const override {
1173a34c753fSRafael Auler     switch (Opcode) {
1174a34c753fSRafael Auler     default:
1175a34c753fSRafael Auler       return Opcode;
1176a34c753fSRafael Auler     case AArch64::TBNZW:    return AArch64::TBZW;
1177a34c753fSRafael Auler     case AArch64::TBNZX:    return AArch64::TBZX;
1178a34c753fSRafael Auler     case AArch64::CBNZW:    return AArch64::CBZW;
1179a34c753fSRafael Auler     case AArch64::CBNZX:    return AArch64::CBZX;
1180a34c753fSRafael Auler     }
1181a34c753fSRafael Auler   }
1182a34c753fSRafael Auler 
11833fefb3c5SNathan Sidwell   void reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,
1184a34c753fSRafael Auler                               MCContext *Ctx) const override {
1185a34c753fSRafael Auler     if (isTB(Inst) || isCB(Inst)) {
1186a34c753fSRafael Auler       Inst.setOpcode(getInvertedBranchOpcode(Inst.getOpcode()));
1187a34c753fSRafael Auler       assert(Inst.getOpcode() != 0 && "Invalid branch instruction");
1188a34c753fSRafael Auler     } else if (Inst.getOpcode() == AArch64::Bcc) {
1189a34c753fSRafael Auler       Inst.getOperand(0).setImm(AArch64CC::getInvertedCondCode(
1190a34c753fSRafael Auler           static_cast<AArch64CC::CondCode>(Inst.getOperand(0).getImm())));
1191a34c753fSRafael Auler       assert(Inst.getOperand(0).getImm() != AArch64CC::AL &&
1192a34c753fSRafael Auler              Inst.getOperand(0).getImm() != AArch64CC::NV &&
1193a34c753fSRafael Auler              "Can't reverse ALWAYS cond code");
1194a34c753fSRafael Auler     } else {
1195a34c753fSRafael Auler       LLVM_DEBUG(Inst.dump());
1196a34c753fSRafael Auler       llvm_unreachable("Unrecognized branch instruction");
1197a34c753fSRafael Auler     }
11983fefb3c5SNathan Sidwell     replaceBranchTarget(Inst, TBB, Ctx);
1199a34c753fSRafael Auler   }
1200a34c753fSRafael Auler 
1201a34c753fSRafael Auler   int getPCRelEncodingSize(const MCInst &Inst) const override {
1202a34c753fSRafael Auler     switch (Inst.getOpcode()) {
1203a34c753fSRafael Auler     default:
1204a34c753fSRafael Auler       llvm_unreachable("Failed to get pcrel encoding size");
1205a34c753fSRafael Auler       return 0;
1206a34c753fSRafael Auler     case AArch64::TBZW:     return 16;
1207a34c753fSRafael Auler     case AArch64::TBZX:     return 16;
1208a34c753fSRafael Auler     case AArch64::TBNZW:    return 16;
1209a34c753fSRafael Auler     case AArch64::TBNZX:    return 16;
1210a34c753fSRafael Auler     case AArch64::CBZW:     return 21;
1211a34c753fSRafael Auler     case AArch64::CBZX:     return 21;
1212a34c753fSRafael Auler     case AArch64::CBNZW:    return 21;
1213a34c753fSRafael Auler     case AArch64::CBNZX:    return 21;
1214a34c753fSRafael Auler     case AArch64::B:        return 28;
1215a34c753fSRafael Auler     case AArch64::BL:       return 28;
1216a34c753fSRafael Auler     case AArch64::Bcc:      return 21;
1217a34c753fSRafael Auler     }
1218a34c753fSRafael Auler   }
1219a34c753fSRafael Auler 
122040c2e0faSMaksim Panchenko   int getShortJmpEncodingSize() const override { return 33; }
1221a34c753fSRafael Auler 
122240c2e0faSMaksim Panchenko   int getUncondBranchEncodingSize() const override { return 28; }
1223a34c753fSRafael Auler 
12246e4c2305SElvina Yakubova   InstructionListType createCmpJE(MCPhysReg RegNo, int64_t Imm,
12256e4c2305SElvina Yakubova                                   const MCSymbol *Target,
12266e4c2305SElvina Yakubova                                   MCContext *Ctx) const override {
12276e4c2305SElvina Yakubova     InstructionListType Code;
12286e4c2305SElvina Yakubova     Code.emplace_back(MCInstBuilder(AArch64::SUBSXri)
12296e4c2305SElvina Yakubova                           .addReg(RegNo)
12306e4c2305SElvina Yakubova                           .addReg(RegNo)
12316e4c2305SElvina Yakubova                           .addImm(Imm)
12326e4c2305SElvina Yakubova                           .addImm(0));
12336e4c2305SElvina Yakubova     Code.emplace_back(MCInstBuilder(AArch64::Bcc)
12346e4c2305SElvina Yakubova                           .addImm(Imm)
12356e4c2305SElvina Yakubova                           .addExpr(MCSymbolRefExpr::create(
12366e4c2305SElvina Yakubova                               Target, MCSymbolRefExpr::VK_None, *Ctx)));
12376e4c2305SElvina Yakubova     return Code;
12386e4c2305SElvina Yakubova   }
12396e4c2305SElvina Yakubova 
1240bba790dbSMaksim Panchenko   void createTailCall(MCInst &Inst, const MCSymbol *Target,
1241a34c753fSRafael Auler                       MCContext *Ctx) override {
12426e4c2305SElvina Yakubova     return createDirectCall(Inst, Target, Ctx, /*IsTailCall*/ true);
1243a34c753fSRafael Auler   }
1244a34c753fSRafael Auler 
124569706eafSMaksim Panchenko   void createLongTailCall(InstructionListType &Seq, const MCSymbol *Target,
1246a34c753fSRafael Auler                           MCContext *Ctx) override {
1247a34c753fSRafael Auler     createShortJmp(Seq, Target, Ctx, /*IsTailCall*/ true);
1248a34c753fSRafael Auler   }
1249a34c753fSRafael Auler 
1250bba790dbSMaksim Panchenko   void createTrap(MCInst &Inst) const override {
125119fb5a21SVladislav Khmelevsky     Inst.clear();
125219fb5a21SVladislav Khmelevsky     Inst.setOpcode(AArch64::BRK);
125319fb5a21SVladislav Khmelevsky     Inst.addOperand(MCOperand::createImm(1));
125419fb5a21SVladislav Khmelevsky   }
125519fb5a21SVladislav Khmelevsky 
1256a34c753fSRafael Auler   bool convertJmpToTailCall(MCInst &Inst) override {
1257a34c753fSRafael Auler     setTailCall(Inst);
1258a34c753fSRafael Auler     return true;
1259a34c753fSRafael Auler   }
1260a34c753fSRafael Auler 
1261a34c753fSRafael Auler   bool convertTailCallToJmp(MCInst &Inst) override {
1262a34c753fSRafael Auler     removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
1263a9cd49d5SAmir Ayupov     clearOffset(Inst);
1264a34c753fSRafael Auler     if (getConditionalTailCall(Inst))
1265a34c753fSRafael Auler       unsetConditionalTailCall(Inst);
1266a34c753fSRafael Auler     return true;
1267a34c753fSRafael Auler   }
1268a34c753fSRafael Auler 
126934c6c5e7SMaksim Panchenko   InstructionListType createIndirectPLTCall(MCInst &&DirectCall,
1270a13bc971SPaschalis Mpeis                                             const MCSymbol *TargetLocation,
1271a13bc971SPaschalis Mpeis                                             MCContext *Ctx) override {
1272a13bc971SPaschalis Mpeis     const bool IsTailCall = isTailCall(DirectCall);
1273a13bc971SPaschalis Mpeis     assert((DirectCall.getOpcode() == AArch64::BL ||
1274a13bc971SPaschalis Mpeis             (DirectCall.getOpcode() == AArch64::B && IsTailCall)) &&
1275a13bc971SPaschalis Mpeis            "64-bit direct (tail) call instruction expected");
1276a13bc971SPaschalis Mpeis 
1277a13bc971SPaschalis Mpeis     InstructionListType Code;
1278a13bc971SPaschalis Mpeis     // Code sequence for indirect plt call:
1279a13bc971SPaschalis Mpeis     // adrp	x16 <symbol>
1280a13bc971SPaschalis Mpeis     // ldr	x17, [x16, #<offset>]
1281a13bc971SPaschalis Mpeis     // blr	x17  ; or 'br' for tail calls
1282a13bc971SPaschalis Mpeis 
1283a13bc971SPaschalis Mpeis     MCInst InstAdrp;
1284a13bc971SPaschalis Mpeis     InstAdrp.setOpcode(AArch64::ADRP);
1285a13bc971SPaschalis Mpeis     InstAdrp.addOperand(MCOperand::createReg(AArch64::X16));
1286a13bc971SPaschalis Mpeis     InstAdrp.addOperand(MCOperand::createImm(0));
1287a13bc971SPaschalis Mpeis     setOperandToSymbolRef(InstAdrp, /* OpNum */ 1, TargetLocation,
1288a13bc971SPaschalis Mpeis                           /* Addend */ 0, Ctx, ELF::R_AARCH64_ADR_GOT_PAGE);
1289a13bc971SPaschalis Mpeis     Code.emplace_back(InstAdrp);
1290a13bc971SPaschalis Mpeis 
1291a13bc971SPaschalis Mpeis     MCInst InstLoad;
1292a13bc971SPaschalis Mpeis     InstLoad.setOpcode(AArch64::LDRXui);
1293a13bc971SPaschalis Mpeis     InstLoad.addOperand(MCOperand::createReg(AArch64::X17));
1294a13bc971SPaschalis Mpeis     InstLoad.addOperand(MCOperand::createReg(AArch64::X16));
1295a13bc971SPaschalis Mpeis     InstLoad.addOperand(MCOperand::createImm(0));
1296a13bc971SPaschalis Mpeis     setOperandToSymbolRef(InstLoad, /* OpNum */ 2, TargetLocation,
1297a13bc971SPaschalis Mpeis                           /* Addend */ 0, Ctx, ELF::R_AARCH64_LD64_GOT_LO12_NC);
1298a13bc971SPaschalis Mpeis     Code.emplace_back(InstLoad);
1299a13bc971SPaschalis Mpeis 
1300a13bc971SPaschalis Mpeis     MCInst InstCall;
1301a13bc971SPaschalis Mpeis     InstCall.setOpcode(IsTailCall ? AArch64::BR : AArch64::BLR);
1302a13bc971SPaschalis Mpeis     InstCall.addOperand(MCOperand::createReg(AArch64::X17));
130334c6c5e7SMaksim Panchenko     moveAnnotations(std::move(DirectCall), InstCall);
1304a13bc971SPaschalis Mpeis     Code.emplace_back(InstCall);
1305a13bc971SPaschalis Mpeis 
1306a13bc971SPaschalis Mpeis     return Code;
1307a13bc971SPaschalis Mpeis   }
1308a13bc971SPaschalis Mpeis 
1309a34c753fSRafael Auler   bool lowerTailCall(MCInst &Inst) override {
1310a34c753fSRafael Auler     removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
1311a34c753fSRafael Auler     if (getConditionalTailCall(Inst))
1312a34c753fSRafael Auler       unsetConditionalTailCall(Inst);
1313a34c753fSRafael Auler     return true;
1314a34c753fSRafael Auler   }
1315a34c753fSRafael Auler 
1316a34c753fSRafael Auler   bool isNoop(const MCInst &Inst) const override {
1317a34c753fSRafael Auler     return Inst.getOpcode() == AArch64::HINT &&
1318a34c753fSRafael Auler            Inst.getOperand(0).getImm() == 0;
1319a34c753fSRafael Auler   }
1320a34c753fSRafael Auler 
1321bba790dbSMaksim Panchenko   void createNoop(MCInst &Inst) const override {
1322a34c753fSRafael Auler     Inst.setOpcode(AArch64::HINT);
1323a34c753fSRafael Auler     Inst.clear();
1324a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0));
1325a34c753fSRafael Auler   }
1326a34c753fSRafael Auler 
1327ad599c25SAlexey Moksyakov   bool isStorePair(const MCInst &Inst) const {
1328ad599c25SAlexey Moksyakov     const unsigned opcode = Inst.getOpcode();
1329ad599c25SAlexey Moksyakov 
1330ad599c25SAlexey Moksyakov     auto isStorePairImmOffset = [&]() {
1331ad599c25SAlexey Moksyakov       switch (opcode) {
1332ad599c25SAlexey Moksyakov       case AArch64::STPWi:
1333ad599c25SAlexey Moksyakov       case AArch64::STPXi:
1334ad599c25SAlexey Moksyakov       case AArch64::STPSi:
1335ad599c25SAlexey Moksyakov       case AArch64::STPDi:
1336ad599c25SAlexey Moksyakov       case AArch64::STPQi:
1337ad599c25SAlexey Moksyakov       case AArch64::STNPWi:
1338ad599c25SAlexey Moksyakov       case AArch64::STNPXi:
1339ad599c25SAlexey Moksyakov       case AArch64::STNPSi:
1340ad599c25SAlexey Moksyakov       case AArch64::STNPDi:
1341ad599c25SAlexey Moksyakov       case AArch64::STNPQi:
1342ad599c25SAlexey Moksyakov         return true;
1343ad599c25SAlexey Moksyakov       default:
1344ad599c25SAlexey Moksyakov         break;
1345ad599c25SAlexey Moksyakov       }
1346ad599c25SAlexey Moksyakov 
1347ad599c25SAlexey Moksyakov       return false;
1348ad599c25SAlexey Moksyakov     };
1349ad599c25SAlexey Moksyakov 
1350ad599c25SAlexey Moksyakov     auto isStorePairPostIndex = [&]() {
1351ad599c25SAlexey Moksyakov       switch (opcode) {
1352ad599c25SAlexey Moksyakov       case AArch64::STPWpost:
1353ad599c25SAlexey Moksyakov       case AArch64::STPXpost:
1354ad599c25SAlexey Moksyakov       case AArch64::STPSpost:
1355ad599c25SAlexey Moksyakov       case AArch64::STPDpost:
1356ad599c25SAlexey Moksyakov       case AArch64::STPQpost:
1357ad599c25SAlexey Moksyakov         return true;
1358ad599c25SAlexey Moksyakov       default:
1359ad599c25SAlexey Moksyakov         break;
1360ad599c25SAlexey Moksyakov       }
1361ad599c25SAlexey Moksyakov 
1362ad599c25SAlexey Moksyakov       return false;
1363ad599c25SAlexey Moksyakov     };
1364ad599c25SAlexey Moksyakov 
1365ad599c25SAlexey Moksyakov     auto isStorePairPreIndex = [&]() {
1366ad599c25SAlexey Moksyakov       switch (opcode) {
1367ad599c25SAlexey Moksyakov       case AArch64::STPWpre:
1368ad599c25SAlexey Moksyakov       case AArch64::STPXpre:
1369ad599c25SAlexey Moksyakov       case AArch64::STPSpre:
1370ad599c25SAlexey Moksyakov       case AArch64::STPDpre:
1371ad599c25SAlexey Moksyakov       case AArch64::STPQpre:
1372ad599c25SAlexey Moksyakov         return true;
1373ad599c25SAlexey Moksyakov       default:
1374ad599c25SAlexey Moksyakov         break;
1375ad599c25SAlexey Moksyakov       }
1376ad599c25SAlexey Moksyakov 
1377ad599c25SAlexey Moksyakov       return false;
1378ad599c25SAlexey Moksyakov     };
1379ad599c25SAlexey Moksyakov 
1380ad599c25SAlexey Moksyakov     return isStorePairImmOffset() || isStorePairPostIndex() ||
1381ad599c25SAlexey Moksyakov            isStorePairPreIndex();
1382ad599c25SAlexey Moksyakov   }
1383ad599c25SAlexey Moksyakov 
1384ad599c25SAlexey Moksyakov   bool isStoreReg(const MCInst &Inst) const {
1385ad599c25SAlexey Moksyakov     const unsigned opcode = Inst.getOpcode();
1386ad599c25SAlexey Moksyakov 
1387ad599c25SAlexey Moksyakov     auto isStoreRegUnscaleImm = [&]() {
1388ad599c25SAlexey Moksyakov       switch (opcode) {
1389ad599c25SAlexey Moksyakov       case AArch64::STURBi:
1390ad599c25SAlexey Moksyakov       case AArch64::STURBBi:
1391ad599c25SAlexey Moksyakov       case AArch64::STURHi:
1392ad599c25SAlexey Moksyakov       case AArch64::STURHHi:
1393ad599c25SAlexey Moksyakov       case AArch64::STURWi:
1394ad599c25SAlexey Moksyakov       case AArch64::STURXi:
1395ad599c25SAlexey Moksyakov       case AArch64::STURSi:
1396ad599c25SAlexey Moksyakov       case AArch64::STURDi:
1397ad599c25SAlexey Moksyakov       case AArch64::STURQi:
1398ad599c25SAlexey Moksyakov         return true;
1399ad599c25SAlexey Moksyakov       default:
1400ad599c25SAlexey Moksyakov         break;
1401ad599c25SAlexey Moksyakov       }
1402ad599c25SAlexey Moksyakov 
1403ad599c25SAlexey Moksyakov       return false;
1404ad599c25SAlexey Moksyakov     };
1405ad599c25SAlexey Moksyakov 
1406ad599c25SAlexey Moksyakov     auto isStoreRegScaledImm = [&]() {
1407ad599c25SAlexey Moksyakov       switch (opcode) {
1408ad599c25SAlexey Moksyakov       case AArch64::STRBui:
1409ad599c25SAlexey Moksyakov       case AArch64::STRBBui:
1410ad599c25SAlexey Moksyakov       case AArch64::STRHui:
1411ad599c25SAlexey Moksyakov       case AArch64::STRHHui:
1412ad599c25SAlexey Moksyakov       case AArch64::STRWui:
1413ad599c25SAlexey Moksyakov       case AArch64::STRXui:
1414ad599c25SAlexey Moksyakov       case AArch64::STRSui:
1415ad599c25SAlexey Moksyakov       case AArch64::STRDui:
1416ad599c25SAlexey Moksyakov       case AArch64::STRQui:
1417ad599c25SAlexey Moksyakov         return true;
1418ad599c25SAlexey Moksyakov       default:
1419ad599c25SAlexey Moksyakov         break;
1420ad599c25SAlexey Moksyakov       }
1421ad599c25SAlexey Moksyakov 
1422ad599c25SAlexey Moksyakov       return false;
1423ad599c25SAlexey Moksyakov     };
1424ad599c25SAlexey Moksyakov 
1425ad599c25SAlexey Moksyakov     auto isStoreRegImmPostIndexed = [&]() {
1426ad599c25SAlexey Moksyakov       switch (opcode) {
1427ad599c25SAlexey Moksyakov       case AArch64::STRBpost:
1428ad599c25SAlexey Moksyakov       case AArch64::STRBBpost:
1429ad599c25SAlexey Moksyakov       case AArch64::STRHpost:
1430ad599c25SAlexey Moksyakov       case AArch64::STRHHpost:
1431ad599c25SAlexey Moksyakov       case AArch64::STRWpost:
1432ad599c25SAlexey Moksyakov       case AArch64::STRXpost:
1433ad599c25SAlexey Moksyakov       case AArch64::STRSpost:
1434ad599c25SAlexey Moksyakov       case AArch64::STRDpost:
1435ad599c25SAlexey Moksyakov       case AArch64::STRQpost:
1436ad599c25SAlexey Moksyakov         return true;
1437ad599c25SAlexey Moksyakov       default:
1438ad599c25SAlexey Moksyakov         break;
1439ad599c25SAlexey Moksyakov       }
1440ad599c25SAlexey Moksyakov 
1441ad599c25SAlexey Moksyakov       return false;
1442ad599c25SAlexey Moksyakov     };
1443ad599c25SAlexey Moksyakov 
1444ad599c25SAlexey Moksyakov     auto isStoreRegImmPreIndexed = [&]() {
1445ad599c25SAlexey Moksyakov       switch (opcode) {
1446ad599c25SAlexey Moksyakov       case AArch64::STRBpre:
1447ad599c25SAlexey Moksyakov       case AArch64::STRBBpre:
1448ad599c25SAlexey Moksyakov       case AArch64::STRHpre:
1449ad599c25SAlexey Moksyakov       case AArch64::STRHHpre:
1450ad599c25SAlexey Moksyakov       case AArch64::STRWpre:
1451ad599c25SAlexey Moksyakov       case AArch64::STRXpre:
1452ad599c25SAlexey Moksyakov       case AArch64::STRSpre:
1453ad599c25SAlexey Moksyakov       case AArch64::STRDpre:
1454ad599c25SAlexey Moksyakov       case AArch64::STRQpre:
1455ad599c25SAlexey Moksyakov         return true;
1456ad599c25SAlexey Moksyakov       default:
1457ad599c25SAlexey Moksyakov         break;
1458ad599c25SAlexey Moksyakov       }
1459ad599c25SAlexey Moksyakov 
1460ad599c25SAlexey Moksyakov       return false;
1461ad599c25SAlexey Moksyakov     };
1462ad599c25SAlexey Moksyakov 
1463ad599c25SAlexey Moksyakov     auto isStoreRegUnscaleUnpriv = [&]() {
1464ad599c25SAlexey Moksyakov       switch (opcode) {
1465ad599c25SAlexey Moksyakov       case AArch64::STTRBi:
1466ad599c25SAlexey Moksyakov       case AArch64::STTRHi:
1467ad599c25SAlexey Moksyakov       case AArch64::STTRWi:
1468ad599c25SAlexey Moksyakov       case AArch64::STTRXi:
1469ad599c25SAlexey Moksyakov         return true;
1470ad599c25SAlexey Moksyakov       default:
1471ad599c25SAlexey Moksyakov         break;
1472ad599c25SAlexey Moksyakov       }
1473ad599c25SAlexey Moksyakov 
1474ad599c25SAlexey Moksyakov       return false;
1475ad599c25SAlexey Moksyakov     };
1476ad599c25SAlexey Moksyakov 
1477ad599c25SAlexey Moksyakov     auto isStoreRegTrunc = [&]() {
1478ad599c25SAlexey Moksyakov       switch (opcode) {
1479ad599c25SAlexey Moksyakov       case AArch64::STRBBroW:
1480ad599c25SAlexey Moksyakov       case AArch64::STRBBroX:
1481ad599c25SAlexey Moksyakov       case AArch64::STRBroW:
1482ad599c25SAlexey Moksyakov       case AArch64::STRBroX:
1483ad599c25SAlexey Moksyakov       case AArch64::STRDroW:
1484ad599c25SAlexey Moksyakov       case AArch64::STRDroX:
1485ad599c25SAlexey Moksyakov       case AArch64::STRHHroW:
1486ad599c25SAlexey Moksyakov       case AArch64::STRHHroX:
1487ad599c25SAlexey Moksyakov       case AArch64::STRHroW:
1488ad599c25SAlexey Moksyakov       case AArch64::STRHroX:
1489ad599c25SAlexey Moksyakov       case AArch64::STRQroW:
1490ad599c25SAlexey Moksyakov       case AArch64::STRQroX:
1491ad599c25SAlexey Moksyakov       case AArch64::STRSroW:
1492ad599c25SAlexey Moksyakov       case AArch64::STRSroX:
1493ad599c25SAlexey Moksyakov       case AArch64::STRWroW:
1494ad599c25SAlexey Moksyakov       case AArch64::STRWroX:
1495ad599c25SAlexey Moksyakov       case AArch64::STRXroW:
1496ad599c25SAlexey Moksyakov       case AArch64::STRXroX:
1497ad599c25SAlexey Moksyakov         return true;
1498ad599c25SAlexey Moksyakov       default:
1499ad599c25SAlexey Moksyakov         break;
1500ad599c25SAlexey Moksyakov       }
1501ad599c25SAlexey Moksyakov 
1502ad599c25SAlexey Moksyakov       return false;
1503ad599c25SAlexey Moksyakov     };
1504ad599c25SAlexey Moksyakov 
1505ad599c25SAlexey Moksyakov     return isStoreRegUnscaleImm() || isStoreRegScaledImm() ||
1506ad599c25SAlexey Moksyakov            isStoreRegImmPreIndexed() || isStoreRegImmPostIndexed() ||
1507ad599c25SAlexey Moksyakov            isStoreRegUnscaleUnpriv() || isStoreRegTrunc();
1508ad599c25SAlexey Moksyakov   }
1509ad599c25SAlexey Moksyakov 
1510ad599c25SAlexey Moksyakov   bool mayStore(const MCInst &Inst) const override {
1511ad599c25SAlexey Moksyakov     return isStorePair(Inst) || isStoreReg(Inst) ||
1512ad599c25SAlexey Moksyakov            isAArch64ExclusiveStore(Inst);
1513ad599c25SAlexey Moksyakov   }
1514ad599c25SAlexey Moksyakov 
1515ad599c25SAlexey Moksyakov   bool isStoreToStack(const MCInst &Inst) const {
1516ad599c25SAlexey Moksyakov     if (!mayStore(Inst))
1517ad599c25SAlexey Moksyakov       return false;
1518ad599c25SAlexey Moksyakov 
1519ad599c25SAlexey Moksyakov     for (const MCOperand &Operand : useOperands(Inst)) {
1520ad599c25SAlexey Moksyakov       if (!Operand.isReg())
1521ad599c25SAlexey Moksyakov         continue;
1522ad599c25SAlexey Moksyakov 
1523ad599c25SAlexey Moksyakov       unsigned Reg = Operand.getReg();
1524ad599c25SAlexey Moksyakov       if (Reg == AArch64::SP || Reg == AArch64::WSP)
1525ad599c25SAlexey Moksyakov         return true;
1526ad599c25SAlexey Moksyakov     }
1527ad599c25SAlexey Moksyakov 
1528ad599c25SAlexey Moksyakov     return false;
1529ad599c25SAlexey Moksyakov   }
1530a34c753fSRafael Auler 
1531bba790dbSMaksim Panchenko   void createDirectCall(MCInst &Inst, const MCSymbol *Target, MCContext *Ctx,
15326e4c2305SElvina Yakubova                         bool IsTailCall) override {
15336e4c2305SElvina Yakubova     Inst.setOpcode(IsTailCall ? AArch64::B : AArch64::BL);
15346e4c2305SElvina Yakubova     Inst.clear();
15356e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createExpr(getTargetExprFor(
15366e4c2305SElvina Yakubova         Inst, MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
15376e4c2305SElvina Yakubova         *Ctx, 0)));
15386e4c2305SElvina Yakubova     if (IsTailCall)
15396e4c2305SElvina Yakubova       convertJmpToTailCall(Inst);
15406e4c2305SElvina Yakubova   }
15416e4c2305SElvina Yakubova 
154240c2e0faSMaksim Panchenko   bool analyzeBranch(InstructionIterator Begin, InstructionIterator End,
154340c2e0faSMaksim Panchenko                      const MCSymbol *&TBB, const MCSymbol *&FBB,
1544a34c753fSRafael Auler                      MCInst *&CondBranch,
1545a34c753fSRafael Auler                      MCInst *&UncondBranch) const override {
1546a34c753fSRafael Auler     auto I = End;
1547a34c753fSRafael Auler 
1548a34c753fSRafael Auler     while (I != Begin) {
1549a34c753fSRafael Auler       --I;
1550a34c753fSRafael Auler 
1551a34c753fSRafael Auler       // Ignore nops and CFIs
1552a34c753fSRafael Auler       if (isPseudo(*I) || isNoop(*I))
1553a34c753fSRafael Auler         continue;
1554a34c753fSRafael Auler 
1555a34c753fSRafael Auler       // Stop when we find the first non-terminator
1556a34c753fSRafael Auler       if (!isTerminator(*I) || isTailCall(*I) || !isBranch(*I))
1557a34c753fSRafael Auler         break;
1558a34c753fSRafael Auler 
1559a34c753fSRafael Auler       // Handle unconditional branches.
1560a34c753fSRafael Auler       if (isUnconditionalBranch(*I)) {
1561a34c753fSRafael Auler         // If any code was seen after this unconditional branch, we've seen
1562a34c753fSRafael Auler         // unreachable code. Ignore them.
1563a34c753fSRafael Auler         CondBranch = nullptr;
1564a34c753fSRafael Auler         UncondBranch = &*I;
1565a34c753fSRafael Auler         const MCSymbol *Sym = getTargetSymbol(*I);
1566a34c753fSRafael Auler         assert(Sym != nullptr &&
1567a34c753fSRafael Auler                "Couldn't extract BB symbol from jump operand");
1568a34c753fSRafael Auler         TBB = Sym;
1569a34c753fSRafael Auler         continue;
1570a34c753fSRafael Auler       }
1571a34c753fSRafael Auler 
1572a34c753fSRafael Auler       // Handle conditional branches and ignore indirect branches
157389ceb779SAmir Ayupov       if (isIndirectBranch(*I))
1574a34c753fSRafael Auler         return false;
1575a34c753fSRafael Auler 
1576a34c753fSRafael Auler       if (CondBranch == nullptr) {
1577a34c753fSRafael Auler         const MCSymbol *TargetBB = getTargetSymbol(*I);
1578a34c753fSRafael Auler         if (TargetBB == nullptr) {
1579a34c753fSRafael Auler           // Unrecognized branch target
1580a34c753fSRafael Auler           return false;
1581a34c753fSRafael Auler         }
1582a34c753fSRafael Auler         FBB = TBB;
1583a34c753fSRafael Auler         TBB = TargetBB;
1584a34c753fSRafael Auler         CondBranch = &*I;
1585a34c753fSRafael Auler         continue;
1586a34c753fSRafael Auler       }
1587a34c753fSRafael Auler 
1588a34c753fSRafael Auler       llvm_unreachable("multiple conditional branches in one BB");
1589a34c753fSRafael Auler     }
1590a34c753fSRafael Auler     return true;
1591a34c753fSRafael Auler   }
1592a34c753fSRafael Auler 
159369706eafSMaksim Panchenko   void createLongJmp(InstructionListType &Seq, const MCSymbol *Target,
1594a34c753fSRafael Auler                      MCContext *Ctx, bool IsTailCall) override {
1595a34c753fSRafael Auler     // ip0 (r16) is reserved to the linker (refer to 5.3.1.1 of "Procedure Call
1596a34c753fSRafael Auler     //   Standard for the ARM 64-bit Architecture (AArch64)".
1597a34c753fSRafael Auler     // The sequence of instructions we create here is the following:
1598a34c753fSRafael Auler     //  movz ip0, #:abs_g3:<addr>
1599a34c753fSRafael Auler     //  movk ip0, #:abs_g2_nc:<addr>
1600a34c753fSRafael Auler     //  movk ip0, #:abs_g1_nc:<addr>
1601a34c753fSRafael Auler     //  movk ip0, #:abs_g0_nc:<addr>
1602a34c753fSRafael Auler     //  br ip0
1603a34c753fSRafael Auler     MCInst Inst;
1604a34c753fSRafael Auler     Inst.setOpcode(AArch64::MOVZXi);
1605a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1606a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
1607a34c753fSRafael Auler         MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
1608a34c753fSRafael Auler         AArch64MCExpr::VK_ABS_G3, *Ctx)));
1609a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0x30));
1610a34c753fSRafael Auler     Seq.emplace_back(Inst);
1611a34c753fSRafael Auler 
1612a34c753fSRafael Auler     Inst.clear();
1613a34c753fSRafael Auler     Inst.setOpcode(AArch64::MOVKXi);
1614a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1615a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1616a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
1617a34c753fSRafael Auler         MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
1618a34c753fSRafael Auler         AArch64MCExpr::VK_ABS_G2_NC, *Ctx)));
1619a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0x20));
1620a34c753fSRafael Auler     Seq.emplace_back(Inst);
1621a34c753fSRafael Auler 
1622a34c753fSRafael Auler     Inst.clear();
1623a34c753fSRafael Auler     Inst.setOpcode(AArch64::MOVKXi);
1624a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1625a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1626a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
1627a34c753fSRafael Auler         MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
1628a34c753fSRafael Auler         AArch64MCExpr::VK_ABS_G1_NC, *Ctx)));
1629a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0x10));
1630a34c753fSRafael Auler     Seq.emplace_back(Inst);
1631a34c753fSRafael Auler 
1632a34c753fSRafael Auler     Inst.clear();
1633a34c753fSRafael Auler     Inst.setOpcode(AArch64::MOVKXi);
1634a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1635a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1636a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
1637a34c753fSRafael Auler         MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
1638a34c753fSRafael Auler         AArch64MCExpr::VK_ABS_G0_NC, *Ctx)));
1639a34c753fSRafael Auler     Inst.addOperand(MCOperand::createImm(0));
1640a34c753fSRafael Auler     Seq.emplace_back(Inst);
1641a34c753fSRafael Auler 
1642a34c753fSRafael Auler     Inst.clear();
1643a34c753fSRafael Auler     Inst.setOpcode(AArch64::BR);
1644a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::X16));
1645a34c753fSRafael Auler     if (IsTailCall)
1646a34c753fSRafael Auler       setTailCall(Inst);
1647a34c753fSRafael Auler     Seq.emplace_back(Inst);
1648a34c753fSRafael Auler   }
1649a34c753fSRafael Auler 
165069706eafSMaksim Panchenko   void createShortJmp(InstructionListType &Seq, const MCSymbol *Target,
1651a34c753fSRafael Auler                       MCContext *Ctx, bool IsTailCall) override {
1652a34c753fSRafael Auler     // ip0 (r16) is reserved to the linker (refer to 5.3.1.1 of "Procedure Call
1653a34c753fSRafael Auler     //   Standard for the ARM 64-bit Architecture (AArch64)".
1654a34c753fSRafael Auler     // The sequence of instructions we create here is the following:
1655a34c753fSRafael Auler     //  adrp ip0, imm
1656a34c753fSRafael Auler     //  add ip0, ip0, imm
1657a34c753fSRafael Auler     //  br ip0
1658a34c753fSRafael Auler     MCPhysReg Reg = AArch64::X16;
165969706eafSMaksim Panchenko     InstructionListType Insts = materializeAddress(Target, Ctx, Reg);
1660a34c753fSRafael Auler     Insts.emplace_back();
1661a34c753fSRafael Auler     MCInst &Inst = Insts.back();
1662a34c753fSRafael Auler     Inst.clear();
1663a34c753fSRafael Auler     Inst.setOpcode(AArch64::BR);
1664a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(Reg));
1665a34c753fSRafael Auler     if (IsTailCall)
1666a34c753fSRafael Auler       setTailCall(Inst);
1667a34c753fSRafael Auler     Seq.swap(Insts);
1668a34c753fSRafael Auler   }
1669a34c753fSRafael Auler 
1670a34c753fSRafael Auler   /// Matching pattern here is
1671a34c753fSRafael Auler   ///
1672a34c753fSRafael Auler   ///    ADRP  x16, imm
1673a34c753fSRafael Auler   ///    ADD   x16, x16, imm
1674a34c753fSRafael Auler   ///    BR    x16
1675a34c753fSRafael Auler   ///
167635efe1d8SVladislav Khmelevsky   uint64_t matchLinkerVeneer(InstructionIterator Begin, InstructionIterator End,
1677a34c753fSRafael Auler                              uint64_t Address, const MCInst &CurInst,
1678a34c753fSRafael Auler                              MCInst *&TargetHiBits, MCInst *&TargetLowBits,
1679a34c753fSRafael Auler                              uint64_t &Target) const override {
1680a34c753fSRafael Auler     if (CurInst.getOpcode() != AArch64::BR || !CurInst.getOperand(0).isReg() ||
1681a34c753fSRafael Auler         CurInst.getOperand(0).getReg() != AArch64::X16)
168235efe1d8SVladislav Khmelevsky       return 0;
1683a34c753fSRafael Auler 
1684a34c753fSRafael Auler     auto I = End;
1685a34c753fSRafael Auler     if (I == Begin)
168635efe1d8SVladislav Khmelevsky       return 0;
1687a34c753fSRafael Auler 
1688a34c753fSRafael Auler     --I;
1689a34c753fSRafael Auler     Address -= 4;
16908aab58baSMaksim Panchenko     if (I == Begin || I->getOpcode() != AArch64::ADDXri ||
16918aab58baSMaksim Panchenko         MCPlus::getNumPrimeOperands(*I) < 3 || !I->getOperand(0).isReg() ||
1692a34c753fSRafael Auler         !I->getOperand(1).isReg() ||
1693a34c753fSRafael Auler         I->getOperand(0).getReg() != AArch64::X16 ||
16948aab58baSMaksim Panchenko         I->getOperand(1).getReg() != AArch64::X16 || !I->getOperand(2).isImm())
169535efe1d8SVladislav Khmelevsky       return 0;
1696a34c753fSRafael Auler     TargetLowBits = &*I;
1697a34c753fSRafael Auler     uint64_t Addr = I->getOperand(2).getImm() & 0xFFF;
1698a34c753fSRafael Auler 
1699a34c753fSRafael Auler     --I;
1700a34c753fSRafael Auler     Address -= 4;
1701a34c753fSRafael Auler     if (I->getOpcode() != AArch64::ADRP ||
17028aab58baSMaksim Panchenko         MCPlus::getNumPrimeOperands(*I) < 2 || !I->getOperand(0).isReg() ||
17038aab58baSMaksim Panchenko         !I->getOperand(1).isImm() || I->getOperand(0).getReg() != AArch64::X16)
170435efe1d8SVladislav Khmelevsky       return 0;
1705a34c753fSRafael Auler     TargetHiBits = &*I;
1706a34c753fSRafael Auler     Addr |= (Address + ((int64_t)I->getOperand(1).getImm() << 12)) &
1707a34c753fSRafael Auler             0xFFFFFFFFFFFFF000ULL;
1708a34c753fSRafael Auler     Target = Addr;
170935efe1d8SVladislav Khmelevsky     return 3;
1710a34c753fSRafael Auler   }
1711a34c753fSRafael Auler 
1712be89e794SMaksim Panchenko   /// Match the following pattern:
1713be89e794SMaksim Panchenko   ///
1714be89e794SMaksim Panchenko   ///   LDR x16, .L1
1715be89e794SMaksim Panchenko   ///   BR  x16
1716be89e794SMaksim Panchenko   /// L1:
1717be89e794SMaksim Panchenko   ///   .quad Target
1718be89e794SMaksim Panchenko   ///
1719be89e794SMaksim Panchenko   /// Populate \p TargetAddress with the Target value on successful match.
1720be89e794SMaksim Panchenko   bool matchAbsLongVeneer(const BinaryFunction &BF,
1721be89e794SMaksim Panchenko                           uint64_t &TargetAddress) const override {
1722be89e794SMaksim Panchenko     if (BF.size() != 1 || BF.getMaxSize() < 16)
1723be89e794SMaksim Panchenko       return false;
1724be89e794SMaksim Panchenko 
1725be89e794SMaksim Panchenko     if (!BF.hasConstantIsland())
1726be89e794SMaksim Panchenko       return false;
1727be89e794SMaksim Panchenko 
1728be89e794SMaksim Panchenko     const BinaryBasicBlock &BB = BF.front();
1729be89e794SMaksim Panchenko     if (BB.size() != 2)
1730be89e794SMaksim Panchenko       return false;
1731be89e794SMaksim Panchenko 
1732be89e794SMaksim Panchenko     const MCInst &LDRInst = BB.getInstructionAtIndex(0);
1733be89e794SMaksim Panchenko     if (LDRInst.getOpcode() != AArch64::LDRXl)
1734be89e794SMaksim Panchenko       return false;
1735be89e794SMaksim Panchenko 
1736be89e794SMaksim Panchenko     if (!LDRInst.getOperand(0).isReg() ||
1737be89e794SMaksim Panchenko         LDRInst.getOperand(0).getReg() != AArch64::X16)
1738be89e794SMaksim Panchenko       return false;
1739be89e794SMaksim Panchenko 
1740be89e794SMaksim Panchenko     const MCSymbol *TargetSym = getTargetSymbol(LDRInst, 1);
1741be89e794SMaksim Panchenko     if (!TargetSym)
1742be89e794SMaksim Panchenko       return false;
1743be89e794SMaksim Panchenko 
1744be89e794SMaksim Panchenko     const MCInst &BRInst = BB.getInstructionAtIndex(1);
1745be89e794SMaksim Panchenko     if (BRInst.getOpcode() != AArch64::BR)
1746be89e794SMaksim Panchenko       return false;
1747be89e794SMaksim Panchenko     if (!BRInst.getOperand(0).isReg() ||
1748be89e794SMaksim Panchenko         BRInst.getOperand(0).getReg() != AArch64::X16)
1749be89e794SMaksim Panchenko       return false;
1750be89e794SMaksim Panchenko 
1751be89e794SMaksim Panchenko     const BinaryFunction::IslandInfo &IInfo = BF.getIslandInfo();
1752be89e794SMaksim Panchenko     if (IInfo.HasDynamicRelocations)
1753be89e794SMaksim Panchenko       return false;
1754be89e794SMaksim Panchenko 
1755be89e794SMaksim Panchenko     auto Iter = IInfo.Offsets.find(8);
1756be89e794SMaksim Panchenko     if (Iter == IInfo.Offsets.end() || Iter->second != TargetSym)
1757be89e794SMaksim Panchenko       return false;
1758be89e794SMaksim Panchenko 
1759be89e794SMaksim Panchenko     // Extract the absolute value stored inside the island.
1760be89e794SMaksim Panchenko     StringRef SectionContents = BF.getOriginSection()->getContents();
1761be89e794SMaksim Panchenko     StringRef FunctionContents = SectionContents.substr(
1762be89e794SMaksim Panchenko         BF.getAddress() - BF.getOriginSection()->getAddress(), BF.getMaxSize());
1763be89e794SMaksim Panchenko 
1764be89e794SMaksim Panchenko     const BinaryContext &BC = BF.getBinaryContext();
1765be89e794SMaksim Panchenko     DataExtractor DE(FunctionContents, BC.AsmInfo->isLittleEndian(),
1766be89e794SMaksim Panchenko                      BC.AsmInfo->getCodePointerSize());
1767be89e794SMaksim Panchenko     uint64_t Offset = 8;
1768be89e794SMaksim Panchenko     TargetAddress = DE.getAddress(&Offset);
1769be89e794SMaksim Panchenko 
1770be89e794SMaksim Panchenko     return true;
1771be89e794SMaksim Panchenko   }
1772be89e794SMaksim Panchenko 
177317ed8f29SVladislav Khmelevsky   bool matchAdrpAddPair(const MCInst &Adrp, const MCInst &Add) const override {
177417ed8f29SVladislav Khmelevsky     if (!isADRP(Adrp) || !isAddXri(Add))
177517ed8f29SVladislav Khmelevsky       return false;
177617ed8f29SVladislav Khmelevsky 
177717ed8f29SVladislav Khmelevsky     assert(Adrp.getOperand(0).isReg() &&
177817ed8f29SVladislav Khmelevsky            "Unexpected operand in ADRP instruction");
177917ed8f29SVladislav Khmelevsky     MCPhysReg AdrpReg = Adrp.getOperand(0).getReg();
178017ed8f29SVladislav Khmelevsky     assert(Add.getOperand(1).isReg() &&
178117ed8f29SVladislav Khmelevsky            "Unexpected operand in ADDXri instruction");
178217ed8f29SVladislav Khmelevsky     MCPhysReg AddReg = Add.getOperand(1).getReg();
178317ed8f29SVladislav Khmelevsky     return AdrpReg == AddReg;
178417ed8f29SVladislav Khmelevsky   }
178517ed8f29SVladislav Khmelevsky 
1786a34c753fSRafael Auler   bool replaceImmWithSymbolRef(MCInst &Inst, const MCSymbol *Symbol,
1787a34c753fSRafael Auler                                int64_t Addend, MCContext *Ctx, int64_t &Value,
1788a34c753fSRafael Auler                                uint64_t RelType) const override {
1789a34c753fSRafael Auler     unsigned ImmOpNo = -1U;
1790a34c753fSRafael Auler     for (unsigned Index = 0; Index < MCPlus::getNumPrimeOperands(Inst);
1791a34c753fSRafael Auler          ++Index) {
1792a34c753fSRafael Auler       if (Inst.getOperand(Index).isImm()) {
1793a34c753fSRafael Auler         ImmOpNo = Index;
1794a34c753fSRafael Auler         break;
1795a34c753fSRafael Auler       }
1796a34c753fSRafael Auler     }
1797a34c753fSRafael Auler     if (ImmOpNo == -1U)
1798a34c753fSRafael Auler       return false;
1799a34c753fSRafael Auler 
1800a34c753fSRafael Auler     Value = Inst.getOperand(ImmOpNo).getImm();
1801a34c753fSRafael Auler 
1802a34c753fSRafael Auler     setOperandToSymbolRef(Inst, ImmOpNo, Symbol, Addend, Ctx, RelType);
1803a34c753fSRafael Auler 
1804a34c753fSRafael Auler     return true;
1805a34c753fSRafael Auler   }
1806a34c753fSRafael Auler 
1807bba790dbSMaksim Panchenko   void createUncondBranch(MCInst &Inst, const MCSymbol *TBB,
1808a34c753fSRafael Auler                           MCContext *Ctx) const override {
1809a34c753fSRafael Auler     Inst.setOpcode(AArch64::B);
1810a34c753fSRafael Auler     Inst.clear();
1811a34c753fSRafael Auler     Inst.addOperand(MCOperand::createExpr(getTargetExprFor(
1812a34c753fSRafael Auler         Inst, MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx),
1813a34c753fSRafael Auler         *Ctx, 0)));
1814a34c753fSRafael Auler   }
1815a34c753fSRafael Auler 
1816edda8577SAmir Ayupov   bool shouldRecordCodeRelocation(uint64_t RelType) const override {
1817edda8577SAmir Ayupov     switch (RelType) {
1818edda8577SAmir Ayupov     case ELF::R_AARCH64_ABS64:
1819edda8577SAmir Ayupov     case ELF::R_AARCH64_ABS32:
1820edda8577SAmir Ayupov     case ELF::R_AARCH64_ABS16:
1821edda8577SAmir Ayupov     case ELF::R_AARCH64_ADD_ABS_LO12_NC:
1822edda8577SAmir Ayupov     case ELF::R_AARCH64_ADR_GOT_PAGE:
1823edda8577SAmir Ayupov     case ELF::R_AARCH64_ADR_PREL_LO21:
1824edda8577SAmir Ayupov     case ELF::R_AARCH64_ADR_PREL_PG_HI21:
1825edda8577SAmir Ayupov     case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC:
1826edda8577SAmir Ayupov     case ELF::R_AARCH64_LD64_GOT_LO12_NC:
1827edda8577SAmir Ayupov     case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
1828edda8577SAmir Ayupov     case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
1829edda8577SAmir Ayupov     case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
1830edda8577SAmir Ayupov     case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
1831edda8577SAmir Ayupov     case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
1832edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSDESC_ADD_LO12:
1833edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
1834edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
1835edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSDESC_LD64_LO12:
1836edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
1837edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
1838e11d49cbSAlexey Moksyakov     case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
1839e11d49cbSAlexey Moksyakov     case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
1840edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G0:
1841edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G0_NC:
1842edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G1:
1843edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G1_NC:
1844edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G2:
1845edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G2_NC:
1846edda8577SAmir Ayupov     case ELF::R_AARCH64_MOVW_UABS_G3:
1847edda8577SAmir Ayupov     case ELF::R_AARCH64_PREL16:
1848edda8577SAmir Ayupov     case ELF::R_AARCH64_PREL32:
1849edda8577SAmir Ayupov     case ELF::R_AARCH64_PREL64:
1850edda8577SAmir Ayupov       return true;
1851edda8577SAmir Ayupov     case ELF::R_AARCH64_CALL26:
1852edda8577SAmir Ayupov     case ELF::R_AARCH64_JUMP26:
1853edda8577SAmir Ayupov     case ELF::R_AARCH64_TSTBR14:
1854edda8577SAmir Ayupov     case ELF::R_AARCH64_CONDBR19:
1855edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSDESC_CALL:
1856edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
1857edda8577SAmir Ayupov     case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
1858edda8577SAmir Ayupov       return false;
1859edda8577SAmir Ayupov     default:
1860edda8577SAmir Ayupov       llvm_unreachable("Unexpected AArch64 relocation type in code");
1861edda8577SAmir Ayupov     }
1862edda8577SAmir Ayupov   }
1863edda8577SAmir Ayupov 
186428fd2ca1SDenis Revunov   StringRef getTrapFillValue() const override {
186528fd2ca1SDenis Revunov     return StringRef("\0\0\0\0", 4);
186628fd2ca1SDenis Revunov   }
186728fd2ca1SDenis Revunov 
1868bba790dbSMaksim Panchenko   void createReturn(MCInst &Inst) const override {
1869a34c753fSRafael Auler     Inst.setOpcode(AArch64::RET);
1870a34c753fSRafael Auler     Inst.clear();
1871a34c753fSRafael Auler     Inst.addOperand(MCOperand::createReg(AArch64::LR));
1872a34c753fSRafael Auler   }
1873a34c753fSRafael Auler 
1874bba790dbSMaksim Panchenko   void createStackPointerIncrement(
18756e4c2305SElvina Yakubova       MCInst &Inst, int Size,
18766e4c2305SElvina Yakubova       bool NoFlagsClobber = false /*unused for AArch64*/) const override {
18776e4c2305SElvina Yakubova     Inst.setOpcode(AArch64::SUBXri);
18786e4c2305SElvina Yakubova     Inst.clear();
18796e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(AArch64::SP));
18806e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(AArch64::SP));
18816e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(Size));
18826e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(0));
18836e4c2305SElvina Yakubova   }
18846e4c2305SElvina Yakubova 
1885bba790dbSMaksim Panchenko   void createStackPointerDecrement(
18866e4c2305SElvina Yakubova       MCInst &Inst, int Size,
18876e4c2305SElvina Yakubova       bool NoFlagsClobber = false /*unused for AArch64*/) const override {
18886e4c2305SElvina Yakubova     Inst.setOpcode(AArch64::ADDXri);
18896e4c2305SElvina Yakubova     Inst.clear();
18906e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(AArch64::SP));
18916e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(AArch64::SP));
18926e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(Size));
18936e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createImm(0));
18946e4c2305SElvina Yakubova   }
18956e4c2305SElvina Yakubova 
18966e4c2305SElvina Yakubova   void createIndirectBranch(MCInst &Inst, MCPhysReg MemBaseReg,
18976e4c2305SElvina Yakubova                             int64_t Disp) const {
18986e4c2305SElvina Yakubova     Inst.setOpcode(AArch64::BR);
189959ab86bbSMaksim Panchenko     Inst.clear();
19006e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(MemBaseReg));
19016e4c2305SElvina Yakubova   }
19026e4c2305SElvina Yakubova 
19036e4c2305SElvina Yakubova   InstructionListType createInstrumentedIndCallHandlerExitBB() const override {
19046e4c2305SElvina Yakubova     InstructionListType Insts(5);
19056e4c2305SElvina Yakubova     // Code sequence for instrumented indirect call handler:
19066e4c2305SElvina Yakubova     //   msr  nzcv, x1
19076e4c2305SElvina Yakubova     //   ldp  x0, x1, [sp], #16
19086e4c2305SElvina Yakubova     //   ldr  x16, [sp], #16
19096e4c2305SElvina Yakubova     //   ldp  x0, x1, [sp], #16
19106e4c2305SElvina Yakubova     //   br   x16
19116e4c2305SElvina Yakubova     setSystemFlag(Insts[0], AArch64::X1);
19126e4c2305SElvina Yakubova     createPopRegisters(Insts[1], AArch64::X0, AArch64::X1);
19136e4c2305SElvina Yakubova     // Here we load address of the next function which should be called in the
19146e4c2305SElvina Yakubova     // original binary to X16 register. Writing to X16 is permitted without
19156e4c2305SElvina Yakubova     // needing to restore.
19166e4c2305SElvina Yakubova     loadReg(Insts[2], AArch64::X16, AArch64::SP);
19176e4c2305SElvina Yakubova     createPopRegisters(Insts[3], AArch64::X0, AArch64::X1);
19186e4c2305SElvina Yakubova     createIndirectBranch(Insts[4], AArch64::X16, 0);
19196e4c2305SElvina Yakubova     return Insts;
19206e4c2305SElvina Yakubova   }
19216e4c2305SElvina Yakubova 
19226e4c2305SElvina Yakubova   InstructionListType
19236e4c2305SElvina Yakubova   createInstrumentedIndTailCallHandlerExitBB() const override {
19246e4c2305SElvina Yakubova     return createInstrumentedIndCallHandlerExitBB();
19256e4c2305SElvina Yakubova   }
19266e4c2305SElvina Yakubova 
192770405a0bSElvina Yakubova   InstructionListType createGetter(MCContext *Ctx, const char *name) const {
192870405a0bSElvina Yakubova     InstructionListType Insts(4);
192970405a0bSElvina Yakubova     MCSymbol *Locs = Ctx->getOrCreateSymbol(name);
193070405a0bSElvina Yakubova     InstructionListType Addr = materializeAddress(Locs, Ctx, AArch64::X0);
193170405a0bSElvina Yakubova     std::copy(Addr.begin(), Addr.end(), Insts.begin());
193270405a0bSElvina Yakubova     assert(Addr.size() == 2 && "Invalid Addr size");
193370405a0bSElvina Yakubova     loadReg(Insts[2], AArch64::X0, AArch64::X0);
193470405a0bSElvina Yakubova     createReturn(Insts[3]);
193570405a0bSElvina Yakubova     return Insts;
193670405a0bSElvina Yakubova   }
193770405a0bSElvina Yakubova 
193870405a0bSElvina Yakubova   InstructionListType createNumCountersGetter(MCContext *Ctx) const override {
193970405a0bSElvina Yakubova     return createGetter(Ctx, "__bolt_num_counters");
194070405a0bSElvina Yakubova   }
194170405a0bSElvina Yakubova 
194270405a0bSElvina Yakubova   InstructionListType
194370405a0bSElvina Yakubova   createInstrLocationsGetter(MCContext *Ctx) const override {
194470405a0bSElvina Yakubova     return createGetter(Ctx, "__bolt_instr_locations");
194570405a0bSElvina Yakubova   }
194670405a0bSElvina Yakubova 
194770405a0bSElvina Yakubova   InstructionListType createInstrTablesGetter(MCContext *Ctx) const override {
194870405a0bSElvina Yakubova     return createGetter(Ctx, "__bolt_instr_tables");
194970405a0bSElvina Yakubova   }
195070405a0bSElvina Yakubova 
195170405a0bSElvina Yakubova   InstructionListType createInstrNumFuncsGetter(MCContext *Ctx) const override {
195270405a0bSElvina Yakubova     return createGetter(Ctx, "__bolt_instr_num_funcs");
195370405a0bSElvina Yakubova   }
195470405a0bSElvina Yakubova 
19556e4c2305SElvina Yakubova   void convertIndirectCallToLoad(MCInst &Inst, MCPhysReg Reg) override {
19566e4c2305SElvina Yakubova     bool IsTailCall = isTailCall(Inst);
19576e4c2305SElvina Yakubova     if (IsTailCall)
19586e4c2305SElvina Yakubova       removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
19596e4c2305SElvina Yakubova     if (Inst.getOpcode() == AArch64::BR || Inst.getOpcode() == AArch64::BLR) {
19606e4c2305SElvina Yakubova       Inst.setOpcode(AArch64::ORRXrs);
19616e4c2305SElvina Yakubova       Inst.insert(Inst.begin(), MCOperand::createReg(Reg));
19626e4c2305SElvina Yakubova       Inst.insert(Inst.begin() + 1, MCOperand::createReg(AArch64::XZR));
19636e4c2305SElvina Yakubova       Inst.insert(Inst.begin() + 3, MCOperand::createImm(0));
19646e4c2305SElvina Yakubova       return;
19656e4c2305SElvina Yakubova     }
19666e4c2305SElvina Yakubova     llvm_unreachable("not implemented");
19676e4c2305SElvina Yakubova   }
19686e4c2305SElvina Yakubova 
19696e4c2305SElvina Yakubova   InstructionListType createLoadImmediate(const MCPhysReg Dest,
19706e4c2305SElvina Yakubova                                           uint64_t Imm) const override {
19716e4c2305SElvina Yakubova     InstructionListType Insts(4);
19726e4c2305SElvina Yakubova     int Shift = 48;
19736e4c2305SElvina Yakubova     for (int I = 0; I < 4; I++, Shift -= 16) {
19746e4c2305SElvina Yakubova       Insts[I].setOpcode(AArch64::MOVKXi);
19756e4c2305SElvina Yakubova       Insts[I].addOperand(MCOperand::createReg(Dest));
19766e4c2305SElvina Yakubova       Insts[I].addOperand(MCOperand::createReg(Dest));
19776e4c2305SElvina Yakubova       Insts[I].addOperand(MCOperand::createImm((Imm >> Shift) & 0xFFFF));
19786e4c2305SElvina Yakubova       Insts[I].addOperand(MCOperand::createImm(Shift));
19796e4c2305SElvina Yakubova     }
19806e4c2305SElvina Yakubova     return Insts;
19816e4c2305SElvina Yakubova   }
19826e4c2305SElvina Yakubova 
19836e4c2305SElvina Yakubova   void createIndirectCallInst(MCInst &Inst, bool IsTailCall,
19846e4c2305SElvina Yakubova                               MCPhysReg Reg) const {
19856e4c2305SElvina Yakubova     Inst.clear();
19866e4c2305SElvina Yakubova     Inst.setOpcode(IsTailCall ? AArch64::BR : AArch64::BLR);
19876e4c2305SElvina Yakubova     Inst.addOperand(MCOperand::createReg(Reg));
19886e4c2305SElvina Yakubova   }
19896e4c2305SElvina Yakubova 
19906e4c2305SElvina Yakubova   InstructionListType createInstrumentedIndirectCall(MCInst &&CallInst,
19916e4c2305SElvina Yakubova                                                      MCSymbol *HandlerFuncAddr,
19926e4c2305SElvina Yakubova                                                      int CallSiteID,
19936e4c2305SElvina Yakubova                                                      MCContext *Ctx) override {
19946e4c2305SElvina Yakubova     InstructionListType Insts;
19956e4c2305SElvina Yakubova     // Code sequence used to enter indirect call instrumentation helper:
19966e4c2305SElvina Yakubova     //   stp x0, x1, [sp, #-16]! createPushRegisters
19976e4c2305SElvina Yakubova     //   mov target x0  convertIndirectCallToLoad -> orr x0 target xzr
19986e4c2305SElvina Yakubova     //   mov x1 CallSiteID createLoadImmediate ->
19996e4c2305SElvina Yakubova     //   movk    x1, #0x0, lsl #48
20006e4c2305SElvina Yakubova     //   movk    x1, #0x0, lsl #32
20016e4c2305SElvina Yakubova     //   movk    x1, #0x0, lsl #16
20026e4c2305SElvina Yakubova     //   movk    x1, #0x0
20036e4c2305SElvina Yakubova     //   stp x0, x1, [sp, #-16]!
20046e4c2305SElvina Yakubova     //   bl *HandlerFuncAddr createIndirectCall ->
20056e4c2305SElvina Yakubova     //   adr x0 *HandlerFuncAddr -> adrp + add
20066e4c2305SElvina Yakubova     //   blr x0
20076e4c2305SElvina Yakubova     Insts.emplace_back();
20086e4c2305SElvina Yakubova     createPushRegisters(Insts.back(), AArch64::X0, AArch64::X1);
20096e4c2305SElvina Yakubova     Insts.emplace_back(CallInst);
20106e4c2305SElvina Yakubova     convertIndirectCallToLoad(Insts.back(), AArch64::X0);
20116e4c2305SElvina Yakubova     InstructionListType LoadImm =
20126e4c2305SElvina Yakubova         createLoadImmediate(getIntArgRegister(1), CallSiteID);
20136e4c2305SElvina Yakubova     Insts.insert(Insts.end(), LoadImm.begin(), LoadImm.end());
20146e4c2305SElvina Yakubova     Insts.emplace_back();
20156e4c2305SElvina Yakubova     createPushRegisters(Insts.back(), AArch64::X0, AArch64::X1);
20166e4c2305SElvina Yakubova     Insts.resize(Insts.size() + 2);
20176e4c2305SElvina Yakubova     InstructionListType Addr =
20186e4c2305SElvina Yakubova         materializeAddress(HandlerFuncAddr, Ctx, AArch64::X0);
20196e4c2305SElvina Yakubova     assert(Addr.size() == 2 && "Invalid Addr size");
20206e4c2305SElvina Yakubova     std::copy(Addr.begin(), Addr.end(), Insts.end() - Addr.size());
20216e4c2305SElvina Yakubova     Insts.emplace_back();
20226e4c2305SElvina Yakubova     createIndirectCallInst(Insts.back(), isTailCall(CallInst), AArch64::X0);
20236e4c2305SElvina Yakubova 
20246e4c2305SElvina Yakubova     // Carry over metadata including tail call marker if present.
20256e4c2305SElvina Yakubova     stripAnnotations(Insts.back());
20266e4c2305SElvina Yakubova     moveAnnotations(std::move(CallInst), Insts.back());
20276e4c2305SElvina Yakubova 
20286e4c2305SElvina Yakubova     return Insts;
20296e4c2305SElvina Yakubova   }
20306e4c2305SElvina Yakubova 
20316e4c2305SElvina Yakubova   InstructionListType
20326e4c2305SElvina Yakubova   createInstrumentedIndCallHandlerEntryBB(const MCSymbol *InstrTrampoline,
20336e4c2305SElvina Yakubova                                           const MCSymbol *IndCallHandler,
20346e4c2305SElvina Yakubova                                           MCContext *Ctx) override {
20356e4c2305SElvina Yakubova     // Code sequence used to check whether InstrTampoline was initialized
20366e4c2305SElvina Yakubova     // and call it if so, returns via IndCallHandler
20376e4c2305SElvina Yakubova     //   stp     x0, x1, [sp, #-16]!
20386e4c2305SElvina Yakubova     //   mrs     x1, nzcv
20396e4c2305SElvina Yakubova     //   adr     x0, InstrTrampoline -> adrp + add
20406e4c2305SElvina Yakubova     //   ldr     x0, [x0]
20416e4c2305SElvina Yakubova     //   subs    x0, x0, #0x0
20426e4c2305SElvina Yakubova     //   b.eq    IndCallHandler
20436e4c2305SElvina Yakubova     //   str     x30, [sp, #-16]!
20446e4c2305SElvina Yakubova     //   blr     x0
20456e4c2305SElvina Yakubova     //   ldr     x30, [sp], #16
20466e4c2305SElvina Yakubova     //   b       IndCallHandler
20476e4c2305SElvina Yakubova     InstructionListType Insts;
20486e4c2305SElvina Yakubova     Insts.emplace_back();
20496e4c2305SElvina Yakubova     createPushRegisters(Insts.back(), AArch64::X0, AArch64::X1);
20506e4c2305SElvina Yakubova     Insts.emplace_back();
20516e4c2305SElvina Yakubova     getSystemFlag(Insts.back(), getIntArgRegister(1));
20526e4c2305SElvina Yakubova     Insts.emplace_back();
20536e4c2305SElvina Yakubova     Insts.emplace_back();
20546e4c2305SElvina Yakubova     InstructionListType Addr =
20556e4c2305SElvina Yakubova         materializeAddress(InstrTrampoline, Ctx, AArch64::X0);
20566e4c2305SElvina Yakubova     std::copy(Addr.begin(), Addr.end(), Insts.end() - Addr.size());
20576e4c2305SElvina Yakubova     assert(Addr.size() == 2 && "Invalid Addr size");
20586e4c2305SElvina Yakubova     Insts.emplace_back();
20596e4c2305SElvina Yakubova     loadReg(Insts.back(), AArch64::X0, AArch64::X0);
20606e4c2305SElvina Yakubova     InstructionListType cmpJmp =
20616e4c2305SElvina Yakubova         createCmpJE(AArch64::X0, 0, IndCallHandler, Ctx);
20626e4c2305SElvina Yakubova     Insts.insert(Insts.end(), cmpJmp.begin(), cmpJmp.end());
20636e4c2305SElvina Yakubova     Insts.emplace_back();
20646e4c2305SElvina Yakubova     storeReg(Insts.back(), AArch64::LR, AArch64::SP);
20656e4c2305SElvina Yakubova     Insts.emplace_back();
20666e4c2305SElvina Yakubova     Insts.back().setOpcode(AArch64::BLR);
20676e4c2305SElvina Yakubova     Insts.back().addOperand(MCOperand::createReg(AArch64::X0));
20686e4c2305SElvina Yakubova     Insts.emplace_back();
20696e4c2305SElvina Yakubova     loadReg(Insts.back(), AArch64::LR, AArch64::SP);
20706e4c2305SElvina Yakubova     Insts.emplace_back();
20716e4c2305SElvina Yakubova     createDirectCall(Insts.back(), IndCallHandler, Ctx, /*IsTailCall*/ true);
20726e4c2305SElvina Yakubova     return Insts;
20736e4c2305SElvina Yakubova   }
20746e4c2305SElvina Yakubova 
20756e4c2305SElvina Yakubova   InstructionListType
20766e4c2305SElvina Yakubova   createInstrIncMemory(const MCSymbol *Target, MCContext *Ctx, bool IsLeaf,
20776e4c2305SElvina Yakubova                        unsigned CodePointerSize) const override {
20786e4c2305SElvina Yakubova     unsigned int I = 0;
20796e4c2305SElvina Yakubova     InstructionListType Instrs(IsLeaf ? 12 : 10);
20806e4c2305SElvina Yakubova 
20816e4c2305SElvina Yakubova     if (IsLeaf)
20826e4c2305SElvina Yakubova       createStackPointerIncrement(Instrs[I++], 128);
20836e4c2305SElvina Yakubova     createPushRegisters(Instrs[I++], AArch64::X0, AArch64::X1);
20846e4c2305SElvina Yakubova     getSystemFlag(Instrs[I++], AArch64::X1);
20856e4c2305SElvina Yakubova     InstructionListType Addr = materializeAddress(Target, Ctx, AArch64::X0);
20866e4c2305SElvina Yakubova     assert(Addr.size() == 2 && "Invalid Addr size");
20876e4c2305SElvina Yakubova     std::copy(Addr.begin(), Addr.end(), Instrs.begin() + I);
20886e4c2305SElvina Yakubova     I += Addr.size();
20896e4c2305SElvina Yakubova     storeReg(Instrs[I++], AArch64::X2, AArch64::SP);
20906e4c2305SElvina Yakubova     InstructionListType Insts = createIncMemory(AArch64::X0, AArch64::X2);
20916e4c2305SElvina Yakubova     assert(Insts.size() == 2 && "Invalid Insts size");
20926e4c2305SElvina Yakubova     std::copy(Insts.begin(), Insts.end(), Instrs.begin() + I);
20936e4c2305SElvina Yakubova     I += Insts.size();
20946e4c2305SElvina Yakubova     loadReg(Instrs[I++], AArch64::X2, AArch64::SP);
20956e4c2305SElvina Yakubova     setSystemFlag(Instrs[I++], AArch64::X1);
20966e4c2305SElvina Yakubova     createPopRegisters(Instrs[I++], AArch64::X0, AArch64::X1);
20976e4c2305SElvina Yakubova     if (IsLeaf)
20986e4c2305SElvina Yakubova       createStackPointerDecrement(Instrs[I++], 128);
20996e4c2305SElvina Yakubova     return Instrs;
21006e4c2305SElvina Yakubova   }
21016e4c2305SElvina Yakubova 
21026e4c2305SElvina Yakubova   std::vector<MCInst> createSymbolTrampoline(const MCSymbol *TgtSym,
21036e4c2305SElvina Yakubova                                              MCContext *Ctx) override {
21046e4c2305SElvina Yakubova     std::vector<MCInst> Insts;
21056e4c2305SElvina Yakubova     createShortJmp(Insts, TgtSym, Ctx, /*IsTailCall*/ true);
21066e4c2305SElvina Yakubova     return Insts;
21076e4c2305SElvina Yakubova   }
21086e4c2305SElvina Yakubova 
210969706eafSMaksim Panchenko   InstructionListType materializeAddress(const MCSymbol *Target, MCContext *Ctx,
2110a34c753fSRafael Auler                                          MCPhysReg RegName,
2111a34c753fSRafael Auler                                          int64_t Addend = 0) const override {
2112a34c753fSRafael Auler     // Get page-aligned address and add page offset
211369706eafSMaksim Panchenko     InstructionListType Insts(2);
2114a34c753fSRafael Auler     Insts[0].setOpcode(AArch64::ADRP);
2115a34c753fSRafael Auler     Insts[0].clear();
2116a34c753fSRafael Auler     Insts[0].addOperand(MCOperand::createReg(RegName));
2117a34c753fSRafael Auler     Insts[0].addOperand(MCOperand::createImm(0));
2118a34c753fSRafael Auler     setOperandToSymbolRef(Insts[0], /* OpNum */ 1, Target, Addend, Ctx,
2119a34c753fSRafael Auler                           ELF::R_AARCH64_NONE);
2120a34c753fSRafael Auler     Insts[1].setOpcode(AArch64::ADDXri);
2121a34c753fSRafael Auler     Insts[1].clear();
2122a34c753fSRafael Auler     Insts[1].addOperand(MCOperand::createReg(RegName));
2123a34c753fSRafael Auler     Insts[1].addOperand(MCOperand::createReg(RegName));
2124a34c753fSRafael Auler     Insts[1].addOperand(MCOperand::createImm(0));
2125a34c753fSRafael Auler     Insts[1].addOperand(MCOperand::createImm(0));
2126a34c753fSRafael Auler     setOperandToSymbolRef(Insts[1], /* OpNum */ 2, Target, Addend, Ctx,
2127a34c753fSRafael Auler                           ELF::R_AARCH64_ADD_ABS_LO12_NC);
2128a34c753fSRafael Auler     return Insts;
2129a34c753fSRafael Auler   }
213062020a3aSzhoujiapeng 
213162020a3aSzhoujiapeng   std::optional<Relocation>
213262020a3aSzhoujiapeng   createRelocation(const MCFixup &Fixup,
213362020a3aSzhoujiapeng                    const MCAsmBackend &MAB) const override {
213462020a3aSzhoujiapeng     const MCFixupKindInfo &FKI = MAB.getFixupKindInfo(Fixup.getKind());
213562020a3aSzhoujiapeng 
213662020a3aSzhoujiapeng     assert(FKI.TargetOffset == 0 && "0-bit relocation offset expected");
213762020a3aSzhoujiapeng     const uint64_t RelOffset = Fixup.getOffset();
213862020a3aSzhoujiapeng 
213962020a3aSzhoujiapeng     uint64_t RelType;
214062020a3aSzhoujiapeng     if (Fixup.getKind() == MCFixupKind(AArch64::fixup_aarch64_pcrel_call26))
214162020a3aSzhoujiapeng       RelType = ELF::R_AARCH64_CALL26;
214271c2a132Ssinan     else if (Fixup.getKind() ==
214371c2a132Ssinan              MCFixupKind(AArch64::fixup_aarch64_pcrel_branch26))
214471c2a132Ssinan       RelType = ELF::R_AARCH64_JUMP26;
214562020a3aSzhoujiapeng     else if (FKI.Flags & MCFixupKindInfo::FKF_IsPCRel) {
214662020a3aSzhoujiapeng       switch (FKI.TargetSize) {
214762020a3aSzhoujiapeng       default:
214862020a3aSzhoujiapeng         return std::nullopt;
214962020a3aSzhoujiapeng       case 16:
215062020a3aSzhoujiapeng         RelType = ELF::R_AARCH64_PREL16;
215162020a3aSzhoujiapeng         break;
215262020a3aSzhoujiapeng       case 32:
215362020a3aSzhoujiapeng         RelType = ELF::R_AARCH64_PREL32;
215462020a3aSzhoujiapeng         break;
215562020a3aSzhoujiapeng       case 64:
215662020a3aSzhoujiapeng         RelType = ELF::R_AARCH64_PREL64;
215762020a3aSzhoujiapeng         break;
215862020a3aSzhoujiapeng       }
215962020a3aSzhoujiapeng     } else {
216062020a3aSzhoujiapeng       switch (FKI.TargetSize) {
216162020a3aSzhoujiapeng       default:
216262020a3aSzhoujiapeng         return std::nullopt;
216362020a3aSzhoujiapeng       case 16:
216462020a3aSzhoujiapeng         RelType = ELF::R_AARCH64_ABS16;
216562020a3aSzhoujiapeng         break;
216662020a3aSzhoujiapeng       case 32:
216762020a3aSzhoujiapeng         RelType = ELF::R_AARCH64_ABS32;
216862020a3aSzhoujiapeng         break;
216962020a3aSzhoujiapeng       case 64:
217062020a3aSzhoujiapeng         RelType = ELF::R_AARCH64_ABS64;
217162020a3aSzhoujiapeng         break;
217262020a3aSzhoujiapeng       }
217362020a3aSzhoujiapeng     }
217462020a3aSzhoujiapeng 
217562020a3aSzhoujiapeng     auto [RelSymbol, RelAddend] = extractFixupExpr(Fixup);
217662020a3aSzhoujiapeng 
217762020a3aSzhoujiapeng     return Relocation({RelOffset, RelSymbol, RelType, RelAddend, 0});
217862020a3aSzhoujiapeng   }
2179b6b49288SJob Noorman 
2180b6b49288SJob Noorman   uint16_t getMinFunctionAlignment() const override { return 4; }
21811fa02b96SNicholas 
21821fa02b96SNicholas   std::optional<uint32_t>
21831fa02b96SNicholas   getInstructionSize(const MCInst &Inst) const override {
21841fa02b96SNicholas     return 4;
21851fa02b96SNicholas   }
2186a34c753fSRafael Auler };
2187a34c753fSRafael Auler 
2188a34c753fSRafael Auler } // end anonymous namespace
2189a34c753fSRafael Auler 
2190a34c753fSRafael Auler namespace llvm {
2191a34c753fSRafael Auler namespace bolt {
2192a34c753fSRafael Auler 
2193a34c753fSRafael Auler MCPlusBuilder *createAArch64MCPlusBuilder(const MCInstrAnalysis *Analysis,
2194a34c753fSRafael Auler                                           const MCInstrInfo *Info,
21958fb83bf5SJob Noorman                                           const MCRegisterInfo *RegInfo,
21968fb83bf5SJob Noorman                                           const MCSubtargetInfo *STI) {
21978fb83bf5SJob Noorman   return new AArch64MCPlusBuilder(Analysis, Info, RegInfo, STI);
2198a34c753fSRafael Auler }
2199a34c753fSRafael Auler 
220040c2e0faSMaksim Panchenko } // namespace bolt
220140c2e0faSMaksim Panchenko } // namespace llvm
2202