summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/Mips/MCTargetDesc
diff options
context:
space:
mode:
authorDaniel Sanders <daniel.sanders@imgtec.com>2016-05-03 13:35:44 +0000
committerDaniel Sanders <daniel.sanders@imgtec.com>2016-05-03 13:35:44 +0000
commitfe98b2f54b0478537b9869708a6d87eafb326a1f (patch)
tree6f460d58e338449f0e77f032087596f7460d3c97 /llvm/lib/Target/Mips/MCTargetDesc
parent32e78c3ff7172bacc6759518c3167014938c3dda (diff)
downloadbcm5719-llvm-fe98b2f54b0478537b9869708a6d87eafb326a1f.tar.gz
bcm5719-llvm-fe98b2f54b0478537b9869708a6d87eafb326a1f.zip
[mips] Use MipsMCExpr instead of MCSymbolRefExpr for all relocations.
Summary: This is much closer to the way MIPS relocation expressions work (%hi(foo + 2) rather than %hi(foo) + 2) and removes the need for the various bodges in MipsAsmParser::evaluateRelocExpr(). Removing those bodges ensures that the constant stored in MCValue is the full 32 or 64-bit (depending on ABI) offset from the symbol. This will be used to correct the %hi/%lo matching needed to sort the relocation table correctly. As part of this: * Gave MCExpr::print() the ability to omit parenthesis when emitting a symbol reference inside a MipsMCExpr operator like %hi(X). Without this we print things like %lo(($L1)). * %hi(%neg(%gprel(X))) is now three MipsMCExpr's instead of one. Most of the related special cases have been removed or moved to MipsMCExpr. We can remove the rest as we gain support for the less common relocations when they are not part of this specific combination. * Renamed MipsMCExpr::VariantKind and the enum prefix ('VK_') to avoid confusion with MCSymbolRefExpr::VariantKind and its prefix (also 'VK_'). * fixup_Mips_GOT_Local and fixup_Mips_GOT_Global were found to be identical and merged into fixup_Mips_GOT. * MO_GOT16 and MO_GOT turned out to be identical and have been merged into MO_GOT. * VK_Mips_GOT and VK_Mips_GOT16 turned out to be the same thing so they have been merged into MEK_GOT Reviewers: sdardis Subscribers: dsanders, sdardis, llvm-commits Differential Revision: http://reviews.llvm.org/D19716 llvm-svn: 268379
Diffstat (limited to 'llvm/lib/Target/Mips/MCTargetDesc')
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp21
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h3
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp5
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h7
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp173
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp295
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h66
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp25
8 files changed, 408 insertions, 187 deletions
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
index 6abf5e78545..ad4505bb24e 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
@@ -14,6 +14,7 @@
#include "MCTargetDesc/MipsFixupKinds.h"
#include "MCTargetDesc/MipsAsmBackend.h"
+#include "MCTargetDesc/MipsMCExpr.h"
#include "MCTargetDesc/MipsMCTargetDesc.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAssembler.h"
@@ -23,7 +24,9 @@
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCValue.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
@@ -40,9 +43,6 @@ static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
default:
return 0;
case FK_Data_2:
- case FK_GPRel_4:
- case FK_Data_4:
- case FK_Data_8:
case Mips::fixup_Mips_LO16:
case Mips::fixup_Mips_GPREL16:
case Mips::fixup_Mips_GPOFF_HI:
@@ -57,6 +57,11 @@ static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
case Mips::fixup_MICROMIPS_GOT_OFST:
case Mips::fixup_MICROMIPS_GOT_DISP:
case Mips::fixup_MIPS_PCLO16:
+ Value &= 0xffff;
+ break;
+ case FK_GPRel_4:
+ case FK_Data_4:
+ case FK_Data_8:
break;
case Mips::fixup_Mips_PC16:
// The displacement is then divided by 4 to give us an 18 bit
@@ -85,7 +90,7 @@ static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
Value >>= 2;
break;
case Mips::fixup_Mips_HI16:
- case Mips::fixup_Mips_GOT_Local:
+ case Mips::fixup_Mips_GOT:
case Mips::fixup_Mips_GOT_HI16:
case Mips::fixup_Mips_CALL_HI16:
case Mips::fixup_MICROMIPS_HI16:
@@ -295,8 +300,7 @@ getFixupKindInfo(MCFixupKind Kind) const {
{ "fixup_Mips_LO16", 0, 16, 0 },
{ "fixup_Mips_GPREL16", 0, 16, 0 },
{ "fixup_Mips_LITERAL", 0, 16, 0 },
- { "fixup_Mips_GOT_Global", 0, 16, 0 },
- { "fixup_Mips_GOT_Local", 0, 16, 0 },
+ { "fixup_Mips_GOT", 0, 16, 0 },
{ "fixup_Mips_PC16", 0, 16, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_Mips_CALL16", 0, 16, 0 },
{ "fixup_Mips_GPREL32", 0, 32, 0 },
@@ -364,8 +368,7 @@ getFixupKindInfo(MCFixupKind Kind) const {
{ "fixup_Mips_LO16", 16, 16, 0 },
{ "fixup_Mips_GPREL16", 16, 16, 0 },
{ "fixup_Mips_LITERAL", 16, 16, 0 },
- { "fixup_Mips_GOT_Global", 16, 16, 0 },
- { "fixup_Mips_GOT_Local", 16, 16, 0 },
+ { "fixup_Mips_GOT", 16, 16, 0 },
{ "fixup_Mips_PC16", 16, 16, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_Mips_CALL16", 16, 16, 0 },
{ "fixup_Mips_GPREL32", 0, 32, 0 },
@@ -460,6 +463,8 @@ void MipsAsmBackend::processFixupValue(const MCAssembler &Asm,
// we are only checking if the fixup can be applied correctly. We have
// access to MCContext from here which allows us to report a fatal error
// with *possibly* a source code location.
+ // The caller will also ignore any changes we make to Value
+ // (recordRelocation() overwrites it with it's own calculation).
(void)adjustFixupValue(Fixup, Value, &Asm.getContext());
}
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
index 0e54563b825..2bcff881788 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
@@ -33,9 +33,8 @@ namespace MipsII {
MO_NO_FLAG,
- /// MO_GOT16 - Represents the offset into the global offset table at which
+ /// MO_GOT - Represents the offset into the global offset table at which
/// the address the relocation entry symbol resides during execution.
- MO_GOT16,
MO_GOT,
/// MO_GOT_CALL - Represents the offset into the global offset table at
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
index cdb5c89d3ec..f7f6fa51e31 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
@@ -131,8 +131,7 @@ unsigned MipsELFObjectWriter::getRelocType(MCContext &Ctx,
return ELF::R_MIPS_26;
case Mips::fixup_Mips_CALL16:
return ELF::R_MIPS_CALL16;
- case Mips::fixup_Mips_GOT_Global:
- case Mips::fixup_Mips_GOT_Local:
+ case Mips::fixup_Mips_GOT:
return ELF::R_MIPS_GOT16;
case Mips::fixup_Mips_HI16:
return ELF::R_MIPS_HI16;
@@ -402,7 +401,7 @@ bool MipsELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym,
case ELF::R_MIPS_GOT16:
case ELF::R_MIPS16_GOT16:
case ELF::R_MICROMIPS_GOT16:
- llvm_unreachable("Should have been handled already");
+ return true;
// These relocations might be paired with another relocation. The pairing is
// done by the static linker by matching the symbol. Since we only see one
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h
index ba6038e0fed..1a15a648004 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h
@@ -50,11 +50,8 @@ namespace Mips {
// 16 bit literal fixup resulting in - R_MIPS_LITERAL.
fixup_Mips_LITERAL,
- // Global symbol fixup resulting in - R_MIPS_GOT16.
- fixup_Mips_GOT_Global,
-
- // Local symbol fixup resulting in - R_MIPS_GOT16.
- fixup_Mips_GOT_Local,
+ // Symbol fixup resulting in - R_MIPS_GOT16.
+ fixup_Mips_GOT,
// PC relative branch fixup resulting in - R_MIPS_PC16.
fixup_Mips_PC16,
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
index 50c6e67c6be..57b087d0006 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
@@ -509,126 +509,117 @@ getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups,
Mips::Fixups FixupKind = Mips::Fixups(0);
switch (MipsExpr->getKind()) {
- default: llvm_unreachable("Unsupported fixup kind for target expression!");
- case MipsMCExpr::VK_Mips_HIGHEST:
- FixupKind = Mips::fixup_Mips_HIGHEST;
+ case MipsMCExpr::MEK_NEG:
+ case MipsMCExpr::MEK_None:
+ case MipsMCExpr::MEK_Special:
+ llvm_unreachable("Unhandled fixup kind!");
break;
- case MipsMCExpr::VK_Mips_HIGHER:
- FixupKind = Mips::fixup_Mips_HIGHER;
+ case MipsMCExpr::MEK_CALL_HI16:
+ FixupKind = Mips::fixup_Mips_CALL_HI16;
break;
- case MipsMCExpr::VK_Mips_HI:
- FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_HI16
- : Mips::fixup_Mips_HI16;
+ case MipsMCExpr::MEK_CALL_LO16:
+ FixupKind = Mips::fixup_Mips_CALL_LO16;
break;
- case MipsMCExpr::VK_Mips_LO:
- FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_LO16
- : Mips::fixup_Mips_LO16;
+ case MipsMCExpr::MEK_DTPREL_HI:
+ FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_DTPREL_HI16
+ : Mips::fixup_Mips_DTPREL_HI;
break;
- }
- Fixups.push_back(MCFixup::create(0, MipsExpr, MCFixupKind(FixupKind)));
- return 0;
- }
-
- if (Kind == MCExpr::SymbolRef) {
- Mips::Fixups FixupKind = Mips::Fixups(0);
-
- switch(cast<MCSymbolRefExpr>(Expr)->getKind()) {
- default: llvm_unreachable("Unknown fixup kind!");
+ case MipsMCExpr::MEK_DTPREL_LO:
+ FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_DTPREL_LO16
+ : Mips::fixup_Mips_DTPREL_LO;
break;
- case MCSymbolRefExpr::VK_None:
- FixupKind = Mips::fixup_Mips_32; // FIXME: This is ok for O32/N32 but not N64.
+ case MipsMCExpr::MEK_GOTTPREL:
+ FixupKind = Mips::fixup_Mips_GOTTPREL;
+ break;
+ case MipsMCExpr::MEK_GOT:
+ FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT16
+ : Mips::fixup_Mips_GOT;
break;
- case MCSymbolRefExpr::VK_Mips_GPOFF_HI :
- FixupKind = Mips::fixup_Mips_GPOFF_HI;
+ case MipsMCExpr::MEK_GOT_CALL:
+ FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_CALL16
+ : Mips::fixup_Mips_CALL16;
break;
- case MCSymbolRefExpr::VK_Mips_GPOFF_LO :
- FixupKind = Mips::fixup_Mips_GPOFF_LO;
+ case MipsMCExpr::MEK_GOT_DISP:
+ FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT_DISP
+ : Mips::fixup_Mips_GOT_DISP;
break;
- case MCSymbolRefExpr::VK_Mips_GOT_PAGE :
+ case MipsMCExpr::MEK_GOT_HI16:
+ FixupKind = Mips::fixup_Mips_GOT_HI16;
+ break;
+ case MipsMCExpr::MEK_GOT_LO16:
+ FixupKind = Mips::fixup_Mips_GOT_LO16;
+ break;
+ case MipsMCExpr::MEK_GOT_PAGE:
FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT_PAGE
- : Mips::fixup_Mips_GOT_PAGE;
+ : Mips::fixup_Mips_GOT_PAGE;
break;
- case MCSymbolRefExpr::VK_Mips_GOT_OFST :
+ case MipsMCExpr::MEK_GOT_OFST:
FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT_OFST
- : Mips::fixup_Mips_GOT_OFST;
- break;
- case MCSymbolRefExpr::VK_Mips_GOT_DISP :
- FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT_DISP
- : Mips::fixup_Mips_GOT_DISP;
+ : Mips::fixup_Mips_GOT_OFST;
break;
- case MCSymbolRefExpr::VK_Mips_GPREL:
+ case MipsMCExpr::MEK_GPREL:
FixupKind = Mips::fixup_Mips_GPREL16;
break;
- case MCSymbolRefExpr::VK_Mips_GOT_CALL:
- FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_CALL16
- : Mips::fixup_Mips_CALL16;
+ case MipsMCExpr::MEK_LO: {
+ // Check for %lo(%neg(%gp_rel(X)))
+ if (MipsExpr->isGpOff()) {
+ FixupKind = Mips::fixup_Mips_GPOFF_LO;
+ break;
+ }
+ FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_LO16
+ : Mips::fixup_Mips_LO16;
break;
- case MCSymbolRefExpr::VK_Mips_GOT16:
- FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT16
- : Mips::fixup_Mips_GOT_Global;
+ }
+ case MipsMCExpr::MEK_HIGHEST:
+ FixupKind = Mips::fixup_Mips_HIGHEST;
break;
- case MCSymbolRefExpr::VK_Mips_GOT:
- FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_GOT16
- : Mips::fixup_Mips_GOT_Local;
+ case MipsMCExpr::MEK_HIGHER:
+ FixupKind = Mips::fixup_Mips_HIGHER;
break;
- case MCSymbolRefExpr::VK_Mips_ABS_HI:
+ case MipsMCExpr::MEK_HI:
+ // Check for %hi(%neg(%gp_rel(X)))
+ if (MipsExpr->isGpOff()) {
+ FixupKind = Mips::fixup_Mips_GPOFF_HI;
+ break;
+ }
FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_HI16
- : Mips::fixup_Mips_HI16;
+ : Mips::fixup_Mips_HI16;
break;
- case MCSymbolRefExpr::VK_Mips_ABS_LO:
- FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_LO16
- : Mips::fixup_Mips_LO16;
+ case MipsMCExpr::MEK_PCREL_HI16:
+ FixupKind = Mips::fixup_MIPS_PCHI16;
break;
- case MCSymbolRefExpr::VK_Mips_TLSGD:
+ case MipsMCExpr::MEK_PCREL_LO16:
+ FixupKind = Mips::fixup_MIPS_PCLO16;
+ break;
+ case MipsMCExpr::MEK_TLSGD:
FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_GD
- : Mips::fixup_Mips_TLSGD;
+ : Mips::fixup_Mips_TLSGD;
break;
- case MCSymbolRefExpr::VK_Mips_TLSLDM:
+ case MipsMCExpr::MEK_TLSLDM:
FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_LDM
- : Mips::fixup_Mips_TLSLDM;
- break;
- case MCSymbolRefExpr::VK_Mips_DTPREL_HI:
- FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_DTPREL_HI16
- : Mips::fixup_Mips_DTPREL_HI;
- break;
- case MCSymbolRefExpr::VK_Mips_DTPREL_LO:
- FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_DTPREL_LO16
- : Mips::fixup_Mips_DTPREL_LO;
- break;
- case MCSymbolRefExpr::VK_Mips_GOTTPREL:
- FixupKind = Mips::fixup_Mips_GOTTPREL;
+ : Mips::fixup_Mips_TLSLDM;
break;
- case MCSymbolRefExpr::VK_Mips_TPREL_HI:
+ case MipsMCExpr::MEK_TPREL_HI:
FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_TPREL_HI16
- : Mips::fixup_Mips_TPREL_HI;
+ : Mips::fixup_Mips_TPREL_HI;
break;
- case MCSymbolRefExpr::VK_Mips_TPREL_LO:
+ case MipsMCExpr::MEK_TPREL_LO:
FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_TPREL_LO16
- : Mips::fixup_Mips_TPREL_LO;
- break;
- case MCSymbolRefExpr::VK_Mips_HIGHER:
- FixupKind = Mips::fixup_Mips_HIGHER;
+ : Mips::fixup_Mips_TPREL_LO;
break;
- case MCSymbolRefExpr::VK_Mips_HIGHEST:
- FixupKind = Mips::fixup_Mips_HIGHEST;
- break;
- case MCSymbolRefExpr::VK_Mips_GOT_HI16:
- FixupKind = Mips::fixup_Mips_GOT_HI16;
- break;
- case MCSymbolRefExpr::VK_Mips_GOT_LO16:
- FixupKind = Mips::fixup_Mips_GOT_LO16;
- break;
- case MCSymbolRefExpr::VK_Mips_CALL_HI16:
- FixupKind = Mips::fixup_Mips_CALL_HI16;
- break;
- case MCSymbolRefExpr::VK_Mips_CALL_LO16:
- FixupKind = Mips::fixup_Mips_CALL_LO16;
- break;
- case MCSymbolRefExpr::VK_Mips_PCREL_HI16:
- FixupKind = Mips::fixup_MIPS_PCHI16;
+ }
+ Fixups.push_back(MCFixup::create(0, MipsExpr, MCFixupKind(FixupKind)));
+ return 0;
+ }
+
+ if (Kind == MCExpr::SymbolRef) {
+ Mips::Fixups FixupKind = Mips::Fixups(0);
+
+ switch(cast<MCSymbolRefExpr>(Expr)->getKind()) {
+ default: llvm_unreachable("Unknown fixup kind!");
break;
- case MCSymbolRefExpr::VK_Mips_PCREL_LO16:
- FixupKind = Mips::fixup_MIPS_PCLO16;
+ case MCSymbolRefExpr::VK_None:
+ FixupKind = Mips::fixup_Mips_32; // FIXME: This is ok for O32/N32 but not N64.
break;
} // switch
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp
index c85fc4816b0..082bb87fcb8 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp
@@ -12,69 +12,110 @@
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCSymbolELF.h"
+#include "llvm/Support/ELF.h"
using namespace llvm;
#define DEBUG_TYPE "mipsmcexpr"
-bool MipsMCExpr::isSupportedBinaryExpr(MCSymbolRefExpr::VariantKind VK,
- const MCBinaryExpr *BE) {
- switch (VK) {
- case MCSymbolRefExpr::VK_Mips_ABS_LO:
- case MCSymbolRefExpr::VK_Mips_ABS_HI:
- case MCSymbolRefExpr::VK_Mips_HIGHER:
- case MCSymbolRefExpr::VK_Mips_HIGHEST:
- break;
- default:
- return false;
- }
+const MipsMCExpr *MipsMCExpr::create(MipsMCExpr::MipsExprKind Kind,
+ const MCExpr *Expr, MCContext &Ctx) {
+ return new (Ctx) MipsMCExpr(Kind, Expr);
+}
- // We support expressions of the form "(sym1 binop1 sym2) binop2 const",
- // where "binop2 const" is optional.
- if (isa<MCBinaryExpr>(BE->getLHS())) {
- if (!isa<MCConstantExpr>(BE->getRHS()))
- return false;
- BE = cast<MCBinaryExpr>(BE->getLHS());
- }
- return (isa<MCSymbolRefExpr>(BE->getLHS())
- && isa<MCSymbolRefExpr>(BE->getRHS()));
+const MipsMCExpr *MipsMCExpr::createGpOff(MipsMCExpr::MipsExprKind Kind,
+ const MCExpr *Expr, MCContext &Ctx) {
+ return create(Kind, create(MEK_NEG, create(MEK_GPREL, Expr, Ctx), Ctx), Ctx);
}
-const MipsMCExpr*
-MipsMCExpr::create(MCSymbolRefExpr::VariantKind VK, const MCExpr *Expr,
- MCContext &Ctx) {
- VariantKind Kind;
- switch (VK) {
- case MCSymbolRefExpr::VK_Mips_ABS_LO:
- Kind = VK_Mips_LO;
+void MipsMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
+ int64_t AbsVal;
+
+ switch (Kind) {
+ case MEK_None:
+ case MEK_Special:
+ llvm_unreachable("MEK_None and MEK_Special are invalid");
break;
- case MCSymbolRefExpr::VK_Mips_ABS_HI:
- Kind = VK_Mips_HI;
+ case MEK_CALL_HI16:
+ OS << "%call_hi";
break;
- case MCSymbolRefExpr::VK_Mips_HIGHER:
- Kind = VK_Mips_HIGHER;
+ case MEK_CALL_LO16:
+ OS << "%call_lo";
break;
- case MCSymbolRefExpr::VK_Mips_HIGHEST:
- Kind = VK_Mips_HIGHEST;
+ case MEK_DTPREL_HI:
+ OS << "%dtprel_hi";
+ break;
+ case MEK_DTPREL_LO:
+ OS << "%dtprel_lo";
+ break;
+ case MEK_GOT:
+ OS << "%got";
+ break;
+ case MEK_GOTTPREL:
+ OS << "%gottprel";
+ break;
+ case MEK_GOT_CALL:
+ OS << "%call16";
+ break;
+ case MEK_GOT_DISP:
+ OS << "%got_disp";
+ break;
+ case MEK_GOT_HI16:
+ OS << "%got_hi";
+ break;
+ case MEK_GOT_LO16:
+ OS << "%got_lo";
+ break;
+ case MEK_GOT_PAGE:
+ OS << "%got_page";
+ break;
+ case MEK_GOT_OFST:
+ OS << "%got_ofst";
+ break;
+ case MEK_GPREL:
+ OS << "%gp_rel";
+ break;
+ case MEK_HI:
+ OS << "%hi";
+ break;
+ case MEK_HIGHER:
+ OS << "%higher";
+ break;
+ case MEK_HIGHEST:
+ OS << "%highest";
+ break;
+ case MEK_LO:
+ OS << "%lo";
+ break;
+ case MEK_NEG:
+ OS << "%neg";
+ break;
+ case MEK_PCREL_HI16:
+ OS << "%pcrel_hi";
+ break;
+ case MEK_PCREL_LO16:
+ OS << "%pcrel_lo";
+ break;
+ case MEK_TLSGD:
+ OS << "%tlsgd";
+ break;
+ case MEK_TLSLDM:
+ OS << "%tlsldm";
+ break;
+ case MEK_TPREL_HI:
+ OS << "%tprel_hi";
+ break;
+ case MEK_TPREL_LO:
+ OS << "%tprel_lo";
break;
- default:
- llvm_unreachable("Invalid kind!");
- }
-
- return new (Ctx) MipsMCExpr(Kind, Expr);
-}
-
-void MipsMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
- switch (Kind) {
- default: llvm_unreachable("Invalid kind!");
- case VK_Mips_LO: OS << "%lo"; break;
- case VK_Mips_HI: OS << "%hi"; break;
- case VK_Mips_HIGHER: OS << "%higher"; break;
- case VK_Mips_HIGHEST: OS << "%highest"; break;
}
OS << '(';
- Expr->print(OS, MAI);
+ if (Expr->evaluateAsAbsolute(AbsVal))
+ OS << AbsVal;
+ else
+ Expr->print(OS, MAI, true);
OS << ')';
}
@@ -82,9 +123,165 @@ bool
MipsMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
const MCAsmLayout *Layout,
const MCFixup *Fixup) const {
- return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup);
+ // Look for the %hi(%neg(%gp_rel(X))) and %lo(%neg(%gp_rel(X))) special cases.
+ if (isGpOff()) {
+ const MCExpr *SubExpr =
+ cast<MipsMCExpr>(cast<MipsMCExpr>(getSubExpr())->getSubExpr())
+ ->getSubExpr();
+ if (!SubExpr->evaluateAsRelocatable(Res, Layout, Fixup))
+ return false;
+
+ Res = MCValue::get(Res.getSymA(), Res.getSymB(), Res.getConstant(),
+ MEK_Special);
+ return true;
+ }
+
+ if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup))
+ return false;
+
+ if (Res.getRefKind() != MCSymbolRefExpr::VK_None)
+ return false;
+
+ // evaluateAsAbsolute() and evaluateAsValue() require that we evaluate the
+ // %hi/%lo/etc. here. Fixup is a null pointer when either of these is the
+ // caller.
+ if (Res.isAbsolute() && Fixup == nullptr) {
+ int64_t AbsVal = Res.getConstant();
+ switch (Kind) {
+ case MEK_None:
+ case MEK_Special:
+ llvm_unreachable("MEK_None and MEK_Special are invalid");
+ case MEK_DTPREL_HI:
+ case MEK_DTPREL_LO:
+ case MEK_GOT:
+ case MEK_GOTTPREL:
+ case MEK_GOT_CALL:
+ case MEK_GOT_DISP:
+ case MEK_GOT_HI16:
+ case MEK_GOT_LO16:
+ case MEK_GOT_OFST:
+ case MEK_GOT_PAGE:
+ case MEK_GPREL:
+ case MEK_PCREL_HI16:
+ case MEK_PCREL_LO16:
+ case MEK_TLSGD:
+ case MEK_TLSLDM:
+ case MEK_TPREL_HI:
+ case MEK_TPREL_LO:
+ return false;
+ case MEK_LO:
+ case MEK_CALL_LO16:
+ AbsVal = SignExtend64<16>(AbsVal);
+ break;
+ case MEK_CALL_HI16:
+ case MEK_HI:
+ AbsVal = SignExtend64<16>((AbsVal + 0x8000) >> 16);
+ break;
+ case MEK_HIGHER:
+ AbsVal = SignExtend64<16>((AbsVal + 0x80008000LL) >> 32);
+ break;
+ case MEK_HIGHEST:
+ AbsVal = SignExtend64<16>((AbsVal + 0x800080008000LL) >> 48);
+ break;
+ case MEK_NEG:
+ AbsVal = -AbsVal;
+ break;
+ }
+ Res = MCValue::get(AbsVal);
+ return true;
+ }
+
+ // We want to defer it for relocatable expressions since the constant is
+ // applied to the whole symbol value.
+ //
+ // The value of getKind() that is given to MCValue is only intended to aid
+ // debugging when inspecting MCValue objects. It shouldn't be relied upon
+ // for decision making.
+ Res = MCValue::get(Res.getSymA(), Res.getSymB(), Res.getConstant(), getKind());
+
+ return true;
}
void MipsMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
Streamer.visitUsedExpr(*getSubExpr());
}
+
+static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {
+ switch (Expr->getKind()) {
+ case MCExpr::Target:
+ fixELFSymbolsInTLSFixupsImpl(cast<MipsMCExpr>(Expr)->getSubExpr(), Asm);
+ break;
+ case MCExpr::Constant:
+ break;
+ case MCExpr::Binary: {
+ const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
+ fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm);
+ fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm);
+ break;
+ }
+ case MCExpr::SymbolRef: {
+ // We're known to be under a TLS fixup, so any symbol should be
+ // modified. There should be only one.
+ const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);
+ cast<MCSymbolELF>(SymRef.getSymbol()).setType(ELF::STT_TLS);
+ break;
+ }
+ case MCExpr::Unary:
+ fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm);
+ break;
+ }
+}
+
+void MipsMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
+ switch (getKind()) {
+ case MEK_None:
+ case MEK_Special:
+ llvm_unreachable("MEK_None and MEK_Special are invalid");
+ break;
+ case MEK_CALL_HI16:
+ case MEK_CALL_LO16:
+ case MEK_DTPREL_HI:
+ case MEK_DTPREL_LO:
+ case MEK_GOT:
+ case MEK_GOT_CALL:
+ case MEK_GOT_DISP:
+ case MEK_GOT_HI16:
+ case MEK_GOT_LO16:
+ case MEK_GOT_OFST:
+ case MEK_GOT_PAGE:
+ case MEK_GPREL:
+ case MEK_HI:
+ case MEK_HIGHER:
+ case MEK_HIGHEST:
+ case MEK_LO:
+ case MEK_NEG:
+ case MEK_PCREL_HI16:
+ case MEK_PCREL_LO16:
+ case MEK_TLSLDM:
+ // If we do have nested target-specific expressions, they will be in
+ // a consecutive chain.
+ if (const MipsMCExpr *E = dyn_cast<const MipsMCExpr>(getSubExpr()))
+ E->fixELFSymbolsInTLSFixups(Asm);
+ break;
+ case MEK_GOTTPREL:
+ case MEK_TLSGD:
+ case MEK_TPREL_HI:
+ case MEK_TPREL_LO:
+ fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm);
+ break;
+ }
+}
+
+bool MipsMCExpr::isGpOff(MipsExprKind &Kind) const {
+ if (getKind() == MEK_HI || getKind() == MEK_LO) {
+ if (const MipsMCExpr *S1 = dyn_cast<const MipsMCExpr>(getSubExpr())) {
+ if (const MipsMCExpr *S2 = dyn_cast<const MipsMCExpr>(S1->getSubExpr())) {
+ if (S1->getKind() == MEK_NEG && S2->getKind() == MEK_GPREL) {
+ Kind = getKind();
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h
index e889972c5c0..d1a4334ec64 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h
@@ -18,49 +18,73 @@ namespace llvm {
class MipsMCExpr : public MCTargetExpr {
public:
- enum VariantKind {
- VK_Mips_None,
- VK_Mips_LO,
- VK_Mips_HI,
- VK_Mips_HIGHER,
- VK_Mips_HIGHEST
+ enum MipsExprKind {
+ MEK_None,
+ MEK_CALL_HI16,
+ MEK_CALL_LO16,
+ MEK_DTPREL_HI,
+ MEK_DTPREL_LO,
+ MEK_GOT,
+ MEK_GOTTPREL,
+ MEK_GOT_CALL,
+ MEK_GOT_DISP,
+ MEK_GOT_HI16,
+ MEK_GOT_LO16,
+ MEK_GOT_OFST,
+ MEK_GOT_PAGE,
+ MEK_GPREL,
+ MEK_HI,
+ MEK_HIGHER,
+ MEK_HIGHEST,
+ MEK_LO,
+ MEK_NEG,
+ MEK_PCREL_HI16,
+ MEK_PCREL_LO16,
+ MEK_TLSGD,
+ MEK_TLSLDM,
+ MEK_TPREL_HI,
+ MEK_TPREL_LO,
+ MEK_Special,
};
private:
- const VariantKind Kind;
+ const MipsExprKind Kind;
const MCExpr *Expr;
- explicit MipsMCExpr(VariantKind Kind, const MCExpr *Expr)
- : Kind(Kind), Expr(Expr) {}
+ explicit MipsMCExpr(MipsExprKind Kind, const MCExpr *Expr)
+ : Kind(Kind), Expr(Expr) {}
public:
- static bool isSupportedBinaryExpr(MCSymbolRefExpr::VariantKind VK,
- const MCBinaryExpr *BE);
+ static const MipsMCExpr *create(MipsExprKind Kind, const MCExpr *Expr,
+ MCContext &Ctx);
+ static const MipsMCExpr *createGpOff(MipsExprKind Kind, const MCExpr *Expr,
+ MCContext &Ctx);
- static const MipsMCExpr *create(MCSymbolRefExpr::VariantKind VK,
- const MCExpr *Expr, MCContext &Ctx);
+ /// Get the kind of this expression.
+ MipsExprKind getKind() const { return Kind; }
- /// getOpcode - Get the kind of this expression.
- VariantKind getKind() const { return Kind; }
-
- /// getSubExpr - Get the child of this expression.
+ /// Get the child of this expression.
const MCExpr *getSubExpr() const { return Expr; }
void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
- bool evaluateAsRelocatableImpl(MCValue &Res,
- const MCAsmLayout *Layout,
+ bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout,
const MCFixup *Fixup) const override;
void visitUsedExpr(MCStreamer &Streamer) const override;
MCFragment *findAssociatedFragment() const override {
return getSubExpr()->findAssociatedFragment();
}
- // There are no TLS MipsMCExprs at the moment.
- void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {}
+ void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override;
static bool classof(const MCExpr *E) {
return E->getKind() == MCExpr::Target;
}
+
+ bool isGpOff(MipsExprKind &Kind) const;
+ bool isGpOff() const {
+ MipsExprKind Kind;
+ return isGpOff(Kind);
+ }
};
} // end namespace llvm
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
index 5eec7213b9f..73b7722aa08 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
@@ -14,6 +14,7 @@
#include "MipsTargetStreamer.h"
#include "InstPrinter/MipsInstPrinter.h"
#include "MipsELFStreamer.h"
+#include "MipsMCExpr.h"
#include "MipsMCTargetDesc.h"
#include "MipsTargetObjectFile.h"
#include "llvm/MC/MCContext.h"
@@ -981,8 +982,11 @@ void MipsTargetELFStreamer::emitDirectiveCpLoad(unsigned RegNo) {
MCInst TmpInst;
TmpInst.setOpcode(Mips::LUi);
TmpInst.addOperand(MCOperand::createReg(Mips::GP));
- const MCSymbolRefExpr *HiSym = MCSymbolRefExpr::create(
- "_gp_disp", MCSymbolRefExpr::VK_Mips_ABS_HI, MCA.getContext());
+ const MCExpr *HiSym = MipsMCExpr::create(
+ MipsMCExpr::MEK_HI,
+ MCSymbolRefExpr::create("_gp_disp", MCSymbolRefExpr::VK_None,
+ MCA.getContext()),
+ MCA.getContext());
TmpInst.addOperand(MCOperand::createExpr(HiSym));
getStreamer().EmitInstruction(TmpInst, STI);
@@ -991,8 +995,11 @@ void MipsTargetELFStreamer::emitDirectiveCpLoad(unsigned RegNo) {
TmpInst.setOpcode(Mips::ADDiu);
TmpInst.addOperand(MCOperand::createReg(Mips::GP));
TmpInst.addOperand(MCOperand::createReg(Mips::GP));
- const MCSymbolRefExpr *LoSym = MCSymbolRefExpr::create(
- "_gp_disp", MCSymbolRefExpr::VK_Mips_ABS_LO, MCA.getContext());
+ const MCExpr *LoSym = MipsMCExpr::create(
+ MipsMCExpr::MEK_LO,
+ MCSymbolRefExpr::create("_gp_disp", MCSymbolRefExpr::VK_None,
+ MCA.getContext()),
+ MCA.getContext());
TmpInst.addOperand(MCOperand::createExpr(LoSym));
getStreamer().EmitInstruction(TmpInst, STI);
@@ -1055,10 +1062,12 @@ void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
getStreamer().EmitInstruction(Inst, STI);
Inst.clear();
- const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::create(
- &Sym, MCSymbolRefExpr::VK_Mips_GPOFF_HI, MCA.getContext());
- const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::create(
- &Sym, MCSymbolRefExpr::VK_Mips_GPOFF_LO, MCA.getContext());
+ const MipsMCExpr *HiExpr = MipsMCExpr::createGpOff(
+ MipsMCExpr::MEK_HI, MCSymbolRefExpr::create(&Sym, MCA.getContext()),
+ MCA.getContext());
+ const MipsMCExpr *LoExpr = MipsMCExpr::createGpOff(
+ MipsMCExpr::MEK_LO, MCSymbolRefExpr::create(&Sym, MCA.getContext()),
+ MCA.getContext());
// lui $gp, %hi(%neg(%gp_rel(funcSym)))
Inst.setOpcode(Mips::LUi);
OpenPOWER on IntegriCloud