[llvm] f2816ff - [InstCombine] Simplify and/or by replacing operands with constants (#77231)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 30 22:31:00 PST 2024


Author: Yingwei Zheng
Date: 2024-01-31T14:30:55+08:00
New Revision: f2816ff60c7dae0347beba9b11154b33e6311059

URL: https://github.com/llvm/llvm-project/commit/f2816ff60c7dae0347beba9b11154b33e6311059
DIFF: https://github.com/llvm/llvm-project/commit/f2816ff60c7dae0347beba9b11154b33e6311059.diff

LOG: [InstCombine] Simplify and/or by replacing operands with constants (#77231)

This patch tries to simplify `X | Y` by replacing occurrences of `Y` in
`X` with 0. Similarly, it tries to simplify `X & Y` by replacing
occurrences of `Y` in `X` with -1.

Alive2: https://alive2.llvm.org/ce/z/cNjDTR
Note: As the current implementation is too conservative in the one-use
checks, I cannot remove other existing hard-coded simplifications if
they involves more than two instructions (e.g, `A & ~(A ^ B) --> A &
B`).

Compile-time impact:
http://llvm-compile-time-tracker.com/compare.php?from=a085402ef54379758e6c996dbaedfcb92ad222b5&to=9d655c6685865ffce0ad336fed81228f3071bd03&stat=instructions%3Au

|stage1-O3|stage1-ReleaseThinLTO|stage1-ReleaseLTO-g|stage1-O0-g|stage2-O3|stage2-O0-g|stage2-clang|
|--|--|--|--|--|--|--|
|+0.01%|-0.00%|+0.00%|-0.02%|+0.01%|+0.02%|-0.01%|

Fixes #76554.

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
    llvm/test/Transforms/InstCombine/and-or-icmps.ll
    llvm/test/Transforms/InstCombine/and-or-not.ll
    llvm/test/Transforms/InstCombine/and-xor-or.ll
    llvm/test/Transforms/InstCombine/or-xor.ll
    llvm/test/Transforms/InstCombine/or.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 5fd944a859ef0..1cfa797be2207 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2179,6 +2179,49 @@ foldBitwiseLogicWithIntrinsics(BinaryOperator &I,
   }
 }
 
+// Try to simplify X | Y by replacing occurrences of Y in X with 0.
+// Similarly, simplify X & Y by replacing occurrences of Y in X with -1.
+// Return the simplified result of X if successful, and nullptr otherwise.
+static Value *simplifyAndOrWithOpReplaced(Value *X, Value *Y, bool IsAnd,
+                                          InstCombinerImpl &IC,
+                                          unsigned Depth = 0) {
+  if (isa<Constant>(X) || X == Y)
+    return nullptr;
+
+  Value *RHS;
+  if (match(X, m_c_And(m_Specific(Y), m_Value(RHS)))) {
+    return IsAnd ? RHS : Constant::getNullValue(X->getType());
+  } else if (match(X, m_c_Or(m_Specific(Y), m_Value(RHS)))) {
+    return IsAnd ? Constant::getAllOnesValue(X->getType()) : RHS;
+  } else if (match(X, m_c_Xor(m_Specific(Y), m_Value(RHS)))) {
+    if (IsAnd) {
+      if (X->hasOneUse())
+        return IC.Builder.CreateNot(RHS);
+
+      if (Value *NotRHS =
+              IC.getFreelyInverted(RHS, RHS->hasOneUse(), &IC.Builder))
+        return NotRHS;
+    } else
+      return RHS;
+  }
+
+  // Replace uses of Y in X recursively.
+  Value *Op0, *Op1;
+  if (Depth < 2 && match(X, m_BitwiseLogic(m_Value(Op0), m_Value(Op1)))) {
+    // TODO: Relax the one-use constraint to clean up existing hard-coded
+    // simplifications.
+    if (!X->hasOneUse())
+      return nullptr;
+    Value *NewOp0 = simplifyAndOrWithOpReplaced(Op0, Y, IsAnd, IC, Depth + 1);
+    Value *NewOp1 = simplifyAndOrWithOpReplaced(Op1, Y, IsAnd, IC, Depth + 1);
+    if (!NewOp0 && !NewOp1)
+      return nullptr;
+    return IC.Builder.CreateBinOp(cast<BinaryOperator>(X)->getOpcode(),
+                                  NewOp0 ? NewOp0 : Op0, NewOp1 ? NewOp1 : Op1);
+  }
+  return nullptr;
+}
+
 // FIXME: We use commutative matchers (m_c_*) for some, but not all, matches
 // here. We should standardize that construct where it is needed or choose some
 // other way to ensure that commutated variants of patterns are not missed.
@@ -2505,13 +2548,6 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
 
   {
     Value *A, *B, *C;
-    // A & (A ^ B) --> A & ~B
-    if (match(Op1, m_OneUse(m_c_Xor(m_Specific(Op0), m_Value(B)))))
-      return BinaryOperator::CreateAnd(Op0, Builder.CreateNot(B));
-    // (A ^ B) & A --> A & ~B
-    if (match(Op0, m_OneUse(m_c_Xor(m_Specific(Op1), m_Value(B)))))
-      return BinaryOperator::CreateAnd(Op1, Builder.CreateNot(B));
-
     // A & ~(A ^ B) --> A & B
     if (match(Op1, m_Not(m_c_Xor(m_Specific(Op0), m_Value(B)))))
       return BinaryOperator::CreateAnd(Op0, B);
@@ -2708,6 +2744,11 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
   if (Instruction *Res = foldBitwiseLogicWithIntrinsics(I, Builder))
     return Res;
 
+  if (Value *V = simplifyAndOrWithOpReplaced(Op0, Op1, /*IsAnd*/ true, *this))
+    return BinaryOperator::CreateAnd(V, Op1);
+  if (Value *V = simplifyAndOrWithOpReplaced(Op1, Op0, /*IsAnd*/ true, *this))
+    return BinaryOperator::CreateAnd(Op0, V);
+
   return nullptr;
 }
 
@@ -3423,10 +3464,6 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
     return BinaryOperator::CreateMul(X, IncrementY);
   }
 
