Index: llvm/docs/RISCVUsage.rst =================================================================== --- llvm/docs/RISCVUsage.rst +++ llvm/docs/RISCVUsage.rst @@ -145,6 +145,9 @@ ``experimental-zvfh`` LLVM implements `this draft text `_. +``experimental-zfa`` + LLVM implements the `0.1 draft specification `_ (see Chapter 25). + To use an experimental extension from `clang`, you must add `-menable-experimental-extensions` to the command line, and specify the exact version of the experimental extension you are using. To use an experimental extension with LLVM's internal developer tools (e.g. `llc`, `llvm-objdump`, `llvm-mc`), you must prefix the extension name with `experimental-`. Note that you don't need to specify the version with internal tools, and shouldn't include the `experimental-` prefix with `clang`. Vendor Extensions Index: llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -534,6 +534,20 @@ return RISCVFPRndMode::stringToRoundingMode(Str) != RISCVFPRndMode::Invalid; } + /// Return true if the operand is "rtz" floating point rounding mode. + bool isFRMArgforCVTMOD() const { + if (!isImm()) + return false; + const MCExpr *Val = getImm(); + auto *SVal = dyn_cast(Val); + if (!SVal || SVal->getKind() != MCSymbolRefExpr::VK_None) + return false; + + StringRef Str = SVal->getSymbol().getName(); + + return RISCVFPRndMode::stringToRoundingMode(Str) == RISCVFPRndMode::RTZ; + } + bool isImmXLenLI() const { int64_t Imm; RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; @@ -1025,11 +1039,27 @@ return FRM; } + // Returns the "rtz" rounding mode represented by this RISCVOperand. Should only + // be called after checking isFRMArgforCVTMOD. + RISCVFPRndMode::RoundingMode getRoundingModeforCVTMOD() const { + // isFRMArg has validated the operand, meaning this cast is safe. + auto SE = cast(getImm()); + RISCVFPRndMode::RoundingMode FRM = + RISCVFPRndMode::stringToRoundingMode(SE->getSymbol().getName()); + assert(FRM == RISCVFPRndMode::RTZ && "Invalid rounding mode"); + return FRM; + } + void addFRMArgOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(getRoundingMode())); } + void addFRMArgOperandsforCVTMOD(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createImm(getRoundingModeforCVTMOD())); + } + #include "THEAD/THEADOperand.def" }; } // end anonymous namespace. @@ -1295,6 +1325,12 @@ ErrorLoc, "operand must be a valid floating point rounding mode mnemonic"); } + case Match_InvalidFRMArgforCVTMOD: { + SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error( + ErrorLoc, + "operand must be 'rtz' floating-point rounding mode mnemonic"); + } case Match_InvalidBareSymbol: { SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error(ErrorLoc, "operand must be a bare symbol name"); Index: llvm/lib/Target/RISCV/RISCV.td =================================================================== --- llvm/lib/Target/RISCV/RISCV.td +++ llvm/lib/Target/RISCV/RISCV.td @@ -125,6 +125,14 @@ "'Zhinx' (Half Float in Integer) or " "'Zhinxmin' (Half Float in Integer Minimal)">; +def FeatureStdExtZfa + : SubtargetFeature<"experimental-zfa", "HasStdExtZfa", "true", + "'Zfa' (Additional Floating-Point)", + [FeatureStdExtF]>; +def HasStdExtZfa : Predicate<"Subtarget->hasStdExtZfa()">, + AssemblerPredicate<(all_of FeatureStdExtZfa), + "'Zfa' (Additional Floating-Point)">; + def FeatureStdExtC : SubtargetFeature<"c", "HasStdExtC", "true", "'C' (Compressed Instructions)">; Index: llvm/lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -1865,6 +1865,7 @@ include "RISCVInstrInfoZk.td" include "RISCVInstrInfoV.td" include "RISCVInstrInfoZfh.td" +include "RISCVInstrInfoZfa.td" include "RISCVInstrInfoZicbo.td" //===----------------------------------------------------------------------===// Index: llvm/lib/Target/RISCV/RISCVInstrInfoZfa.td =================================================================== --- /dev/null +++ llvm/lib/Target/RISCV/RISCVInstrInfoZfa.td @@ -0,0 +1,102 @@ +//===-- RISCVInstrInfoZfa.td - RISC-V 'Zfa' instructions ---*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file describes the RISC-V instructions from the standard 'Zfa' +// additional floating-point extension, version 0.1. +// This version is still experimental as the 'Zfa' extension hasn't been +// ratified yet. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Operand and SDNode transformation definitions. +//===----------------------------------------------------------------------===// + +def FRMArgforCVTMOD : AsmOperandClass { + let Name = "FRMArgforCVTMOD"; + let RenderMethod = "addFRMArgOperandsforCVTMOD"; + let DiagnosticType = "InvalidFRMArgforCVTMOD"; +} + +def frmargforcvtmod : Operand { + let ParserMatchClass = FRMArgforCVTMOD; + let PrintMethod = "printFRMArg"; + let DecoderMethod = "decodeFRMArg"; +} + +//===----------------------------------------------------------------------===// +// Instruction class templates +//===----------------------------------------------------------------------===// + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1 in +class FPBinaryOp_rr funct7, bits<3> funct3, DAGOperand rdty, + DAGOperand rsty, string opcodestr> + : RVInstR; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1, + UseNamedOperandTable = 1, hasPostISelHook = 1 in +class FPUnaryOp_r_rtz funct7, bits<5> rs2val, DAGOperand rdty, + DAGOperand rs1ty, string opcodestr> + : RVInstRFrm { + let rs2 = rs2val; +} + +//===----------------------------------------------------------------------===// +// Instructions +//===----------------------------------------------------------------------===// + +let Predicates = [HasStdExtZfa] in { +def FMINM_S: FPALU_rr<0b0010100, 0b010, "fminm.s", FPR32, /*Commutable*/ 1>; +def FMAXM_S: FPALU_rr<0b0010100, 0b011, "fmaxm.s", FPR32, /*Commutable*/ 1>; + +def FROUND_S : FPUnaryOp_r_frm<0b0100000, 0b00100, FPR32, FPR32, "fround.s">; +def FROUNDNX_S : FPUnaryOp_r_frm<0b0100000, 0b00101, FPR32, FPR32, "froundnx.s">; + +def FLTQ_S : FPCmp_rr<0b1010000, 0b101, "fltq.s", FPR32, /*Commutable*/ 1>; +def FLEQ_S : FPCmp_rr<0b1010000, 0b100, "fleq.s", FPR32, /*Commutable*/ 1>; +} // Predicates = [HasStdExtZfa] + +let Predicates = [HasStdExtZfa, HasStdExtD] in { +def FLI_D : FPUnaryOp_imm<0b1111001, 0b00001, 0b000, OPC_OP_FP, (outs FPR64:$rd), + (ins loadfp64imm:$imm), "fli.d", "$rd, $imm">, + Sched<[WriteFMovI64ToF64, ReadFMovI64ToF64]>; + +def FMINM_D: FPALU_rr<0b0010101, 0b010, "fminm.d", FPR64, /*Commutable*/ 1>; +def FMAXM_D: FPALU_rr<0b0010101, 0b011, "fmaxm.d", FPR64, /*Commutable*/ 1>; + +def FROUND_D : FPUnaryOp_r_frm<0b0100001, 0b00100, FPR64, FPR64, "fround.d">; +def FROUNDNX_D : FPUnaryOp_r_frm<0b0100001, 0b00101, FPR64, FPR64, "froundnx.d">; + +def FCVTMOD_W_D + : FPUnaryOp_r_rtz<0b1100001, 0b01000, GPR, FPR64, "fcvtmod.w.d">, + Sched<[WriteFCvtF64ToI32, ReadFCvtF64ToI32]>; + +def FLTQ_D : FPCmp_rr<0b1010001, 0b101, "fltq.d", FPR64, /*Commutable*/ 1>; +def FLEQ_D : FPCmp_rr<0b1010001, 0b100, "fleq.d", FPR64, /*Commutable*/ 1>; +} // Predicates = [HasStdExtZfa, HasStdExtD] + +let Predicates = [HasStdExtZfa, HasStdExtD, IsRV32] in { +def FMVH_X_D : FPUnaryOp_r<0b1110001, 0b00001, 0b000, GPR, FPR64, "fmvh.x.d">, + Sched<[WriteFMovF32ToI32, ReadFMovF32ToI32]>; +def FMVP_D_X : FPBinaryOp_rr<0b1011001, 0b000, FPR64, GPR, "fmvp.d.x">, + Sched<[WriteFMovI32ToF32, ReadFMovI32ToF32]>; +} // Predicates = [HasStdExtZfa, HasStdExtD, IsRV32] + +let Predicates = [HasStdExtZfa, HasStdExtZfh] in { +def FMINM_H: FPALU_rr<0b0010110, 0b010, "fminm.h", FPR16, /*Commutable*/ 1>; +def FMAXM_H: FPALU_rr<0b0010110, 0b011, "fmaxm.h", FPR16, /*Commutable*/ 1>; + +def FROUND_H : FPUnaryOp_r_frm<0b0100010, 0b00100, FPR16, FPR16, "fround.h">; +def FROUNDNX_H : FPUnaryOp_r_frm<0b0100010, 0b00101, FPR16, FPR16, "froundnx.h">; + +def FLTQ_H : FPCmp_rr<0b1010010, 0b101, "fltq.h", FPR16, /*Commutable*/ 1>; +def FLEQ_H : FPCmp_rr<0b1010010, 0b100, "fleq.h", FPR16, /*Commutable*/ 1>; +} // Predicates = [HasStdExtZfa, HasStdExtZfh] Index: llvm/test/MC/RISCV/rv32zfa-only-valid.s =================================================================== --- /dev/null +++ llvm/test/MC/RISCV/rv32zfa-only-valid.s @@ -0,0 +1,13 @@ +# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-zfa,+d,+zfh -riscv-no-aliases -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+experimental-zfa,+d,+zfh < %s \ +# RUN: | llvm-objdump --mattr=+experimental-zfa,+d,+zfh -M no-aliases -d -r - \ +# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s + +# CHECK-ASM-AND-OBJ: fmvh.x.d a1, fs1 +# CHECK-ASM: encoding: [0xd3,0x85,0x14,0xe2] +fmvh.x.d a1, fs1 + +# CHECK-ASM-AND-OBJ: fmvp.d.x fs1, a1, a2 +# CHECK-ASM: encoding: [0xd3,0x84,0xc5,0xb2] +fmvp.d.x fs1, a1, a2 Index: llvm/test/MC/RISCV/rv32zfa-valid.s =================================================================== --- /dev/null +++ llvm/test/MC/RISCV/rv32zfa-valid.s @@ -0,0 +1,86 @@ +# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-zfa,+d,+zfh -riscv-no-aliases -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc %s -triple=riscv64 -mattr=+experimental-zfa,+d,+zfh -riscv-no-aliases -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+experimental-zfa,+d,+zfh < %s \ +# RUN: | llvm-objdump --mattr=+experimental-zfa,+d,+zfh -M no-aliases -d -r - \ +# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+experimental-zfa,+d,+zfh < %s \ +# RUN: | llvm-objdump --mattr=+experimental-zfa,+d,+zfh -M no-aliases -d -r - \ +# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s + +# CHECK-ASM-AND-OBJ: fminm.s fa0, fa1, fa2 +# CHECK-ASM: encoding: [0x53,0xa5,0xc5,0x28] +fminm.s fa0, fa1, fa2 + +# CHECK-ASM-AND-OBJ: fmaxm.s fs3, fs4, fs5 +# CHECK-ASM: encoding: [0xd3,0x39,0x5a,0x29] +fmaxm.s fs3, fs4, fs5 + +# CHECK-ASM-AND-OBJ: fminm.d fa0, fa1, fa2 +# CHECK-ASM: encoding: [0x53,0xa5,0xc5,0x2a] +fminm.d fa0, fa1, fa2 + +# CHECK-ASM-AND-OBJ: fmaxm.d fs3, fs4, fs5 +# CHECK-ASM: encoding: [0xd3,0x39,0x5a,0x2b] +fmaxm.d fs3, fs4, fs5 + +# CHECK-ASM-AND-OBJ: fminm.h fa0, fa1, fa2 +# CHECK-ASM: encoding: [0x53,0xa5,0xc5,0x2c] +fminm.h fa0, fa1, fa2 + +# CHECK-ASM-AND-OBJ: fmaxm.h fs3, fs4, fs5 +# CHECK-ASM: encoding: [0xd3,0x39,0x5a,0x2d] +fmaxm.h fs3, fs4, fs5 + +# CHECK-ASM-AND-OBJ: fround.s fs1, fs2, dyn +# CHECK-ASM: encoding: [0xd3,0x74,0x49,0x40] +fround.s fs1, fs2, dyn + +# CHECK-ASM-AND-OBJ: froundnx.s fs1, fs2, dyn +# CHECK-ASM: encoding: [0xd3,0x74,0x59,0x40] +froundnx.s fs1, fs2, dyn + +# CHECK-ASM-AND-OBJ: fround.d fs1, fs2, dyn +# CHECK-ASM: encoding: [0xd3,0x74,0x49,0x42] +fround.d fs1, fs2, dyn + +# CHECK-ASM-AND-OBJ: froundnx.d fs1, fs2, dyn +# CHECK-ASM: encoding: [0xd3,0x74,0x59,0x42] +froundnx.d fs1, fs2, dyn + +# CHECK-ASM-AND-OBJ: fround.h ft1, fa1, dyn +# CHECK-ASM: encoding: [0xd3,0xf0,0x45,0x44] +fround.h ft1, fa1, dyn + +# CHECK-ASM-AND-OBJ: froundnx.h ft1, fa1, dyn +# CHECK-ASM: encoding: [0xd3,0xf0,0x55,0x44] +froundnx.h ft1, fa1, dyn + +# CHECK-ASM-AND-OBJ: fcvtmod.w.d a1, ft1, rtz +# CHECK-ASM: encoding: [0xd3,0x95,0x80,0xc2] +fcvtmod.w.d a1, ft1, rtz + +# CHECK-ASM-AND-OBJ: fltq.s a1, fs1, fs2 +# CHECK-ASM: encoding: [0xd3,0xd5,0x24,0xa1] +fltq.s a1, fs1, fs2 + +# CHECK-ASM-AND-OBJ: fleq.s a1, ft1, ft1 +# CHECK-ASM: encoding: [0xd3,0xc5,0x10,0xa0] +fleq.s a1, ft1, ft1 + +# CHECK-ASM-AND-OBJ: fltq.d a1, fs1, fs2 +# CHECK-ASM: encoding: [0xd3,0xd5,0x24,0xa3] +fltq.d a1, fs1, fs2 + +# CHECK-ASM-AND-OBJ: fleq.d a1, ft1, ft2 +# CHECK-ASM: encoding: [0xd3,0xc5,0x20,0xa2] +fleq.d a1, ft1, ft2 + +# CHECK-ASM-AND-OBJ: fltq.h a1, fs1, fs2 +# CHECK-ASM: encoding: [0xd3,0xd5,0x24,0xa5] +fltq.h a1, fs1, fs2 + +# CHECK-ASM-AND-OBJ: fleq.h a1, ft1, ft2 +# CHECK-ASM: encoding: [0xd3,0xc5,0x20,0xa4] +fleq.h a1, ft1, ft2