Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/MipsMCExpr.h" #include "MCTargetDesc/MipsMCTargetDesc.h" #include "MipsRegisterInfo.h" #include "MipsTargetStreamer.h" @@ -1313,6 +1314,20 @@ } 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) + Res = MipsMCExpr::CreateHi(Expr, getContext()); + else + Res = MipsMCExpr::CreateLo(Expr, getContext()); + return Res; + } + const MCExpr *LExp = evaluateRelocExpr(BE->getLHS(), RelocStr); const MCExpr *RExp = evaluateRelocExpr(BE->getRHS(), RelocStr); Res = MCBinaryExpr::Create(BE->getOpcode(), LExp, RExp, getContext()); @@ -1343,8 +1358,8 @@ } case MCExpr::Unary: return isEvaluated(cast(Expr)->getSubExpr()); - default: - return false; + case MCExpr::Target: + return true; } return false; } Index: lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp =================================================================== --- lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp +++ lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp @@ -14,6 +14,7 @@ #define DEBUG_TYPE "asm-printer" #include "MipsInstPrinter.h" #include "MipsInstrInfo.h" +#include "MCTargetDesc/MipsMCExpr.h" #include "llvm/ADT/StringExtras.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" @@ -129,8 +130,10 @@ const MCConstantExpr *CE = dyn_cast(BE->getRHS()); assert(SRE && CE && "Binary expression must be sym+const."); Offset = CE->getValue(); - } - else if (!(SRE = dyn_cast(Expr))) + } else if (const MipsMCExpr *ME = dyn_cast(Expr)) { + ME->print(OS); + return; + } else if (!(SRE = dyn_cast(Expr))) assert(false && "Unexpected MCExpr type."); MCSymbolRefExpr::VariantKind Kind = SRE->getKind(); Index: lib/Target/Mips/MCTargetDesc/CMakeLists.txt =================================================================== --- lib/Target/Mips/MCTargetDesc/CMakeLists.txt +++ lib/Target/Mips/MCTargetDesc/CMakeLists.txt @@ -2,6 +2,7 @@ MipsAsmBackend.cpp MipsMCAsmInfo.cpp MipsMCCodeEmitter.cpp + MipsMCExpr.cpp MipsMCTargetDesc.cpp MipsELFObjectWriter.cpp MipsTargetStreamer.cpp Index: lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -14,6 +14,7 @@ #define DEBUG_TYPE "mccodeemitter" #include "MCTargetDesc/MipsBaseInfo.h" #include "MCTargetDesc/MipsFixupKinds.h" +#include "MCTargetDesc/MipsMCExpr.h" #include "MCTargetDesc/MipsMCTargetDesc.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/Statistic.h" @@ -385,6 +386,26 @@ Res += getExprOpValue(cast(Expr)->getRHS(), Fixups, STI); return Res; } + + if (Kind == MCExpr::Target) { + const MipsMCExpr *MipsExpr = cast(Expr); + + Mips::Fixups FixupKind = Mips::Fixups(0); + switch (MipsExpr->getKind()) { + default: llvm_unreachable("Unsupported fixup kind for target expression!"); + case MipsMCExpr::VK_Mips_ABS_HI: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_HI16 + : Mips::fixup_Mips_HI16; + break; + case MipsMCExpr::VK_Mips_ABS_LO: + FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_LO16 + : Mips::fixup_Mips_LO16; + break; + } + Fixups.push_back(MCFixup::Create(0, MipsExpr, MCFixupKind(FixupKind))); + return 0; + } + if (Kind == MCExpr::SymbolRef) { Mips::Fixups FixupKind = Mips::Fixups(0); Index: lib/Target/Mips/MCTargetDesc/MipsMCExpr.h =================================================================== --- /dev/null +++ lib/Target/Mips/MCTargetDesc/MipsMCExpr.h @@ -0,0 +1,69 @@ +//===-- MipsMCExpr.h - Mips specific MC expression classes ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSMCEXPR_H +#define MIPSMCEXPR_H + +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCValue.h" +#include "llvm/MC/MCAsmLayout.h" + +namespace llvm { + +class MipsMCExpr : public MCTargetExpr { +public: + enum VariantKind { + VK_Mips_None, + VK_Mips_ABS_LO, + VK_Mips_ABS_HI + }; + +private: + const VariantKind Kind; + const MCExpr *Expr; + + explicit MipsMCExpr(VariantKind Kind, const MCExpr *Expr) + : Kind(Kind), Expr(Expr) {} + +public: + static const MipsMCExpr *Create(VariantKind Kind, const MCExpr *Expr, + MCContext &Ctx); + + 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); + } + + /// getOpcode - Get the kind of this expression. + VariantKind getKind() const { return Kind; } + + /// getSubExpr - Get the child of this expression. + const MCExpr *getSubExpr() const { return Expr; } + + void PrintImpl(raw_ostream &OS) const; + bool EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const; + void AddValueSymbols(MCAssembler *) const; + const MCSection *FindAssociatedSection() const { + return getSubExpr()->FindAssociatedSection(); + } + + // There are no TLS MipsMCExprs at the moment. + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {} + + static bool classof(const MCExpr *E) { + return E->getKind() == MCExpr::Target; + } +}; +} // end namespace llvm + +#endif Index: lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp =================================================================== --- /dev/null +++ lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp @@ -0,0 +1,73 @@ +//===-- MipsMCExpr.cpp - Mips specific MC expression classes --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mipsmcexpr" +#include "MipsMCExpr.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCAsmInfo.h" + +using namespace llvm; + +const MipsMCExpr* +MipsMCExpr::Create(VariantKind Kind, const MCExpr *Expr, + MCContext &Ctx) { + 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; + } + + OS << '('; + Expr->print(OS); + OS << ')'; +} + +bool +MipsMCExpr::EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const { + if (!Layout) + return false; + return getSubExpr()->EvaluateAsRelocatable(Res, *Layout); +} + +// FIXME: This basically copies MCObjectStreamer::AddValueSymbols. Perhaps +// that method should be made public? +static void AddValueSymbolsImpl(const MCExpr *Value, MCAssembler *Asm) { + switch (Value->getKind()) { + case MCExpr::Target: + llvm_unreachable("Can't handle nested target expr!"); + + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast(Value); + AddValueSymbolsImpl(BE->getLHS(), Asm); + AddValueSymbolsImpl(BE->getRHS(), Asm); + break; + } + + case MCExpr::SymbolRef: + Asm->getOrCreateSymbolData(cast(Value)->getSymbol()); + break; + + case MCExpr::Unary: + AddValueSymbolsImpl(cast(Value)->getSubExpr(), Asm); + break; + } +} + +void MipsMCExpr::AddValueSymbols(MCAssembler *Asm) const { + AddValueSymbolsImpl(getSubExpr(), Asm); +} Index: test/MC/Mips/hilo-addressing.s =================================================================== --- test/MC/Mips/hilo-addressing.s +++ test/MC/Mips/hilo-addressing.s @@ -1,11 +1,42 @@ -# RUN: llvm-mc -show-encoding -triple mips-unknown-unknown %s | FileCheck %s - - .ent hilo_test - .equ addr, 0xdeadbeef -# CHECK: # encoding: [0x3c,0x04,0xde,0xae] - lui $4,%hi(addr) -# CHECK: # encoding: [0x03,0xe0,0x00,0x08] - jr $31 -# CHECK: # encoding: [0x80,0x82,0xbe,0xef] - lb $2,%lo(addr)($4) - .end hilo_test +# RUN: llvm-mc -show-encoding -triple mips-unknown-unknown %s \ +# RUN: | FileCheck %s -check-prefix=CHECK-ENC + +# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o - \ +# RUN: | llvm-objdump -disassemble - | FileCheck %s -check-prefix=CHECK-INSTR + +# RUN: llvm-mc %s -filetype=obj -triple=mipsel-unknown-linux \ +# RUN: | llvm-readobj -r | FileCheck %s -check-prefix=CHECK-REL + + +# Check that 1 is added to the high 16 bits if bit 15 of the low part is 1. + + .equ addr, 0xdeadbeef + lui $4, %hi(addr) + lb $2, %lo(addr)($4) +# CHECK-ENC: # encoding: [0x3c,0x04,0xde,0xae] +# CHECK-ENC: # encoding: [0x80,0x82,0xbe,0xef] + + +# Check that assembler can handle %hi(label1 - label2) and %lo(label1 - label2) +# expressions. + +$L1: + # Emit zeros so that difference between $L3 and $L1 is 0x30124 bytes. + .fill 0x30124-8 +$L2: + lui $4, %hi($L3-$L1) + addiu $4, $4, %lo($L3-$L1) +# CHECK-INSTR: lui $4, 3 +# CHECK-INSTR: addiu $4, $4, 292 + +$L3: + lui $5, %hi($L2-$L3) + lw $5, %lo($L2-$L3)($5) +# CHECK-INSTR: lui $5, 0 +# CHECK-INSTR: lw $5, -8($5) + + +# Check that relocation is not emitted for %hi(label1 - label2) and +# %lo(label1 - label2) expressions. + +# CHECK-REL-NOT: R_MIPS