[llvm] 14baa81 - [InstCombine] Fix invalid IR when folding frexp(frexp(x)) with mismatched exponent types (#202419)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 8 13:46:27 PDT 2026


Author: Justin Lebar
Date: 2026-06-08T20:46:22Z
New Revision: 14baa81e24fcd22cca188cabe3a6c76debd14c95

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

LOG: [InstCombine] Fix invalid IR when folding frexp(frexp(x)) with mismatched exponent types (#202419)

Instcombine folds the idempotent frexp pattern

    %inner = call { double, i64 } @llvm.frexp.f64.i64(double %x)
    %f     = extractvalue { double, i64 } %inner, 0
    %outer = call { double, i32 } @llvm.frexp.f64.i32(double %f)

to `{ %f, 0 }`, because the fraction after the first frexp call is known
0.  It did this by reusing the inner frexp's result struct and
overwriting field 1 with zero.

But you can see in this example that reusing the inner frexp's
result struct is invalid, because that call returns { double, i64 },
whereas the second call returns { double, i32 }.

Fix this by building the new struct instead of modifying the old one.

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
    llvm/test/Transforms/InstCombine/frexp.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 57013391be87e..35c60e6eb3753 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -4256,17 +4256,17 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       return I;
     break;
   case Intrinsic::frexp: {
-    Value *X;
-    // The first result is idempotent with the added complication of the struct
-    // return, and the second result is zero because the value is already
-    // normalized.
-    if (match(II->getArgOperand(0), m_ExtractValue<0>(m_Value(X)))) {
-      if (match(X, m_Intrinsic<Intrinsic::frexp>(m_Value()))) {
-        X = Builder.CreateInsertValue(
-            X, Constant::getNullValue(II->getType()->getStructElementType(1)),
-            1);
-        return replaceInstUsesWith(*II, X);
-      }
+    // frexp(frexp(x).fract) -> { frexp(x).fract, 0 }: the fraction operand is
+    // already normalized, so the first result is idempotent and the second is
+    // zero.
+    if (match(II->getArgOperand(0),
+              m_ExtractValue<0>(m_Intrinsic<Intrinsic::frexp>(m_Value())))) {
+      Value *Res = Builder.CreateInsertValue(PoisonValue::get(II->getType()),
+                                             II->getArgOperand(0), 0);
+      Res = Builder.CreateInsertValue(
+          Res, Constant::getNullValue(II->getType()->getStructElementType(1)),
+          1);
+      return replaceInstUsesWith(*II, Res);
     }
     break;
   }

diff  --git a/llvm/test/Transforms/InstCombine/frexp.ll b/llvm/test/Transforms/InstCombine/frexp.ll
index aa335c82469ad..56d2898cae5c6 100644
--- a/llvm/test/Transforms/InstCombine/frexp.ll
+++ b/llvm/test/Transforms/InstCombine/frexp.ll
@@ -293,3 +293,21 @@ define { <2 x float>, <2 x i32> } @frexp_splat_undef_inf() {
   %ret = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> <float undef, float 0x7FF0000000000000>)
   ret { <2 x float>, <2 x i32> } %ret
 }
+
+; The inner and outer frexp use 
diff erent exponent integer types. The fold still
+; applies; the result is rebuilt with the outer's struct type rather than
+; reusing the inner result struct (which would be a type-mismatched insertvalue).
+define { double, i32 } @frexp_frexp_
diff erent_exp_type(double %x) {
+; CHECK-LABEL: define { double, i32 } @frexp_frexp_
diff erent_exp_type(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[FREXP0:%.*]] = call { double, i64 } @llvm.frexp.f64.i64(double [[X]])
+; CHECK-NEXT:    [[FREXP0_0:%.*]] = extractvalue { double, i64 } [[FREXP0]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { double, i32 } poison, double [[FREXP0_0]], 0
+; CHECK-NEXT:    [[FREXP1:%.*]] = insertvalue { double, i32 } [[TMP1]], i32 0, 1
+; CHECK-NEXT:    ret { double, i32 } [[FREXP1]]
+;
+  %frexp0 = call { double, i64 } @llvm.frexp.f64.i64(double %x)
+  %frexp0.0 = extractvalue { double, i64 } %frexp0, 0
+  %frexp1 = call { double, i32 } @llvm.frexp.f64.i32(double %frexp0.0)
+  ret { double, i32 } %frexp1
+}


        


More information about the llvm-commits mailing list