Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[InstCombine] Canonicalize fcmp with inf #80986

Merged
merged 3 commits into from
Feb 7, 2024

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Feb 7, 2024

This patch canonicalizes floating-point comparisons with inf:

fcmp olt X, +inf -> fcmp one X, +inf
fcmp ole X, +inf -> fcmp ord X, 0
fcmp ogt X, +inf -> false
fcmp oge X, +inf -> fcmp oeq X, +inf
fcmp ult X, +inf -> fcmp une X, +inf
fcmp ule X, +inf -> true
fcmp ugt X, +inf -> fcmp uno X, 0
fcmp uge X, +inf -> fcmp ueq X, +inf
fcmp olt X, -inf -> false
fcmp ole X, -inf -> fcmp oeq X, -inf
fcmp ogt X, -inf -> fcmp one X, -inf
fcmp oge X, -inf -> fcmp ord X, 0
fcmp ult X, -inf -> fcmp uno X, 0
fcmp ule X, -inf -> fcmp ueq X, -inf
fcmp ugt X, -inf -> fcmp une X, -inf
fcmp uge X, -inf -> true

Alive2: https://alive2.llvm.org/ce/z/FRqqDg

The motivation of this patch is to fix the regression found in dtcxzyw/llvm-opt-benchmark#199 (comment).

@dtcxzyw dtcxzyw requested a review from nikic as a code owner February 7, 2024 12:42
dtcxzyw added a commit to dtcxzyw/llvm-opt-benchmark that referenced this pull request Feb 7, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Feb 7, 2024

@llvm/pr-subscribers-llvm-transforms

Author: Yingwei Zheng (dtcxzyw)

Changes

This patch canonicalizes floating-point comparisons with inf:

fcmp olt X, +inf -> fcmp one X, +inf
fcmp ole X, +inf -> fcmp ord X, 0
fcmp ogt X, +inf -> false
fcmp oge X, +inf -> fcmp oeq X, +inf
fcmp ult X, +inf -> fcmp une X, +inf
fcmp ule X, +inf -> true
fcmp ugt X, +inf -> fcmp uno X, 0
fcmp uge X, +inf -> fcmp ueq X, +inf
fcmp olt X, -inf -> false
fcmp ole X, -inf -> fcmp oeq X, -inf
fcmp ogt X, -inf -> fcmp one X, -inf
fcmp oge X, -inf -> fcmp ord X, 0
fcmp ult X, -inf -> fcmp uno X, 0
fcmp ule X, -inf -> fcmp ueq X, -inf
fcmp ugt X, -inf -> fcmp une X, -inf
fcmp uge X, -inf -> true

Alive2: https://alive2.llvm.org/ce/z/FRqqDg

The motivation of this patch is to fix the regression found in dtcxzyw/llvm-opt-benchmark#199 (comment).


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

5 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp (+42-1)
  • (modified) llvm/test/Transforms/InstCombine/and-fcmp.ll (+20-20)
  • (added) llvm/test/Transforms/InstCombine/canonicalize-fcmp-inf.ll (+200)
  • (modified) llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll (+2-2)
  • (modified) llvm/test/Transforms/InstCombine/fold-select-fmul-if-zero.ll (+2-2)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 380cb3504209d3..85960660e6ab06 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7751,6 +7751,48 @@ Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
   if (match(Op1, m_AnyZeroFP()) && !match(Op1, m_PosZeroFP()))
     return replaceOperand(I, 1, ConstantFP::getZero(OpType));
 
