summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target
diff options
context:
space:
mode:
authorAlex Bradbury <asb@lowrisc.org>2017-09-28 08:26:24 +0000
committerAlex Bradbury <asb@lowrisc.org>2017-09-28 08:26:24 +0000
commit9d3f12501a4594421a8d07053dd9dbaa652c7418 (patch)
treed802b5c35d624cb00ed2c3e7578b4afa6f3195df /llvm/lib/Target
parent07f1e2e2b3880bfc3e470bb111c31028371ab8f3 (diff)
downloadbcm5719-llvm-9d3f12501a4594421a8d07053dd9dbaa652c7418.tar.gz
bcm5719-llvm-9d3f12501a4594421a8d07053dd9dbaa652c7418.zip
[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
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r--llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp182
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt3
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp107
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h1
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp23
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h46
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp58
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp99
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h75
-rw-r--r--llvm/lib/Target/RISCV/RISCVInstrFormats.td37
-rw-r--r--llvm/lib/Target/RISCV/RISCVInstrInfo.td1
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>";
}
OpenPOWER on IntegriCloud