-  // X | (X ^ Y) --> X | Y (4 commuted patterns)
-  if (match(&I, m_c_Or(m_Value(X), m_c_Xor(m_Deferred(X), m_Value(Y)))))
-    return BinaryOperator::CreateOr(X, Y);
-
   // (A & C) | (B & D)
   Value *A, *B, *C, *D;
   if (match(Op0, m_And(m_Value(A), m_Value(C))) &&
@@ -3911,6 +3948,11 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
   if (Instruction *Res = foldBitwiseLogicWithIntrinsics(I, Builder))
     return Res;
 
+  if (Value *V = simplifyAndOrWithOpReplaced(Op0, Op1, /*IsAnd*/ false, *this))
+    return BinaryOperator::CreateOr(V, Op1);
+  if (Value *V = simplifyAndOrWithOpReplaced(Op1, Op0, /*IsAnd*/ false, *this))
+    return BinaryOperator::CreateOr(Op0, V);
+
   return nullptr;
 }
 

diff  --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
index 91ecf24760259..c8d348df5f427 100644
--- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
@@ -369,16 +369,12 @@ define void @simplify_before_foldAndOfICmps(ptr %p) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i16 [[L7]], -1
 ; CHECK-NEXT:    [[B11:%.*]] = zext i1 [[TMP1]] to i16
 ; CHECK-NEXT:    [[C10:%.*]] = icmp ugt i16 [[L7]], [[B11]]
-; CHECK-NEXT:    [[C5:%.*]] = icmp slt i16 [[L7]], 1
 ; CHECK-NEXT:    [[C7:%.*]] = icmp slt i16 [[L7]], 0
-; CHECK-NEXT:    [[B15:%.*]] = xor i1 [[C7]], [[C10]]
-; CHECK-NEXT:    [[C6:%.*]] = xor i1 [[B15]], true
-; CHECK-NEXT:    [[TMP2:%.*]] = and i1 [[C5]], [[C6]]
-; CHECK-NEXT:    [[C3:%.*]] = and i1 [[TMP2]], [[C10]]
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i1 [[C10]], true
-; CHECK-NEXT:    [[C18:%.*]] = or i1 [[C7]], [[TMP3]]
-; CHECK-NEXT:    [[TMP4:%.*]] = sext i1 [[C3]] to i64
-; CHECK-NEXT:    [[G26:%.*]] = getelementptr i1, ptr null, i64 [[TMP4]]
+; CHECK-NEXT:    [[C3:%.*]] = and i1 [[C7]], [[C10]]
+; CHECK-NEXT:    [[TMP2:%.*]] = xor i1 [[C10]], true
+; CHECK-NEXT:    [[C18:%.*]] = or i1 [[C7]], [[TMP2]]
+; CHECK-NEXT:    [[TMP3:%.*]] = sext i1 [[C3]] to i64
+; CHECK-NEXT:    [[G26:%.*]] = getelementptr i1, ptr null, i64 [[TMP3]]
 ; CHECK-NEXT:    store i16 [[L7]], ptr [[P:%.*]], align 2
 ; CHECK-NEXT:    store i1 [[C18]], ptr [[P]], align 1
 ; CHECK-NEXT:    store ptr [[G26]], ptr [[P]], align 8

