diff --git a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 736c910e45a..911a1190437 100644 --- a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -1448,23 +1448,30 @@ const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, const MCExpr *Res; // Check the type of the expression. if (const MCConstantExpr *MCE = dyn_cast(Expr)) { - // It's a constant, evaluate lo or hi value. - if (RelocStr == "lo") { - short Val = MCE->getValue(); - Res = MCConstantExpr::Create(Val, getContext()); - } else if (RelocStr == "hi") { - int Val = MCE->getValue(); - int LoSign = Val & 0x8000; - Val = (Val & 0xffff0000) >> 16; - // Lower part is treated as a signed int, so if it is negative - // we must add 1 to the hi part to compensate. - if (LoSign) - Val++; - Res = MCConstantExpr::Create(Val, getContext()); - } else { - llvm_unreachable("Invalid RelocStr value"); + // It's a constant, evaluate reloc value. + int16_t Val; + switch (getVariantKind(RelocStr)) { + case MCSymbolRefExpr::VK_Mips_ABS_LO: + // Get the 1st 16-bits. + Val = MCE->getValue() & 0xffff; + break; + case MCSymbolRefExpr::VK_Mips_ABS_HI: + // Get the 2nd 16-bits. Also add 1 if bit 15 is 1, to compensate for low + // 16 bits being negative. + Val = ((MCE->getValue() + 0x8000) >> 16) & 0xffff; + break; + case MCSymbolRefExpr::VK_Mips_HIGHER: + // Get the 3rd 16-bits. + Val = ((MCE->getValue() + 0x80008000LL) >> 32) & 0xffff; + break; + case MCSymbolRefExpr::VK_Mips_HIGHEST: + // Get the 4th 16-bits. + Val = ((MCE->getValue() + 0x800080008000LL) >> 48) & 0xffff; + break; + default: + report_fatal_error("Unsupported reloc value!"); } - return Res; + return MCConstantExpr::Create(Val, getContext()); } if (const MCSymbolRefExpr *MSRE = dyn_cast(Expr)) { @@ -1478,15 +1485,9 @@ const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, if (const MCBinaryExpr *BE = dyn_cast(Expr)) { MCSymbolRefExpr::VariantKind VK = getVariantKind(RelocStr); - // Check for %hi(sym1-sym2) and %lo(sym1-sym2) expressions. - if (isa(BE->getLHS()) && isa(BE->getRHS()) - && (VK == MCSymbolRefExpr::VK_Mips_ABS_HI - || VK == MCSymbolRefExpr::VK_Mips_ABS_LO)) { - // Create target expression for %hi(sym1-sym2) and %lo(sym1-sym2). - if (VK == MCSymbolRefExpr::VK_Mips_ABS_HI) - return MipsMCExpr::CreateHi(Expr, getContext()); - return MipsMCExpr::CreateLo(Expr, getContext()); - } + // Try to create target expression. + if (MipsMCExpr::isSupportedBinaryExpr(VK, BE)) + return MipsMCExpr::Create(VK, Expr, getContext()); const MCExpr *LExp = evaluateRelocExpr(BE->getLHS(), RelocStr); const MCExpr *RExp = evaluateRelocExpr(BE->getRHS(), RelocStr); diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp index 6730bedb9f5..edd21469d2e 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -306,11 +306,17 @@ getExprOpValue(const MCExpr *Expr,SmallVectorImpl &Fixups, Mips::Fixups FixupKind = Mips::Fixups(0); switch (MipsExpr->getKind()) { default: llvm_unreachable("Unsupported fixup kind for target expression!"); - case MipsMCExpr::VK_Mips_ABS_HI: + case MipsMCExpr::VK_Mips_HIGHEST: + FixupKind = Mips::fixup_Mips_HIGHEST; + break; + case MipsMCExpr::VK_Mips_HIGHER: + FixupKind = Mips::fixup_Mips_HIGHER; + break; + case MipsMCExpr::VK_Mips_HI: FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_HI16 : Mips::fixup_Mips_HI16; break; - case MipsMCExpr::VK_Mips_ABS_LO: + case MipsMCExpr::VK_Mips_LO: FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_LO16 : Mips::fixup_Mips_LO16; break; diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp index 22ce41100a0..c7ba12d0417 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp @@ -15,17 +15,60 @@ using namespace llvm; +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; + } + + // We support expressions of the form "(sym1 binop1 sym2) binop2 const", + // where "binop2 const" is optional. + if (isa(BE->getLHS())) { + if (!isa(BE->getRHS())) + return false; + BE = cast(BE->getLHS()); + } + return (isa(BE->getLHS()) + && isa(BE->getRHS())); +} + const MipsMCExpr* -MipsMCExpr::Create(VariantKind Kind, const MCExpr *Expr, +MipsMCExpr::Create(MCSymbolRefExpr::VariantKind VK, const MCExpr *Expr, MCContext &Ctx) { + VariantKind Kind; + switch (VK) { + case MCSymbolRefExpr::VK_Mips_ABS_LO: + Kind = VK_Mips_LO; + break; + case MCSymbolRefExpr::VK_Mips_ABS_HI: + Kind = VK_Mips_HI; + break; + case MCSymbolRefExpr::VK_Mips_HIGHER: + Kind = VK_Mips_HIGHER; + break; + case MCSymbolRefExpr::VK_Mips_HIGHEST: + Kind = VK_Mips_HIGHEST; + break; + default: + llvm_unreachable("Invalid kind!"); + } + return new (Ctx) MipsMCExpr(Kind, Expr); } void MipsMCExpr::PrintImpl(raw_ostream &OS) const { switch (Kind) { default: llvm_unreachable("Invalid kind!"); - case VK_Mips_ABS_LO: OS << "%lo"; break; - case VK_Mips_ABS_HI: OS << "%hi"; break; + 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 << '('; diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h index 0ec17554c0b..722bba71e9b 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h +++ b/lib/Target/Mips/MCTargetDesc/MipsMCExpr.h @@ -20,8 +20,10 @@ class MipsMCExpr : public MCTargetExpr { public: enum VariantKind { VK_Mips_None, - VK_Mips_ABS_LO, - VK_Mips_ABS_HI + VK_Mips_LO, + VK_Mips_HI, + VK_Mips_HIGHER, + VK_Mips_HIGHEST }; private: @@ -32,16 +34,11 @@ private: : Kind(Kind), Expr(Expr) {} public: - static const MipsMCExpr *Create(VariantKind Kind, const MCExpr *Expr, - MCContext &Ctx); + static bool isSupportedBinaryExpr(MCSymbolRefExpr::VariantKind VK, + const MCBinaryExpr *BE); - static const MipsMCExpr *CreateLo(const MCExpr *Expr, MCContext &Ctx) { - return Create(VK_Mips_ABS_LO, Expr, Ctx); - } - - static const MipsMCExpr *CreateHi(const MCExpr *Expr, MCContext &Ctx) { - return Create(VK_Mips_ABS_HI, Expr, Ctx); - } + static const MipsMCExpr *Create(MCSymbolRefExpr::VariantKind VK, + const MCExpr *Expr, MCContext &Ctx); /// getOpcode - Get the kind of this expression. VariantKind getKind() const { return Kind; } diff --git a/test/MC/Mips/higher-highest-addressing.s b/test/MC/Mips/higher-highest-addressing.s new file mode 100644 index 00000000000..2973a6400ae --- /dev/null +++ b/test/MC/Mips/higher-highest-addressing.s @@ -0,0 +1,54 @@ +# RUN: llvm-mc -filetype=obj -triple=mips64el-unknown-linux -mcpu=mips64r2 %s \ +# RUN: | llvm-objdump -disassemble -triple mips64el - | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=mips64el-unknown-linux -mcpu=mips64r2 %s \ +# RUN: | llvm-readobj -r | FileCheck %s -check-prefix=CHECK-REL + + +# Test that R_MIPS_HIGHER and R_MIPS_HIGHEST relocations are created. By using +# NEXT we also test that none of the expressions from the test2 generates +# relocations. + +test1: +# CHECK-LABEL: test1: + + lui $5, %highest(func) + daddiu $5, $5, %higher(func) + +# CHECK-REL: Relocations [ +# CHECK-REL-NEXT: { +# CHECK-REL-NEXT: 0x{{[0-9,A-F]+}} R_MIPS_HIGHEST +# CHECK-REL-NEXT: 0x{{[0-9,A-F]+}} R_MIPS_HIGHER +# CHECK-REL-NEXT: } + + +# Test the calculation of %higher and %highest: +# ((x + 0x80008000) >> 32) & 0xffff (higher) +# ((x + 0x800080008000) >> 48) & 0xffff (highest). + +test2: +# CHECK-LABEL: test2: + +# Check the case where relocations are not modified by adding +1. The constant +# is chosen so that it is just below the value that triggers the addition of +1 +# to %higher. +$L1: + lui $6, %highest($L2-$L1+0x300047FFF7FF7) + daddiu $6, $6, %higher($L2-$L1+0x300047FFF7FF7) +$L2: +# CHECK: lui $6, 3 +# CHECK: daddiu $6, $6, 4 + + +# Check the case where %higher is modified by adding +1. + lui $7, %highest($L2-$L1+0x300047FFF7FF8) + ld $7, %higher ($L2-$L1+0x300047FFF7FF8)($7) +# CHECK: lui $7, 3 +# CHECK: ld $7, 5($7) + + +# Check the case where both %higher and %highest are modified by adding +1. + lui $8, %highest(0x37FFF7FFF8000) + ld $8, %higher (0x37FFF7FFF8000)($8) +# CHECK: lui $8, 4 +# CHECK: ld $8, -32768($8) diff --git a/test/MC/Mips/higher_highest.ll b/test/MC/Mips/higher_highest.ll deleted file mode 100644 index 6c3d71f6a4b..00000000000 --- a/test/MC/Mips/higher_highest.ll +++ /dev/null @@ -1,32 +0,0 @@ -; DISABLE: llc -march=mips64el -mcpu=mips64 -mattr=n64 -force-mips-long-branch -filetype=obj < %s -o - | llvm-readobj -r | FileCheck %s -; RUN: false -; XFAIL: * -; Disabled because currently we don't have a way to generate these relocations. -; -; Check that the R_MIPS_HIGHER and R_MIPS_HIGHEST relocations were created. - -; CHECK: Relocations [ -; CHECK: 0x{{[0-9,A-F]+}} R_MIPS_HIGHEST -; CHECK: 0x{{[0-9,A-F]+}} R_MIPS_HIGHEST -; CHECK: 0x{{[0-9,A-F]+}} R_MIPS_HIGHER -; CHECK: 0x{{[0-9,A-F]+}} R_MIPS_HIGHER -; CHECK: ] - -@g0 = external global i32 - -define void @foo1(i32 %s) nounwind { -entry: - - %tobool = icmp eq i32 %s, 0 - br i1 %tobool, label %if.end, label %if.then - -if.then: ; preds = %entry - %0 = load i32* @g0, align 4 - %add = add nsw i32 %0, 12 - store i32 %add, i32* @g0, align 4 - br label %if.end - -if.end: ; preds = %entry, %if.then - ret void -} -