[llvm] df56b55 - [RISCV][CodeGen] Add codegen patterns for experimental zfa extension (try 2)

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 17 10:28:17 PST 2023


Author: Jun Sha (Joshua)
Date: 2023-02-17T10:28:08-08:00
New Revision: df56b55e1288b17163ab55f3f8f71cff0224937d

URL: https://github.com/llvm/llvm-project/commit/df56b55e1288b17163ab55f3f8f71cff0224937d
DIFF: https://github.com/llvm/llvm-project/commit/df56b55e1288b17163ab55f3f8f71cff0224937d.diff

LOG: [RISCV][CodeGen] Add codegen patterns for experimental zfa extension (try 2)

Recommit by preames with commit message, various style cleanups, and unaddressed review comments corrected.

This patch implements experimental codegen support for the RISCV Zfa extension as specified here: https://github.com/riscv/riscv-isa-manual/releases/download/draft-20221119-5234c63/riscv-spec.pdf, Ch. 25. This extension has not been ratified.

This change does not include support for FLI (upcoming in a follow up change) or FCVTMOD (not relevant for C/C++).

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

Added: 
    llvm/test/CodeGen/RISCV/double-zfa.ll
    llvm/test/CodeGen/RISCV/float-zfa.ll
    llvm/test/CodeGen/RISCV/half-zfa.ll

Modified: 
    llvm/lib/Target/RISCV/RISCVISelLowering.cpp
    llvm/lib/Target/RISCV/RISCVInstrInfoZfa.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 9f053b9f5313f..ebb32bd599668 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -353,7 +353,8 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
   if (Subtarget.hasStdExtZfhOrZfhmin()) {
     if (Subtarget.hasStdExtZfh()) {
       setOperationAction(FPLegalNodeTypes, MVT::f16, Legal);
-      setOperationAction(FPRndMode, MVT::f16, Custom);
+      setOperationAction(FPRndMode, MVT::f16,
+                         Subtarget.hasStdExtZfa() ? Legal : Custom);
       setOperationAction(ISD::SELECT, MVT::f16, Custom);
     } else {
       static const unsigned ZfhminPromoteOps[] = {
@@ -382,7 +383,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
     setOperationAction(ISD::SELECT_CC, MVT::f16, Expand);
     setOperationAction(ISD::BR_CC, MVT::f16, Expand);
 
-    setOperationAction({ISD::FREM, ISD::FNEARBYINT, ISD::FPOW, ISD::FPOWI,
+    setOperationAction(ISD::FNEARBYINT, MVT::f16,
+                       Subtarget.hasStdExtZfa() ? Legal : Promote);
+    setOperationAction({ISD::FREM, ISD::FPOW, ISD::FPOWI,
                         ISD::FCOS, ISD::FSIN, ISD::FSINCOS, ISD::FEXP,
                         ISD::FEXP2, ISD::FLOG, ISD::FLOG2, ISD::FLOG10},
                        MVT::f16, Promote);
@@ -402,7 +405,8 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
 
   if (Subtarget.hasStdExtF()) {
     setOperationAction(FPLegalNodeTypes, MVT::f32, Legal);
-    setOperationAction(FPRndMode, MVT::f32, Custom);
+    setOperationAction(FPRndMode, MVT::f32,
+                       Subtarget.hasStdExtZfa() ? Legal : Custom);
     setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
     setOperationAction(ISD::SELECT_CC, MVT::f32, Expand);
     setOperationAction(ISD::SELECT, MVT::f32, Custom);
@@ -410,6 +414,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
     setOperationAction(FPOpToExpand, MVT::f32, Expand);
     setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand);
     setTruncStoreAction(MVT::f32, MVT::f16, Expand);
+
+    if (Subtarget.hasStdExtZfa())
+      setOperationAction(ISD::FNEARBYINT, MVT::f32, Legal);
   }
 
   if (Subtarget.hasStdExtF() && Subtarget.is64Bit())
@@ -417,9 +424,18 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
 
   if (Subtarget.hasStdExtD()) {
     setOperationAction(FPLegalNodeTypes, MVT::f64, Legal);
-    if (Subtarget.is64Bit()) {
-      setOperationAction(FPRndMode, MVT::f64, Custom);
+
+    if (Subtarget.hasStdExtZfa()) {
+      setOperationAction(FPRndMode, MVT::f64, Legal);
+      setOperationAction(ISD::FNEARBYINT, MVT::f64, Legal);
+      setOperationAction(ISD::BITCAST, MVT::i64, Custom);
+      setOperationAction(ISD::BITCAST, MVT::f64, Custom);
     }
+
+    if (Subtarget.is64Bit())
+      setOperationAction(FPRndMode, MVT::f64,
+                         Subtarget.hasStdExtZfa() ? Legal : Custom);
+
     setOperationAction(ISD::STRICT_FP_ROUND, MVT::f32, Legal);
     setOperationAction(ISD::STRICT_FP_EXTEND, MVT::f64, Legal);
     setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
@@ -3832,6 +3848,16 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
           DAG.getNode(RISCVISD::FMV_W_X_RV64, DL, MVT::f32, NewOp0);
       return FPConv;
     }
+    if (VT == MVT::f64 && Op0VT == MVT::i64 && XLenVT == MVT::i32 &&
+        Subtarget.hasStdExtZfa()) {
+      SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, Op0,
+                               DAG.getConstant(0, DL, MVT::i32));
+      SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, Op0,
+                               DAG.getConstant(1, DL, MVT::i32));
+      SDValue RetReg =
+          DAG.getNode(RISCVISD::BuildPairF64, DL, MVT::f64, Lo, Hi);
+      return RetReg;
+    }
 
     // Consider other scalar<->scalar casts as legal if the types are legal.
     // Otherwise expand them.
@@ -8040,6 +8066,13 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
       SDValue FPConv =
           DAG.getNode(RISCVISD::FMV_X_ANYEXTW_RV64, DL, MVT::i64, Op0);
       Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, FPConv));
+    } else if (VT == MVT::i64 && Op0VT == MVT::f64 && XLenVT == MVT::i32 &&
+               Subtarget.hasStdExtZfa()) {
+      SDValue NewReg = DAG.getNode(RISCVISD::SplitF64, DL,
+                                   DAG.getVTList(MVT::i32, MVT::i32), Op0);
+      SDValue RetReg = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64,
+                                   NewReg.getValue(0), NewReg.getValue(1));
+      Results.push_back(RetReg);
     } else if (!VT.isVector() && Op0VT.isFixedLengthVector() &&
                isTypeLegal(Op0VT)) {
       // Custom-legalize bitcasts from fixed-length vector types to illegal
@@ -11144,7 +11177,8 @@ static MachineBasicBlock *emitReadCycleWidePseudo(MachineInstr &MI,
 }
 
 static MachineBasicBlock *emitSplitF64Pseudo(MachineInstr &MI,
-                                             MachineBasicBlock *BB) {
+                                             MachineBasicBlock *BB,
+                                             const RISCVSubtarget &Subtarget) {
   assert(MI.getOpcode() == RISCV::SplitF64Pseudo && "Unexpected instruction");
 
   MachineFunction &MF = *BB->getParent();
@@ -11154,6 +11188,14 @@ static MachineBasicBlock *emitSplitF64Pseudo(MachineInstr &MI,
   Register LoReg = MI.getOperand(0).getReg();
   Register HiReg = MI.getOperand(1).getReg();
   Register SrcReg = MI.getOperand(2).getReg();
+  if (Subtarget.hasStdExtD() && Subtarget.hasStdExtZfa() &&
+      !Subtarget.is64Bit()) {
+    BuildMI(*BB, MI, DL, TII.get(RISCV::FMV_X_W_FPR64), LoReg).addReg(SrcReg);
+    BuildMI(*BB, MI, DL, TII.get(RISCV::FMVH_X_D), HiReg).addReg(SrcReg);
+    MI.eraseFromParent(); // The pseudo instruction is gone now.
+    return BB;
+  }
+
   const TargetRegisterClass *SrcRC = &RISCV::FPR64RegClass;
   int FI = MF.getInfo<RISCVMachineFunctionInfo>()->getMoveF64FrameIndex(MF);
 
@@ -11177,7 +11219,8 @@ static MachineBasicBlock *emitSplitF64Pseudo(MachineInstr &MI,
 }
 
 static MachineBasicBlock *emitBuildPairF64Pseudo(MachineInstr &MI,
-                                                 MachineBasicBlock *BB) {
+                                                 MachineBasicBlock *BB,
+                                                 const RISCVSubtarget &Subtarget) {
   assert(MI.getOpcode() == RISCV::BuildPairF64Pseudo &&
          "Unexpected instruction");
 
@@ -11188,6 +11231,15 @@ static MachineBasicBlock *emitBuildPairF64Pseudo(MachineInstr &MI,
   Register DstReg = MI.getOperand(0).getReg();
   Register LoReg = MI.getOperand(1).getReg();
   Register HiReg = MI.getOperand(2).getReg();
+  if (Subtarget.hasStdExtD() && Subtarget.hasStdExtZfa() &&
+      !Subtarget.is64Bit()) {
+    BuildMI(*BB, MI, DL, TII.get(RISCV::FMVP_D_X), DstReg)
+        .addReg(LoReg)
+        .addReg(HiReg);
+    MI.eraseFromParent();
+    return BB;
+  }
+
   const TargetRegisterClass *DstRC = &RISCV::FPR64RegClass;
   int FI = MF.getInfo<RISCVMachineFunctionInfo>()->getMoveF64FrameIndex(MF);
 
@@ -11703,9 +11755,9 @@ RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
   case RISCV::Select_FPR64_Using_CC_GPR:
     return emitSelectPseudo(MI, BB, Subtarget);
   case RISCV::BuildPairF64Pseudo:
-    return emitBuildPairF64Pseudo(MI, BB);
+    return emitBuildPairF64Pseudo(MI, BB, Subtarget);
   case RISCV::SplitF64Pseudo:
-    return emitSplitF64Pseudo(MI, BB);
+    return emitSplitF64Pseudo(MI, BB, Subtarget);
   case RISCV::PseudoQuietFLE_H:
     return emitQuietFCMP(MI, BB, RISCV::FLE_H, RISCV::FEQ_H, Subtarget);
   case RISCV::PseudoQuietFLT_H:

diff  --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZfa.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZfa.td
index 91132516d7992..609a8662ff8f3 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZfa.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZfa.td
@@ -85,6 +85,10 @@ 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]>;
+let isCodeGenOnly = 1, mayRaiseFPException = 0 in
+def FMV_X_W_FPR64 : FPUnaryOp_r<0b1110000, 0b00000, 0b000, GPR, FPR64,
+                                "fmv.x.w">,
+                    Sched<[WriteFMovF32ToI32, ReadFMovF32ToI32]>;
 } // Predicates = [HasStdExtZfa, HasStdExtD, IsRV32]
 
 let Predicates = [HasStdExtZfa, HasStdExtZfh] in {
@@ -97,3 +101,76 @@ 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]
+
+
+//===----------------------------------------------------------------------===//
+// Codegen patterns
+//===----------------------------------------------------------------------===//
+
+let Predicates = [HasStdExtZfa] in {
+def: PatFprFpr<fminimum, FMINM_S, FPR32>;
+def: PatFprFpr<fmaximum, FMAXM_S, FPR32>;
+
+// frint rounds according to the current rounding mode and detects
+// inexact conditions.
+def: Pat<(any_frint FPR32 : $rs1), (FROUNDNX_S FPR32 : $rs1, 0b111)>;
+
+// fnearbyint is like frint but does not detect inexact conditions.
+def: Pat<(any_fnearbyint FPR32 : $rs1), (FROUND_S FPR32 : $rs1, 0b111)>;
+
+def: Pat<(any_fround FPR32 : $rs1), (FROUND_S FPR32 : $rs1, 0b100)>;
+def: Pat<(any_ffloor FPR32 : $rs1), (FROUND_S FPR32 : $rs1, 0b011)>;
+def: Pat<(any_fceil FPR32 : $rs1), (FROUND_S FPR32 : $rs1, 0b010)>;
+def: Pat<(any_ftrunc FPR32 : $rs1), (FROUND_S FPR32 : $rs1, 0b001)>;
+
+def: PatSetCC<FPR32, strict_fsetcc, SETLT, FLTQ_S>;
+def: PatSetCC<FPR32, strict_fsetcc, SETOLT, FLTQ_S>;
+def: PatSetCC<FPR32, strict_fsetcc, SETLE, FLEQ_S>;
+def: PatSetCC<FPR32, strict_fsetcc, SETOLE, FLEQ_S>;
+} // Predicates = [HasStdExtZfa]
+
+let Predicates = [HasStdExtZfa, HasStdExtD] in {
+def: PatFprFpr<fminimum, FMINM_D, FPR64>;
+def: PatFprFpr<fmaximum, FMAXM_D, FPR64>;
+
+// frint rounds according to the current rounding mode and detects
+// inexact conditions.
+def: Pat<(any_frint FPR64 : $rs1), (FROUNDNX_D FPR64 : $rs1, 0b111)>;
+
+// fnearbyint is like frint but does not detect inexact conditions.
+def: Pat<(any_fnearbyint FPR64 : $rs1), (FROUND_D FPR64 : $rs1, 0b111)>;
+
+def: Pat<(any_fround FPR64 : $rs1), (FROUND_D FPR64 : $rs1, 0b100)>;
+def: Pat<(any_froundeven FPR64 : $rs1), (FROUND_D FPR64 : $rs1, 0b000)>;
+def: Pat<(any_ffloor FPR64 : $rs1), (FROUND_D FPR64 : $rs1, 0b011)>;
+def: Pat<(any_fceil FPR64 : $rs1), (FROUND_D FPR64 : $rs1, 0b010)>;
+def: Pat<(any_ftrunc FPR64 : $rs1), (FROUND_D FPR64 : $rs1, 0b001)>;
+
+def: PatSetCC<FPR64, strict_fsetcc, SETLT, FLTQ_D>;
+def: PatSetCC<FPR64, strict_fsetcc, SETOLT, FLTQ_D>;
+def: PatSetCC<FPR64, strict_fsetcc, SETLE, FLEQ_D>;
+def: PatSetCC<FPR64, strict_fsetcc, SETOLE, FLEQ_D>;
+} // Predicates = [HasStdExtZfa, HasStdExtD]
+
+let Predicates = [HasStdExtZfa, HasStdExtZfh] in {
+def: PatFprFpr<fminimum, FMINM_H, FPR16>;
+def: PatFprFpr<fmaximum, FMAXM_H, FPR16>;
+
+// frint rounds according to the current rounding mode and detects
+// inexact conditions.
+def: Pat<(any_frint FPR16 : $rs1), (FROUNDNX_H FPR16 : $rs1, 0b111)>;
+
+// fnearbyint is like frint but does not detect inexact conditions.
+def: Pat<(any_fnearbyint FPR16 : $rs1), (FROUND_H FPR16 : $rs1, 0b111)>;
+
+def: Pat<(any_fround FPR16 : $rs1), (FROUND_H FPR16 : $rs1, 0b100)>;
+def: Pat<(any_froundeven FPR16 : $rs1), (FROUND_H FPR16 : $rs1, 0b000)>;
+def: Pat<(any_ffloor FPR16 : $rs1), (FROUND_H FPR16 : $rs1, 0b011)>;
+def: Pat<(any_fceil FPR16 : $rs1), (FROUND_H FPR16 : $rs1, 0b010)>;
+def: Pat<(any_ftrunc FPR16 : $rs1), (FROUND_H FPR16 : $rs1, 0b001)>;
+
+def: PatSetCC<FPR16, strict_fsetcc, SETLT, FLTQ_H>;
+def: PatSetCC<FPR16, strict_fsetcc, SETOLT, FLTQ_H>;
+def: PatSetCC<FPR16, strict_fsetcc, SETLE, FLEQ_H>;
+def: PatSetCC<FPR16, strict_fsetcc, SETOLE, FLEQ_H>;
+} // Predicates = [HasStdExtZfa, HasStdExtZfh]

diff  --git a/llvm/test/CodeGen/RISCV/double-zfa.ll b/llvm/test/CodeGen/RISCV/double-zfa.ll
new file mode 100644
index 0000000000000..83fb00d7e1306
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/double-zfa.ll
@@ -0,0 +1,149 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -target-abi ilp32d -mattr=+experimental-zfa,+d < %s \
+; RUN:     | FileCheck --check-prefixes=CHECK,RV32IDZFA %s
+; RUN: llc -mtriple=riscv64 -target-abi lp64d -mattr=+experimental-zfa,+d < %s \
+; RUN:     | FileCheck --check-prefixes=CHECK,RV64DZFA %s
+
+declare double @llvm.minimum.f64(double, double)
+
+define double @fminm_d(double %a, double %b) nounwind {
+; CHECK-LABEL: fminm_d:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fminm.d fa0, fa0, fa1
+; CHECK-NEXT:    ret
+  %1 = call double @llvm.minimum.f64(double %a, double %b)
+  ret double %1
+}
+
+declare double @llvm.maximum.f64(double, double)
+
+define double @fmaxm_d(double %a, double %b) nounwind {
+; CHECK-LABEL: fmaxm_d:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fmaxm.d fa0, fa0, fa1
+; CHECK-NEXT:    ret
+  %1 = call double @llvm.maximum.f64(double %a, double %b)
+  ret double %1
+}
+
+define double @fround_d_1(double %a) nounwind {
+; CHECK-LABEL: fround_d_1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.d fa0, fa0, rmm
+; CHECK-NEXT:    ret
+  %call = tail call double @round(double %a) nounwind readnone
+  ret double %call
+}
+
+declare double @round(double) nounwind readnone
+
+
+define double @fround_d_2(double %a) nounwind {
+; CHECK-LABEL: fround_d_2:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.d fa0, fa0, rup
+; CHECK-NEXT:    ret
+  %call = tail call double @floor(double %a) nounwind readnone
+  ret double %call
+}
+
+declare double @floor(double) nounwind readnone
+
+
+define double @fround_d_3(double %a) nounwind {
+; CHECK-LABEL: fround_d_3:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.d fa0, fa0, rdn
+; CHECK-NEXT:    ret
+  %call = tail call double @ceil(double %a) nounwind readnone
+  ret double %call
+}
+
+declare double @ceil(double) nounwind readnone
+
+
+define double @fround_d_4(double %a) nounwind {
+; CHECK-LABEL: fround_d_4:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.d fa0, fa0, rtz
+; CHECK-NEXT:    ret
+  %call = tail call double @trunc(double %a) nounwind readnone
+  ret double %call
+}
+
+declare double @trunc(double) nounwind readnone
+
+
+define double @fround_d_5(double %a) nounwind {
+; CHECK-LABEL: fround_d_5:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.d fa0, fa0
+; CHECK-NEXT:    ret
+  %call = tail call double @nearbyint(double %a) nounwind readnone
+  ret double %call
+}
+
+declare double @nearbyint(double) nounwind readnone
+
+
+define double @froundnx_d(double %a) nounwind {
+; CHECK-LABEL: froundnx_d:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    froundnx.d fa0, fa0
+; CHECK-NEXT:    ret
+  %call = tail call double @rint(double %a) nounwind readnone
+  ret double %call
+}
+
+declare double @rint(double) nounwind readnone
+
+declare i1 @llvm.experimental.constrained.fcmp.f64(double, double, metadata, metadata)
+
+define i32 @fcmp_olt_q(double %a, double %b) nounwind strictfp {
+; CHECK-LABEL: fcmp_olt_q:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fltq.d a0, fa0, fa1
+; CHECK-NEXT:    ret
+  %1 = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"olt", metadata !"fpexcept.strict") strictfp
+  %2 = zext i1 %1 to i32
+  ret i32 %2
+}
+
+define i32 @fcmp_ole_q(double %a, double %b) nounwind strictfp {
+; CHECK-LABEL: fcmp_ole_q:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fleq.d a0, fa0, fa1
+; CHECK-NEXT:    ret
+  %1 = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"ole", metadata !"fpexcept.strict") strictfp
+  %2 = zext i1 %1 to i32
+  ret i32 %2
+}
+
+define i64 @fmvh_x_d(double %fa) {
+; RV32IDZFA-LABEL: fmvh_x_d:
+; RV32IDZFA:       # %bb.0:
+; RV32IDZFA-NEXT:    fmv.x.w a0, fa0
+; RV32IDZFA-NEXT:    fmvh.x.d a1, fa0
+; RV32IDZFA-NEXT:    ret
+;
+; RV64DZFA-LABEL: fmvh_x_d:
+; RV64DZFA:       # %bb.0:
+; RV64DZFA-NEXT:    fmv.x.d a0, fa0
+; RV64DZFA-NEXT:    ret
+  %i = bitcast double %fa to i64
+  ret i64 %i
+}
+
+define double @fmvp_d_x(i64 %a) {
+; RV32IDZFA-LABEL: fmvp_d_x:
+; RV32IDZFA:       # %bb.0:
+; RV32IDZFA-NEXT:    fmvp.d.x fa0, a0, a1
+; RV32IDZFA-NEXT:    ret
+;
+; RV64DZFA-LABEL: fmvp_d_x:
+; RV64DZFA:       # %bb.0:
+; RV64DZFA-NEXT:    fmv.d.x fa0, a0
+; RV64DZFA-NEXT:    ret
+  %or = bitcast i64 %a to double
+  ret double %or
+}

diff  --git a/llvm/test/CodeGen/RISCV/float-zfa.ll b/llvm/test/CodeGen/RISCV/float-zfa.ll
new file mode 100644
index 0000000000000..017264b16f25a
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/float-zfa.ll
@@ -0,0 +1,121 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -target-abi ilp32f -mattr=+experimental-zfa < %s \
+; RUN:     | FileCheck %s
+; RUN: llc -mtriple=riscv64 -target-abi lp64f -mattr=+experimental-zfa < %s \
+; RUN:     | FileCheck %s
+
+declare float @llvm.minimum.f32(float, float)
+
+define float @fminm_s(float %a, float %b) nounwind {
+; CHECK-LABEL: fminm_s:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fminm.s fa0, fa0, fa1
+; CHECK-NEXT:    ret
+  %1 = call float @llvm.minimum.f32(float %a, float %b)
+  ret float %1
+}
+
+declare float @llvm.maximum.f32(float, float)
+
+define float @fmaxm_s(float %a, float %b) nounwind {
+; CHECK-LABEL: fmaxm_s:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fmaxm.s fa0, fa0, fa1
+; CHECK-NEXT:    ret
+  %1 = call float @llvm.maximum.f32(float %a, float %b)
+  ret float %1
+}
+
+
+define float @fround_s_1(float %a) nounwind {
+; CHECK-LABEL: fround_s_1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.s fa0, fa0, rmm
+; CHECK-NEXT:    ret
+  %call = tail call float @roundf(float %a) nounwind readnone
+  ret float %call
+}
+
+declare float @roundf(float) nounwind readnone
+
+
+define float @fround_s_2(float %a) nounwind {
+; CHECK-LABEL: fround_s_2:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.s fa0, fa0, rup
+; CHECK-NEXT:    ret
+  %call = tail call float @floorf(float %a) nounwind readnone
+  ret float %call
+}
+
+declare float @floorf(float) nounwind readnone
+
+
+define float @fround_s_3(float %a) nounwind {
+; CHECK-LABEL: fround_s_3:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.s fa0, fa0, rdn
+; CHECK-NEXT:    ret
+  %call = tail call float @ceilf(float %a) nounwind readnone
+  ret float %call
+}
+
+declare float @ceilf(float) nounwind readnone
+
+
+define float @fround_s_4(float %a) nounwind {
+; CHECK-LABEL: fround_s_4:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.s fa0, fa0, rtz
+; CHECK-NEXT:    ret
+  %call = tail call float @truncf(float %a) nounwind readnone
+  ret float %call
+}
+
+declare float @truncf(float) nounwind readnone
+
+
+define float @fround_s_5(float %a) nounwind {
+; CHECK-LABEL: fround_s_5:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.s fa0, fa0
+; CHECK-NEXT:    ret
+  %call = tail call float @nearbyintf(float %a) nounwind readnone
+  ret float %call
+}
+
+declare float @nearbyintf(float) nounwind readnone
+
+
+define float @froundnx_s(float %a) nounwind {
+; CHECK-LABEL: froundnx_s:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    froundnx.s fa0, fa0
+; CHECK-NEXT:    ret
+  %call = tail call float @rintf(float %a) nounwind readnone
+  ret float %call
+}
+
+declare float @rintf(float) nounwind readnone
+
+declare i1 @llvm.experimental.constrained.fcmp.f32(float, float, metadata, metadata)
+
+define i32 @fcmp_olt_q(float %a, float %b) nounwind strictfp {
+; CHECK-LABEL: fcmp_olt_q:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fltq.s a0, fa0, fa1
+; CHECK-NEXT:    ret
+  %1 = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"olt", metadata !"fpexcept.strict") strictfp
+  %2 = zext i1 %1 to i32
+  ret i32 %2
+}
+
+define i32 @fcmp_ole_q(float %a, float %b) nounwind strictfp {
+; CHECK-LABEL: fcmp_ole_q:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fleq.s a0, fa0, fa1
+; CHECK-NEXT:    ret
+  %1 = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"ole", metadata !"fpexcept.strict") strictfp
+  %2 = zext i1 %1 to i32
+  ret i32 %2
+}

