diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 766616766b94..f91f0bb63ceb 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -6159,6 +6159,19 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op, Known.KnownFPClasses &= ~AssertedClasses; break; } + case ISD::SELECT: + case ISD::VSELECT: { + // TODO: Add adjustKnownFPClassForSelectArm clamp recognition as in + // IR-level ValueTracking. + KnownFPClass KnownFalseClass = computeKnownFPClass( + Op.getOperand(2), DemandedElts, InterestedClasses, Depth + 1); + if (KnownFalseClass.isUnknown()) + break; + KnownFPClass KnownTrueClass = computeKnownFPClass( + Op.getOperand(1), DemandedElts, InterestedClasses, Depth + 1); + Known = KnownTrueClass.intersectWith(KnownFalseClass); + break; + } default: if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN || Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) { diff --git a/llvm/test/CodeGen/RISCV/known-fpclass.ll b/llvm/test/CodeGen/RISCV/known-fpclass.ll index 8d4b162753ba..8e8aab925967 100644 --- a/llvm/test/CodeGen/RISCV/known-fpclass.ll +++ b/llvm/test/CodeGen/RISCV/known-fpclass.ll @@ -70,3 +70,197 @@ define @test_no_overlap_nan_vs_pinf( nofpc %class = call @llvm.is.fpclass.nxv4f32( %a, i32 512) ret %class } + +; Fixed vector vselect tests +define <4 x i1> @vselect_both_nevernan(<4 x i1> %cond, <4 x float> nofpclass(nan) %a, <4 x float> nofpclass(nan) %b) { +; CHECK-LABEL: vselect_both_nevernan: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e8, mf4, ta, ma +; CHECK-NEXT: vmclr.m v0 +; CHECK-NEXT: ret + %sel = select <4 x i1> %cond, <4 x float> %a, <4 x float> %b + %class = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %sel, i32 3) ; 0x3 = "nan" + ret <4 x i1> %class +} + +define <4 x i1> @vselect_both_neverzero(<4 x i1> %cond, <4 x float> nofpclass(zero) %a, <4 x float> nofpclass(zero) %b) { +; CHECK-LABEL: vselect_both_neverzero: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e8, mf4, ta, ma +; CHECK-NEXT: vmclr.m v0 +; CHECK-NEXT: ret + %sel = select <4 x i1> %cond, <4 x float> %a, <4 x float> %b + %class = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %sel, i32 96) ; 0x60 = "zero" + ret <4 x i1> %class +} + +; Scalable vector vselect tests +define @vselect_both_neverinf( %cond, nofpclass(inf) %a, nofpclass(inf) %b) { +; CHECK-LABEL: vselect_both_neverinf: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e8, mf2, ta, ma +; CHECK-NEXT: vmclr.m v0 +; CHECK-NEXT: ret + %sel = select %cond, %a, %b + %class = call @llvm.is.fpclass.nxv4f32( %sel, i32 516) ; 0x204 = "inf" + ret %class +} + +define @vselect_both_nevernan_query_naninf( %cond, nofpclass(nan) %a, nofpclass(nan) %b) { +; CHECK-LABEL: vselect_both_nevernan_query_naninf: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e32, m2, ta, ma +; CHECK-NEXT: vmerge.vvm v8, v10, v8, v0 +; CHECK-NEXT: vfclass.v v8, v8 +; CHECK-NEXT: li a0, 129 +; CHECK-NEXT: vand.vx v8, v8, a0 +; CHECK-NEXT: vmsne.vi v0, v8, 0 +; CHECK-NEXT: ret + %sel = select %cond, %a, %b + %class = call @llvm.is.fpclass.nxv4f32( %sel, i32 519) ; 0x207 = "nan|inf" + ret %class +} + +define @vselect_rhs_unknown( %cond, nofpclass(nan) %a, %b) { +; CHECK-LABEL: vselect_rhs_unknown: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e32, m2, ta, ma +; CHECK-NEXT: vmerge.vvm v8, v10, v8, v0 +; CHECK-NEXT: vfclass.v v8, v8 +; CHECK-NEXT: li a0, 768 +; CHECK-NEXT: vand.vx v8, v8, a0 +; CHECK-NEXT: vmsne.vi v0, v8, 0 +; CHECK-NEXT: ret + %sel = select %cond, %a, %b + %class = call @llvm.is.fpclass.nxv4f32( %sel, i32 3) ; 0x3 = "nan" + ret %class +} + +define @vselect_lhs_unknown( %cond, %a, nofpclass(nan) %b) { +; CHECK-LABEL: vselect_lhs_unknown: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e32, m2, ta, ma +; CHECK-NEXT: vmerge.vvm v8, v10, v8, v0 +; CHECK-NEXT: vfclass.v v8, v8 +; CHECK-NEXT: li a0, 768 +; CHECK-NEXT: vand.vx v8, v8, a0 +; CHECK-NEXT: vmsne.vi v0, v8, 0 +; CHECK-NEXT: ret + %sel = select %cond, %a, %b + %class = call @llvm.is.fpclass.nxv4f32( %sel, i32 3) ; 0x3 = "nan" + ret %class +} + +define i1 @select_rhs_unknown(i1 %cond, float nofpclass(nan) %a, float %b) { +; CHECK-LABEL: select_rhs_unknown: +; CHECK: # %bb.0: +; CHECK-NEXT: andi a0, a0, 1 +; CHECK-NEXT: bnez a0, .LBB12_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: fmv.s fa0, fa1 +; CHECK-NEXT: .LBB12_2: +; CHECK-NEXT: fclass.s a0, fa0 +; CHECK-NEXT: andi a0, a0, 768 +; CHECK-NEXT: snez a0, a0 +; CHECK-NEXT: ret + %sel = select i1 %cond, float %a, float %b + %class = call i1 @llvm.is.fpclass.f32(float %sel, i32 3) ; 0x3 = "nan" + ret i1 %class +} + +define i1 @select_lhs_unknown(i1 %cond, float %a, float nofpclass(nan) %b) { +; CHECK-LABEL: select_lhs_unknown: +; CHECK: # %bb.0: +; CHECK-NEXT: andi a0, a0, 1 +; CHECK-NEXT: bnez a0, .LBB13_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: fmv.s fa0, fa1 +; CHECK-NEXT: .LBB13_2: +; CHECK-NEXT: fclass.s a0, fa0 +; CHECK-NEXT: andi a0, a0, 768 +; CHECK-NEXT: snez a0, a0 +; CHECK-NEXT: ret + %sel = select i1 %cond, float %a, float %b + %class = call i1 @llvm.is.fpclass.f32(float %sel, i32 3) ; 0x3 = "nan" + ret i1 %class +} + +define @vselect_asymmetric_nevernan_neverinf_query_nan( %cond, nofpclass(nan) %a, nofpclass(inf) %b) { +; CHECK-LABEL: vselect_asymmetric_nevernan_neverinf_query_nan: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e32, m2, ta, ma +; CHECK-NEXT: vmerge.vvm v8, v10, v8, v0 +; CHECK-NEXT: vfclass.v v8, v8 +; CHECK-NEXT: li a0, 768 +; CHECK-NEXT: vand.vx v8, v8, a0 +; CHECK-NEXT: vmsne.vi v0, v8, 0 +; CHECK-NEXT: ret + %sel = select %cond, %a, %b + %class = call @llvm.is.fpclass.nxv4f32( %sel, i32 3) ; 0x3 = "nan" + ret %class +} + +; Scalar select tests +define i1 @select_both_nevernan(i1 %cond, float nofpclass(nan) %a, float nofpclass(nan) %b) { +; CHECK-LABEL: select_both_nevernan: +; CHECK: # %bb.0: +; CHECK-NEXT: li a0, 0 +; CHECK-NEXT: ret + %sel = select i1 %cond, float %a, float %b + %class = call i1 @llvm.is.fpclass.f32(float %sel, i32 3) ; 0x3 = "nan" + ret i1 %class +} + +define i1 @select_both_neverinf(i1 %cond, float nofpclass(inf) %a, float nofpclass(inf) %b) { +; CHECK-LABEL: select_both_neverinf: +; CHECK: # %bb.0: +; CHECK-NEXT: li a0, 0 +; CHECK-NEXT: ret + %sel = select i1 %cond, float %a, float %b + %class = call i1 @llvm.is.fpclass.f32(float %sel, i32 516) ; 0x204 = "inf" + ret i1 %class +} + +define i1 @select_both_neverzero(i1 %cond, float nofpclass(zero) %a, float nofpclass(zero) %b) { +; CHECK-LABEL: select_both_neverzero: +; CHECK: # %bb.0: +; CHECK-NEXT: li a0, 0 +; CHECK-NEXT: ret + %sel = select i1 %cond, float %a, float %b + %class = call i1 @llvm.is.fpclass.f32(float %sel, i32 96) ; 0x60 = "zero" + ret i1 %class +} + +define i1 @select_asymmetric_nevernan_neverinf_query_nan(i1 %cond, float nofpclass(nan) %a, float nofpclass(inf) %b) { +; CHECK-LABEL: select_asymmetric_nevernan_neverinf_query_nan: +; CHECK: # %bb.0: +; CHECK-NEXT: andi a0, a0, 1 +; CHECK-NEXT: bnez a0, .LBB18_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: fmv.s fa0, fa1 +; CHECK-NEXT: .LBB18_2: +; CHECK-NEXT: fclass.s a0, fa0 +; CHECK-NEXT: andi a0, a0, 768 +; CHECK-NEXT: snez a0, a0 +; CHECK-NEXT: ret + %sel = select i1 %cond, float %a, float %b + %class = call i1 @llvm.is.fpclass.f32(float %sel, i32 3) ; 0x3 = "nan" + ret i1 %class +} + +define i1 @select_asymmetric_nevernan_neverinf_query_inf(i1 %cond, float nofpclass(nan) %a, float nofpclass(inf) %b) { +; CHECK-LABEL: select_asymmetric_nevernan_neverinf_query_inf: +; CHECK: # %bb.0: +; CHECK-NEXT: andi a0, a0, 1 +; CHECK-NEXT: bnez a0, .LBB19_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: fmv.s fa0, fa1 +; CHECK-NEXT: .LBB19_2: +; CHECK-NEXT: fclass.s a0, fa0 +; CHECK-NEXT: andi a0, a0, 129 +; CHECK-NEXT: snez a0, a0 +; CHECK-NEXT: ret + %sel = select i1 %cond, float %a, float %b + %class = call i1 @llvm.is.fpclass.f32(float %sel, i32 516) ; 0x204 = "inf" + ret i1 %class +}