]> granicus.if.org Git - llvm/commitdiff
[InstSimplify] move (A & ~B) | (A ^ B) -> (A ^ B) from InstCombine
authorSanjay Patel <spatel@rotateright.com>
Mon, 24 Apr 2017 18:24:36 +0000 (18:24 +0000)
committerSanjay Patel <spatel@rotateright.com>
Mon, 24 Apr 2017 18:24:36 +0000 (18:24 +0000)
This is a straight cut and paste, but there's a bigger problem: if this
fold exists for simplifyOr, there should be a DeMorganized version for
simplifyAnd. But more than that, we have a patchwork of ad hoc logic
optimizations in InstCombine. There should be some structure to ensure
that we're not missing sibling folds across and/or/xor.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301213 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/InstructionSimplify.cpp
lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
test/Transforms/InstCombine/or.ll
test/Transforms/InstSimplify/AndOrXor.ll

index 2259fbaeb982de10195fb4ab21d899fb1d13f8ad..0f60f1ba8a9c5e63e5457d714d0c2455dd336f32 100644 (file)
@@ -1877,6 +1877,19 @@ static Value *SimplifyOrInst(Value *Op0, Value *Op1, const Query &Q,
       (A == Op0 || B == Op0))
     return Constant::getAllOnesValue(Op0->getType());
 
