Skip to content

Commit 09d9caa

Browse files
committed
[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>
1 parent 8e6daa1 commit 09d9caa

File tree

3 files changed

+114
-32
lines changed

3 files changed

+114
-32
lines changed

llvm/include/llvm/IR/PatternMatch.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,19 @@ inline api_pred_ty<is_maxsignedvalue> m_MaxSignedValue(const APInt *&V) {
542542
return V;
543543
}
544544

545+
struct is_minsignedvalue {
546+
bool isValue(const APInt &C) const { return C.isMinSignedValue(); }
547+
};
548+
/// Match an integer or vector with values having only high bit set
549+
/// (0x80...).
550+
/// For vectors, this includes constants with undefined elements.
551+
inline cst_pred_ty<is_minsignedvalue> m_MinSignedValue() {
552+
return cst_pred_ty<is_minsignedvalue>();
553+
}
554+
inline api_pred_ty<is_minsignedvalue> m_MinSignedValue(const APInt *&V) {
555+
return V;
556+
}
557+
545558
struct is_negative {
546559
bool isValue(const APInt &C) const { return C.isNegative(); }
547560
};

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "InstCombineInternal.h"
1414
#include "llvm/ADT/APFloat.h"
15+
#include "llvm/ADT/APInt.h"
1516
#include "llvm/ADT/APSInt.h"
1617
#include "llvm/ADT/SetVector.h"
1718
#include "llvm/ADT/Statistic.h"
@@ -21,6 +22,7 @@
2122
#include "llvm/Analysis/InstructionSimplify.h"
2223
#include "llvm/Analysis/Utils/Local.h"
2324
#include "llvm/Analysis/VectorUtils.h"
25+
#include "llvm/IR/CmpPredicate.h"
2426
#include "llvm/IR/ConstantRange.h"
2527
#include "llvm/IR/Constants.h"
2628
#include "llvm/IR/DataLayout.h"
@@ -7611,6 +7613,87 @@ Instruction *InstCombinerImpl::foldICmpCommutative(CmpPredicate Pred,
76117613
return nullptr;
76127614
}
76137615

7616+
/// Cast integral constant (either scalar or vector) to an appropriate vector
7617+
/// one
7618+
///
7619+
/// \param C integral contsant to cast
7620+
/// \param FPType floating point type to cast to
7621+
/// \param Addend addend to add before casting
7622+
/// \param DL target data layout
7623+
///
7624+
/// \return result constant
7625+
static Constant *castIntegralConstantToFloat(Constant *C, Type *FPType,
7626+
int Addend, const DataLayout &DL) {
7627+
assert(FPType->isFPOrFPVectorTy() &&
7628+
"fptosi operand must have floating point type");
7629+
7630+
Constant *CWithAddend = ConstantFoldBinaryOpOperands(
7631+
Instruction::Add, C, ConstantInt::getSigned(C->getType(), Addend), DL);
7632+
if (!CWithAddend)
7633+
return nullptr;
7634+
return ConstantFoldCastOperand(Instruction::SIToFP, CWithAddend, FPType, DL);
7635+
}
7636+
7637+
/// Fold icmp (fptosi %arg) C -> fcmp $arg
7638+
/// Folds:
7639+
/// - icmp sgt %arg <negative> -> fcmp ogt %arg <negative>
7640+
/// - icmp sgt %arg <non-negative> -> fcmp oge %arg (<non-negative> + 1)
7641+
/// - icmp slt %arg <positive> -> fcmp olt %arg <positive>
7642+
/// - icmp slt %arg <non-positive> -> fcmp ole %arg (<non-positive> - 1)
7643+
///
7644+
/// \param ICmp icmp instruction
7645+
/// \param IC InstCombiner isntance
7646+
/// \param DL target data layout
7647+
///
7648+
/// \return folded instruction or nullptr, if failed to combine instructions
7649+
static Instruction *foldICmpFToSIToFCmp(ICmpInst &ICmp, InstCombiner &IC,
7650+
const DataLayout &DL) {
7651+
// Expect that canonical form: first argument is fptosi, second is constant
7652+
CmpPredicate Pred;
7653+
Value *FloatOp;
7654+
Constant *C;
7655+
if (!match(&ICmp, m_ICmp(Pred, m_OneUse(m_FPToSI(m_Value(FloatOp))),
7656+
m_ImmConstant(C))))
7657+
return nullptr;
7658+
7659+
if (Pred != ICmpInst::ICMP_SGT && Pred != ICmpInst::ICMP_SLT)
7660+
return nullptr;
7661+
7662+
FCmpInst::Predicate FCmpPredicate;
7663+
Constant *FCmpConstant{};
7664+
7665+
switch (ICmp.getPredicate()) {
7666+
case ICmpInst::ICMP_SGT:
7667+
if (match(C, m_Negative())) {
7668+
// icmp sgt %arg <negative> -> fcmp ogt %arg <negative>
7669+
FCmpPredicate = FCmpInst::FCMP_OGT;
7670+
FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), 0, DL);
7671+
} else if (match(C, m_NonNegative()) && !match(C, m_MaxSignedValue())) {
7672+
// icmp sgt %arg <non-negative> -> fcmp oge %arg (<non-negative> + 1)
7673+
FCmpPredicate = FCmpInst::FCMP_OGE;
7674+
FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), 1, DL);
7675+
}
7676+
break;
7677+
case ICmpInst::ICMP_SLT:
7678+
if (match(C, m_StrictlyPositive())) {
7679+
// icmp slt %arg <positive> -> fcmp olt %arg <positive>
7680+
FCmpPredicate = FCmpInst::FCMP_OLT;
7681+
FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), 0, DL);
7682+
} else if (match(C, m_NonPositive()) && !match(C, m_MinSignedValue())) {
7683+
// icmp slt %arg <non-positive> -> fcmp ole %arg (<non-positive> - 1)
7684+
FCmpPredicate = FCmpInst::FCMP_OLE;
7685+
FCmpConstant = castIntegralConstantToFloat(C, FloatOp->getType(), -1, DL);
7686+
}
7687+
break;
7688+
default:
7689+
llvm_unreachable("Unknown icmp comparator");
7690+
}
7691+
if (!FCmpConstant)
7692+
return nullptr;
7693+
7694+
return new FCmpInst(FCmpPredicate, FloatOp, FCmpConstant);
7695+
}
7696+
76147697
Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
76157698
bool Changed = false;
76167699
const SimplifyQuery Q = SQ.getWithInstruction(&I);
@@ -7748,6 +7831,8 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
77487831
if (Instruction *Res =
77497832
foldICmpCommutative(I.getSwappedCmpPredicate(), Op1, Op0, I))
77507833
return Res;
7834+
if (Instruction *Res = foldICmpFToSIToFCmp(I, *this, DL))
7835+
return Res;
77517836

77527837
if (I.isCommutative()) {
77537838
if (auto Pair = matchSymmetricPair(I.getOperand(0), I.getOperand(1))) {

llvm/test/Transforms/InstCombine/icmp.ll

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6059,8 +6059,7 @@ define i1 @icmp_samesign_logical_or(i32 %In) {
60596059
define i1 @float_to_int_comparing_constant1_positive1(float %arg0) {
60606060
; CHECK-LABEL: define i1 @float_to_int_comparing_constant1_positive1(
60616061
; CHECK-SAME: float [[ARG0:%.*]]) {
6062-
; CHECK-NEXT: [[V0:%.*]] = fptosi float [[ARG0]] to i32
6063-
; CHECK-NEXT: [[V1:%.*]] = icmp sgt i32 [[V0]], -1
6062+
; CHECK-NEXT: [[V1:%.*]] = fcmp ogt float [[ARG0]], -1.000000e+00
60646063
; CHECK-NEXT: ret i1 [[V1]]
60656064
;
60666065
%v0 = fptosi float %arg0 to i32
@@ -6072,8 +6071,7 @@ define i1 @float_to_int_comparing_constant1_positive1(float %arg0) {
60726071
define i1 @float_to_int_comparing_constant1_positive2(float %arg0) {
60736072
; CHECK-LABEL: define i1 @float_to_int_comparing_constant1_positive2(
60746073
; CHECK-SAME: float [[ARG0:%.*]]) {
6075-
; CHECK-NEXT: [[V0:%.*]] = fptosi float [[ARG0]] to i32
6076-
; CHECK-NEXT: [[V1:%.*]] = icmp sgt i32 [[V0]], 1
6074+
; CHECK-NEXT: [[V1:%.*]] = fcmp oge float [[ARG0]], 2.000000e+00
60776075
; CHECK-NEXT: ret i1 [[V1]]
60786076
;
60796077
%v0 = fptosi float %arg0 to i32
@@ -6085,8 +6083,7 @@ define i1 @float_to_int_comparing_constant1_positive2(float %arg0) {
60856083
define i1 @float_to_int_comparing_constant2_positive1(float %arg0) {
60866084
; CHECK-LABEL: define i1 @float_to_int_comparing_constant2_positive1(
60876085
; CHECK-SAME: float [[ARG0:%.*]]) {
6088-
; CHECK-NEXT: [[V0:%.*]] = fptosi float [[ARG0]] to i32
6089-
; CHECK-NEXT: [[V1:%.*]] = icmp slt i32 [[V0]], 1
6086+
; CHECK-NEXT: [[V1:%.*]] = fcmp olt float [[ARG0]], 1.000000e+00
60906087
; CHECK-NEXT: ret i1 [[V1]]
60916088
;
60926089
%v0 = fptosi float %arg0 to i32
@@ -6098,8 +6095,7 @@ define i1 @float_to_int_comparing_constant2_positive1(float %arg0) {
60986095
define i1 @float_to_int_comparing_constant2_positive2(float %arg0) {
60996096
; CHECK-LABEL: define i1 @float_to_int_comparing_constant2_positive2(
61006097
; CHECK-SAME: float [[ARG0:%.*]]) {
6101-
; CHECK-NEXT: [[V0:%.*]] = fptosi float [[ARG0]] to i32
6102-
; CHECK-NEXT: [[V1:%.*]] = icmp slt i32 [[V0]], 0
6098+
; CHECK-NEXT: [[V1:%.*]] = fcmp ole float [[ARG0]], -1.000000e+00
61036099
; CHECK-NEXT: ret i1 [[V1]]
61046100
;
61056101
%v0 = fptosi float %arg0 to i32
@@ -6110,8 +6106,7 @@ define i1 @float_to_int_comparing_constant2_positive2(float %arg0) {
61106106
define i1 @double_to_int_comparing_constant1_positive1(double %arg0) {
61116107
; CHECK-LABEL: define i1 @double_to_int_comparing_constant1_positive1(
61126108
; CHECK-SAME: double [[ARG0:%.*]]) {
6113-
; CHECK-NEXT: [[V0:%.*]] = fptosi double [[ARG0]] to i32
6114-
; CHECK-NEXT: [[V1:%.*]] = icmp sgt i32 [[V0]], -1
6109+
; CHECK-NEXT: [[V1:%.*]] = fcmp ogt double [[ARG0]], -1.000000e+00
61156110
; CHECK-NEXT: ret i1 [[V1]]
61166111
;
61176112
%v0 = fptosi double %arg0 to i32
@@ -6122,8 +6117,7 @@ define i1 @double_to_int_comparing_constant1_positive1(double %arg0) {
61226117
define i1 @double_to_int_comparing_constant1_positive2(double %arg0) {
61236118
; CHECK-LABEL: define i1 @double_to_int_comparing_constant1_positive2(
61246119
; CHECK-SAME: double [[ARG0:%.*]]) {
6125-
; CHECK-NEXT: [[V0:%.*]] = fptosi double [[ARG0]] to i32
6126-
; CHECK-NEXT: [[V1:%.*]] = icmp sgt i32 [[V0]], 1
6120+
; CHECK-NEXT: [[V1:%.*]] = fcmp oge double [[ARG0]], 2.000000e+00
61276121
; CHECK-NEXT: ret i1 [[V1]]
61286122
;
61296123
%v0 = fptosi double %arg0 to i32
@@ -6134,8 +6128,7 @@ define i1 @double_to_int_comparing_constant1_positive2(double %arg0) {
61346128
define i1 @fp16_to_int_comparing_constant2_positive1(half %arg0) {
61356129
; CHECK-LABEL: define i1 @fp16_to_int_comparing_constant2_positive1(
61366130
; CHECK-SAME: half [[ARG0:%.*]]) {
6137-
; CHECK-NEXT: [[V0:%.*]] = fptosi half [[ARG0]] to i32
6138-
; CHECK-NEXT: [[V1:%.*]] = icmp slt i32 [[V0]], 1
6131+
; CHECK-NEXT: [[V1:%.*]] = fcmp olt half [[ARG0]], 0xH3C00
61396132
; CHECK-NEXT: ret i1 [[V1]]
61406133
;
61416134
%v0 = fptosi half %arg0 to i32
@@ -6146,8 +6139,7 @@ define i1 @fp16_to_int_comparing_constant2_positive1(half %arg0) {
61466139
define i1 @fp16_to_int_comparing_constant2_positive2(half %arg0) {
61476140
; CHECK-LABEL: define i1 @fp16_to_int_comparing_constant2_positive2(
61486141
; CHECK-SAME: half [[ARG0:%.*]]) {
6149-
; CHECK-NEXT: [[V0:%.*]] = fptosi half [[ARG0]] to i32
6150-
; CHECK-NEXT: [[V1:%.*]] = icmp slt i32 [[V0]], 0
6142+
; CHECK-NEXT: [[V1:%.*]] = fcmp ole half [[ARG0]], 0xHBC00
61516143
; CHECK-NEXT: ret i1 [[V1]]
61526144
;
61536145
%v0 = fptosi half %arg0 to i32
@@ -6222,8 +6214,7 @@ define i1 @float_to_int_comparing_constant2_negative2(float %arg0) {
62226214
define <2 x i1> @float_to_int_comparing_constant_vec_positive1(<2 x float> %arg0) {
62236215
; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_positive1(
62246216
; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
6225-
; CHECK-NEXT: [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
6226-
; CHECK-NEXT: [[V1:%.*]] = icmp sgt <2 x i32> [[V0]], splat (i32 -1)
6217+
; CHECK-NEXT: [[V1:%.*]] = fcmp ogt <2 x float> [[ARG0]], splat (float -1.000000e+00)
62276218
; CHECK-NEXT: ret <2 x i1> [[V1]]
62286219
;
62296220
%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
62346225
define <2 x i1> @float_to_int_comparing_constant_vec_positive2(<2 x float> %arg0) {
62356226
; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_positive2(
62366227
; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
6237-
; CHECK-NEXT: [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
6238-
; CHECK-NEXT: [[V1:%.*]] = icmp sgt <2 x i32> [[V0]], <i32 0, i32 1>
6228+
; CHECK-NEXT: [[V1:%.*]] = fcmp oge <2 x float> [[ARG0]], <float 1.000000e+00, float 2.000000e+00>
62396229
; CHECK-NEXT: ret <2 x i1> [[V1]]
62406230
;
62416231
%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
62476237
define <2 x i1> @float_to_int_comparing_constant_vec_positive3(<2 x float> %arg0) {
62486238
; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_positive3(
62496239
; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
6250-
; CHECK-NEXT: [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
6251-
; CHECK-NEXT: [[V1:%.*]] = icmp slt <2 x i32> [[V0]], splat (i32 1)
6240+
; CHECK-NEXT: [[V1:%.*]] = fcmp olt <2 x float> [[ARG0]], splat (float 1.000000e+00)
62526241
; CHECK-NEXT: ret <2 x i1> [[V1]]
62536242
;
62546243
%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
62596248
define <2 x i1> @float_to_int_comparing_constant_vec_positive4(<2 x float> %arg0) {
62606249
; CHECK-LABEL: define <2 x i1> @float_to_int_comparing_constant_vec_positive4(
62616250
; CHECK-SAME: <2 x float> [[ARG0:%.*]]) {
6262-
; CHECK-NEXT: [[V0:%.*]] = fptosi <2 x float> [[ARG0]] to <2 x i32>
6263-
; CHECK-NEXT: [[V1:%.*]] = icmp slt <2 x i32> [[V0]], <i32 -1, i32 0>
6251+
; CHECK-NEXT: [[V1:%.*]] = fcmp ole <2 x float> [[ARG0]], <float -2.000000e+00, float -1.000000e+00>
62646252
; CHECK-NEXT: ret <2 x i1> [[V1]]
62656253
;
62666254
%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
62716259
define <2 x i1> @half_to_int_comparing_constant_vec_positive1(<2 x half> %arg0) {
62726260
; CHECK-LABEL: define <2 x i1> @half_to_int_comparing_constant_vec_positive1(
62736261
; CHECK-SAME: <2 x half> [[ARG0:%.*]]) {
6274-
; CHECK-NEXT: [[V0:%.*]] = fptosi <2 x half> [[ARG0]] to <2 x i32>
6275-
; CHECK-NEXT: [[V1:%.*]] = icmp sgt <2 x i32> [[V0]], splat (i32 -1)
6262+
; CHECK-NEXT: [[V1:%.*]] = fcmp ogt <2 x half> [[ARG0]], splat (half 0xHBC00)
62766263
; CHECK-NEXT: ret <2 x i1> [[V1]]
62776264
;
62786265
%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)
62836270
define <2 x i1> @half_to_int_comparing_constant_vec_positive2(<2 x half> %arg0) {
62846271
; CHECK-LABEL: define <2 x i1> @half_to_int_comparing_constant_vec_positive2(
62856272
; CHECK-SAME: <2 x half> [[ARG0:%.*]]) {
6286-
; CHECK-NEXT: [[V0:%.*]] = fptosi <2 x half> [[ARG0]] to <2 x i32>
6287-
; CHECK-NEXT: [[V1:%.*]] = icmp sgt <2 x i32> [[V0]], <i32 0, i32 1>
6273+
; CHECK-NEXT: [[V1:%.*]] = fcmp oge <2 x half> [[ARG0]], <half 0xH3C00, half 0xH4000>
62886274
; CHECK-NEXT: ret <2 x i1> [[V1]]
62896275
;
62906276
%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)
62956281
define <2 x i1> @double_to_int_comparing_constant_vec_positive3(<2 x double> %arg0) {
62966282
; CHECK-LABEL: define <2 x i1> @double_to_int_comparing_constant_vec_positive3(
62976283
; CHECK-SAME: <2 x double> [[ARG0:%.*]]) {
6298-
; CHECK-NEXT: [[V0:%.*]] = fptosi <2 x double> [[ARG0]] to <2 x i32>
6299-
; CHECK-NEXT: [[V1:%.*]] = icmp slt <2 x i32> [[V0]], splat (i32 1)
6284+
; CHECK-NEXT: [[V1:%.*]] = fcmp olt <2 x double> [[ARG0]], splat (double 1.000000e+00)
63006285
; CHECK-NEXT: ret <2 x i1> [[V1]]
63016286
;
63026287
%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
63076292
define <2 x i1> @double_to_int_comparing_constant_vec_positive4(<2 x double> %arg0) {
63086293
; CHECK-LABEL: define <2 x i1> @double_to_int_comparing_constant_vec_positive4(
63096294
; CHECK-SAME: <2 x double> [[ARG0:%.*]]) {
6310-
; CHECK-NEXT: [[V0:%.*]] = fptosi <2 x double> [[ARG0]] to <2 x i32>
6311-
; CHECK-NEXT: [[V1:%.*]] = icmp slt <2 x i32> [[V0]], <i32 -1, i32 0>
6295+
; CHECK-NEXT: [[V1:%.*]] = fcmp ole <2 x double> [[ARG0]], <double -2.000000e+00, double -1.000000e+00>
63126296
; CHECK-NEXT: ret <2 x i1> [[V1]]
63136297
;
63146298
%v0 = fptosi <2 x double> %arg0 to <2 x i32>

0 commit comments

Comments
 (0)