From: Alex Bradbury Date: Thu, 28 Sep 2017 08:26:24 +0000 (+0000) Subject: [RISCV] Add common fixups and relocations X-Git-Tag: llvmorg-6.0.0-rc1~7010 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9d3f12501a4594421a8d07053dd9dbaa652c7418;p=platform%2Fupstream%2Fllvm.git [RISCV] Add common fixups and relocations %lo(), %hi(), and %pcrel_hi() are supported and test cases have been added to ensure the appropriate fixups and relocations are generated. I've added an instruction format field which is used in RISCVMCCodeEmitter to, for instance, tell whether it should emit a lo12_i fixup or a lo12_s fixup (RISC-V has two 12-bit immediate encodings depending on the instruction type). Differential Revision: https://reviews.llvm.org/D23568 llvm-svn: 314389 --- diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 4b1eec9..b0db5f4 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "MCTargetDesc/RISCVBaseInfo.h" +#include "MCTargetDesc/RISCVMCExpr.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" @@ -53,6 +54,7 @@ class RISCVAsmParser : public MCTargetAsmParser { OperandMatchResultTy parseImmediate(OperandVector &Operands); OperandMatchResultTy parseRegister(OperandVector &Operands); OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands); + OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); bool parseOperand(OperandVector &Operands); @@ -64,6 +66,10 @@ public: #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) { @@ -121,13 +127,32 @@ public: bool isImm() const override { return Kind == Immediate; } bool isMem() const override { return false; } - bool isConstantImm() const { - return isImm() && dyn_cast(getImm()); - } - - int64_t getConstantImm() const { + bool evaluateConstantImm(int64_t &Imm, RISCVMCExpr::VariantKind &VK) const { const MCExpr *Val = getImm(); - return static_cast(Val)->getValue(); + bool Ret = false; + if (auto *RE = dyn_cast(Val)) { + Ret = RE->evaluateAsConstant(Imm); + VK = RE->getKind(); + } else if (auto CE = dyn_cast(Val)) { + Ret = true; + VK = RISCVMCExpr::VK_RISCV_None; + Imm = CE->getValue(); + } + return Ret; + } + + // True if operand is a symbol with no modifiers, or a constant with no + // modifiers and isShiftedInt(Op). + template bool isBareSimmNLsb0() const { + int64_t Imm; + RISCVMCExpr::VariantKind VK; + bool IsConstantImm = evaluateConstantImm(Imm, VK); + bool IsValid; + if (!IsConstantImm) + IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); + else + IsValid = isShiftedInt(Imm); + return IsValid && VK == RISCVMCExpr::VK_RISCV_None; } // Predicate methods for AsmOperands defined in RISCVInstrInfo.td @@ -158,28 +183,49 @@ public: } bool isUImm5() const { - return (isConstantImm() && isUInt<5>(getConstantImm())); + int64_t Imm; + RISCVMCExpr::VariantKind VK; + bool IsConstantImm = evaluateConstantImm(Imm, VK); + return IsConstantImm && isUInt<5>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; } bool isSImm12() const { - return (isConstantImm() && isInt<12>(getConstantImm())); + RISCVMCExpr::VariantKind VK; + int64_t Imm; + bool IsValid; + bool IsConstantImm = evaluateConstantImm(Imm, VK); + if (!IsConstantImm) + IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); + else + IsValid = isInt<12>(Imm); + return IsValid && + (VK == RISCVMCExpr::VK_RISCV_None || VK == RISCVMCExpr::VK_RISCV_LO); } bool isUImm12() const { - return (isConstantImm() && isUInt<12>(getConstantImm())); + int64_t Imm; + RISCVMCExpr::VariantKind VK; + bool IsConstantImm = evaluateConstantImm(Imm, VK); + return IsConstantImm && isUInt<12>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; } - bool isSImm13Lsb0() const { - return (isConstantImm() && isShiftedInt<12, 1>(getConstantImm())); - } + bool isSImm13Lsb0() const { return isBareSimmNLsb0<13>(); } bool isUImm20() const { - return (isConstantImm() && isUInt<20>(getConstantImm())); + RISCVMCExpr::VariantKind VK; + int64_t Imm; + bool IsValid; + bool IsConstantImm = evaluateConstantImm(Imm, VK); + if (!IsConstantImm) + IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); + else + IsValid = isUInt<20>(Imm); + return IsValid && (VK == RISCVMCExpr::VK_RISCV_None || + VK == RISCVMCExpr::VK_RISCV_HI || + VK == RISCVMCExpr::VK_RISCV_PCREL_HI); } - bool isSImm21Lsb0() const { - return (isConstantImm() && isShiftedInt<20, 1>(getConstantImm())); - } + bool isSImm21Lsb0() const { return isBareSimmNLsb0<21>(); } /// getStartLoc - Gets location of the first token of this operand SMLoc getStartLoc() const override { return StartLoc; } @@ -234,7 +280,7 @@ public: } static std::unique_ptr createImm(const MCExpr *Val, SMLoc S, - SMLoc E) { + SMLoc E, MCContext &Ctx) { auto Op = make_unique(Immediate); Op->Imm.Val = Val; Op->StartLoc = S; @@ -244,8 +290,17 @@ public: void addExpr(MCInst &Inst, const MCExpr *Expr) const { assert(Expr && "Expr shouldn't be null!"); - if (auto *CE = dyn_cast(Expr)) - Inst.addOperand(MCOperand::createImm(CE->getValue())); + int64_t Imm = 0; + bool IsConstant = false; + if (auto *RE = dyn_cast(Expr)) { + IsConstant = RE->evaluateAsConstant(Imm); + } else if (auto *CE = dyn_cast(Expr)) { + IsConstant = true; + Imm = CE->getValue(); + } + + if (IsConstant) + Inst.addOperand(MCOperand::createImm(Imm)); else Inst.addOperand(MCOperand::createExpr(Expr)); } @@ -411,9 +466,51 @@ OperandMatchResultTy RISCVAsmParser::parseImmediate(OperandVector &Operands) { Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); break; } + case AsmToken::Percent: + return parseOperandWithModifier(Operands); + } + + Operands.push_back(RISCVOperand::createImm(Res, S, E, getContext())); + return MatchOperand_Success; +} + +OperandMatchResultTy +RISCVAsmParser::parseOperandWithModifier(OperandVector &Operands) { + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + + if (getLexer().getKind() != AsmToken::Percent) { + Error(getLoc(), "expected '%' for operand modifier"); + return MatchOperand_ParseFail; + } + + getParser().Lex(); // Eat '%' + + if (getLexer().getKind() != AsmToken::Identifier) { + Error(getLoc(), "expected valid identifier for operand modifier"); + return MatchOperand_ParseFail; + } + StringRef Identifier = getParser().getTok().getIdentifier(); + RISCVMCExpr::VariantKind VK = RISCVMCExpr::getVariantKindForName(Identifier); + if (VK == RISCVMCExpr::VK_RISCV_Invalid) { + Error(getLoc(), "unrecognized operand modifier"); + return MatchOperand_ParseFail; + } + + getParser().Lex(); // Eat the identifier + if (getLexer().getKind() != AsmToken::LParen) { + Error(getLoc(), "expected '('"); + return MatchOperand_ParseFail; + } + getParser().Lex(); // Eat '(' + + const MCExpr *SubExpr; + if (getParser().parseParenExpression(SubExpr, E)) { + return MatchOperand_ParseFail; } - Operands.push_back(RISCVOperand::createImm(Res, S, E)); + const MCExpr *ModExpr = RISCVMCExpr::create(SubExpr, VK, getContext()); + Operands.push_back(RISCVOperand::createImm(ModExpr, S, E, getContext())); return MatchOperand_Success; } @@ -498,6 +595,51 @@ bool RISCVAsmParser::ParseInstruction(ParseInstructionInfo &Info, return false; } +bool RISCVAsmParser::classifySymbolRef(const MCExpr *Expr, + RISCVMCExpr::VariantKind &Kind, + int64_t &Addend) { + Kind = RISCVMCExpr::VK_RISCV_None; + Addend = 0; + + if (const RISCVMCExpr *RE = dyn_cast(Expr)) { + Kind = RE->getKind(); + Expr = RE->getSubExpr(); + } + + // It's a simple symbol reference or constant with no addend. + if (isa(Expr) || isa(Expr)) + return true; + + const MCBinaryExpr *BE = dyn_cast(Expr); + if (!BE) + return false; + + if (!isa(BE->getLHS())) + return false; + + if (BE->getOpcode() != MCBinaryExpr::Add && + BE->getOpcode() != MCBinaryExpr::Sub) + return false; + + // We are able to support the subtraction of two symbol references + if (BE->getOpcode() == MCBinaryExpr::Sub && + isa(BE->getRHS())) + return true; + + // 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() { diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt index d79de74..6042964 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt +++ b/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt @@ -2,6 +2,7 @@ add_llvm_library(LLVMRISCVDesc RISCVAsmBackend.cpp RISCVELFObjectWriter.cpp RISCVMCAsmInfo.cpp - RISCVMCTargetDesc.cpp RISCVMCCodeEmitter.cpp + RISCVMCExpr.cpp + RISCVMCTargetDesc.cpp ) diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index 4896c38..692a179 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -7,9 +7,12 @@ // //===----------------------------------------------------------------------===// +#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/MCContext.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCExpr.h" @@ -44,7 +47,31 @@ public: 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 }, + { "fixup_riscv_jal", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_riscv_branch", 0, 32, 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; } @@ -70,10 +97,88 @@ bool RISCVAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const { return true; } +static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, + MCContext &Ctx) { + unsigned Kind = Fixup.getKind(); + 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; + case RISCV::fixup_riscv_jal: { + if (!isInt<21>(Value)) + Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + if (Value & 0x1) + Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned"); + // Need to produce imm[19|10:1|11|19:12] from the 21-bit Value. + unsigned Sbit = (Value >> 20) & 0x1; + unsigned Hi8 = (Value >> 12) & 0xff; + unsigned Mid1 = (Value >> 11) & 0x1; + unsigned Lo10 = (Value >> 1) & 0x3ff; + // Inst{31} = Sbit; + // Inst{30-21} = Lo10; + // Inst{20} = Mid1; + // Inst{19-12} = Hi8; + Value = (Sbit << 19) | (Lo10 << 9) | (Mid1 << 8) | Hi8; + return Value; + } + case RISCV::fixup_riscv_branch: { + if (!isInt<13>(Value)) + Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + if (Value & 0x1) + Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned"); + // Need to extract imm[12], imm[10:5], imm[4:1], imm[11] from the 13-bit + // Value. + unsigned Sbit = (Value >> 12) & 0x1; + unsigned Hi1 = (Value >> 11) & 0x1; + unsigned Mid6 = (Value >> 5) & 0x3f; + unsigned Lo4 = (Value >> 1) & 0xf; + // Inst{31} = Sbit; + // Inst{30-25} = Mid6; + // Inst{11-8} = Lo4; + // Inst{7} = Hi1; + Value = (Sbit << 31) | (Mid6 << 25) | (Lo4 << 8) | (Hi1 << 7); + return Value; + } + + } +} + void RISCVAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef Data, uint64_t Value, bool IsResolved) const { + MCContext &Ctx = Asm.getContext(); + 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, Value, Ctx); + + // Shift the value into position. + Value <<= Info.TargetOffset; + + unsigned Offset = Fixup.getOffset(); + assert(Offset + NumBytes <= Data.size() && "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) { + Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); + } return; } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h index c3bf321..cfb1242 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -32,6 +32,7 @@ enum { InstFormatMask = 15 }; + enum { MO_None, MO_LO, diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp index 93c981e..95d4242 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/llvm/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" @@ -37,7 +38,27 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { - report_fatal_error("invalid fixup kind!"); + // Determine the type of the relocation + 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; + case RISCV::fixup_riscv_jal: + return ELF::R_RISCV_JAL; + case RISCV::fixup_riscv_branch: + return ELF::R_RISCV_BRANCH; + } } MCObjectWriter *llvm::createRISCVELFObjectWriter(raw_pwrite_stream &OS, diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h new file mode 100644 index 0000000..1152294 --- /dev/null +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -0,0 +1,46 @@ +//===-- 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, + // fixup_riscv_jal - 20-bit fixup for symbol references in the jal + // instruction + fixup_riscv_jal, + // fixup_riscv_branch - 12-bit fixup for symbol references in the branch + // instructions + fixup_riscv_branch, + + // fixup_riscv_invalid - used as a sentinel and a marker, must be last fixup + fixup_riscv_invalid, + NumTargetFixupKinds = fixup_riscv_invalid - FirstTargetFixupKind +}; +} // end namespace RISCV +} // end namespace llvm + +#endif diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp index f4eaf06..f821215 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -11,6 +11,9 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/RISCVBaseInfo.h" +#include "MCTargetDesc/RISCVFixupKinds.h" +#include "MCTargetDesc/RISCVMCExpr.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "llvm/ADT/Statistic.h" #include "llvm/MC/MCAsmInfo.h" @@ -18,8 +21,10 @@ #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/Support/Casting.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/raw_ostream.h" @@ -28,15 +33,18 @@ using namespace llvm; #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 +67,7 @@ public: 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 +77,7 @@ public: 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, @@ -107,9 +116,7 @@ RISCVMCCodeEmitter::getImmOpValueAsr1(const MCInst &MI, unsigned OpNo, return Res >> 1; } - llvm_unreachable("Unhandled expression!"); - - return 0; + return getImmOpValue(MI, OpNo, Fixups, STI); } unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, @@ -118,11 +125,50 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, const MCOperand &MO = MI.getOperand(OpNo); + MCInstrDesc const &Desc = MCII.get(MI.getOpcode()); + unsigned MIFrm = Desc.TSFlags & RISCVII::InstFormatMask; + // 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 = RISCV::fixup_riscv_invalid; + 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!"); + case RISCVMCExpr::VK_RISCV_LO: + FixupKind = MIFrm == RISCVII::InstFormatI ? 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 if (Kind == MCExpr::SymbolRef && + cast(Expr)->getKind() == MCSymbolRefExpr::VK_None) { + if (Desc.getOpcode() == RISCV::JAL) { + FixupKind = RISCV::fixup_riscv_jal; + } else if (MIFrm == RISCVII::InstFormatSB) { + FixupKind = RISCV::fixup_riscv_branch; + } + } + + assert(FixupKind != RISCV::fixup_riscv_invalid && "Unhandled expression!"); + + Fixups.push_back( + MCFixup::create(0, Expr, MCFixupKind(FixupKind), MI.getLoc())); + ++MCNumFixups; return 0; } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp new file mode 100644 index 0000000..b36236e --- /dev/null +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -0,0 +1,99 @@ +//===-- 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_Invalid); +} + +StringRef RISCVMCExpr::getVariantKindName(VariantKind Kind) { + switch (Kind) { + default: + llvm_unreachable("Invalid ELF symbol kind"); + case VK_RISCV_LO: + return "lo"; + case VK_RISCV_HI: + return "hi"; + case VK_RISCV_PCREL_HI: + return "pcrel_hi"; + } +} + +bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const { + MCValue Value; + + if (Kind == VK_RISCV_PCREL_HI) + return false; + + 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) { + default: + llvm_unreachable("Invalid 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; + } +} diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h new file mode 100644 index 0000000..69b55ca --- /dev/null +++ b/llvm/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 diff --git a/llvm/lib/Target/RISCV/RISCVInstrFormats.td b/llvm/lib/Target/RISCV/RISCVInstrFormats.td index d77f387..383b73c 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrFormats.td +++ b/llvm/lib/Target/RISCV/RISCVInstrFormats.td @@ -25,7 +25,22 @@ // //===----------------------------------------------------------------------===// -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 InstFormat val> { + bits<4> Value = val; +} +def InstFormatPseudo : InstFormat<0>; +def InstFormatR : InstFormat<1>; +def InstFormatI : InstFormat<2>; +def InstFormatS : InstFormat<3>; +def InstFormatSB : InstFormat<4>; +def InstFormatU : InstFormat<5>; +def InstFormatOther : InstFormat<6>; + +class RISCVInst pattern, + InstFormat format> : Instruction { field bits<32> Inst; // SoftFail is a field the disassembler can use to provide a way for @@ -45,17 +60,19 @@ class RISCVInst pattern> dag InOperandList = ins; let AsmString = asmstr; let Pattern = pattern; + + let TSFlags{3-0} = format.Value; } // Pseudo instructions -class Pseudo pattern> - : RISCVInst { +class Pseudo pattern> + : RISCVInst { let isPseudo = 1; let isCodeGenOnly = 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; @@ -70,7 +87,7 @@ class FR funct7, bits<3> funct3, bits<7> opcode, dag outs, dag ins, } class FI funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list pattern> - : RISCVInst + : RISCVInst { bits<12> imm12; bits<5> rs1; @@ -84,7 +101,7 @@ class FI funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list< } class FI32Shift funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list pattern> - : RISCVInst + : RISCVInst { bits<5> shamt; bits<5> rs1; @@ -101,7 +118,7 @@ class FI32Shift funct3, bits<7> opcode, dag outs, dag in } class FS funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list pattern> - : RISCVInst + : RISCVInst { bits<12> imm12; bits<5> rs2; @@ -116,7 +133,7 @@ class FS funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list< } class FSB funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list pattern> - : RISCVInst + : RISCVInst { bits<12> imm12; bits<5> rs2; @@ -133,7 +150,7 @@ class FSB funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list } class FU opcode, dag outs, dag ins, string asmstr, list pattern> - : RISCVInst + : RISCVInst { bits<20> imm20; bits<5> rd; @@ -144,7 +161,7 @@ class FU opcode, dag outs, dag ins, string asmstr, list pattern> } class FUJ opcode, dag outs, dag ins, string asmstr, list pattern> - : RISCVInst + : RISCVInst { bits<20> imm20; bits<5> rd; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index e84e4da..1a5f32e 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -46,6 +46,7 @@ def uimm5 : Operand { def simm12 : Operand { let ParserMatchClass = SImmAsmOperand<12>; + let EncoderMethod = "getImmOpValue"; let DecoderMethod = "decodeSImmOperand<12>"; } diff --git a/llvm/test/MC/RISCV/fixups-diagnostics.s b/llvm/test/MC/RISCV/fixups-diagnostics.s new file mode 100644 index 0000000..d346605 --- /dev/null +++ b/llvm/test/MC/RISCV/fixups-diagnostics.s @@ -0,0 +1,18 @@ +# RUN: not llvm-mc -triple riscv32 -filetype obj < %s -o /dev/null 2>&1 | FileCheck %s + + jal a0, far_distant # CHECK: :[[@LINE]]:3: error: fixup value out of range + jal a0, unaligned # CHECK: :[[@LINE]]:3: error: fixup value must be 2-byte aligned + + beq a0, a1, distant # CHECK: :[[@LINE]]:3: error: fixup value out of range + blt t0, t1, unaligned # CHECK: :[[@LINE]]:3: error: fixup value must be 2-byte aligned + + .byte 0 +unaligned: + .byte 0 + .byte 0 + .byte 0 + + .space 1<<12 +distant: + .space 1<<20 +far_distant: diff --git a/llvm/test/MC/RISCV/fixups.s b/llvm/test/MC/RISCV/fixups.s new file mode 100644 index 0000000..19cc692 --- /dev/null +++ b/llvm/test/MC/RISCV/fixups.s @@ -0,0 +1,49 @@ +# 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 + +.LBB0: +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) + +jal zero, .LBB0 +# CHECK-FIXUP: fixup A - offset: 0, value: .LBB0, kind: fixup_riscv_jal +# CHECK-INSTR: jal zero, -16 +jal zero, .LBB2 +# CHECK-FIXUP: fixup A - offset: 0, value: .LBB2, kind: fixup_riscv_jal +# CHECK-INSTR: jal zero, 330996 +beq a0, a1, .LBB0 +# CHECK-FIXUP: fixup A - offset: 0, value: .LBB0, kind: fixup_riscv_branch +# CHECK-INSTR: beq a0, a1, -24 +blt a0, a1, .LBB1 +# CHECK-FIXUP: fixup A - offset: 0, value: .LBB1, kind: fixup_riscv_branch +# CHECK-INSTR: blt a0, a1, 1108 + +.fill 1104 + +.LBB1: + +.fill 329876 +addi zero, zero, 0 +.LBB2: + +.set val, 0x12345678 + +# CHECK-REL-NOT: R_RISCV diff --git a/llvm/test/MC/RISCV/hilo-constaddr.s b/llvm/test/MC/RISCV/hilo-constaddr.s new file mode 100644 index 0000000..691401f --- /dev/null +++ b/llvm/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 diff --git a/llvm/test/MC/RISCV/relocations.s b/llvm/test/MC/RISCV/relocations.s new file mode 100644 index 0000000..c11e2f3 --- /dev/null +++ b/llvm/test/MC/RISCV/relocations.s @@ -0,0 +1,65 @@ +# 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 0x0 +# INSTR: lui t1, %hi(foo) +# FIXUP: fixup A - offset: 0, value: %hi(foo), kind: fixup_riscv_hi20 + +lui t1, %hi(foo+4) +# RELOC: R_RISCV_HI20 foo 0x4 +# INSTR: lui t1, %hi(foo+4) +# FIXUP: fixup A - offset: 0, value: %hi(foo+4), kind: fixup_riscv_hi20 + +addi t1, t1, %lo(foo) +# RELOC: R_RISCV_LO12_I foo 0x0 +# INSTR: addi t1, t1, %lo(foo) +# FIXUP: fixup A - offset: 0, value: %lo(foo), kind: fixup_riscv_lo12_i + +addi t1, t1, %lo(foo+4) +# RELOC: R_RISCV_LO12_I foo 0x4 +# INSTR: addi t1, t1, %lo(foo+4) +# FIXUP: fixup A - offset: 0, value: %lo(foo+4), kind: fixup_riscv_lo12_i + +sb t1, %lo(foo)(a2) +# RELOC: R_RISCV_LO12_S foo 0x0 +# INSTR: sb t1, %lo(foo)(a2) +# FIXUP: fixup A - offset: 0, value: %lo(foo), kind: fixup_riscv_lo12_s + +sb t1, %lo(foo+4)(a2) +# RELOC: R_RISCV_LO12_S foo 0x4 +# INSTR: sb t1, %lo(foo+4)(a2) +# FIXUP: fixup A - offset: 0, value: %lo(foo+4), kind: fixup_riscv_lo12_s + +auipc t1, %pcrel_hi(foo) +# RELOC: R_RISCV_PCREL_HI20 foo 0x0 +# INSTR: auipc t1, %pcrel_hi(foo) +# FIXUP: fixup A - offset: 0, value: %pcrel_hi(foo), kind: fixup_riscv_pcrel_hi20 + +auipc t1, %pcrel_hi(foo+4) +# RELOC: R_RISCV_PCREL_HI20 foo 0x4 +# INSTR: auipc t1, %pcrel_hi(foo+4) +# FIXUP: fixup A - offset: 0, value: %pcrel_hi(foo+4), kind: fixup_riscv_pcrel_hi20 + +jal zero, foo +# RELOC: R_RISCV_JAL +# INSTR: jal zero, foo +# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_jal + +bgeu a0, a1, foo +# RELOC: R_RISCV_BRANCH +# INSTR: bgeu a0, a1, foo +# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_branch diff --git a/llvm/test/MC/RISCV/rv32i-invalid.s b/llvm/test/MC/RISCV/rv32i-invalid.s index faafbfb..da49b93 100644 --- a/llvm/test/MC/RISCV/rv32i-invalid.s +++ b/llvm/test/MC/RISCV/rv32i-invalid.s @@ -15,6 +15,10 @@ csrrwi a1, 0x1, -1 # CHECK: :[[@LINE]]:17: error: immediate must be an integer i csrrsi t1, 999, 32 # CHECK: :[[@LINE]]:17: error: immediate must be an integer in the range [0, 31] csrrci x0, 43, -90 # CHECK: :[[@LINE]]:16: error: immediate must be an integer in the range [0, 31] +## simm12 +ori a0, a1, -2049 # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-2048, 2047] +andi ra, sp, 2048 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [-2048, 2047] + ## uimm12 csrrw a0, -1, a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095] csrrs a0, 4096, a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095] @@ -24,10 +28,6 @@ csrrwi a0, -50, 0 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in csrrsi a0, 4097, a0 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [0, 4095] csrrci a0, 0xffff, a0 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [0, 4095] -## simm12 -ori a0, a1, -2049 # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-2048, 2047] -andi ra, sp, 2048 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [-2048, 2047] - ## simm13_lsb0 beq t0, t1, -4098 # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] bne t0, t1, -4097 # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] @@ -48,6 +48,59 @@ jal gp, 1048575 # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 jal gp, 1048576 # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] jal gp, 1 # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] +# Illegal operand modifier +## fencearg +fence %hi(iorw), iorw # CHECK: :[[@LINE]]:7: error: operand must be formed of letters selected in-order from 'iorw' +fence %lo(iorw), iorw # CHECK: :[[@LINE]]:7: error: operand must be formed of letters selected in-order from 'iorw' +fence %pcrel_hi(iorw), iorw # CHECK: :[[@LINE]]:7: error: operand must be formed of letters selected in-order from 'iorw' + +## uimm5 +slli a0, a0, %lo(1) # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 31] +srli a0, a0, %lo(a) # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 31] +srai a0, a0, %hi(2) # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 31] +csrrwi a1, 0x1, %hi(b) # CHECK: :[[@LINE]]:17: error: immediate must be an integer in the range [0, 31] +csrrsi t1, 999, %pcrel_hi(3) # CHECK: :[[@LINE]]:17: error: immediate must be an integer in the range [0, 31] +csrrci x0, 43, %pcrel_hi(c) # CHECK: :[[@LINE]]:16: error: immediate must be an integer in the range [0, 31] + +## simm12 +ori a0, a1, %hi(foo) # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-2048, 2047] +andi ra, sp, %pcrel_hi(123) # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [-2048, 2047] +xori a2, a3, %hi(345) # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [-2048, 2047] + +## uimm12 +csrrw a0, %lo(1), a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095] +csrrs a0, %lo(a), a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095] +csrrs a0, %hi(2), a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095] +csrrc a0, %hi(b), a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095] +csrrwi a0, %pcrel_hi(3), 0 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [0, 4095] +csrrsi a0, %pcrel_hi(c), a0 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [0, 4095] + +## simm13_lsb0 +beq t0, t1, %lo(1) # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] +bne t0, t1, %lo(a) # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] +blt t0, t1, %hi(2) # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] +bge t0, t1, %hi(b) # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] +bltu t0, t1, %pcrel_hi(3) # CHECK: :[[@LINE]]:14: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] +bgeu t0, t1, %pcrel_hi(c) # CHECK: :[[@LINE]]:14: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] + +## uimm20 +lui a0, %lo(1) # CHECK: :[[@LINE]]:9: error: immediate must be an integer in the range [0, 1048575] +auipc a1, %lo(foo) # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 1048575] + +## simm21_lsb0 +jal gp, %lo(1) # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] +jal gp, %lo(a) # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] +jal gp, %hi(2) # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] +jal gp, %hi(b) # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] +jal gp, %pcrel_hi(3) # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] +jal gp, %pcrel_hi(c) # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] + +# Unrecognized operand modifier +addi t0, sp, %modifer(255) # CHECK: :[[@LINE]]:15: error: unrecognized operand modifier + +# Use of operand modifier on register name +addi t1, %lo(t2), 1 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction + # Invalid mnemonics subs t0, t2, t1 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic nandi t0, zero, 0 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic diff --git a/llvm/test/MC/RISCV/rv32i-valid.s b/llvm/test/MC/RISCV/rv32i-valid.s index 95d9da4..be65600 100644 --- a/llvm/test/MC/RISCV/rv32i-valid.s +++ b/llvm/test/MC/RISCV/rv32i-valid.s @@ -13,6 +13,15 @@ lui a0, 2 # CHECK-INST: lui s11, 552960 # CHECK: encoding: [0xb7,0x0d,0x00,0x87] lui s11, (0x87000000>>12) +# CHECK-INST: lui a0, 0 +# CHECK: encoding: [0x37,0x05,0x00,0x00] +lui a0, %hi(2) +# CHECK-INST: lui s11, 552960 +# CHECK: encoding: [0xb7,0x0d,0x00,0x87] +lui s11, (0x87000000>>12) +# CHECK-INST: lui s11, 552960 +# CHECK: encoding: [0xb7,0x0d,0x00,0x87] +lui s11, %hi(0x87000000) # CHECK-INST: lui t0, 1048575 # CHECK: encoding: [0xb7,0xf2,0xff,0xff] lui t0, 1048575 @@ -43,6 +52,9 @@ jal a3, 256 # CHECK-INST: jalr a0, a1, -2048 # CHECK: encoding: [0x67,0x85,0x05,0x80] jalr a0, a1, -2048 +# CHECK-INST: jalr a0, a1, -2048 +# CHECK: encoding: [0x67,0x85,0x05,0x80] +jalr a0, a1, %lo(2048) # CHECK-INST: jalr t2, t1, 2047 # CHECK: encoding: [0xe7,0x03,0xf3,0x7f] jalr t2, t1, 2047 @@ -78,6 +90,9 @@ lb s3, +4(ra) # CHECK-INST: lh t1, -2048(zero) # CHECK: encoding: [0x03,0x13,0x00,0x80] lh t1, -2048(zero) +# CHECK-INST: lh t1, -2048(zero) +# CHECK: encoding: [0x03,0x13,0x00,0x80] +lh t1, %lo(2048)(zero) # CHECK-INST: lh sp, 2047(a0) # CHECK: encoding: [0x03,0x11,0xf5,0x7f] lh sp, 2047(a0) @@ -97,6 +112,9 @@ sb a0, 2047(a2) # CHECK-INST: sh t3, -2048(t5) # CHECK: encoding: [0x23,0x10,0xcf,0x81] sh t3, -2048(t5) +# CHECK-INST: sh t3, -2048(t5) +# CHECK: encoding: [0x23,0x10,0xcf,0x81] +sh t3, %lo(2048)(t5) # CHECK-INST: sw ra, 999(zero) # CHECK: encoding: [0xa3,0x23,0x10,0x3e] sw ra, 999(zero) @@ -116,6 +134,9 @@ xori tp, t1, -99 # CHECK-INST: ori a0, a1, -2048 # CHECK: encoding: [0x13,0xe5,0x05,0x80] ori a0, a1, -2048 +# CHECK-INST: ori a0, a1, -2048 +# CHECK: encoding: [0x13,0xe5,0x05,0x80] +ori a0, a1, %lo(2048) # CHECK-INST: andi ra, sp, 2047 # CHECK: encoding: [0x93,0x70,0xf1,0x7f] andi ra, sp, 2047