summaryrefslogtreecommitdiff
path: root/llvm/lib/MC/MCExpr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/MC/MCExpr.cpp')
-rw-r--r--llvm/lib/MC/MCExpr.cpp138
1 files changed, 95 insertions, 43 deletions
diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp
index ecf63b10f73f..3b123a46d9dc 100644
--- a/llvm/lib/MC/MCExpr.cpp
+++ b/llvm/lib/MC/MCExpr.cpp
@@ -47,6 +47,8 @@ void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI, bool InParens) const {
auto Value = cast<MCConstantExpr>(*this).getValue();
auto PrintInHex = cast<MCConstantExpr>(*this).useHexFormat();
auto SizeInBytes = cast<MCConstantExpr>(*this).getSizeInBytes();
+ if (Value < 0 && MAI && !MAI->supportsSignedData())
+ PrintInHex = true;
if (PrintInHex)
switch (SizeInBytes) {
default:
@@ -83,8 +85,13 @@ void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI, bool InParens) const {
} else
Sym.print(OS, MAI);
- if (SRE.getKind() != MCSymbolRefExpr::VK_None)
- SRE.printVariantKind(OS);
+ const MCSymbolRefExpr::VariantKind Kind = SRE.getKind();
+ if (Kind != MCSymbolRefExpr::VK_None) {
+ if (MAI && MAI->useParensForSymbolVariant()) // ARM
+ OS << '(' << MCSymbolRefExpr::getVariantKindName(Kind) << ')';
+ else
+ OS << '@' << MCSymbolRefExpr::getVariantKindName(Kind);
+ }
return;
}
@@ -143,6 +150,7 @@ void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI, bool InParens) const {
case MCBinaryExpr::Mul: OS << '*'; break;
case MCBinaryExpr::NE: OS << "!="; break;
case MCBinaryExpr::Or: OS << '|'; break;
+ case MCBinaryExpr::OrNot: OS << '!'; break;
case MCBinaryExpr::Shl: OS << "<<"; break;
case MCBinaryExpr::Sub: OS << '-'; break;
case MCBinaryExpr::Xor: OS << '^'; break;
@@ -194,8 +202,7 @@ const MCConstantExpr *MCConstantExpr::create(int64_t Value, MCContext &Ctx,
MCSymbolRefExpr::MCSymbolRefExpr(const MCSymbol *Symbol, VariantKind Kind,
const MCAsmInfo *MAI, SMLoc Loc)
: MCExpr(MCExpr::SymbolRef, Loc,
- encodeSubclassData(Kind, MAI->useParensForSymbolVariant(),
- MAI->hasSubsectionsViaSymbols())),
+ encodeSubclassData(Kind, MAI->hasSubsectionsViaSymbols())),
Symbol(Symbol) {
assert(Symbol);
}
@@ -246,6 +253,7 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
case VK_SIZE: return "SIZE";
case VK_WEAKREF: return "WEAKREF";
case VK_X86_ABS8: return "ABS8";
+ case VK_X86_PLTOFF: return "PLTOFF";
case VK_ARM_NONE: return "none";
case VK_ARM_GOT_PREL: return "GOT_PREL";
case VK_ARM_TARGET1: return "target1";
@@ -319,9 +327,18 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
case VK_PPC_GOT_TLSLD_HA: return "got@tlsld@ha";
case VK_PPC_GOT_PCREL:
return "got@pcrel";
+ case VK_PPC_GOT_TLSGD_PCREL:
+ return "got@tlsgd@pcrel";
+ case VK_PPC_GOT_TLSLD_PCREL:
+ return "got@tlsld@pcrel";
+ case VK_PPC_GOT_TPREL_PCREL:
+ return "got@tprel@pcrel";
+ case VK_PPC_TLS_PCREL:
+ return "tls@pcrel";
case VK_PPC_TLSLD: return "tlsld";
case VK_PPC_LOCAL: return "local";
case VK_PPC_NOTOC: return "notoc";
+ case VK_PPC_PCREL_OPT: return "<<invalid>>";
case VK_COFF_IMGREL32: return "IMGREL";
case VK_Hexagon_LO16: return "LO16";
case VK_Hexagon_HI16: return "HI16";
@@ -334,6 +351,7 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
case VK_Hexagon_IE_GOT: return "IEGOT";
case VK_WASM_TYPEINDEX: return "TYPEINDEX";
case VK_WASM_MBREL: return "MBREL";
+ case VK_WASM_TLSREL: return "TLSREL";
case VK_WASM_TBREL: return "TBREL";
case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo";
case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi";
@@ -393,6 +411,7 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) {
.Case("secrel32", VK_SECREL)
.Case("size", VK_SIZE)
.Case("abs8", VK_X86_ABS8)
+ .Case("pltoff", VK_X86_PLTOFF)
.Case("l", VK_PPC_LO)
.Case("h", VK_PPC_HI)
.Case("ha", VK_PPC_HA)
@@ -450,6 +469,10 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) {
.Case("got@tlsld@h", VK_PPC_GOT_TLSLD_HI)
.Case("got@tlsld@ha", VK_PPC_GOT_TLSLD_HA)
.Case("got@pcrel", VK_PPC_GOT_PCREL)
+ .Case("got@tlsgd@pcrel", VK_PPC_GOT_TLSGD_PCREL)
+ .Case("got@tlsld@pcrel", VK_PPC_GOT_TLSLD_PCREL)
+ .Case("got@tprel@pcrel", VK_PPC_GOT_TPREL_PCREL)
+ .Case("tls@pcrel", VK_PPC_TLS_PCREL)
.Case("notoc", VK_PPC_NOTOC)
.Case("gdgot", VK_Hexagon_GD_GOT)
.Case("gdplt", VK_Hexagon_GD_PLT)
@@ -470,6 +493,7 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) {
.Case("typeindex", VK_WASM_TYPEINDEX)
.Case("tbrel", VK_WASM_TBREL)
.Case("mbrel", VK_WASM_MBREL)
+ .Case("tlsrel", VK_WASM_TLSREL)
.Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO)
.Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI)
.Case("rel32@lo", VK_AMDGPU_REL32_LO)
@@ -494,13 +518,6 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) {
.Default(VK_Invalid);
}
-void MCSymbolRefExpr::printVariantKind(raw_ostream &OS) const {
- if (useParensForSymbolVariant())
- OS << '(' << MCSymbolRefExpr::getVariantKindName(getKind()) << ')';
- else
- OS << '@' << MCSymbolRefExpr::getVariantKindName(getKind());
-}
-
/* *** */
void MCTargetExpr::anchor() {}
@@ -575,12 +592,7 @@ static void AttemptToFoldSymbolOffsetDifference(
if (!Asm->getWriter().isSymbolRefDifferenceFullyResolved(*Asm, A, B, InSet))
return;
- MCFragment *FA = SA.getFragment();
- MCFragment *FB = SB.getFragment();
- if (FA == FB && !SA.isVariable() && !SA.isUnset() && !SB.isVariable() &&
- !SB.isUnset()) {
- Addend += (SA.getOffset() - SB.getOffset());
-
+ auto FinalizeFolding = [&]() {
// Pointers to Thumb symbols need to have their low-bit set to allow
// for interworking.
if (Asm->isThumbFunc(&SA))
@@ -594,11 +606,17 @@ static void AttemptToFoldSymbolOffsetDifference(
// Clear the symbol expr pointers to indicate we have folded these
// operands.
A = B = nullptr;
- return;
- }
+ };
- if (!Layout)
- return;
+ const MCFragment *FA = SA.getFragment();
+ const MCFragment *FB = SB.getFragment();
+ // If both symbols are in the same fragment, return the difference of their
+ // offsets
+ if (FA == FB && !SA.isVariable() && !SA.isUnset() && !SB.isVariable() &&
+ !SB.isUnset()) {
+ Addend += SA.getOffset() - SB.getOffset();
+ return FinalizeFolding();
+ }
const MCSection &SecA = *FA->getParent();
const MCSection &SecB = *FB->getParent();
@@ -606,30 +624,46 @@ static void AttemptToFoldSymbolOffsetDifference(
if ((&SecA != &SecB) && !Addrs)
return;
- // One of the symbol involved is part of a fragment being laid out. Quit now
- // to avoid a self loop.
- if (!Layout->canGetFragmentOffset(FA) || !Layout->canGetFragmentOffset(FB))
- return;
+ if (Layout) {
+ // One of the symbol involved is part of a fragment being laid out. Quit now
+ // to avoid a self loop.
+ if (!Layout->canGetFragmentOffset(FA) || !Layout->canGetFragmentOffset(FB))
+ return;
- // Eagerly evaluate.
- Addend += Layout->getSymbolOffset(A->getSymbol()) -
- Layout->getSymbolOffset(B->getSymbol());
- if (Addrs && (&SecA != &SecB))
- Addend += (Addrs->lookup(&SecA) - Addrs->lookup(&SecB));
+ // Eagerly evaluate when layout is finalized.
+ Addend += Layout->getSymbolOffset(A->getSymbol()) -
+ Layout->getSymbolOffset(B->getSymbol());
+ if (Addrs && (&SecA != &SecB))
+ Addend += (Addrs->lookup(&SecA) - Addrs->lookup(&SecB));
- // Pointers to Thumb symbols need to have their low-bit set to allow
- // for interworking.
- if (Asm->isThumbFunc(&SA))
- Addend |= 1;
-
- // If symbol is labeled as micromips, we set low-bit to ensure
- // correct offset in .gcc_except_table
- if (Asm->getBackend().isMicroMips(&SA))
- Addend |= 1;
+ FinalizeFolding();
+ } else {
+ // When layout is not finalized, our ability to resolve differences between
+ // symbols is limited to specific cases where the fragments between two
+ // symbols (including the fragments the symbols are defined in) are
+ // fixed-size fragments so the difference can be calculated. For example,
+ // this is important when the Subtarget is changed and a new MCDataFragment
+ // is created in the case of foo: instr; .arch_extension ext; instr .if . -
+ // foo.
+ if (SA.isVariable() || SA.isUnset() || SB.isVariable() || SB.isUnset() ||
+ FA->getKind() != MCFragment::FT_Data ||
+ FB->getKind() != MCFragment::FT_Data ||
+ FA->getSubsectionNumber() != FB->getSubsectionNumber())
+ return;
+ // Try to find a constant displacement from FA to FB, add the displacement
+ // between the offset in FA of SA and the offset in FB of SB.
+ int64_t Displacement = SA.getOffset() - SB.getOffset();
+ for (auto FI = FB->getIterator(), FE = SecA.end(); FI != FE; ++FI) {
+ if (&*FI == FA) {
+ Addend += Displacement;
+ return FinalizeFolding();
+ }
- // Clear the symbol expr pointers to indicate we have folded these
- // operands.
- A = B = nullptr;
+ if (FI->getKind() != MCFragment::FT_Data)
+ return;
+ Displacement += cast<MCDataFragment>(FI)->getContents().size();
+ }
+ }
}
static bool canFold(const MCAssembler *Asm, const MCSymbolRefExpr *A,
@@ -770,13 +804,30 @@ bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm,
case SymbolRef: {
const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(this);
const MCSymbol &Sym = SRE->getSymbol();
+ const auto Kind = SRE->getKind();
// Evaluate recursively if this is a variable.
- if (Sym.isVariable() && SRE->getKind() == MCSymbolRefExpr::VK_None &&
+ if (Sym.isVariable() && (Kind == MCSymbolRefExpr::VK_None || Layout) &&
canExpand(Sym, InSet)) {
bool IsMachO = SRE->hasSubsectionsViaSymbols();
if (Sym.getVariableValue()->evaluateAsRelocatableImpl(
Res, Asm, Layout, Fixup, Addrs, InSet || IsMachO)) {
+ if (Kind != MCSymbolRefExpr::VK_None) {
+ if (Res.isAbsolute()) {
+ Res = MCValue::get(SRE, nullptr, 0);
+ return true;
+ }
+ // If the reference has a variant kind, we can only handle expressions
+ // which evaluate exactly to a single unadorned symbol. Attach the
+ // original VariantKind to SymA of the result.
+ if (Res.getRefKind() != MCSymbolRefExpr::VK_None || !Res.getSymA() ||
+ Res.getSymB() || Res.getConstant())
+ return false;
+ Res =
+ MCValue::get(MCSymbolRefExpr::create(&Res.getSymA()->getSymbol(),
+ Kind, Asm->getContext()),
+ Res.getSymB(), Res.getConstant(), Res.getRefKind());
+ }
if (!IsMachO)
return true;
@@ -917,6 +968,7 @@ bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm,
case MCBinaryExpr::Mul: Result = LHS * RHS; break;
case MCBinaryExpr::NE: Result = LHS != RHS; break;
case MCBinaryExpr::Or: Result = LHS | RHS; break;
+ case MCBinaryExpr::OrNot: Result = LHS | ~RHS; break;
case MCBinaryExpr::Shl: Result = uint64_t(LHS) << uint64_t(RHS); break;
case MCBinaryExpr::Sub: Result = LHS - RHS; break;
case MCBinaryExpr::Xor: Result = LHS ^ RHS; break;