[llvm] [InstCombine] Optimize unneeded float to int cast when icmp (PR #155501)

Artem Trokhymchuk via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 7 06:16:20 PDT 2025


https://github.com/trokhymchuk updated https://github.com/llvm/llvm-project/pull/155501

>From 8e6daa19e69791e3d541912e9fb878242d8f78b2 Mon Sep 17 00:00:00 2001
From: Artem Trokhymchuk <trkhmchk at gmail.com>
Date: Tue, 26 Aug 2025 00:28:10 +0300
Subject: [PATCH 1/3] [InstCombint] add icmp <cond> (fptosi %x) -> fcmp <cond>
 %y optimization tests

Add optimization test reducing unneded float-to-int cast when
comparing numbers:
* icmp sgt (fptosi %x), <negative> -> fcmp ogt %x, <negative>
* icmp sgt (fptosi %x), <non-negative> -> fcmp oge %x, <non-negative + 1>
* icmp slt (fptosi %x), <positive> -> fcmp olt %x, <positive>
* icmp slt (fptosi %x), <non-positive> -> fcmp ole %x, <non-positive - 1>
---
 llvm/test/Transforms/InstCombine/icmp.ll | 305 +++++++++++++++++++++++
 1 file changed, 305 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll
index 0faa7da482ef2..eccf9ec39da61 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -6054,3 +6054,308 @@ define i1 @icmp_samesign_logical_or(i32 %In) {
   %V = select i1 %c1, i1 true, i1 %c2
   ret i1 %V
 }
+
+; https://alive2.llvm.org/ce/z/XtQS6H
+define i1 @float_to_int_comparing_constant1_positive1(float %arg0) {
+; CHECK-LABEL: define i1 @float_to_int_comparing_constant1_positive1(
+; CHECK-SAME: float [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi float [[ARG0]] to i32
+; CHECK-NEXT:    [[V1:%.*]] = icmp sgt i32 [[V0]], -1
+; CHECK-NEXT:    ret i1 [[V1]]
+;
+  %v0 = fptosi float %arg0 to i32
+  %v1 = icmp sgt i32 %v0, -1
+  ret i1 %v1
+}
+
+; https://alive2.llvm.org/ce/z/ZycBgc
+define i1 @float_to_int_comparing_constant1_positive2(float %arg0) {
+; CHECK-LABEL: define i1 @float_to_int_comparing_constant1_positive2(
+; CHECK-SAME: float [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi float [[ARG0]] to i32
+; CHECK-NEXT:    [[V1:%.*]] = icmp sgt i32 [[V0]], 1
+; CHECK-NEXT:    ret i1 [[V1]]
+;
+  %v0 = fptosi float %arg0 to i32
+  %v1 = icmp sgt i32 %v0, 1
+  ret i1 %v1
+}
+
+; https://alive2.llvm.org/ce/z/5VRWXi
+define i1 @float_to_int_comparing_constant2_positive1(float %arg0) {
+; CHECK-LABEL: define i1 @float_to_int_comparing_constant2_positive1(
+; CHECK-SAME: float [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi float [[ARG0]] to i32
+; CHECK-NEXT:    [[V1:%.*]] = icmp slt i32 [[V0]], 1
+; CHECK-NEXT:    ret i1 [[V1]]
+;
+  %v0 = fptosi float %arg0 to i32
+  %v1 = icmp slt i32 %v0, 1
+  ret i1 %v1
+}
+
+; https://alive2.llvm.org/ce/z/9bejWa
+define i1 @float_to_int_comparing_constant2_positive2(float %arg0) {
+; CHECK-LABEL: define i1 @float_to_int_comparing_constant2_positive2(
+; CHECK-SAME: float [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi float [[ARG0]] to i32
+; CHECK-NEXT:    [[V1:%.*]] = icmp slt i32 [[V0]], 0
+; CHECK-NEXT:    ret i1 [[V1]]
+;
+  %v0 = fptosi float %arg0 to i32
+  %v1 = icmp slt i32 %v0, 0
+  ret i1 %v1
+}
+
+define i1 @double_to_int_comparing_constant1_positive1(double %arg0) {
+; CHECK-LABEL: define i1 @double_to_int_comparing_constant1_positive1(
+; CHECK-SAME: double [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi double [[ARG0]] to i32
+; CHECK-NEXT:    [[V1:%.*]] = icmp sgt i32 [[V0]], -1
+; CHECK-NEXT:    ret i1 [[V1]]
+;
+  %v0 = fptosi double %arg0 to i32
+  %v1 = icmp sgt i32 %v0, -1
+  ret i1 %v1
+}
+
+define i1 @double_to_int_comparing_constant1_positive2(double %arg0) {
+; CHECK-LABEL: define i1 @double_to_int_comparing_constant1_positive2(
+; CHECK-SAME: double [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi double [[ARG0]] to i32
+; CHECK-NEXT:    [[V1:%.*]] = icmp sgt i32 [[V0]], 1
+; CHECK-NEXT:    ret i1 [[V1]]
+;
+  %v0 = fptosi double %arg0 to i32
+  %v1 = icmp sgt i32 %v0, 1
+  ret i1 %v1
+}
+
+define i1 @fp16_to_int_comparing_constant2_positive1(half %arg0) {
+; CHECK-LABEL: define i1 @fp16_to_int_comparing_constant2_positive1(
+; CHECK-SAME: half [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi half [[ARG0]] to i32
+; CHECK-NEXT:    [[V1:%.*]] = icmp slt i32 [[V0]], 1
+; CHECK-NEXT:    ret i1 [[V1]]
+;
+  %v0 = fptosi half %arg0 to i32
+  %v1 = icmp slt i32 %v0, 1
+  ret i1 %v1
+}
+
+define i1 @fp16_to_int_comparing_constant2_positive2(half %arg0) {
+; CHECK-LABEL: define i1 @fp16_to_int_comparing_constant2_positive2(
+; CHECK-SAME: half [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi half [[ARG0]] to i32
+; CHECK-NEXT:    [[V1:%.*]] = icmp slt i32 [[V0]], 0
+; CHECK-NEXT:    ret i1 [[V1]]
+;
+  %v0 = fptosi half %arg0 to i32
+  %v1 = icmp slt i32 %v0, 0
+  ret i1 %v1
+}
+
+define i1 @fp16_to_int_comparing_constant2_negative1(half %arg0) {
+; CHECK-LABEL: define i1 @fp16_to_int_comparing_constant2_negative1(
+; CHECK-SAME: half [[ARG0:%.*]]) {
+; CHECK-NEXT:    ret i1 false
+;
+  %v0 = fptosi half %arg0 to i32
+  %v1 = icmp slt i32 %v0, -65535
+  ret i1 %v1
+}
+
+define i1 @fp16_to_int_comparing_constant2_negativee2(half %arg0) {
+; CHECK-LABEL: define i1 @fp16_to_int_comparing_constant2_negativee2(
+; CHECK-SAME: half [[ARG0:%.*]]) {
+; CHECK-NEXT:    ret i1 true
+;
+  %v0 = fptosi half %arg0 to i32
+  %v1 = icmp slt i32 %v0, 65535
+  ret i1 %v1
+}
+
+define i1 @float_to_int_comparing_constant1_negative1(float %arg0) {
+; CHECK-LABEL: define i1 @float_to_int_comparing_constant1_negative1(
+; CHECK-SAME: float [[ARG0:%.*]]) {
+; CHECK-NEXT:    ret i1 false
+;
+  %v0 = fptosi float %arg0 to i8
+  %v1 = icmp sgt i8 %v0, 127
+  ret i1 %v1
+}
+
+define i1 @float_to_int_comparing_constant1_negative2(float %arg0) {
+; CHECK-LABEL: define i1 @float_to_int_comparing_constant1_negative2(
+; CHECK-SAME: float [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi float [[ARG0]] to i8
+; CHECK-NEXT:    [[V1:%.*]] = icmp eq i8 [[V0]], 127
+; CHECK-NEXT:    ret i1 [[V1]]
+;
+  %v0 = fptosi float %arg0 to i8
+  %v1 = icmp sge i8 %v0, 127
+  ret i1 %v1
+}
+
+define i1 @float_to_int_comparing_constant2_negative1(float %arg0) {
+; CHECK-LABEL: define i1 @float_to_int_comparing_constant2_negative1(
+; CHECK-SAME: float [[ARG0:%.*]]) {
+; CHECK-NEXT:    ret i1 false
+;
+  %v0 = fptosi float %arg0 to i8
+  %v1 = icmp slt i8 %v0, -128
+  ret i1 %v1
+}
+
+define i1 @float_to_int_comparing_constant2_negative2(float %arg0) {
+; CHECK-LABEL: define i1 @float_to_int_comparing_constant2_negative2(
+; CHECK-SAME: float [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi float [[ARG0]] to i8
+; CHECK-NEXT:    [[V1:%.*]] = icmp eq i8 [[V0]], -128
+; CHECK-NEXT:    ret i1 [[V1]]
+;
+  %v0 = fptosi float %arg0 to i8
+  %v1 = icmp sle i8 %v0, -128
+  ret i1 %v1
+}
+
+define <2 x i1> @float_to_int_comparing_constant_vec_positive1(<2 x float> %arg0) {
+; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_positive1(
+; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
+; CHECK-NEXT:    [[V1:%.*]] = icmp sgt <2 x i32> [[V0]], splat (i32 -1)
+; CHECK-NEXT:    ret <2 x i1> [[V1]]
+;
+  %v0 = fptosi <2 x float> %arg0 to <2 x i32>
+  %v1 = icmp sgt <2 x i32> %v0, <i32 -1, i32 -1>
+  ret <2 x i1> %v1
+}
+
+define <2 x i1> @float_to_int_comparing_constant_vec_positive2(<2 x float> %arg0) {
+; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_positive2(
+; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
+; CHECK-NEXT:    [[V1:%.*]] = icmp sgt <2 x i32> [[V0]], <i32 0, i32 1>
+; CHECK-NEXT:    ret <2 x i1> [[V1]]
+;
+  %v0 = fptosi <2 x float> %arg0 to <2 x i32>
+  %v1 = icmp sgt <2 x i32> %v0, <i32 0, i32 1>
+  ret <2 x i1> %v1
+}
+
+
+define <2 x i1> @float_to_int_comparing_constant_vec_positive3(<2 x float> %arg0) {
+; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_positive3(
+; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
+; CHECK-NEXT:    [[V1:%.*]] = icmp slt <2 x i32> [[V0]], splat (i32 1)
+; CHECK-NEXT:    ret <2 x i1> [[V1]]
+;
+  %v0 = fptosi <2 x float> %arg0 to <2 x i32>
+  %v1 = icmp slt <2 x i32> %v0, <i32 1, i32 1>
+  ret <2 x i1> %v1
+}
+
+define <2 x i1> @float_to_int_comparing_constant_vec_positive4(<2 x float> %arg0) {
+; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_positive4(
+; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
+; CHECK-NEXT:    [[V1:%.*]] = icmp slt <2 x i32> [[V0]], <i32 -1, i32 0>
+; CHECK-NEXT:    ret <2 x i1> [[V1]]
+;
+  %v0 = fptosi <2 x float> %arg0 to <2 x i32>
+  %v1 = icmp slt <2 x i32> %v0, <i32 -1, i32 0>
+  ret <2 x i1> %v1
+}
+
+define <2 x i1> @half_to_int_comparing_constant_vec_positive1(<2 x half> %arg0) {
+; CHECK-LABEL: define <2 x i1> @half_to_int_comparing_constant_vec_positive1(
+; CHECK-SAME: <2 x half> [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x half> [[ARG0]] to <2 x i32>
+; CHECK-NEXT:    [[V1:%.*]] = icmp sgt <2 x i32> [[V0]], splat (i32 -1)
+; CHECK-NEXT:    ret <2 x i1> [[V1]]
+;
+  %v0 = fptosi <2 x half> %arg0 to <2 x i32>
+  %v1 = icmp sgt <2 x i32> %v0, <i32 -1, i32 -1>
+  ret <2 x i1> %v1
+}
+
+define <2 x i1> @half_to_int_comparing_constant_vec_positive2(<2 x half> %arg0) {
+; CHECK-LABEL: define <2 x i1> @half_to_int_comparing_constant_vec_positive2(
+; CHECK-SAME: <2 x half> [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x half> [[ARG0]] to <2 x i32>
+; CHECK-NEXT:    [[V1:%.*]] = icmp sgt <2 x i32> [[V0]], <i32 0, i32 1>
+; CHECK-NEXT:    ret <2 x i1> [[V1]]
+;
+  %v0 = fptosi <2 x half> %arg0 to <2 x i32>
+  %v1 = icmp sgt <2 x i32> %v0, <i32 0, i32 1>
+  ret <2 x i1> %v1
+}
+
+define <2 x i1> @double_to_int_comparing_constant_vec_positive3(<2 x double> %arg0) {
+; CHECK-LABEL: define <2 x i1> @double_to_int_comparing_constant_vec_positive3(
+; CHECK-SAME: <2 x double> [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x double> [[ARG0]] to <2 x i32>
+; CHECK-NEXT:    [[V1:%.*]] = icmp slt <2 x i32> [[V0]], splat (i32 1)
+; CHECK-NEXT:    ret <2 x i1> [[V1]]
+;
+  %v0 = fptosi <2 x double> %arg0 to <2 x i32>
+  %v1 = icmp slt <2 x i32> %v0, <i32 1, i32 1>
+  ret <2 x i1> %v1
+}
+
+define <2 x i1> @double_to_int_comparing_constant_vec_positive4(<2 x double> %arg0) {
+; CHECK-LABEL: define <2 x i1> @double_to_int_comparing_constant_vec_positive4(
+; CHECK-SAME: <2 x double> [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x double> [[ARG0]] to <2 x i32>
+; CHECK-NEXT:    [[V1:%.*]] = icmp slt <2 x i32> [[V0]], <i32 -1, i32 0>
+; CHECK-NEXT:    ret <2 x i1> [[V1]]
+;
+  %v0 = fptosi <2 x double> %arg0 to <2 x i32>
+  %v1 = icmp slt <2 x i32> %v0, <i32 -1, i32 0>
+  ret <2 x i1> %v1
+}
+
+define <2 x i1> @float_to_int_comparing_constant_vec_negative1(<2 x float> %arg0) {
+; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_negative1(
+; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
+; CHECK-NEXT:    [[V1:%.*]] = icmp sgt <2 x i32> [[V0]], <i32 -1, i32 1>
+; CHECK-NEXT:    ret <2 x i1> [[V1]]
+;
+  %v0 = fptosi <2 x float> %arg0 to <2 x i32>
+  %v1 = icmp sgt <2 x i32> %v0, <i32 -1, i32 1>
+  ret <2 x i1> %v1
+}
+
+define <2 x i1> @float_to_int_comparing_constant_vec_negative2(<2 x float> %arg0) {
+; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_negative2(
+; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
+; CHECK-NEXT:    [[V1:%.*]] = icmp slt <2 x i32> [[V0]], <i32 -1, i32 1>
+; CHECK-NEXT:    ret <2 x i1> [[V1]]
+;
+  %v0 = fptosi <2 x float> %arg0 to <2 x i32>
+  %v1 = icmp slt <2 x i32> %v0, <i32 -1, i32 1>
+  ret <2 x i1> %v1
+}
+
+define <2 x i1> @float_to_int_comparing_constant_vec_negative3(<2 x float> %arg0) {
+; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_negative3(
+; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %v0 = fptosi <2 x float> %arg0 to <2 x i8>
+  %v1 = icmp sgt <2 x i8> %v0, <i8 127, i8 127>
+  ret <2 x i1> %v1
+}
+
+define <2 x i1> @float_to_int_comparing_constant_vec_negative4(<2 x float> %arg0) {
+; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_negative4(
+; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %v0 = fptosi <2 x float> %arg0 to <2 x i8>
+  %v1 = icmp slt <2 x i8> %v0, <i8 -128, i8 -128>
+  ret <2 x i1> %v1
+}

>From f5acd774934d935146cb52c0b980be7e3169a46c Mon Sep 17 00:00:00 2001
From: Artem Trokhymchuk <trkhmchk at gmail.com>
Date: Tue, 26 Aug 2025 22:58:27 +0300
Subject: [PATCH 2/3] [InstCombine] add icmp <cond> (fptosi %x) -> fcmp <cond>
 %y optimization implementation

Add optimization test reducing unneded float-to-int cast when
comparing numbers:
* icmp sgt (fptosi %x), <negative> -> fcmp ogt %x, <negative>
* icmp sgt (fptosi %x), <non-negative> -> fcmp oge %x, <non-negative + 1>
* icmp slt (fptosi %x), <positive> -> fcmp olt %x, <positive>
* icmp slt (fptosi %x), <non-positive> -> fcmp ole %x, <non-positive - 1>
---
 .../InstCombine/InstCombineCompares.cpp       | 85 +++++++++++++++++++
 llvm/test/Transforms/InstCombine/icmp.ll      | 48 ++++-------
 2 files changed, 101 insertions(+), 32 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 90feddf6dcfe1..4464da1b8a852 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -12,6 +12,7 @@
 
 #include "InstCombineInternal.h"
 #include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/Statistic.h"
@@ -21,6 +22,7 @@
 #include "llvm/Analysis/InstructionSimplify.h"
 #include "llvm/Analysis/Utils/Local.h"
 #include "llvm/Analysis/VectorUtils.h"
+#include "llvm/IR/CmpPredicate.h"
 #include "llvm/IR/ConstantRange.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
@@ -7611,6 +7613,87 @@ Instruction *InstCombinerImpl::foldICmpCommutative(CmpPredicate Pred,
   return nullptr;
 }
 
+/// Cast integral constant (either scalar or vector) to an appropriate vector
+/// one
+///
+/// \param C integral contsant to cast
+/// \param FPType floating point type to cast to
+/// \param Addend addend to add before casting
+/// \param DL target data layout
+///
+/// \return result constant
+static Constant *castIntegralConstantToFloat(Constant *C, Type *FPType,
+                                             int Addend, const DataLayout &DL) {
+  assert(FPType->isFPOrFPVectorTy() &&
+         "fptosi operand must have floating point type");
+
+  Constant *CWithAddend = ConstantFoldBinaryOpOperands(
+      Instruction::Add, C, ConstantInt::getSigned(C->getType(), Addend), DL);
+  if (!CWithAddend)
+    return nullptr;
+  return ConstantFoldCastOperand(Instruction::SIToFP, CWithAddend, FPType, DL);
+}
+
+/// Fold icmp (fptosi %arg) C -> fcmp $arg
+/// Folds:
+///  - icmp sgt %arg <negative> -> fcmp ogt %arg <negative>
+///  - icmp sgt %arg <non-negative> -> fcmp oge %arg (<non-negative> + 1)
+///  - icmp slt %arg <positive> -> fcmp olt %arg <positive>
+///  - icmp slt %arg <non-positive> -> fcmp ole %arg (<non-positive> - 1)
+///
+/// \param ICmp icmp instruction
+/// \param IC InstCombiner isntance
+/// \param DL target data layout
+///
+/// \return folded instruction or nullptr, if failed to combine instructions
+static Instruction *foldICmpFToSIToFCmp(ICmpInst &ICmp, InstCombiner &IC,
+                                        const DataLayout &DL) {
+  // Expect that canonical form: first argument is fptosi, second is constant
+  CmpPredicate Pred;
+  Value *FloatOp;
+  Constant *C;
+  if (!match(&ICmp, m_ICmp(Pred, m_OneUse(m_FPToSI(m_Value(FloatOp))),
+                           m_ImmConstant(C))))
+    return nullptr;
+
+  if (Pred != ICmpInst::ICMP_SGT && Pred != ICmpInst::ICMP_SLT)
+    return nullptr;
+
+  FCmpInst::Predicate FCmpPredicate;
+  Constant *FCmpConstant{};
+
+  switch (ICmp.getPredicate()) {
+  case ICmpInst::ICMP_SGT:
+    if (match(C, m_Negative())) {
+      // icmp sgt %arg <negative> -> fcmp ogt %arg <negative>
+      FCmpPredicate = FCmpInst::FCMP_OGT;
+      FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), 0, DL);
+    } else if (match(C, m_NonNegative())) {
+      // icmp sgt %arg <non-negative> -> fcmp oge %arg (<non-negative> + 1)
+      FCmpPredicate = FCmpInst::FCMP_OGE;
+      FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), 1, DL);
+    }
+    break;
+  case ICmpInst::ICMP_SLT:
+    if (match(C, m_StrictlyPositive())) {
+      // icmp slt %arg <positive> -> fcmp olt %arg <positive>
+      FCmpPredicate = FCmpInst::FCMP_OLT;
+      FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), 0, DL);
+    } else if (match(C, m_NonPositive())) {
+      // icmp slt %arg <non-positive> -> fcmp ole %arg (<non-positive> - 1)
+      FCmpPredicate = FCmpInst::FCMP_OLE;
+      FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), -1, DL);
+    }
+    break;
+  default:
+    llvm_unreachable("Unknown icmp comparator");
+  }
+  if (!FCmpConstant)
+    return nullptr;
+
+  return new FCmpInst(FCmpPredicate, FloatOp, FCmpConstant);
+}
+
 Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
   bool Changed = false;
   const SimplifyQuery Q = SQ.getWithInstruction(&I);
@@ -7748,6 +7831,8 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
   if (Instruction *Res =
           foldICmpCommutative(I.getSwappedCmpPredicate(), Op1, Op0, I))
     return Res;
+  if (Instruction *Res = foldICmpFToSIToFCmp(I, *this, DL))
+    return Res;
 
   if (I.isCommutative()) {
     if (auto Pair = matchSymmetricPair(I.getOperand(0), I.getOperand(1))) {
diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll
index eccf9ec39da61..79da4af93e9d5 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -6059,8 +6059,7 @@ define i1 @icmp_samesign_logical_or(i32 %In) {
 define i1 @float_to_int_comparing_constant1_positive1(float %arg0) {
 ; CHECK-LABEL: define i1 @float_to_int_comparing_constant1_positive1(
 ; CHECK-SAME: float [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi float [[ARG0]] to i32
-; CHECK-NEXT:    [[V1:%.*]] = icmp sgt i32 [[V0]], -1
+; CHECK-NEXT:    [[V1:%.*]] = fcmp ogt float [[ARG0]], -1.000000e+00
 ; CHECK-NEXT:    ret i1 [[V1]]
 ;
   %v0 = fptosi float %arg0 to i32
@@ -6072,8 +6071,7 @@ define i1 @float_to_int_comparing_constant1_positive1(float %arg0) {
 define i1 @float_to_int_comparing_constant1_positive2(float %arg0) {
 ; CHECK-LABEL: define i1 @float_to_int_comparing_constant1_positive2(
 ; CHECK-SAME: float [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi float [[ARG0]] to i32
-; CHECK-NEXT:    [[V1:%.*]] = icmp sgt i32 [[V0]], 1
+; CHECK-NEXT:    [[V1:%.*]] = fcmp oge float [[ARG0]], 2.000000e+00
 ; CHECK-NEXT:    ret i1 [[V1]]
 ;
   %v0 = fptosi float %arg0 to i32
@@ -6085,8 +6083,7 @@ define i1 @float_to_int_comparing_constant1_positive2(float %arg0) {
 define i1 @float_to_int_comparing_constant2_positive1(float %arg0) {
 ; CHECK-LABEL: define i1 @float_to_int_comparing_constant2_positive1(
 ; CHECK-SAME: float [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi float [[ARG0]] to i32
-; CHECK-NEXT:    [[V1:%.*]] = icmp slt i32 [[V0]], 1
+; CHECK-NEXT:    [[V1:%.*]] = fcmp olt float [[ARG0]], 1.000000e+00
 ; CHECK-NEXT:    ret i1 [[V1]]
 ;
   %v0 = fptosi float %arg0 to i32
@@ -6098,8 +6095,7 @@ define i1 @float_to_int_comparing_constant2_positive1(float %arg0) {
 define i1 @float_to_int_comparing_constant2_positive2(float %arg0) {
 ; CHECK-LABEL: define i1 @float_to_int_comparing_constant2_positive2(
 ; CHECK-SAME: float [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi float [[ARG0]] to i32
-; CHECK-NEXT:    [[V1:%.*]] = icmp slt i32 [[V0]], 0
+; CHECK-NEXT:    [[V1:%.*]] = fcmp ole float [[ARG0]], -1.000000e+00
 ; CHECK-NEXT:    ret i1 [[V1]]
 ;
   %v0 = fptosi float %arg0 to i32
@@ -6110,8 +6106,7 @@ define i1 @float_to_int_comparing_constant2_positive2(float %arg0) {
 define i1 @double_to_int_comparing_constant1_positive1(double %arg0) {
 ; CHECK-LABEL: define i1 @double_to_int_comparing_constant1_positive1(
 ; CHECK-SAME: double [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi double [[ARG0]] to i32
-; CHECK-NEXT:    [[V1:%.*]] = icmp sgt i32 [[V0]], -1
+; CHECK-NEXT:    [[V1:%.*]] = fcmp ogt double [[ARG0]], -1.000000e+00
 ; CHECK-NEXT:    ret i1 [[V1]]
 ;
   %v0 = fptosi double %arg0 to i32
@@ -6122,8 +6117,7 @@ define i1 @double_to_int_comparing_constant1_positive1(double %arg0) {
 define i1 @double_to_int_comparing_constant1_positive2(double %arg0) {
 ; CHECK-LABEL: define i1 @double_to_int_comparing_constant1_positive2(
 ; CHECK-SAME: double [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi double [[ARG0]] to i32
-; CHECK-NEXT:    [[V1:%.*]] = icmp sgt i32 [[V0]], 1
+; CHECK-NEXT:    [[V1:%.*]] = fcmp oge double [[ARG0]], 2.000000e+00
 ; CHECK-NEXT:    ret i1 [[V1]]
 ;
   %v0 = fptosi double %arg0 to i32
@@ -6134,8 +6128,7 @@ define i1 @double_to_int_comparing_constant1_positive2(double %arg0) {
 define i1 @fp16_to_int_comparing_constant2_positive1(half %arg0) {
 ; CHECK-LABEL: define i1 @fp16_to_int_comparing_constant2_positive1(
 ; CHECK-SAME: half [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi half [[ARG0]] to i32
-; CHECK-NEXT:    [[V1:%.*]] = icmp slt i32 [[V0]], 1
+; CHECK-NEXT:    [[V1:%.*]] = fcmp olt half [[ARG0]], 0xH3C00
 ; CHECK-NEXT:    ret i1 [[V1]]
 ;
   %v0 = fptosi half %arg0 to i32
@@ -6146,8 +6139,7 @@ define i1 @fp16_to_int_comparing_constant2_positive1(half %arg0) {
 define i1 @fp16_to_int_comparing_constant2_positive2(half %arg0) {
 ; CHECK-LABEL: define i1 @fp16_to_int_comparing_constant2_positive2(
 ; CHECK-SAME: half [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi half [[ARG0]] to i32
-; CHECK-NEXT:    [[V1:%.*]] = icmp slt i32 [[V0]], 0
+; CHECK-NEXT:    [[V1:%.*]] = fcmp ole half [[ARG0]], 0xHBC00
 ; CHECK-NEXT:    ret i1 [[V1]]
 ;
   %v0 = fptosi half %arg0 to i32
@@ -6222,8 +6214,7 @@ define i1 @float_to_int_comparing_constant2_negative2(float %arg0) {
 define <2 x i1> @float_to_int_comparing_constant_vec_positive1(<2 x float> %arg0) {
 ; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_positive1(
 ; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
-; CHECK-NEXT:    [[V1:%.*]] = icmp sgt <2 x i32> [[V0]], splat (i32 -1)
+; CHECK-NEXT:    [[V1:%.*]] = fcmp ogt <2 x float> [[ARG0]], splat (float -1.000000e+00)
 ; CHECK-NEXT:    ret <2 x i1> [[V1]]
 ;
   %v0 = fptosi <2 x float> %arg0 to <2 x i32>
@@ -6234,8 +6225,7 @@ define <2 x i1> @float_to_int_comparing_constant_vec_positive1(<2 x float> %arg0
 define <2 x i1> @float_to_int_comparing_constant_vec_positive2(<2 x float> %arg0) {
 ; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_positive2(
 ; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
-; CHECK-NEXT:    [[V1:%.*]] = icmp sgt <2 x i32> [[V0]], <i32 0, i32 1>
+; CHECK-NEXT:    [[V1:%.*]] = fcmp oge <2 x float> [[ARG0]], <float 1.000000e+00, float 2.000000e+00>
 ; CHECK-NEXT:    ret <2 x i1> [[V1]]
 ;
   %v0 = fptosi <2 x float> %arg0 to <2 x i32>
@@ -6247,8 +6237,7 @@ define <2 x i1> @float_to_int_comparing_constant_vec_positive2(<2 x float> %arg0
 define <2 x i1> @float_to_int_comparing_constant_vec_positive3(<2 x float> %arg0) {
 ; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_positive3(
 ; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
-; CHECK-NEXT:    [[V1:%.*]] = icmp slt <2 x i32> [[V0]], splat (i32 1)
+; CHECK-NEXT:    [[V1:%.*]] = fcmp olt <2 x float> [[ARG0]], splat (float 1.000000e+00)
 ; CHECK-NEXT:    ret <2 x i1> [[V1]]
 ;
   %v0 = fptosi <2 x float> %arg0 to <2 x i32>
@@ -6259,8 +6248,7 @@ define <2 x i1> @float_to_int_comparing_constant_vec_positive3(<2 x float> %arg0
 define <2 x i1> @float_to_int_comparing_constant_vec_positive4(<2 x float> %arg0) {
 ; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_positive4(
 ; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
-; CHECK-NEXT:    [[V1:%.*]] = icmp slt <2 x i32> [[V0]], <i32 -1, i32 0>
+; CHECK-NEXT:    [[V1:%.*]] = fcmp ole <2 x float> [[ARG0]], <float -2.000000e+00, float -1.000000e+00>
 ; CHECK-NEXT:    ret <2 x i1> [[V1]]
 ;
   %v0 = fptosi <2 x float> %arg0 to <2 x i32>
@@ -6271,8 +6259,7 @@ define <2 x i1> @float_to_int_comparing_constant_vec_positive4(<2 x float> %arg0
 define <2 x i1> @half_to_int_comparing_constant_vec_positive1(<2 x half> %arg0) {
 ; CHECK-LABEL: define <2 x i1> @half_to_int_comparing_constant_vec_positive1(
 ; CHECK-SAME: <2 x half> [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x half> [[ARG0]] to <2 x i32>
-; CHECK-NEXT:    [[V1:%.*]] = icmp sgt <2 x i32> [[V0]], splat (i32 -1)
+; CHECK-NEXT:    [[V1:%.*]] = fcmp ogt <2 x half> [[ARG0]], splat (half 0xHBC00)
 ; CHECK-NEXT:    ret <2 x i1> [[V1]]
 ;
   %v0 = fptosi <2 x half> %arg0 to <2 x i32>
@@ -6283,8 +6270,7 @@ define <2 x i1> @half_to_int_comparing_constant_vec_positive1(<2 x half> %arg0)
 define <2 x i1> @half_to_int_comparing_constant_vec_positive2(<2 x half> %arg0) {
 ; CHECK-LABEL: define <2 x i1> @half_to_int_comparing_constant_vec_positive2(
 ; CHECK-SAME: <2 x half> [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x half> [[ARG0]] to <2 x i32>
-; CHECK-NEXT:    [[V1:%.*]] = icmp sgt <2 x i32> [[V0]], <i32 0, i32 1>
+; CHECK-NEXT:    [[V1:%.*]] = fcmp oge <2 x half> [[ARG0]], <half 0xH3C00, half 0xH4000>
 ; CHECK-NEXT:    ret <2 x i1> [[V1]]
 ;
   %v0 = fptosi <2 x half> %arg0 to <2 x i32>
@@ -6295,8 +6281,7 @@ define <2 x i1> @half_to_int_comparing_constant_vec_positive2(<2 x half> %arg0)
 define <2 x i1> @double_to_int_comparing_constant_vec_positive3(<2 x double> %arg0) {
 ; CHECK-LABEL: define <2 x i1> @double_to_int_comparing_constant_vec_positive3(
 ; CHECK-SAME: <2 x double> [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x double> [[ARG0]] to <2 x i32>
-; CHECK-NEXT:    [[V1:%.*]] = icmp slt <2 x i32> [[V0]], splat (i32 1)
+; CHECK-NEXT:    [[V1:%.*]] = fcmp olt <2 x double> [[ARG0]], splat (double 1.000000e+00)
 ; CHECK-NEXT:    ret <2 x i1> [[V1]]
 ;
   %v0 = fptosi <2 x double> %arg0 to <2 x i32>
@@ -6307,8 +6292,7 @@ define <2 x i1> @double_to_int_comparing_constant_vec_positive3(<2 x double> %ar
 define <2 x i1> @double_to_int_comparing_constant_vec_positive4(<2 x double> %arg0) {
 ; CHECK-LABEL: define <2 x i1> @double_to_int_comparing_constant_vec_positive4(
 ; CHECK-SAME: <2 x double> [[ARG0:%.*]]) {
-; CHECK-NEXT:    [[V0:%.*]] = fptosi <2 x double> [[ARG0]] to <2 x i32>
-; CHECK-NEXT:    [[V1:%.*]] = icmp slt <2 x i32> [[V0]], <i32 -1, i32 0>
+; CHECK-NEXT:    [[V1:%.*]] = fcmp ole <2 x double> [[ARG0]], <double -2.000000e+00, double -1.000000e+00>
 ; CHECK-NEXT:    ret <2 x i1> [[V1]]
 ;
   %v0 = fptosi <2 x double> %arg0 to <2 x i32>

>From 64e797cc0b4c5acf353007c947c995e96a1a31da Mon Sep 17 00:00:00 2001
From: Artem Trokhymchuk <trkhmchk at gmail.com>
Date: Sun, 7 Sep 2025 15:12:53 +0300
Subject: [PATCH 3/3] [InstCombine] add icmp <cond> (fptosi %x) -> fcmp <cond>
 %y fix regression tests

Fix regression in the llvm/test/Transforms/PGOProfile/chr.ll after
optimizing fptosi cast in icmp.
---
 llvm/test/Transforms/PGOProfile/chr.ll | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/llvm/test/Transforms/PGOProfile/chr.ll b/llvm/test/Transforms/PGOProfile/chr.ll
index f0a1574c5f209..4133f56f9a630 100644
--- a/llvm/test/Transforms/PGOProfile/chr.ll
+++ b/llvm/test/Transforms/PGOProfile/chr.ll
@@ -1128,9 +1128,7 @@ define void @test_chr_11(ptr %i, i32 %x) !prof !14 {
 ; CHECK-NEXT:    [[CONV:%.*]] = sitofp i32 [[DOTFR1]] to double
 ; CHECK-NEXT:    [[DIV:%.*]] = fdiv double 1.000000e+00, [[CONV]]
 ; CHECK-NEXT:    [[MUL16:%.*]] = fmul double [[DIV]], [[CONV]]
-; CHECK-NEXT:    [[CONV717:%.*]] = fptosi double [[MUL16]] to i32
-; CHECK-NEXT:    [[CONV717_FR:%.*]] = freeze i32 [[CONV717]]
-; CHECK-NEXT:    [[CMP18:%.*]] = icmp sgt i32 [[CONV717_FR]], 0
+; CHECK-NEXT:    [[CMP18:%.*]] = fcmp oge double [[MUL16]], 1.000000e+00
 ; CHECK-NEXT:    [[TMP3:%.*]] = and i1 [[TMP2]], [[CMP18]]
 ; CHECK-NEXT:    br i1 [[TMP3]], label [[BB0:%.*]], label [[ENTRY_SPLIT_NONCHR:%.*]], !prof [[PROF15]]
 ; CHECK:       bb0:
@@ -1146,8 +1144,7 @@ define void @test_chr_11(ptr %i, i32 %x) !prof !14 {
 ; CHECK-NEXT:    [[CONV_NONCHR:%.*]] = sitofp i32 [[DOTFR1]] to double
 ; CHECK-NEXT:    [[DIV_NONCHR:%.*]] = fdiv double 1.000000e+00, [[CONV_NONCHR]]
 ; CHECK-NEXT:    [[MUL16_NONCHR:%.*]] = fmul double [[DIV_NONCHR]], [[CONV_NONCHR]]
-; CHECK-NEXT:    [[CONV717_NONCHR:%.*]] = fptosi double [[MUL16_NONCHR]] to i32
-; CHECK-NEXT:    [[CMP18_NONCHR:%.*]] = icmp slt i32 [[CONV717_NONCHR]], 1
+; CHECK-NEXT:    [[CMP18_NONCHR:%.*]] = fcmp olt double [[MUL16_NONCHR]], 1.000000e+00
 ; CHECK-NEXT:    br i1 [[CMP18_NONCHR]], label [[BB3]], label [[BB2_NONCHR:%.*]], !prof [[PROF16]]
 ; CHECK:       bb2.nonchr:
 ; CHECK-NEXT:    call void @foo()



More information about the llvm-commits mailing list