Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "MCTargetDesc/RISCVMCExpr.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" @@ -57,6 +58,7 @@ OperandMatchResultTy parseImmediate(OperandVector &Operands); OperandMatchResultTy parseRegister(OperandVector &Operands); OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands); + OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); bool parseOperand(OperandVector &Operands); @@ -68,6 +70,10 @@ #undef GET_OPERAND_DIAGNOSTIC_TYPES }; + static bool classifySymbolRef(const MCExpr *Expr, + RISCVMCExpr::VariantKind &Kind, + int64_t &Addend); + RISCVAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, const MCInstrInfo &MII, const MCTargetOptions &Options) : MCTargetAsmParser(Options, STI), Parser(Parser), STI(STI) { @@ -150,7 +156,16 @@ } bool isSImm12() const { - return (isConstantImm() && isInt<12>(getConstantImm())); + if (isConstantImm()) { + return isInt<12>(getConstantImm()); + } else if (isImm()) { + RISCVMCExpr::VariantKind VK; + int64_t Addend; + if (!RISCVAsmParser::classifySymbolRef(getImm(), VK, Addend)) + return true; + return VK == RISCVMCExpr::VK_RISCV_LO; + } + return false; } bool isUImm12() const { @@ -163,7 +178,16 @@ } bool isUImm20() const { - return (isConstantImm() && isUInt<20>(getConstantImm())); + if (isConstantImm()) { + return isUInt<20>(getConstantImm()); + } else if (isImm()) { + RISCVMCExpr::VariantKind VK; + int64_t Addend; + if (!RISCVAsmParser::classifySymbolRef(getImm(), VK, Addend)) + return true; + return VK == RISCVMCExpr::VK_RISCV_HI || VK == RISCVMCExpr::VK_RISCV_PCREL_HI; + } + return false; } bool isSImm21Mask1() const { @@ -225,8 +249,13 @@ } static std::unique_ptr createImm(const MCExpr *Val, SMLoc S, - SMLoc E) { + SMLoc E, MCContext &Ctx) { auto Op = make_unique(Immediate); + if (const RISCVMCExpr *RE = dyn_cast(Val)) { + int64_t Res; + if (RE->evaluateAsConstant(Res)) + Val = MCConstantExpr::create(Res, Ctx); + } Op->Imm.Val = Val; Op->StartLoc = S; Op->EndLoc = E; @@ -360,6 +389,10 @@ RISCVAsmParser::OperandMatchResultTy RISCVAsmParser::parseImmediate(OperandVector &Operands) { + SMLoc S = Parser.getTok().getLoc(); + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + const MCExpr *Res; + switch (getLexer().getKind()) { default: return MatchOperand_NoMatch; @@ -368,16 +401,63 @@ case AsmToken::Plus: case AsmToken::Integer: case AsmToken::String: + if (getParser().parseExpression(Res)) + return MatchOperand_ParseFail; + break; + case AsmToken::Identifier: { + StringRef Identifier; + if (getParser().parseIdentifier(Identifier)) + return MatchOperand_ParseFail; + MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); + Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + break; + } + case AsmToken::Percent: + return parseOperandWithModifier(Operands); break; } - const MCExpr *IdVal; + Operands.push_back(RISCVOperand::createImm(Res, S, E, getContext())); + return MatchOperand_Success; +} + +RISCVAsmParser::OperandMatchResultTy +RISCVAsmParser::parseOperandWithModifier(OperandVector &Operands) { SMLoc S = Parser.getTok().getLoc(); - if (getParser().parseExpression(IdVal)) + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + if (getLexer().getKind() != AsmToken::Percent) { + Error(getLoc(), "expected '%' for operand modifier"); return MatchOperand_ParseFail; + } - SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - Operands.push_back(RISCVOperand::createImm(IdVal, S, E)); + Parser.Lex(); // Eat '%' + + if (getLexer().getKind() != AsmToken::Identifier) { + Error(getLoc(), "expected valid identifier for operand modifier"); + return MatchOperand_ParseFail; + } + StringRef Identifier = Parser.getTok().getString(); + RISCVMCExpr::VariantKind VK = RISCVMCExpr::getVariantKindForName(Identifier); + if (VK == RISCVMCExpr::VK_RISCV_None) { + Error(getLoc(), "unrecognized operand modifier"); + return MatchOperand_ParseFail; + } + + Parser.Lex(); // Eat the identifier + if (getLexer().getKind() != AsmToken::LParen) { + Error(getLoc(), "expected '('"); + return MatchOperand_ParseFail; + } + Parser.Lex(); // Eat '(' + + const MCExpr *SubExpr; + if (Parser.parseParenExpression(SubExpr, E)) { + return MatchOperand_ParseFail; + } + + const MCExpr *ModExpr = RISCVMCExpr::create(SubExpr, VK, getContext()); + Operands.push_back(RISCVOperand::createImm(ModExpr, S, E, getContext())); return MatchOperand_Success; } @@ -464,6 +544,52 @@ return false; } +bool RISCVAsmParser::classifySymbolRef(const MCExpr *Expr, + RISCVMCExpr::VariantKind &Kind, + int64_t &Addend) { + Kind = RISCVMCExpr::VK_RISCV_Invalid; + Addend = 0; + + if (const RISCVMCExpr *RE = dyn_cast(Expr)) { + Kind = RE->getKind(); + Expr = RE->getSubExpr(); + } + + assert(!isa(Expr) && + "simple constants should have been evaluated already"); + + const MCSymbolRefExpr *SE = dyn_cast(Expr); + if (SE) { + // It's a simple symbol reference with no addend. + return true; + } + + const MCBinaryExpr *BE = dyn_cast(Expr); + if (!BE) + return false; + + SE = dyn_cast(BE->getLHS()); + if (!SE) + return false; + + if (BE->getOpcode() != MCBinaryExpr::Add && + BE->getOpcode() != MCBinaryExpr::Sub) + return false; + + // See if the addend is is a constant, otherwise there's more going + // on here than we can deal with. + auto AddendExpr = dyn_cast(BE->getRHS()); + if (!AddendExpr) + return false; + + Addend = AddendExpr->getValue(); + if (BE->getOpcode() == MCBinaryExpr::Sub) + Addend = -Addend; + + // It's some symbol reference + a constant addend + return Kind != RISCVMCExpr::VK_RISCV_Invalid; +} + bool RISCVAsmParser::ParseDirective(AsmToken DirectiveID) { return true; } extern "C" void LLVMInitializeRISCVAsmParser() { Index: lib/Target/RISCV/MCTargetDesc/CMakeLists.txt =================================================================== --- lib/Target/RISCV/MCTargetDesc/CMakeLists.txt +++ lib/Target/RISCV/MCTargetDesc/CMakeLists.txt @@ -2,6 +2,7 @@ RISCVAsmBackend.cpp RISCVELFObjectWriter.cpp RISCVMCAsmInfo.cpp - RISCVMCTargetDesc.cpp RISCVMCCodeEmitter.cpp + RISCVMCExpr.cpp + RISCVMCTargetDesc.cpp ) Index: lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -7,7 +7,9 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/RISCVFixupKinds.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "llvm/ADT/APInt.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCDirectives.h" @@ -43,7 +45,30 @@ return false; } - unsigned getNumFixupKinds() const override { return 1; } + unsigned getNumFixupKinds() const override { + return RISCV::NumTargetFixupKinds; + } + + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { + const static MCFixupKindInfo Infos[RISCV::NumTargetFixupKinds] = { + // This table *must* be in the order that the fixup_* kinds are defined in + // RISCVFixupKinds.h. + // + // name offset bits flags + { "fixup_riscv_hi20", 12, 20, 0 }, + { "fixup_riscv_lo12_i", 20, 12, 0 }, + { "fixup_riscv_lo12_s", 0, 32, 0 }, + { "fixup_riscv_pcrel_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel } + }; + + + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return Infos[Kind - FirstTargetFixupKind]; + } bool mayNeedRelaxation(const MCInst &Inst) const override { return false; } @@ -69,9 +94,49 @@ return true; } +static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) { + switch (Kind) { + default: + llvm_unreachable("Unknown fixup kind!"); + case FK_Data_1: + case FK_Data_2: + case FK_Data_4: + case FK_Data_8: + return Value; + case RISCV::fixup_riscv_lo12_i: + return Value & 0xfff; + case RISCV::fixup_riscv_lo12_s: + return (((Value >> 5) & 0x7f) << 25) | ((Value & 0x1f) << 7); + case RISCV::fixup_riscv_hi20: + case RISCV::fixup_riscv_pcrel_hi20: + // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative. + return ((Value + 0x800) >> 12) & 0xfffff; + } +} + void RISCVAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, uint64_t Value, bool IsPCRel) const { + MCFixupKind Kind = Fixup.getKind(); + unsigned NumBytes = (getFixupKindInfo(Kind).TargetSize + 7) / 8; + if (!Value) + return; // Doesn't change encoding. + MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); + // Apply any target-specific value adjustments. + Value = adjustFixupValue(Fixup.getKind(), Value); + + // Shift the value into position. + Value <<= Info.TargetOffset; + + unsigned Offset = Fixup.getOffset(); + assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); + + // For each byte of the fragment that the fixup touches, mask in the + // bits from the fixup value. + for (unsigned i = 0; i != 4; ++i) { + unsigned Idx = i; + Data[Offset + i] |= uint8_t((Value >> (Idx * 8)) & 0xff); + } return; } Index: lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h =================================================================== --- /dev/null +++ lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -0,0 +1,37 @@ +//===-- RISCVBaseInfo.h - Top level definitions for RISCV MC ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains small standalone enum definitions for the RISCV target +// useful for the compiler back-end and the MC libraries. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVBASEINFO_H +#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVBASEINFO_H + +#include "RISCVMCTargetDesc.h" + +namespace llvm { + +// RISCVII - This namespace holds all of the target specific flags that +// instruction info tracks. All definitions must match RISCVInstrFormats.td. +namespace RISCVII { +enum { + Pseudo = 0, + FrmR = 1, + FrmI = 2, + FrmS = 3, + FrmU = 4, + FrmOther = 5, + + FormMask = 15 +}; +} +} + +#endif Index: lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/RISCVFixupKinds.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCFixup.h" @@ -41,6 +42,18 @@ switch ((unsigned)Fixup.getKind()) { default: llvm_unreachable("invalid fixup kind!"); + case FK_Data_4: + return ELF::R_RISCV_32; + case FK_Data_8: + return ELF::R_RISCV_64; + case RISCV::fixup_riscv_hi20: + return ELF::R_RISCV_HI20; + case RISCV::fixup_riscv_lo12_i: + return ELF::R_RISCV_LO12_I; + case RISCV::fixup_riscv_lo12_s: + return ELF::R_RISCV_LO12_S; + case RISCV::fixup_riscv_pcrel_hi20: + return ELF::R_RISCV_PCREL_HI20; } } Index: lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h =================================================================== --- /dev/null +++ lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -0,0 +1,40 @@ +//===-- RISCVFixupKinds.h - RISCV Specific Fixup Entries --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVFIXUPKINDS_H +#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVFIXUPKINDS_H + +#include "llvm/MC/MCFixup.h" + +#undef RISCV + +namespace llvm { +namespace RISCV { +enum Fixups { + // fixup_riscv_hi20 - 20-bit fixup corresponding to hi(foo) for + // instructions like lui + fixup_riscv_hi20 = FirstTargetFixupKind, + // fixup_riscv_lo12_i - 12-bit fixup corresponding to lo(foo) for + // instructions like addi + fixup_riscv_lo12_i, + // fixup_riscv_lo12_s - 12-bit fixup corresponding to lo(foo) for + // the S-type store instructions + fixup_riscv_lo12_s, + // fixup_riscv_pcrel_hi20 - 20-bit fixup corresponding to pcrel_hi(foo) for + // instructions like auipc + fixup_riscv_pcrel_hi20, + + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind +}; +} // end namespace RISCV +} // end namespace llvm + +#endif Index: lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -11,12 +11,16 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/RISCVBaseInfo.h" +#include "MCTargetDesc/RISCVFixupKinds.h" +#include "MCTargetDesc/RISCVMCExpr.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "llvm/ADT/Statistic.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCAsmInfo.h" @@ -28,15 +32,18 @@ #define DEBUG_TYPE "mccodeemitter" STATISTIC(MCNumEmitted, "Number of MC instructions emitted"); +STATISTIC(MCNumFixups, "Number of MC fixups created."); namespace { class RISCVMCCodeEmitter : public MCCodeEmitter { RISCVMCCodeEmitter(const RISCVMCCodeEmitter &) = delete; void operator=(const RISCVMCCodeEmitter &) = delete; MCContext &Ctx; + MCInstrInfo const &MCII; public: - RISCVMCCodeEmitter(MCContext &ctx) : Ctx(ctx) {} + RISCVMCCodeEmitter(MCContext &ctx, MCInstrInfo const &MCII) + : Ctx(ctx), MCII(MCII) {} ~RISCVMCCodeEmitter() override {} @@ -59,6 +66,7 @@ unsigned getImmOpValueAsr1(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + unsigned getImmOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -68,7 +76,7 @@ MCCodeEmitter *llvm::createRISCVMCCodeEmitter(const MCInstrInfo &MCII, const MCRegisterInfo &MRI, MCContext &Ctx) { - return new RISCVMCCodeEmitter(Ctx); + return new RISCVMCCodeEmitter(Ctx, MCII); } void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, @@ -106,9 +114,7 @@ return Res >> 1; } - llvm_unreachable("Unhandled expression!"); - - return 0; + return getImmOpValue(MI, OpNo, Fixups, STI); } unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, @@ -117,11 +123,43 @@ const MCOperand &MO = MI.getOperand(OpNo); + MCInstrDesc const &Desc = MCII.get(MI.getOpcode()); + unsigned MIFrm = Desc.TSFlags & RISCVII::FormMask; + // If the destination is an immediate, there is nothing to do if (MO.isImm()) return MO.getImm(); - llvm_unreachable("Unhandled expression!"); + assert(MO.isExpr() && + "getImmOpValue expects only expressions or immediates"); + const MCExpr *Expr = MO.getExpr(); + MCExpr::ExprKind Kind = Expr->getKind(); + RISCV::Fixups FixupKind; + if (Kind == MCExpr::Target) { + const RISCVMCExpr *RVExpr = cast(Expr); + + switch (RVExpr->getKind()) { + case RISCVMCExpr::VK_RISCV_None: + case RISCVMCExpr::VK_RISCV_Invalid: + llvm_unreachable("Unhandled fixup kind!"); + break; + case RISCVMCExpr::VK_RISCV_LO: + FixupKind = MIFrm == RISCVII::FrmI ? RISCV::fixup_riscv_lo12_i + : RISCV::fixup_riscv_lo12_s; + break; + case RISCVMCExpr::VK_RISCV_HI: + FixupKind = RISCV::fixup_riscv_hi20; + break; + case RISCVMCExpr::VK_RISCV_PCREL_HI: + FixupKind = RISCV::fixup_riscv_pcrel_hi20; + break; + } + } else { + llvm_unreachable("Unhandled expression!"); + } + Fixups.push_back( + MCFixup::create(0, Expr, MCFixupKind(FixupKind), MI.getLoc())); + ++MCNumFixups; return 0; } Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h =================================================================== --- /dev/null +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -0,0 +1,75 @@ +//===-- RISCVMCExpr.h - RISCV 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. +// +//===----------------------------------------------------------------------===// +// +// This file describes RISCV-specific MCExprs, used for modifiers like +// "%hi" or "%lo" etc., +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCEXPR_H +#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCEXPR_H + +#include "llvm/MC/MCExpr.h" + +namespace llvm { + +class StringRef; +class RISCVMCExpr : public MCTargetExpr { +public: + enum VariantKind { + VK_RISCV_None, + VK_RISCV_LO, + VK_RISCV_HI, + VK_RISCV_PCREL_HI, + VK_RISCV_Invalid + }; + +private: + const MCExpr *Expr; + const VariantKind Kind; + + int64_t evaluateAsInt64(int64_t Value) const; + + explicit RISCVMCExpr(const MCExpr *Expr, VariantKind Kind) + : Expr(Expr), Kind(Kind) {} + +public: + static const RISCVMCExpr *create(const MCExpr *Expr, VariantKind Kind, + MCContext &Ctx); + + VariantKind getKind() const { return Kind; } + + const MCExpr *getSubExpr() const { return Expr; } + + void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override; + 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 RISCVMCExprs at the moment. + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} + + bool evaluateAsConstant(int64_t &Res) const; + + static bool classof(const MCExpr *E) { + return E->getKind() == MCExpr::Target; + } + + static bool classof(const RISCVMCExpr *) { return true; } + + static VariantKind getVariantKindForName(StringRef name); + static StringRef getVariantKindName(VariantKind Kind); +}; + +} // end namespace llvm. + +#endif Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp =================================================================== --- /dev/null +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -0,0 +1,96 @@ +//===-- RISCVMCExpr.cpp - RISCV 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. +// +//===----------------------------------------------------------------------===// +// +// This file contains the implementation of the assembly expression modifiers +// accepted by the RISCV architecture (e.g. ":lo12:", ":gottprel_g1:", ...). +// +//===----------------------------------------------------------------------===// + +#include "RISCVMCExpr.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +#define DEBUG_TYPE "riscvmcexpr" + +const RISCVMCExpr *RISCVMCExpr::create(const MCExpr *Expr, VariantKind Kind, + MCContext &Ctx) { + return new (Ctx) RISCVMCExpr(Expr, Kind); +} + +void RISCVMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { + bool HasVariant = getKind() != VK_RISCV_None; + if (HasVariant) + OS << '%' << getVariantKindName(getKind()) << '('; + Expr->print(OS, MAI); + if (HasVariant) + OS << ')'; +} + +bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout, + const MCFixup *Fixup) const { + return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup); +} + +void RISCVMCExpr::visitUsedExpr(MCStreamer &Streamer) const { + Streamer.visitUsedExpr(*getSubExpr()); +} + +RISCVMCExpr::VariantKind RISCVMCExpr::getVariantKindForName(StringRef name) { + return StringSwitch(name) + .Case("lo", VK_RISCV_LO) + .Case("hi", VK_RISCV_HI) + .Case("pcrel_hi", VK_RISCV_PCREL_HI) + .Default(VK_RISCV_None); +} + +StringRef RISCVMCExpr::getVariantKindName(VariantKind Kind) { + switch (Kind) { + case VK_RISCV_LO: + return "lo"; + case VK_RISCV_HI: + return "hi"; + case VK_RISCV_PCREL_HI: + return "pcrel_hi"; + default: + llvm_unreachable("Invalid ELF symbol kind"); + } +} + +bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const { + MCValue Value; + + if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr)) + return false; + + if (!Value.isAbsolute()) + return false; + + Res = evaluateAsInt64(Value.getConstant()); + return true; +} + +int64_t RISCVMCExpr::evaluateAsInt64(int64_t Value) const { + switch (Kind) { + case VK_RISCV_LO: + return SignExtend64<12>(Value); + case VK_RISCV_HI: + // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative. + return ((Value + 0x800) >> 12) & 0xfffff; + default: + llvm_unreachable("Invalid kind"); + } +} Index: lib/Target/RISCV/RISCVInstrFormats.td =================================================================== --- lib/Target/RISCV/RISCVInstrFormats.td +++ lib/Target/RISCV/RISCVInstrFormats.td @@ -25,7 +25,20 @@ // //===----------------------------------------------------------------------===// -class RISCVInst pattern> +// Format specifies the encoding used by the instruction. This is used by +// RISCVMCCodeEmitter to determine which form of fixup to use. These +// definitions must be kept in-sync with RISCVBaseInfo.h. +class Format val> { + bits<4> Value = val; +} +def FrmPseudo : Format<0>; +def FrmR : Format<1>; +def FrmI : Format<2>; +def FrmS : Format<3>; +def FrmU : Format<4>; +def FrmOther : Format<5>; + +class RISCVInst pattern, Format format> : Instruction { field bits<32> Inst; // SoftFail is a field the disassembler can use to provide a way for @@ -45,16 +58,18 @@ dag InOperandList = ins; let AsmString = asmstr; let Pattern = pattern; + + let TSFlags{3-0} = format.Value; } // Pseudo instructions class Pseudo pattern> - : RISCVInst { + : RISCVInst { let isPseudo = 1; } class FR funct7, bits<3> funct3, bits<7> opcode, dag outs, dag ins, - string asmstr, list pattern> : RISCVInst + string asmstr, list pattern> : RISCVInst { bits<5> rs2; bits<5> rs1; @@ -69,7 +84,7 @@ } class FI funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list pattern> - : RISCVInst + : RISCVInst { bits<12> imm12; bits<5> rs1; @@ -83,7 +98,7 @@ } class FI32Shift funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list pattern> - : RISCVInst + : RISCVInst { bits<5> shamt; bits<5> rs1; @@ -100,7 +115,7 @@ } class FS funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list pattern> - : RISCVInst + : RISCVInst { bits<12> imm12; bits<5> rs2; @@ -115,7 +130,7 @@ } class FSB funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list pattern> - : RISCVInst + : RISCVInst { bits<12> imm12; bits<5> rs2; @@ -132,7 +147,7 @@ } class FU opcode, dag outs, dag ins, string asmstr, list pattern> - : RISCVInst + : RISCVInst { bits<20> imm20; bits<5> rd; @@ -143,7 +158,7 @@ } class FUJ opcode, dag outs, dag ins, string asmstr, list pattern> - : RISCVInst + : RISCVInst { bits<21> imm20; bits<5> rd; Index: lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.td +++ lib/Target/RISCV/RISCVInstrInfo.td @@ -39,6 +39,7 @@ def simm12 : Operand { let ParserMatchClass = SImmAsmOperand<12>; + let EncoderMethod = "getImmOpValue"; let DecoderMethod = "decodeSImmOperand<12>"; } @@ -157,7 +158,7 @@ def OR : ALU_rr<0b0000000, 0b110, "or">; def AND : ALU_rr<0b0000000, 0b111, "and">; -def FENCE : RISCVInst<(outs), (ins uimm4:$pred, uimm4:$succ), "fence\t$pred, $succ", []> +def FENCE : RISCVInst<(outs), (ins uimm4:$pred, uimm4:$succ), "fence\t$pred, $succ", [], FrmOther> { bits<4> pred; bits<4> succ; @@ -169,7 +170,7 @@ let Inst{31-28} = 0; } -def FENCEI : RISCVInst<(outs), (ins), "fence.i", []> { +def FENCEI : RISCVInst<(outs), (ins), "fence.i", [], FrmOther> { let Opcode = 0b0001111; let Inst{11-7} = 0; let Inst{14-12} = 0b001; Index: test/MC/RISCV/fixups.s =================================================================== --- /dev/null +++ test/MC/RISCV/fixups.s @@ -0,0 +1,27 @@ +# RUN: llvm-mc -triple riscv32 < %s -show-encoding \ +# RUN: | FileCheck -check-prefix=CHECK-FIXUP %s +# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \ +# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INSTR %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 %s \ +# RUN: | llvm-readobj -r | FileCheck %s -check-prefix=CHECK-REL + +# Checks that fixups that can be resolved within the same object file are +# applied correctly + +lui t1, %hi(val) +# CHECK-FIXUP: fixup A - offset: 0, value: %hi(val), kind: fixup_riscv_hi20 +# CHECK-INSTR: lui t1, 74565 + +lw a0, %lo(val)(t1) +# CHECK-FIXUP: fixup A - offset: 0, value: %lo(val), kind: fixup_riscv_lo12_i +# CHECK-INSTR: lw a0, 1656(t1) +addi a1, t1, %lo(val) +# CHECK-FIXUP: fixup A - offset: 0, value: %lo(val), kind: fixup_riscv_lo12_i +# CHECK-INSTR: addi a1, t1, 1656 +sw a0, %lo(val)(t1) +# CHECK-FIXUP: fixup A - offset: 0, value: %lo(val), kind: fixup_riscv_lo12_s +# CHECK-INSTR: sw a0, 1656(t1) + +.set val, 0x12345678 + +# CHECK-REL-NOT: R_RISCV Index: test/MC/RISCV/hilo-constaddr.s =================================================================== --- /dev/null +++ test/MC/RISCV/hilo-constaddr.s @@ -0,0 +1,39 @@ +# RUN: llvm-mc -filetype=obj -triple=riscv32 %s \ +# RUN: | llvm-objdump -d - | FileCheck %s -check-prefix=CHECK-INSTR + +# RUN: llvm-mc -filetype=obj -triple=riscv32 %s \ +# RUN: | llvm-readobj -r | FileCheck %s -check-prefix=CHECK-REL + +# Check the assembler can handle hi and lo expressions with a constant +# address, and constant expressions involving labels. Test case derived from +# test/MC/Mips/hilo-addressing.s + +# Check that 1 is added to the high 20 bits if bit 11 of the low part is 1. +.equ addr, 0xdeadbeef + lui t0, %hi(addr) + lw ra, %lo(addr)(t0) +# CHECK-INSTR: lui t0, 912092 +# CHECK-INSTR: lw ra, -273(t0) + +# Check that assembler can handle %hi(label1 - label2) and %lo(label1 - label2) +# expressions. + +tmp1: + # Emit zeros so that difference between tmp1 and tmp3 is 0x30124 bytes. + .fill 0x30124-8 +tmp2: + lui t0, %hi(tmp3-tmp1) + lw ra, %lo(tmp3-tmp1)(t0) +# CHECK-INSTR: lui t0, 48 +# CHECK-INSTR: lw ra, 292(t0) + +tmp3: + lui t1, %hi(tmp2-tmp3) + lw sp, %lo(tmp2-tmp3)(t1) +# CHECK-INSTR: lui t1, 0 +# CHECK-INSTR: lw sp, -8(t1) + +# Check that a relocation isn't emitted for %hi(label1 - label2) and +# %lo(label1 - label2) expressions. + +# CHECK-REL-NOT: R_RISCV Index: test/MC/RISCV/relocations.s =================================================================== --- /dev/null +++ test/MC/RISCV/relocations.s @@ -0,0 +1,35 @@ +# RUN: llvm-mc -triple riscv32 < %s -show-encoding \ +# RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s +# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \ +# RUN: | llvm-readobj -r | FileCheck -check-prefix=RELOC %s + +# Check prefixes: +# RELOC - Check the relocation in the object. +# FIXUP - Check the fixup on the instruction. +# INSTR - Check the instruction is handled properly by the ASMPrinter + +.long foo +# RELOC: R_RISCV_32 foo + +.quad foo +# RELOC: R_RISCV_64 foo + +lui t1, %hi(foo) +# RELOC: R_RISCV_HI20 foo +# INSTR: lui t1, %hi(foo) +# FIXUP: fixup A - offset: 0, value: %hi(foo), kind: fixup_riscv_hi20 + +addi t1, t1, %lo(foo) +# RELOC: R_RISCV_LO12_I foo +# INSTR: addi t1, t1, %lo(foo) +# FIXUP: fixup A - offset: 0, value: %lo(foo), kind: fixup_riscv_lo12_i + +sb t1, %lo(foo)(a2) +# RELOC: R_RISCV_LO12_S foo +# INSTR: sb t1, %lo(foo)(a2) +# FIXUP: fixup A - offset: 0, value: %lo(foo), kind: fixup_riscv_lo12_s + +auipc t1, %pcrel_hi(foo) +# RELOC: R_RISCV_PCREL_HI20 +# INSTR: auipc t1, %pcrel_hi(foo) +# FIXUP: fixup A - offset: 0, value: %pcrel_hi(foo), kind: fixup_riscv_pcrel_hi20 Index: test/MC/RISCV/rv32i-invalid.s =================================================================== --- test/MC/RISCV/rv32i-invalid.s +++ test/MC/RISCV/rv32i-invalid.s @@ -53,9 +53,9 @@ nandi t0, zero, 0 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic # Invalid register names -addi foo, sp, 10 # CHECK: :[[@LINE]]:6: error: unknown operand -slti a10, a2, 0x20 # CHECK: :[[@LINE]]:6: error: unknown operand -slt x32, s0, s0 # CHECK: :[[@LINE]]:5: error: unknown operand +addi foo, sp, 10 # CHECK: :[[@LINE]]:6: error: invalid operand for instruction +slti a10, a2, 0x20 # CHECK: :[[@LINE]]:6: error: invalid operand for instruction +slt x32, s0, s0 # CHECK: :[[@LINE]]:5: error: invalid operand for instruction # RV64I mnemonics addiw a0, sp, 100 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic Index: test/MC/RISCV/rv32i-valid.s =================================================================== --- test/MC/RISCV/rv32i-valid.s +++ test/MC/RISCV/rv32i-valid.s @@ -7,8 +7,12 @@ lui a0, 2 # CHECK: encoding: [0x37,0x25,0x00,0x00] # CHECK-DIS: lui a0, 2 +lui a0, %hi(2) # CHECK: encoding: [0x37,0x05,0x00,0x00] +# CHECK-DIS: lui a0, 0 lui s11, (0x87000000>>12) # CHECK: encoding: [0xb7,0x0d,0x00,0x87] # CHECK-DIS: lui s11, 552960 +lui s11, %hi(0x87000000) # CHECK: encoding: [0xb7,0x0d,0x00,0x87] +# CHECK-DIS: lui s11, 552960 lui t0, 1048575 # CHECK: encoding: [0xb7,0xf2,0xff,0xff] # CHECK-DIS: lui t0, 1048575 lui gp, 0 # CHECK: encoding: [0xb7,0x01,0x00,0x00] @@ -30,6 +34,8 @@ jalr a0, a1, -2048 # CHECK: encoding: [0x67,0x85,0x05,0x80] # CHECK-DIS: jalr a0, a1, -2048 +jalr a0, a1, %lo(2048) # CHECK: encoding: [0x67,0x85,0x05,0x80] +# CHECK-DIS: jalr a0, a1, -2048 jalr t2, t1, 2047 # CHECK: encoding: [0xe7,0x03,0xf3,0x7f] # CHECK-DIS: jalr t2, t1, 2047 jalr sp, zero, 256 # CHECK: encoding: [0x67,0x01,0x00,0x10] @@ -55,6 +61,8 @@ # CHECK-DIS: lb s3, 4(ra) lh t1, -2048(zero) # CHECK: encoding: [0x03,0x13,0x00,0x80] # CHECK-DIS: lh t1, -2048(zero) +lh t1, %lo(2048)(zero) # CHECK: encoding: [0x03,0x13,0x00,0x80] +# CHECK-DIS: lh t1, -2048(zero) lh sp, 2047(a0) # CHECK: encoding: [0x03,0x11,0xf5,0x7f] # CHECK-DIS: lh sp, 2047(a0) lw a0, 97(a2) # CHECK: encoding: [0x03,0x25,0x16,0x06] @@ -68,6 +76,8 @@ # CHECK-DIS: sb a0, 2047(a2) sh t3, -2048(t5) # CHECK: encoding: [0x23,0x10,0xcf,0x81] # CHECK-DIS: sh t3, -2048(t5) +sh t3, %lo(2048)(t5) # CHECK: encoding: [0x23,0x10,0xcf,0x81] +# CHECK-DIS: sh t3, -2048(t5) sw ra, 999(zero) # CHECK: encoding: [0xa3,0x23,0x10,0x3e] # CHECK-DIS: sw ra, 999(zero) @@ -81,6 +91,8 @@ # CHECK-DIS: xori tp, t1, -99 ori a0, a1, -2048 # CHECK: encoding: [0x13,0xe5,0x05,0x80] # CHECK-DIS: ori a0, a1, -2048 +ori a0, a1, %lo(2048) # CHECK: encoding: [0x13,0xe5,0x05,0x80] +# CHECK-DIS: ori a0, a1, -2048 andi ra, sp, 2047 # CHECK: encoding: [0x93,0x70,0xf1,0x7f] # CHECK-DIS: andi ra, sp, 2047 andi x1, x2, 2047 # CHECK: encoding: [0x93,0x70,0xf1,0x7f]