-
Notifications
You must be signed in to change notification settings - Fork 15.4k
InstCombine: Fold ldexp with constant exponent to fmul #171731
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
InstCombine: Fold ldexp with constant exponent to fmul #171731
Conversation
|
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-llvm-ir Author: Matt Arsenault (arsenm) ChangesIf we can represent this with an fmul, prefer it as a canonical Full diff: https://github.com/llvm/llvm-project/pull/171731.diff 3 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 85602a5a7575a..b498bafb3caaa 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3089,6 +3089,19 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
// exponent. Also could broaden sign check to cover == 0 case.
Value *Src = II->getArgOperand(0);
Value *Exp = II->getArgOperand(1);
+
+ uint64_t ConstExp;
+ if (match(Exp, m_ConstantInt(ConstExp))) {
+ // ldexp(x, K) -> fmul x, 2^K
+ const fltSemantics &FPTy =
+ Src->getType()->getScalarType()->getFltSemantics();
+ Constant *FPConst =
+ ConstantFP::get(Src->getType(), scalbn(APFloat::getOne(FPTy),
+ static_cast<int>(ConstExp),
+ APFloat::rmNearestTiesToEven));
+ return BinaryOperator::CreateFMulFMF(Src, FPConst, II);
+ }
+
Value *InnerSrc;
Value *InnerExp;
if (match(Src, m_OneUse(m_Intrinsic<Intrinsic::ldexp>(
diff --git a/llvm/test/Transforms/InstCombine/fold-select-fmul-if-zero.ll b/llvm/test/Transforms/InstCombine/fold-select-fmul-if-zero.ll
index 1ba7005f99e3d..4495b0f26042b 100644
--- a/llvm/test/Transforms/InstCombine/fold-select-fmul-if-zero.ll
+++ b/llvm/test/Transforms/InstCombine/fold-select-fmul-if-zero.ll
@@ -49,10 +49,7 @@ define float @fmul_by_32_if_0_oeq_zero_f32(float %x) {
define float @ldexp_by_5_if_0_oeq_zero_f32(float %x) {
; CHECK-LABEL: @ldexp_by_5_if_0_oeq_zero_f32(
-; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
-; CHECK-NEXT: [[SCALED_X:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 5)
-; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = select i1 [[X_IS_ZERO]], float [[SCALED_X]], float [[X]]
-; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
+; CHECK-NEXT: ret float [[X:%.*]]
;
%x.is.zero = fcmp oeq float %x, 0.0
%scaled.x = call float @llvm.ldexp.f32.i32(float %x, i32 5)
@@ -62,10 +59,7 @@ define float @ldexp_by_5_if_0_oeq_zero_f32(float %x) {
define <2 x float> @ldexp_by_5_if_0_oeq_zero_v2f32(<2 x float> %x) {
; CHECK-LABEL: @ldexp_by_5_if_0_oeq_zero_v2f32(
-; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq <2 x float> [[X:%.*]], zeroinitializer
-; CHECK-NEXT: [[SCALED_X:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X]], <2 x i32> splat (i32 5))
-; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = select <2 x i1> [[X_IS_ZERO]], <2 x float> [[SCALED_X]], <2 x float> [[X]]
-; CHECK-NEXT: ret <2 x float> [[SCALED_IF_DENORMAL]]
+; CHECK-NEXT: ret <2 x float> [[SCALED_IF_DENORMAL:%.*]]
;
%x.is.zero = fcmp oeq <2 x float> %x, zeroinitializer
%scaled.x = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %x, <2 x i32> <i32 5, i32 5>)
diff --git a/llvm/test/Transforms/InstCombine/ldexp.ll b/llvm/test/Transforms/InstCombine/ldexp.ll
index 8908d476b4a2c..43e80b1a1e588 100644
--- a/llvm/test/Transforms/InstCombine/ldexp.ll
+++ b/llvm/test/Transforms/InstCombine/ldexp.ll
@@ -444,7 +444,7 @@ define float @ldexp_ldexp_different_exp_type(float %x, i32 %a, i64 %b) {
define float @ldexp_ldexp_constants(float %x) {
; CHECK-LABEL: define float @ldexp_ldexp_constants
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 32)
+; CHECK-NEXT: [[LDEXP1:%.*]] = fmul reassoc float [[X]], 0x41F0000000000000
; CHECK-NEXT: ret float [[LDEXP1]]
;
%ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 8)
@@ -455,7 +455,7 @@ define float @ldexp_ldexp_constants(float %x) {
define float @ldexp_ldexp_constants_nsz(float %x) {
; CHECK-LABEL: define float @ldexp_ldexp_constants_nsz
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc nsz float @llvm.ldexp.f32.i32(float [[X]], i32 32)
+; CHECK-NEXT: [[LDEXP1:%.*]] = fmul reassoc nsz float [[X]], 0x41F0000000000000
; CHECK-NEXT: ret float [[LDEXP1]]
;
%ldexp0 = call reassoc nsz float @llvm.ldexp.f32.i32(float %x, i32 8)
@@ -466,7 +466,7 @@ define float @ldexp_ldexp_constants_nsz(float %x) {
define float @ldexp_ldexp_constants_nsz0(float %x) {
; CHECK-LABEL: define float @ldexp_ldexp_constants_nsz0
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc nsz float @llvm.ldexp.f32.i32(float [[X]], i32 32)
+; CHECK-NEXT: [[LDEXP1:%.*]] = fmul reassoc float [[X]], 0x41F0000000000000
; CHECK-NEXT: ret float [[LDEXP1]]
;
%ldexp0 = call reassoc nsz float @llvm.ldexp.f32.i32(float %x, i32 8)
@@ -477,7 +477,7 @@ define float @ldexp_ldexp_constants_nsz0(float %x) {
define float @ldexp_ldexp_constants_nsz1(float %x) {
; CHECK-LABEL: define float @ldexp_ldexp_constants_nsz1
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc nsz float @llvm.ldexp.f32.i32(float [[X]], i32 32)
+; CHECK-NEXT: [[LDEXP1:%.*]] = fmul reassoc nsz float [[X]], 0x41F0000000000000
; CHECK-NEXT: ret float [[LDEXP1]]
;
%ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 8)
@@ -641,7 +641,7 @@ define float @ldexp_ldexp_0(float %x, i32 %y) {
define float @ldexp_neg150(float %x) {
; CHECK-LABEL: define float @ldexp_neg150
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -150)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 0.000000e+00
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -150)
@@ -651,7 +651,7 @@ define float @ldexp_neg150(float %x) {
define float @ldexp_neg149(float %x) {
; CHECK-LABEL: define float @ldexp_neg149
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -149)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 0x36A0000000000000
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -149)
@@ -661,7 +661,7 @@ define float @ldexp_neg149(float %x) {
define float @ldexp_neg148(float %x) {
; CHECK-LABEL: define float @ldexp_neg148
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -148)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 0x36B0000000000000
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -148)
@@ -671,7 +671,7 @@ define float @ldexp_neg148(float %x) {
define float @ldexp_neg127(float %x) {
; CHECK-LABEL: define float @ldexp_neg127
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -127)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 0x3800000000000000
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -127)
@@ -681,7 +681,7 @@ define float @ldexp_neg127(float %x) {
define float @ldexp_neg126(float %x) {
; CHECK-LABEL: define float @ldexp_neg126
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -126)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 0x3810000000000000
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -126)
@@ -691,7 +691,7 @@ define float @ldexp_neg126(float %x) {
define float @ldexp_neg125(float %x) {
; CHECK-LABEL: define float @ldexp_neg125
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -125)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 0x3820000000000000
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -125)
@@ -701,7 +701,7 @@ define float @ldexp_neg125(float %x) {
define float @ldexp_neg16(float %x) {
; CHECK-LABEL: define float @ldexp_neg16
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -16)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 0x3EF0000000000000
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -16)
@@ -711,7 +711,7 @@ define float @ldexp_neg16(float %x) {
define float @ldexp_neg8(float %x) {
; CHECK-LABEL: define float @ldexp_neg8
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -8)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 3.906250e-03
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -8)
@@ -721,7 +721,7 @@ define float @ldexp_neg8(float %x) {
define float @ldexp_neg4(float %x) {
; CHECK-LABEL: define float @ldexp_neg4
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -4)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 6.250000e-02
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -4)
@@ -731,7 +731,7 @@ define float @ldexp_neg4(float %x) {
define float @ldexp_neg2(float %x) {
; CHECK-LABEL: define float @ldexp_neg2
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -2)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 2.500000e-01
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -2)
@@ -741,7 +741,7 @@ define float @ldexp_neg2(float %x) {
define float @ldexp_neg1(float %x) {
; CHECK-LABEL: define float @ldexp_neg1
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -1)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 5.000000e-01
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -1)
@@ -760,7 +760,7 @@ define float @ldexp_0(float %x) {
define float @ldexp_1(float %x) {
; CHECK-LABEL: define float @ldexp_1
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 1)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 2.000000e+00
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 1)
@@ -770,7 +770,7 @@ define float @ldexp_1(float %x) {
define float @ldexp_2(float %x) {
; CHECK-LABEL: define float @ldexp_2
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 2)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 4.000000e+00
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 2)
@@ -780,7 +780,7 @@ define float @ldexp_2(float %x) {
define float @ldexp_3(float %x) {
; CHECK-LABEL: define float @ldexp_3
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 3)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 8.000000e+00
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 3)
@@ -790,7 +790,7 @@ define float @ldexp_3(float %x) {
define float @ldexp_10(float %x) {
; CHECK-LABEL: define float @ldexp_10
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 10)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 1.024000e+03
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 10)
@@ -800,7 +800,7 @@ define float @ldexp_10(float %x) {
define float @ldexp_125(float %x) {
; CHECK-LABEL: define float @ldexp_125
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 125)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 0x47C0000000000000
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 125)
@@ -810,7 +810,7 @@ define float @ldexp_125(float %x) {
define float @ldexp_126(float %x) {
; CHECK-LABEL: define float @ldexp_126
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 126)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 0x47D0000000000000
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 126)
@@ -820,17 +820,27 @@ define float @ldexp_126(float %x) {
define float @ldexp_127(float %x) {
; CHECK-LABEL: define float @ldexp_127
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 127)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 0x47E0000000000000
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 127)
ret float %ldexp
}
+define float @ldexp_128(float %x) {
+; CHECK-LABEL: define float @ldexp_128
+; CHECK-SAME: (float [[X:%.*]]) {
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 0x7FF0000000000000
+; CHECK-NEXT: ret float [[LDEXP]]
+;
+ %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 128)
+ ret float %ldexp
+}
+
define <2 x float> @ldexp_3_vector(<2 x float> %x) {
; CHECK-LABEL: define <2 x float> @ldexp_3_vector
; CHECK-SAME: (<2 x float> [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X]], <2 x i32> splat (i32 3))
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul <2 x float> [[X]], splat (float 8.000000e+00)
; CHECK-NEXT: ret <2 x float> [[LDEXP]]
;
%ldexp = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %x, <2 x i32> <i32 3, i32 3>)
@@ -860,7 +870,7 @@ define <2 x float> @ldexp_3_4_vector(<2 x float> %x) {
define float @ldexp_2_flags(float %x) {
; CHECK-LABEL: define float @ldexp_2_flags
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call nsz contract float @llvm.ldexp.f32.i32(float [[X]], i32 2)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul nsz contract float [[X]], 4.000000e+00
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call contract nsz float @llvm.ldexp.f32.i32(float %x, i32 2)
@@ -870,7 +880,7 @@ define float @ldexp_2_flags(float %x) {
define float @ldexp_metadata(float %x) {
; CHECK-LABEL: define float @ldexp_metadata
; CHECK-SAME: (float [[X:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 2), !foo [[META2:![0-9]+]]
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul float [[X]], 4.000000e+00
; CHECK-NEXT: ret float [[LDEXP]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 2), !foo !2
@@ -880,7 +890,7 @@ define float @ldexp_metadata(float %x) {
define float @ldexp_8_contractable(float %x, float %y) {
; CHECK-LABEL: define float @ldexp_8_contractable
; CHECK-SAME: (float [[X:%.*]], float [[Y:%.*]]) {
-; CHECK-NEXT: [[LDEXP:%.*]] = call contract float @llvm.ldexp.f32.i32(float [[X]], i32 2)
+; CHECK-NEXT: [[LDEXP:%.*]] = fmul contract float [[X]], 4.000000e+00
; CHECK-NEXT: [[FADD:%.*]] = fadd contract float [[LDEXP]], [[Y]]
; CHECK-NEXT: ret float [[FADD]]
;
|
fed7047 to
b552c70
Compare
435d0fb to
0b17025
Compare
b552c70 to
892f156
Compare
0b17025 to
44aa41c
Compare
If we can represent this with an fmul, prefer it as a canonical form. More optimizations will understand fmul, and allows contract to fma.
44aa41c to
95c40ed
Compare
dtcxzyw
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/10/builds/18919 Here is the relevant piece of the build log for the reference |
|
Hello, our bot was broken by the test failure. Could you please take a look? Thanks! |
Yeah it should be a subnormal: https://godbolt.org/z/7jbEqz1jz |
|
This can be fixed by bailing out on out-of-scale cases. |
…)" This reverts commit 5eb2ec2.
) Reverts #171731 Fails on a libc test
…fmul" (#171895) Reverts llvm/llvm-project#171731 Fails on a libc test

If we can represent this with an fmul, prefer it as a canonical
form. More optimizations will understand fmul, and allows contract to
fma.