Skip to content

Commit

Permalink
[RISCV] MC layer support for the standard RV32F instruction set exten…
Browse files Browse the repository at this point in the history
…sion

The most interesting part of this patch is probably the handling of 
rounding mode arguments. Sadly, the RISC-V assembler handles floating point 
rounding modes as a special "argument" when it would be more consistent to 
handle them like the atomics, opcode suffixes. This patch supports parsing 
this optional parameter, using InstAlias to allow parsing these floating point 
instructions when no rounding mode is specified.

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

llvm-svn: 320020
  • Loading branch information
asb committed Dec 7, 2017
1 parent 293da70 commit 0d6cf90
Show file tree
Hide file tree
Showing 14 changed files with 594 additions and 13 deletions.
36 changes: 36 additions & 0 deletions llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,20 @@ struct RISCVOperand : public MCParsedAsmOperand {
return true;
}

/// Return true if the operand is a valid floating point rounding mode.
bool isFRMArg() 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();

return RISCVFPRndMode::stringToRoundingMode(Str) != RISCVFPRndMode::Invalid;
}

bool isUImm5() const {
int64_t Imm;
RISCVMCExpr::VariantKind VK;
Expand Down Expand Up @@ -344,6 +358,22 @@ struct RISCVOperand : public MCParsedAsmOperand {
}
Inst.addOperand(MCOperand::createImm(Imm));
}

// Returns the rounding mode represented by this RISCVOperand. Should only
// be called after checking isFRMArg.
RISCVFPRndMode::RoundingMode getRoundingMode() const {
// isFRMArg has validated the operand, meaning this cast is safe.
auto SE = cast<MCSymbolRefExpr>(getImm());
RISCVFPRndMode::RoundingMode FRM =
RISCVFPRndMode::stringToRoundingMode(SE->getSymbol().getName());
assert(FRM != RISCVFPRndMode::Invalid && "Invalid rounding mode");
return FRM;
}

void addFRMArgOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::createImm(getRoundingMode()));
}
};
} // end anonymous namespace.

Expand Down Expand Up @@ -411,6 +441,12 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
ErrorLoc,
"operand must be formed of letters selected in-order from 'iorw'");
}
case Match_InvalidFRMArg: {
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
return Error(
ErrorLoc,
"operand must be a valid floating point rounding mode mnemonic");
}
}

llvm_unreachable("Unknown match type detected!");
Expand Down
25 changes: 25 additions & 0 deletions llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,31 @@ static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo,
return MCDisassembler::Success;
}

static const unsigned FPR32DecoderTable[] = {
RISCV::F0_32, RISCV::F1_32, RISCV::F2_32, RISCV::F3_32,
RISCV::F4_32, RISCV::F5_32, RISCV::F6_32, RISCV::F7_32,
RISCV::F8_32, RISCV::F9_32, RISCV::F10_32, RISCV::F11_32,
RISCV::F12_32, RISCV::F13_32, RISCV::F14_32, RISCV::F15_32,
RISCV::F16_32, RISCV::F17_32, RISCV::F18_32, RISCV::F19_32,
RISCV::F20_32, RISCV::F21_32, RISCV::F22_32, RISCV::F23_32,
RISCV::F24_32, RISCV::F25_32, RISCV::F26_32, RISCV::F27_32,
RISCV::F28_32, RISCV::F29_32, RISCV::F30_32, RISCV::F31_32
};

static DecodeStatus DecodeFPR32RegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
if (RegNo > sizeof(FPR32DecoderTable))
return MCDisassembler::Fail;

// We must define our own mapping from RegNo to register identifier.
// Accessing index RegNo in the register class will work in the case that
// registers were added in ascending order, but not in general.
unsigned Reg = FPR32DecoderTable[RegNo];
Inst.addOperand(MCOperand::createReg(Reg));
return MCDisassembler::Success;
}

template <unsigned N>
static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder) {
Expand Down
12 changes: 11 additions & 1 deletion llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
Expand All @@ -24,11 +25,13 @@ using namespace llvm;
#define DEBUG_TYPE "asm-printer"

// Include the auto-generated portion of the assembly writer.
#define PRINT_ALIAS_INSTR
#include "RISCVGenAsmWriter.inc"

void RISCVInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
StringRef Annot, const MCSubtargetInfo &STI) {
printInstruction(MI, O);
if (!printAliasInstr(MI, O))
printInstruction(MI, O);
printAnnotation(O, Annot);
}

Expand Down Expand Up @@ -67,3 +70,10 @@ void RISCVInstPrinter::printFenceArg(const MCInst *MI, unsigned OpNo,
if ((FenceArg & RISCVFenceField::W) != 0)
O << 'w';
}

void RISCVInstPrinter::printFRMArg(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
auto FRMArg =
static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm());
O << RISCVFPRndMode::roundingModeToString(FRMArg);
}
4 changes: 4 additions & 0 deletions llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ 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);
void printFRMArg(const MCInst *MI, unsigned OpNo, raw_ostream &O);

// Autogenerated by tblgen.
void printInstruction(const MCInst *MI, raw_ostream &O);
bool printAliasInstr(const MCInst *MI, raw_ostream &O);
void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx,
unsigned PrintMethodIdx, raw_ostream &O);
static const char *getRegisterName(unsigned RegNo,
unsigned AltIdx = RISCV::ABIRegAltName);
};
Expand Down
58 changes: 52 additions & 6 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVBASEINFO_H

#include "RISCVMCTargetDesc.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"

