[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