+  // (A & ~B) | (A ^ B) -> (A ^ B)
+  // (~B & A) | (A ^ B) -> (A ^ B)
+  if (match(Op0, m_c_And(m_Value(A), m_Not(m_Value(B)))) &&
+      match(Op1, m_Xor(m_Specific(A), m_Specific(B))))
+    return Op1;
+
+  // Commute the 'or' operands.
+  // (A ^ B) | (A & ~B) -> (A ^ B)
+  // (A ^ B) | (~B & A) -> (A ^ B)
+  if (match(Op1, m_c_And(m_Value(A), m_Not(m_Value(B)))) &&
+      match(Op0, m_Xor(m_Specific(A), m_Specific(B))))
+    return Op0;
+
   if (auto *ICILHS = dyn_cast<ICmpInst>(Op0)) {
     if (auto *ICIRHS = dyn_cast<ICmpInst>(Op1)) {
       if (Value *V = SimplifyOrOfICmps(ICILHS, ICIRHS))
index dccc311546374fb731397ebbab7534753dabccdf..9baaeadb8dff0ba8712aa2ed42ddb0fb4bd1e2d6 100644 (file)
@@ -2151,19 +2151,6 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) {
       match(Op0, m_c_And(m_Specific(A), m_Value(B))))
     return BinaryOperator::CreateOr(Op1, B);
 
-  // (A & ~B) | (A ^ B) -> (A ^ B)
-  // (~B & A) | (A ^ B) -> (A ^ B)
-  if (match(Op0, m_c_And(m_Value(A), m_Not(m_Value(B)))) &&
-      match(Op1, m_Xor(m_Specific(A), m_Specific(B))))
-    return BinaryOperator::CreateXor(A, B);
-
-  // Commute the 'or' operands.
-  // (A ^ B) | (A & ~B) -> (A ^ B)
-  // (A ^ B) | (~B & A) -> (A ^ B)
-  if (match(Op1, m_c_And(m_Value(A), m_Not(m_Value(B)))) &&
-      match(Op0, m_Xor(m_Specific(A), m_Specific(B))))
-    return BinaryOperator::CreateXor(A, B);
-
   // (A & C)|(B & D)
   Value *C = nullptr, *D = nullptr;
   if (match(Op0, m_And(m_Value(A), m_Value(C))) &&
index 41e6d2d1f8277b03269c5cf8d4b5e459d7d61e05..9ae5eafdfccff341964c87ed493f83202bc32352 100644 (file)
@@ -619,59 +619,6 @@ define i32 @test42_commuted_xor(i32 %a, i32 %b) {
   ret i32 %or
 }
 
-; (A & ~B) | (A ^ B) -> A ^ B
-
-define i32 @test43(i32 %a, i32 %b) {
-; CHECK-LABEL: @test43(
-; CHECK-NEXT:    [[OR:%.*]] = xor i32 %a, %b
-; CHECK-NEXT:    ret i32 [[OR]]
-;
-  %neg = xor i32 %b, -1
-  %and = and i32 %a, %neg
-  %xor = xor i32 %a, %b
-  %or = or i32 %and, %xor
-  ret i32 %or
-}
-
-define i32 @test43_commuted_and(i32 %a, i32 %b) {
-; CHECK-LABEL: @test43_commuted_and(
-; CHECK-NEXT:    [[OR:%.*]] = xor i32 %a, %b
-; CHECK-NEXT:    ret i32 [[OR]]
-;
-  %neg = xor i32 %b, -1
-  %and = and i32 %neg, %a
-  %xor = xor i32 %a, %b
-  %or = or i32 %and, %xor
-  ret i32 %or
-}
-
-; Commute operands of the 'or'.
-; (A ^ B) | (A & ~B) -> A ^ B
-
-define i32 @test44(i32 %a, i32 %b) {
-; CHECK-LABEL: @test44(
-; CHECK-NEXT:    [[OR:%.*]] = xor i32 %a, %b
-; CHECK-NEXT:    ret i32 [[OR]]
-;
-  %xor = xor i32 %a, %b
-  %neg = xor i32 %b, -1
-  %and = and i32 %a, %neg
-  %or = or i32 %xor, %and
-  ret i32 %or
-}
-
-define i32 @test44_commuted_and(i32 %a, i32 %b) {
-; CHECK-LABEL: @test44_commuted_and(
-; CHECK-NEXT:    [[OR:%.*]] = xor i32 %a, %b
-; CHECK-NEXT:    ret i32 [[OR]]
-;
-  %xor = xor i32 %a, %b
-  %neg = xor i32 %b, -1
-  %and = and i32 %neg, %a
-  %or = or i32 %xor, %and
-  ret i32 %or
-}
-
 define i32 @test45(i32 %x, i32 %y, i32 %z) {
 ; CHECK-LABEL: @test45(
 ; CHECK-NEXT:    [[TMP1:%.*]] = and i32 %x, %z
index aa71c6ba86ae63420b9a4b9b208dfad26d6487ed..5292732842b78b83d6ed18067ad8387d6a5b23b4 100644 (file)
@@ -468,3 +468,56 @@ define <2 x i3> @and_of_different_cast_icmps_vec(<2 x i8> %i, <2 x i16> %j) {
   ret <2 x i3> %and
 }
 
+; (A & ~B) | (A ^ B) -> A ^ B
+
+define i32 @test43(i32 %a, i32 %b) {
+; CHECK-LABEL: @test43(
+; CHECK-NEXT:    [[OR:%.*]] = xor i32 %a, %b
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %neg = xor i32 %b, -1
+  %and = and i32 %a, %neg
+  %xor = xor i32 %a, %b
+  %or = or i32 %and, %xor
+  ret i32 %or
+}
+
+define i32 @test43_commuted_and(i32 %a, i32 %b) {
+; CHECK-LABEL: @test43_commuted_and(
+; CHECK-NEXT:    [[OR:%.*]] = xor i32 %a, %b
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %neg = xor i32 %b, -1
+  %and = and i32 %neg, %a
+  %xor = xor i32 %a, %b
+  %or = or i32 %and, %xor
+  ret i32 %or
+}
+
+; Commute operands of the 'or'.
+; (A ^ B) | (A & ~B) -> A ^ B
+
+define i32 @test44(i32 %a, i32 %b) {
+; CHECK-LABEL: @test44(
+; CHECK-NEXT:    [[OR:%.*]] = xor i32 %a, %b
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %a, %b
+  %neg = xor i32 %b, -1
+  %and = and i32 %a, %neg
+  %or = or i32 %xor, %and
+  ret i32 %or
+}
+
+define i32 @test44_commuted_and(i32 %a, i32 %b) {
+; CHECK-LABEL: @test44_commuted_and(
+; CHECK-NEXT:    [[OR:%.*]] = xor i32 %a, %b
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %a, %b
+  %neg = xor i32 %b, -1
+  %and = and i32 %neg, %a
+  %or = or i32 %xor, %and
+  ret i32 %or
+}
+