Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -4472,6 +4472,13 @@ break; } case Instruction::FMul: { + // X * X is always non-negative or a NaN. + if (Op->getOperand(0) == Op->getOperand(1)) + Known.knownNot(fcNegative); + + if ((InterestedClasses & fcNan) != fcNan) + break; + KnownFPClass KnownLHS, KnownRHS; computeKnownFPClass(Op->getOperand(1), DemandedElts, fcNan | fcInf | fcZero | fcSubnormal, KnownRHS, 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 @@ -164,6 +164,36 @@ ret float %fmul } +define float @ret_fmul_square(float %arg) #0 { +; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fmul_square +; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG]], [[ARG]] +; CHECK-NEXT: ret float [[FMUL]] +; + %fmul = fmul float %arg, %arg + ret float %fmul +} + +define float @ret_fmul_square_nnan(float nofpclass(nan) %arg) #0 { +; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fmul_square_nnan +; CHECK-SAME: (float nofpclass(nan) [[ARG:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG]], [[ARG]] +; CHECK-NEXT: ret float [[FMUL]] +; + %fmul = fmul float %arg, %arg + ret float %fmul +} + +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-SAME: (float nofpclass(nan zero) [[ARG:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG]], [[ARG]] +; CHECK-NEXT: ret float [[FMUL]] +; + %fmul = fmul float %arg, %arg + ret float %fmul +} + attributes #0 = { "denormal-fp-math"="ieee,ieee" } attributes #1 = { "denormal-fp-math"="ieee,preserve-sign" } attributes #2 = { "denormal-fp-math"="ieee,positive-zero" } Index: llvm/unittests/Analysis/ValueTrackingTest.cpp =================================================================== --- llvm/unittests/Analysis/ValueTrackingTest.cpp +++ llvm/unittests/Analysis/ValueTrackingTest.cpp @@ -1580,11 +1580,11 @@ TEST_F(ComputeKnownFPClassTest, FMul) { parseAssembly( - "define float @test(float nofpclass(nan inf) %nnan.ninf, float nofpclass(nan) %nnan, float nofpclass(qnan) %no.qnan, float %unknown) {\n" - " %A = fmul float %nnan.ninf, %nnan.ninf" - " %A2 = fmul float %nnan.ninf, %nnan" - " %A3 = fmul float %nnan, %nnan.ninf" - " %A4 = fmul float %nnan.ninf, %no.qnan" + "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" " ret float %A\n" "}\n"); @@ -1592,23 +1592,23 @@ expectKnownFPClass(fcAllFlags, std::nullopt, A2); expectKnownFPClass(fcAllFlags, std::nullopt, A3); expectKnownFPClass(fcAllFlags, std::nullopt, A4); - expectKnownFPClass(fcAllFlags, std::nullopt, A5); + 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.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" + "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" " %A2 = fmul float %no.zero, %no.zero" - " %A3 = fmul float %no.poszero.nan, %no.zero.nan" + " %A3 = fmul float %no.poszero.nan, %no.zero.nan0" " %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" + " %A6 = fmul float %no.zero.nan0, %no.nan" + " %A7 = fmul float %no.nan, %no.zero.nan0" " ret float %A\n" "}\n"); expectKnownFPClass(fcFinite | fcInf, std::nullopt, A); - expectKnownFPClass(fcAllFlags, std::nullopt, A2); + expectKnownFPClass(fcPositive | fcNan, std::nullopt, A2); expectKnownFPClass(fcAllFlags, std::nullopt, A3); expectKnownFPClass(fcAllFlags, std::nullopt, A4); expectKnownFPClass(fcAllFlags, std::nullopt, A5);