forked from OSchip/llvm-project
[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 llvm-svn: 313485
This commit is contained in:
parent
06335bbd2f
commit
6758ecb98c
|
@ -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 MCTargetAsmParser {
|
|||
|
||||
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::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|||
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::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|||
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::parseRegister(OperandVector &Operands) {
|
|||
}
|
||||
|
||||
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::parseImmediate(OperandVector &Operands) {
|
|||
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(OperandVector &Operands) {
|
|||
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");
|
||||
|
|
|
@ -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(const MCInst *MI, unsigned OpNo,
|
|||
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';
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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(const MCInst &MI, const MCOperand &MO,
|
|||
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"
|
||||
|
|
|
@ -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">;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue