1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 19:23:23 +01:00

[RISCV] MC layer support for the standard RV32D instruction set extension

As the FPR32 and FPR64 registers have the same names, use 
validateTargetOperandClass in RISCVAsmParser to coerce a parsed FPR32 to an 
FPR64 when necessary. The rest of this patch is very similar to the RV32F 
patch.

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

llvm-svn: 320023
This commit is contained in:
Alex Bradbury 2017-12-07 10:46:23 +00:00
parent a2d7c39420
commit e4dd444e6f
10 changed files with 441 additions and 0 deletions

View File

@ -32,6 +32,9 @@ struct RISCVOperand;
class RISCVAsmParser : public MCTargetAsmParser {
SMLoc getLoc() const { return getParser().getTok().getLoc(); }
unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
unsigned Kind) override;
bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo,
int Lower, int Upper, Twine Msg);
@ -381,6 +384,67 @@ public:
#define GET_MATCHER_IMPLEMENTATION
#include "RISCVGenAsmMatcher.inc"
// Return the matching FPR64 register for the given FPR32.
// FIXME: Ideally this function could be removed in favour of using
// information from TableGen.
unsigned convertFPR32ToFPR64(unsigned Reg) {
switch (Reg) {
default:
llvm_unreachable("Not a recognised FPR32 register");
case RISCV::F0_32: return RISCV::F0_64;
case RISCV::F1_32: return RISCV::F1_64;
case RISCV::F2_32: return RISCV::F2_64;
case RISCV::F3_32: return RISCV::F3_64;
case RISCV::F4_32: return RISCV::F4_64;
case RISCV::F5_32: return RISCV::F5_64;
case RISCV::F6_32: return RISCV::F6_64;
case RISCV::F7_32: return RISCV::F7_64;
case RISCV::F8_32: return RISCV::F8_64;
case RISCV::F9_32: return RISCV::F9_64;
case RISCV::F10_32: return RISCV::F10_64;
case RISCV::F11_32: return RISCV::F11_64;
case RISCV::F12_32: return RISCV::F12_64;
case RISCV::F13_32: return RISCV::F13_64;
case RISCV::F14_32: return RISCV::F14_64;
case RISCV::F15_32: return RISCV::F15_64;
case RISCV::F16_32: return RISCV::F16_64;
case RISCV::F17_32: return RISCV::F17_64;
case RISCV::F18_32: return RISCV::F18_64;
case RISCV::F19_32: return RISCV::F19_64;
case RISCV::F20_32: return RISCV::F20_64;
case RISCV::F21_32: return RISCV::F21_64;
case RISCV::F22_32: return RISCV::F22_64;
case RISCV::F23_32: return RISCV::F23_64;
case RISCV::F24_32: return RISCV::F24_64;
case RISCV::F25_32: return RISCV::F25_64;
case RISCV::F26_32: return RISCV::F26_64;
case RISCV::F27_32: return RISCV::F27_64;
case RISCV::F28_32: return RISCV::F28_64;
case RISCV::F29_32: return RISCV::F29_64;
case RISCV::F30_32: return RISCV::F30_64;
case RISCV::F31_32: return RISCV::F31_64;
}
}
unsigned RISCVAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
unsigned Kind) {
RISCVOperand &Op = static_cast<RISCVOperand &>(AsmOp);
if (!Op.isReg())
return Match_InvalidOperand;
unsigned Reg = Op.getReg();
bool IsRegFPR32 =
RISCVMCRegisterClasses[RISCV::FPR32RegClassID].contains(Reg);
// As the parser couldn't differentiate an FPR32 from an FPR64, coerce the
// register from FPR32 to FPR64 if necessary.
if (IsRegFPR32 && Kind == MCK_FPR64) {
Op.Reg.RegNum = convertFPR32ToFPR64(Reg);
return Match_Success;
}
return Match_InvalidOperand;
}
bool RISCVAsmParser::generateImmOutOfRangeError(
OperandVector &Operands, uint64_t ErrorInfo, int Lower, int Upper,
Twine Msg = "immediate must be an integer in the range") {

View File

@ -105,6 +105,31 @@ static DecodeStatus DecodeFPR32RegisterClass(MCInst &Inst, uint64_t RegNo,
return MCDisassembler::Success;
}
static const unsigned FPR64DecoderTable[] = {
RISCV::F0_64, RISCV::F1_64, RISCV::F2_64, RISCV::F3_64,
RISCV::F4_64, RISCV::F5_64, RISCV::F6_64, RISCV::F7_64,
RISCV::F8_64, RISCV::F9_64, RISCV::F10_64, RISCV::F11_64,
RISCV::F12_64, RISCV::F13_64, RISCV::F14_64, RISCV::F15_64,
RISCV::F16_64, RISCV::F17_64, RISCV::F18_64, RISCV::F19_64,
RISCV::F20_64, RISCV::F21_64, RISCV::F22_64, RISCV::F23_64,
RISCV::F24_64, RISCV::F25_64, RISCV::F26_64, RISCV::F27_64,
RISCV::F28_64, RISCV::F29_64, RISCV::F30_64, RISCV::F31_64
};
static DecodeStatus DecodeFPR64RegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
if (RegNo > sizeof(FPR64DecoderTable))
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 = FPR64DecoderTable[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) {

View File

@ -31,6 +31,13 @@ def FeatureStdExtF
def HasStdExtF : Predicate<"Subtarget->hasStdExtF()">,
AssemblerPredicate<"FeatureStdExtF">;
def FeatureStdExtD
: SubtargetFeature<"d", "HasStdExtD", "true",
"'D' (Double-Precision Floating-Point)",
[FeatureStdExtF]>;
def HasStdExtD : Predicate<"Subtarget->hasStdExtD()">,
AssemblerPredicate<"FeatureStdExtD">;
def Feature64Bit
: SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">;
@ -63,6 +70,7 @@ def RISCVInstrInfo : InstrInfo {
def RISCVAsmParser : AsmParser {
let ShouldEmitMatchRegisterAltName = 1;
let AllowDuplicateRegisterNames = 1;
}
def RISCV : Target {

View File

@ -442,3 +442,4 @@ def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),
include "RISCVInstrInfoM.td"
include "RISCVInstrInfoA.td"
include "RISCVInstrInfoF.td"
include "RISCVInstrInfoD.td"

View File

@ -0,0 +1,131 @@
//===-- RISCVInstrInfoD.td - RISC-V 'D' instructions -------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the RISC-V instructions from the standard 'D',
// Double-Precision Floating-Point instruction set extension.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Instruction Class Templates
//===----------------------------------------------------------------------===//
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
class FPFMAD_rrr_frm<RISCVOpcode opcode, string opcodestr>
: RVInstR4<0b01, opcode, (outs FPR64:$rd),
(ins FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, frmarg:$funct3),
opcodestr, "$rd, $rs1, $rs2, $rs3, $funct3">;
class FPFMADDynFrmAlias<FPFMAD_rrr_frm Inst, string OpcodeStr>
: InstAlias<OpcodeStr#" $rd, $rs1, $rs2, $rs3",
(Inst FPR64:$rd, FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, 0b111)>;
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
class FPALUD_rr<bits<7> funct7, bits<3> funct3, string opcodestr>
: RVInstR<funct7, funct3, OPC_OP_FP, (outs FPR64:$rd),
(ins FPR64:$rs1, FPR64:$rs2), opcodestr, "$rd, $rs1, $rs2">;
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
class FPALUD_rr_frm<bits<7> funct7, string opcodestr>
: RVInstRFrm<funct7, OPC_OP_FP, (outs FPR64:$rd),
(ins FPR64:$rs1, FPR64:$rs2, frmarg:$funct3), opcodestr,
"$rd, $rs1, $rs2, $funct3">;
class FPALUDDynFrmAlias<FPALUD_rr_frm Inst, string OpcodeStr>
: InstAlias<OpcodeStr#" $rd, $rs1, $rs2",
(Inst FPR64:$rd, FPR64:$rs1, FPR64:$rs2, 0b111)>;
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
class FPCmpD_rr<bits<3> funct3, string opcodestr>
: RVInstR<0b1010001, funct3, OPC_OP_FP, (outs GPR:$rd),
(ins FPR64:$rs1, FPR64:$rs2), opcodestr, "$rd, $rs1, $rs2">;
//===----------------------------------------------------------------------===//
// Instructions
//===----------------------------------------------------------------------===//
let Predicates = [HasStdExtD] in {
let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
def FLD : RVInstI<0b011, OPC_LOAD_FP, (outs FPR64:$rd),
(ins GPR:$rs1, simm12:$imm12),
"fld", "$rd, ${imm12}(${rs1})">;
// Operands for stores are in the order srcreg, base, offset rather than
// reflecting the order these fields are specified in the instruction
// encoding.
let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
def FSD : RVInstS<0b011, OPC_STORE_FP, (outs),
(ins FPR64:$rs2, GPR:$rs1, simm12:$imm12),
"fsd", "$rs2, ${imm12}(${rs1})">;
def FMADD_D : FPFMAD_rrr_frm<OPC_MADD, "fmadd.d">;
def : FPFMADDynFrmAlias<FMADD_D, "fmadd.d">;
def FMSUB_D : FPFMAD_rrr_frm<OPC_MSUB, "fmsub.d">;
def : FPFMADDynFrmAlias<FMSUB_D, "fmsub.d">;
def FNMSUB_D : FPFMAD_rrr_frm<OPC_NMSUB, "fnmsub.d">;
def : FPFMADDynFrmAlias<FNMSUB_D, "fnmsub.d">;
def FNMADD_D : FPFMAD_rrr_frm<OPC_NMADD, "fnmadd.d">;
def : FPFMADDynFrmAlias<FNMADD_D, "fnmadd.d">;
def FADD_D : FPALUD_rr_frm<0b0000001, "fadd.d">;
def : FPALUDDynFrmAlias<FADD_D, "fadd.d">;
def FSUB_D : FPALUD_rr_frm<0b0000101, "fsub.d">;
def : FPALUDDynFrmAlias<FSUB_D, "fsub.d">;
def FMUL_D : FPALUD_rr_frm<0b0001001, "fmul.d">;
def : FPALUDDynFrmAlias<FMUL_D, "fmul.d">;
def FDIV_D : FPALUD_rr_frm<0b0001101, "fdiv.d">;
def : FPALUDDynFrmAlias<FDIV_D, "fdiv.d">;
def FSQRT_D : FPUnaryOp_r_frm<0b0101101, FPR64, FPR64, "fsqrt.d"> {
let rs2 = 0b00000;
}
def : FPUnaryOpDynFrmAlias<FSQRT_D, "fsqrt.d", FPR64, FPR64>;
def FSGNJ_D : FPALUD_rr<0b0010001, 0b000, "fsgnj.d">;
def FSGNJN_D : FPALUD_rr<0b0010001, 0b001, "fsgnjn.d">;
def FSGNJX_D : FPALUD_rr<0b0010001, 0b010, "fsgnjx.d">;
def FMIN_D : FPALUD_rr<0b0010101, 0b000, "fmin.d">;
def FMAX_D : FPALUD_rr<0b0010101, 0b001, "fmax.d">;
def FCVT_S_D : FPUnaryOp_r_frm<0b0100000, FPR32, FPR64, "fcvt.s.d"> {
let rs2 = 0b00001;
}
def : FPUnaryOpDynFrmAlias<FCVT_S_D, "fcvt.s.d", FPR32, FPR64>;
def FCVT_D_S : FPUnaryOp_r<0b0100001, 0b000, FPR64, FPR32, "fcvt.d.s"> {
let rs2 = 0b00000;
}
def FEQ_D : FPCmpD_rr<0b010, "feq.d">;
def FLT_D : FPCmpD_rr<0b001, "flt.d">;
def FLE_D : FPCmpD_rr<0b000, "fle.d">;
def FCLASS_D : FPUnaryOp_r<0b1110001, 0b001, GPR, FPR64, "fclass.d"> {
let rs2 = 0b00000;
}
def FCVT_W_D : FPUnaryOp_r_frm<0b1100001, GPR, FPR64, "fcvt.w.d"> {
let rs2 = 0b00000;
}
def : FPUnaryOpDynFrmAlias<FCVT_W_D, "fcvt.w.d", GPR, FPR64>;
def FCVT_WU_D : FPUnaryOp_r_frm<0b1100001, GPR, FPR64, "fcvt.wu.d"> {
let rs2 = 0b00001;
}
def : FPUnaryOpDynFrmAlias<FCVT_WU_D, "fcvt.wu.d", GPR, FPR64>;
def FCVT_D_W : FPUnaryOp_r<0b1101001, 0b000, FPR64, GPR, "fcvt.d.w"> {
let rs2 = 0b00000;
}
def FCVT_D_WU : FPUnaryOp_r<0b1101001, 0b000, FPR64, GPR, "fcvt.d.wu"> {
let rs2 = 0b00001;
}
} // Predicates = [HasStdExtD]

View File

@ -22,6 +22,18 @@ class RISCVReg32<bits<5> Enc, string n, list<string> alt = []> : Register<n> {
let AltNames = alt;
}
// Because RISCVReg64 register have AsmName and AltNames that alias with their
// 32-bit sub-register, RISCVAsmParser will need to coerce a register number
// from a RISCVReg32 to the equivalent RISCVReg64 when appropriate.
def sub_32 : SubRegIndex<32>;
class RISCVReg64<RISCVReg32 subreg> : Register<""> {
let HWEncoding{4-0} = subreg.HWEncoding{4-0};
let SubRegs = [subreg];
let SubRegIndices = [sub_32];
let AsmName = subreg.AsmName;
let AltNames = subreg.AltNames;
}
def ABIRegAltName : RegAltNameIndex;
} // Namespace = "RISCV"
@ -113,6 +125,11 @@ let RegAltNameIndices = [ABIRegAltName] in {
def F29_32 : RISCVReg32<29,"f29", ["ft9"]>, DwarfRegNum<[61]>;
def F30_32 : RISCVReg32<30,"f30", ["ft10"]>, DwarfRegNum<[62]>;
def F31_32 : RISCVReg32<31,"f31", ["ft11"]>, DwarfRegNum<[63]>;
foreach Index = 0-31 in {
def F#Index#_64 : RISCVReg64<!cast<RISCVReg32>("F"#Index#"_32")>,
DwarfRegNum<[!add(Index, 32)]>;
}
}
// The order of registers represents the preferred allocation sequence,
@ -124,3 +141,13 @@ def FPR32 : RegisterClass<"RISCV", [f32], 32, (add
(sequence "F%u_32", 8, 9),
(sequence "F%u_32", 18, 27)
)>;
// The order of registers represents the preferred allocation sequence,
// meaning caller-save regs are listed before callee-save.
def FPR64 : RegisterClass<"RISCV", [f64], 64, (add
(sequence "F%u_64", 0, 7),
(sequence "F%u_64", 10, 17),
(sequence "F%u_64", 28, 31),
(sequence "F%u_64", 8, 9),
(sequence "F%u_64", 18, 27)
)>;

View File

@ -33,6 +33,7 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
bool HasStdExtM = false;
bool HasStdExtA = false;
bool HasStdExtF = false;
bool HasStdExtD = false;
bool HasRV64 = false;
unsigned XLen = 32;
MVT XLenVT = MVT::i32;
@ -72,6 +73,7 @@ public:
bool hasStdExtM() const { return HasStdExtM; }
bool hasStdExtA() const { return HasStdExtA; }
bool hasStdExtF() const { return HasStdExtF; }
bool hasStdExtD() const { return HasStdExtD; }
bool is64Bit() const { return HasRV64; }
MVT getXLenVT() const { return XLenVT; }
unsigned getXLen() const { return XLen; }

View File

@ -0,0 +1,21 @@
# RUN: not llvm-mc -triple riscv32 -mattr=+d < %s 2>&1 | FileCheck %s
# Out of range immediates
## simm12
fld ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: immediate must be an integer in the range [-2048, 2047]
fsd ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: immediate must be an integer in the range [-2048, 2047]
# Memory operand not formatted correctly
fld ft1, a0, -200 # CHECK: :[[@LINE]]:10: error: immediate must be an integer in the range [-2048, 2047]
fsd ft2, a1, 100 # CHECK: :[[@LINE]]:10: error: immediate must be an integer in the range [-2048, 2047]
# Invalid register names
fld ft15, 100(a0) # CHECK: :[[@LINE]]:5: error: invalid operand for instruction
fld ft1, 100(a10) # CHECK: :[[@LINE]]:14: error: expected register
fsgnjn.d fa100, fa2, fa3 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
# Integer registers where FP regs are expected
fadd.d a2, a1, a0 # CHECK: :[[@LINE]]:8: error: invalid operand for instruction
# FP registers where integer regs are expected
fcvt.wu.d ft2, a1 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction

159
test/MC/RISCV/rv32d-valid.s Normal file
View File

@ -0,0 +1,159 @@
# RUN: llvm-mc %s -triple=riscv32 -mattr=+d -show-encoding \
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s
# RUN: llvm-mc %s -triple=riscv64 -mattr=+d -show-encoding \
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+d < %s \
# RUN: | llvm-objdump -mattr=+d -d - | FileCheck -check-prefix=CHECK-INST %s
# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+d < %s \
# RUN: | llvm-objdump -mattr=+d -d - | FileCheck -check-prefix=CHECK-INST %s
# Support for the 'D' extension implies support for 'F'
# CHECK-INST: fadd.s fs10, fs11, ft8
# CHECK: encoding: [0x53,0xfd,0xcd,0x01]
fadd.s f26, f27, f28
# CHECK-INST: fld ft0, 12(a0)
# CHECK: encoding: [0x07,0x30,0xc5,0x00]
fld f0, 12(a0)
# CHECK-INST: fld ft1, 4(ra)
# CHECK: encoding: [0x87,0xb0,0x40,0x00]
fld f1, +4(ra)
# CHECK-INST: fld ft2, -2048(a3)
# CHECK: encoding: [0x07,0xb1,0x06,0x80]
fld f2, -2048(x13)
# CHECK-INST: fld ft3, -2048(s1)
# CHECK: encoding: [0x87,0xb1,0x04,0x80]
fld f3, %lo(2048)(s1)
# CHECK-INST: fld ft4, 2047(s2)
# CHECK: encoding: [0x07,0x32,0xf9,0x7f]
fld f4, 2047(s2)
# CHECK-INST: fld ft5, 0(s3)
# CHECK: encoding: [0x87,0xb2,0x09,0x00]
fld f5, 0(s3)
# CHECK-INST: fsd ft6, 2047(s4)
# CHECK: encoding: [0xa7,0x3f,0x6a,0x7e]
fsd f6, 2047(s4)
# CHECK-INST: fsd ft7, -2048(s5)
# CHECK: encoding: [0x27,0xb0,0x7a,0x80]
fsd f7, -2048(s5)
# CHECK-INST: fsd fs0, -2048(s6)
# CHECK: encoding: [0x27,0x30,0x8b,0x80]
fsd f8, %lo(2048)(s6)
# CHECK-INST: fsd fs1, 999(s7)
# CHECK: encoding: [0xa7,0xb3,0x9b,0x3e]
fsd f9, 999(s7)
# CHECK-INST: fmadd.d fa0, fa1, fa2, fa3
# CHECK: encoding: [0x43,0xf5,0xc5,0x6a]
fmadd.d f10, f11, f12, f13
# CHECK-INST: fmsub.d fa4, fa5, fa6, fa7
# CHECK: encoding: [0x47,0xf7,0x07,0x8b]
fmsub.d f14, f15, f16, f17
# CHECK-INST: fnmsub.d fs2, fs3, fs4, fs5
# CHECK: encoding: [0x4b,0xf9,0x49,0xab]
fnmsub.d f18, f19, f20, f21
# CHECK-INST: fnmadd.d fs6, fs7, fs8, fs9
# CHECK: encoding: [0x4f,0xfb,0x8b,0xcb]
fnmadd.d f22, f23, f24, f25
# CHECK-INST: fadd.d fs10, fs11, ft8
# CHECK: encoding: [0x53,0xfd,0xcd,0x03]
fadd.d f26, f27, f28
# CHECK-INST: fsub.d ft9, ft10, ft11
# CHECK: encoding: [0xd3,0x7e,0xff,0x0b]
fsub.d f29, f30, f31
# CHECK-INST: fmul.d ft0, ft1, ft2
# CHECK: encoding: [0x53,0xf0,0x20,0x12]
fmul.d ft0, ft1, ft2
# CHECK-INST: fdiv.d ft3, ft4, ft5
# CHECK: encoding: [0xd3,0x71,0x52,0x1a]
fdiv.d ft3, ft4, ft5
# CHECK-INST: fsqrt.d ft6, ft7
# CHECK: encoding: [0x53,0xf3,0x03,0x5a]
fsqrt.d ft6, ft7
# CHECK-INST: fsgnj.d fs1, fa0, fa1
# CHECK: encoding: [0xd3,0x04,0xb5,0x22]
fsgnj.d fs1, fa0, fa1
# CHECK-INST: fsgnjn.d fa1, fa3, fa4
# CHECK: encoding: [0xd3,0x95,0xe6,0x22]
fsgnjn.d fa1, fa3, fa4
# CHECK-INST: fsgnjx.d fa3, fa2, fa1
# CHECK: encoding: [0xd3,0x26,0xb6,0x22]
fsgnjx.d fa3, fa2, fa1
# CHECK-INST: fmin.d fa5, fa6, fa7
# CHECK: encoding: [0xd3,0x07,0x18,0x2b]
fmin.d fa5, fa6, fa7
# CHECK-INST: fmax.d fs2, fs3, fs4
# CHECK: encoding: [0x53,0x99,0x49,0x2b]
fmax.d fs2, fs3, fs4
# CHECK-INST: fcvt.s.d fs5, fs6
# CHECK: encoding: [0xd3,0x7a,0x1b,0x40]
fcvt.s.d fs5, fs6
# CHECK-INST: fcvt.d.s fs7, fs8
# CHECK: encoding: [0xd3,0x0b,0x0c,0x42]
fcvt.d.s fs7, fs8
# CHECK-INST: feq.d a1, fs8, fs9
# CHECK: encoding: [0xd3,0x25,0x9c,0xa3]
feq.d a1, fs8, fs9
# CHECK-INST: flt.d a2, fs10, fs11
# CHECK: encoding: [0x53,0x16,0xbd,0xa3]
flt.d a2, fs10, fs11
# CHECK-INST: fle.d a3, ft8, ft9
# CHECK: encoding: [0xd3,0x06,0xde,0xa3]
fle.d a3, ft8, ft9
# CHECK-INST: fclass.d a3, ft10
# CHECK: encoding: [0xd3,0x16,0x0f,0xe2]
fclass.d a3, ft10
# CHECK-INST: fcvt.w.d a4, ft11
# CHECK: encoding: [0x53,0xf7,0x0f,0xc2]
fcvt.w.d a4, ft11
# CHECK-INST: fcvt.d.w ft0, a5
# CHECK: encoding: [0x53,0x80,0x07,0xd2]
fcvt.d.w ft0, a5
# CHECK-INST: fcvt.d.wu ft1, a6
# CHECK: encoding: [0xd3,0x00,0x18,0xd2]
fcvt.d.wu ft1, a6
# Rounding modes
# CHECK-INST: fmadd.d fa0, fa1, fa2, fa3, rne
# CHECK: encoding: [0x43,0x85,0xc5,0x6a]
fmadd.d f10, f11, f12, f13, rne
# CHECK-INST: fmsub.d fa4, fa5, fa6, fa7, rtz
# CHECK: encoding: [0x47,0x97,0x07,0x8b]
fmsub.d f14, f15, f16, f17, rtz
# CHECK-INST: fnmsub.d fs2, fs3, fs4, fs5, rdn
# CHECK: encoding: [0x4b,0xa9,0x49,0xab]
fnmsub.d f18, f19, f20, f21, rdn
# CHECK-INST: fnmadd.d fs6, fs7, fs8, fs9, rup
# CHECK: encoding: [0x4f,0xbb,0x8b,0xcb]
fnmadd.d f22, f23, f24, f25, rup
# CHECK-INST: fadd.d fs10, fs11, ft8, rmm
# CHECK: encoding: [0x53,0xcd,0xcd,0x03]
fadd.d f26, f27, f28, rmm
# CHECK-INST: fsub.d ft9, ft10, ft11
# CHECK: encoding: [0xd3,0x7e,0xff,0x0b]
fsub.d f29, f30, f31, dyn
# CHECK-INST: fmul.d ft0, ft1, ft2, rne
# CHECK: encoding: [0x53,0x80,0x20,0x12]
fmul.d ft0, ft1, ft2, rne
# CHECK-INST: fdiv.d ft3, ft4, ft5, rtz
# CHECK: encoding: [0xd3,0x11,0x52,0x1a]
fdiv.d ft3, ft4, ft5, rtz
# CHECK-INST: fsqrt.d ft6, ft7, rdn
# CHECK: encoding: [0x53,0xa3,0x03,0x5a]
fsqrt.d ft6, ft7, rdn
# CHECK-INST: fcvt.s.d fs5, fs6, rup
# CHECK: encoding: [0xd3,0x3a,0x1b,0x40]
fcvt.s.d fs5, fs6, rup
# CHECK-INST: fcvt.w.d a4, ft11, rmm
# CHECK: encoding: [0x53,0xc7,0x0f,0xc2]
fcvt.w.d a4, ft11, rmm
# CHECK-INST: fcvt.wu.d a5, ft10
# CHECK: encoding: [0xd3,0x77,0x1f,0xc2]
fcvt.wu.d a5, ft10, dyn

View File

@ -27,3 +27,6 @@ fmadd.s f10, f11, f12, ree # CHECK: :[[@LINE]]:24: error: invalid operand for in
fmadd.s f10, f11, f12, f13, ree # CHECK: :[[@LINE]]:29: error: operand must be a valid floating point rounding mode mnemonic
fmsub.s f14, f15, f16, f17, 0 # CHECK: :[[@LINE]]:29: error: operand must be a valid floating point rounding mode mnemonic
fnmsub.s f18, f19, f20, f21, 0b111 # CHECK: :[[@LINE]]:30: error: operand must be a valid floating point rounding mode mnemonic
# Using 'D' instructions for an 'F'-only target
fadd.d ft0, ft1, ft2 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled