Skip to content

Conversation

@arsenm
Copy link
Contributor

@arsenm arsenm commented Dec 10, 2025

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

@arsenm arsenm added floating-point Floating-point math llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:ir llvm:transforms labels Dec 10, 2025 — with Graphite App
@arsenm arsenm marked this pull request as ready for review December 10, 2025 23:02
@arsenm arsenm requested a review from nikic as a code owner December 10, 2025 23:02
@llvmbot
Copy link
Member

llvmbot commented Dec 10, 2025

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-ir

Author: Matt Arsenault (arsenm)

Changes

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


Full diff: https://github.com/llvm/llvm-project/pull/171731.diff

3 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp (+13)
  • (modified) llvm/test/Transforms/InstCombine/fold-select-fmul-if-zero.ll (+2-8)
  • (modified) llvm/test/Transforms/InstCombine/ldexp.ll (+36-26)
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]]
 ;

@arsenm arsenm force-pushed the users/arsenm/valuetracking/fmul-large-exponent-constant-is-not-subnormal branch from fed7047 to b552c70 Compare December 11, 2025 10:41
@arsenm arsenm force-pushed the users/arsenm/instcombine-fold-ldexp-constant-to-fmul-pow2 branch from 435d0fb to 0b17025 Compare December 11, 2025 10:41
@arsenm arsenm force-pushed the users/arsenm/valuetracking/fmul-large-exponent-constant-is-not-subnormal branch from b552c70 to 892f156 Compare December 11, 2025 12:07
@arsenm arsenm force-pushed the users/arsenm/instcombine-fold-ldexp-constant-to-fmul-pow2 branch from 0b17025 to 44aa41c Compare December 11, 2025 12:07
Base automatically changed from users/arsenm/valuetracking/fmul-large-exponent-constant-is-not-subnormal to main December 11, 2025 12:40
If we can represent this with an fmul, prefer it as a canonical
form. More optimizations will understand fmul, and allows contract to
fma.
@arsenm arsenm force-pushed the users/arsenm/instcombine-fold-ldexp-constant-to-fmul-pow2 branch from 44aa41c to 95c40ed Compare December 11, 2025 12:48
Copy link
Member

@dtcxzyw dtcxzyw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@arsenm arsenm merged commit 5eb2ec2 into main Dec 11, 2025
10 checks passed
@arsenm arsenm deleted the users/arsenm/instcombine-fold-ldexp-constant-to-fmul-pow2 branch December 11, 2025 18:20
@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 11, 2025

LLVM Buildbot has detected a new failure on builder openmp-offload-amdgpu-runtime-2 running on rocm-worker-hw-02 while building llvm at step 10 "Add check check-libc-amdgcn-amd-amdhsa".

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
Step 10 (Add check check-libc-amdgcn-amd-amdhsa) failure: test (failure)
...
[ RUN      ] LlvmLibcUIntClassTest.OtherWordTypeTests
[       OK ] LlvmLibcUIntClassTest.OtherWordTypeTests (1 us)
[ RUN      ] LlvmLibcUIntClassTest.OtherWordTypeCastTests
[       OK ] LlvmLibcUIntClassTest.OtherWordTypeCastTests (2 us)
[ RUN      ] LlvmLibcUIntClassTest.SignedOtherWordTypeCastTests
[       OK ] LlvmLibcUIntClassTest.SignedOtherWordTypeCastTests (1 us)
[ RUN      ] LlvmLibcUIntClassTest.MixedSignednessOtherWordTypeCastTests
[       OK ] LlvmLibcUIntClassTest.MixedSignednessOtherWordTypeCastTests (1 us)
Ran 88 tests.  PASS: 88  FAIL: 0
[2432/3298] Running hermetic test libc.test.src.math.ldexp_test.__hermetic__
FAILED: libc/test/src/math/libc.test.src.math.ldexp_test.__hermetic__.__cmd__ /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-amdgcn-amd-amdhsa-bins/libc/test/src/math/libc.test.src.math.ldexp_test.__hermetic__.__cmd__ 
cd /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-amdgcn-amd-amdhsa-bins/libc/test/src/math && /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/bin/amdhsa-loader /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-amdgcn-amd-amdhsa-bins/libc/test/src/math/libc.test.src.math.ldexp_test.__hermetic__.__build__
[==========] Running 6 tests from 1 test suite.
[ RUN      ] LlvmLibcLdExpTest.SpecialNumbers
[       OK ] LlvmLibcLdExpTest.SpecialNumbers (25 us)
[ RUN      ] LlvmLibcLdExpTest.PowersOfTwo
[       OK ] LlvmLibcLdExpTest.PowersOfTwo (60 us)
[ RUN      ] LlvmLibcLdExpTest.OverFlow
[       OK ] LlvmLibcLdExpTest.OverFlow (108 us)
[ RUN      ] LlvmLibcLdExpTest.UnderflowToZeroOnNormal
[       OK ] LlvmLibcLdExpTest.UnderflowToZeroOnNormal (6 us)
[ RUN      ] LlvmLibcLdExpTest.UnderflowToZeroOnSubnormal
[       OK ] LlvmLibcLdExpTest.UnderflowToZeroOnSubnormal (5 us)
[ RUN      ] LlvmLibcLdExpTest.NormalOperation
/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/libc/test/src/math/LdExpTest.h:137: FAILURE
      Expected: result_bits.is_zero()
      Which is: 1
To be equal to: false
      Which is: 0
[  FAILED  ] LlvmLibcLdExpTest.NormalOperation
Ran 6 tests.  PASS: 5  FAIL: 1
[2433/3298] Linking CXX executable libc/test/src/math/smoke/libc.test.src.math.smoke.atan2_test.__hermetic__.__build__
[2434/3298] Running hermetic test libc.test.src.__support.arg_list_test.__hermetic__
[==========] Running 5 tests from 1 test suite.
[ RUN      ] LlvmLibcArgListTest.BasicUsage
[       OK ] LlvmLibcArgListTest.BasicUsage (7 us)
[ RUN      ] LlvmLibcArgListTest.CopyConstructor
[       OK ] LlvmLibcArgListTest.CopyConstructor (3 us)
[ RUN      ] LlvmLibcArgListTest.TestPrimitiveTypes
[       OK ] LlvmLibcArgListTest.TestPrimitiveTypes (5 us)
[ RUN      ] LlvmLibcArgListTest.TestStructTypes
[       OK ] LlvmLibcArgListTest.TestStructTypes (2 us)
[ RUN      ] LlvmLibcArgListTest.TestVectorTypes
[       OK ] LlvmLibcArgListTest.TestVectorTypes (4 us)
Ran 5 tests.  PASS: 5  FAIL: 0
[2435/3298] Running hermetic test libc.test.src.__support.CPP.optional_test.__hermetic__
[==========] Running 1 test from 1 test suite.
[ RUN      ] LlvmLibcOptionalTest.Tests
[       OK ] LlvmLibcOptionalTest.Tests (4 us)

@Kewen12
Copy link
Contributor

Kewen12 commented Dec 11, 2025

Hello, our bot was broken by the test failure. Could you please take a look? Thanks!

@dtcxzyw
Copy link
Member

dtcxzyw commented Dec 11, 2025

   // Start with a normal number high exponent but pass a very low number for
    // exp. The result should be a subnormal number.
    x = NormalFloat(Sign::POS, FPBits::EXP_BIAS, NormalFloat::ONE);
    int exp = -FPBits::MAX_BIASED_EXPONENT - 5;
    T result = func(x, exp);
    FPBits result_bits(result);
    ASSERT_FALSE(result_bits.is_zero());
    // Verify that the result is indeed subnormal.
    ASSERT_EQ(result_bits.get_biased_exponent(), uint16_t(0));

Yeah it should be a subnormal: https://godbolt.org/z/7jbEqz1jz

@dtcxzyw
Copy link
Member

dtcxzyw commented Dec 11, 2025

This can be fixed by bailing out on out-of-scale cases.

arsenm added a commit that referenced this pull request Dec 11, 2025
arsenm added a commit that referenced this pull request Dec 11, 2025
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Dec 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

floating-point Floating-point math llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:ir llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants