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