diff options
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r-- | llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 182 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt | 3 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 107 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h | 1 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp | 23 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h | 46 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp | 58 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp | 99 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h | 75 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/RISCVInstrFormats.td | 37 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/RISCVInstrInfo.td | 1 |
11 files changed, 593 insertions, 39 deletions
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 4b1eec9ec86..b0db5f4d8fb 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<MCConstantExpr>(getImm()); - } - - int64_t getConstantImm() const { + bool evaluateConstantImm(int64_t &Imm, RISCVMCExpr::VariantKind &VK) const { const MCExpr *Val = getImm(); - return static_cast<const MCConstantExpr *>(Val)->getValue(); + bool Ret = false; + if (auto *RE = dyn_cast<RISCVMCExpr>(Val)) { + Ret = RE->evaluateAsConstant(Imm); + VK = RE->getKind(); + } else if (auto CE = dyn_cast<MCConstantExpr>(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<N-1, 1>(Op). + template <int N> 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<N - 1, 1>(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<RISCVOperand> createImm(const MCExpr *Val, SMLoc S, - SMLoc E) { + SMLoc E, MCContext &Ctx) { auto Op = make_unique<RISCVOperand>(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<MCConstantExpr>(Expr)) - Inst.addOperand(MCOperand::createImm(CE->getValue())); + int64_t Imm = 0; + bool IsConstant = false; + if (auto *RE = dyn_cast<RISCVMCExpr>(Expr)) { + IsConstant = RE->evaluateAsConstant(Imm); + } else if (auto *CE = dyn_cast<MCConstantExpr>(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<RISCVMCExpr>(Expr)) { + Kind = RE->getKind(); + Expr = RE->getSubExpr(); + } + + // It's a simple symbol reference or constant with no addend. + if (isa<MCConstantExpr>(Expr) || isa<MCSymbolRefExpr>(Expr)) + return true; + + const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr); + if (!BE) + return false; + + if (!isa<MCSymbolRefExpr>(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<MCSymbolRefExpr>(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<MCConstantExpr>(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 d79de74f7cf..60429647edd 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 4896c38dbb0..692a179e927 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<char> 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 c3bf3213a98..cfb124262c6 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 93c981e2a2a..95d4242e404 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 00000000000..115229414d5 --- /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 f4eaf06f622..f8212159331 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<MCFixup> &Fixups, const MCSubtargetInfo &STI) const; + unsigned getImmOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &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<RISCVMCExpr>(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<MCSymbolRefExpr>(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 00000000000..b36236ea155 --- /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<RISCVMCExpr::VariantKind>(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 00000000000..69b55ca6f7c --- /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 d77f3874c7d..383b73cf4e0 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrFormats.td +++ b/llvm/lib/Target/RISCV/RISCVInstrFormats.td @@ -25,7 +25,22 @@ // //===----------------------------------------------------------------------===// -class RISCVInst<dag outs, dag ins, string asmstr, list<dag> 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<bits<4> 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<dag outs, dag ins, string asmstr, list<dag> 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<dag outs, dag ins, string asmstr, list<dag> pattern> dag InOperandList = ins; let AsmString = asmstr; let Pattern = pattern; + + let TSFlags{3-0} = format.Value; } // Pseudo instructions -class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern> - : RISCVInst<outs, ins, "", pattern> { +class Pseudo<dag outs, dag ins, list<dag> pattern> + : RISCVInst<outs, ins, "", pattern, InstFormatPseudo> { let isPseudo = 1; let isCodeGenOnly = 1; } class FR<bits<7> funct7, bits<3> funct3, bits<7> opcode, dag outs, dag ins, - string asmstr, list<dag> pattern> : RISCVInst<outs, ins, asmstr, pattern> + string asmstr, list<dag> pattern> : RISCVInst<outs, ins, asmstr, pattern, InstFormatR> { bits<5> rs2; bits<5> rs1; @@ -70,7 +87,7 @@ class FR<bits<7> funct7, bits<3> funct3, bits<7> opcode, dag outs, dag ins, } class FI<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern> - : RISCVInst<outs, ins, asmstr, pattern> + : RISCVInst<outs, ins, asmstr, pattern, InstFormatI> { bits<12> imm12; bits<5> rs1; @@ -84,7 +101,7 @@ class FI<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list< } class FI32Shift<bit arithshift, bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern> - : RISCVInst<outs, ins, asmstr, pattern> + : RISCVInst<outs, ins, asmstr, pattern, InstFormatI> { bits<5> shamt; bits<5> rs1; @@ -101,7 +118,7 @@ class FI32Shift<bit arithshift, bits<3> funct3, bits<7> opcode, dag outs, dag in } class FS<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern> - : RISCVInst<outs, ins, asmstr, pattern> + : RISCVInst<outs, ins, asmstr, pattern, InstFormatS> { bits<12> imm12; bits<5> rs2; @@ -116,7 +133,7 @@ class FS<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list< } class FSB<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern> - : RISCVInst<outs, ins, asmstr, pattern> + : RISCVInst<outs, ins, asmstr, pattern, InstFormatSB> { bits<12> imm12; bits<5> rs2; @@ -133,7 +150,7 @@ class FSB<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list } class FU<bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern> - : RISCVInst<outs, ins, asmstr, pattern> + : RISCVInst<outs, ins, asmstr, pattern, InstFormatU> { bits<20> imm20; bits<5> rd; @@ -144,7 +161,7 @@ class FU<bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern> } class FUJ<bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern> - : RISCVInst<outs, ins, asmstr, pattern> + : RISCVInst<outs, ins, asmstr, pattern, InstFormatU> { bits<20> imm20; bits<5> rd; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index e84e4dabb94..1a5f32ecabe 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -46,6 +46,7 @@ def uimm5 : Operand<i32> { def simm12 : Operand<i32> { let ParserMatchClass = SImmAsmOperand<12>; + let EncoderMethod = "getImmOpValue"; let DecoderMethod = "decodeSImmOperand<12>"; } |