| 1 | //===- MCExpr.cpp - Assembly Level Expression Implementation --------------===// |
| 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 | #include "llvm/MC/MCExpr.h" |
| 10 | #include "llvm/ADT/ScopeExit.h" |
| 11 | #include "llvm/ADT/Statistic.h" |
| 12 | #include "llvm/Config/llvm-config.h" |
| 13 | #include "llvm/MC/MCAsmBackend.h" |
| 14 | #include "llvm/MC/MCAsmInfo.h" |
| 15 | #include "llvm/MC/MCAssembler.h" |
| 16 | #include "llvm/MC/MCContext.h" |
| 17 | #include "llvm/MC/MCObjectWriter.h" |
| 18 | #include "llvm/MC/MCStreamer.h" |
| 19 | #include "llvm/MC/MCSymbol.h" |
| 20 | #include "llvm/MC/MCValue.h" |
| 21 | #include "llvm/Support/Casting.h" |
| 22 | #include "llvm/Support/Compiler.h" |
| 23 | #include "llvm/Support/Debug.h" |
| 24 | #include "llvm/Support/ErrorHandling.h" |
| 25 | #include "llvm/Support/raw_ostream.h" |
| 26 | #include <cassert> |
| 27 | #include <cstdint> |
| 28 | |
| 29 | using namespace llvm; |
| 30 | |
| 31 | #define DEBUG_TYPE "mcexpr" |
| 32 | |
| 33 | namespace { |
| 34 | namespace stats { |
| 35 | |
| 36 | STATISTIC(MCExprEvaluate, "Number of MCExpr evaluations" ); |
| 37 | |
| 38 | } // end namespace stats |
| 39 | } // end anonymous namespace |
| 40 | |
| 41 | static int getPrecedence(MCBinaryExpr::Opcode Op) { |
| 42 | switch (Op) { |
| 43 | case MCBinaryExpr::Add: |
| 44 | case MCBinaryExpr::Sub: |
| 45 | return 1; |
| 46 | default: |
| 47 | return 0; |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | // VariantKind printing and formatting utilize MAI. operator<< (dump and some |
| 52 | // target code) specifies MAI as nullptr and should be avoided when MAI is |
| 53 | // needed. |
| 54 | void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI, |
| 55 | int SurroundingPrec) const { |
| 56 | constexpr int MaxPrec = 9; |
| 57 | switch (getKind()) { |
| 58 | case MCExpr::Target: |
| 59 | return cast<MCTargetExpr>(Val: this)->printImpl(OS, MAI); |
| 60 | case MCExpr::Constant: { |
| 61 | auto Value = cast<MCConstantExpr>(Val: *this).getValue(); |
| 62 | auto PrintInHex = cast<MCConstantExpr>(Val: *this).useHexFormat(); |
| 63 | auto SizeInBytes = cast<MCConstantExpr>(Val: *this).getSizeInBytes(); |
| 64 | if (Value < 0 && MAI && !MAI->supportsSignedData()) |
| 65 | PrintInHex = true; |
| 66 | if (PrintInHex) |
| 67 | switch (SizeInBytes) { |
| 68 | default: |
| 69 | OS << "0x" << Twine::utohexstr(Val: Value); |
| 70 | break; |
| 71 | case 1: |
| 72 | OS << format(Fmt: "0x%02" PRIx64, Vals: Value); |
| 73 | break; |
| 74 | case 2: |
| 75 | OS << format(Fmt: "0x%04" PRIx64, Vals: Value); |
| 76 | break; |
| 77 | case 4: |
| 78 | OS << format(Fmt: "0x%08" PRIx64, Vals: Value); |
| 79 | break; |
| 80 | case 8: |
| 81 | OS << format(Fmt: "0x%016" PRIx64, Vals: Value); |
| 82 | break; |
| 83 | } |
| 84 | else |
| 85 | OS << Value; |
| 86 | return; |
| 87 | } |
| 88 | case MCExpr::SymbolRef: { |
| 89 | const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(Val: *this); |
| 90 | const MCSymbol &Sym = SRE.getSymbol(); |
| 91 | Sym.print(OS, MAI); |
| 92 | |
| 93 | const MCSymbolRefExpr::VariantKind Kind = SRE.getKind(); |
| 94 | if (Kind) { |
| 95 | if (!MAI) // should only be used by dump() |
| 96 | OS << "@<variant " << Kind << '>'; |
| 97 | else if (MAI->useParensForSpecifier()) // ARM |
| 98 | OS << '(' << MAI->getSpecifierName(S: Kind) << ')'; |
| 99 | else |
| 100 | OS << '@' << MAI->getSpecifierName(S: Kind); |
| 101 | } |
| 102 | |
| 103 | return; |
| 104 | } |
| 105 | |
| 106 | case MCExpr::Unary: { |
| 107 | const MCUnaryExpr &UE = cast<MCUnaryExpr>(Val: *this); |
| 108 | switch (UE.getOpcode()) { |
| 109 | case MCUnaryExpr::LNot: OS << '!'; break; |
| 110 | case MCUnaryExpr::Minus: OS << '-'; break; |
| 111 | case MCUnaryExpr::Not: OS << '~'; break; |
| 112 | case MCUnaryExpr::Plus: OS << '+'; break; |
| 113 | } |
| 114 | UE.getSubExpr()->print(OS, MAI, SurroundingPrec: MaxPrec); |
| 115 | return; |
| 116 | } |
| 117 | |
| 118 | case MCExpr::Binary: { |
| 119 | const MCBinaryExpr &BE = cast<MCBinaryExpr>(Val: *this); |
| 120 | // We want to avoid redundant parentheses for relocatable expressions like |
| 121 | // a-b+c. |
| 122 | // |
| 123 | // Print '(' if the current operator has lower precedence than the |
| 124 | // surrounding operator, or if the surrounding operator's precedence is |
| 125 | // unknown (set to HighPrecedence). |
| 126 | int Prec = getPrecedence(Op: BE.getOpcode()); |
| 127 | bool Paren = Prec < SurroundingPrec; |
| 128 | if (Paren) |
| 129 | OS << '('; |
| 130 | // Many operators' precedence is different from C. Set the precedence to |
| 131 | // HighPrecedence for unknown operators. |
| 132 | int SubPrec = Prec ? Prec : MaxPrec; |
| 133 | BE.getLHS()->print(OS, MAI, SurroundingPrec: SubPrec); |
| 134 | |
| 135 | switch (BE.getOpcode()) { |
| 136 | case MCBinaryExpr::Add: |
| 137 | // Print "X-42" instead of "X+-42". |
| 138 | if (const MCConstantExpr *RHSC = dyn_cast<MCConstantExpr>(Val: BE.getRHS())) { |
| 139 | if (RHSC->getValue() < 0) { |
| 140 | OS << RHSC->getValue(); |
| 141 | if (Paren) |
| 142 | OS << ')'; |
| 143 | return; |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | OS << '+'; |
| 148 | break; |
| 149 | case MCBinaryExpr::AShr: OS << ">>" ; break; |
| 150 | case MCBinaryExpr::And: OS << '&'; break; |
| 151 | case MCBinaryExpr::Div: OS << '/'; break; |
| 152 | case MCBinaryExpr::EQ: OS << "==" ; break; |
| 153 | case MCBinaryExpr::GT: OS << '>'; break; |
| 154 | case MCBinaryExpr::GTE: OS << ">=" ; break; |
| 155 | case MCBinaryExpr::LAnd: OS << "&&" ; break; |
| 156 | case MCBinaryExpr::LOr: OS << "||" ; break; |
| 157 | case MCBinaryExpr::LShr: OS << ">>" ; break; |
| 158 | case MCBinaryExpr::LT: OS << '<'; break; |
| 159 | case MCBinaryExpr::LTE: OS << "<=" ; break; |
| 160 | case MCBinaryExpr::Mod: OS << '%'; break; |
| 161 | case MCBinaryExpr::Mul: OS << '*'; break; |
| 162 | case MCBinaryExpr::NE: OS << "!=" ; break; |
| 163 | case MCBinaryExpr::Or: OS << '|'; break; |
| 164 | case MCBinaryExpr::OrNot: OS << '!'; break; |
| 165 | case MCBinaryExpr::Shl: OS << "<<" ; break; |
| 166 | case MCBinaryExpr::Sub: OS << '-'; break; |
| 167 | case MCBinaryExpr::Xor: OS << '^'; break; |
| 168 | } |
| 169 | |
| 170 | BE.getRHS()->print(OS, MAI, SurroundingPrec: SubPrec + 1); |
| 171 | if (Paren) |
| 172 | OS << ')'; |
| 173 | return; |
| 174 | } |
| 175 | |
| 176 | case MCExpr::Specifier: { |
| 177 | auto &SE = cast<MCSpecifierExpr>(Val: *this); |
| 178 | if (MAI) |
| 179 | return MAI->printSpecifierExpr(OS, SE); |
| 180 | // Used by dump features like -show-inst. Regular MCAsmStreamer output must |
| 181 | // set MAI. |
| 182 | OS << "specifier(" << SE.getSpecifier() << ','; |
| 183 | SE.getSubExpr()->print(OS, MAI: nullptr); |
| 184 | OS << ')'; |
| 185 | return; |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | llvm_unreachable("Invalid expression kind!" ); |
| 190 | } |
| 191 | |
| 192 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
| 193 | LLVM_DUMP_METHOD void MCExpr::dump() const { |
| 194 | print(dbgs(), nullptr); |
| 195 | dbgs() << '\n'; |
| 196 | } |
| 197 | #endif |
| 198 | |
| 199 | /* *** */ |
| 200 | |
| 201 | const MCBinaryExpr *MCBinaryExpr::create(Opcode Opc, const MCExpr *LHS, |
| 202 | const MCExpr *RHS, MCContext &Ctx, |
| 203 | SMLoc Loc) { |
| 204 | return new (Ctx) MCBinaryExpr(Opc, LHS, RHS, Loc); |
| 205 | } |
| 206 | |
| 207 | const MCUnaryExpr *MCUnaryExpr::create(Opcode Opc, const MCExpr *Expr, |
| 208 | MCContext &Ctx, SMLoc Loc) { |
| 209 | return new (Ctx) MCUnaryExpr(Opc, Expr, Loc); |
| 210 | } |
| 211 | |
| 212 | const MCConstantExpr *MCConstantExpr::create(int64_t Value, MCContext &Ctx, |
| 213 | bool PrintInHex, |
| 214 | unsigned SizeInBytes) { |
| 215 | return new (Ctx) MCConstantExpr(Value, PrintInHex, SizeInBytes); |
| 216 | } |
| 217 | |
| 218 | /* *** */ |
| 219 | |
| 220 | MCSymbolRefExpr::MCSymbolRefExpr(const MCSymbol *Symbol, Spec specifier, |
| 221 | const MCAsmInfo *MAI, SMLoc Loc) |
| 222 | : MCExpr(MCExpr::SymbolRef, Loc, specifier), Symbol(Symbol) { |
| 223 | assert(Symbol); |
| 224 | } |
| 225 | |
| 226 | const MCSymbolRefExpr *MCSymbolRefExpr::create(const MCSymbol *Sym, |
| 227 | uint16_t specifier, |
| 228 | MCContext &Ctx, SMLoc Loc) { |
| 229 | return new (Ctx) MCSymbolRefExpr(Sym, specifier, Ctx.getAsmInfo(), Loc); |
| 230 | } |
| 231 | |
| 232 | /* *** */ |
| 233 | |
| 234 | void MCTargetExpr::anchor() {} |
| 235 | |
| 236 | /* *** */ |
| 237 | |
| 238 | bool MCExpr::evaluateAsAbsolute(int64_t &Res) const { |
| 239 | return evaluateAsAbsolute(Res, Asm: nullptr, InSet: false); |
| 240 | } |
| 241 | |
| 242 | bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const { |
| 243 | return evaluateAsAbsolute(Res, Asm: &Asm, InSet: false); |
| 244 | } |
| 245 | |
| 246 | bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const { |
| 247 | return evaluateAsAbsolute(Res, Asm, InSet: false); |
| 248 | } |
| 249 | |
| 250 | bool MCExpr::evaluateKnownAbsolute(int64_t &Res, const MCAssembler &Asm) const { |
| 251 | return evaluateAsAbsolute(Res, Asm: &Asm, InSet: true); |
| 252 | } |
| 253 | |
| 254 | bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, |
| 255 | bool InSet) const { |
| 256 | MCValue Value; |
| 257 | |
| 258 | // Fast path constants. |
| 259 | if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Val: this)) { |
| 260 | Res = CE->getValue(); |
| 261 | return true; |
| 262 | } |
| 263 | |
| 264 | bool IsRelocatable = evaluateAsRelocatableImpl(Res&: Value, Asm, InSet); |
| 265 | Res = Value.getConstant(); |
| 266 | // Value with RefKind (e.g. %hi(0xdeadbeef) in MIPS) is not considered |
| 267 | // absolute (the value is unknown at parse time), even if it might be resolved |
| 268 | // by evaluateFixup. |
| 269 | return IsRelocatable && Value.isAbsolute() && Value.getSpecifier() == 0; |
| 270 | } |
| 271 | |
| 272 | /// Helper method for \see EvaluateSymbolAdd(). |
| 273 | static void attemptToFoldSymbolOffsetDifference(const MCAssembler *Asm, |
| 274 | bool InSet, const MCSymbol *&A, |
| 275 | const MCSymbol *&B, |
| 276 | int64_t &Addend) { |
| 277 | if (!A || !B) |
| 278 | return; |
| 279 | |
| 280 | const MCSymbol &SA = *A, &SB = *B; |
| 281 | if (SA.isUndefined() || SB.isUndefined()) |
| 282 | return; |
| 283 | if (!Asm->getWriter().isSymbolRefDifferenceFullyResolved(A: SA, B: SB, InSet)) |
| 284 | return; |
| 285 | |
| 286 | auto FinalizeFolding = [&]() { |
| 287 | // Pointers to Thumb symbols need to have their low-bit set to allow |
| 288 | // for interworking. |
| 289 | if (Asm->isThumbFunc(Func: &SA)) |
| 290 | Addend |= 1; |
| 291 | |
| 292 | // Clear the symbol expr pointers to indicate we have folded these |
| 293 | // operands. |
| 294 | A = B = nullptr; |
| 295 | }; |
| 296 | |
| 297 | const MCFragment *FA = SA.getFragment(); |
| 298 | const MCFragment *FB = SB.getFragment(); |
| 299 | const MCSection &SecA = *FA->getParent(); |
| 300 | const MCSection &SecB = *FB->getParent(); |
| 301 | if (&SecA != &SecB) |
| 302 | return; |
| 303 | |
| 304 | // When layout is available, we can generally compute the difference using the |
| 305 | // getSymbolOffset path, which also avoids the possible slow fragment walk. |
| 306 | // However, linker relaxation may cause incorrect fold of A-B if A and B are |
| 307 | // separated by a linker-relaxable fragment. If the section contains |
| 308 | // linker-relaxable instruction and InSet is false (not expressions in |
| 309 | // directive like .size/.fill), disable the fast path. |
| 310 | bool Layout = Asm->hasLayout(); |
| 311 | if (Layout && (InSet || !SecA.isLinkerRelaxable())) { |
| 312 | // If both symbols are in the same fragment, return the difference of their |
| 313 | // offsets. canGetFragmentOffset(FA) may be false. |
| 314 | if (FA == FB && !SA.isVariable() && !SB.isVariable()) { |
| 315 | Addend += SA.getOffset() - SB.getOffset(); |
| 316 | return FinalizeFolding(); |
| 317 | } |
| 318 | |
| 319 | // Eagerly evaluate when layout is finalized. |
| 320 | Addend += Asm->getSymbolOffset(S: SA) - Asm->getSymbolOffset(S: SB); |
| 321 | FinalizeFolding(); |
| 322 | } else { |
| 323 | // When layout is not finalized, our ability to resolve differences between |
| 324 | // symbols is limited to specific cases where the fragments between two |
| 325 | // symbols (including the fragments the symbols are defined in) are |
| 326 | // fixed-size fragments so the difference can be calculated. For example, |
| 327 | // this is important when the Subtarget is changed and a new MCDataFragment |
| 328 | // is created in the case of foo: instr; .arch_extension ext; instr .if . - |
| 329 | // foo. |
| 330 | if (SA.isVariable() || SB.isVariable()) |
| 331 | return; |
| 332 | |
| 333 | // Try to find a constant displacement from FA to FB, add the displacement |
| 334 | // between the offset in FA of SA and the offset in FB of SB. |
| 335 | bool Reverse = false; |
| 336 | if (FA == FB) |
| 337 | Reverse = SA.getOffset() < SB.getOffset(); |
| 338 | else |
| 339 | Reverse = FA->getLayoutOrder() < FB->getLayoutOrder(); |
| 340 | |
| 341 | uint64_t SAOffset = SA.getOffset(), SBOffset = SB.getOffset(); |
| 342 | int64_t Displacement = SA.getOffset() - SB.getOffset(); |
| 343 | if (Reverse) { |
| 344 | std::swap(a&: FA, b&: FB); |
| 345 | std::swap(a&: SAOffset, b&: SBOffset); |
| 346 | Displacement *= -1; |
| 347 | } |
| 348 | |
| 349 | // Track whether B is before a relaxable instruction and whether A is after |
| 350 | // a relaxable instruction. If SA and SB are separated by a linker-relaxable |
| 351 | // instruction, the difference cannot be resolved as it may be changed by |
| 352 | // the linker. |
| 353 | bool BBeforeRelax = false, AAfterRelax = false; |
| 354 | for (auto FI = FB; FI; FI = FI->getNext()) { |
| 355 | auto DF = dyn_cast<MCDataFragment>(Val: FI); |
| 356 | if (DF && DF->isLinkerRelaxable()) { |
| 357 | if (&*FI != FB || SBOffset != DF->getContents().size()) |
| 358 | BBeforeRelax = true; |
| 359 | if (&*FI != FA || SAOffset == DF->getContents().size()) |
| 360 | AAfterRelax = true; |
| 361 | if (BBeforeRelax && AAfterRelax) |
| 362 | return; |
| 363 | } |
| 364 | if (&*FI == FA) { |
| 365 | // If FA and FB belong to the same subsection, the loop will find FA and |
| 366 | // we can resolve the difference. |
| 367 | Addend += Reverse ? -Displacement : Displacement; |
| 368 | FinalizeFolding(); |
| 369 | return; |
| 370 | } |
| 371 | |
| 372 | int64_t Num; |
| 373 | unsigned Count; |
| 374 | if (DF) { |
| 375 | Displacement += DF->getContents().size(); |
| 376 | } else if (auto *RF = dyn_cast<MCRelaxableFragment>(Val: FI); |
| 377 | RF && Asm->hasFinalLayout()) { |
| 378 | // Before finishLayout, a relaxable fragment's size is indeterminate. |
| 379 | // After layout, during relocation generation, it can be treated as a |
| 380 | // data fragment. |
| 381 | Displacement += RF->getContents().size(); |
| 382 | } else if (auto *AF = dyn_cast<MCAlignFragment>(Val: FI); |
| 383 | AF && Layout && AF->hasEmitNops() && |
| 384 | !Asm->getBackend().shouldInsertExtraNopBytesForCodeAlign( |
| 385 | AF: *AF, Size&: Count)) { |
| 386 | Displacement += Asm->computeFragmentSize(F: *AF); |
| 387 | } else if (auto *FF = dyn_cast<MCFillFragment>(Val: FI); |
| 388 | FF && FF->getNumValues().evaluateAsAbsolute(Res&: Num)) { |
| 389 | Displacement += Num * FF->getValueSize(); |
| 390 | } else { |
| 391 | return; |
| 392 | } |
| 393 | } |
| 394 | } |
| 395 | } |
| 396 | |
| 397 | // Evaluate the sum of two relocatable expressions. |
| 398 | // |
| 399 | // Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). |
| 400 | // |
| 401 | // This routine attempts to aggressively fold the operands such that the result |
| 402 | // is representable in an MCValue, but may not always succeed. |
| 403 | // |
| 404 | // LHS_A and RHS_A might have relocation specifiers while LHS_B and RHS_B |
| 405 | // cannot have specifiers. |
| 406 | // |
| 407 | // \returns True on success, false if the result is not representable in an |
| 408 | // MCValue. |
| 409 | |
| 410 | // NOTE: This function can be used before layout is done (see the object |
| 411 | // streamer for example) and having the Asm argument lets us avoid relaxations |
| 412 | // early. |
| 413 | bool MCExpr::evaluateSymbolicAdd(const MCAssembler *Asm, bool InSet, |
| 414 | const MCValue &LHS, const MCValue &RHS, |
| 415 | MCValue &Res) { |
| 416 | const MCSymbol *LHS_A = LHS.getAddSym(); |
| 417 | const MCSymbol *LHS_B = LHS.getSubSym(); |
| 418 | int64_t LHS_Cst = LHS.getConstant(); |
| 419 | |
| 420 | const MCSymbol *RHS_A = RHS.getAddSym(); |
| 421 | const MCSymbol *RHS_B = RHS.getSubSym(); |
| 422 | int64_t RHS_Cst = RHS.getConstant(); |
| 423 | |
| 424 | // Fold the result constant immediately. |
| 425 | int64_t Result_Cst = LHS_Cst + RHS_Cst; |
| 426 | |
| 427 | // If we have a layout, we can fold resolved differences. |
| 428 | if (Asm && !LHS.getSpecifier() && !RHS.getSpecifier()) { |
| 429 | // While LHS_A-LHS_B and RHS_A-RHS_B from recursive calls have already been |
| 430 | // folded, reassociating terms in |
| 431 | // Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). |
| 432 | // might bring more opportunities. |
| 433 | if (LHS_A && RHS_B) { |
| 434 | attemptToFoldSymbolOffsetDifference(Asm, InSet, A&: LHS_A, B&: RHS_B, Addend&: Result_Cst); |
| 435 | } |
| 436 | if (RHS_A && LHS_B) { |
| 437 | attemptToFoldSymbolOffsetDifference(Asm, InSet, A&: RHS_A, B&: LHS_B, Addend&: Result_Cst); |
| 438 | } |
| 439 | } |
| 440 | |
| 441 | // We can't represent the addition or subtraction of two symbols. |
| 442 | if ((LHS_A && RHS_A) || (LHS_B && RHS_B)) |
| 443 | return false; |
| 444 | |
| 445 | // At this point, we have at most one additive symbol and one subtractive |
| 446 | // symbol -- find them. |
| 447 | auto *A = LHS_A ? LHS_A : RHS_A; |
| 448 | auto *B = LHS_B ? LHS_B : RHS_B; |
| 449 | auto Spec = LHS.getSpecifier(); |
| 450 | if (!Spec) |
| 451 | Spec = RHS.getSpecifier(); |
| 452 | Res = MCValue::get(SymA: A, SymB: B, Val: Result_Cst, Specifier: Spec); |
| 453 | return true; |
| 454 | } |
| 455 | |
| 456 | bool MCExpr::evaluateAsRelocatable(MCValue &Res, const MCAssembler *Asm) const { |
| 457 | return evaluateAsRelocatableImpl(Res, Asm, InSet: false); |
| 458 | } |
| 459 | bool MCExpr::evaluateAsValue(MCValue &Res, const MCAssembler &Asm) const { |
| 460 | return evaluateAsRelocatableImpl(Res, Asm: &Asm, InSet: true); |
| 461 | } |
| 462 | |
| 463 | bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, |
| 464 | bool InSet) const { |
| 465 | ++stats::MCExprEvaluate; |
| 466 | switch (getKind()) { |
| 467 | case Target: |
| 468 | return cast<MCTargetExpr>(Val: this)->evaluateAsRelocatableImpl(Res, Asm); |
| 469 | case Constant: |
| 470 | Res = MCValue::get(Val: cast<MCConstantExpr>(Val: this)->getValue()); |
| 471 | return true; |
| 472 | |
| 473 | case SymbolRef: { |
| 474 | const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(Val: this); |
| 475 | MCSymbol &Sym = const_cast<MCSymbol &>(SRE->getSymbol()); |
| 476 | const auto Kind = SRE->getKind(); |
| 477 | bool Layout = Asm && Asm->hasLayout(); |
| 478 | |
| 479 | // If the symbol is equated, resolve the inner expression. |
| 480 | // However, when two IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY symbols reference |
| 481 | // each other, we retain the equated symbol to avoid a cyclic definition |
| 482 | // error. |
| 483 | if (Sym.isResolving()) { |
| 484 | if (Asm && Asm->hasFinalLayout()) { |
| 485 | Asm->getContext().reportError( |
| 486 | L: Sym.getVariableValue()->getLoc(), |
| 487 | Msg: "cyclic dependency detected for symbol '" + Sym.getName() + "'" ); |
| 488 | Sym.setVariableValue(MCConstantExpr::create(Value: 0, Ctx&: Asm->getContext())); |
| 489 | } |
| 490 | return false; |
| 491 | } |
| 492 | if (Sym.isVariable() && (Kind == 0 || Layout) && !Sym.isWeakExternal()) { |
| 493 | Sym.setIsResolving(true); |
| 494 | auto _ = make_scope_exit(F: [&] { Sym.setIsResolving(false); }); |
| 495 | bool IsMachO = |
| 496 | Asm && Asm->getContext().getAsmInfo()->hasSubsectionsViaSymbols(); |
| 497 | if (!Sym.getVariableValue()->evaluateAsRelocatableImpl(Res, Asm, |
| 498 | InSet: InSet || IsMachO)) |
| 499 | return false; |
| 500 | // When generating relocations, if Sym resolves to a symbol relative to a |
| 501 | // section, relocations are generated against Sym. Treat label differences |
| 502 | // as constants. |
| 503 | auto *A = Res.getAddSym(); |
| 504 | auto *B = Res.getSubSym(); |
| 505 | if (InSet || !(A && !B && A->isInSection())) { |
| 506 | if (Kind) { |
| 507 | if (Res.isAbsolute()) { |
| 508 | Res = MCValue::get(SymA: &Sym, SymB: nullptr, Val: 0, Specifier: Kind); |
| 509 | return true; |
| 510 | } |
| 511 | // If the reference has a variant kind, we can only handle expressions |
| 512 | // which evaluate exactly to a single unadorned symbol. Attach the |
| 513 | // original VariantKind to SymA of the result. |
| 514 | if (Res.getSpecifier() || !Res.getAddSym() || Res.getSubSym() || |
| 515 | Res.getConstant()) |
| 516 | return false; |
| 517 | Res.Specifier = Kind; |
| 518 | } |
| 519 | if (!IsMachO) |
| 520 | return true; |
| 521 | |
| 522 | // FIXME: This is small hack. Given |
| 523 | // a = b + 4 |
| 524 | // .long a |
| 525 | // the OS X assembler will completely drop the 4. We should probably |
| 526 | // include it in the relocation or produce an error if that is not |
| 527 | // possible. |
| 528 | // Allow constant expressions. |
| 529 | if (!A && !B) |
| 530 | return true; |
| 531 | // Allows aliases with zero offset. |
| 532 | if (Res.getConstant() == 0 && (!A || !B)) |
| 533 | return true; |
| 534 | } |
| 535 | } |
| 536 | |
| 537 | Res = MCValue::get(SymA: &Sym, SymB: nullptr, Val: 0, Specifier: Kind); |
| 538 | return true; |
| 539 | } |
| 540 | |
| 541 | case Unary: { |
| 542 | const MCUnaryExpr *AUE = cast<MCUnaryExpr>(Val: this); |
| 543 | MCValue Value; |
| 544 | |
| 545 | if (!AUE->getSubExpr()->evaluateAsRelocatableImpl(Res&: Value, Asm, InSet)) |
| 546 | return false; |
| 547 | switch (AUE->getOpcode()) { |
| 548 | case MCUnaryExpr::LNot: |
| 549 | if (!Value.isAbsolute()) |
| 550 | return false; |
| 551 | Res = MCValue::get(Val: !Value.getConstant()); |
| 552 | break; |
| 553 | case MCUnaryExpr::Minus: |
| 554 | /// -(a - b + const) ==> (b - a - const) |
| 555 | if (Value.getAddSym() && !Value.getSubSym()) |
| 556 | return false; |
| 557 | |
| 558 | // The cast avoids undefined behavior if the constant is INT64_MIN. |
| 559 | Res = MCValue::get(SymA: Value.getSubSym(), SymB: Value.getAddSym(), |
| 560 | Val: -(uint64_t)Value.getConstant()); |
| 561 | break; |
| 562 | case MCUnaryExpr::Not: |
| 563 | if (!Value.isAbsolute()) |
| 564 | return false; |
| 565 | Res = MCValue::get(Val: ~Value.getConstant()); |
| 566 | break; |
| 567 | case MCUnaryExpr::Plus: |
| 568 | Res = Value; |
| 569 | break; |
| 570 | } |
| 571 | |
| 572 | return true; |
| 573 | } |
| 574 | |
| 575 | case Binary: { |
| 576 | const MCBinaryExpr *ABE = cast<MCBinaryExpr>(Val: this); |
| 577 | MCValue LHSValue, RHSValue; |
| 578 | |
| 579 | if (!ABE->getLHS()->evaluateAsRelocatableImpl(Res&: LHSValue, Asm, InSet) || |
| 580 | !ABE->getRHS()->evaluateAsRelocatableImpl(Res&: RHSValue, Asm, InSet)) { |
| 581 | // Check if both are Target Expressions, see if we can compare them. |
| 582 | if (const MCTargetExpr *L = dyn_cast<MCTargetExpr>(Val: ABE->getLHS())) { |
| 583 | if (const MCTargetExpr *R = dyn_cast<MCTargetExpr>(Val: ABE->getRHS())) { |
| 584 | switch (ABE->getOpcode()) { |
| 585 | case MCBinaryExpr::EQ: |
| 586 | Res = MCValue::get(Val: L->isEqualTo(x: R) ? -1 : 0); |
| 587 | return true; |
| 588 | case MCBinaryExpr::NE: |
| 589 | Res = MCValue::get(Val: L->isEqualTo(x: R) ? 0 : -1); |
| 590 | return true; |
| 591 | default: |
| 592 | break; |
| 593 | } |
| 594 | } |
| 595 | } |
| 596 | return false; |
| 597 | } |
| 598 | |
| 599 | // We only support a few operations on non-constant expressions, handle |
| 600 | // those first. |
| 601 | auto Op = ABE->getOpcode(); |
| 602 | int64_t LHS = LHSValue.getConstant(), RHS = RHSValue.getConstant(); |
| 603 | if (!LHSValue.isAbsolute() || !RHSValue.isAbsolute()) { |
| 604 | switch (Op) { |
| 605 | default: |
| 606 | return false; |
| 607 | case MCBinaryExpr::Add: |
| 608 | case MCBinaryExpr::Sub: |
| 609 | if (Op == MCBinaryExpr::Sub) { |
| 610 | std::swap(a&: RHSValue.SymA, b&: RHSValue.SymB); |
| 611 | RHSValue.Cst = -(uint64_t)RHSValue.Cst; |
| 612 | } |
| 613 | if (RHSValue.isAbsolute()) { |
| 614 | LHSValue.Cst += RHSValue.Cst; |
| 615 | Res = LHSValue; |
| 616 | return true; |
| 617 | } |
| 618 | if (LHSValue.isAbsolute()) { |
| 619 | RHSValue.Cst += LHSValue.Cst; |
| 620 | Res = RHSValue; |
| 621 | return true; |
| 622 | } |
| 623 | if (LHSValue.SymB && LHSValue.Specifier) |
| 624 | return false; |
| 625 | if (RHSValue.SymB && RHSValue.Specifier) |
| 626 | return false; |
| 627 | return evaluateSymbolicAdd(Asm, InSet, LHS: LHSValue, RHS: RHSValue, Res); |
| 628 | } |
| 629 | } |
| 630 | |
| 631 | // FIXME: We need target hooks for the evaluation. It may be limited in |
| 632 | // width, and gas defines the result of comparisons differently from |
| 633 | // Apple as. |
| 634 | int64_t Result = 0; |
| 635 | switch (Op) { |
| 636 | case MCBinaryExpr::AShr: Result = LHS >> RHS; break; |
| 637 | case MCBinaryExpr::Add: Result = LHS + RHS; break; |
| 638 | case MCBinaryExpr::And: Result = LHS & RHS; break; |
| 639 | case MCBinaryExpr::Div: |
| 640 | case MCBinaryExpr::Mod: |
| 641 | // Handle division by zero. gas just emits a warning and keeps going, |
| 642 | // we try to be stricter. |
| 643 | // FIXME: Currently the caller of this function has no way to understand |
| 644 | // we're bailing out because of 'division by zero'. Therefore, it will |
| 645 | // emit a 'expected relocatable expression' error. It would be nice to |
| 646 | // change this code to emit a better diagnostic. |
| 647 | if (RHS == 0) |
| 648 | return false; |
| 649 | if (ABE->getOpcode() == MCBinaryExpr::Div) |
| 650 | Result = LHS / RHS; |
| 651 | else |
| 652 | Result = LHS % RHS; |
| 653 | break; |
| 654 | case MCBinaryExpr::EQ: Result = LHS == RHS; break; |
| 655 | case MCBinaryExpr::GT: Result = LHS > RHS; break; |
| 656 | case MCBinaryExpr::GTE: Result = LHS >= RHS; break; |
| 657 | case MCBinaryExpr::LAnd: Result = LHS && RHS; break; |
| 658 | case MCBinaryExpr::LOr: Result = LHS || RHS; break; |
| 659 | case MCBinaryExpr::LShr: Result = uint64_t(LHS) >> uint64_t(RHS); break; |
| 660 | case MCBinaryExpr::LT: Result = LHS < RHS; break; |
| 661 | case MCBinaryExpr::LTE: Result = LHS <= RHS; break; |
| 662 | case MCBinaryExpr::Mul: Result = LHS * RHS; break; |
| 663 | case MCBinaryExpr::NE: Result = LHS != RHS; break; |
| 664 | case MCBinaryExpr::Or: Result = LHS | RHS; break; |
| 665 | case MCBinaryExpr::OrNot: Result = LHS | ~RHS; break; |
| 666 | case MCBinaryExpr::Shl: Result = uint64_t(LHS) << uint64_t(RHS); break; |
| 667 | case MCBinaryExpr::Sub: Result = LHS - RHS; break; |
| 668 | case MCBinaryExpr::Xor: Result = LHS ^ RHS; break; |
| 669 | } |
| 670 | |
| 671 | switch (Op) { |
| 672 | default: |
| 673 | Res = MCValue::get(Val: Result); |
| 674 | break; |
| 675 | case MCBinaryExpr::EQ: |
| 676 | case MCBinaryExpr::GT: |
| 677 | case MCBinaryExpr::GTE: |
| 678 | case MCBinaryExpr::LT: |
| 679 | case MCBinaryExpr::LTE: |
| 680 | case MCBinaryExpr::NE: |
| 681 | // A comparison operator returns a -1 if true and 0 if false. |
| 682 | Res = MCValue::get(Val: Result ? -1 : 0); |
| 683 | break; |
| 684 | } |
| 685 | |
| 686 | return true; |
| 687 | } |
| 688 | case Specifier: |
| 689 | // Fold the expression during relocation generation. As parse time Asm might |
| 690 | // be null, and targets should not rely on the folding. |
| 691 | return Asm && Asm->getContext().getAsmInfo()->evaluateAsRelocatableImpl( |
| 692 | cast<MCSpecifierExpr>(Val: *this), Res, Asm); |
| 693 | } |
| 694 | |
| 695 | llvm_unreachable("Invalid assembly expression kind!" ); |
| 696 | } |
| 697 | |
| 698 | MCFragment *MCExpr::findAssociatedFragment() const { |
| 699 | switch (getKind()) { |
| 700 | case Target: |
| 701 | // We never look through target specific expressions. |
| 702 | return cast<MCTargetExpr>(Val: this)->findAssociatedFragment(); |
| 703 | |
| 704 | case Constant: |
| 705 | return MCSymbol::AbsolutePseudoFragment; |
| 706 | |
| 707 | case SymbolRef: { |
| 708 | auto &Sym = |
| 709 | const_cast<MCSymbol &>(cast<MCSymbolRefExpr>(Val: this)->getSymbol()); |
| 710 | if (Sym.Fragment) |
| 711 | return Sym.Fragment; |
| 712 | if (Sym.isResolving()) |
| 713 | return MCSymbol::AbsolutePseudoFragment; |
| 714 | Sym.setIsResolving(true); |
| 715 | auto *F = Sym.getFragment(); |
| 716 | Sym.setIsResolving(false); |
| 717 | return F; |
| 718 | } |
| 719 | |
| 720 | case Unary: |
| 721 | return cast<MCUnaryExpr>(Val: this)->getSubExpr()->findAssociatedFragment(); |
| 722 | |
| 723 | case Binary: { |
| 724 | const MCBinaryExpr *BE = cast<MCBinaryExpr>(Val: this); |
| 725 | MCFragment *LHS_F = BE->getLHS()->findAssociatedFragment(); |
| 726 | MCFragment *RHS_F = BE->getRHS()->findAssociatedFragment(); |
| 727 | |
| 728 | // If either is absolute, return the other. |
| 729 | if (LHS_F == MCSymbol::AbsolutePseudoFragment) |
| 730 | return RHS_F; |
| 731 | if (RHS_F == MCSymbol::AbsolutePseudoFragment) |
| 732 | return LHS_F; |
| 733 | |
| 734 | // Not always correct, but probably the best we can do without more context. |
| 735 | if (BE->getOpcode() == MCBinaryExpr::Sub) |
| 736 | return MCSymbol::AbsolutePseudoFragment; |
| 737 | |
| 738 | // Otherwise, return the first non-null fragment. |
| 739 | return LHS_F ? LHS_F : RHS_F; |
| 740 | } |
| 741 | |
| 742 | case Specifier: |
| 743 | return cast<MCSpecifierExpr>(Val: this)->getSubExpr()->findAssociatedFragment(); |
| 744 | } |
| 745 | |
| 746 | llvm_unreachable("Invalid assembly expression kind!" ); |
| 747 | } |
| 748 | |
| 749 | const MCSpecifierExpr *MCSpecifierExpr::create(const MCExpr *Expr, Spec S, |
| 750 | MCContext &Ctx, SMLoc Loc) { |
| 751 | return new (Ctx) MCSpecifierExpr(Expr, S, Loc); |
| 752 | } |
| 753 | |
| 754 | const MCSpecifierExpr *MCSpecifierExpr::create(const MCSymbol *Sym, Spec S, |
| 755 | MCContext &Ctx, SMLoc Loc) { |
| 756 | return new (Ctx) MCSpecifierExpr(MCSymbolRefExpr::create(Symbol: Sym, Ctx), S, Loc); |
| 757 | } |
| 758 | |