Skip to content

[InstCombine] Simplify compare abs(X) and X. #76385

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

Merged
merged 2 commits into from
Jan 5, 2024
Merged

[InstCombine] Simplify compare abs(X) and X. #76385

merged 2 commits into from
Jan 5, 2024

Conversation

Z572
Copy link
Contributor

@Z572 Z572 commented Dec 26, 2023

@llvmbot
Copy link
Member

llvmbot commented Dec 26, 2023

@llvm/pr-subscribers-llvm-transforms

Author: None (Z572)

Changes

fix #72653
proof: https://alive2.llvm.org/ce/z/zPNyUb


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

2 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp (+41)
  • (added) llvm/test/Transforms/InstCombine/icmp-abs.ll (+212)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 289976718e52f3..19ddffe75ff9b6 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7109,6 +7109,47 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
     }
   }
 
+  {
+    Value *X;
+    Constant *C;
+    if (match(Op0, m_OneUse(m_Intrinsic<Intrinsic::abs>(m_Value(X),
+                                                        m_Constant(C)))) &&
+        match(Op1, m_Specific(X))) {
+      auto *NullValue = Constant::getNullValue(X->getType());
+      auto *MinVal = ConstantInt::get(
+          X->getType(),
+          APInt::getSignedMinValue(X->getType()->getScalarSizeInBits()));
+      bool IsIntMinPosion = C->isZeroValue();
+      switch (Pred) {
+      case CmpInst::ICMP_ULE:
+      case CmpInst::ICMP_SGE:
+        return replaceInstUsesWith(I, ConstantInt::getTrue(I.getType()));
+      case CmpInst::ICMP_UGT:
+      case CmpInst::ICMP_SLT:
+        return replaceInstUsesWith(I, ConstantInt::getFalse(I.getType()));
+      case CmpInst::ICMP_UGE:
+      case CmpInst::ICMP_SLE:
+      case CmpInst::ICMP_EQ: {
+        auto *SGE = Builder.CreateICmpSGE(X, NullValue);
+        return replaceInstUsesWith(
+            I, IsIntMinPosion
+                   ? Builder.CreateOr(SGE, Builder.CreateICmpEQ(X, MinVal))
+                   : SGE);
+      }
+      case CmpInst::ICMP_ULT:
+      case CmpInst::ICMP_NE:
+      case CmpInst::ICMP_SGT: {
+        auto *SLT = Builder.CreateICmpSLT(X, NullValue);
+        return replaceInstUsesWith(
+            I, IsIntMinPosion
+                   ? Builder.CreateAnd(SLT, Builder.CreateICmpNE(X, MinVal))
+                   : SLT);
+      }
+      default:
+        break;
+      }
+    }
+  }
   if (Instruction *Res = foldICmpEquality(I))
     return Res;
 
diff --git a/llvm/test/Transforms/InstCombine/icmp-abs.ll b/llvm/test/Transforms/InstCombine/icmp-abs.ll
new file mode 100644
index 00000000000000..382dab800dd942
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/icmp-abs.ll
@@ -0,0 +1,212 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+target datalayout = "e-p:64:64:64-p1:16:16:16-p2:32:32:32-p3:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+declare i4 @llvm.abs.i4(i4, i1)
+declare void @use_i4(i4)
+
+define i1 @icmp_sge_abs(i4 %arg) {
+; CHECK-LABEL: @icmp_sge_abs(
+; CHECK-NEXT:    ret i1 true
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
+  %cmp = icmp sge i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_sge_abs_false(i4 %arg) {
+; CHECK-LABEL: @icmp_sge_abs_false(
+; CHECK-NEXT:    ret i1 true
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
+  %cmp = icmp sge i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_eq_abs(i4 %arg) {
+; CHECK-LABEL: @icmp_eq_abs(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i4 [[ARG:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
+  %cmp = icmp eq i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_eq_abs_false(i4 %arg) {
+; CHECK-LABEL: @icmp_eq_abs_false(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i4 [[ARG:%.*]], -7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
+  %cmp = icmp eq i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_ne_abs(i4 %arg) {
+; CHECK-LABEL: @icmp_ne_abs(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i4 [[ARG:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
+  %cmp = icmp ne i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_ne_abs_false(i4 %arg) {
+; CHECK-LABEL: @icmp_ne_abs_false(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i4 [[ARG:%.*]], -8
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
+  %cmp = icmp ne i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_sle_abs(i4 %arg) {
+; CHECK-LABEL: @icmp_sle_abs(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i4 [[ARG:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
+  %cmp = icmp sle i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_sle_abs_false(i4 %arg) {
+; CHECK-LABEL: @icmp_sle_abs_false(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i4 [[ARG:%.*]], -7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
+  %cmp = icmp sle i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_slt_abs(i4 %arg) {
+; CHECK-LABEL: @icmp_slt_abs(
+; CHECK-NEXT:    ret i1 false
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
+  %cmp = icmp slt i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_slt_abs_false(i4 %arg) {
+; CHECK-LABEL: @icmp_slt_abs_false(
+; CHECK-NEXT:    ret i1 false
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
+  %cmp = icmp slt i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_sgt_abs(i4 %arg) {
+; CHECK-LABEL: @icmp_sgt_abs(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i4 [[ARG:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
+  %cmp = icmp sgt i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_sgt_abs_false(i4 %arg) {
+; CHECK-LABEL: @icmp_sgt_abs_false(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i4 [[ARG:%.*]], -8
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
+  %cmp = icmp sgt i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_ugt_abs(i4 %arg) {
+; CHECK-LABEL: @icmp_ugt_abs(
+; CHECK-NEXT:    ret i1 false
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
+  %cmp = icmp ugt i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_ugt_abs_false(i4 %arg) {
+; CHECK-LABEL: @icmp_ugt_abs_false(
+; CHECK-NEXT:    ret i1 false
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
+  %cmp = icmp ugt i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_uge_abs(i4 %arg) {
+; CHECK-LABEL: @icmp_uge_abs(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i4 [[ARG:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
+  %cmp = icmp uge i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_uge_abs_false(i4 %arg) {
+; CHECK-LABEL: @icmp_uge_abs_false(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i4 [[ARG:%.*]], -7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
+  %cmp = icmp uge i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_ule_abs(i4 %arg) {
+; CHECK-LABEL: @icmp_ule_abs(
+; CHECK-NEXT:    ret i1 true
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
+  %cmp = icmp ule i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_ule_abs_false(i4 %arg) {
+; CHECK-LABEL: @icmp_ule_abs_false(
+; CHECK-NEXT:    ret i1 true
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
+  %cmp = icmp ule i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_ult_abs(i4 %arg) {
+; CHECK-LABEL: @icmp_ult_abs(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i4 [[ARG:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
+  %cmp = icmp ult i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_ult_abs_false(i4 %arg) {
+; CHECK-LABEL: @icmp_ult_abs_false(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i4 [[ARG:%.*]], -8
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
+  %cmp = icmp ult i4 %abs, %arg
+  ret i1 %cmp
+}
+
+define i1 @icmp_sgt_abs_use(i4 %arg) {
+; CHECK-LABEL: @icmp_sgt_abs_use(
+; CHECK-NEXT:    [[ABS:%.*]] = call i4 @llvm.abs.i4(i4 [[ARG:%.*]], i1 false)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i4 [[ABS]], [[ARG]]
+; CHECK-NEXT:    call void @use_i4(i4 [[ABS]])
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
+  %cmp = icmp sgt i4 %abs, %arg
+  call void @use_i4(i4 %abs)
+  ret i1 %cmp
+}

@dtcxzyw
Copy link
Member

dtcxzyw commented Dec 26, 2023

See also #73189.

@dtcxzyw dtcxzyw requested a review from fhahn December 26, 2023 07:55
@nikic
Copy link
Contributor

nikic commented Jan 2, 2024

Please rebase over 9d5b096 and move the fold into foldICmpCommutative().

Copy link
Member

@dtcxzyw dtcxzyw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Please wait for additional approval from other reviewers.

dtcxzyw added a commit to dtcxzyw/llvm-opt-benchmark that referenced this pull request Jan 4, 2024
Copy link
Member

@dtcxzyw dtcxzyw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Please wait for additional approval from other reviewers.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Z572 Z572 merged commit 86ef039 into llvm:main Jan 5, 2024
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.

a <= abs(a) is always true
4 participants