[llvm] [InstCombine] Optimize unneeded float to int cast when icmp (PR #155501)
Artem Trokhymchuk via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 31 12:23:59 PDT 2025
https://github.com/trokhymchuk updated https://github.com/llvm/llvm-project/pull/155501
>From e581d01fec551debee5618b528e8a87633ed401c 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/7] [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 | 191 +++++++++++++++++++++++
1 file changed, 191 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll
index 0faa7da482ef2..e4054d47b09fc 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -6054,3 +6054,194 @@ 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 @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> @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 e0d1431dd64854d85a3e1aac7580783b7a2b8aa3 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/7] [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 | 206 ++++++++++++++++++
llvm/test/Transforms/InstCombine/icmp.ll | 24 +-
2 files changed, 214 insertions(+), 16 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 90feddf6dcfe1..f9f3c59a2a18d 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 e4054d47b09fc..8df13997f1b1f 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 ole 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 olt float [[ARG0]], -1.000000e+00
; CHECK-NEXT: ret i1 [[V1]]
;
%v0 = fptosi float %arg0 to i32
@@ -6154,8 +6150,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>
@@ -6166,8 +6161,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>
@@ -6179,8 +6173,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 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>
@@ -6191,8 +6184,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 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>
>From 91ed9ba1835c380cee6e52e1b48558d4477411b2 Mon Sep 17 00:00:00 2001
From: Artem Trokhymchuk <trkhmchk at gmail.com>
Date: Sun, 31 Aug 2025 17:37:31 +0300
Subject: [PATCH 3/7] fixup! [InstCombine] add icmp <cond> (fptosi %x) -> fcmp
<cond> %y optimization implementation
---
.../InstCombine/InstCombineCompares.cpp | 25 +++++--------------
1 file changed, 6 insertions(+), 19 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index f9f3c59a2a18d..0fe62e2884ac3 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7628,35 +7628,22 @@ enum class SignType {
/// \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) {
+ auto CheckSign = [Sign](const APInt &Value) {
switch (Sign) {
case SignType::Positive:
- return !CI->isNegative() && !CI->isZero();
+ return Value.isStrictlyPositive();
case SignType::NonPositive:
- return CI->isNegative() || CI->isZero();
+ return Value.isNonPositive();
case SignType::Negative:
- return CI->isNegative();
+ return Value.isNegative();
case SignType::NonNegative:
- return !CI->isNegative();
+ return Value.isNonNegative();
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;
+ return match(C, m_CheckedInt(CheckSign));
}
/// Cast ConstantInt to an appropriate APFloat instance
>From 90acb8276534562fe29b163783b7c924df250751 Mon Sep 17 00:00:00 2001
From: Artem Trokhymchuk <trkhmchk at gmail.com>
Date: Sun, 31 Aug 2025 17:48:10 +0300
Subject: [PATCH 4/7] fixup! [InstCombine] add icmp <cond> (fptosi %x) -> fcmp
<cond> %y optimization implementation
---
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 0fe62e2884ac3..e3952c82948d9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7655,9 +7655,8 @@ static bool checkConstantSignType(const Constant *C, SignType Sign) {
/// \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()};
+ APFloat FVal{FPType->getFltSemantics()};
+ APInt CIAPIntValue{CI->getValue()};
if (CIAPIntValue.isMaxSignedValue() && Addend > 0)
return std::make_pair(APFloatBase::opStatus::opOverflow, FVal);
>From 9c37da014f256d2c0129740cb6d7896499692fc9 Mon Sep 17 00:00:00 2001
From: Artem Trokhymchuk <trkhmchk at gmail.com>
Date: Sun, 31 Aug 2025 20:37:27 +0300
Subject: [PATCH 5/7] fixup! [InstCombine] add icmp <cond> (fptosi %x) -> fcmp
<cond> %y optimization implementation
---
.../InstCombine/InstCombineCompares.cpp | 119 ++++++++----------
1 file changed, 52 insertions(+), 67 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index e3952c82948d9..394c85d6f5045 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7646,52 +7646,53 @@ static bool checkConstantSignType(const Constant *C, SignType Sign) {
return match(C, m_CheckedInt(CheckSign));
}
-/// Cast ConstantInt to an appropriate APFloat instance
+/// Get inner type: if the type matches CheckFn, the type itself
+/// is returned. Otherwise, type is converted to vector and inner
+/// type is retuend.
///
-/// \param CI ConstantInt instance to cast
-/// \param FPType floating point type to cast to
-/// \param Addend addend to add to constant before casting
+/// \param T type to get inner type from
+/// \param CheckFn function to check whether T is acceptable
///
-/// \return pair {cast status, APFloat result}
-static std::pair<APFloatBase::opStatus, APFloat>
-castCIToAPF(const ConstantInt *CI, const Type *FPType, int Addend) {
- APFloat FVal{FPType->getFltSemantics()};
- APInt CIAPIntValue{CI->getValue()};
-
- if (CIAPIntValue.isMaxSignedValue() && Addend > 0)
- return std::make_pair(APFloatBase::opStatus::opOverflow, FVal);
+/// \param if T matches CheckFn, the T is retuend. otherwise T
+/// is converted to VectorType and inner type is retuend
+static Type *getInnerType(Type *T, bool (Type::*CheckFn)() const) {
+ if ((T->*CheckFn)())
+ return T;
- if (CIAPIntValue.isMinSignedValue() && Addend < 0)
- return std::make_pair(APFloatBase::opStatus::opUnderflow, FVal);
+ VectorType *VT{llvm::cast<llvm::VectorType>(T)};
+ if (!VT)
+ return nullptr;
- APFloatBase::opStatus Status{FVal.convertFromAPInt(
- CI->getValue() + Addend, true, APFloat::rmNearestTiesToEven)};
- return std::make_pair(Status, FVal);
+ return VT->getElementType();
}
-/// Cast ConstantDataVector<ConstantInt> to ConstantVector<ConstantFP>
+/// Converts Addend to an appropriate constant and returns it
///
-/// \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
+/// \param C constant to extract type and size (if vector) to
+/// create an appropriate addned type
+/// \param Addend addend to create constant from
///
-/// \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;
+/// \return Constant of the C type and with Addend in storage
+static Constant *getConstantAddend(const Constant *C, int Addend) {
+ Type *InnerType{getInnerType(C->getType(), static_cast<bool (Type::*)() const>(&Type::isIntegerTy))};
+ if (!InnerType)
+ return nullptr;
- auto ConverstionResult = castCIToAPF(CI, FPType, Addend);
- if (ConverstionResult.first != APFloat::opOK)
- return nullptr;
+ IntegerType *IntegralInnerType = llvm::dyn_cast<llvm::IntegerType>(InnerType);
+ if (!IntegralInnerType)
+ return nullptr;
- Elts.push_back(ConstantFP::get(FPType, ConverstionResult.second));
- }
- return ConstantVector::get(Elts);
+ Constant *CIAddend{
+ ConstantInt::get(InnerType, APInt{IntegralInnerType->getBitWidth(),
+ static_cast<uint64_t>(Addend), true})};
+ if (C->getType()->isIntegerTy())
+ return CIAddend;
+
+ const ConstantDataVector *CDV = dyn_cast<ConstantDataVector>(C);
+ if (!CDV)
+ return nullptr;
+
+ return ConstantDataVector::getSplat(CDV->getNumElements(), CIAddend);
}
/// Cast integral constant (either scalar or vector) to an appropriate vector
@@ -7700,36 +7701,18 @@ static Constant *castCIDVToCFPDV(const ConstantDataVector *CDV, Type *FPType,
/// \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(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;
-
+static Constant *castIntegralConstantToFloat(Constant *C, Type *FPType,
+ int Addend, const DataLayout &DL) {
+ Type *InnerType{getInnerType(FPType, &Type::isFloatingPointTy)};
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);
+ Constant *CWithAddend{ConstantFoldBinaryOpOperands(
+ Instruction::Add, C, getConstantAddend(C, Addend), DL)};
+ return ConstantFoldCastOperand(Instruction::SIToFP, CWithAddend, FPType, DL);
}
/// Fold icmp (fptosi %arg) C -> fcmp $arg
@@ -7741,9 +7724,11 @@ static Constant *castIntegralConstantToFloat(const Constant *C, Type *FPType,
///
/// \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) {
+static Instruction *foldICmpFToSIToFCmp(ICmpInst &ICmp, InstCombiner &IC,
+ const DataLayout &DL) {
if (ICmp.getPredicate() != ICmpInst::ICMP_SGT &&
ICmp.getPredicate() != ICmpInst::ICMP_SLT)
return nullptr;
@@ -7770,22 +7755,22 @@ static Instruction *foldICmpFToSIToFCmp(ICmpInst &ICmp, InstCombiner &IC) {
if (checkConstantSignType(C, SignType::Negative)) {
// icmp sgt %arg <negative> -> fcmp ogt %arg <negative>
FCmpPredicate = FCmpInst::FCMP_OGT;
- FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), 0);
+ FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), 0, DL);
} 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);
+ FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), 1, DL);
}
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);
+ FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), 0, DL);
} 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);
+ FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), -1, DL);
}
break;
default:
@@ -7938,7 +7923,7 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
if (Instruction *Res =
foldICmpCommutative(I.getSwappedCmpPredicate(), Op1, Op0, I))
return Res;
- if (Instruction *Res = foldICmpFToSIToFCmp(I, *this))
+ if (Instruction *Res = foldICmpFToSIToFCmp(I, *this, DL))
return Res;
if (I.isCommutative()) {
>From a410608b7cfc5ff9c48e1311f3365156c79a955d Mon Sep 17 00:00:00 2001
From: Artem Trokhymchuk <trkhmchk at gmail.com>
Date: Sun, 31 Aug 2025 20:37:49 +0300
Subject: [PATCH 6/7] fixup! [InstCombine] add icmp <cond> (fptosi %x) -> fcmp
<cond> %y optimization implementation
---
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 394c85d6f5045..02ffcbd8076ad 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7739,8 +7739,6 @@ static Instruction *foldICmpFToSIToFCmp(ICmpInst &ICmp, InstCombiner &IC,
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));
>From cf201c32a620ad864aed4bb5e2efa35872cfbe44 Mon Sep 17 00:00:00 2001
From: Artem Trokhymchuk <trkhmchk at gmail.com>
Date: Sun, 31 Aug 2025 21:01:59 +0300
Subject: [PATCH 7/7] fixup! [InstCombine] add icmp <cond> (fptosi %x) -> fcmp
<cond> %y optimization implementation
---
.../InstCombine/InstCombineCompares.cpp | 26 ++++++++-----------
1 file changed, 11 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 02ffcbd8076ad..bc0bceb2ca438 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -22,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"
@@ -7674,7 +7675,8 @@ static Type *getInnerType(Type *T, bool (Type::*CheckFn)() const) {
///
/// \return Constant of the C type and with Addend in storage
static Constant *getConstantAddend(const Constant *C, int Addend) {
- Type *InnerType{getInnerType(C->getType(), static_cast<bool (Type::*)() const>(&Type::isIntegerTy))};
+ Type *InnerType{getInnerType(
+ C->getType(), static_cast<bool (Type::*)() const>(&Type::isIntegerTy))};
if (!InnerType)
return nullptr;
@@ -7701,7 +7703,7 @@ static Constant *getConstantAddend(const Constant *C, int Addend) {
/// \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
+/// \param DL target data layout
///
/// \return result constant
static Constant *castIntegralConstantToFloat(Constant *C, Type *FPType,
@@ -7729,22 +7731,16 @@ static Constant *castIntegralConstantToFloat(Constant *C, Type *FPType,
/// \return folded instruction or nullptr, if failed to combine instructions
static Instruction *foldICmpFToSIToFCmp(ICmpInst &ICmp, InstCombiner &IC,
const DataLayout &DL) {
- 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)
+ // Expect that canonical form: first argument is fptosi, second is constant
+ CmpPredicate Pred;
+ Value *FloatOp;
+ Constant *C;
+ if (!match(&ICmp, m_ICmp(Pred, m_FPToSI(m_Value(FloatOp)), m_ImmConstant(C))))
return nullptr;
- Value *FloatOp = FToSI->getOperand(0);
-
- // And the second must be constant
- Constant *C = dyn_cast<Constant>(ICmp.getOperand(1));
- if (!C)
+ if (Pred != ICmpInst::ICMP_SGT && Pred != ICmpInst::ICMP_SLT)
return nullptr;
-
+
FCmpInst::Predicate FCmpPredicate;
Constant *FCmpConstant{};
More information about the llvm-commits
mailing list