[llvm] r314389 - [RISCV] Add common fixups and relocations

Alex Bradbury via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 28 01:26:24 PDT 2017


Author: asb
Date: Thu Sep 28 01:26:24 2017
New Revision: 314389

URL: http://llvm.org/viewvc/llvm-project?rev=314389&view=rev
Log:
[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

Added:
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
    llvm/trunk/test/MC/RISCV/fixups-diagnostics.s
    llvm/trunk/test/MC/RISCV/fixups.s
    llvm/trunk/test/MC/RISCV/hilo-constaddr.s
    llvm/trunk/test/MC/RISCV/relocations.s
Modified:
    llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
    llvm/trunk/lib/Target/RISCV/RISCVInstrFormats.td
    llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td
    llvm/trunk/test/MC/RISCV/rv32i-invalid.s
    llvm/trunk/test/MC/RISCV/rv32i-valid.s

Modified: llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp?rev=314389&r1=314388&r2=314389&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp Thu Sep 28 01:26:24 2017
@@ -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 MCTargetAs
   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());
+  bool evaluateConstantImm(int64_t &Imm, RISCVMCExpr::VariantKind &VK) const {
+    const MCExpr *Val = getImm();
+    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;
   }
 
-  int64_t getConstantImm() const {
-    const MCExpr *Val = getImm();
-    return static_cast<const MCConstantExpr *>(Val)->getValue();
+  // 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::par
     Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
     break;
   }
+  case AsmToken::Percent:
+    return parseOperandWithModifier(Operands);
   }
 
-  Operands.push_back(RISCVOperand::createImm(Res, S, E));
+  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;
+  }
+
+  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(Pa
   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() {

Modified: llvm/trunk/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt?rev=314389&r1=314388&r2=314389&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt (original)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt Thu Sep 28 01:26:24 2017
@@ -2,6 +2,7 @@ add_llvm_library(LLVMRISCVDesc
   RISCVAsmBackend.cpp
   RISCVELFObjectWriter.cpp
   RISCVMCAsmInfo.cpp
-  RISCVMCTargetDesc.cpp
   RISCVMCCodeEmitter.cpp
+  RISCVMCExpr.cpp
+  RISCVMCTargetDesc.cpp
 )

Modified: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp?rev=314389&r1=314388&r2=314389&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp Thu Sep 28 01:26:24 2017
@@ -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(uint6
   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;
 }
 

Modified: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h?rev=314389&r1=314388&r2=314389&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h (original)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h Thu Sep 28 01:26:24 2017
@@ -32,6 +32,7 @@ enum {
 
   InstFormatMask = 15
 };
+
 enum {
   MO_None,
   MO_LO,

Modified: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp?rev=314389&r1=314388&r2=314389&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp Thu Sep 28 01:26:24 2017
@@ -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::getRelocT
                                             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,

Added: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h?rev=314389&view=auto
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h (added)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h Thu Sep 28 01:26:24 2017
@@ -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

Modified: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp?rev=314389&r1=314388&r2=314389&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp Thu Sep 28 01:26:24 2017
@@ -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(co
     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::getImmOpVal
 
   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;
 }

Added: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp?rev=314389&view=auto
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp (added)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp Thu Sep 28 01:26:24 2017
@@ -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;
+  }
+}

Added: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h?rev=314389&view=auto
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h (added)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h Thu Sep 28 01:26:24 2017
@@ -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

Modified: llvm/trunk/lib/Target/RISCV/RISCVInstrFormats.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVInstrFormats.td?rev=314389&r1=314388&r2=314389&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVInstrFormats.td (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVInstrFormats.td Thu Sep 28 01:26:24 2017
@@ -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, strin
   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,
 }
 
 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,
 }
 
 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>
 }
 
 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,
 }
 
 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
 }
 
 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 i
 }
 
 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;

Modified: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td?rev=314389&r1=314388&r2=314389&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td Thu Sep 28 01:26:24 2017
@@ -46,6 +46,7 @@ def uimm5 : Operand<i32> {
 
 def simm12 : Operand<i32> {
   let ParserMatchClass = SImmAsmOperand<12>;
+  let EncoderMethod = "getImmOpValue";
   let DecoderMethod = "decodeSImmOperand<12>";
 }
 

Added: llvm/trunk/test/MC/RISCV/fixups-diagnostics.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/fixups-diagnostics.s?rev=314389&view=auto
==============================================================================
--- llvm/trunk/test/MC/RISCV/fixups-diagnostics.s (added)
+++ llvm/trunk/test/MC/RISCV/fixups-diagnostics.s Thu Sep 28 01:26:24 2017
@@ -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:

Added: llvm/trunk/test/MC/RISCV/fixups.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/fixups.s?rev=314389&view=auto
==============================================================================
--- llvm/trunk/test/MC/RISCV/fixups.s (added)
+++ llvm/trunk/test/MC/RISCV/fixups.s Thu Sep 28 01:26:24 2017
@@ -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

Added: llvm/trunk/test/MC/RISCV/hilo-constaddr.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/hilo-constaddr.s?rev=314389&view=auto
==============================================================================
--- llvm/trunk/test/MC/RISCV/hilo-constaddr.s (added)
+++ llvm/trunk/test/MC/RISCV/hilo-constaddr.s Thu Sep 28 01:26:24 2017
@@ -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

Added: llvm/trunk/test/MC/RISCV/relocations.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/relocations.s?rev=314389&view=auto
==============================================================================
--- llvm/trunk/test/MC/RISCV/relocations.s (added)
+++ llvm/trunk/test/MC/RISCV/relocations.s Thu Sep 28 01:26:24 2017
@@ -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

Modified: llvm/trunk/test/MC/RISCV/rv32i-invalid.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/rv32i-invalid.s?rev=314389&r1=314388&r2=314389&view=diff
==============================================================================
--- llvm/trunk/test/MC/RISCV/rv32i-invalid.s (original)
+++ llvm/trunk/test/MC/RISCV/rv32i-invalid.s Thu Sep 28 01:26:24 2017
@@ -15,6 +15,10 @@ csrrwi a1, 0x1, -1 # CHECK: :[[@LINE]]:1
 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
 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: e
 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

Modified: llvm/trunk/test/MC/RISCV/rv32i-valid.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/rv32i-valid.s?rev=314389&r1=314388&r2=314389&view=diff
==============================================================================
--- llvm/trunk/test/MC/RISCV/rv32i-valid.s (original)
+++ llvm/trunk/test/MC/RISCV/rv32i-valid.s Thu Sep 28 01:26:24 2017
@@ -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




More information about the llvm-commits mailing list