namespace llvm {

Expand All @@ -24,12 +26,13 @@ namespace RISCVII {
enum {
InstFormatPseudo = 0,
InstFormatR = 1,
InstFormatI = 2,
InstFormatS = 3,
InstFormatB = 4,
InstFormatU = 5,
InstFormatJ = 6,
InstFormatOther = 7,
InstFormatR4 = 2,
InstFormatI = 3,
InstFormatS = 4,
InstFormatB = 5,
InstFormatU = 6,
InstFormatJ = 7,
InstFormatOther = 8,

InstFormatMask = 15
};
Expand All @@ -51,6 +54,49 @@ enum FenceField {
W = 1
};
}

// Describes the supported floating point rounding mode encodings.
namespace RISCVFPRndMode {
enum RoundingMode {
RNE = 0,
RTZ = 1,
RDN = 2,
RUP = 3,
RMM = 4,
DYN = 7,
Invalid
};

inline static StringRef roundingModeToString(RoundingMode RndMode) {
switch (RndMode) {
default:
llvm_unreachable("Unknown floating point rounding mode");
case RISCVFPRndMode::RNE:
return "rne";
case RISCVFPRndMode::RTZ:
return "rtz";
case RISCVFPRndMode::RDN:
return "rdn";
case RISCVFPRndMode::RUP:
return "rup";
case RISCVFPRndMode::RMM:
return "rmm";
case RISCVFPRndMode::DYN:
return "dyn";
}
}

inline static RoundingMode stringToRoundingMode(StringRef Str) {
return StringSwitch<RoundingMode>(Str)
.Case("rne", RISCVFPRndMode::RNE)
.Case("rtz", RISCVFPRndMode::RTZ)
.Case("rdn", RISCVFPRndMode::RDN)
.Case("rup", RISCVFPRndMode::RUP)
.Case("rmm", RISCVFPRndMode::RMM)
.Case("dyn", RISCVFPRndMode::DYN)
.Default(RISCVFPRndMode::Invalid);
}
} // namespace RISCVFPRndMode
} // namespace llvm

#endif
6 changes: 6 additions & 0 deletions llvm/lib/Target/RISCV/RISCV.td
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ def FeatureStdExtA
def HasStdExtA : Predicate<"Subtarget->hasStdExtA()">,
AssemblerPredicate<"FeatureStdExtA">;

def FeatureStdExtF
: SubtargetFeature<"f", "HasStdExtF", "true",
"'F' (Single-Precision Floating-Point)">;
def HasStdExtF : Predicate<"Subtarget->hasStdExtF()">,
AssemblerPredicate<"FeatureStdExtF">;

def Feature64Bit
: SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">;

Expand Down
47 changes: 41 additions & 6 deletions llvm/lib/Target/RISCV/RISCVInstrFormats.td
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ class InstFormat<bits<4> val> {
}
def InstFormatPseudo : InstFormat<0>;
def InstFormatR : InstFormat<1>;
def InstFormatI : InstFormat<2>;
def InstFormatS : InstFormat<3>;
def InstFormatB : InstFormat<4>;
def InstFormatU : InstFormat<5>;
def InstFormatJ : InstFormat<6>;
def InstFormatOther : InstFormat<7>;
def InstFormatR4 : InstFormat<2>;
def InstFormatI : InstFormat<3>;
def InstFormatS : InstFormat<4>;
def InstFormatB : InstFormat<5>;
def InstFormatU : InstFormat<6>;
def InstFormatJ : InstFormat<7>;
def InstFormatOther : InstFormat<8>;

// The following opcode names and match those given in Table 19.1 in the
// RISC-V User-level ISA specification ("RISC-V base opcode map").
Expand Down Expand Up @@ -118,6 +119,24 @@ class RVInstR<bits<7> funct7, bits<3> funct3, RISCVOpcode opcode, dag outs,
let Opcode = opcode.Value;
}

class RVInstR4<bits<2> funct2, RISCVOpcode opcode, dag outs, dag ins,
string opcodestr, string argstr>
: RVInst<outs, ins, opcodestr, argstr, [], InstFormatR4> {
bits<5> rs3;
bits<5> rs2;
bits<5> rs1;
bits<3> funct3;
bits<5> rd;

let Inst{31-27} = rs3;
let Inst{26-25} = funct2;
let Inst{24-20} = rs2;
let Inst{19-15} = rs1;
let Inst{14-12} = funct3;
let Inst{11-7} = rd;
let Opcode = opcode.Value;
}

class RVInstRAtomic<bits<5> funct5, bit aq, bit rl, bits<3> funct3,
RISCVOpcode opcode, dag outs, dag ins, string opcodestr,
string argstr>
Expand All @@ -136,6 +155,22 @@ class RVInstRAtomic<bits<5> funct5, bit aq, bit rl, bits<3> funct3,
let Opcode = opcode.Value;
}

class RVInstRFrm<bits<7> funct7, RISCVOpcode opcode, dag outs, dag ins,
string opcodestr, string argstr>
: RVInst<outs, ins, opcodestr, argstr, [], InstFormatR> {
bits<5> rs2;
bits<5> rs1;
bits<3> funct3;
bits<5> rd;

let Inst{31-25} = funct7;
let Inst{24-20} = rs2;
let Inst{19-15} = rs1;
let Inst{14-12} = funct3;
let Inst{11-7} = rd;
let Opcode = opcode.Value;
}

class RVInstI<bits<3> funct3, RISCVOpcode opcode, dag outs, dag ins,
string opcodestr, string argstr>
: RVInst<outs, ins, opcodestr, argstr, [], InstFormatI> {
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -441,3 +441,4 @@ def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),

include "RISCVInstrInfoM.td"
include "RISCVInstrInfoA.td"
include "RISCVInstrInfoF.td"
Loading

0 comments on commit 0d6cf90

Please sign in to comment.