diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -92,6 +92,8 @@ addRegisterClass(MVT::f32, &RISCV::FPR32RegClass); if (Subtarget.hasStdExtD()) addRegisterClass(MVT::f64, &RISCV::FPR64RegClass); + if (Subtarget.hasStdExtZfinx()) + addRegisterClass(MVT::f32, &RISCV::GPRF32RegClass); static const MVT::SimpleValueType BoolVecVTs[] = { MVT::nxv1i1, MVT::nxv2i1, MVT::nxv4i1, MVT::nxv8i1, @@ -379,7 +381,7 @@ setOperationAction(ISD::FPOWI, MVT::i32, Custom); } - if (Subtarget.hasStdExtF()) { + if (Subtarget.hasStdExtF() || Subtarget.hasStdExtZfinx()) { for (auto NT : FPLegalNodeTypes) setOperationAction(NT, MVT::f32, Legal); for (auto CC : FPCCToExpand) @@ -1340,7 +1342,7 @@ // FIXME: Change to Zfhmin once f16 becomes a legal type with Zfhmin. if (VT == MVT::f16 && !Subtarget.hasStdExtZfh()) return false; - if (VT == MVT::f32 && !Subtarget.hasStdExtF()) + if (VT == MVT::f32 && !Subtarget.hasStdExtF() && !Subtarget.hasStdExtZfinx()) return false; if (VT == MVT::f64 && !Subtarget.hasStdExtD()) return false; @@ -1349,7 +1351,8 @@ bool RISCVTargetLowering::hasBitPreservingFPLogic(EVT VT) const { return (VT == MVT::f16 && Subtarget.hasStdExtZfh()) || - (VT == MVT::f32 && Subtarget.hasStdExtF()) || + (VT == MVT::f32 && + (Subtarget.hasStdExtF() || Subtarget.hasStdExtZfinx())) || (VT == MVT::f64 && Subtarget.hasStdExtD()); } @@ -11479,7 +11482,7 @@ case MVT::f16: return Subtarget.hasStdExtZfh(); case MVT::f32: - return Subtarget.hasStdExtF(); + return Subtarget.hasStdExtF() || Subtarget.hasStdExtZfinx(); case MVT::f64: return Subtarget.hasStdExtD(); default: diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td @@ -461,22 +461,50 @@ def fpimmneg0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(-0.0); }]>; /// Generic pattern classes -class PatSetCC +class PatSetCC : Pat<(OpNode Ty:$rs1, Ty:$rs2, Cond), (Inst $rs1, $rs2)>; +multiclass PatSetCC_m Exts> { + foreach Ext = Exts in + let Predicates = Ext.Predicates in + def Ext.Suffix : PatSetCC(Inst#Ext.Suffix)>; +} class PatFprFpr + DAGOperand RegTy> : Pat<(OpNode RegTy:$rs1, RegTy:$rs2), (Inst $rs1, $rs2)>; +multiclass PatFprFpr_m Exts> { + foreach Ext = Exts in + let Predicates = Ext.Predicates in + def Ext.Suffix : PatFprFpr(Inst#Ext.Suffix), + Ext.Reg>; +} class PatFprFprDynFrm + DAGOperand RegTy> : Pat<(OpNode RegTy:$rs1, RegTy:$rs2), (Inst $rs1, $rs2, 0b111)>; +multiclass PatFprFprDynFrm_m Exts> { + foreach Ext = Exts in + let Predicates = Ext.Predicates in + def Ext.Suffix : PatFprFprDynFrm(Inst#Ext.Suffix), + Ext.Reg>; +} let Predicates = [HasStdExtF] in { - /// Float constants def : Pat<(f32 (fpimm0)), (FMV_W_X X0)>; def : Pat<(f32 (fpimmneg0)), (FSGNJN_S (FMV_W_X X0), (FMV_W_X X0))>; +} // Predicates = [HasStdExtF] + +let Predicates = [HasStdExtZfinx] in { +def : Pat<(f32 (fpimm0)), (COPY (f32 X0))>; +def : Pat<(f32 (fpimmneg0)), (FSGNJN_S_INX (COPY (f32 X0)), (COPY (f32 X0)))>; +} // Predicates = [HasStdExtZfinx] /// Float conversion operations @@ -484,18 +512,28 @@ // are defined later. /// Float arithmetic operations +defm : PatFprFprDynFrm_m; +defm : PatFprFprDynFrm_m; +defm : PatFprFprDynFrm_m; +defm : PatFprFprDynFrm_m; -def : PatFprFprDynFrm; -def : PatFprFprDynFrm; -def : PatFprFprDynFrm; -def : PatFprFprDynFrm; - +let Predicates = [HasStdExtF] in { def : Pat<(any_fsqrt FPR32:$rs1), (FSQRT_S FPR32:$rs1, 0b111)>; def : Pat<(fneg FPR32:$rs1), (FSGNJN_S $rs1, $rs1)>; def : Pat<(fabs FPR32:$rs1), (FSGNJX_S $rs1, $rs1)>; +} // Predicates = [HasStdExtF] + +let Predicates = [HasStdExtZfinx] in { +def : Pat<(any_fsqrt FPR32INX:$rs1), (FSQRT_S_INX FPR32INX:$rs1, 0b111)>; + +def : Pat<(fneg FPR32INX:$rs1), (FSGNJN_S_INX $rs1, $rs1)>; +def : Pat<(fabs FPR32INX:$rs1), (FSGNJX_S_INX $rs1, $rs1)>; +} // Predicates = [HasStdExtZfinx] + +defm : PatFprFpr_m; -def : PatFprFpr; +let Predicates = [HasStdExtF] in { def : Pat<(fcopysign FPR32:$rs1, (fneg FPR32:$rs2)), (FSGNJN_S $rs1, $rs2)>; // fmadd: rs1 * rs2 + rs3 @@ -513,20 +551,42 @@ // fnmadd: -rs1 * rs2 - rs3 def : Pat<(any_fma (fneg FPR32:$rs1), FPR32:$rs2, (fneg FPR32:$rs3)), (FNMADD_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, 0b111)>; +} // Predicates = [HasStdExtF] + +let Predicates = [HasStdExtZfinx] in { +def : Pat<(fcopysign FPR32INX:$rs1, (fneg FPR32INX:$rs2)), (FSGNJN_S_INX $rs1, $rs2)>; + +// fmadd: rs1 * rs2 + rs3 +def : Pat<(any_fma FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3), + (FMADD_S_INX $rs1, $rs2, $rs3, 0b111)>; + +// fmsub: rs1 * rs2 - rs3 +def : Pat<(any_fma FPR32INX:$rs1, FPR32INX:$rs2, (fneg FPR32INX:$rs3)), + (FMSUB_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, 0b111)>; + +// fnmsub: -rs1 * rs2 + rs3 +def : Pat<(any_fma (fneg FPR32INX:$rs1), FPR32INX:$rs2, FPR32INX:$rs3), + (FNMSUB_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, 0b111)>; + +// fnmadd: -rs1 * rs2 - rs3 +def : Pat<(any_fma (fneg FPR32INX:$rs1), FPR32INX:$rs2, (fneg FPR32INX:$rs3)), + (FNMADD_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, 0b111)>; +} // Predicates = [HasStdExtZfinx] // The ratified 20191213 ISA spec defines fmin and fmax in a way that matches // LLVM's fminnum and fmaxnum // . -def : PatFprFpr; -def : PatFprFpr; +defm : PatFprFpr_m; +defm : PatFprFpr_m; /// Setcc // FIXME: SETEQ/SETLT/SETLE imply nonans, can we pick better instructions for // strict versions of those. // Match non-signaling FEQ_S -def : PatSetCC; -def : PatSetCC; +defm : PatSetCC_m; +defm : PatSetCC_m; +let Predicates = [HasStdExtF] in { def : PatSetCC; def : PatSetCC; def : PatSetCC; @@ -566,7 +626,15 @@ // Moves (no conversion) def : Pat<(bitconvert (i32 GPR:$rs1)), (FMV_W_X GPR:$rs1)>; def : Pat<(i32 (bitconvert FPR32:$rs1)), (FMV_X_W FPR32:$rs1)>; +} // Predicates = [HasStdExtF, IsRV32] +let Predicates = [HasStdExtZfinx, IsRV32] in { +// Moves (no conversion) +def : Pat<(f32 (bitconvert (i32 GPR:$rs1))), (COPY GPR:$rs1)>; +def : Pat<(i32 (bitconvert FPR32INX:$rs1)), (COPY FPR32INX:$rs1)>; +} // Predicates = [HasStdExtZfinx, IsRV32] + +let Predicates = [HasStdExtF, IsRV32] in { // float->[u]int. Round-to-zero must be used. def : Pat<(i32 (any_fp_to_sint FPR32:$rs1)), (FCVT_W_S $rs1, 0b001)>; def : Pat<(i32 (any_fp_to_uint FPR32:$rs1)), (FCVT_WU_S $rs1, 0b001)>; diff --git a/llvm/test/CodeGen/RISCV/float-arith.ll b/llvm/test/CodeGen/RISCV/float-arith.ll --- a/llvm/test/CodeGen/RISCV/float-arith.ll +++ b/llvm/test/CodeGen/RISCV/float-arith.ll @@ -3,6 +3,8 @@ ; RUN: -target-abi=ilp32f | FileCheck -check-prefix=RV32IF %s ; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s \ ; RUN: -target-abi=lp64f | FileCheck -check-prefix=RV64IF %s +; RUN: llc -mtriple=riscv32 -mattr=+zfinx -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32IZFINX %s ; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ ; RUN: | FileCheck -check-prefix=RV32I %s ; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ @@ -24,6 +26,11 @@ ; RV64IF-NEXT: fadd.s fa0, fa0, fa1 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fadd_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fadd.s a0, a0, a1 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fadd_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -56,6 +63,11 @@ ; RV64IF-NEXT: fsub.s fa0, fa0, fa1 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fsub_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fsub.s a0, a0, a1 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fsub_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -88,6 +100,11 @@ ; RV64IF-NEXT: fmul.s fa0, fa0, fa1 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fmul_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fmul.s a0, a0, a1 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fmul_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -120,6 +137,11 @@ ; RV64IF-NEXT: fdiv.s fa0, fa0, fa1 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fdiv_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fdiv.s a0, a0, a1 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fdiv_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -154,6 +176,11 @@ ; RV64IF-NEXT: fsqrt.s fa0, fa0 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fsqrt_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fsqrt.s a0, a0 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fsqrt_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -188,6 +215,11 @@ ; RV64IF-NEXT: fsgnj.s fa0, fa0, fa1 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fsgnj_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fsgnj.s a0, a0, a1 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fsgnj_s: ; RV32I: # %bb.0: ; RV32I-NEXT: lui a2, 524288 @@ -226,6 +258,13 @@ ; RV64IF-NEXT: feq.s a0, ft0, ft1 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fneg_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fadd.s a0, a0, a0 +; RV32IZFINX-NEXT: fneg.s a1, a0 +; RV32IZFINX-NEXT: feq.s a0, a0, a1 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fneg_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -275,6 +314,12 @@ ; RV64IF-NEXT: fsgnjn.s fa0, fa0, ft0 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fsgnjn_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fadd.s a1, a0, a1 +; RV32IZFINX-NEXT: fsgnjn.s a0, a0, a1 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fsgnjn_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -335,6 +380,13 @@ ; RV64IF-NEXT: fadd.s fa0, ft1, ft0 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fabs_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fadd.s a0, a0, a1 +; RV32IZFINX-NEXT: fabs.s a1, a0 +; RV32IZFINX-NEXT: fadd.s a0, a1, a0 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fabs_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -379,6 +431,11 @@ ; RV64IF-NEXT: fmin.s fa0, fa0, fa1 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fmin_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fmin.s a0, a0, a1 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fmin_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -413,6 +470,11 @@ ; RV64IF-NEXT: fmax.s fa0, fa0, fa1 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fmax_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fmax.s a0, a0, a1 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fmax_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -447,6 +509,11 @@ ; RV64IF-NEXT: fmadd.s fa0, fa0, fa1, fa2 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fmadd_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fmadd.s a0, a0, a1, a2 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fmadd_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -483,6 +550,12 @@ ; RV64IF-NEXT: fmsub.s fa0, fa0, fa1, ft0 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fmsub_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fadd.s a2, a2, zero +; RV32IZFINX-NEXT: fmsub.s a0, a0, a1, a2 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fmsub_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -549,6 +622,13 @@ ; RV64IF-NEXT: fnmadd.s fa0, ft1, fa1, ft0 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fnmadd_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fadd.s a0, a0, zero +; RV32IZFINX-NEXT: fadd.s a2, a2, zero +; RV32IZFINX-NEXT: fnmadd.s a0, a0, a1, a2 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fnmadd_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -629,6 +709,13 @@ ; RV64IF-NEXT: fnmadd.s fa0, ft1, fa0, ft0 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fnmadd_s_2: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fadd.s a1, a1, zero +; RV32IZFINX-NEXT: fadd.s a2, a2, zero +; RV32IZFINX-NEXT: fnmadd.s a0, a1, a0, a2 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fnmadd_s_2: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -707,6 +794,12 @@ ; RV64IF-NEXT: fnmsub.s fa0, ft0, fa1, fa2 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fnmsub_s: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fadd.s a0, a0, zero +; RV32IZFINX-NEXT: fnmsub.s a0, a0, a1, a2 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fnmsub_s: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -769,6 +862,12 @@ ; RV64IF-NEXT: fnmsub.s fa0, ft0, fa0, fa2 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fnmsub_s_2: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fadd.s a1, a1, zero +; RV32IZFINX-NEXT: fnmsub.s a0, a1, a0, a2 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fnmsub_s_2: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -829,6 +928,11 @@ ; RV64IF-NEXT: fmadd.s fa0, fa0, fa1, fa2 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fmadd_s_contract: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fmadd.s a0, a0, a1, a2 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fmadd_s_contract: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -876,6 +980,12 @@ ; RV64IF-NEXT: fmsub.s fa0, fa0, fa1, ft0 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fmsub_s_contract: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fadd.s a2, a2, zero +; RV32IZFINX-NEXT: fmsub.s a0, a0, a1, a2 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fmsub_s_contract: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -950,6 +1060,14 @@ ; RV64IF-NEXT: fnmadd.s fa0, ft1, ft2, ft0 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fnmadd_s_contract: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fadd.s a0, a0, zero +; RV32IZFINX-NEXT: fadd.s a1, a1, zero +; RV32IZFINX-NEXT: fadd.s a2, a2, zero +; RV32IZFINX-NEXT: fnmadd.s a0, a0, a1, a2 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fnmadd_s_contract: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16 @@ -1043,6 +1161,13 @@ ; RV64IF-NEXT: fnmsub.s fa0, ft1, ft0, fa2 ; RV64IF-NEXT: ret ; +; RV32IZFINX-LABEL: fnmsub_s_contract: +; RV32IZFINX: # %bb.0: +; RV32IZFINX-NEXT: fadd.s a0, a0, zero +; RV32IZFINX-NEXT: fadd.s a1, a1, zero +; RV32IZFINX-NEXT: fnmsub.s a0, a0, a1, a2 +; RV32IZFINX-NEXT: ret +; ; RV32I-LABEL: fnmsub_s_contract: ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -16