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

[ValueTracking] Add support for xor/disjoint or in getInvertibleOperands #87705

Closed

Conversation

goldsteinn
Copy link
Contributor

@goldsteinn goldsteinn commented Apr 4, 2024

  • [ValueTracking] Add tests for xor/disjoint or in getInvertibleOperands; NFC
  • [ValueTracking] Add support for xor/disjoint or in getInvertibleOperands

This strengthens our isKnownNonEqual logic with some fairly
trivial cases.

Proofs: https://alive2.llvm.org/ce/z/4pxRTj

@llvmbot
Copy link
Collaborator

llvmbot commented Apr 4, 2024

@llvm/pr-subscribers-llvm-analysis

@llvm/pr-subscribers-llvm-transforms

Author: None (goldsteinn)

Changes
  • [ValueTracking] Add tests for xor/disjoint or in getInvertibleOperands; NFC
  • [ValueTracking] Add support for xor/disjoint or in getInvertibleOperands

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

2 Files Affected:

  • (modified) llvm/lib/Analysis/ValueTracking.cpp (+14-1)
  • (modified) llvm/test/Transforms/InstSimplify/icmp.ll (+79-1)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 5ad4da43bca7db..885f4b0907ea6b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3004,7 +3004,20 @@ getInvertibleOperands(const Operator *Op1,
   switch (Op1->getOpcode()) {
   default:
     break;
-  case Instruction::Add:
+  case Instruction::Or:
+    if (!cast<PossiblyDisjointInst>(Op1)->isDisjoint() ||
+        !cast<PossiblyDisjointInst>(Op2)->isDisjoint())
+      break;
+    [[fallthrough]];
+  case Instruction::Xor:
+  case Instruction::Add: {
+    Value *Other;
+    if (match(Op2, m_c_BinOp(m_Specific(Op1->getOperand(0)), m_Value(Other))))
+      return std::make_pair(Op1->getOperand(1), Other);
+    if (match(Op2, m_c_BinOp(m_Specific(Op1->getOperand(1)), m_Value(Other))))
+      return std::make_pair(Op1->getOperand(0), Other);
+    break;
+  }
   case Instruction::Sub:
     if (Op1->getOperand(0) == Op2->getOperand(0))
       return getOperands(1);
diff --git a/llvm/test/Transforms/InstSimplify/icmp.ll b/llvm/test/Transforms/InstSimplify/icmp.ll
index 3109768bdfe005..d1799098115496 100644
--- a/llvm/test/Transforms/InstSimplify/icmp.ll
+++ b/llvm/test/Transforms/InstSimplify/icmp.ll
@@ -270,7 +270,7 @@ define i1 @load_ptr(ptr %p) {
 
 define i1 @load_ptr_null_valid(ptr %p) null_pointer_is_valid {
 ; CHECK-LABEL: @load_ptr_null_valid(
-; CHECK-NEXT:    [[LOAD_P:%.*]] = load ptr, ptr [[P:%.*]], align 8, !dereferenceable !0
+; CHECK-NEXT:    [[LOAD_P:%.*]] = load ptr, ptr [[P:%.*]], align 8, !dereferenceable [[META0:![0-9]+]]
 ; CHECK-NEXT:    [[R:%.*]] = icmp ne ptr [[LOAD_P]], null
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
@@ -278,3 +278,81 @@ define i1 @load_ptr_null_valid(ptr %p) null_pointer_is_valid {
   %r = icmp ne ptr %load_p, null
   ret i1 %r
 }
+
+define i1 @non_eq_disjoint_or_common_op(i8 %x, i8 %y, i8 %ww, i8 %a) {
+; CHECK-LABEL: @non_eq_disjoint_or_common_op(
+; CHECK-NEXT:    ret i1 false
+;
+  %w = add nuw i8 %ww, 1
+  %z = add i8 %y, %w
+
+  %xy = or disjoint i8 %x, %y
+  %xz = or disjoint i8 %x, %z
+
+  %axy = add i8 %a, %xy
+  %axz = add i8 %a, %xz
+  %r = icmp eq i8 %axy, %axz
+  ret i1 %r
+}
+
+define i1 @non_eq_disjoint_or_common_op_fail(i8 %x, i8 %y, i8 %ww, i8 %a) {
+; CHECK-LABEL: @non_eq_disjoint_or_common_op_fail(
+; CHECK-NEXT:    [[W:%.*]] = add nuw i8 [[WW:%.*]], 1
+; CHECK-NEXT:    [[Z:%.*]] = add i8 [[Y:%.*]], [[W]]
+; CHECK-NEXT:    [[XY:%.*]] = or i8 [[X:%.*]], [[Y]]
+; CHECK-NEXT:    [[XZ:%.*]] = or disjoint i8 [[X]], [[Z]]
+; CHECK-NEXT:    [[AXY:%.*]] = add i8 [[A:%.*]], [[XY]]
+; CHECK-NEXT:    [[AXZ:%.*]] = add i8 [[A]], [[XZ]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[AXY]], [[AXZ]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %w = add nuw i8 %ww, 1
+  %z = add i8 %y, %w
+
+  %xy = or i8 %x, %y
+  %xz = or disjoint i8 %x, %z
+
+  %axy = add i8 %a, %xy
+  %axz = add i8 %a, %xz
+  %r = icmp eq i8 %axy, %axz
+  ret i1 %r
+}
+
+define i1 @non_eq_xor_common_op(i8 %x, i8 %y, i8 %ww, i8 %a) {
+; CHECK-LABEL: @non_eq_xor_common_op(
+; CHECK-NEXT:    ret i1 false
+;
+  %w = add nuw i8 %ww, 1
+  %z = add i8 %y, %w
+
+  %xy = xor i8 %y, %x
+  %xz = xor i8 %x, %z
+
+  %axy = add i8 %a, %xy
+  %axz = add i8 %a, %xz
+  %r = icmp eq i8 %axy, %axz
+  ret i1 %r
+}
+
+define i1 @non_eq_xor_common_op_fail(i8 %x, i8 %y, i8 %ww, i8 %a) {
+; CHECK-LABEL: @non_eq_xor_common_op_fail(
+; CHECK-NEXT:    [[W:%.*]] = add nsw i8 [[WW:%.*]], 1
+; CHECK-NEXT:    [[Z:%.*]] = add i8 [[Y:%.*]], [[W]]
+; CHECK-NEXT:    [[XY:%.*]] = xor i8 [[Y]], [[X:%.*]]
+; CHECK-NEXT:    [[XZ:%.*]] = xor i8 [[X]], [[Z]]
+; CHECK-NEXT:    [[AXY:%.*]] = add i8 [[A:%.*]], [[XY]]
+; CHECK-NEXT:    [[AXZ:%.*]] = add i8 [[A]], [[XZ]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[AXY]], [[AXZ]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %w = add nsw i8 %ww, 1
+  %z = add i8 %y, %w
+
+  %xy = xor i8 %y, %x
+  %xz = xor i8 %x, %z
+
+  %axy = add i8 %a, %xy
+  %axz = add i8 %a, %xz
+  %r = icmp eq i8 %axy, %axz
+  ret i1 %r
+}

@goldsteinn goldsteinn changed the title goldsteinn/or xor no invertible [ValueTracking] Add support for xor/disjoint or in getInvertibleOperands Apr 4, 2024
@goldsteinn goldsteinn requested a review from dtcxzyw April 4, 2024 20:43
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

dtcxzyw added a commit to dtcxzyw/llvm-opt-benchmark that referenced this pull request Apr 10, 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.

None yet

4 participants