[llvm] [InstCombine] Fix `frexp(frexp(x)) -> frexp(x)` fold (PR #138837)

Iris Shi via llvm-commits llvm-commits at lists.llvm.org
Wed May 7 02:59:31 PDT 2025


https://github.com/el-ev updated https://github.com/llvm/llvm-project/pull/138837

>From c7afb92733c6b14d80961e7617affd6acf8a19d4 Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Wed, 7 May 2025 17:32:31 +0800
Subject: [PATCH 1/2] [InstCombine] Fix `frexp(frexp(x)) -> frexp(x)` fold

---
 llvm/lib/Analysis/InstructionSimplify.cpp            |  9 ---------
 llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 12 ++++++++++++
 .../{InstSimplify => InstCombine}/frexp.ll           | 11 +++++++----
 3 files changed, 19 insertions(+), 13 deletions(-)
 rename llvm/test/Transforms/{InstSimplify => InstCombine}/frexp.ll (96%)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 5a2943de9066e..85e3be9cc45c3 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -6377,15 +6377,6 @@ static Value *simplifyUnaryIntrinsic(Function *F, Value *Op0,
     if (isSplatValue(Op0))
       return Op0;
     break;
-  case Intrinsic::frexp: {
-    // Frexp is idempotent with the added complication of the struct return.
-    if (match(Op0, m_ExtractValue<0>(m_Value(X)))) {
-      if (match(X, m_Intrinsic<Intrinsic::frexp>(m_Value())))
-        return X;
-    }
-
-    break;
-  }
   default:
     break;
   }
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 3e78b20e41f0d..624c97cf39de3 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3799,6 +3799,18 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     }
     break;
   }
+  case Intrinsic::frexp: {
+    Value *X;
+    // Frexp is idempotent with the added complication of the struct return.
+    if (match(II->getArgOperand(0), m_ExtractValue<0>(m_Value(X)))) {
+      if (match(X, m_Intrinsic<Intrinsic::frexp>(m_Value()))) {
+        X = Builder.CreateInsertValue(
+            X, ConstantInt::get(II->getType()->getStructElementType(1), 0), 1);
+        return replaceInstUsesWith(*II, X);
+      }
+    }
+    break;
+  }
   default: {
     // Handle target specific intrinsics
     std::optional<Instruction *> V = targetInstCombineIntrinsic(*II);
diff --git a/llvm/test/Transforms/InstSimplify/frexp.ll b/llvm/test/Transforms/InstCombine/frexp.ll
similarity index 96%
rename from llvm/test/Transforms/InstSimplify/frexp.ll
rename to llvm/test/Transforms/InstCombine/frexp.ll
index 34cfce92bac43..6541f0d77a093 100644
--- a/llvm/test/Transforms/InstSimplify/frexp.ll
+++ b/llvm/test/Transforms/InstCombine/frexp.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
-; RUN: opt -S -passes=instsimplify %s | FileCheck %s
+; RUN: opt -S -passes=instcombine %s | FileCheck %s
 
 declare { float, i32 } @llvm.frexp.f32.i32(float)
 declare { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float>)
@@ -12,7 +12,8 @@ define { float, i32 } @frexp_frexp(float %x) {
 ; CHECK-LABEL: define { float, i32 } @frexp_frexp(
 ; CHECK-SAME: float [[X:%.*]]) {
 ; CHECK-NEXT:    [[FREXP0:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    ret { float, i32 } [[FREXP0]]
+; CHECK-NEXT:    [[FREXP1:%.*]] = insertvalue { float, i32 } [[FREXP0]], i32 0, 1
+; CHECK-NEXT:    ret { float, i32 } [[FREXP1]]
 ;
   %frexp0 = call { float, i32 } @llvm.frexp.f32.i32(float %x)
   %frexp0.0 = extractvalue { float, i32 } %frexp0, 0
@@ -24,7 +25,8 @@ define { <2 x float>, <2 x i32> } @frexp_frexp_vector(<2 x float> %x) {
 ; CHECK-LABEL: define { <2 x float>, <2 x i32> } @frexp_frexp_vector(
 ; CHECK-SAME: <2 x float> [[X:%.*]]) {
 ; CHECK-NEXT:    [[FREXP0:%.*]] = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> [[X]])
-; CHECK-NEXT:    ret { <2 x float>, <2 x i32> } [[FREXP0]]
+; CHECK-NEXT:    [[FREXP1:%.*]] = insertvalue { <2 x float>, <2 x i32> } [[FREXP0]], <2 x i32> zeroinitializer, 1
+; CHECK-NEXT:    ret { <2 x float>, <2 x i32> } [[FREXP1]]
 ;
   %frexp0 = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> %x)
   %frexp0.0 = extractvalue { <2 x float>, <2 x i32> } %frexp0, 0
@@ -47,7 +49,8 @@ define { <vscale x 2 x float>, <vscale x 2 x i32> } @frexp_frexp_scalable_vector
 ; CHECK-LABEL: define { <vscale x 2 x float>, <vscale x 2 x i32> } @frexp_frexp_scalable_vector(
 ; CHECK-SAME: <vscale x 2 x float> [[X:%.*]]) {
 ; CHECK-NEXT:    [[FREXP0:%.*]] = call { <vscale x 2 x float>, <vscale x 2 x i32> } @llvm.frexp.nxv2f32.nxv2i32(<vscale x 2 x float> [[X]])
-; CHECK-NEXT:    ret { <vscale x 2 x float>, <vscale x 2 x i32> } [[FREXP0]]
+; CHECK-NEXT:    [[FREXP1:%.*]] = insertvalue { <vscale x 2 x float>, <vscale x 2 x i32> } [[FREXP0]], <vscale x 2 x i32> zeroinitializer, 1
+; CHECK-NEXT:    ret { <vscale x 2 x float>, <vscale x 2 x i32> } [[FREXP1]]
 ;
   %frexp0 = call { <vscale x 2 x float>, <vscale x 2 x i32> } @llvm.frexp.nxv2f32.nxv2i32(<vscale x 2 x float> %x)
   %frexp0.0 = extractvalue { <vscale x 2 x float>, <vscale x 2 x i32> } %frexp0, 0

>From 93fcdea390991e03db544a19dd242d18cdd509e9 Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Wed, 7 May 2025 17:59:04 +0800
Subject: [PATCH 2/2] apply suggestions

---
 llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 624c97cf39de3..e571738d74ac3 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3801,11 +3801,14 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
   }
   case Intrinsic::frexp: {
     Value *X;
-    // Frexp is idempotent with the added complication of the struct return.
+    // 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, ConstantInt::get(II->getType()->getStructElementType(1), 0), 1);
+            X, Constant::getNullValue(II->getType()->getStructElementType(1)),
+            1);
         return replaceInstUsesWith(*II, X);
       }
     }



More information about the llvm-commits mailing list