diff  --git a/llvm/test/CodeGen/RISCV/half-zfa.ll b/llvm/test/CodeGen/RISCV/half-zfa.ll
new file mode 100644
index 0000000000000..98dcf1f13c114
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/half-zfa.ll
@@ -0,0 +1,120 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -target-abi ilp32f -mattr=+experimental-zfa,+zfh < %s \
+; RUN:     | FileCheck %s
+; RUN: llc -mtriple=riscv64 -target-abi lp64f -mattr=+experimental-zfa,+zfh < %s \
+; RUN:     | FileCheck %s
+
+declare half @llvm.minimum.f16(half, half)
+
+define half @fminm_h(half %a, half %b) nounwind {
+; CHECK-LABEL: fminm_h:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fminm.h fa0, fa0, fa1
+; CHECK-NEXT:    ret
+  %1 = call half @llvm.minimum.f16(half %a, half %b)
+  ret half %1
+}
+
+declare half @llvm.maximum.f16(half, half)
+
+define half @fmaxm_h(half %a, half %b) nounwind {
+; CHECK-LABEL: fmaxm_h:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fmaxm.h fa0, fa0, fa1
+; CHECK-NEXT:    ret
+  %1 = tail call half @llvm.maximum.f16(half %a, half %b)
+  ret half %1
+}
+
+define half @fround_h_1(half %a) nounwind {
+; CHECK-LABEL: fround_h_1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.h fa0, fa0, rmm
+; CHECK-NEXT:    ret
+  %call = tail call half @llvm.round.f16(half %a) nounwind readnone
+  ret half %call
+}
+
+declare half @llvm.round.f16(half) nounwind readnone
+
+
+define half @fround_h_2(half %a) nounwind {
+; CHECK-LABEL: fround_h_2:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.h fa0, fa0, rup
+; CHECK-NEXT:    ret
+  %call = tail call half @llvm.floor.f16(half %a) nounwind readnone
+  ret half %call
+}
+
+declare half @llvm.floor.f16(half) nounwind readnone
+
+
+define half @fround_h_3(half %a) nounwind {
+; CHECK-LABEL: fround_h_3:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.h fa0, fa0, rdn
+; CHECK-NEXT:    ret
+  %call = tail call half @llvm.ceil.f16(half %a) nounwind readnone
+  ret half %call
+}
+
+declare half @llvm.ceil.f16(half) nounwind readnone
+
+
+define half @fround_h_4(half %a) nounwind {
+; CHECK-LABEL: fround_h_4:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.h fa0, fa0, rtz
+; CHECK-NEXT:    ret
+  %call = tail call half @llvm.trunc.f16(half %a) nounwind readnone
+  ret half %call
+}
+
+declare half @llvm.trunc.f16(half) nounwind readnone
+
+
+define half @fround_h_5(half %a) nounwind {
+; CHECK-LABEL: fround_h_5:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fround.h fa0, fa0
+; CHECK-NEXT:    ret
+  %call = tail call half @llvm.nearbyint.f16(half %a) nounwind readnone
+  ret half %call
+}
+
+declare half @llvm.nearbyint.f16(half) nounwind readnone
+
+
+define half @froundnx_h(half %a) nounwind {
+; CHECK-LABEL: froundnx_h:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    froundnx.h fa0, fa0
+; CHECK-NEXT:    ret
+  %call = tail call half @llvm.rint.f16(half %a) nounwind readnone
+  ret half %call
+}
+
+declare half @llvm.rint.f16(half) nounwind readnone
+
+declare i1 @llvm.experimental.constrained.fcmp.f16(half, half, metadata, metadata)
+
+define i32 @fcmp_olt_q(half %a, half %b) nounwind strictfp {
+; CHECK-LABEL: fcmp_olt_q:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fltq.h a0, fa0, fa1
+; CHECK-NEXT:    ret
+  %1 = call i1 @llvm.experimental.constrained.fcmp.f16(half %a, half %b, metadata !"olt", metadata !"fpexcept.strict") strictfp
+  %2 = zext i1 %1 to i32
+  ret i32 %2
+}
+
+define i32 @fcmp_ole_q(half %a, half %b) nounwind strictfp {
+; CHECK-LABEL: fcmp_ole_q:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fleq.h a0, fa0, fa1
+; CHECK-NEXT:    ret
+  %1 = call i1 @llvm.experimental.constrained.fcmp.f16(half %a, half %b, metadata !"ole", metadata !"fpexcept.strict") strictfp
+  %2 = zext i1 %1 to i32
+  ret i32 %2
+}


        


More information about the llvm-commits mailing list