[llvm] Inst combine optimize unneded float to int cast when icmp (PR #155501)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 27 13:04:06 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Artem Trokhymchuk  (trokhymchuk)

<details>
<summary>Changes</summary>

Fixes #<!-- -->154242 

The following folds are supported:

* `fold icmp sgt (fptosi %x), <negative> -> fcmp ogt %x, <negative>`: https://alive2.llvm.org/ce/z/XtQS6H
* `icmp sgt (fptosi %x), <non-negative> -> fcmp oge %x, <non-negative + 1>`: https://alive2.llvm.org/ce/z/ZycBgc
* `icmp slt (fptosi %x), <positive> -> fcmp olt %x, <positive>`: https://alive2.llvm.org/ce/z/5VRWXi
* `icmp slt (fptosi %x), <non-positive> -> fcmp ole %x, <non-positive - 1>:` https://alive2.llvm.org/ce/z/9bejWa


---
Full diff: https://github.com/llvm/llvm-project/pull/155501.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp (+206) 
- (modified) llvm/test/Transforms/InstCombine/icmp.ll (+183) 


``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 3a8e043038153..b3df684a227bb 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"
@@ -31,6 +32,7 @@
 #include "llvm/Support/KnownBits.h"
 #include "llvm/Transforms/InstCombine/InstCombiner.h"
 #include <bitset>
+#include <utility>
 
 using namespace llvm;
 using namespace PatternMatch;
@@ -7611,6 +7613,208 @@ Instruction *InstCombinerImpl::foldICmpCommutative(CmpPredicate Pred,
   return nullptr;
 }
 
+enum class SignType {
+  Positive,
+  NonPositive,
+  Negative,
+  NonNegative,
+};
+
+/// Check signess of a constant integer or vector of integers
+///
+/// \param C constant to check for signedness
+/// \param SignType the sign type to check against
+///
+/// \return whether constant is signess corresponds with the requesed requested
+/// sign
+static bool checkConstantSignType(const Constant *C, SignType Sign) {
+  auto Check = [Sign](const ConstantInt *CI) {
+    switch (Sign) {
+    case SignType::Positive:
+      return !CI->isNegative() && !CI->isZero();
+    case SignType::NonPositive:
+      return CI->isNegative() || CI->isZero();
+    case SignType::Negative:
+      return CI->isNegative();
+    case SignType::NonNegative:
+      return !CI->isNegative();
+    default:
+      llvm_unreachable("Unknown sign type");
+    }
+  };
+
+  if (auto *CI = dyn_cast<ConstantInt>(C))
+    return Check(CI);
+
+  // Check every element for vector
+  if (auto *CDV = dyn_cast<ConstantDataVector>(C)) {
+    for (std::size_t i{}; i != CDV->getNumElements(); ++i) {
+      auto *CI = dyn_cast<ConstantInt>(CDV->getElementAsConstant(i));
+      if (!CI || !Check(CI))
+        return false;
+    }
+    return true;
+  }
+
+  return false;
+}
+
+/// Cast ConstantInt to an appropriate APFloat instance
+///
+/// \param CI ConstantInt instance to cast
+/// \param FPType floating point type to cast to
+/// \param Addend addend to add to constant before casting
+///
+/// \return pair {cast status, APFloat result}
+static std::pair<APFloatBase::opStatus, APFloat>
+castCIToAPF(const ConstantInt *CI, const Type *FPType, int Addend) {
+  APFloat FVal{FPType->isFloatTy() ? APFloat::IEEEsingle()
+                                   : APFloat::IEEEdouble()};
+  APInt CIAPIntValue{CI->getValue()};
+
+  if (CIAPIntValue.isMaxSignedValue() && Addend > 0)
+    return std::make_pair(APFloatBase::opStatus::opOverflow, FVal);
+
+  if (CIAPIntValue.isMinSignedValue() && Addend < 0)
+    return std::make_pair(APFloatBase::opStatus::opUnderflow, FVal);
+
+  APFloatBase::opStatus Status{FVal.convertFromAPInt(
+      CI->getValue() + Addend, true, APFloat::rmNearestTiesToEven)};
+  return std::make_pair(Status, FVal);
+}
+
+/// Cast ConstantDataVector<ConstantInt> to ConstantVector<ConstantFP>
+///
+/// \param CDV ConstantInt datavector to cast
+/// \param FPType floating point type to cast to
+/// \param Addend addend to add before casting
+/// \param Context context to use
+///
+/// \return result constant
+static Constant *castCIDVToCFPDV(const ConstantDataVector *CDV, Type *FPType,
+                                 int Addend, LLVMContext &Context) {
+  SmallVector<Constant *, 16> Elts;
+  for (std::size_t i{}; i != CDV->getNumElements(); ++i) {
+    ConstantInt *CI = dyn_cast<ConstantInt>(CDV->getElementAsConstant(i));
+    if (!CI)
+      return nullptr;
+
+    auto ConverstionResult = castCIToAPF(CI, FPType, Addend);
+    if (ConverstionResult.first != APFloat::opOK)
+      return nullptr;
+
+    Elts.push_back(ConstantFP::get(FPType, ConverstionResult.second));
+  }
+  return ConstantVector::get(Elts);
+}
+
+/// 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
+///
+/// \return result constant
+static Constant *castIntegralConstantToFloat(const Constant *C, Type *FPType,
+                                             int Addend) {
+  Type *InnerType;
+  if (FPType->isFloatingPointTy())
+    InnerType = FPType;
+  else if (FPType->isVectorTy())
+    InnerType = llvm::cast<llvm::VectorType>(FPType)->getElementType();
+  else
+    return nullptr;
+
+  if (!InnerType || !InnerType->isFloatingPointTy())
+    return nullptr;
+
+  if (const ConstantInt *CI = dyn_cast<ConstantInt>(C)) {
+    auto ConverstionResult = castCIToAPF(CI, FPType, Addend);
+    if (ConverstionResult.first != APFloat::opOK)
+      return nullptr;
+
+    return ConstantFP::get(FPType, ConverstionResult.second);
+  }
+
+  const ConstantDataVector *CDV = dyn_cast<ConstantDataVector>(C);
+  if (!CDV)
+    return nullptr;
+
+  LLVMContext &Ctx = C->getContext();
+
+  return castCIDVToCFPDV(CDV, InnerType, Addend, Ctx);
+}
+
+/// 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
+///
+/// \return folded instruction or nullptr, if failed to combine instructions
+static Instruction *foldICmpFToSIToFCmp(ICmpInst &ICmp, InstCombiner &IC) {
+  if (ICmp.getPredicate() != ICmpInst::ICMP_SGT &&
+      ICmp.getPredicate() != ICmpInst::ICMP_SLT)
+    return nullptr;
+
+  // Expect that canonical form: first argument is fptosi
+  auto *FToSI = dyn_cast<FPToSIInst>(ICmp.getOperand(0));
+  if (!FToSI)
+    return nullptr;
+
+  Value *FloatOp = FToSI->getOperand(0);
+  if (!FloatOp)
+    return nullptr;
+
+  // And the second must be constant
+  Constant *C = dyn_cast<Constant>(ICmp.getOperand(1));
+  if (!C)
+    return nullptr;
+
+  FCmpInst::Predicate FCmpPredicate;
+  Constant *FCmpConstant{};
+
+  switch (ICmp.getPredicate()) {
+  case ICmpInst::ICMP_SGT:
+    if (checkConstantSignType(C, SignType::Negative)) {
+      // icmp sgt %arg <negative> -> fcmp ogt %arg <negative>
+      FCmpPredicate = FCmpInst::FCMP_OGT;
+      FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), 0);
+    } else if (checkConstantSignType(C, SignType::NonNegative)) {
+      // icmp sgt %arg <non-negative> -> fcmp oge %arg (<non-negative> + 1)
+      FCmpPredicate = FCmpInst::FCMP_OGE;
+      FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), 1);
+    }
+    break;
+  case ICmpInst::ICMP_SLT:
+    if (checkConstantSignType(C, SignType::Positive)) {
+      // icmp slt %arg <positive> -> fcmp olt %arg <positive>
+      FCmpPredicate = FCmpInst::FCMP_OLE;
+      FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), 0);
+    } else if (checkConstantSignType(C, SignType::NonPositive)) {
+      // icmp slt %arg <non-positive> -> fcmp ole %arg (<non-positive> - 1)
+      FCmpPredicate = FCmpInst::FCMP_OLT;
+      FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), -1);
+    }
+    break;
+  default:
+    llvm_unreachable("Unknown icmp comparator");
+  }
+  if (!FCmpConstant)
+    return nullptr;
+
+  IRBuilder<> B(&ICmp);
+  Value *New;
+  // fcmp FCmpPredicate %arg C
+  New = B.CreateFCmp(FCmpPredicate, FloatOp, FCmpConstant);
+  return IC.replaceInstUsesWith(ICmp, New);
+}
+
 Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
   bool Changed = false;
   const SimplifyQuery Q = SQ.getWithInstruction(&I);
@@ -7748,6 +7952,8 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
   if (Instruction *Res =
           foldICmpCommutative(I.getSwappedCmpPredicate(), Op1, Op0, I))
     return Res;
+  if (Instruction *Res = foldICmpFToSIToFCmp(I, *this))
+    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 0faa7da482ef2..8df13997f1b1f 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -6054,3 +6054,186 @@ 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:    [[V1:%.*]] = fcmp ogt float [[ARG0]], -1.000000e+00
+; 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:    [[V1:%.*]] = fcmp oge float [[ARG0]], 2.000000e+00
+; 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:    [[V1:%.*]] = fcmp ole float [[ARG0]], 1.000000e+00
+; 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:    [[V1:%.*]] = fcmp olt float [[ARG0]], -1.000000e+00
+; CHECK-NEXT:    ret i1 [[V1]]
+;
+  %v0 = fptosi float %arg0 to i32
+  %v1 = icmp slt i32 %v0, 0
+  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:    [[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>
+  %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:    [[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>
+  %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:    [[V1:%.*]] = fcmp ole <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>
+  %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:    [[V1:%.*]] = fcmp olt <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>
+  %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
+}

``````````

</details>


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


More information about the llvm-commits mailing list