Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -4243,6 +4243,27 @@ break; } + case Intrinsic::fma: + case Intrinsic::fmuladd: { + if ((InterestedClasses & fcNegative) == fcNone) + break; + + if (II->getArgOperand(0) != II->getArgOperand(1)) + break; + + // The multiply cannot be -0 and therefore the add can't be -0 + Known.knownNot(fcNegZero); + + // x * x + y is non-negative if y is non-negative. + KnownFPClass KnownAddend; + computeKnownFPClass(II->getArgOperand(2), DemandedElts, + InterestedClasses, KnownAddend, Depth + 1, Q, TLI); + + // TODO: Known sign bit with no nans + if (KnownAddend.cannotBeOrderedLessThanZero()) + Known.knownNot(fcNegative); + break; + } case Intrinsic::sin: case Intrinsic::cos: { // Return NaN on infinite inputs. Index: llvm/test/Transforms/Attributor/nofpclass-fma.ll =================================================================== --- llvm/test/Transforms/Attributor/nofpclass-fma.ll +++ llvm/test/Transforms/Attributor/nofpclass-fma.ll @@ -5,9 +5,9 @@ declare float @llvm.fmuladd.f32(float, float, float) define float @ret_fma_same_mul_arg(float %arg0, float %arg1) { -; CHECK-LABEL: define float @ret_fma_same_mul_arg +; CHECK-LABEL: define nofpclass(nzero) float @ret_fma_same_mul_arg ; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1:[0-9]+]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.fma.f32(float [[ARG0]], float [[ARG0]], float [[ARG1]]) #[[ATTR2:[0-9]+]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero) float @llvm.fma.f32(float [[ARG0]], float [[ARG0]], float [[ARG1]]) #[[ATTR2:[0-9]+]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.fma.f32(float %arg0, float %arg0, float %arg1) @@ -15,9 +15,9 @@ } define float @ret_fma_same_mul_arg_positive_addend(float %arg0, float nofpclass(ninf nsub nnorm) %arg1) { -; CHECK-LABEL: define float @ret_fma_same_mul_arg_positive_addend +; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fma_same_mul_arg_positive_addend ; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.fma.f32(float [[ARG0]], float [[ARG0]], float [[ARG1]]) #[[ATTR2]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fma.f32(float [[ARG0]], float [[ARG0]], float [[ARG1]]) #[[ATTR2]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.fma.f32(float %arg0, float %arg0, float %arg1) @@ -35,9 +35,9 @@ } define float @ret_fmuladd_different_same_arg_positive_addend(float %arg0, float nofpclass(ninf nsub nnorm) %arg1) { -; CHECK-LABEL: define float @ret_fmuladd_different_same_arg_positive_addend +; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fmuladd_different_same_arg_positive_addend ; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.fmuladd.f32(float [[ARG0]], float [[ARG0]], float [[ARG1]]) #[[ATTR2]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fmuladd.f32(float [[ARG0]], float [[ARG0]], float [[ARG1]]) #[[ATTR2]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.fmuladd.f32(float %arg0, float %arg0, float %arg1)