[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