[llvm] r313485 - [RISCV] Add support for all RV32I instructions

Alex Bradbury via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 17 07:27:35 PDT 2017


Author: asb
Date: Sun Sep 17 07:27:35 2017
New Revision: 313485

URL: http://llvm.org/viewvc/llvm-project?rev=313485&view=rev
Log:
[RISCV] Add support for all RV32I instructions

This patch supports all RV32I instructions as described in the RISC-V manual.
A future patch will add support for pseudoinstructions and other instruction
expansions (e.g. 0-arg fence -> fence iorw, iorw).

Differential Revision: https://reviews.llvm.org/D23566

Added:
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
Modified:
    llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
    llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp
    llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
    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=313485&r1=313484&r2=313485&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp Sun Sep 17 07:27:35 2017
@@ -7,6 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "MCTargetDesc/RISCVBaseInfo.h"
 #include "MCTargetDesc/RISCVMCTargetDesc.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -30,6 +31,9 @@ struct RISCVOperand;
 class RISCVAsmParser : public MCTargetAsmParser {
   SMLoc getLoc() const { return getParser().getTok().getLoc(); }
 
+  bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo,
+                                  int Lower, int Upper, Twine Msg);
+
   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
                                OperandVector &Operands, MCStreamer &Out,
                                uint64_t &ErrorInfo,
@@ -48,6 +52,7 @@ class RISCVAsmParser : public MCTargetAs
 
   OperandMatchResultTy parseImmediate(OperandVector &Operands);
   OperandMatchResultTy parseRegister(OperandVector &Operands);
+  OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands);
 
   bool parseOperand(OperandVector &Operands);
 
@@ -125,10 +130,57 @@ public:
     return static_cast<const MCConstantExpr *>(Val)->getValue();
   }
 
+  // Predicate methods for AsmOperands defined in RISCVInstrInfo.td
+
+  /// Return true if the operand is a valid for the fence instruction e.g.
+  /// ('iorw').
+  bool isFenceArg() const {
+    if (!isImm())
+      return false;
+    const MCExpr *Val = getImm();
+    auto *SVal = dyn_cast<MCSymbolRefExpr>(Val);
+    if (!SVal || SVal->getKind() != MCSymbolRefExpr::VK_None)
+      return false;
+
+    StringRef Str = SVal->getSymbol().getName();
+    // Letters must be unique, taken from 'iorw', and in ascending order. This
+    // holds as long as each individual character is one of 'iorw' and is
+    // greater than the previous character.
+    char Prev = '\0';
+    for (char c : Str) {
+      if (c != 'i' && c != 'o' && c != 'r' && c != 'w')
+        return false;
+      if (c <= Prev)
+        return false;
+      Prev = c;
+    }
+    return true;
+  }
+
+  bool isUImm5() const {
+    return (isConstantImm() && isUInt<5>(getConstantImm()));
+  }
+
   bool isSImm12() const {
     return (isConstantImm() && isInt<12>(getConstantImm()));
   }
 
+  bool isUImm12() const {
+    return (isConstantImm() && isUInt<12>(getConstantImm()));
+  }
+
+  bool isSImm13Lsb0() const {
+    return (isConstantImm() && isShiftedInt<12, 1>(getConstantImm()));
+  }
+
+  bool isUImm20() const {
+    return (isConstantImm() && isUInt<20>(getConstantImm()));
+  }
+
+  bool isSImm21Lsb0() const {
+    return (isConstantImm() && isShiftedInt<20, 1>(getConstantImm()));
+  }
+
   /// getStartLoc - Gets location of the first token of this operand
   SMLoc getStartLoc() const override { return StartLoc; }
   /// getEndLoc - Gets location of the last token of this operand
@@ -208,6 +260,24 @@ public:
     assert(N == 1 && "Invalid number of operands!");
     addExpr(Inst, getImm());
   }
+
+  void addFenceArgOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    // isFenceArg has validated the operand, meaning this cast is safe
+    auto SE = cast<MCSymbolRefExpr>(getImm());
+
+    unsigned Imm = 0;
+    for (char c : SE->getSymbol().getName()) {
+      switch (c) {
+        default: llvm_unreachable("FenceArg must contain only [iorw]");
+        case 'i': Imm |= RISCVFenceField::I; break;
+        case 'o': Imm |= RISCVFenceField::O; break;
+        case 'r': Imm |= RISCVFenceField::R; break;
+        case 'w': Imm |= RISCVFenceField::W; break;
+      }
+    }
+    Inst.addOperand(MCOperand::createImm(Imm));
+  }
 };
 } // end anonymous namespace.
 
