//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "mcexpr"
#include "llvm/MC/MCExpr.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
+#define DEBUG_TYPE "mcexpr"
+
namespace {
namespace stats {
STATISTIC(MCExprEvaluate, "Number of MCExpr evaluations");
else
OS << Sym;
- if (SRE.getKind() == MCSymbolRefExpr::VK_ARM_NONE ||
- SRE.getKind() == MCSymbolRefExpr::VK_ARM_PLT ||
- SRE.getKind() == MCSymbolRefExpr::VK_ARM_TLSGD ||
- SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOT ||
- SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOTOFF ||
- SRE.getKind() == MCSymbolRefExpr::VK_ARM_TPOFF ||
- SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOTTPOFF ||
- SRE.getKind() == MCSymbolRefExpr::VK_ARM_TARGET1 ||
- SRE.getKind() == MCSymbolRefExpr::VK_ARM_TARGET2 ||
- SRE.getKind() == MCSymbolRefExpr::VK_ARM_PREL31)
- OS << MCSymbolRefExpr::getVariantKindName(SRE.getKind());
- else if (SRE.getKind() != MCSymbolRefExpr::VK_None)
- OS << '@' << MCSymbolRefExpr::getVariantKindName(SRE.getKind());
+ if (SRE.getKind() != MCSymbolRefExpr::VK_None)
+ SRE.printVariantKind(OS);
return;
}
/* *** */
+MCSymbolRefExpr::MCSymbolRefExpr(const MCSymbol *Symbol, VariantKind Kind,
+ const MCAsmInfo *MAI)
+ : MCExpr(MCExpr::SymbolRef), Kind(Kind),
+ UseParensForSymbolVariant(MAI->useParensForSymbolVariant()),
+ HasSubsectionsViaSymbols(MAI->hasSubsectionsViaSymbols()),
+ Symbol(Symbol) {
+ assert(Symbol);
+}
+
const MCSymbolRefExpr *MCSymbolRefExpr::Create(const MCSymbol *Sym,
VariantKind Kind,
MCContext &Ctx) {
- return new (Ctx) MCSymbolRefExpr(Sym, Kind);
+ return new (Ctx) MCSymbolRefExpr(Sym, Kind, Ctx.getAsmInfo());
}
const MCSymbolRefExpr *MCSymbolRefExpr::Create(StringRef Name, VariantKind Kind,
case VK_TPOFF: return "TPOFF";
case VK_DTPOFF: return "DTPOFF";
case VK_TLVP: return "TLVP";
+ case VK_TLVPPAGE: return "TLVPPAGE";
+ case VK_TLVPPAGEOFF: return "TLVPPAGEOFF";
+ case VK_PAGE: return "PAGE";
+ case VK_PAGEOFF: return "PAGEOFF";
+ case VK_GOTPAGE: return "GOTPAGE";
+ case VK_GOTPAGEOFF: return "GOTPAGEOFF";
case VK_SECREL: return "SECREL32";
- case VK_ARM_NONE: return "(NONE)";
- case VK_ARM_PLT: return "(PLT)";
- case VK_ARM_GOT: return "(GOT)";
- case VK_ARM_GOTOFF: return "(GOTOFF)";
- case VK_ARM_TPOFF: return "(tpoff)";
- case VK_ARM_GOTTPOFF: return "(gottpoff)";
- case VK_ARM_TLSGD: return "(tlsgd)";
- case VK_ARM_TARGET1: return "(target1)";
- case VK_ARM_TARGET2: return "(target2)";
- case VK_ARM_PREL31: return "(prel31)";
+ case VK_WEAKREF: return "WEAKREF";
+ case VK_ARM_NONE: return "none";
+ case VK_ARM_TARGET1: return "target1";
+ case VK_ARM_TARGET2: return "target2";
+ case VK_ARM_PREL31: return "prel31";
+ case VK_ARM_TLSLDO: return "tlsldo";
+ case VK_ARM_TLSCALL: return "tlscall";
+ case VK_ARM_TLSDESC: return "tlsdesc";
+ case VK_ARM_TLSDESCSEQ: return "tlsdescseq";
case VK_PPC_LO: return "l";
case VK_PPC_HI: return "h";
case VK_PPC_HA: return "ha";
case VK_PPC_GOT_TLSGD_LO: return "got@tlsgd@l";
case VK_PPC_GOT_TLSGD_HI: return "got@tlsgd@h";
case VK_PPC_GOT_TLSGD_HA: return "got@tlsgd@ha";
+ case VK_PPC_TLSGD: return "tlsgd";
case VK_PPC_GOT_TLSLD: return "got@tlsld";
case VK_PPC_GOT_TLSLD_LO: return "got@tlsld@l";
case VK_PPC_GOT_TLSLD_HI: return "got@tlsld@h";
case VK_PPC_GOT_TLSLD_HA: return "got@tlsld@ha";
+ case VK_PPC_TLSLD: return "tlsld";
case VK_Mips_GPREL: return "GPREL";
case VK_Mips_GOT_CALL: return "GOT_CALL";
case VK_Mips_GOT16: return "GOT16";
case VK_Mips_GOT_LO16: return "GOT_LO16";
case VK_Mips_CALL_HI16: return "CALL_HI16";
case VK_Mips_CALL_LO16: return "CALL_LO16";
- case VK_COFF_IMGREL32: return "IMGREL32";
+ case VK_Mips_PCREL_HI16: return "PCREL_HI16";
+ case VK_Mips_PCREL_LO16: return "PCREL_LO16";
+ case VK_COFF_IMGREL32: return "IMGREL";
}
llvm_unreachable("Invalid variant kind");
}
.Case("gotoff", VK_GOTOFF)
.Case("GOTPCREL", VK_GOTPCREL)
.Case("gotpcrel", VK_GOTPCREL)
+ .Case("GOT_PREL", VK_GOTPCREL)
+ .Case("got_prel", VK_GOTPCREL)
.Case("GOTTPOFF", VK_GOTTPOFF)
.Case("gottpoff", VK_GOTTPOFF)
.Case("INDNTPOFF", VK_INDNTPOFF)
.Case("dtpoff", VK_DTPOFF)
.Case("TLVP", VK_TLVP)
.Case("tlvp", VK_TLVP)
+ .Case("TLVPPAGE", VK_TLVPPAGE)
+ .Case("tlvppage", VK_TLVPPAGE)
+ .Case("TLVPPAGEOFF", VK_TLVPPAGEOFF)
+ .Case("tlvppageoff", VK_TLVPPAGEOFF)
+ .Case("PAGE", VK_PAGE)
+ .Case("page", VK_PAGE)
+ .Case("PAGEOFF", VK_PAGEOFF)
+ .Case("pageoff", VK_PAGEOFF)
+ .Case("GOTPAGE", VK_GOTPAGE)
+ .Case("gotpage", VK_GOTPAGE)
+ .Case("GOTPAGEOFF", VK_GOTPAGEOFF)
+ .Case("gotpageoff", VK_GOTPAGEOFF)
.Case("IMGREL", VK_COFF_IMGREL32)
.Case("imgrel", VK_COFF_IMGREL32)
.Case("SECREL32", VK_SECREL)
.Case("got@tlsld@h", VK_PPC_GOT_TLSLD_HI)
.Case("GOT@TLSLD@HA", VK_PPC_GOT_TLSLD_HA)
.Case("got@tlsld@ha", VK_PPC_GOT_TLSLD_HA)
+ .Case("NONE", VK_ARM_NONE)
+ .Case("none", VK_ARM_NONE)
+ .Case("TARGET1", VK_ARM_TARGET1)
+ .Case("target1", VK_ARM_TARGET1)
+ .Case("TARGET2", VK_ARM_TARGET2)
+ .Case("target2", VK_ARM_TARGET2)
+ .Case("PREL31", VK_ARM_PREL31)
+ .Case("prel31", VK_ARM_PREL31)
+ .Case("TLSLDO", VK_ARM_TLSLDO)
+ .Case("tlsldo", VK_ARM_TLSLDO)
+ .Case("TLSCALL", VK_ARM_TLSCALL)
+ .Case("tlscall", VK_ARM_TLSCALL)
+ .Case("TLSDESC", VK_ARM_TLSDESC)
+ .Case("tlsdesc", VK_ARM_TLSDESC)
.Default(VK_Invalid);
}
+void MCSymbolRefExpr::printVariantKind(raw_ostream &OS) const {
+ if (UseParensForSymbolVariant)
+ OS << '(' << MCSymbolRefExpr::getVariantKindName(getKind()) << ')';
+ else
+ OS << '@' << MCSymbolRefExpr::getVariantKindName(getKind());
+}
+
/* *** */
void MCTargetExpr::anchor() {}
/* *** */
bool MCExpr::EvaluateAsAbsolute(int64_t &Res) const {
- return EvaluateAsAbsolute(Res, 0, 0, 0);
+ return EvaluateAsAbsolute(Res, nullptr, nullptr, nullptr);
}
bool MCExpr::EvaluateAsAbsolute(int64_t &Res,
const MCAsmLayout &Layout) const {
- return EvaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, 0);
+ return EvaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr);
}
bool MCExpr::EvaluateAsAbsolute(int64_t &Res,
}
bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const {
- return EvaluateAsAbsolute(Res, &Asm, 0, 0);
+ return EvaluateAsAbsolute(Res, &Asm, nullptr, nullptr);
+}
+
+int64_t MCExpr::evaluateKnownAbsolute(const MCAsmLayout &Layout) const {
+ int64_t Res;
+ bool Abs =
+ evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr, true);
+ (void)Abs;
+ assert(Abs && "Not actually absolute");
+ return Res;
}
bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm,
const MCAsmLayout *Layout,
const SectionAddrMap *Addrs) const {
+ // FIXME: The use if InSet = Addrs is a hack. Setting InSet causes us
+ // absolutize differences across sections and that is what the MachO writer
+ // uses Addrs for.
+ return evaluateAsAbsolute(Res, Asm, Layout, Addrs, Addrs);
+}
+
+bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm,
+ const MCAsmLayout *Layout,
+ const SectionAddrMap *Addrs, bool InSet) const {
MCValue Value;
// Fast path constants.
return true;
}
- // FIXME: The use if InSet = Addrs is a hack. Setting InSet causes us
- // absolutize differences across sections and that is what the MachO writer
- // uses Addrs for.
- bool IsRelocatable =
- EvaluateAsRelocatableImpl(Value, Asm, Layout, Addrs, /*InSet*/ Addrs);
+ bool IsRelocatable = EvaluateAsRelocatableImpl(
+ Value, Asm, Layout, nullptr, Addrs, InSet, /*ForceVarExpansion*/ false);
// Record the current value.
Res = Value.getConstant();
if (!Asm->getWriter().IsSymbolRefDifferenceFullyResolved(*Asm, A, B, InSet))
return;
- MCSymbolData &AD = Asm->getSymbolData(SA);
- MCSymbolData &BD = Asm->getSymbolData(SB);
+ const MCSymbolData &AD = Asm->getSymbolData(SA);
+ const MCSymbolData &BD = Asm->getSymbolData(SB);
if (AD.getFragment() == BD.getFragment()) {
Addend += (AD.getOffset() - BD.getOffset());
// Clear the symbol expr pointers to indicate we have folded these
// operands.
- A = B = 0;
+ A = B = nullptr;
return;
}
// Clear the symbol expr pointers to indicate we have folded these
// operands.
- A = B = 0;
+ A = B = nullptr;
}
/// \brief Evaluate the result of an add between (conceptually) two MCValues.
}
bool MCExpr::EvaluateAsRelocatable(MCValue &Res,
- const MCAsmLayout &Layout) const {
- return EvaluateAsRelocatableImpl(Res, &Layout.getAssembler(), &Layout,
- 0, false);
+ const MCAsmLayout *Layout,
+ const MCFixup *Fixup) const {
+ MCAssembler *Assembler = Layout ? &Layout->getAssembler() : nullptr;
+ return EvaluateAsRelocatableImpl(Res, Assembler, Layout, Fixup, nullptr,
+ false, /*ForceVarExpansion*/ false);
+}
+
+bool MCExpr::EvaluateAsValue(MCValue &Res, const MCAsmLayout *Layout,
+ const MCFixup *Fixup) const {
+ MCAssembler *Assembler = Layout ? &Layout->getAssembler() : nullptr;
+ return EvaluateAsRelocatableImpl(Res, Assembler, Layout, Fixup, nullptr,
+ false, /*ForceVarExpansion*/ true);
}
-bool MCExpr::EvaluateAsRelocatableImpl(MCValue &Res,
- const MCAssembler *Asm,
+bool MCExpr::EvaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm,
const MCAsmLayout *Layout,
- const SectionAddrMap *Addrs,
- bool InSet) const {
+ const MCFixup *Fixup,
+ const SectionAddrMap *Addrs, bool InSet,
+ bool ForceVarExpansion) const {
++stats::MCExprEvaluate;
switch (getKind()) {
case Target:
- return cast<MCTargetExpr>(this)->EvaluateAsRelocatableImpl(Res, Layout);
+ return cast<MCTargetExpr>(this)->EvaluateAsRelocatableImpl(Res, Layout,
+ Fixup);
case Constant:
Res = MCValue::get(cast<MCConstantExpr>(this)->getValue());
// Evaluate recursively if this is a variable.
if (Sym.isVariable() && SRE->getKind() == MCSymbolRefExpr::VK_None) {
- bool Ret = Sym.getVariableValue()->EvaluateAsRelocatableImpl(Res, Asm,
- Layout,
- Addrs,
- true);
- // If we failed to simplify this to a constant, let the target
- // handle it.
- if (Ret && !Res.getSymA() && !Res.getSymB())
- return true;
+ if (Sym.getVariableValue()->EvaluateAsRelocatableImpl(
+ Res, Asm, Layout, Fixup, Addrs, true, ForceVarExpansion)) {
+ const MCSymbolRefExpr *A = Res.getSymA();
+ const MCSymbolRefExpr *B = Res.getSymB();
+
+ if (SRE->hasSubsectionsViaSymbols()) {
+ // FIXME: This is small hack. Given
+ // a = b + 4
+ // .long a
+ // the OS X assembler will completely drop the 4. We should probably
+ // include it in the relocation or produce an error if that is not
+ // possible.
+ if (!A && !B)
+ return true;
+ } else {
+ if (ForceVarExpansion)
+ return true;
+ bool IsSymbol = A && A->getSymbol().isDefined();
+ if (!IsSymbol)
+ return true;
+ }
+ }
}
- Res = MCValue::get(SRE, 0, 0);
+ Res = MCValue::get(SRE, nullptr, 0);
return true;
}
MCValue Value;
if (!AUE->getSubExpr()->EvaluateAsRelocatableImpl(Value, Asm, Layout,
- Addrs, InSet))
+ Fixup, Addrs, InSet,
+ ForceVarExpansion))
return false;
switch (AUE->getOpcode()) {
MCValue LHSValue, RHSValue;
if (!ABE->getLHS()->EvaluateAsRelocatableImpl(LHSValue, Asm, Layout,
- Addrs, InSet) ||
+ Fixup, Addrs, InSet,
+ ForceVarExpansion) ||
!ABE->getRHS()->EvaluateAsRelocatableImpl(RHSValue, Asm, Layout,
- Addrs, InSet))
+ Fixup, Addrs, InSet,
+ ForceVarExpansion))
return false;
// We only support a few operations on non-constant expressions, handle
if (Sym.isDefined())
return &Sym.getSection();
- return 0;
+ return nullptr;
}
case Unary: