Skip to content

Commit 39fcd2c

Browse files
authored
ValueTracking: Teach computeKnownFPClass that multiply can avoid denormals (#171730)
Multiply by large constant can be used to scale denormal inputs into a normal range. This pattern appears frequently in math function library implementations to make use of hardware instructions that do not support denormals. We already handle this case for ldexp, but now canonicalize ldexp by a constant to an fmul. The test cases are mostly the existing nofpclass test for ldexp, run through the new instcombine to replace ldexp with fmul.
1 parent e463bf9 commit 39fcd2c

File tree

3 files changed

+29
-11
lines changed

3 files changed

+29
-11
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5646,6 +5646,24 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
56465646
KnownFPClass KnownLHS, KnownRHS;
56475647
computeKnownFPClass(Op->getOperand(1), DemandedElts, NeedForNan, KnownRHS,
56485648
Q, Depth + 1);
5649+
5650+
const APFloat *CRHS;
5651+
if (match(Op->getOperand(1), m_APFloat(CRHS))) {
5652+
// Match denormal scaling pattern, similar to the case in ldexp. If the
5653+
// constant's exponent is sufficiently large, the result cannot be
5654+
// subnormal.
5655+
5656+
// TODO: Should do general ConstantFPRange analysis.
5657+
const fltSemantics &Flt =
5658+
Op->getType()->getScalarType()->getFltSemantics();
5659+
unsigned Precision = APFloat::semanticsPrecision(Flt);
5660+
const int MantissaBits = Precision - 1;
5661+
5662+
int MinKnownExponent = ilogb(*CRHS);
5663+
if (MinKnownExponent >= MantissaBits)
5664+
Known.knownNot(fcSubnormal);
5665+
}
5666+
56495667
if (!KnownRHS.isKnownNeverNaN())
56505668
break;
56515669

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ define float @ret_mul_exponent_f32_22(float %arg0) {
3535
}
3636

3737
define float @ret_mul_exponent_f32_23(float %arg0) {
38-
; CHECK-LABEL: define float @ret_mul_exponent_f32_23(
38+
; CHECK-LABEL: define nofpclass(sub) float @ret_mul_exponent_f32_23(
3939
; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] {
4040
; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x4160000000000000
4141
; CHECK-NEXT: ret float [[CALL]]
@@ -45,7 +45,7 @@ define float @ret_mul_exponent_f32_23(float %arg0) {
4545
}
4646

4747
define float @ret_mul_exponent_f32_24(float %arg0) {
48-
; CHECK-LABEL: define float @ret_mul_exponent_f32_24(
48+
; CHECK-LABEL: define nofpclass(sub) float @ret_mul_exponent_f32_24(
4949
; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] {
5050
; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x4170000000000000
5151
; CHECK-NEXT: ret float [[CALL]]
@@ -55,7 +55,7 @@ define float @ret_mul_exponent_f32_24(float %arg0) {
5555
}
5656

5757
define float @ret_mul_exponent_f32_23_nnan(float nofpclass(nan) %arg0) {
58-
; CHECK-LABEL: define nofpclass(nan) float @ret_mul_exponent_f32_23_nnan(
58+
; CHECK-LABEL: define nofpclass(nan sub) float @ret_mul_exponent_f32_23_nnan(
5959
; CHECK-SAME: float nofpclass(nan) [[ARG0:%.*]]) #[[ATTR0]] {
6060
; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x4160000000000000
6161
; CHECK-NEXT: ret float [[CALL]]
@@ -85,7 +85,7 @@ define double @ret_mul_exponent_f64_51(double %arg0) {
8585
}
8686

8787
define double @ret_mul_exponent_f64_52(double %arg0) {
88-
; CHECK-LABEL: define double @ret_mul_exponent_f64_52(
88+
; CHECK-LABEL: define nofpclass(sub) double @ret_mul_exponent_f64_52(
8989
; CHECK-SAME: double [[ARG0:%.*]]) #[[ATTR0]] {
9090
; CHECK-NEXT: [[CALL:%.*]] = fmul double [[ARG0]], 0x4330000000000000
9191
; CHECK-NEXT: ret double [[CALL]]
@@ -95,7 +95,7 @@ define double @ret_mul_exponent_f64_52(double %arg0) {
9595
}
9696

9797
define double @ret_mul_exponent_f64_53(double %arg0) {
98-
; CHECK-LABEL: define double @ret_mul_exponent_f64_53(
98+
; CHECK-LABEL: define nofpclass(sub) double @ret_mul_exponent_f64_53(
9999
; CHECK-SAME: double [[ARG0:%.*]]) #[[ATTR0]] {
100100
; CHECK-NEXT: [[CALL:%.*]] = fmul double [[ARG0]], 0x4340000000000000
101101
; CHECK-NEXT: ret double [[CALL]]
@@ -125,7 +125,7 @@ define half @ret_mul_exponent_f16_9(half %arg0) {
125125
}
126126

127127
define half @ret_mul_exponent_f16_10(half %arg0) {
128-
; CHECK-LABEL: define half @ret_mul_exponent_f16_10(
128+
; CHECK-LABEL: define nofpclass(sub) half @ret_mul_exponent_f16_10(
129129
; CHECK-SAME: half [[ARG0:%.*]]) #[[ATTR0]] {
130130
; CHECK-NEXT: [[CALL:%.*]] = fmul half [[ARG0]], 0xH6400
131131
; CHECK-NEXT: ret half [[CALL]]
@@ -145,7 +145,7 @@ define bfloat @ret_mul_exponent_bf16_6(bfloat %arg0) {
145145
}
146146

147147
define bfloat @ret_mul_exponent_bf16_7(bfloat %arg0) {
148-
; CHECK-LABEL: define bfloat @ret_mul_exponent_bf16_7(
148+
; CHECK-LABEL: define nofpclass(sub) bfloat @ret_mul_exponent_bf16_7(
149149
; CHECK-SAME: bfloat [[ARG0:%.*]]) #[[ATTR0]] {
150150
; CHECK-NEXT: [[CALL:%.*]] = fmul bfloat [[ARG0]], 0xR4300
151151
; CHECK-NEXT: ret bfloat [[CALL]]
@@ -155,7 +155,7 @@ define bfloat @ret_mul_exponent_bf16_7(bfloat %arg0) {
155155
}
156156

157157
define bfloat @ret_mul_exponent_bf16_8(bfloat %arg0) {
158-
; CHECK-LABEL: define bfloat @ret_mul_exponent_bf16_8(
158+
; CHECK-LABEL: define nofpclass(sub) bfloat @ret_mul_exponent_bf16_8(
159159
; CHECK-SAME: bfloat [[ARG0:%.*]]) #[[ATTR0]] {
160160
; CHECK-NEXT: [[CALL:%.*]] = fmul bfloat [[ARG0]], 0xR4380
161161
; CHECK-NEXT: ret bfloat [[CALL]]
@@ -215,7 +215,7 @@ define float @ret_mul_exponent_f32_neg127(float %arg0) {
215215
}
216216

217217
define <2 x float> @ret_mul_exponent_v2f32_splat_23(<2 x float> %arg0) {
218-
; CHECK-LABEL: define <2 x float> @ret_mul_exponent_v2f32_splat_23(
218+
; CHECK-LABEL: define nofpclass(sub) <2 x float> @ret_mul_exponent_v2f32_splat_23(
219219
; CHECK-SAME: <2 x float> [[ARG0:%.*]]) #[[ATTR0]] {
220220
; CHECK-NEXT: [[CALL:%.*]] = fmul <2 x float> [[ARG0]], splat (float 0x4160000000000000)
221221
; CHECK-NEXT: ret <2 x float> [[CALL]]
@@ -267,7 +267,7 @@ define float @ret_mul_f32_0(float %arg0) {
267267
}
268268

269269
define float @ret_mul_f32_inf(float %arg0) {
270-
; CHECK-LABEL: define float @ret_mul_f32_inf(
270+
; CHECK-LABEL: define nofpclass(sub) float @ret_mul_f32_inf(
271271
; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] {
272272
; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x7FF0000000000000
273273
; CHECK-NEXT: ret float [[CALL]]

llvm/test/Transforms/Attributor/nofpclass-nan-fmul.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ define float @ret_fmul_square_nnan_nzero(float nofpclass(nan zero) %arg) #0 {
195195
}
196196

197197
define float @ret_fmul_ieee_inf(float %arg) {
198-
; CHECK-LABEL: define float @ret_fmul_ieee_inf
198+
; CHECK-LABEL: define nofpclass(sub) float @ret_fmul_ieee_inf
199199
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR4:[0-9]+]] {
200200
; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG]], 0x7FF0000000000000
201201
; CHECK-NEXT: ret float [[FMUL]]

0 commit comments

Comments
 (0)