@@ -215,13 +285,19 @@ public:
 #define GET_MATCHER_IMPLEMENTATION
 #include "RISCVGenAsmMatcher.inc"
 
+bool RISCVAsmParser::generateImmOutOfRangeError(
+    OperandVector &Operands, uint64_t ErrorInfo, int Lower, int Upper,
+    Twine Msg = "immediate must be an integer in the range") {
+  SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
+  return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]");
+}
+
 bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
                                              OperandVector &Operands,
                                              MCStreamer &Out,
                                              uint64_t &ErrorInfo,
                                              bool MatchingInlineAsm) {
   MCInst Inst;
-  SMLoc ErrorLoc;
 
   switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
   default:
@@ -234,8 +310,8 @@ bool RISCVAsmParser::MatchAndEmitInstruc
     return Error(IDLoc, "instruction use requires an option to be enabled");
   case Match_MnemonicFail:
     return Error(IDLoc, "unrecognized instruction mnemonic");
-  case Match_InvalidOperand:
-    ErrorLoc = IDLoc;
+  case Match_InvalidOperand: {
+    SMLoc ErrorLoc = IDLoc;
     if (ErrorInfo != ~0U) {
       if (ErrorInfo >= Operands.size())
         return Error(ErrorLoc, "too few operands for instruction");
@@ -245,10 +321,30 @@ bool RISCVAsmParser::MatchAndEmitInstruc
         ErrorLoc = IDLoc;
     }
     return Error(ErrorLoc, "invalid operand for instruction");
+  }
+  case Match_InvalidUImm5:
+    return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1);
   case Match_InvalidSImm12:
+    return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 11),
+                                      (1 << 11) - 1);
+  case Match_InvalidUImm12:
+    return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 12) - 1);
+  case Match_InvalidSImm13Lsb0:
+    return generateImmOutOfRangeError(
+        Operands, ErrorInfo, -(1 << 12), (1 << 12) - 2,
+        "immediate must be a multiple of 2 bytes in the range");
+  case Match_InvalidUImm20:
+    return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 20) - 1);
+  case Match_InvalidSImm21Lsb0:
+    return generateImmOutOfRangeError(
+        Operands, ErrorInfo, -(1 << 20), (1 << 20) - 2,
+        "immediate must be a multiple of 2 bytes in the range");
+  case Match_InvalidFenceArg: {
     SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
-    return Error(ErrorLoc,
-                 "immediate must be an integer in the range [-2048, 2047]");
+    return Error(
+        ErrorLoc,
+        "operand must be formed of letters selected in-order from 'iorw'");
+  }
   }
 
   llvm_unreachable("Unknown match type detected!");
@@ -292,6 +388,10 @@ OperandMatchResultTy RISCVAsmParser::par
 }
 
 OperandMatchResultTy RISCVAsmParser::parseImmediate(OperandVector &Operands) {
+  SMLoc S = getLoc();
+  SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
+  const MCExpr *Res;
+
   switch (getLexer().getKind()) {
   default:
     return MatchOperand_NoMatch;
@@ -300,16 +400,46 @@ OperandMatchResultTy RISCVAsmParser::par
   case AsmToken::Plus:
   case AsmToken::Integer:
   case AsmToken::String:
+    if (getParser().parseExpression(Res))
+      return MatchOperand_ParseFail;
+    break;
+  case AsmToken::Identifier: {
+    StringRef Identifier;
+    if (getParser().parseIdentifier(Identifier))
+      return MatchOperand_ParseFail;
+    MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
+    Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
     break;
   }
+  }
 
-  const MCExpr *IdVal;
-  SMLoc S = getLoc();
-  if (getParser().parseExpression(IdVal))
+  Operands.push_back(RISCVOperand::createImm(Res, S, E));
+  return MatchOperand_Success;
+}
+
+OperandMatchResultTy
+RISCVAsmParser::parseMemOpBaseReg(OperandVector &Operands) {
+  if (getLexer().isNot(AsmToken::LParen)) {
+    Error(getLoc(), "expected '('");
     return MatchOperand_ParseFail;
+  }
+
+  getParser().Lex(); // Eat '('
+  Operands.push_back(RISCVOperand::createToken("(", getLoc()));
+
+  if (parseRegister(Operands) != MatchOperand_Success) {
+    Error(getLoc(), "expected register");
+    return MatchOperand_ParseFail;
+  }
+
+  if (getLexer().isNot(AsmToken::RParen)) {
+    Error(getLoc(), "expected ')'");
+    return MatchOperand_ParseFail;
+  }
+
+  getParser().Lex(); // Eat ')'
+  Operands.push_back(RISCVOperand::createToken(")", getLoc()));
 
-  SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
-  Operands.push_back(RISCVOperand::createImm(IdVal, S, E));
   return MatchOperand_Success;
 }
 
@@ -322,8 +452,12 @@ bool RISCVAsmParser::parseOperand(Operan
     return false;
 
   // Attempt to parse token as an immediate
-  if (parseImmediate(Operands) == MatchOperand_Success)
+  if (parseImmediate(Operands) == MatchOperand_Success) {
+    // Parse memory base register if present
+    if (getLexer().is(AsmToken::LParen))
+      return parseMemOpBaseReg(Operands) != MatchOperand_Success;
     return false;
+  }
 
   // Finally we have exhausted all options and must declare defeat.
   Error(getLoc(), "unknown operand");

Modified: llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp?rev=313485&r1=313484&r2=313485&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp Sun Sep 17 07:27:35 2017
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "RISCVInstPrinter.h"
+#include "MCTargetDesc/RISCVBaseInfo.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
@@ -53,3 +54,16 @@ void RISCVInstPrinter::printOperand(cons
   assert(MO.isExpr() && "Unknown operand kind in printOperand");
   MO.getExpr()->print(O, &MAI);
 }
+
+void RISCVInstPrinter::printFenceArg(const MCInst *MI, unsigned OpNo,
+                                     raw_ostream &O) {
+  unsigned FenceArg = MI->getOperand(OpNo).getImm();
+  if ((FenceArg & RISCVFenceField::I) != 0)
+    O << 'i';
+  if ((FenceArg & RISCVFenceField::O) != 0)
+    O << 'o';
+  if ((FenceArg & RISCVFenceField::R) != 0)
+    O << 'r';
+  if ((FenceArg & RISCVFenceField::W) != 0)
+    O << 'w';
+}

Modified: llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h?rev=313485&r1=313484&r2=313485&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h (original)
+++ llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h Sun Sep 17 07:27:35 2017
@@ -32,6 +32,7 @@ public:
 
   void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O,
                     const char *Modifier = nullptr);
+  void printFenceArg(const MCInst *MI, unsigned OpNo, raw_ostream &O);
 
   // Autogenerated by tblgen.
   void printInstruction(const MCInst *MI, raw_ostream &O);

Added: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h?rev=313485&view=auto
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h (added)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h Sun Sep 17 07:27:35 2017
@@ -0,0 +1,54 @@
+//===-- RISCVBaseInfo.h - Top level definitions for RISCV MC ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains small standalone enum definitions for the RISCV target
+// useful for the compiler back-end and the MC libraries.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVBASEINFO_H
+#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVBASEINFO_H
+
+#include "RISCVMCTargetDesc.h"
+
+namespace llvm {
+
+// RISCVII - This namespace holds all of the target specific flags that
+// instruction info tracks. All definitions must match RISCVInstrFormats.td.
+namespace RISCVII {
+enum {
+  InstFormatPseudo = 0,
+  InstFormatR = 1,
+  InstFormatI = 2,
+  InstFormatS = 3,
+  InstFormatSB = 4,
+  InstFormatU = 5,
+  InstFormatOther = 6,
+
+  InstFormatMask = 15
+};
+enum {
+  MO_None,
+  MO_LO,
+  MO_HI,
+  MO_PCREL_HI,
+};
+} // namespace RISCVII
+
+// Describes the predecessor/successor bits used in the FENCE instruction.
+namespace RISCVFenceField {
+enum FenceField {
+  I = 8,
+  O = 4,
+  R = 2,
+  W = 1
+};
+}
+} // 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=313485&r1=313484&r2=313485&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp Sun Sep 17 07:27:35 2017
@@ -55,6 +55,10 @@ public:
   unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
                              SmallVectorImpl<MCFixup> &Fixups,
                              const MCSubtargetInfo &STI) const;
+
+  unsigned getImmOpValueAsr1(const MCInst &MI, unsigned OpNo,
+                             SmallVectorImpl<MCFixup> &Fixups,
+                             const MCSubtargetInfo &STI) const;
 };
 } // end anonymous namespace
 
@@ -88,4 +92,19 @@ RISCVMCCodeEmitter::getMachineOpValue(co
   return 0;
 }
 
+unsigned
+RISCVMCCodeEmitter::getImmOpValueAsr1(const MCInst &MI, unsigned OpNo,
+                                      SmallVectorImpl<MCFixup> &Fixups,
+                                      const MCSubtargetInfo &STI) const {
+  const MCOperand &MO = MI.getOperand(OpNo);
+
+  if (MO.isImm()) {
+    unsigned Res = MO.getImm();
+    assert((Res & 1) == 0 && "LSB is non-zero");
+    return Res >> 1;
+  }
+
+  llvm_unreachable("Unhandled expression!");
+}
+
 #include "RISCVGenMCCodeEmitter.inc"

Modified: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td?rev=313485&r1=313484&r2=313485&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td Sun Sep 17 07:27:35 2017
@@ -13,17 +13,59 @@
 
 include "RISCVInstrFormats.td"
 
-class SImmAsmOperand<int width>
-  : AsmOperandClass {
-  let Name = "SImm" # width;
+class ImmAsmOperand<string prefix, int width, string suffix> : AsmOperandClass {
+  let Name = prefix # "Imm" # width # suffix;
   let RenderMethod = "addImmOperands";
   let DiagnosticType = !strconcat("Invalid", Name);
 }
 
+class SImmAsmOperand<int width, string suffix = "">
+  : ImmAsmOperand<"S", width, suffix> {
+}
+
+class UImmAsmOperand<int width, string suffix = "">
+  : ImmAsmOperand<"U", width, suffix> {
+}
+
+def FenceArg : AsmOperandClass {
+  let Name = "FenceArg";
+  let RenderMethod = "addFenceArgOperands";
+  let DiagnosticType = "InvalidFenceArg";
+}
+
+def fencearg : Operand<i32> {
+  let ParserMatchClass = FenceArg;
+  let PrintMethod = "printFenceArg";
+}
+
+def uimm5 : Operand<i32> {
+  let ParserMatchClass = UImmAsmOperand<5>;
+}
+
 def simm12 : Operand<i32> {
   let ParserMatchClass = SImmAsmOperand<12>;
 }
 
+def uimm12 : Operand<i32> {
+  let ParserMatchClass = UImmAsmOperand<12>;
+}
+
+// A 13-bit signed immediate where the least significant bit is zero.
+def simm13_lsb0 : Operand<i32> {
+  let ParserMatchClass = SImmAsmOperand<13, "Lsb0">;
+  let EncoderMethod = "getImmOpValueAsr1";
+}
+
+def uimm20 : Operand<i32> {
+  let ParserMatchClass = UImmAsmOperand<20>;
+}
+
+// A 21-bit signed immediate where the least significant bit is zero.
+def simm21_lsb0 : Operand<i32> {
+  let ParserMatchClass = SImmAsmOperand<21, "Lsb0">;
+  let EncoderMethod = "getImmOpValueAsr1";
+}
+
 // As noted in RISCVRegisterInfo.td, the hope is that support for
 // variable-sized register classes will mean that instruction definitions do
 // not need to be duplicated for 32-bit and 64-bit register classes. For now
@@ -32,6 +74,52 @@ def simm12 : Operand<i32> {
 // like <http://lists.llvm.org/pipermail/llvm-dev/2016-September/105027.html>
 // is adopted.
 
+def LUI : FU<0b0110111, (outs GPR:$rd), (ins uimm20:$imm20),
+             "lui\t$rd, $imm20", []>;
+
+def AUIPC : FU<0b0010111, (outs GPR:$rd), (ins uimm20:$imm20),
+             "auipc\t$rd, $imm20", []>;
+
+def JAL : FUJ<0b1101111, (outs GPR:$rd), (ins simm21_lsb0:$imm20),
+              "jal\t$rd, $imm20", []>;
+
+def JALR : FI<0b000, 0b1100111, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12),
+              "jalr\t$rd, $rs1, $imm12", []>;
+
+class Bcc<bits<3> funct3, string OpcodeStr> :
+      FSB<funct3, 0b1100011, (outs), (ins GPR:$rs1, GPR:$rs2, simm13_lsb0:$imm12),
+         OpcodeStr#"\t$rs1, $rs2, $imm12", []> {
+}
+
+def BEQ   : Bcc<0b000, "beq">;
+def BNE   : Bcc<0b001, "bne">;
+def BLT   : Bcc<0b100, "blt">;
+def BGE   : Bcc<0b101, "bge">;
+def BLTU  : Bcc<0b110, "bltu">;
+def BGEU  : Bcc<0b111, "bgeu">;
+
+class LD_ri<bits<3> funct3, string OpcodeStr> :
+      FI<funct3, 0b0000011, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12),
+         OpcodeStr#"\t$rd, ${imm12}(${rs1})", []> {
+  let mayLoad = 1;
+}
+
+def LB   : LD_ri<0b000, "lb">;
+def LH   : LD_ri<0b001, "lh">;
+def LW   : LD_ri<0b010, "lw">;
+def LBU  : LD_ri<0b100, "lbu">;
+def LHU  : LD_ri<0b101, "lhu">;
+
+class ST_ri<bits<3> funct3, string OpcodeStr> :
+      FS<funct3, 0b0100011, (outs), (ins GPR:$rs1, GPR:$rs2, simm12:$imm12),
+         OpcodeStr#"\t$rs2, ${imm12}(${rs1})", []> {
+  let mayStore = 1;
+}
+
+def SB  : ST_ri<0b000, "sb">;
+def SH  : ST_ri<0b001, "sh">;
+def SW  : ST_ri<0b010, "sw">;
+
 class ALU_ri<bits<3> funct3, string OpcodeStr> :
       FI<funct3, 0b0010011, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12),
          OpcodeStr#"\t$rd, $rs1, $imm12", []>
@@ -45,6 +133,16 @@ def XORI  : ALU_ri<0b100, "xori">;
 def ORI   : ALU_ri<0b110, "ori">;
 def ANDI  : ALU_ri<0b111, "andi">;
 
+class SHIFT32_ri<bit arithshift, bits<3> funct3, string OpcodeStr> :
+      FI32Shift<arithshift, funct3, 0b0010011, (outs GPR:$rd), (ins GPR:$rs1, uimm5:$shamt),
+         OpcodeStr#"\t$rd, $rs1, $shamt", []>
+{
+}
+
+def SLLI : SHIFT32_ri<0, 0b001, "slli">;
+def SRLI : SHIFT32_ri<0, 0b101, "srli">;
+def SRAI : SHIFT32_ri<1, 0b101, "srai">;
+
 class ALU_rr<bits<7> funct7, bits<3> funct3, string OpcodeStr> :
       FR<funct7, funct3, 0b0110011, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2),
          OpcodeStr#"\t$rd, $rs1, $rs2", []>
@@ -62,3 +160,47 @@ def SRA  : ALU_rr<0b0100000, 0b101, "sra
 def OR   : ALU_rr<0b0000000, 0b110, "or">;
 def AND  : ALU_rr<0b0000000, 0b111, "and">;
 
+def FENCE : FI<0b000, 0b0001111, (outs), (ins fencearg:$pred, fencearg:$succ),
+               "fence\t$pred, $succ", []> {
+  bits<4> pred;
+  bits<4> succ;
+
+  let rs1 = 0;
+  let rd = 0;
+  let imm12 = {0b0000,pred,succ};
+}
+
+def FENCEI : FI<0b001, 0b0001111, (outs), (ins), "fence.i", []> {
+  let rs1 = 0;
+  let rd = 0;
+  let imm12 = 0;
+}
+
+let rs1=0, rd=0 in {
+  def ECALL  : FI<0b000, 0b1110011, (outs), (ins), "ecall", []> {
+    let imm12=0;
+  }
+  def EBREAK : FI<0b000, 0b1110011, (outs), (ins), "ebreak", []> {
+    let imm12=1;
+  }
+}
+
+class CSR_rr<bits<3> funct3, string OpcodeStr> :
+      FI<funct3, 0b1110011, (outs GPR:$rd), (ins uimm12:$imm12, GPR:$rs1),
+         OpcodeStr#"\t$rd, $imm12, $rs1", []>
+{
+}
+
+def CSRRW : CSR_rr<0b001, "csrrw">;
+def CSRRS : CSR_rr<0b010, "csrrs">;
+def CSRRC : CSR_rr<0b011, "csrrc">;
+
+class CSR_ri<bits<3> funct3, string OpcodeStr> :
+      FI<funct3, 0b1110011, (outs GPR:$rd), (ins uimm12:$imm12, uimm5:$rs1),
+         OpcodeStr#"\t$rd, $imm12, $rs1", []>
+{
+}
+
+def CSRRWI : CSR_ri<0b101, "csrrwi">;
+def CSRRSI : CSR_ri<0b110, "csrrsi">;
+def CSRRCI : CSR_ri<0b111, "csrrci">;

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=313485&r1=313484&r2=313485&view=diff
==============================================================================
--- llvm/trunk/test/MC/RISCV/rv32i-invalid.s (original)
+++ llvm/trunk/test/MC/RISCV/rv32i-invalid.s Sun Sep 17 07:27:35 2017
@@ -1,17 +1,61 @@
 # RUN: not llvm-mc -triple riscv32 < %s 2>&1 | FileCheck %s
 
 # Out of range immediates
+## fencearg
+fence iorw, iore # CHECK: :[[@LINE]]:13: error: operand must be formed of letters selected in-order from 'iorw'
+fence wr, wr # CHECK: :[[@LINE]]:7: error: operand must be formed of letters selected in-order from 'iorw'
+fence rw, rr # CHECK: :[[@LINE]]:11: error: operand must be formed of letters selected in-order from 'iorw'
+fence 1, rw # CHECK: :[[@LINE]]:7: error: operand must be formed of letters selected in-order from 'iorw'
+
+## uimm5
+slli a0, a0, 32 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 31]
+srli a0, a0, -1 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 31]
+srai a0, a0, -19 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 31]
+csrrwi a1, 0x1, -1 # CHECK: :[[@LINE]]:17: error: immediate must be an integer in the range [0, 31]
+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]
+
+## 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]
+csrrs a0, -0xf, a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095]
+csrrc a0, 0x1000, a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095]
+csrrwi a0, -50, 0 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [0, 4095]
+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]
+blt t0, t1, 4095 # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094]
+bge t0, t1, 4096 # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094]
+bltu t0, t1, 13 # CHECK: :[[@LINE]]:14: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094]
+bgeu t0, t1, -13 # CHECK: :[[@LINE]]:14: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094]
+
+## uimm20
+lui a0, -1 # CHECK: :[[@LINE]]:9: error: immediate must be an integer in the range [0, 1048575]
+lui s0, 1048576 # CHECK: :[[@LINE]]:9: error: immediate must be an integer in the range [0, 1048575]
+auipc zero, -0xf # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [0, 1048575]
+
+## simm21_lsb0
+jal gp, -1048578 # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574]
+jal gp, -1048577 # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574]
+jal gp, 1048575 # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574]
+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]
+
 # Invalid mnemonics
 subs t0, t2, t1 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic
 nandi t0, zero, 0 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic
 
 # Invalid register names
-addi foo, sp, 10 # CHECK: :[[@LINE]]:6: error: unknown operand
-slti a10, a2, 0x20 # CHECK: :[[@LINE]]:6: error: unknown operand
-slt x32, s0, s0 # CHECK: :[[@LINE]]:5: error: unknown operand
+addi foo, sp, 10 # CHECK: :[[@LINE]]:6: error: invalid operand for instruction
+slti a10, a2, 0x20 # CHECK: :[[@LINE]]:6: error: invalid operand for instruction
+slt x32, s0, s0 # CHECK: :[[@LINE]]:5: error: invalid operand for instruction
 
 # RV64I mnemonics
 addiw a0, sp, 100 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic

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=313485&r1=313484&r2=313485&view=diff
==============================================================================
--- llvm/trunk/test/MC/RISCV/rv32i-valid.s (original)
+++ llvm/trunk/test/MC/RISCV/rv32i-valid.s Sun Sep 17 07:27:35 2017
@@ -3,6 +3,100 @@
 # RUN: llvm-mc %s -triple=riscv64 -show-encoding \
 # RUN:     | FileCheck -check-prefixes=CHECK,CHECK-INST %s
 
