Skip to content

Commit c457619

Browse files
committed
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.
1 parent 6251adc commit c457619

File tree

2 files changed

+33
-27
lines changed

2 files changed

+33
-27
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4700,24 +4700,30 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
47004700
if ((KnownSrc.KnownFPClasses & ExpInfoMask) == fcNone)
47014701
break;
47024702

4703+
const fltSemantics &Flt
4704+
= II->getType()->getScalarType()->getFltSemantics();
4705+
unsigned Precision = APFloat::semanticsPrecision(Flt);
47034706
const Value *ExpArg = II->getArgOperand(1);
4704-
KnownBits ExpKnownBits(
4705-
ExpArg->getType()->getScalarType()->getIntegerBitWidth());
4706-
computeKnownBits(ExpArg, ExpKnownBits, Depth + 1, Q);
4707+
ConstantRange ExpRange = computeConstantRange(
4708+
ExpArg, true, Q.IIQ.UseInstrInfo, Q.AC, Q.CxtI, Q.DT, Depth + 1);
47074709

4708-
const Function *F = II->getFunction();
4710+
const int MantissaBits = Precision - 1;
4711+
if (ExpRange.getSignedMin().sge(static_cast<int64_t>(MantissaBits)))
4712+
Known.knownNot(fcSubnormal);
47094713

4710-
if (ExpKnownBits.isZero()) {
4714+
const Function *F = II->getFunction();
4715+
const APInt *ConstVal = ExpRange.getSingleElement();
4716+
if (ConstVal && ConstVal->isZero()) {
47114717
// ldexp(x, 0) -> x, so propagate everything.
4712-
Known.propagateCanonicalizingSrc(KnownSrc, *II->getFunction(),
4718+
Known.propagateCanonicalizingSrc(KnownSrc, *F,
47134719
II->getType());
4714-
} else if (ExpKnownBits.isNegative()) {
4715-
// If we know the power is < 0, can't introduce inf
4720+
} else if (ExpRange.isAllNegative()) {
4721+
// If we know the power is <= 0, can't introduce inf
47164722
if (KnownSrc.isKnownNeverPosInfinity())
47174723
Known.knownNot(fcPosInf);
47184724
if (KnownSrc.isKnownNeverNegInfinity())
47194725
Known.knownNot(fcNegInf);
4720-
} else if (ExpKnownBits.isNonNegative()) {
4726+
} else if (ExpRange.isAllNonNegative()) {
47214727
// If we know the power is >= 0, can't introduce subnormal or zero
47224728
if (KnownSrc.isKnownNeverPosSubnormal())
47234729
Known.knownNot(fcPosSubnormal);

llvm/test/Transforms/Attributor/nofpclass-ldexp.ll

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -702,10 +702,10 @@ define <2 x float> @ret_ldexp_v2f32_known_pos_exp_noinf(<2 x float> nofpclass(in
702702
}
703703

704704
define <2 x float> @ret_ldexp_v2f32_known_neg_exp_noinf(<2 x float> nofpclass(inf) %arg0, <2 x i32> %arg1) #0 {
705-
; CHECK-LABEL: define nofpclass(inf) <2 x float> @ret_ldexp_v2f32_known_neg_exp_noinf
705+
; CHECK-LABEL: define <2 x float> @ret_ldexp_v2f32_known_neg_exp_noinf
706706
; CHECK-SAME: (<2 x float> nofpclass(inf) [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR1]] {
707707
; CHECK-NEXT: [[OR_ARG1:%.*]] = or <2 x i32> [[ARG1]], <i32 -16, i32 -32>
708-
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[ARG0]], <2 x i32> [[OR_ARG1]]) #[[ATTR10]]
708+
; CHECK-NEXT: [[CALL:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[ARG0]], <2 x i32> [[OR_ARG1]]) #[[ATTR10]]
709709
; CHECK-NEXT: ret <2 x float> [[CALL]]
710710
;
711711
%or.arg1 = or <2 x i32> %arg1, <i32 -16, i32 -32>
@@ -844,19 +844,19 @@ define float @ret_ldexp_f32_22(float %arg0) #0 {
844844
}
845845

846846
define float @ret_ldexp_f32_23(float %arg0) #0 {
847-
; CHECK-LABEL: define float @ret_ldexp_f32_23
847+
; CHECK-LABEL: define nofpclass(sub) float @ret_ldexp_f32_23
848848
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR1]] {
849-
; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 23) #[[ATTR10]]
849+
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 23) #[[ATTR10]]
850850
; CHECK-NEXT: ret float [[CALL]]
851851
;
852852
%call = call float @llvm.ldexp.f32.i32(float %arg0, i32 23)
853853
ret float %call
854854
}
855855

856856
define float @ret_ldexp_f32_24(float %arg0) #0 {
857-
; CHECK-LABEL: define float @ret_ldexp_f32_24
857+
; CHECK-LABEL: define nofpclass(sub) float @ret_ldexp_f32_24
858858
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR1]] {
859-
; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 24) #[[ATTR10]]
859+
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 24) #[[ATTR10]]
860860
; CHECK-NEXT: ret float [[CALL]]
861861
;
862862
%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 {
876876
}
877877

878878
define float @ret_ldexp_f32_23_nnan(float nofpclass(nan) %arg0) #0 {
879-
; CHECK-LABEL: define nofpclass(nan) float @ret_ldexp_f32_23_nnan
879+
; CHECK-LABEL: define nofpclass(nan sub) float @ret_ldexp_f32_23_nnan
880880
; CHECK-SAME: (float nofpclass(nan) [[ARG0:%.*]]) #[[ATTR1]] {
881-
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 23) #[[ATTR10]]
881+
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 23) #[[ATTR10]]
882882
; CHECK-NEXT: ret float [[CALL]]
883883
;
884884
%call = call float @llvm.ldexp.f32.i32(float %arg0, i32 23)
@@ -906,19 +906,19 @@ define double @ret_ldexp_f64_51(double %arg0) #0 {
906906
}
907907

908908
define double @ret_ldexp_f64_52(double %arg0) #0 {
909-
; CHECK-LABEL: define double @ret_ldexp_f64_52
909+
; CHECK-LABEL: define nofpclass(sub) double @ret_ldexp_f64_52
910910
; CHECK-SAME: (double [[ARG0:%.*]]) #[[ATTR1]] {
911-
; CHECK-NEXT: [[CALL:%.*]] = call double @llvm.ldexp.f64.i32(double [[ARG0]], i32 noundef 52) #[[ATTR10]]
911+
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) double @llvm.ldexp.f64.i32(double [[ARG0]], i32 noundef 52) #[[ATTR10]]
912912
; CHECK-NEXT: ret double [[CALL]]
913913
;
914914
%call = call double @llvm.ldexp.f64.i32(double %arg0, i32 52)
915915
ret double %call
916916
}
917917

918918
define double @ret_ldexp_f64_53(double %arg0) #0 {
919-
; CHECK-LABEL: define double @ret_ldexp_f64_53
919+
; CHECK-LABEL: define nofpclass(sub) double @ret_ldexp_f64_53
920920
; CHECK-SAME: (double [[ARG0:%.*]]) #[[ATTR1]] {
921-
; CHECK-NEXT: [[CALL:%.*]] = call double @llvm.ldexp.f64.i32(double [[ARG0]], i32 noundef 53) #[[ATTR10]]
921+
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) double @llvm.ldexp.f64.i32(double [[ARG0]], i32 noundef 53) #[[ATTR10]]
922922
; CHECK-NEXT: ret double [[CALL]]
923923
;
924924
%call = call double @llvm.ldexp.f64.i32(double %arg0, i32 53)
@@ -946,9 +946,9 @@ define half @ret_ldexp_f16_9(half %arg0) #0 {
946946
}
947947

948948
define half @ret_ldexp_f16_10(half %arg0) #0 {
949-
; CHECK-LABEL: define half @ret_ldexp_f16_10
949+
; CHECK-LABEL: define nofpclass(sub) half @ret_ldexp_f16_10
950950
; CHECK-SAME: (half [[ARG0:%.*]]) #[[ATTR1]] {
951-
; CHECK-NEXT: [[CALL:%.*]] = call half @llvm.ldexp.f16.i32(half [[ARG0]], i32 noundef 10) #[[ATTR10]]
951+
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) half @llvm.ldexp.f16.i32(half [[ARG0]], i32 noundef 10) #[[ATTR10]]
952952
; CHECK-NEXT: ret half [[CALL]]
953953
;
954954
%call = call half @llvm.ldexp.f16.i32(half %arg0, i32 10)
@@ -966,19 +966,19 @@ define bfloat @ret_ldexp_bf16_6(bfloat %arg0) #0 {
966966
}
967967

968968
define bfloat @ret_ldexp_bf16_7(bfloat %arg0) #0 {
969-
; CHECK-LABEL: define bfloat @ret_ldexp_bf16_7
969+
; CHECK-LABEL: define nofpclass(sub) bfloat @ret_ldexp_bf16_7
970970
; CHECK-SAME: (bfloat [[ARG0:%.*]]) #[[ATTR1]] {
971-
; CHECK-NEXT: [[CALL:%.*]] = call bfloat @llvm.ldexp.bf16.i32(bfloat [[ARG0]], i32 noundef 7) #[[ATTR10]]
971+
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) bfloat @llvm.ldexp.bf16.i32(bfloat [[ARG0]], i32 noundef 7) #[[ATTR10]]
972972
; CHECK-NEXT: ret bfloat [[CALL]]
973973
;
974974
%call = call bfloat @llvm.ldexp.bf16.i32(bfloat %arg0, i32 7)
975975
ret bfloat %call
976976
}
977977

978978
define bfloat @ret_ldexp_bf16_8(bfloat %arg0) #0 {
979-
; CHECK-LABEL: define bfloat @ret_ldexp_bf16_8
979+
; CHECK-LABEL: define nofpclass(sub) bfloat @ret_ldexp_bf16_8
980980
; CHECK-SAME: (bfloat [[ARG0:%.*]]) #[[ATTR1]] {
981-
; CHECK-NEXT: [[CALL:%.*]] = call bfloat @llvm.ldexp.bf16.i32(bfloat [[ARG0]], i32 noundef 8) #[[ATTR10]]
981+
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) bfloat @llvm.ldexp.bf16.i32(bfloat [[ARG0]], i32 noundef 8) #[[ATTR10]]
982982
; CHECK-NEXT: ret bfloat [[CALL]]
983983
;
984984
%call = call bfloat @llvm.ldexp.bf16.i32(bfloat %arg0, i32 8)

0 commit comments

Comments
 (0)