[llvm] c457619 - ValueTracking: ldexp cannot return denormals based on range of exponent

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 11 11:53:08 PDT 2023


Author: Matt Arsenault
Date: 2023-07-11T14:53:03-04:00
New Revision: c457619c5b2ed854c5277470c4313b337de91665

URL: https://github.com/llvm/llvm-project/commit/c457619c5b2ed854c5277470c4313b337de91665
DIFF: https://github.com/llvm/llvm-project/commit/c457619c5b2ed854c5277470c4313b337de91665.diff

LOG: ValueTracking: ldexp cannot return denormals based on range of exponent

The implementations of a number of math functions on amdgpu involve
pre and post-scaling the inputs out of the denormal range. If these
are chained together we can possibly fold them out.

computeConstantRange seems weaker than computeKnownBits, so this
regresses some of the older vector tests.

Added: 
    

Modified: 
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/test/Transforms/Attributor/nofpclass-ldexp.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index bf2b67988ce845..b73b65e8629bbe 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -4700,24 +4700,30 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
         if ((KnownSrc.KnownFPClasses & ExpInfoMask) == fcNone)
           break;
 
+        const fltSemantics &Flt
+          = II->getType()->getScalarType()->getFltSemantics();
+        unsigned Precision = APFloat::semanticsPrecision(Flt);
         const Value *ExpArg = II->getArgOperand(1);
-        KnownBits ExpKnownBits(
-            ExpArg->getType()->getScalarType()->getIntegerBitWidth());
-        computeKnownBits(ExpArg, ExpKnownBits, Depth + 1, Q);
+        ConstantRange ExpRange = computeConstantRange(
+            ExpArg, true, Q.IIQ.UseInstrInfo, Q.AC, Q.CxtI, Q.DT, Depth + 1);
 
-        const Function *F = II->getFunction();
+        const int MantissaBits = Precision - 1;
+        if (ExpRange.getSignedMin().sge(static_cast<int64_t>(MantissaBits)))
+          Known.knownNot(fcSubnormal);
 
-        if (ExpKnownBits.isZero()) {
+        const Function *F = II->getFunction();
+        const APInt *ConstVal = ExpRange.getSingleElement();
+        if (ConstVal && ConstVal->isZero()) {
           // ldexp(x, 0) -> x, so propagate everything.
-          Known.propagateCanonicalizingSrc(KnownSrc, *II->getFunction(),
+          Known.propagateCanonicalizingSrc(KnownSrc, *F,
                                            II->getType());
-        } else if (ExpKnownBits.isNegative()) {
-          // If we know the power is < 0, can't introduce inf
+        } else if (ExpRange.isAllNegative()) {
+          // If we know the power is <= 0, can't introduce inf
           if (KnownSrc.isKnownNeverPosInfinity())
             Known.knownNot(fcPosInf);
           if (KnownSrc.isKnownNeverNegInfinity())
             Known.knownNot(fcNegInf);
-        } else if (ExpKnownBits.isNonNegative()) {
+        } else if (ExpRange.isAllNonNegative()) {
           // If we know the power is >= 0, can't introduce subnormal or zero
           if (KnownSrc.isKnownNeverPosSubnormal())
             Known.knownNot(fcPosSubnormal);

diff  --git a/llvm/test/Transforms/Attributor/nofpclass-ldexp.ll b/llvm/test/Transforms/Attributor/nofpclass-ldexp.ll
index 40beec9a201455..73ceaca90807b0 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-ldexp.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-ldexp.ll
@@ -702,10 +702,10 @@ define <2 x float> @ret_ldexp_v2f32_known_pos_exp_noinf(<2 x float> nofpclass(in
 }
 
 define <2 x float> @ret_ldexp_v2f32_known_neg_exp_noinf(<2 x float> nofpclass(inf) %arg0, <2 x i32> %arg1) #0 {
-; CHECK-LABEL: define nofpclass(inf) <2 x float> @ret_ldexp_v2f32_known_neg_exp_noinf
+; CHECK-LABEL: define <2 x float> @ret_ldexp_v2f32_known_neg_exp_noinf
 ; CHECK-SAME: (<2 x float> nofpclass(inf) [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[OR_ARG1:%.*]] = or <2 x i32> [[ARG1]], <i32 -16, i32 -32>
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf) <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[ARG0]], <2 x i32> [[OR_ARG1]]) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[ARG0]], <2 x i32> [[OR_ARG1]]) #[[ATTR10]]
 ; CHECK-NEXT:    ret <2 x float> [[CALL]]
 ;
   %or.arg1 = or <2 x i32> %arg1, <i32 -16, i32 -32>
@@ -844,9 +844,9 @@ define float @ret_ldexp_f32_22(float %arg0) #0 {
 }
 
 define float @ret_ldexp_f32_23(float %arg0) #0 {
-; CHECK-LABEL: define float @ret_ldexp_f32_23
+; CHECK-LABEL: define nofpclass(sub) float @ret_ldexp_f32_23
 ; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 23) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 23) #[[ATTR10]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 23)
@@ -854,9 +854,9 @@ define float @ret_ldexp_f32_23(float %arg0) #0 {
 }
 
 define float @ret_ldexp_f32_24(float %arg0) #0 {
-; CHECK-LABEL: define float @ret_ldexp_f32_24
+; CHECK-LABEL: define nofpclass(sub) float @ret_ldexp_f32_24
 ; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 24) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 24) #[[ATTR10]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 24)
@@ -876,9 +876,9 @@ define float @ret_ldexp_f32_min24(float %arg0, i32 %arg1) #0 {
 }
 
 define float @ret_ldexp_f32_23_nnan(float nofpclass(nan) %arg0) #0 {
-; CHECK-LABEL: define nofpclass(nan) float @ret_ldexp_f32_23_nnan
+; CHECK-LABEL: define nofpclass(nan sub) float @ret_ldexp_f32_23_nnan
 ; CHECK-SAME: (float nofpclass(nan) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 23) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 23) #[[ATTR10]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 23)
@@ -906,9 +906,9 @@ define double @ret_ldexp_f64_51(double %arg0) #0 {
 }
 
 define double @ret_ldexp_f64_52(double %arg0) #0 {
-; CHECK-LABEL: define double @ret_ldexp_f64_52
+; CHECK-LABEL: define nofpclass(sub) double @ret_ldexp_f64_52
 ; CHECK-SAME: (double [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call double @llvm.ldexp.f64.i32(double [[ARG0]], i32 noundef 52) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(sub) double @llvm.ldexp.f64.i32(double [[ARG0]], i32 noundef 52) #[[ATTR10]]
 ; CHECK-NEXT:    ret double [[CALL]]
 ;
   %call = call double @llvm.ldexp.f64.i32(double %arg0, i32 52)
@@ -916,9 +916,9 @@ define double @ret_ldexp_f64_52(double %arg0) #0 {
 }
 
 define double @ret_ldexp_f64_53(double %arg0) #0 {
-; CHECK-LABEL: define double @ret_ldexp_f64_53
+; CHECK-LABEL: define nofpclass(sub) double @ret_ldexp_f64_53
 ; CHECK-SAME: (double [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call double @llvm.ldexp.f64.i32(double [[ARG0]], i32 noundef 53) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(sub) double @llvm.ldexp.f64.i32(double [[ARG0]], i32 noundef 53) #[[ATTR10]]
 ; CHECK-NEXT:    ret double [[CALL]]
 ;
   %call = call double @llvm.ldexp.f64.i32(double %arg0, i32 53)
@@ -946,9 +946,9 @@ define half @ret_ldexp_f16_9(half %arg0) #0 {
 }
 
 define half @ret_ldexp_f16_10(half %arg0) #0 {
-; CHECK-LABEL: define half @ret_ldexp_f16_10
+; CHECK-LABEL: define nofpclass(sub) half @ret_ldexp_f16_10
 ; CHECK-SAME: (half [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call half @llvm.ldexp.f16.i32(half [[ARG0]], i32 noundef 10) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(sub) half @llvm.ldexp.f16.i32(half [[ARG0]], i32 noundef 10) #[[ATTR10]]
 ; CHECK-NEXT:    ret half [[CALL]]
 ;
   %call = call half @llvm.ldexp.f16.i32(half %arg0, i32 10)
@@ -966,9 +966,9 @@ define bfloat @ret_ldexp_bf16_6(bfloat %arg0) #0 {
 }
 
 define bfloat @ret_ldexp_bf16_7(bfloat %arg0) #0 {
-; CHECK-LABEL: define bfloat @ret_ldexp_bf16_7
+; CHECK-LABEL: define nofpclass(sub) bfloat @ret_ldexp_bf16_7
 ; CHECK-SAME: (bfloat [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call bfloat @llvm.ldexp.bf16.i32(bfloat [[ARG0]], i32 noundef 7) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(sub) bfloat @llvm.ldexp.bf16.i32(bfloat [[ARG0]], i32 noundef 7) #[[ATTR10]]
 ; CHECK-NEXT:    ret bfloat [[CALL]]
 ;
   %call = call bfloat @llvm.ldexp.bf16.i32(bfloat %arg0, i32 7)
@@ -976,9 +976,9 @@ define bfloat @ret_ldexp_bf16_7(bfloat %arg0) #0 {
 }
 
 define bfloat @ret_ldexp_bf16_8(bfloat %arg0) #0 {
-; CHECK-LABEL: define bfloat @ret_ldexp_bf16_8
+; CHECK-LABEL: define nofpclass(sub) bfloat @ret_ldexp_bf16_8
 ; CHECK-SAME: (bfloat [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call bfloat @llvm.ldexp.bf16.i32(bfloat [[ARG0]], i32 noundef 8) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(sub) bfloat @llvm.ldexp.bf16.i32(bfloat [[ARG0]], i32 noundef 8) #[[ATTR10]]
 ; CHECK-NEXT:    ret bfloat [[CALL]]
 ;
   %call = call bfloat @llvm.ldexp.bf16.i32(bfloat %arg0, i32 8)


        


More information about the llvm-commits mailing list