[llvm] df633b2 - [InstCombine] Fold icmp on frexp exponent to fcmp on fabs(x) (#210711)

via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 8 11:16:29 PDT 2026


Author: FathimaHaris
Date: 2026-08-09T02:16:24+08:00
New Revision: df633b22c76997a9b189d02995528610f0858293

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

LOG: [InstCombine] Fold icmp on frexp exponent to fcmp on fabs(x) (#210711)

Recognize signed icmp predicates comparing extractvalue(frexp(x), 1)
against an
integer constant and rewrite them as equivalent fcmp comparisons of
fabs(x)
against the corresponding power-of-two threshold.

frexp(x) returns a mantissa in [0.5, 1) and an exponent E such that
        2^(E-1) <= | x | < 2^E. 
When code only checks that exponent against a constant, the comparison
can be rewritten directly in terms of | x |, dropping the need for
frexp's exponent output:

    icmp spred i32 (extractvalue (frexp x), 1), C
              --> fcmp fpred float (fabs x), 2^ExpVal

Predicate mapping:
          - slt -->  olt (ExpVal = C-1)
          - sgt --> oge (ExpVal = C)

Alive2 Generic proof: https://alive2.llvm.org/ce/z/aqEu4p

Fixes #186554 .

**Test updates**
This patch also updates
frexp-implied-exponent-range-dominating-conditions.ll.

The _nofold tests in this file were originally checking that the
dominating
condition alone could not fold the comparison to a constant. After this
patch,
the remaining frexp exponent comparison is itself recognized by the new
fold,
so these tests now simplify to fabs/fcmp.

At the -passes=instcombine pass , the transformed IR temporarily
contains two fabs calls (one from the dominating-condition fold and one
introduced by this transform). A later optimization pass in the full -O3
pipeline
removes the duplicate fabs, producing the fully simplified IR.

Alive2 proofs:
- -passes=instcombine : https://alive2.llvm.org/ce/z/ZLHh8V
- Full -O3 pipeline : https://alive2.llvm.org/ce/z/5P3pUC

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
    llvm/test/Transforms/InstCombine/frexp-implied-exponent-range-dominating-conditions.ll
    llvm/test/Transforms/InstCombine/known-range-frexp-exp.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 2da5d2464b674..cc79f67e9f32f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3652,6 +3652,51 @@ Instruction *InstCombinerImpl::foldICmpInstWithConstant(ICmpInst &Cmp) {
       if (Instruction *I = foldICmpIntrinsicWithConstant(Cmp, II, *C))
         return I;
 
+    {
+      // icmp slt/sgt (extractvalue (frexp X), 1), C -->
+      //                         fcmp olt/oge (fabs X), 2^ExpVal
+      // slt -> olt, ExpVal = C-1; sgt -> oge, ExpVal = C.
+      Value *X;
+      if (match(Cmp.getOperand(0),
+                m_OneUse(m_ExtractValue<1>(
+                    m_OneUse(m_Intrinsic<Intrinsic::frexp>(m_Value(X))))))) {
+        ICmpInst::Predicate Pred = Cmp.getPredicate();
+        APInt Exp;
+        FCmpInst::Predicate NewPred;
+        bool ValidPred = true;
+
+        switch (Pred) {
+        case ICmpInst::ICMP_SLT:
+          NewPred = FCmpInst::FCMP_OLT;
+          Exp = *C - 1;
+          break;
+        case ICmpInst::ICMP_SGT:
+          NewPred = FCmpInst::FCMP_OGE;
+          Exp = *C;
+          break;
+        default:
+          ValidPred = false;
+          break;
+        }
+
+        if (ValidPred) {
+          const fltSemantics &Sem =
+              X->getType()->getScalarType()->getFltSemantics();
+          int MaxExp = APFloat::semanticsMaxExponent(Sem);
+
+          if (!Exp.isNegative() && Exp.sle(MaxExp + 1) &&
+              isKnownNeverInfOrNaN(X, SQ.getWithInstruction(&Cmp))) {
+            int ExpVal = static_cast<int>(Exp.getSExtValue());
+            APFloat CmpConst = scalbn(APFloat::getOne(Sem), ExpVal,
+                                      APFloat::rmNearestTiesToEven);
+            Value *Fabs = Builder.CreateFAbs(X);
+            return new FCmpInst(NewPred, Fabs,
+                                ConstantFP::get(X->getType(), CmpConst));
+          }
+        }
+      }
+    }
+
     // (extractval ([s/u]subo X, Y), 0) == 0 --> X == Y
     // (extractval ([s/u]subo X, Y), 0) != 0 --> X != Y
     // TODO: This checks one-use, but that is not strictly necessary.

diff  --git a/llvm/test/Transforms/InstCombine/frexp-implied-exponent-range-dominating-conditions.ll b/llvm/test/Transforms/InstCombine/frexp-implied-exponent-range-dominating-conditions.ll
index 7226e64b30971..a7c40a96067cd 100644
--- a/llvm/test/Transforms/InstCombine/frexp-implied-exponent-range-dominating-conditions.ll
+++ b/llvm/test/Transforms/InstCombine/frexp-implied-exponent-range-dominating-conditions.ll
@@ -1244,9 +1244,8 @@ define i1 @issue208192(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:    [[C:%.*]] = fcmp ugt float [[ABS]], 1.000000e+00
 ; CHECK-NEXT:    br i1 [[C]], label %[[LARGE:.*]], label %[[SMALL:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 1
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 1.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false
@@ -1306,9 +1305,8 @@ define i1 @frexp_exp_ogt_1_nofold(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:    [[C:%.*]] = fcmp ogt float [[ABS]], 1.000000e+00
 ; CHECK-NEXT:    br i1 [[C]], label %[[LARGE:.*]], label %[[SMALL:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 1
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 1.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false
@@ -1420,9 +1418,8 @@ define i1 @frexp_exp_ugt_1_nofold(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:    [[C:%.*]] = fcmp ugt float [[ABS]], 1.000000e+00
 ; CHECK-NEXT:    br i1 [[C]], label %[[LARGE:.*]], label %[[SMALL:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 1
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 1.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false
@@ -1591,9 +1588,8 @@ define i1 @frexp_exp_ole_1_nofold(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:    [[C:%.*]] = fcmp ugt float [[ABS]], 1.000000e+00
 ; CHECK-NEXT:    br i1 [[C]], label %[[LARGE:.*]], label %[[SMALL:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 1
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 1.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false
@@ -1705,9 +1701,8 @@ define i1 @frexp_exp_ule_1_nofold(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:    [[C:%.*]] = fcmp ule float [[ABS]], 1.000000e+00
 ; CHECK-NEXT:    br i1 [[C]], label %[[SMALL:.*]], label %[[LARGE:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 1
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 1.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false
@@ -1762,9 +1757,8 @@ define i1 @frexp_exp_oeq_1_nofold(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:    [[C:%.*]] = fcmp oeq float [[ABS]], 1.000000e+00
 ; CHECK-NEXT:    br i1 [[C]], label %[[SMALL:.*]], label %[[LARGE:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 1
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 1.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false
@@ -1819,9 +1813,8 @@ define i1 @frexp_exp_ueq_1_nofold(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:    [[C:%.*]] = fcmp ueq float [[ABS]], 1.000000e+00
 ; CHECK-NEXT:    br i1 [[C]], label %[[SMALL:.*]], label %[[LARGE:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 1
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 1.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false
@@ -1876,9 +1869,8 @@ define i1 @frexp_exp_one_1_nofold(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:    [[C:%.*]] = fcmp ueq float [[ABS]], 1.000000e+00
 ; CHECK-NEXT:    br i1 [[C]], label %[[SMALL:.*]], label %[[LARGE:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 1
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 1.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false
@@ -1933,9 +1925,8 @@ define i1 @frexp_exp_une_1_nofold(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:    [[C:%.*]] = fcmp une float [[ABS]], 1.000000e+00
 ; CHECK-NEXT:    br i1 [[C]], label %[[LARGE:.*]], label %[[SMALL:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 1
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 1.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false
@@ -2199,9 +2190,8 @@ define i1 @frexp_exp_olt_4_nofold(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:    [[C:%.*]] = fcmp olt float [[ABS]], 4.000000e+00
 ; CHECK-NEXT:    br i1 [[C]], label %[[SMALL:.*]], label %[[LARGE:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 2
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 2.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false
@@ -2258,9 +2248,8 @@ define i1 @frexp_exp_ole_4_nofold(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:    [[C:%.*]] = fcmp ugt float [[ABS]], 4.000000e+00
 ; CHECK-NEXT:    br i1 [[C]], label %[[LARGE:.*]], label %[[SMALL:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 3
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 4.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false
@@ -2317,9 +2306,8 @@ define i1 @frexp_exp_olt_3_nofold(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:    [[C:%.*]] = fcmp olt float [[ABS]], 3.000000e+00
 ; CHECK-NEXT:    br i1 [[C]], label %[[SMALL:.*]], label %[[LARGE:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 2
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 2.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false
@@ -2374,9 +2362,8 @@ define i1 @frexp_exp_ole_3_nofold(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:    [[C:%.*]] = fcmp ugt float [[ABS]], 3.000000e+00
 ; CHECK-NEXT:    br i1 [[C]], label %[[LARGE:.*]], label %[[SMALL:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 2
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 2.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false
@@ -2434,9 +2421,8 @@ define i1 @frexp_exp_negative_limit(float nofpclass(nan inf) %x) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    br i1 true, label %[[SMALL:.*]], label %[[LARGE:.*]]
 ; CHECK:       [[SMALL]]:
-; CHECK-NEXT:    [[FX:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
-; CHECK-NEXT:    [[E:%.*]] = extractvalue { float, i32 } [[FX]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[E]], 2
+; CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[R:%.*]] = fcmp olt float [[TMP0]], 2.000000e+00
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       [[LARGE]]:
 ; CHECK-NEXT:    ret i1 false

diff  --git a/llvm/test/Transforms/InstCombine/known-range-frexp-exp.ll b/llvm/test/Transforms/InstCombine/known-range-frexp-exp.ll
index c6f3153f8c435..50ee28dcbe8dc 100644
--- a/llvm/test/Transforms/InstCombine/known-range-frexp-exp.ll
+++ b/llvm/test/Transforms/InstCombine/known-range-frexp-exp.ll
@@ -1,6 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt -S -passes=instcombine < %s | FileCheck %s
 
+declare void @use.i32(i32)
+
 define i32 @frexp_f32_clamp_min(float %x) {
 ; CHECK-LABEL: define i32 @frexp_f32_clamp_min(
 ; CHECK-SAME: float [[X:%.*]]) {
@@ -155,3 +157,142 @@ define i32 @frexp_f32_clamp_min_no_nan_inf(float nofpclass(nan inf) %x) {
   %clamp = call i32 @llvm.smax.i32(i32 %exp, i32 -148)
   ret i32 %clamp
 }
+
+;Fold icmp on frexp's exponent result into an fcmp against fabs(x).
+; Float exponent signed less-than comparison.
+define i1 @frexp_slt_float(float nofpclass(nan inf) %x) {
+; CHECK-LABEL: define i1 @frexp_slt_float(
+; CHECK-SAME: float nofpclass(nan inf) [[X:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[V2:%.*]] = fcmp olt float [[TMP1]], f0x4B000000
+; CHECK-NEXT:    ret i1 [[V2]]
+;
+  %v0 = call { float, i32 } @llvm.frexp.f32.i32(float %x)
+  %v1 = extractvalue { float, i32 } %v0, 1
+  %v2 = icmp slt i32 %v1, 24
+  ret i1 %v2
+}
+
+; Double exponent signed less-than comparison.
+define i1 @frexp_slt_double(double nofpclass(nan inf) %x) {
+; CHECK-LABEL: define i1 @frexp_slt_double(
+; CHECK-SAME: double nofpclass(nan inf) [[X:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[X]])
+; CHECK-NEXT:    [[V2:%.*]] = fcmp olt double [[TMP1]], 5.120000e+02
+; CHECK-NEXT:    ret i1 [[V2]]
+;
+  %v0 = call { double, i32 } @llvm.frexp.f64.i32(double %x)
+  %v1 = extractvalue { double, i32 } %v0, 1
+  %v2 = icmp slt i32 %v1, 10
+  ret i1 %v2
+}
+
+;128 bit exponent signed less-than comparison
+define i1 @frexp_slt_fp128(fp128 nofpclass(nan inf) %x) {
+; CHECK-LABEL: define i1 @frexp_slt_fp128(
+; CHECK-SAME: fp128 nofpclass(nan inf) [[X:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call fp128 @llvm.fabs.f128(fp128 [[X]])
+; CHECK-NEXT:    [[V2:%.*]] = fcmp olt fp128 [[TMP1]], f0x7FFE0000000000000000000000000000
+; CHECK-NEXT:    ret i1 [[V2]]
+;
+  %v0 = call { fp128, i128 } @llvm.frexp.fp128.i128(fp128 %x)
+  %v1 = extractvalue { fp128, i128 } %v0, 1
+  %v2 = icmp slt i128 %v1, 16384
+  ret i1 %v2
+}
+
+; Float exponent signed greater-than comparison.
+define i1 @frexp_sgt_float(float nofpclass(nan inf) %x) {
+; CHECK-LABEL: define i1 @frexp_sgt_float(
+; CHECK-SAME: float nofpclass(nan inf) [[X:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[V2:%.*]] = fcmp oge float [[TMP1]], 1.310720e+05
+; CHECK-NEXT:    ret i1 [[V2]]
+;
+  %v0 = call { float, i32 } @llvm.frexp.f32.i32(float %x)
+  %v1 = extractvalue { float, i32 } %v0, 1
+  %v2 = icmp sgt i32 %v1, 17
+  ret i1 %v2
+}
+
+; Splat vector test.
+define <2 x i1> @frexp_slt_splat(<2 x float> nofpclass(nan inf) %x) {
+; CHECK-LABEL: define <2 x i1> @frexp_slt_splat(
+; CHECK-SAME: <2 x float> nofpclass(nan inf) [[X:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[X]])
+; CHECK-NEXT:    [[V2:%.*]] = fcmp olt <2 x float> [[TMP1]], splat (float 1.600000e+01)
+; CHECK-NEXT:    ret <2 x i1> [[V2]]
+;
+  %v0 = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> %x)
+  %v1 = extractvalue { <2 x float>, <2 x i32> } %v0, 1
+  %v2 = icmp slt <2 x i32> %v1, splat (i32 5)
+  ret <2 x i1> %v2
+}
+
+; Negative test - exponent may come from a NaN or Inf input.
+define i1 @frexp_slt_no_fold_maybe_nan_inf(float %x) {
+; CHECK-LABEL: define i1 @frexp_slt_no_fold_maybe_nan_inf(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
+; CHECK-NEXT:    [[V1:%.*]] = extractvalue { float, i32 } [[V0]], 1
+; CHECK-NEXT:    [[V2:%.*]] = icmp slt i32 [[V1]], 24
+; CHECK-NEXT:    ret i1 [[V2]]
+;
+  %v0 = call { float, i32 } @llvm.frexp.f32.i32(float %x)
+  %v1 = extractvalue { float, i32 } %v0, 1
+  %v2 = icmp slt i32 %v1, 24
+  ret i1 %v2
+}
+
+; Negative test - Negative exponent.
+define i1 @frexp_slt_no_fold_negative_exp(float nofpclass(nan inf) %x) {
+; CHECK-LABEL: define i1 @frexp_slt_no_fold_negative_exp(
+; CHECK-SAME: float nofpclass(nan inf) [[X:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
+; CHECK-NEXT:    [[V1:%.*]] = extractvalue { float, i32 } [[V0]], 1
+; CHECK-NEXT:    [[V2:%.*]] = icmp slt i32 [[V1]], 0
+; CHECK-NEXT:    ret i1 [[V2]]
+;
+  %v0 = call { float, i32 } @llvm.frexp.f32.i32(float %x)
+  %v1 = extractvalue { float, i32 } %v0, 1
+  %v2 = icmp slt i32 %v1, 0
+  ret i1 %v2
+}
+
+; Negative test-  extractvalue has an additional use.
+define i1 @frexp_slt_no_fold_exp_multi_use(float nofpclass(nan inf) %x) {
+; CHECK-LABEL: define i1 @frexp_slt_no_fold_exp_multi_use(
+; CHECK-SAME: float nofpclass(nan inf) [[X:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
+; CHECK-NEXT:    [[V1:%.*]] = extractvalue { float, i32 } [[V0]], 1
+; CHECK-NEXT:    call void @use.i32(i32 [[V1]])
+; CHECK-NEXT:    [[V2:%.*]] = icmp slt i32 [[V1]], 5
+; CHECK-NEXT:    ret i1 [[V2]]
+;
+  %v0 = call { float, i32 } @llvm.frexp.f32.i32(float %x)
+  %v1 = extractvalue { float, i32 } %v0, 1
+  call void @use.i32(i32 %v1)
+  %v2 = icmp slt i32 %v1, 5
+  ret i1 %v2
+}
+
+;Negative test- frexp result has multiple use .
+define { float, i1 } @frexp_slt_no_fold_mantissa_use(float nofpclass(nan inf) %x) {
+; CHECK-LABEL: define { float, i1 } @frexp_slt_no_fold_mantissa_use(
+; CHECK-SAME: float nofpclass(nan inf) [[X:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
+; CHECK-NEXT:    [[MANT:%.*]] = extractvalue { float, i32 } [[V0]], 0
+; CHECK-NEXT:    [[EXP:%.*]] = extractvalue { float, i32 } [[V0]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[EXP]], 24
+; CHECK-NEXT:    [[R0:%.*]] = insertvalue { float, i1 } poison, float [[MANT]], 0
+; CHECK-NEXT:    [[R1:%.*]] = insertvalue { float, i1 } [[R0]], i1 [[CMP]], 1
+; CHECK-NEXT:    ret { float, i1 } [[R1]]
+;
+  %v0 = call { float, i32 } @llvm.frexp.f32.i32(float %x)
+  %mant = extractvalue { float, i32 } %v0, 0
+  %exp = extractvalue { float, i32 } %v0, 1
+  %cmp = icmp slt i32 %exp, 24
+  %r0 = insertvalue { float, i1 } poison, float %mant, 0
+  %r1 = insertvalue { float, i1 } %r0, i1 %cmp, 1
+  ret { float, i1 } %r1
+}


        


More information about the llvm-commits mailing list