+  // Canonicalize:
+  // fcmp olt X, +inf -> fcmp one X, +inf
+  // fcmp ole X, +inf -> fcmp ord X, 0
+  // fcmp ogt X, +inf -> false
+  // fcmp oge X, +inf -> fcmp oeq X, +inf
+  // fcmp ult X, +inf -> fcmp une X, +inf
+  // fcmp ule X, +inf -> true
+  // fcmp ugt X, +inf -> fcmp uno X, 0
+  // fcmp uge X, +inf -> fcmp ueq X, +inf
+  // fcmp olt X, -inf -> false
+  // fcmp ole X, -inf -> fcmp oeq X, -inf
+  // fcmp ogt X, -inf -> fcmp one X, -inf
+  // fcmp oge X, -inf -> fcmp ord X, 0
+  // fcmp ult X, -inf -> fcmp uno X, 0
+  // fcmp ule X, -inf -> fcmp ueq X, -inf
+  // fcmp ugt X, -inf -> fcmp une X, -inf
+  // fcmp uge X, -inf -> true
+  const APFloat *C;
+  if (match(Op1, m_APFloat(C)) && C->isInfinity()) {
+    switch (C->isNegative() ? FCmpInst::getSwappedPredicate(Pred) : Pred) {
+    default:
+      break;
+    case FCmpInst::FCMP_OGT:
+    case FCmpInst::FCMP_ULE:
+      llvm_unreachable("Should be simplified by InstSimplify");
+    case FCmpInst::FCMP_OLT:
+      return new FCmpInst(FCmpInst::FCMP_ONE, Op0, Op1, "", &I);
+    case FCmpInst::FCMP_OLE:
+      return new FCmpInst(FCmpInst::FCMP_ORD, Op0, ConstantFP::getZero(OpType),
+                          "", &I);
+    case FCmpInst::FCMP_OGE:
+      return new FCmpInst(FCmpInst::FCMP_OEQ, Op0, Op1, "", &I);
+    case FCmpInst::FCMP_ULT:
+      return new FCmpInst(FCmpInst::FCMP_UNE, Op0, Op1, "", &I);
+    case FCmpInst::FCMP_UGT:
+      return new FCmpInst(FCmpInst::FCMP_UNO, Op0, ConstantFP::getZero(OpType),
+                          "", &I);
+    case FCmpInst::FCMP_UGE:
+      return new FCmpInst(FCmpInst::FCMP_UEQ, Op0, Op1, "", &I);
+    }
+  }
+
   // Ignore signbit of bitcasted int when comparing equality to FP 0.0:
   // fcmp oeq/une (bitcast X), 0.0 --> (and X, SignMaskC) ==/!= 0
   if (match(Op1, m_PosZeroFP()) &&
@@ -7864,7 +7906,6 @@ Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
   // TODO: Simplify if the copysign constant is 0.0 or NaN.
   // TODO: Handle non-zero compare constants.
   // TODO: Handle other predicates.
-  const APFloat *C;
   if (match(Op0, m_OneUse(m_Intrinsic<Intrinsic::copysign>(m_APFloat(C),
                                                            m_Value(X)))) &&
       match(Op1, m_AnyZeroFP()) && !C->isZero() && !C->isNaN()) {
diff --git a/llvm/test/Transforms/InstCombine/and-fcmp.ll b/llvm/test/Transforms/InstCombine/and-fcmp.ll
index 42e3f34d126d66..f1ae2e74ac2e4e 100644
--- a/llvm/test/Transforms/InstCombine/and-fcmp.ll
+++ b/llvm/test/Transforms/InstCombine/and-fcmp.ll
@@ -4614,7 +4614,7 @@ define i1 @intersect_fmf_4(double %a, double %b) {
 define i1 @clang_builtin_isnormal_inf_check(half %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -4627,7 +4627,7 @@ define i1 @clang_builtin_isnormal_inf_check(half %x) {
 define <2 x i1> @clang_builtin_isnormal_inf_check_vector(<2 x half> %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_vector(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge <2 x half> [[FABS_X]], <half 0xH7C00, half 0xH7C00>
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq <2 x half> [[FABS_X]], <half 0xH7C00, half 0xH7C00>
 ; CHECK-NEXT:    ret <2 x i1> [[AND]]
 ;
   %fabs.x = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
@@ -4640,7 +4640,7 @@ define <2 x i1> @clang_builtin_isnormal_inf_check_vector(<2 x half> %x) {
 define i1 @clang_builtin_isnormal_inf_check_commute(half %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_commute(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -4653,7 +4653,7 @@ define i1 @clang_builtin_isnormal_inf_check_commute(half %x) {
 define i1 @clang_builtin_isnormal_inf_check_commute_nsz_rhs(half %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_commute_nsz_rhs(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -4666,7 +4666,7 @@ define i1 @clang_builtin_isnormal_inf_check_commute_nsz_rhs(half %x) {
 define i1 @clang_builtin_isnormal_inf_check_commute_nsz_lhs(half %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_commute_nsz_lhs(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -4690,7 +4690,7 @@ define i1 @clang_builtin_isnormal_inf_check_commute_nofabs_ueq(half %x) {
 define i1 @clang_builtin_isnormal_inf_check_commute_nsz(half %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_commute_nsz(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp nsz oge half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp nsz oeq half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -4716,7 +4716,7 @@ define i1 @clang_builtin_isnormal_inf_check_ugt(half %x) {
 define i1 @clang_builtin_isnormal_inf_check_ult(half %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_ult(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp olt half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp one half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -4820,8 +4820,8 @@ define i1 @clang_builtin_isnormal_inf_check_olt(half %x) {
 
 define i1 @clang_builtin_isnormal_inf_check_ole(half %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_ole(
-; CHECK-NEXT:    [[AND:%.*]] = fcmp ord half [[X:%.*]], 0xH0000
-; CHECK-NEXT:    ret i1 [[AND]]
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ord half [[X:%.*]], 0xH0000
+; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
   %ord = fcmp ord half %fabs.x, 0.0
@@ -4846,7 +4846,7 @@ define i1 @clang_builtin_isnormal_inf_check_oeq(half %x) {
 define i1 @clang_builtin_isnormal_inf_check_unnececcary_fabs(half %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_unnececcary_fabs(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -4871,7 +4871,7 @@ define i1 @clang_builtin_isnormal_inf_check_not_ord(half %x) {
 
 define i1 @clang_builtin_isnormal_inf_check_missing_fabs(half %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_missing_fabs(
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq half [[X:%.*]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -4912,7 +4912,7 @@ define i1 @clang_builtin_isnormal_inf_check_not_inf(half %x) {
 define i1 @clang_builtin_isnormal_inf_check_nsz_lhs(half %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_nsz_lhs(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -4925,7 +4925,7 @@ define i1 @clang_builtin_isnormal_inf_check_nsz_lhs(half %x) {
 define i1 @clang_builtin_isnormal_inf_check_nsz_rhs(half %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_nsz_rhs(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -4938,7 +4938,7 @@ define i1 @clang_builtin_isnormal_inf_check_nsz_rhs(half %x) {
 define i1 @clang_builtin_isnormal_inf_check_nsz(half %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_nsz(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp nsz oge half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp nsz oeq half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -4950,7 +4950,7 @@ define i1 @clang_builtin_isnormal_inf_check_nsz(half %x) {
 
 define i1 @clang_builtin_isnormal_inf_check_fneg(half %x) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_fneg(
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq half [[X:%.*]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fneg.x = fneg half %x
@@ -4963,7 +4963,7 @@ define i1 @clang_builtin_isnormal_inf_check_fneg(half %x) {
 define i1 @clang_builtin_isnormal_inf_check_copysign(half %x, half %y) {
 ; CHECK-LABEL: @clang_builtin_isnormal_inf_check_copysign(
 ; CHECK-NEXT:    [[COPYSIGN_X:%.*]] = call half @llvm.copysign.f16(half [[X:%.*]], half [[Y:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge half [[COPYSIGN_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq half [[COPYSIGN_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %copysign.x = call half @llvm.copysign.f16(half %x, half %y)
@@ -4976,7 +4976,7 @@ define i1 @clang_builtin_isnormal_inf_check_copysign(half %x, half %y) {
 define i1 @isnormal_logical_select_0(half %x) {
 ; CHECK-LABEL: @isnormal_logical_select_0(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -4989,7 +4989,7 @@ define i1 @isnormal_logical_select_0(half %x) {
 define i1 @isnormal_logical_select_1(half %x) {
 ; CHECK-LABEL: @isnormal_logical_select_1(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -5002,7 +5002,7 @@ define i1 @isnormal_logical_select_1(half %x) {
 define i1 @isnormal_logical_select_0_fmf0(half %x) {
 ; CHECK-LABEL: @isnormal_logical_select_0_fmf0(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp reassoc nsz arcp oge half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp reassoc nsz arcp oeq half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
@@ -5015,7 +5015,7 @@ define i1 @isnormal_logical_select_0_fmf0(half %x) {
 define i1 @isnormal_logical_select_0_fmf1(half %x) {
 ; CHECK-LABEL: @isnormal_logical_select_0_fmf1(
 ; CHECK-NEXT:    [[FABS_X:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp oge half [[FABS_X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp oeq half [[FABS_X]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs.x = call half @llvm.fabs.f16(half %x)
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-fcmp-inf.ll b/llvm/test/Transforms/InstCombine/canonicalize-fcmp-inf.ll
new file mode 100644
index 00000000000000..2fd397a9be36c2
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/canonicalize-fcmp-inf.ll
@@ -0,0 +1,200 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i1 @olt_pinf(half %x) {
+; CHECK-LABEL: define i1 @olt_pinf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp one half [[X]], 0xH7C00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp olt half %x, 0xH7c00
+  ret i1 %cmp
+}
+
+define i1 @ole_pinf(half %x) {
+; CHECK-LABEL: define i1 @ole_pinf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp ole half %x, 0xH7c00
+  ret i1 %cmp
+}
+
+define i1 @ogt_pinf(half %x) {
+; CHECK-LABEL: define i1 @ogt_pinf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp = fcmp ogt half %x, 0xH7c00
+  ret i1 %cmp
+}
+
+define i1 @oge_pinf(half %x) {
+; CHECK-LABEL: define i1 @oge_pinf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq half [[X]], 0xH7C00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp oge half %x, 0xH7c00
+  ret i1 %cmp
+}
+
+define i1 @ult_pinf(half %x) {
+; CHECK-LABEL: define i1 @ult_pinf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp une half [[X]], 0xH7C00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp ult half %x, 0xH7c00
+  ret i1 %cmp
+}
+
+define i1 @ule_pinf(half %x) {
+; CHECK-LABEL: define i1 @ule_pinf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp = fcmp ule half %x, 0xH7c00
+  ret i1 %cmp
+}
+
+define i1 @ugt_pinf(half %x) {
+; CHECK-LABEL: define i1 @ugt_pinf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp ugt half %x, 0xH7c00
+  ret i1 %cmp
+}
+
+define i1 @uge_pinf(half %x) {
+; CHECK-LABEL: define i1 @uge_pinf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ueq half [[X]], 0xH7C00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp uge half %x, 0xH7c00
+  ret i1 %cmp
+}
+
+define i1 @olt_ninf(half %x) {
+; CHECK-LABEL: define i1 @olt_ninf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp = fcmp olt half %x, 0xHfc00
+  ret i1 %cmp
+}
+
+define i1 @ole_ninf(half %x) {
+; CHECK-LABEL: define i1 @ole_ninf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq half [[X]], 0xHFC00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp ole half %x, 0xHfc00
+  ret i1 %cmp
+}
+
+define i1 @ogt_ninf(half %x) {
+; CHECK-LABEL: define i1 @ogt_ninf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp one half [[X]], 0xHFC00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp ogt half %x, 0xHfc00
+  ret i1 %cmp
+}
+
+define i1 @oge_ninf(half %x) {
+; CHECK-LABEL: define i1 @oge_ninf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp oge half %x, 0xHfc00
+  ret i1 %cmp
+}
+
+define i1 @ult_ninf(half %x) {
+; CHECK-LABEL: define i1 @ult_ninf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp ult half %x, 0xHfc00
+  ret i1 %cmp
+}
+
+define i1 @ule_ninf(half %x) {
+; CHECK-LABEL: define i1 @ule_ninf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ueq half [[X]], 0xHFC00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp ule half %x, 0xHfc00
+  ret i1 %cmp
+}
+
+define i1 @ugt_ninf(half %x) {
+; CHECK-LABEL: define i1 @ugt_ninf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp une half [[X]], 0xHFC00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp ugt half %x, 0xHfc00
+  ret i1 %cmp
+}
+
+define i1 @uge_ninf(half %x) {
+; CHECK-LABEL: define i1 @uge_ninf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp = fcmp uge half %x, 0xHfc00
+  ret i1 %cmp
+}
+
+define i1 @olt_pinf_fmf(half %x) {
+; CHECK-LABEL: define i1 @olt_pinf_fmf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp nsz one half [[X]], 0xH7C00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp nsz olt half %x, 0xH7c00
+  ret i1 %cmp
+}
+
+define i1 @oge_pinf_fmf(half %x) {
+; CHECK-LABEL: define i1 @oge_pinf_fmf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp nnan oeq half [[X]], 0xH7C00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp nnan oge half %x, 0xH7c00
+  ret i1 %cmp
+}
+
+; Negative tests
+
+define i1 @ord_pinf(half %x) {
+; CHECK-LABEL: define i1 @ord_pinf(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp ord half %x, 0xH7c00
+  ret i1 %cmp
+}
+
+define i1 @olt_one(half %x) {
+; CHECK-LABEL: define i1 @olt_one(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp olt half [[X]], 0xH3C00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp olt half %x, 1.0
+  ret i1 %cmp
+}
diff --git a/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll b/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll
index ea056de3f8ee71..24dac97672f71a 100644
--- a/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll
+++ b/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll
@@ -1343,7 +1343,7 @@ define i1 @oge_eq_inf_or_uno(half %x) #0 {
 define i1 @ult_fabs_eq_inf_and_ord(half %x) #0 {
 ; CHECK-LABEL: @ult_fabs_eq_inf_and_ord(
 ; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = fcmp olt half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp one half [[FABS]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
@@ -1355,7 +1355,7 @@ define i1 @ult_fabs_eq_inf_and_ord(half %x) #0 {
 
 define i1 @ult_eq_inf_and_ord(half %x) #0 {
 ; CHECK-LABEL: @ult_eq_inf_and_ord(
-; CHECK-NEXT:    [[AND:%.*]] = fcmp olt half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = fcmp one half [[X:%.*]], 0xH7C00
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %ult.fabs.inf = fcmp ult half %x, 0xH7C00
diff --git a/llvm/test/Transforms/InstCombine/fold-select-fmul-if-zero.ll b/llvm/test/Transforms/InstCombine/fold-select-fmul-if-zero.ll
index 607b12b03b2a12..a7adcd1ac61e7f 100644
--- a/llvm/test/Transforms/InstCombine/fold-select-fmul-if-zero.ll
+++ b/llvm/test/Transforms/InstCombine/fold-select-fmul-if-zero.ll
@@ -659,7 +659,7 @@ define float @fmul_by_var_if_0_oeq_zero_f32_fmul_known_never_nan_inf_neg(float %
 define float @fmul_by_var_if_0_oeq_zero_f32_assume_finite_fmul_nsz(float %x, float %y) {
 ; CHECK-LABEL: @fmul_by_var_if_0_oeq_zero_f32_assume_finite_fmul_nsz(
 ; CHECK-NEXT:    [[FABS_Y:%.*]] = call float @llvm.fabs.f32(float [[Y:%.*]])
-; CHECK-NEXT:    [[IS_FINITE:%.*]] = fcmp olt float [[FABS_Y]], 0x7FF0000000000000
+; CHECK-NEXT:    [[IS_FINITE:%.*]] = fcmp one float [[FABS_Y]], 0x7FF0000000000000
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[IS_FINITE]])
 ; CHECK-NEXT:    ret float [[X:%.*]]
 ;
@@ -676,7 +676,7 @@ define float @fmul_by_var_if_0_oeq_zero_f32_assume_finite_fmul_nsz(float %x, flo
 define float @fmul_by_var_if_not_one_0_zero_f32_assume_finite_fmul_nsz(float %x, float %y) {
 ; CHECK-LABEL: @fmul_by_var_if_not_one_0_zero_f32_assume_finite_fmul_nsz(
 ; CHECK-NEXT:    [[FABS_Y:%.*]] = call float @llvm.fabs.f32(float [[Y:%.*]])
-; CHECK-NEXT:    [[IS_FINITE:%.*]] = fcmp olt float [[FABS_Y]], 0x7FF0000000000000
+; CHECK-NEXT:    [[IS_FINITE:%.*]] = fcmp one float [[FABS_Y]], 0x7FF0000000000000
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[IS_FINITE]])
 ; CHECK-NEXT:    ret float [[X:%.*]]
 ;

@dtcxzyw dtcxzyw merged commit 7a71ac2 into llvm:main Feb 7, 2024
3 of 4 checks passed
@dtcxzyw dtcxzyw deleted the canonicalize-fcmp-inf branch February 7, 2024 15:27
@dtcxzyw
Copy link
Member Author

dtcxzyw commented Feb 7, 2024

project/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp:7769:13: error: 16 enumeration values not handled in switch: 'FCMP_OEQ', 'FCMP_ONE', 'FCMP_UEQ'... [-Werror,-Wswitch]

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Feb 7, 2024

project/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp:7769:13: error: 16 enumeration values not handled in switch: 'FCMP_OEQ', 'FCMP_ONE', 'FCMP_UEQ'... [-Werror,-Wswitch]

Fixed by 934ba0d.

dtcxzyw added a commit that referenced this pull request Feb 8, 2024
This patch generalizes `simplifyAndOrOfFCmps` to simplify patterns like:
```
define i1 @src(float %x, float %y) {
  %or.cond.i = fcmp ord float %x, 0.000000e+00
  %cmp.i.i34 = fcmp olt float %x, %y
  %cmp.i2.sink.i = and i1 %or.cond.i, %cmp.i.i34
  ret i1 %cmp.i2.sink.i
}

define i1 @tgt(float %x, float %y) {
  %cmp.i.i34 = fcmp olt float %x, %y
  ret i1 %cmp.i.i34
}
```
Alive2: https://alive2.llvm.org/ce/z/9rydcx

This patch and #80986 will fix the regression introduced by #80941.
See also the IR diff
dtcxzyw/llvm-opt-benchmark#199 (comment).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants