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