[llvm] [InstSimplify] Fold expression using basic properties of floor and ceiling function (PR #107107)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 4 17:25:44 PDT 2024
https://github.com/c8ef updated https://github.com/llvm/llvm-project/pull/107107
>From c9e8bbd1d93bbd0c2f87320e0cb73a463036ecae Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Tue, 3 Sep 2024 21:30:53 +0800
Subject: [PATCH 1/4] floor(x) <= x --> true
---
llvm/lib/Analysis/InstructionSimplify.cpp | 38 +++++-
.../Transforms/InstSimplify/fp-floor-ceil.ll | 114 ++++++++++++++++++
2 files changed, 147 insertions(+), 5 deletions(-)
create mode 100644 llvm/test/Transforms/InstSimplify/fp-floor-ceil.ll
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 32a9f1ab34fb3f..e67a2875733416 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -4130,12 +4130,9 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
//
// This catches the 2 variable input case, constants are handled below as a
// class-like compare.
+ KnownFPClass LHSClass = computeKnownFPClass(LHS, fcAllFlags, /*Depth=*/0, Q);
+ KnownFPClass RHSClass = computeKnownFPClass(RHS, fcAllFlags, /*Depth=*/0, Q);
if (Pred == FCmpInst::FCMP_ORD || Pred == FCmpInst::FCMP_UNO) {
- KnownFPClass RHSClass =
- computeKnownFPClass(RHS, fcAllFlags, /*Depth=*/0, Q);
- KnownFPClass LHSClass =
- computeKnownFPClass(LHS, fcAllFlags, /*Depth=*/0, Q);
-
if (FMF.noNaNs() ||
(RHSClass.isKnownNeverNaN() && LHSClass.isKnownNeverNaN()))
return ConstantInt::get(RetTy, Pred == FCmpInst::FCMP_ORD);
@@ -4143,6 +4140,37 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
if (RHSClass.isKnownAlwaysNaN() || LHSClass.isKnownAlwaysNaN())
return ConstantInt::get(RetTy, Pred == CmpInst::FCMP_UNO);
}
+ // floor(x) <= x --> true; x <= ceil(x) --> true
+ if (LHSClass.isKnownNeverNaN() &&
+ match(LHS, m_Intrinsic<Intrinsic::floor>(m_Specific(RHS))) ||
+ RHSClass.isKnownNeverNaN() &&
+ match(RHS, m_Intrinsic<Intrinsic::ceil>(m_Specific(LHS)))) {
+ switch (Pred) {
+ case FCmpInst::FCMP_OLE:
+ case FCmpInst::FCMP_ULE:
+ return getTrue(RetTy);
+ case FCmpInst::FCMP_OGT:
+ case FCmpInst::FCMP_UGT:
+ return getFalse(RetTy);
+ default:
+ break;
+ }
+ }
+ if (RHSClass.isKnownNeverNaN() &&
+ match(RHS, m_Intrinsic<Intrinsic::floor>(m_Specific(LHS))) ||
+ LHSClass.isKnownNeverNaN() &&
+ match(LHS, m_Intrinsic<Intrinsic::ceil>(m_Specific(RHS)))) {
+ switch (Pred) {
+ case FCmpInst::FCMP_OGE:
+ case FCmpInst::FCMP_UGE:
+ return getTrue(RetTy);
+ case FCmpInst::FCMP_OLT:
+ case FCmpInst::FCMP_ULT:
+ return getFalse(RetTy);
+ default:
+ break;
+ }
+ }
const APFloat *C = nullptr;
match(RHS, m_APFloatAllowPoison(C));
diff --git a/llvm/test/Transforms/InstSimplify/fp-floor-ceil.ll b/llvm/test/Transforms/InstSimplify/fp-floor-ceil.ll
new file mode 100644
index 00000000000000..fe78656b014ae0
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/fp-floor-ceil.ll
@@ -0,0 +1,114 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+define i1 @x_floor_ole(float %0) {
+; CHECK-LABEL: @x_floor_ole(
+; CHECK-NEXT: ret i1 true
+;
+ %2 = call nnan float @llvm.floor.f32(float %0)
+ %3 = fcmp ole float %2, %0
+ ret i1 %3
+}
+
+define i1 @x_floor_ule(float %0) {
+; CHECK-LABEL: @x_floor_ule(
+; CHECK-NEXT: ret i1 true
+;
+ %2 = call nnan float @llvm.floor.f32(float %0)
+ %3 = fcmp ule float %2, %0
+ ret i1 %3
+}
+
+define i1 @x_floor_ogt(float %0) {
+; CHECK-LABEL: @x_floor_ogt(
+; CHECK-NEXT: ret i1 false
+;
+ %2 = call nnan float @llvm.floor.f32(float %0)
+ %3 = fcmp ogt float %2, %0
+ ret i1 %3
+}
+
+define i1 @x_floor_ugt(float %0) {
+; CHECK-LABEL: @x_floor_ugt(
+; CHECK-NEXT: ret i1 false
+;
+ %2 = call nnan float @llvm.floor.f32(float %0)
+ %3 = fcmp ugt float %2, %0
+ ret i1 %3
+}
+
+define i1 @x_floor_ueq(float %0) {
+; CHECK-LABEL: @x_floor_ueq(
+; CHECK-NEXT: [[TMP2:%.*]] = call nnan float @llvm.floor.f32(float [[TMP0:%.*]])
+; CHECK-NEXT: [[TMP3:%.*]] = fcmp ueq float [[TMP2]], [[TMP0]]
+; CHECK-NEXT: ret i1 [[TMP3]]
+;
+ %2 = call nnan float @llvm.floor.f32(float %0)
+ %3 = fcmp ueq float %2, %0
+ ret i1 %3
+}
+
+define <2 x i1> @x_floor_ugt_vec(<2 x float> %0) {
+; CHECK-LABEL: @x_floor_ugt_vec(
+; CHECK-NEXT: ret <2 x i1> zeroinitializer
+;
+ %2 = call nnan <2 x float> @llvm.floor.v2f32(<2 x float> %0)
+ %3 = fcmp ugt <2 x float> %2, %0
+ ret <2 x i1> %3
+}
+
+define i1 @x_ceil_ole(float %0) {
+; CHECK-LABEL: @x_ceil_ole(
+; CHECK-NEXT: ret i1 false
+;
+ %2 = call nnan float @llvm.ceil.f32(float %0)
+ %3 = fcmp olt float %2, %0
+ ret i1 %3
+}
+
+define i1 @x_ceil_ule(float %0) {
+; CHECK-LABEL: @x_ceil_ule(
+; CHECK-NEXT: ret i1 false
+;
+ %2 = call nnan float @llvm.ceil.f32(float %0)
+ %3 = fcmp ult float %2, %0
+ ret i1 %3
+}
+
+define i1 @x_ceil_ogt(float %0) {
+; CHECK-LABEL: @x_ceil_ogt(
+; CHECK-NEXT: ret i1 true
+;
+ %2 = call nnan float @llvm.ceil.f32(float %0)
+ %3 = fcmp oge float %2, %0
+ ret i1 %3
+}
+
+define i1 @x_ceil_ugt(float %0) {
+; CHECK-LABEL: @x_ceil_ugt(
+; CHECK-NEXT: ret i1 true
+;
+ %2 = call nnan float @llvm.ceil.f32(float %0)
+ %3 = fcmp uge float %2, %0
+ ret i1 %3
+}
+
+define i1 @x_ceil_ueq(float %0) {
+; CHECK-LABEL: @x_ceil_ueq(
+; CHECK-NEXT: [[TMP2:%.*]] = call nnan float @llvm.ceil.f32(float [[TMP0:%.*]])
+; CHECK-NEXT: [[TMP3:%.*]] = fcmp ueq float [[TMP2]], [[TMP0]]
+; CHECK-NEXT: ret i1 [[TMP3]]
+;
+ %2 = call nnan float @llvm.ceil.f32(float %0)
+ %3 = fcmp ueq float %2, %0
+ ret i1 %3
+}
+
+define <2 x i1> @x_ceil_ugt_vec(<2 x float> %0) {
+; CHECK-LABEL: @x_ceil_ugt_vec(
+; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
+;
+ %2 = call nnan <2 x float> @llvm.ceil.f32(<2 x float> %0)
+ %3 = fcmp uge <2 x float> %2, %0
+ ret <2 x i1> %3
+}
>From 2555d8f0e8298aa856ddd78b6247bf9bcd5f9172 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Wed, 4 Sep 2024 21:35:20 +0800
Subject: [PATCH 2/4] address CR
---
llvm/lib/Analysis/InstructionSimplify.cpp | 38 +---
.../InstCombine/InstCombineCompares.cpp | 84 ++++++++
.../Transforms/InstCombine/fp-floor-ceil.ll | 194 ++++++++++++++++++
.../Transforms/InstSimplify/fp-floor-ceil.ll | 114 ----------
4 files changed, 283 insertions(+), 147 deletions(-)
create mode 100644 llvm/test/Transforms/InstCombine/fp-floor-ceil.ll
delete mode 100644 llvm/test/Transforms/InstSimplify/fp-floor-ceil.ll
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index e67a2875733416..32a9f1ab34fb3f 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -4130,9 +4130,12 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
//
// This catches the 2 variable input case, constants are handled below as a
// class-like compare.
- KnownFPClass LHSClass = computeKnownFPClass(LHS, fcAllFlags, /*Depth=*/0, Q);
- KnownFPClass RHSClass = computeKnownFPClass(RHS, fcAllFlags, /*Depth=*/0, Q);
if (Pred == FCmpInst::FCMP_ORD || Pred == FCmpInst::FCMP_UNO) {
+ KnownFPClass RHSClass =
+ computeKnownFPClass(RHS, fcAllFlags, /*Depth=*/0, Q);
+ KnownFPClass LHSClass =
+ computeKnownFPClass(LHS, fcAllFlags, /*Depth=*/0, Q);
+
if (FMF.noNaNs() ||
(RHSClass.isKnownNeverNaN() && LHSClass.isKnownNeverNaN()))
return ConstantInt::get(RetTy, Pred == FCmpInst::FCMP_ORD);
@@ -4140,37 +4143,6 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
if (RHSClass.isKnownAlwaysNaN() || LHSClass.isKnownAlwaysNaN())
return ConstantInt::get(RetTy, Pred == CmpInst::FCMP_UNO);
}
- // floor(x) <= x --> true; x <= ceil(x) --> true
- if (LHSClass.isKnownNeverNaN() &&
- match(LHS, m_Intrinsic<Intrinsic::floor>(m_Specific(RHS))) ||
- RHSClass.isKnownNeverNaN() &&
- match(RHS, m_Intrinsic<Intrinsic::ceil>(m_Specific(LHS)))) {
- switch (Pred) {
- case FCmpInst::FCMP_OLE:
- case FCmpInst::FCMP_ULE:
- return getTrue(RetTy);
- case FCmpInst::FCMP_OGT:
- case FCmpInst::FCMP_UGT:
- return getFalse(RetTy);
- default:
- break;
- }
- }
- if (RHSClass.isKnownNeverNaN() &&
- match(RHS, m_Intrinsic<Intrinsic::floor>(m_Specific(LHS))) ||
- LHSClass.isKnownNeverNaN() &&
- match(LHS, m_Intrinsic<Intrinsic::ceil>(m_Specific(RHS)))) {
- switch (Pred) {
- case FCmpInst::FCMP_OGE:
- case FCmpInst::FCMP_UGE:
- return getTrue(RetTy);
- case FCmpInst::FCMP_OLT:
- case FCmpInst::FCMP_ULT:
- return getFalse(RetTy);
- default:
- break;
- }
- }
const APFloat *C = nullptr;
match(RHS, m_APFloatAllowPoison(C));
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 8e8d472a5df1d3..18ab6e9bac3917 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -8178,6 +8178,87 @@ static Instruction *foldFCmpFSubIntoFCmp(FCmpInst &I, Instruction *LHSI,
return nullptr;
}
+static Instruction *foldFCmpWithFloorAndCeil(FCmpInst &I,
+ InstCombinerImpl &CI) {
+ Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
+ const CmpInst::Predicate Pred = I.getPredicate();
+ Type *OpType = LHS->getType();
+
+ // fcmp ole floor(x), x => fcmp ord x, 0
+ // fcmp ogt floor(x), x => false
+ if (match(LHS, m_Intrinsic<Intrinsic::floor>(m_Specific(RHS)))) {
+ if (Pred == FCmpInst::FCMP_OLE ||
+ Pred == FCmpInst::FCMP_ULE &&
+ isKnownNeverNaN(LHS, 0,
+ CI.getSimplifyQuery().getWithInstruction(&I))) {
+ return new FCmpInst(FCmpInst::FCMP_ORD, RHS, ConstantFP::getZero(OpType),
+ "", &I);
+ }
+ if (Pred == FCmpInst::FCMP_OGT ||
+ Pred == FCmpInst::FCMP_UGT &&
+ isKnownNeverNaN(LHS, 0,
+ CI.getSimplifyQuery().getWithInstruction(&I))) {
+ return CI.replaceInstUsesWith(I, ConstantInt::getFalse(I.getType()));
+ }
+ }
+
+ // fcmp oge x, floor(x) => fcmp ord x, 0
+ // fcmp olt x, floor(x) => false
+ if (match(RHS, m_Intrinsic<Intrinsic::floor>(m_Specific(LHS)))) {
+ if (Pred == FCmpInst::FCMP_OGE ||
+ Pred == FCmpInst::FCMP_UGE &&
+ isKnownNeverNaN(RHS, 0,
+ CI.getSimplifyQuery().getWithInstruction(&I))) {
+ return new FCmpInst(FCmpInst::FCMP_ORD, RHS, ConstantFP::getZero(OpType),
+ "", &I);
+ }
+ if (Pred == FCmpInst::FCMP_OLT ||
+ Pred == FCmpInst::FCMP_ULT &&
+ isKnownNeverNaN(RHS, 0,
+ CI.getSimplifyQuery().getWithInstruction(&I))) {
+ return CI.replaceInstUsesWith(I, ConstantInt::getFalse(I.getType()));
+ }
+ }
+
+ // fcmp oge ceil(x), x => fcmp ord x, 0
+ // fcmp olt ceil(x), x => false
+ if (match(LHS, m_Intrinsic<Intrinsic::ceil>(m_Specific(RHS)))) {
+ if (Pred == FCmpInst::FCMP_OGE ||
+ Pred == FCmpInst::FCMP_UGE &&
+ isKnownNeverNaN(LHS, 0,
+ CI.getSimplifyQuery().getWithInstruction(&I))) {
+ return new FCmpInst(FCmpInst::FCMP_ORD, RHS, ConstantFP::getZero(OpType),
+ "", &I);
+ }
+ if (Pred == FCmpInst::FCMP_OLT ||
+ Pred == FCmpInst::FCMP_ULT &&
+ isKnownNeverNaN(LHS, 0,
+ CI.getSimplifyQuery().getWithInstruction(&I))) {
+ return CI.replaceInstUsesWith(I, ConstantInt::getFalse(I.getType()));
+ }
+ }
+
+ // fcmp ole x, ceil(x) => fcmp ord x, 0
+ // fcmp ogt x, ceil(x) => false
+ if (match(RHS, m_Intrinsic<Intrinsic::ceil>(m_Specific(LHS)))) {
+ if (Pred == FCmpInst::FCMP_OLE ||
+ Pred == FCmpInst::FCMP_ULE &&
+ isKnownNeverNaN(RHS, 0,
+ CI.getSimplifyQuery().getWithInstruction(&I))) {
+ return new FCmpInst(FCmpInst::FCMP_ORD, RHS, ConstantFP::getZero(OpType),
+ "", &I);
+ }
+ if (Pred == FCmpInst::FCMP_OGT ||
+ Pred == FCmpInst::FCMP_UGT &&
+ isKnownNeverNaN(RHS, 0,
+ CI.getSimplifyQuery().getWithInstruction(&I))) {
+ return CI.replaceInstUsesWith(I, ConstantInt::getFalse(I.getType()));
+ }
+ }
+
+ return nullptr;
+}
+
Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
bool Changed = false;
@@ -8382,6 +8463,9 @@ Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
if (Instruction *R = foldSqrtWithFcmpZero(I, *this))
return R;
+ if (Instruction *R = foldFCmpWithFloorAndCeil(I, *this))
+ return R;
+
if (match(Op0, m_FNeg(m_Value(X)))) {
// fcmp pred (fneg X), C --> fcmp swap(pred) X, -C
Constant *C;
diff --git a/llvm/test/Transforms/InstCombine/fp-floor-ceil.ll b/llvm/test/Transforms/InstCombine/fp-floor-ceil.ll
new file mode 100644
index 00000000000000..7d2938f583e3d8
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/fp-floor-ceil.ll
@@ -0,0 +1,194 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i1 @floor_x_ole(float %x) {
+; CHECK-LABEL: @floor_x_ole(
+; CHECK-NEXT: [[RET:%.*]] = fcmp ord float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[RET]]
+;
+ %floor = call float @llvm.floor.f32(float %x)
+ %ret = fcmp ole float %floor, %x
+ ret i1 %ret
+}
+
+define i1 @floor_x_ule(float %x) {
+; CHECK-LABEL: @floor_x_ule(
+; CHECK-NEXT: [[RET:%.*]] = fcmp ord float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[RET]]
+;
+ %floor = call nnan float @llvm.floor.f32(float %x)
+ %ret = fcmp ule float %floor, %x
+ ret i1 %ret
+}
+
+define i1 @floor_x_ogt(float %x) {
+; CHECK-LABEL: @floor_x_ogt(
+; CHECK-NEXT: ret i1 false
+;
+ %floor = call float @llvm.floor.f32(float %x)
+ %ret = fcmp ogt float %floor, %x
+ ret i1 %ret
+}
+
+define i1 @floor_x_ugt(float %x) {
+; CHECK-LABEL: @floor_x_ugt(
+; CHECK-NEXT: ret i1 false
+;
+ %floor = call nnan float @llvm.floor.f32(float %x)
+ %ret = fcmp ugt float %floor, %x
+ ret i1 %ret
+}
+
+define i1 @x_floor_oge(float %x) {
+; CHECK-LABEL: @x_floor_oge(
+; CHECK-NEXT: [[FLOOR:%.*]] = call float @llvm.floor.f32(float [[X:%.*]])
+; CHECK-NEXT: [[RET:%.*]] = fcmp ord float [[FLOOR]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[RET]]
+;
+ %floor = call float @llvm.floor.f32(float %x)
+ %ret = fcmp oge float %x, %floor
+ ret i1 %ret
+}
+
+define i1 @x_floor_uge(float %x) {
+; CHECK-LABEL: @x_floor_uge(
+; CHECK-NEXT: ret i1 true
+;
+ %floor = call nnan float @llvm.floor.f32(float %x)
+ %ret = fcmp uge float %x, %floor
+ ret i1 %ret
+}
+
+define i1 @x_floor_olt(float %x) {
+; CHECK-LABEL: @x_floor_olt(
+; CHECK-NEXT: ret i1 false
+;
+ %floor = call float @llvm.floor.f32(float %x)
+ %ret = fcmp olt float %x, %floor
+ ret i1 %ret
+}
+
+define i1 @x_floor_ult(float nofpclass(nan) %x) {
+; CHECK-LABEL: @x_floor_ult(
+; CHECK-NEXT: ret i1 false
+;
+ %floor = call float @llvm.floor.f32(float %x)
+ %ret = fcmp ult float %x, %floor
+ ret i1 %ret
+}
+
+define <2 x i1> @x_floor_olt_vec(<2 x float> %x) {
+; CHECK-LABEL: @x_floor_olt_vec(
+; CHECK-NEXT: ret <2 x i1> zeroinitializer
+;
+ %floor = call <2 x float> @llvm.floor.f32(<2 x float> %x)
+ %ret = fcmp olt <2 x float> %x, %floor
+ ret <2 x i1> %ret
+}
+
+define i1 @x_floor_ole_neg(float %x) {
+; CHECK-LABEL: @x_floor_ole_neg(
+; CHECK-NEXT: [[FLOOR:%.*]] = call float @llvm.floor.f32(float [[X:%.*]])
+; CHECK-NEXT: [[RET:%.*]] = fcmp ole float [[X]], [[FLOOR]]
+; CHECK-NEXT: ret i1 [[RET]]
+;
+ %floor = call float @llvm.floor.f32(float %x)
+ %ret = fcmp ole float %x, %floor
+ ret i1 %ret
+}
+
+define i1 @ceil_x_oge(float %x) {
+; CHECK-LABEL: @ceil_x_oge(
+; CHECK-NEXT: [[RET:%.*]] = fcmp ord float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[RET]]
+;
+ %ceil = call float @llvm.ceil.f32(float %x)
+ %ret = fcmp oge float %ceil, %x
+ ret i1 %ret
+}
+
+define i1 @ceil_x_uge(float %x) {
+; CHECK-LABEL: @ceil_x_uge(
+; CHECK-NEXT: [[RET:%.*]] = fcmp ord float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[RET]]
+;
+ %ceil = call nnan float @llvm.ceil.f32(float %x)
+ %ret = fcmp uge float %ceil, %x
+ ret i1 %ret
+}
+
+define i1 @ceil_x_olt(float %x) {
+; CHECK-LABEL: @ceil_x_olt(
+; CHECK-NEXT: ret i1 false
+;
+ %ceil = call float @llvm.ceil.f32(float %x)
+ %ret = fcmp olt float %ceil, %x
+ ret i1 %ret
+}
+
+define i1 @ceil_x_ult(float %x) {
+; CHECK-LABEL: @ceil_x_ult(
+; CHECK-NEXT: ret i1 false
+;
+ %ceil = call nnan float @llvm.ceil.f32(float %x)
+ %ret = fcmp ult float %ceil, %x
+ ret i1 %ret
+}
+
+define i1 @x_ceil_ole(float %x) {
+; CHECK-LABEL: @x_ceil_ole(
+; CHECK-NEXT: [[CEIL:%.*]] = call float @llvm.ceil.f32(float [[X:%.*]])
+; CHECK-NEXT: [[RET:%.*]] = fcmp ord float [[CEIL]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[RET]]
+;
+ %ceil = call float @llvm.ceil.f32(float %x)
+ %ret = fcmp ole float %x, %ceil
+ ret i1 %ret
+}
+
+define i1 @x_ceil_ule(float %x) {
+; CHECK-LABEL: @x_ceil_ule(
+; CHECK-NEXT: ret i1 true
+;
+ %ceil = call nnan float @llvm.ceil.f32(float %x)
+ %ret = fcmp ule float %x, %ceil
+ ret i1 %ret
+}
+
+define i1 @x_ceil_ogt(float %x) {
+; CHECK-LABEL: @x_ceil_ogt(
+; CHECK-NEXT: ret i1 false
+;
+ %ceil = call float @llvm.ceil.f32(float %x)
+ %ret = fcmp ogt float %x, %ceil
+ ret i1 %ret
+}
+
+define i1 @x_ceil_ugt(float nofpclass(nan) %x) {
+; CHECK-LABEL: @x_ceil_ugt(
+; CHECK-NEXT: ret i1 false
+;
+ %ceil = call float @llvm.ceil.f32(float %x)
+ %ret = fcmp ugt float %x, %ceil
+ ret i1 %ret
+}
+
+define <2 x i1> @x_ceil_ogt_vec(<2 x float> %x) {
+; CHECK-LABEL: @x_ceil_ogt_vec(
+; CHECK-NEXT: ret <2 x i1> zeroinitializer
+;
+ %ceil = call <2 x float> @llvm.ceil.f32(<2 x float> %x)
+ %ret = fcmp ogt <2 x float> %x, %ceil
+ ret <2 x i1> %ret
+}
+
+define i1 @x_ceil_oge_neg(float %x) {
+; CHECK-LABEL: @x_ceil_oge_neg(
+; CHECK-NEXT: [[CEIL:%.*]] = call float @llvm.ceil.f32(float [[X:%.*]])
+; CHECK-NEXT: [[RET:%.*]] = fcmp oge float [[X]], [[CEIL]]
+; CHECK-NEXT: ret i1 [[RET]]
+;
+ %ceil = call float @llvm.ceil.f32(float %x)
+ %ret = fcmp oge float %x, %ceil
+ ret i1 %ret
+}
diff --git a/llvm/test/Transforms/InstSimplify/fp-floor-ceil.ll b/llvm/test/Transforms/InstSimplify/fp-floor-ceil.ll
deleted file mode 100644
index fe78656b014ae0..00000000000000
--- a/llvm/test/Transforms/InstSimplify/fp-floor-ceil.ll
+++ /dev/null
@@ -1,114 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
-
-define i1 @x_floor_ole(float %0) {
-; CHECK-LABEL: @x_floor_ole(
-; CHECK-NEXT: ret i1 true
-;
- %2 = call nnan float @llvm.floor.f32(float %0)
- %3 = fcmp ole float %2, %0
- ret i1 %3
-}
-
-define i1 @x_floor_ule(float %0) {
-; CHECK-LABEL: @x_floor_ule(
-; CHECK-NEXT: ret i1 true
-;
- %2 = call nnan float @llvm.floor.f32(float %0)
- %3 = fcmp ule float %2, %0
- ret i1 %3
-}
-
-define i1 @x_floor_ogt(float %0) {
-; CHECK-LABEL: @x_floor_ogt(
-; CHECK-NEXT: ret i1 false
-;
- %2 = call nnan float @llvm.floor.f32(float %0)
- %3 = fcmp ogt float %2, %0
- ret i1 %3
-}
-
-define i1 @x_floor_ugt(float %0) {
-; CHECK-LABEL: @x_floor_ugt(
-; CHECK-NEXT: ret i1 false
-;
- %2 = call nnan float @llvm.floor.f32(float %0)
- %3 = fcmp ugt float %2, %0
- ret i1 %3
-}
-
-define i1 @x_floor_ueq(float %0) {
-; CHECK-LABEL: @x_floor_ueq(
-; CHECK-NEXT: [[TMP2:%.*]] = call nnan float @llvm.floor.f32(float [[TMP0:%.*]])
-; CHECK-NEXT: [[TMP3:%.*]] = fcmp ueq float [[TMP2]], [[TMP0]]
-; CHECK-NEXT: ret i1 [[TMP3]]
-;
- %2 = call nnan float @llvm.floor.f32(float %0)
- %3 = fcmp ueq float %2, %0
- ret i1 %3
-}
-
-define <2 x i1> @x_floor_ugt_vec(<2 x float> %0) {
-; CHECK-LABEL: @x_floor_ugt_vec(
-; CHECK-NEXT: ret <2 x i1> zeroinitializer
-;
- %2 = call nnan <2 x float> @llvm.floor.v2f32(<2 x float> %0)
- %3 = fcmp ugt <2 x float> %2, %0
- ret <2 x i1> %3
-}
-
-define i1 @x_ceil_ole(float %0) {
-; CHECK-LABEL: @x_ceil_ole(
-; CHECK-NEXT: ret i1 false
-;
- %2 = call nnan float @llvm.ceil.f32(float %0)
- %3 = fcmp olt float %2, %0
- ret i1 %3
-}
-
-define i1 @x_ceil_ule(float %0) {
-; CHECK-LABEL: @x_ceil_ule(
-; CHECK-NEXT: ret i1 false
-;
- %2 = call nnan float @llvm.ceil.f32(float %0)
- %3 = fcmp ult float %2, %0
- ret i1 %3
-}
-
-define i1 @x_ceil_ogt(float %0) {
-; CHECK-LABEL: @x_ceil_ogt(
-; CHECK-NEXT: ret i1 true
-;
- %2 = call nnan float @llvm.ceil.f32(float %0)
- %3 = fcmp oge float %2, %0
- ret i1 %3
-}
-
-define i1 @x_ceil_ugt(float %0) {
-; CHECK-LABEL: @x_ceil_ugt(
-; CHECK-NEXT: ret i1 true
-;
- %2 = call nnan float @llvm.ceil.f32(float %0)
- %3 = fcmp uge float %2, %0
- ret i1 %3
-}
-
-define i1 @x_ceil_ueq(float %0) {
-; CHECK-LABEL: @x_ceil_ueq(
-; CHECK-NEXT: [[TMP2:%.*]] = call nnan float @llvm.ceil.f32(float [[TMP0:%.*]])
-; CHECK-NEXT: [[TMP3:%.*]] = fcmp ueq float [[TMP2]], [[TMP0]]
-; CHECK-NEXT: ret i1 [[TMP3]]
-;
- %2 = call nnan float @llvm.ceil.f32(float %0)
- %3 = fcmp ueq float %2, %0
- ret i1 %3
-}
-
-define <2 x i1> @x_ceil_ugt_vec(<2 x float> %0) {
-; CHECK-LABEL: @x_ceil_ugt_vec(
-; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
-;
- %2 = call nnan <2 x float> @llvm.ceil.f32(<2 x float> %0)
- %3 = fcmp uge <2 x float> %2, %0
- ret <2 x i1> %3
-}
>From f6ccb189214e20e9888a9eeab23836e8a6275cf9 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Wed, 4 Sep 2024 22:40:14 +0800
Subject: [PATCH 3/4] fmf
---
llvm/test/Transforms/InstCombine/fp-floor-ceil.ll | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/fp-floor-ceil.ll b/llvm/test/Transforms/InstCombine/fp-floor-ceil.ll
index 7d2938f583e3d8..b55cfcc6a74e0a 100644
--- a/llvm/test/Transforms/InstCombine/fp-floor-ceil.ll
+++ b/llvm/test/Transforms/InstCombine/fp-floor-ceil.ll
@@ -13,11 +13,11 @@ define i1 @floor_x_ole(float %x) {
define i1 @floor_x_ule(float %x) {
; CHECK-LABEL: @floor_x_ule(
-; CHECK-NEXT: [[RET:%.*]] = fcmp ord float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[RET:%.*]] = fcmp ninf ord float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RET]]
;
%floor = call nnan float @llvm.floor.f32(float %x)
- %ret = fcmp ule float %floor, %x
+ %ret = fcmp ninf ule float %floor, %x
ret i1 %ret
}
@@ -109,11 +109,11 @@ define i1 @ceil_x_oge(float %x) {
define i1 @ceil_x_uge(float %x) {
; CHECK-LABEL: @ceil_x_uge(
-; CHECK-NEXT: [[RET:%.*]] = fcmp ord float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[RET:%.*]] = fcmp ninf ord float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RET]]
;
%ceil = call nnan float @llvm.ceil.f32(float %x)
- %ret = fcmp uge float %ceil, %x
+ %ret = fcmp ninf uge float %ceil, %x
ret i1 %ret
}
>From a028107e47e8c2f31bb974603b94bdeb3dcb66ba Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Thu, 5 Sep 2024 08:25:29 +0800
Subject: [PATCH 4/4] inf
---
.../InstCombine/InstCombineCompares.cpp | 140 ++++++++++--------
.../Transforms/InstCombine/fp-floor-ceil.ll | 40 ++---
2 files changed, 97 insertions(+), 83 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 18ab6e9bac3917..b5ae2e2fb70461 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -8181,79 +8181,93 @@ static Instruction *foldFCmpFSubIntoFCmp(FCmpInst &I, Instruction *LHSI,
static Instruction *foldFCmpWithFloorAndCeil(FCmpInst &I,
InstCombinerImpl &CI) {
Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
- const CmpInst::Predicate Pred = I.getPredicate();
Type *OpType = LHS->getType();
+ const CmpInst::Predicate Pred = I.getPredicate();
- // fcmp ole floor(x), x => fcmp ord x, 0
- // fcmp ogt floor(x), x => false
- if (match(LHS, m_Intrinsic<Intrinsic::floor>(m_Specific(RHS)))) {
- if (Pred == FCmpInst::FCMP_OLE ||
- Pred == FCmpInst::FCMP_ULE &&
- isKnownNeverNaN(LHS, 0,
- CI.getSimplifyQuery().getWithInstruction(&I))) {
- return new FCmpInst(FCmpInst::FCMP_ORD, RHS, ConstantFP::getZero(OpType),
- "", &I);
- }
- if (Pred == FCmpInst::FCMP_OGT ||
- Pred == FCmpInst::FCMP_UGT &&
- isKnownNeverNaN(LHS, 0,
- CI.getSimplifyQuery().getWithInstruction(&I))) {
- return CI.replaceInstUsesWith(I, ConstantInt::getFalse(I.getType()));
- }
- }
+ bool floor_x = match(LHS, m_Intrinsic<Intrinsic::floor>(m_Specific(RHS)));
+ bool x_floor = match(RHS, m_Intrinsic<Intrinsic::floor>(m_Specific(LHS)));
+ bool ceil_x = match(LHS, m_Intrinsic<Intrinsic::ceil>(m_Specific(RHS)));
+ bool x_ceil = match(RHS, m_Intrinsic<Intrinsic::ceil>(m_Specific(LHS)));
- // fcmp oge x, floor(x) => fcmp ord x, 0
- // fcmp olt x, floor(x) => false
- if (match(RHS, m_Intrinsic<Intrinsic::floor>(m_Specific(LHS)))) {
- if (Pred == FCmpInst::FCMP_OGE ||
- Pred == FCmpInst::FCMP_UGE &&
- isKnownNeverNaN(RHS, 0,
- CI.getSimplifyQuery().getWithInstruction(&I))) {
+ switch (Pred) {
+ case FCmpInst::FCMP_OLE:
+ // fcmp ole floor(x), x => fcmp ord x, 0
+ // fcmp ole x, ceil(x) => fcmp ord x, 0
+ if (floor_x)
return new FCmpInst(FCmpInst::FCMP_ORD, RHS, ConstantFP::getZero(OpType),
"", &I);
- }
- if (Pred == FCmpInst::FCMP_OLT ||
- Pred == FCmpInst::FCMP_ULT &&
- isKnownNeverNaN(RHS, 0,
- CI.getSimplifyQuery().getWithInstruction(&I))) {
- return CI.replaceInstUsesWith(I, ConstantInt::getFalse(I.getType()));
- }
- }
-
- // fcmp oge ceil(x), x => fcmp ord x, 0
- // fcmp olt ceil(x), x => false
- if (match(LHS, m_Intrinsic<Intrinsic::ceil>(m_Specific(RHS)))) {
- if (Pred == FCmpInst::FCMP_OGE ||
- Pred == FCmpInst::FCMP_UGE &&
- isKnownNeverNaN(LHS, 0,
- CI.getSimplifyQuery().getWithInstruction(&I))) {
- return new FCmpInst(FCmpInst::FCMP_ORD, RHS, ConstantFP::getZero(OpType),
+ if (x_ceil)
+ return new FCmpInst(FCmpInst::FCMP_ORD, LHS, ConstantFP::getZero(OpType),
"", &I);
- }
- if (Pred == FCmpInst::FCMP_OLT ||
- Pred == FCmpInst::FCMP_ULT &&
- isKnownNeverNaN(LHS, 0,
- CI.getSimplifyQuery().getWithInstruction(&I))) {
+ break;
+ case FCmpInst::FCMP_OGT:
+ // fcmp ogt floor(x), x => false
+ // fcmp ogt x, ceil(x) => false
+ if (floor_x || x_ceil)
return CI.replaceInstUsesWith(I, ConstantInt::getFalse(I.getType()));
- }
- }
-
- // fcmp ole x, ceil(x) => fcmp ord x, 0
- // fcmp ogt x, ceil(x) => false
- if (match(RHS, m_Intrinsic<Intrinsic::ceil>(m_Specific(LHS)))) {
- if (Pred == FCmpInst::FCMP_OLE ||
- Pred == FCmpInst::FCMP_ULE &&
- isKnownNeverNaN(RHS, 0,
- CI.getSimplifyQuery().getWithInstruction(&I))) {
+ break;
+ case FCmpInst::FCMP_OGE:
+ // fcmp oge x, floor(x) => fcmp ord x, 0
+ // fcmp oge ceil(x), x => fcmp ord x, 0
+ if (x_floor)
+ return new FCmpInst(FCmpInst::FCMP_ORD, LHS, ConstantFP::getZero(OpType),
+ "", &I);
+ if (ceil_x)
return new FCmpInst(FCmpInst::FCMP_ORD, RHS, ConstantFP::getZero(OpType),
"", &I);
- }
- if (Pred == FCmpInst::FCMP_OGT ||
- Pred == FCmpInst::FCMP_UGT &&
- isKnownNeverNaN(RHS, 0,
- CI.getSimplifyQuery().getWithInstruction(&I))) {
+ break;
+ case FCmpInst::FCMP_OLT:
+ // fcmp olt x, floor(x) => false
+ // fcmp olt ceil(x), x => false
+ if (x_floor || ceil_x)
return CI.replaceInstUsesWith(I, ConstantInt::getFalse(I.getType()));
- }
+ break;
+ case FCmpInst::FCMP_ULE:
+ // fcmp ule floor(x), x => fcmp ule -inf, x
+ // fcmp ule x, ceil(x) => fcmp ule x, inf
+ if (floor_x)
+ return new FCmpInst(FCmpInst::FCMP_ULE,
+ ConstantFP::getInfinity(RHS->getType(), true), RHS,
+ "", &I);
+ if (x_ceil)
+ return new FCmpInst(FCmpInst::FCMP_ULE, LHS,
+ ConstantFP::getInfinity(LHS->getType(), false), "",
+ &I);
+ case FCmpInst::FCMP_UGT:
+ // fcmp ugt floor(x), x => fcmp ugt -inf, x
+ // fcmp ugt x, ceil(x) => fcmp ugt x, inf
+ if (floor_x)
+ return new FCmpInst(FCmpInst::FCMP_UGT,
+ ConstantFP::getInfinity(RHS->getType(), true), RHS,
+ "", &I);
+ if (x_ceil)
+ return new FCmpInst(FCmpInst::FCMP_UGT, LHS,
+ ConstantFP::getInfinity(LHS->getType(), false), "",
+ &I);
+ case FCmpInst::FCMP_UGE:
+ // fcmp uge x, floor(x) => fcmp uge x, -inf
+ // fcmp uge ceil(x), x => fcmp uge inf, x
+ if (x_floor)
+ return new FCmpInst(FCmpInst::FCMP_UGE, LHS,
+ ConstantFP::getInfinity(LHS->getType(), true), "",
+ &I);
+ if (ceil_x)
+ return new FCmpInst(FCmpInst::FCMP_UGE,
+ ConstantFP::getInfinity(RHS->getType(), false), RHS,
+ "", &I);
+ case FCmpInst::FCMP_ULT:
+ // fcmp ult x, floor(x) => fcmp ult x, -inf
+ // fcmp ult ceil(x), x => fcmp ult inf, x
+ if (x_floor)
+ return new FCmpInst(FCmpInst::FCMP_ULT, LHS,
+ ConstantFP::getInfinity(LHS->getType(), true), "",
+ &I);
+ if (ceil_x)
+ return new FCmpInst(FCmpInst::FCMP_ULT,
+ ConstantFP::getInfinity(RHS->getType(), false), RHS,
+ "", &I);
+ default:
+ break;
}
return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/fp-floor-ceil.ll b/llvm/test/Transforms/InstCombine/fp-floor-ceil.ll
index b55cfcc6a74e0a..e80ecec61e9a1c 100644
--- a/llvm/test/Transforms/InstCombine/fp-floor-ceil.ll
+++ b/llvm/test/Transforms/InstCombine/fp-floor-ceil.ll
@@ -13,10 +13,9 @@ define i1 @floor_x_ole(float %x) {
define i1 @floor_x_ule(float %x) {
; CHECK-LABEL: @floor_x_ule(
-; CHECK-NEXT: [[RET:%.*]] = fcmp ninf ord float [[X:%.*]], 0.000000e+00
-; CHECK-NEXT: ret i1 [[RET]]
+; CHECK-NEXT: ret i1 true
;
- %floor = call nnan float @llvm.floor.f32(float %x)
+ %floor = call float @llvm.floor.f32(float %x)
%ret = fcmp ninf ule float %floor, %x
ret i1 %ret
}
@@ -32,17 +31,17 @@ define i1 @floor_x_ogt(float %x) {
define i1 @floor_x_ugt(float %x) {
; CHECK-LABEL: @floor_x_ugt(
-; CHECK-NEXT: ret i1 false
+; CHECK-NEXT: [[RET:%.*]] = fcmp uno float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[RET]]
;
- %floor = call nnan float @llvm.floor.f32(float %x)
+ %floor = call float @llvm.floor.f32(float %x)
%ret = fcmp ugt float %floor, %x
ret i1 %ret
}
define i1 @x_floor_oge(float %x) {
; CHECK-LABEL: @x_floor_oge(
-; CHECK-NEXT: [[FLOOR:%.*]] = call float @llvm.floor.f32(float [[X:%.*]])
-; CHECK-NEXT: [[RET:%.*]] = fcmp ord float [[FLOOR]], 0.000000e+00
+; CHECK-NEXT: [[RET:%.*]] = fcmp ord float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RET]]
;
%floor = call float @llvm.floor.f32(float %x)
@@ -54,7 +53,7 @@ define i1 @x_floor_uge(float %x) {
; CHECK-LABEL: @x_floor_uge(
; CHECK-NEXT: ret i1 true
;
- %floor = call nnan float @llvm.floor.f32(float %x)
+ %floor = call float @llvm.floor.f32(float %x)
%ret = fcmp uge float %x, %floor
ret i1 %ret
}
@@ -68,9 +67,10 @@ define i1 @x_floor_olt(float %x) {
ret i1 %ret
}
-define i1 @x_floor_ult(float nofpclass(nan) %x) {
+define i1 @x_floor_ult(float %x) {
; CHECK-LABEL: @x_floor_ult(
-; CHECK-NEXT: ret i1 false
+; CHECK-NEXT: [[RET:%.*]] = fcmp uno float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[RET]]
;
%floor = call float @llvm.floor.f32(float %x)
%ret = fcmp ult float %x, %floor
@@ -109,10 +109,9 @@ define i1 @ceil_x_oge(float %x) {
define i1 @ceil_x_uge(float %x) {
; CHECK-LABEL: @ceil_x_uge(
-; CHECK-NEXT: [[RET:%.*]] = fcmp ninf ord float [[X:%.*]], 0.000000e+00
-; CHECK-NEXT: ret i1 [[RET]]
+; CHECK-NEXT: ret i1 true
;
- %ceil = call nnan float @llvm.ceil.f32(float %x)
+ %ceil = call float @llvm.ceil.f32(float %x)
%ret = fcmp ninf uge float %ceil, %x
ret i1 %ret
}
@@ -128,17 +127,17 @@ define i1 @ceil_x_olt(float %x) {
define i1 @ceil_x_ult(float %x) {
; CHECK-LABEL: @ceil_x_ult(
-; CHECK-NEXT: ret i1 false
+; CHECK-NEXT: [[RET:%.*]] = fcmp uno float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[RET]]
;
- %ceil = call nnan float @llvm.ceil.f32(float %x)
+ %ceil = call float @llvm.ceil.f32(float %x)
%ret = fcmp ult float %ceil, %x
ret i1 %ret
}
define i1 @x_ceil_ole(float %x) {
; CHECK-LABEL: @x_ceil_ole(
-; CHECK-NEXT: [[CEIL:%.*]] = call float @llvm.ceil.f32(float [[X:%.*]])
-; CHECK-NEXT: [[RET:%.*]] = fcmp ord float [[CEIL]], 0.000000e+00
+; CHECK-NEXT: [[RET:%.*]] = fcmp ord float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RET]]
;
%ceil = call float @llvm.ceil.f32(float %x)
@@ -150,7 +149,7 @@ define i1 @x_ceil_ule(float %x) {
; CHECK-LABEL: @x_ceil_ule(
; CHECK-NEXT: ret i1 true
;
- %ceil = call nnan float @llvm.ceil.f32(float %x)
+ %ceil = call float @llvm.ceil.f32(float %x)
%ret = fcmp ule float %x, %ceil
ret i1 %ret
}
@@ -164,9 +163,10 @@ define i1 @x_ceil_ogt(float %x) {
ret i1 %ret
}
-define i1 @x_ceil_ugt(float nofpclass(nan) %x) {
+define i1 @x_ceil_ugt(float %x) {
; CHECK-LABEL: @x_ceil_ugt(
-; CHECK-NEXT: ret i1 false
+; CHECK-NEXT: [[RET:%.*]] = fcmp uno float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[RET]]
;
%ceil = call float @llvm.ceil.f32(float %x)
%ret = fcmp ugt float %x, %ceil
More information about the llvm-commits
mailing list