diff  --git a/llvm/test/Transforms/InstCombine/and-or-not.ll b/llvm/test/Transforms/InstCombine/and-or-not.ll
index ca093eba1b568..2e351c30ea1f7 100644
--- a/llvm/test/Transforms/InstCombine/and-or-not.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-not.ll
@@ -761,11 +761,7 @@ define i4 @simplify_and_common_op_use1(i4 %x, i4 %y, i4 %z)  {
 define i4 @simplify_and_common_op_use2(i4 %x, i4 %y, i4 %z)  {
 ; CHECK-LABEL: @simplify_and_common_op_use2(
 ; CHECK-NEXT:    call void @use(i4 [[Y:%.*]])
-; CHECK-NEXT:    [[TMP1:%.*]] = or i4 [[X:%.*]], [[Z:%.*]]
-; CHECK-NEXT:    [[XYZ:%.*]] = or i4 [[TMP1]], [[Y]]
-; CHECK-NEXT:    [[NOT_XYZ:%.*]] = xor i4 [[XYZ]], -1
-; CHECK-NEXT:    [[R:%.*]] = and i4 [[NOT_XYZ]], [[X]]
-; CHECK-NEXT:    ret i4 [[R]]
+; CHECK-NEXT:    ret i4 0
 ;
   %xy = or i4 %y, %x
   call void @use(i4 %y)
@@ -779,12 +775,8 @@ define i4 @simplify_and_common_op_use2(i4 %x, i4 %y, i4 %z)  {
 
 define i4 @simplify_and_common_op_use3(i4 %x, i4 %y, i4 %z)  {
 ; CHECK-LABEL: @simplify_and_common_op_use3(
-; CHECK-NEXT:    [[XY:%.*]] = or i4 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[XYZ:%.*]] = or i4 [[XY]], [[Z:%.*]]
-; CHECK-NEXT:    call void @use(i4 [[Z]])
-; CHECK-NEXT:    [[NOT_XYZ:%.*]] = xor i4 [[XYZ]], -1
-; CHECK-NEXT:    [[R:%.*]] = and i4 [[NOT_XYZ]], [[X]]
-; CHECK-NEXT:    ret i4 [[R]]
+; CHECK-NEXT:    call void @use(i4 [[Z:%.*]])
+; CHECK-NEXT:    ret i4 0
 ;
   %xy = or i4 %x, %y
   %xyz = or i4 %xy, %z

diff  --git a/llvm/test/Transforms/InstCombine/and-xor-or.ll b/llvm/test/Transforms/InstCombine/and-xor-or.ll
index 69a7890bee22f..d072dc15cbb2c 100644
--- a/llvm/test/Transforms/InstCombine/and-xor-or.ll
+++ b/llvm/test/Transforms/InstCombine/and-xor-or.ll
@@ -3,6 +3,7 @@
 
 declare void @use(i32)
 declare void @use_i8(i8)
+declare void @use_i1(i1)
 
 ; a & (a ^ b) --> a & ~b
 
@@ -112,7 +113,7 @@ define i32 @and_xor_not_common_op_extrause(i32 %a, i32 %b, ptr %dst) {
 ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], ptr [[DST:%.*]]) {
 ; CHECK-NEXT:    [[B2:%.*]] = xor i32 [[B]], -1
 ; CHECK-NEXT:    store i32 [[B2]], ptr [[DST]], align 4
-; CHECK-NEXT:    [[T4:%.*]] = and i32 [[A]], [[B]]
+; CHECK-NEXT:    [[T4:%.*]] = and i32 [[B]], [[A]]
 ; CHECK-NEXT:    ret i32 [[T4]]
 ;
   %b2 = xor i32 %b, -1
@@ -4780,3 +4781,32 @@ define i32 @canonicalize_logic_first_constexpr_nuw(i32 %x) {
   %r = and i32 %a, -10
   ret i32 %r
 }
+
+define i1 @test_and_xor_freely_invertable(i32 %x, i32 %y, i1 %z) {
+; CHECK-LABEL: define {{[^@]+}}@test_and_xor_freely_invertable
+; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i1 [[Z:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sle i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP]], [[Z]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp = icmp sgt i32 %x, %y
+  %xor = xor i1 %cmp, %z
+  %and = and i1 %xor, %z
+  ret i1 %and
+}
+
+define i1 @test_and_xor_freely_invertable_multiuse(i32 %x, i32 %y, i1 %z) {
+; CHECK-LABEL: define {{[^@]+}}@test_and_xor_freely_invertable_multiuse
+; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i1 [[Z:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[X]], [[Y]]
+; CHECK-NEXT:    call void @use_i1(i1 [[CMP]])
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[CMP]], true
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[TMP1]], [[Z]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp = icmp sgt i32 %x, %y
+  call void @use_i1(i1 %cmp)
+  %xor = xor i1 %cmp, %z
+  %and = and i1 %xor, %z
+  ret i1 %and
+}

diff  --git a/llvm/test/Transforms/InstCombine/or-xor.ll b/llvm/test/Transforms/InstCombine/or-xor.ll
index 361aab6c21e27..443a0898df0d7 100644
--- a/llvm/test/Transforms/InstCombine/or-xor.ll
+++ b/llvm/test/Transforms/InstCombine/or-xor.ll
@@ -156,7 +156,7 @@ define i16 @test5_extra_use_not_xor(i16 %x, i16 %y, ptr %dst_not, ptr %dst_xor)
 
 define i8 @xor_common_op_commute0(i8 %x, i8 %y) {
 ; CHECK-LABEL: @xor_common_op_commute0(
-; CHECK-NEXT:    [[Z:%.*]] = or i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[Z:%.*]] = or i8 [[Y:%.*]], [[X:%.*]]
 ; CHECK-NEXT:    ret i8 [[Z]]
 ;
   %xor = xor i8 %x, %y
@@ -168,7 +168,7 @@ define i8 @xor_common_op_commute1(i8 %x, i8 %y) {
 ; CHECK-LABEL: @xor_common_op_commute1(
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[Y:%.*]], [[X:%.*]]
 ; CHECK-NEXT:    call void @use(i8 [[XOR]])
-; CHECK-NEXT:    [[Z:%.*]] = or i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[Z:%.*]] = or i8 [[Y]], [[X]]
 ; CHECK-NEXT:    ret i8 [[Z]]
 ;
   %xor = xor i8 %y, %x
@@ -1059,7 +1059,7 @@ define i8 @or_nand_xor_common_op_commute3_use3(i8 %x, i8 %y, i8 %z) {
 ; (a ^ 4) & (a ^ ~4) -> -1
 define i32 @PR75692_1(i32 %x) {
 ; CHECK-LABEL: @PR75692_1(
-; CHECK-NEXT:  ret i32 -1
+; CHECK-NEXT:    ret i32 -1
 ;
   %t2 = xor i32 %x, 4
   %t3 = xor i32 %x, -5
@@ -1069,11 +1069,11 @@ define i32 @PR75692_1(i32 %x) {
 
 ; (a ^ 4) & (a ^ 3) is not -1
 define i32 @PR75692_2(i32 %x) {
-; CHECK-LABEL: @PR75692_2
-; CHECK-NEXT:  %t2 = xor i32 %x, 4
-; CHECK-NEXT:  %t3 = xor i32 %x, -4
-; CHECK-NEXT:  %t4 = or i32 %t2, %t3
-; CHECK-NEXT:  ret i32 %t4
+; CHECK-LABEL: @PR75692_2(
+; CHECK-NEXT:    [[T2:%.*]] = xor i32 [[X:%.*]], 4
+; CHECK-NEXT:    [[T3:%.*]] = xor i32 [[X]], -4
+; CHECK-NEXT:    [[T4:%.*]] = or i32 [[T2]], [[T3]]
+; CHECK-NEXT:    ret i32 [[T4]]
 ;
   %t2 = xor i32 %x, 4
   %t3 = xor i32 %x, -4
@@ -1083,11 +1083,11 @@ define i32 @PR75692_2(i32 %x) {
 
 ; (a ^ 4) & (b ^ ~4) is not -1, since a != b is possible
 define i32 @PR75692_3(i32 %x, i32 %y) {
-; CHECK-LABEL: @PR75692_3
-; CHECK-NEXT:  %t2 = xor i32 %x, 4
-; CHECK-NEXT:  %t3 = xor i32 %y, -5
-; CHECK-NEXT:  %t4 = or i32 %t2, %t3
-; CHECK-NEXT:  ret i32 %t4
+; CHECK-LABEL: @PR75692_3(
+; CHECK-NEXT:    [[T2:%.*]] = xor i32 [[X:%.*]], 4
+; CHECK-NEXT:    [[T3:%.*]] = xor i32 [[Y:%.*]], -5
+; CHECK-NEXT:    [[T4:%.*]] = or i32 [[T2]], [[T3]]
+; CHECK-NEXT:    ret i32 [[T4]]
 ;
   %t2 = xor i32 %x, 4
   %t3 = xor i32 %y, -5

diff  --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index 573a11599141a..2238b6bcc5653 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -1777,3 +1777,127 @@ if.then:
 if.else:
   ret i32 0
 }
+
+; Tests from PR76554
+define i32 @test_or_and_xor_constant(i32 %x, i32 %y) {
+; CHECK-LABEL: @test_or_and_xor_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[D:%.*]] = and i32 [[TMP1]], -2147483648
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %a = and i32 %x, -2147483648
+  %b = xor i32 %a, -2147483648
+  %c = and i32 %b, %y
+  %d = or i32 %c, %a
+  ret i32 %d
+}
+
+define i32 @test_or_and_xor(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test_or_and_xor(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %a, %b
+  %and = and i32 %xor, %c
+  %or = or i32 %and, %a
+  ret i32 %or
+}
+
+define i32 @test_or_and_xor_commuted1(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test_or_and_xor_commuted1(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %b, %a
+  %and = and i32 %xor, %c
+  %or = or i32 %and, %a
+  ret i32 %or
+}
+
+define i32 @test_or_and_xor_commuted2(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test_or_and_xor_commuted2(
+; CHECK-NEXT:    [[CC:%.*]] = mul i32 [[C:%.*]], [[C]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[CC]], [[B:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %cc = mul i32 %c, %c
+  %xor = xor i32 %a, %b
+  %and = and i32 %cc, %xor
+  %or = or i32 %and, %a
+  ret i32 %or
+}
+
+define i32 @test_or_and_xor_commuted3(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test_or_and_xor_commuted3(
+; CHECK-NEXT:    [[AA:%.*]] = mul i32 [[A:%.*]], [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AA]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %aa = mul i32 %a, %a
+  %xor = xor i32 %aa, %b
+  %and = and i32 %xor, %c
+  %or = or i32 %aa, %and
+  ret i32 %or
+}
+
+define i32 @test_or_and_xor_multiuse1(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test_or_and_xor_multiuse1(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    call void @use(i32 [[XOR]])
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[TMP1]], [[A]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %a, %b
+  call void @use(i32 %xor)
+  %and = and i32 %xor, %c
+  %or = or i32 %and, %a
+  ret i32 %or
+}
+
+; Negative tests
+
+define i32 @test_or_and_xor_mismatched_op(i32 %a, i32 %b, i32 %c, i32 %d) {
+; CHECK-LABEL: @test_or_and_xor_mismatched_op(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[D:%.*]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %a, %b
+  %and = and i32 %xor, %c
+  %or = or i32 %and, %d
+  ret i32 %or
+}
+
+define i32 @test_or_and_xor_multiuse2(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test_or_and_xor_multiuse2(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT:    call void @use(i32 [[AND]])
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[A]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %a, %b
+  %and = and i32 %xor, %c
+  call void @use(i32 %and)
+  %or = or i32 %and, %a
+  ret i32 %or
+}
+
+define i32 @test_or_add_xor(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test_or_add_xor(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[ADD]], [[A]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %a, %b
+  %add = add i32 %xor, %c
+  %or = or i32 %add, %a
+  ret i32 %or
+}


        


More information about the llvm-commits mailing list