+# CHECK-INST: lui a0, 2
+# CHECK: encoding: [0x37,0x25,0x00,0x00]
+lui a0, 2
+# CHECK-INST: lui s11, 552960
+# CHECK: encoding: [0xb7,0x0d,0x00,0x87]
+lui s11, (0x87000000>>12)
+# CHECK-INST: lui t0, 1048575
+# CHECK: encoding: [0xb7,0xf2,0xff,0xff]
+lui t0, 1048575
+# CHECK-INST: lui gp, 0
+# CHECK: encoding: [0xb7,0x01,0x00,0x00]
+lui gp, 0
+
+# CHECK-INST: auipc a0, 2
+# CHECK: encoding: [0x17,0x25,0x00,0x00]
+auipc a0, 2
+# CHECK-INST: auipc s11, 552960
+# CHECK: encoding: [0x97,0x0d,0x00,0x87]
+auipc s11, (0x87000000>>12)
+# CHECK-INST: auipc t0, 1048575
+# CHECK: encoding: [0x97,0xf2,0xff,0xff]
+auipc t0, 1048575
+# CHECK-INST: auipc gp, 0
+# CHECK: encoding: [0x97,0x01,0x00,0x00]
+auipc gp, 0
+
+# CHECK-INST: jal a2, 1048574
+# CHECK: encoding: [0x6f,0xf6,0xff,0x7f]
+jal a2, 1048574
+# CHECK-INST: jal a3, 256
+# CHECK: encoding: [0xef,0x06,0x00,0x10]
+jal a3, 256
+
+# CHECK-INST: jalr a0, a1, -2048
+# CHECK: encoding: [0x67,0x85,0x05,0x80]
+jalr a0, a1, -2048
+# CHECK-INST: jalr t2, t1, 2047
+# CHECK: encoding: [0xe7,0x03,0xf3,0x7f]
+jalr t2, t1, 2047
+# CHECK-INST: jalr sp, zero, 256
+# CHECK: encoding: [0x67,0x01,0x00,0x10]
+jalr sp, zero, 256
+
+# CHECK-INST: beq s1, s1, 102
+# CHECK: encoding: [0x63,0x83,0x94,0x06]
+beq s1, s1, 102
+# CHECK-INST: bne a4, a5, -4096
+# CHECK: encoding: [0x63,0x10,0xf7,0x80]
+bne a4, a5, -4096
+# CHECK-INST: blt sp, gp, 4094
+# CHECK: encoding: [0xe3,0x4f,0x31,0x7e]
+blt sp, gp, 4094
+# CHECK-INST: bge s2, ra, -224
+# CHECK: encoding: [0xe3,0x50,0x19,0xf2]
+bge s2, ra, -224
+# CHECK-INST: bltu zero, zero, 0
+# CHECK: encoding: [0x63,0x60,0x00,0x00]
+bltu zero, zero, 0
+# CHECK-INST: bgeu s8, sp, 512
+# CHECK: encoding: [0x63,0x70,0x2c,0x20]
+bgeu s8, sp, 512
+
+# CHECK-INST: lb s3, 4(ra)
+# CHECK: encoding: [0x83,0x89,0x40,0x00]
+lb s3, 4(ra)
+# CHECK-INST: lb s3, 4(ra)
+# CHECK: encoding: [0x83,0x89,0x40,0x00]
+lb s3, +4(ra)
+# CHECK-INST: lh t1, -2048(zero)
+# CHECK: encoding: [0x03,0x13,0x00,0x80]
+lh t1, -2048(zero)
+# CHECK-INST: lh sp, 2047(a0)
+# CHECK: encoding: [0x03,0x11,0xf5,0x7f]
+lh sp, 2047(a0)
+# CHECK-INST: lw a0, 97(a2)
+# CHECK: encoding: [0x03,0x25,0x16,0x06]
+lw a0, 97(a2)
+# CHECK-INST: lbu s5, 0(s6)
+# CHECK: encoding: [0x83,0x4a,0x0b,0x00]
+lbu s5, 0(s6)
+# CHECK-INST: lhu t3, 255(t3)
+# CHECK: encoding: [0x03,0x5e,0xfe,0x0f]
+lhu t3, 255(t3)
+
+# CHECK-INST: sb a0, 2047(a2)
+# CHECK: encoding: [0xa3,0x0f,0xa6,0x7e]
+sb a0, 2047(a2)
+# CHECK-INST: sh t3, -2048(t5)
+# CHECK: encoding: [0x23,0x10,0xcf,0x81]
+sh t3, -2048(t5)
+# CHECK-INST: sw ra, 999(zero)
+# CHECK: encoding: [0xa3,0x23,0x10,0x3e]
+sw ra, 999(zero)
+
 # CHECK-INST: addi ra, sp, 2
 # CHECK: encoding: [0x93,0x00,0x21,0x00]
 addi ra, sp, 2
@@ -25,6 +119,16 @@ andi ra, sp, 2047
 # CHECK: encoding: [0x93,0x70,0xf1,0x7f]
 andi x1, x2, 2047
 
+# CHECK-INST: slli t3, t3, 31
+# CHECK: encoding: [0x13,0x1e,0xfe,0x01]
+slli t3, t3, 31
+# CHECK-INST: srli a0, a4, 0
+# CHECK: encoding: [0x13,0x55,0x07,0x00]
+srli a0, a4, 0
+# CHECK-INST: srai a2, sp, 15
+# CHECK: encoding: [0x13,0x56,0xf1,0x40]
+srai a2, sp, 15
+
 # CHECK-INST: add ra, zero, zero
 # CHECK: encoding: [0xb3,0x00,0x00,0x00]
 add ra, zero, zero
@@ -61,3 +165,49 @@ or s10, t1, ra
 # CHECK-INST: and a0, s2, s3
 # CHECK: encoding: [0x33,0x75,0x39,0x01]
 and a0, s2, s3
+
+# CHECK-INST: fence iorw, iorw
+# CHECK: encoding: [0x0f,0x00,0xf0,0x0f]
+fence iorw, iorw
+# CHECK-INST: fence io, rw
+# CHECK: encoding: [0x0f,0x00,0x30,0x0c]
+fence io, rw
+# CHECK-INST: fence r, w
+# CHECK: encoding: [0x0f,0x00,0x10,0x02]
+fence r,w
+# CHECK-INST: fence w, ir
+# CHECK: encoding: [0x0f,0x00,0xa0,0x01]
+fence w,ir
+
+# CHECK-INST: fence.i
+# CHECK: encoding: [0x0f,0x10,0x00,0x00]
+fence.i
+
+# CHECK-INST: ecall
+# CHECK: encoding: [0x73,0x00,0x00,0x00]
+ecall
+# CHECK-INST: ebreak
+# CHECK: encoding: [0x73,0x00,0x10,0x00]
+ebreak
+
+# CHECK-INST: csrrw t0, 4095, t1
+# CHECK: encoding: [0xf3,0x12,0xf3,0xff]
+csrrw t0, 0xfff, t1
+# CHECK-INST: csrrs s0, 3072, zero
+# CHECK: encoding: [0x73,0x24,0x00,0xc0]
+csrrs s0, 0xc00, x0
+# CHECK-INST: csrrs s3, 1, s5
+# CHECK: encoding: [0xf3,0xa9,0x1a,0x00]
+csrrs s3, 0x001, s5
+# CHECK-INST: csrrc sp, 0, ra
+# CHECK: encoding: [0x73,0xb1,0x00,0x00]
+csrrc sp, 0x000, ra
+# CHECK-INST: csrrwi a5, 0, 0
+# CHECK: encoding: [0xf3,0x57,0x00,0x00]
+csrrwi a5, 0x000, 0
+# CHECK-INST: csrrsi t2, 4095, 31
+# CHECK: encoding: [0xf3,0xe3,0xff,0xff]
+csrrsi t2, 0xfff, 31
+# CHECK-INST: csrrci t1, 320, 5
+# CHECK: encoding: [0x73,0xf3,0x02,0x14]
+csrrci t1, 0x140, 5




More information about the llvm-commits mailing list