Skip to content

Commit

Permalink
[RISCV] Add support for all RV32I instructions
Browse files Browse the repository at this point in the history
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
  • Loading branch information
asb committed Sep 17, 2017
1 parent 06335bb commit 6758ecb
Show file tree
Hide file tree
Showing 8 changed files with 575 additions and 17 deletions.
156 changes: 145 additions & 11 deletions llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Expand Up @@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//

#include "MCTargetDesc/RISCVBaseInfo.h"
#include "MCTargetDesc/RISCVMCTargetDesc.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
Expand All @@ -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,
Expand All @@ -48,6 +52,7 @@ class RISCVAsmParser : public MCTargetAsmParser {

OperandMatchResultTy parseImmediate(OperandVector &Operands);
OperandMatchResultTy parseRegister(OperandVector &Operands);
OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands);

bool parseOperand(OperandVector &Operands);

Expand Down Expand Up @@ -125,10 +130,57 @@ struct RISCVOperand : public MCParsedAsmOperand {
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
Expand Down Expand Up @@ -208,20 +260,44 @@ struct RISCVOperand : public MCParsedAsmOperand {
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.

#define GET_REGISTER_MATCHER
#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:
Expand All @@ -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");
Expand All @@ -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!");
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand All @@ -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");
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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';
}
1 change: 1 addition & 0 deletions llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h
Expand Up @@ -32,6 +32,7 @@ class RISCVInstPrinter : public MCInstPrinter {

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);
Expand Down
54 changes: 54 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -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
19 changes: 19 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
Expand Up @@ -55,6 +55,10 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
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

Expand Down Expand Up @@ -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"

0 comments on commit 6758ecb

Please sign in to comment.