Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -4449,6 +4449,41 @@ break; } + case Intrinsic::powi: { + if ((InterestedClasses & KnownFPClass::OrderedLessThanZeroMask) == + fcNone) + break; + + const Value *Exp = II->getArgOperand(1); + unsigned BitWidth = + Exp->getType()->getScalarType()->getIntegerBitWidth(); + KnownBits ExponentKnownBits(BitWidth); + computeKnownBits(Exp, DemandedElts, ExponentKnownBits, Depth + 1, Q); + + if (ExponentKnownBits.Zero.isOneBitSet(0)) { // Is even + Known.knownNot(KnownFPClass::OrderedLessThanZeroMask); + break; + } + + // Given that exp is an integer, here are the + // ways that pow can return a negative value: + // + // pow(-x, exp) --> negative if exp is odd and x is negative. + // pow(-0, exp) --> -inf if exp is negative odd. + // pow(-0, exp) --> -0 if exp is positive odd. + // pow(-inf, exp) --> -0 if exp is negative odd. + // pow(-inf, exp) --> -inf if exp is positive odd. + KnownFPClass KnownSrc; + computeKnownFPClass(II->getArgOperand(0), DemandedElts, + InterestedClasses, KnownSrc, Depth + 1, Q, TLI); + if (KnownSrc.cannotBeOrderedLessThanZero() && + KnownSrc.isKnownNeverNegZero()) + Known.knownNot(KnownFPClass::OrderedLessThanZeroMask); + break; + } + case Intrinsic::pow: { + break; + } case Intrinsic::arithmetic_fence: { computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedClasses, Known, Depth + 1, Q, TLI); Index: llvm/test/Transforms/Attributor/nofpclass-powi.ll =================================================================== --- llvm/test/Transforms/Attributor/nofpclass-powi.ll +++ llvm/test/Transforms/Attributor/nofpclass-powi.ll @@ -77,10 +77,10 @@ } define float @ret_powi_f32_masked_to_even(float %arg0, i32 %arg1) { -; CHECK-LABEL: define float @ret_powi_f32_masked_to_even +; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_powi_f32_masked_to_even ; CHECK-SAME: (float [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[KNOWN_EVEN:%.*]] = and i32 [[ARG1]], -2 -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.powi.f32.i32(float [[ARG0]], i32 [[KNOWN_EVEN]]) #[[ATTR2]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.powi.f32.i32(float [[ARG0]], i32 [[KNOWN_EVEN]]) #[[ATTR2]] ; CHECK-NEXT: ret float [[CALL]] ; %known.even = and i32 %arg1, -2 @@ -89,10 +89,10 @@ } define <2 x float> @ret_powi_v2f32_masked_to_even(<2 x float> %arg0, <2 x i32> %arg1) { -; CHECK-LABEL: define <2 x float> @ret_powi_v2f32_masked_to_even +; CHECK-LABEL: define nofpclass(ninf nsub nnorm) <2 x float> @ret_powi_v2f32_masked_to_even ; CHECK-SAME: (<2 x float> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[KNOWN_EVEN:%.*]] = and <2 x i32> [[ARG1]], -; CHECK-NEXT: [[CALL:%.*]] = call <2 x float> @llvm.powi.v2f32.v2i32(<2 x float> [[ARG0]], <2 x i32> [[KNOWN_EVEN]]) #[[ATTR2]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nsub nnorm) <2 x float> @llvm.powi.v2f32.v2i32(<2 x float> [[ARG0]], <2 x i32> [[KNOWN_EVEN]]) #[[ATTR2]] ; CHECK-NEXT: ret <2 x float> [[CALL]] ; %known.even = and <2 x i32> %arg1, @@ -111,9 +111,9 @@ } define float @ret_powi_f32_noneg_nonzero(float nofpclass(ninf nsub nnorm nzero) %arg0, i32 %arg1) { -; CHECK-LABEL: define float @ret_powi_f32_noneg_nonzero +; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_powi_f32_noneg_nonzero ; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.powi.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR2]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.powi.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR2]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)