Index: llvm/include/llvm/Analysis/ValueTracking.h =================================================================== --- llvm/include/llvm/Analysis/ValueTracking.h +++ llvm/include/llvm/Analysis/ValueTracking.h @@ -249,6 +249,11 @@ return (KnownFPClasses & fcInf) == fcNone; } + /// Return true if it's known this can never be a zero. + bool isKnownNeverZero() const { + return (KnownFPClasses & fcZero) == fcNone; + } + KnownFPClass &operator|=(const KnownFPClass &RHS) { KnownFPClasses = KnownFPClasses | RHS.KnownFPClasses; Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -4459,15 +4459,19 @@ } case Instruction::FMul: { KnownFPClass KnownLHS, KnownRHS; - computeKnownFPClass(Op->getOperand(1), DemandedElts, fcNan | fcInf, + computeKnownFPClass(Op->getOperand(1), DemandedElts, fcNan | fcInf | fcZero, KnownRHS, Depth + 1, Q, TLI); - if (KnownRHS.isKnownNeverNaN() && KnownRHS.isKnownNeverInfinity()) { - computeKnownFPClass(Op->getOperand(0), DemandedElts, fcNan | fcInf, - KnownLHS, Depth + 1, Q, TLI); + if (KnownRHS.isKnownNeverNaN() && + (KnownRHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverZero())) { + computeKnownFPClass(Op->getOperand(0), DemandedElts, + fcNan | fcInf | fcZero, KnownLHS, Depth + 1, Q, TLI); + if (!KnownLHS.isKnownNeverNaN()) + break; // Zero multiplied with infinity produces NaN. - // FIXME: If neither side can be zero fmul never produces NaN. - if (KnownLHS.isKnownNeverNaN() && KnownLHS.isKnownNeverInfinity()) + // If neither side can be zero (or nan) fmul never produces NaN. + if ((KnownLHS.isKnownNeverInfinity() || KnownLHS.isKnownNeverZero()) && + (KnownRHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverZero())) 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_nonan_nozero__nonan_nozero(float nofpclass(nan zero) %arg0, float nofpclass(nan zero) %arg1) { -; CHECK-LABEL: define float @ret_fmul_nonan_nozero__nonan_nozero +; CHECK-LABEL: define nofpclass(nan) float @ret_fmul_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]] @@ -32,7 +32,7 @@ } define float @ret_fmul_nonan_nozero__nonan_noinf(float nofpclass(nan zero) %arg0, float nofpclass(nan inf) %arg1) { -; CHECK-LABEL: define float @ret_fmul_nonan_nozero__nonan_noinf +; CHECK-LABEL: define nofpclass(nan) float @ret_fmul_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]] @@ -42,7 +42,7 @@ } define float @ret_fmul_nonan_noinf__nonan_nozero(float nofpclass(nan inf) %arg0, float nofpclass(nan zero) %arg1) { -; CHECK-LABEL: define float @ret_fmul_nonan_noinf__nonan_nozero +; CHECK-LABEL: define nofpclass(nan) float @ret_fmul_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]] Index: llvm/unittests/Analysis/ValueTrackingTest.cpp =================================================================== --- llvm/unittests/Analysis/ValueTrackingTest.cpp +++ llvm/unittests/Analysis/ValueTrackingTest.cpp @@ -72,6 +72,8 @@ A3 = findInstructionByNameOrNull(F, "A3"); A4 = findInstructionByNameOrNull(F, "A4"); A5 = findInstructionByNameOrNull(F, "A5"); + A6 = findInstructionByNameOrNull(F, "A6"); + A7 = findInstructionByNameOrNull(F, "A7"); CxtI = findInstructionByNameOrNull(F, "CxtI"); CxtI2 = findInstructionByNameOrNull(F, "CxtI2"); @@ -83,7 +85,8 @@ Function *F = nullptr; Instruction *A = nullptr; // Instructions (optional) - Instruction *A2 = nullptr, *A3 = nullptr, *A4 = nullptr, *A5 = nullptr; + Instruction *A2 = nullptr, *A3 = nullptr, *A4 = nullptr, *A5 = nullptr, + *A6 = nullptr, *A7 = nullptr; // Context instructions (optional) Instruction *CxtI = nullptr, *CxtI2 = nullptr, *CxtI3 = nullptr; @@ -1592,6 +1595,27 @@ expectKnownFPClass(fcAllFlags, std::nullopt, A5); } +TEST_F(ComputeKnownFPClassTest, FMulNoZero) { + parseAssembly( + "define float @test(float nofpclass(zero) %no.zero, float nofpclass(zero nan) %no.zero.nan, 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, %no.zero.nan" + " %A2 = fmul float %no.zero, %no.zero" + " %A3 = fmul float %no.poszero.nan, %no.zero.nan" + " %A4 = fmul float %no.nan, %no.zero" + " %A5 = fmul float %no.zero, %no.inf" + " %A6 = fmul float %no.zero.nan, %no.nan" + " %A7 = fmul float %no.nan, %no.zero.nan" + " ret float %A\n" + "}\n"); + expectKnownFPClass(fcFinite | fcInf, std::nullopt, A); + expectKnownFPClass(fcAllFlags, std::nullopt, A2); + expectKnownFPClass(fcAllFlags, std::nullopt, A3); + expectKnownFPClass(fcAllFlags, std::nullopt, A4); + expectKnownFPClass(fcAllFlags, std::nullopt, A5); + expectKnownFPClass(fcAllFlags, std::nullopt, A6); + expectKnownFPClass(fcAllFlags, std::nullopt, A7); +} + TEST_F(ValueTrackingTest, isNonZeroRecurrence) { parseAssembly(R"( define i1 @test(i8 %n, i8 %r) {