[InstSimplify] move (A & ~B) | (A ^ B) -> (A ^ B) from InstCombine

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.
 

llvm-svn: 301213
diff --git a/llvm/test/Transforms/InstSimplify/AndOrXor.ll b/llvm/test/Transforms/InstSimplify/AndOrXor.ll
index aa71c6b..5292732 100644
--- a/llvm/test/Transforms/InstSimplify/AndOrXor.ll
+++ b/llvm/test/Transforms/InstSimplify/AndOrXor.ll
@@ -468,3 +468,56 @@
   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
+}
+