Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -4772,14 +4772,14 @@ break; const Function *F = cast(Op)->getFunction(); + if (!F) + break; - // If neither side can be zero (or nan) fmul never produces NaN. - // TODO: Check operand combinations. - // e.g. fmul nofpclass(inf nan zero), nofpclass(nan) -> nofpclass(nan) - if ((KnownLHS.isKnownNeverInfinity() || - (F && KnownLHS.isKnownNeverLogicalZero(*F, Op->getType()))) && - (KnownRHS.isKnownNeverInfinity() || - (F && KnownRHS.isKnownNeverLogicalZero(*F, Op->getType())))) + // If 0 * +/-inf produces NaN. + if ((KnownRHS.isKnownNeverInfinity() && + KnownRHS.isKnownNeverLogicalZero(*F, Op->getType())) || + (KnownLHS.isKnownNeverInfinity() && + KnownLHS.isKnownNeverLogicalZero(*F, Op->getType()))) Known.knownNot(fcNan); } Index: llvm/test/Transforms/Attributor/nofpclass-nan-fmul.ll =================================================================== --- llvm/test/Transforms/Attributor/nofpclass-nan-fmul.ll +++ llvm/test/Transforms/Attributor/nofpclass-nan-fmul.ll @@ -12,7 +12,7 @@ } define float @ret_fmul_ieee_nonan_nozero__nonan_nozero(float nofpclass(nan zero) %arg0, float nofpclass(nan zero) %arg1) #0 { -; CHECK-LABEL: define nofpclass(nan) float @ret_fmul_ieee_nonan_nozero__nonan_nozero +; CHECK-LABEL: define float @ret_fmul_ieee_nonan_nozero__nonan_nozero ; CHECK-SAME: (float nofpclass(nan zero) [[ARG0:%.*]], float nofpclass(nan zero) [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG0]], [[ARG1]] ; CHECK-NEXT: ret float [[FMUL]] @@ -52,7 +52,7 @@ } define float @ret_fmul_ieee_nonan_noinf__nonan_noinf(float nofpclass(nan inf) %arg0, float nofpclass(nan inf) %arg1) #0 { -; CHECK-LABEL: define nofpclass(nan) float @ret_fmul_ieee_nonan_noinf__nonan_noinf +; CHECK-LABEL: define float @ret_fmul_ieee_nonan_noinf__nonan_noinf ; CHECK-SAME: (float nofpclass(nan inf) [[ARG0:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG0]], [[ARG1]] ; CHECK-NEXT: ret float [[FMUL]] @@ -62,7 +62,7 @@ } define float @ret_fmul_ieee_nonan_nozero__nonan_noinf(float nofpclass(nan zero) %arg0, float nofpclass(nan inf) %arg1) #0 { -; CHECK-LABEL: define nofpclass(nan) float @ret_fmul_ieee_nonan_nozero__nonan_noinf +; CHECK-LABEL: define float @ret_fmul_ieee_nonan_nozero__nonan_noinf ; CHECK-SAME: (float nofpclass(nan zero) [[ARG0:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG0]], [[ARG1]] ; CHECK-NEXT: ret float [[FMUL]] @@ -72,7 +72,7 @@ } define float @ret_fmul_ieee_nonan_noinf__nonan_nozero(float nofpclass(nan inf) %arg0, float nofpclass(nan zero) %arg1) #0 { -; CHECK-LABEL: define nofpclass(nan) float @ret_fmul_ieee_nonan_noinf__nonan_nozero +; CHECK-LABEL: define float @ret_fmul_ieee_nonan_noinf__nonan_nozero ; CHECK-SAME: (float nofpclass(nan inf) [[ARG0:%.*]], float nofpclass(nan zero) [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG0]], [[ARG1]] ; CHECK-NEXT: ret float [[FMUL]] @@ -102,7 +102,7 @@ } define float @ret_fmul_ieee_nonan_nozero_nosub__nonan_nozero_nosub(float nofpclass(nan zero sub) %arg0, float nofpclass(nan zero sub) %arg1) #0 { -; CHECK-LABEL: define nofpclass(nan) float @ret_fmul_ieee_nonan_nozero_nosub__nonan_nozero_nosub +; CHECK-LABEL: define float @ret_fmul_ieee_nonan_nozero_nosub__nonan_nozero_nosub ; CHECK-SAME: (float nofpclass(nan zero sub) [[ARG0:%.*]], float nofpclass(nan zero sub) [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG0]], [[ARG1]] ; CHECK-NEXT: ret float [[FMUL]] @@ -113,7 +113,7 @@ ; Denormal mode doesn't matter because sources are nofpclass(sub) define float @ret_fmul_daz_nonan_nozero_nosub__nonan_nozero_nosub(float nofpclass(nan zero sub) %arg0, float nofpclass(nan zero sub) %arg1) #1 { -; CHECK-LABEL: define nofpclass(nan) float @ret_fmul_daz_nonan_nozero_nosub__nonan_nozero_nosub +; CHECK-LABEL: define float @ret_fmul_daz_nonan_nozero_nosub__nonan_nozero_nosub ; CHECK-SAME: (float nofpclass(nan zero sub) [[ARG0:%.*]], float nofpclass(nan zero sub) [[ARG1:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG0]], [[ARG1]] ; CHECK-NEXT: ret float [[FMUL]] @@ -123,7 +123,7 @@ } define float @ret_fmul_dapz_nonan_nozero_nosub__nonan_nozero_nosub(float nofpclass(nan zero sub) %arg0, float nofpclass(nan zero sub) %arg1) #2 { -; CHECK-LABEL: define nofpclass(nan) float @ret_fmul_dapz_nonan_nozero_nosub__nonan_nozero_nosub +; CHECK-LABEL: define float @ret_fmul_dapz_nonan_nozero_nosub__nonan_nozero_nosub ; CHECK-SAME: (float nofpclass(nan zero sub) [[ARG0:%.*]], float nofpclass(nan zero sub) [[ARG1:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG0]], [[ARG1]] ; CHECK-NEXT: ret float [[FMUL]] @@ -133,7 +133,7 @@ } define float @ret_fmul_dynamic_nonan_nozero_nosub__nonan_nozero_nosub(float nofpclass(nan zero sub) %arg0, float nofpclass(nan zero sub) %arg1) #3 { -; CHECK-LABEL: define nofpclass(nan) float @ret_fmul_dynamic_nonan_nozero_nosub__nonan_nozero_nosub +; CHECK-LABEL: define float @ret_fmul_dynamic_nonan_nozero_nosub__nonan_nozero_nosub ; CHECK-SAME: (float nofpclass(nan zero sub) [[ARG0:%.*]], float nofpclass(nan zero sub) [[ARG1:%.*]]) #[[ATTR3]] { ; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG0]], [[ARG1]] ; CHECK-NEXT: ret float [[FMUL]] @@ -185,7 +185,7 @@ } define float @ret_fmul_square_nnan_nzero(float nofpclass(nan zero) %arg) #0 { -; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_fmul_square_nnan_nzero +; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fmul_square_nnan_nzero ; CHECK-SAME: (float nofpclass(nan zero) [[ARG:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG]], [[ARG]] ; CHECK-NEXT: ret float [[FMUL]] @@ -255,7 +255,7 @@ } define float @ret_fmul_ieee_noinf_nonan__noinf_noann(float nofpclass(inf nan) %arg0, float nofpclass(inf nan) %arg1) { -; CHECK-LABEL: define nofpclass(nan) float @ret_fmul_ieee_noinf_nonan__noinf_noann +; CHECK-LABEL: define float @ret_fmul_ieee_noinf_nonan__noinf_noann ; CHECK-SAME: (float nofpclass(nan inf) [[ARG0:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR4]] { ; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG0]], [[ARG1]] ; CHECK-NEXT: ret float [[FMUL]] Index: llvm/test/Transforms/Inline/simplify-instruction-computeKnownFPClass-context.ll =================================================================== --- llvm/test/Transforms/Inline/simplify-instruction-computeKnownFPClass-context.ll +++ llvm/test/Transforms/Inline/simplify-instruction-computeKnownFPClass-context.ll @@ -60,9 +60,9 @@ ret i1 %cmp } -define i1 @simplify_fcmp_ord_fmul_caller(double nofpclass(zero nan) %i0, double nofpclass(zero nan) %i1) { +define i1 @simplify_fcmp_ord_fmul_caller(double nofpclass(zero nan inf) %i0, double nofpclass(zero nan inf) %i1) { ; CHECK-LABEL: define i1 @simplify_fcmp_ord_fmul_caller -; CHECK-SAME: (double nofpclass(nan zero) [[I0:%.*]], double nofpclass(nan zero) [[I1:%.*]]) { +; CHECK-SAME: (double nofpclass(nan inf zero) [[I0:%.*]], double nofpclass(nan inf zero) [[I1:%.*]]) { ; CHECK-NEXT: [[SUB_DOUBLE_SUB_I:%.*]] = fmul double [[I0]], [[I1]] ; CHECK-NEXT: ret i1 true ; Index: llvm/test/Transforms/InstSimplify/known-never-nan.ll =================================================================== --- llvm/test/Transforms/InstSimplify/known-never-nan.ll +++ llvm/test/Transforms/InstSimplify/known-never-nan.ll @@ -559,7 +559,10 @@ ; This should not fold to false because fmul 0 * inf = nan define i1 @issue63316(i64 %arg) { ; CHECK-LABEL: @issue63316( -; CHECK-NEXT: ret i1 false +; CHECK-NEXT: [[SITOFP:%.*]] = sitofp i64 [[ARG:%.*]] to float +; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[SITOFP]], 0x7FF0000000000000 +; CHECK-NEXT: [[FCMP:%.*]] = fcmp uno float [[FMUL]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[FCMP]] ; %sitofp = sitofp i64 %arg to float %fmul = fmul float %sitofp, 0x7FF0000000000000 @@ -569,7 +572,10 @@ define i1 @issue63316_commute(i64 %arg) { ; CHECK-LABEL: @issue63316_commute( -; CHECK-NEXT: ret i1 false +; CHECK-NEXT: [[SITOFP:%.*]] = sitofp i64 [[ARG:%.*]] to float +; CHECK-NEXT: [[FMUL:%.*]] = fmul float 0x7FF0000000000000, [[SITOFP]] +; CHECK-NEXT: [[FCMP:%.*]] = fcmp uno float [[FMUL]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[FCMP]] ; %sitofp = sitofp i64 %arg to float %fmul = fmul float 0x7FF0000000000000, %sitofp Index: llvm/unittests/Analysis/ValueTrackingTest.cpp =================================================================== --- llvm/unittests/Analysis/ValueTrackingTest.cpp +++ llvm/unittests/Analysis/ValueTrackingTest.cpp @@ -1594,40 +1594,47 @@ TEST_F(ComputeKnownFPClassTest, FMul) { parseAssembly( - "define float @test(float nofpclass(nan inf) %nnan.ninf0, float nofpclass(nan inf) %nnan.ninf1, float nofpclass(nan) %nnan, float nofpclass(qnan) %no.qnan, float %unknown) {\n" - " %A = fmul float %nnan.ninf0, %nnan.ninf1" - " %A2 = fmul float %nnan.ninf0, %nnan" - " %A3 = fmul float %nnan, %nnan.ninf0" - " %A4 = fmul float %nnan.ninf0, %no.qnan" - " %A5 = fmul float %nnan, %nnan" + "define float @test(float nofpclass(nan inf zero) %nnan.ninf.nzero0, " + "float nofpclass(nan inf zero) %nnan.ninf.nzero1, float nofpclass(nan " + "zero) %nnan.nzero, float nofpclass(qnan) %no.qnan, float %unknown) {\n" + " %A = fmul float %nnan.ninf.nzero0, %nnan.ninf.nzero1" + " %A2 = fmul float %nnan.ninf.nzero0, %nnan.nzero" + " %A3 = fmul float %nnan.nzero, %nnan.ninf.nzero0" + " %A4 = fmul float %nnan.ninf.nzero0, %no.qnan" + " %A5 = fmul float %nnan.nzero, %nnan.nzero" " ret float %A\n" "}\n"); expectKnownFPClass(fcFinite | fcInf, std::nullopt, A); - expectKnownFPClass(fcAllFlags, std::nullopt, A2); - expectKnownFPClass(fcAllFlags, std::nullopt, A3); + expectKnownFPClass(~fcNan, std::nullopt, A2); + expectKnownFPClass(~fcNan, std::nullopt, A3); expectKnownFPClass(fcAllFlags, std::nullopt, A4); expectKnownFPClass(fcPositive | fcNan, std::nullopt, A5); } TEST_F(ComputeKnownFPClassTest, FMulNoZero) { parseAssembly( - "define float @test(float nofpclass(zero) %no.zero, float nofpclass(zero nan) %no.zero.nan0, float nofpclass(zero nan) %no.zero.nan1, float nofpclass(nzero nan) %no.negzero.nan, float nofpclass(pzero nan) %no.poszero.nan, float nofpclass(inf nan) %no.inf.nan, float nofpclass(inf) %no.inf, float nofpclass(nan) %no.nan) {\n" - " %A = fmul float %no.zero.nan0, %no.zero.nan1" + "define float @test(float nofpclass(zero) %no.zero, float nofpclass(zero " + "nan inf) %no.zero.nan.inf0, float nofpclass(zero nan inf) " + "%no.zero.nan.inf1, float nofpclass(nzero nan) %no.negzero.nan, float " + "nofpclass(pzero nan) %no.poszero.nan, float nofpclass(inf nan) " + "%no.inf.nan, float nofpclass(inf) %no.inf, float nofpclass(nan) " + "%no.nan) {\n" + " %A = fmul float %no.zero.nan.inf0, %no.zero.nan.inf1" " %A2 = fmul float %no.zero, %no.zero" - " %A3 = fmul float %no.poszero.nan, %no.zero.nan0" + " %A3 = fmul float %no.poszero.nan, %no.zero.nan.inf0" " %A4 = fmul float %no.nan, %no.zero" " %A5 = fmul float %no.zero, %no.inf" - " %A6 = fmul float %no.zero.nan0, %no.nan" - " %A7 = fmul float %no.nan, %no.zero.nan0" + " %A6 = fmul float %no.zero.nan.inf0, %no.nan" + " %A7 = fmul float %no.nan, %no.zero.nan.inf0" " ret float %A\n" "}\n"); - expectKnownFPClass(fcFinite | fcInf, std::nullopt, A); + expectKnownFPClass(~fcNan, std::nullopt, A); expectKnownFPClass(fcPositive | fcNan, std::nullopt, A2); - expectKnownFPClass(fcAllFlags, std::nullopt, A3); + expectKnownFPClass(~fcNan, std::nullopt, A3); expectKnownFPClass(fcAllFlags, std::nullopt, A4); expectKnownFPClass(fcAllFlags, std::nullopt, A5); expectKnownFPClass(fcAllFlags, std::nullopt, A6); - expectKnownFPClass(fcAllFlags, std::nullopt, A7); + expectKnownFPClass(~fcNan, std::nullopt, A7); } TEST_F(ComputeKnownFPClassTest, Phi) {