diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -3615,6 +3615,10 @@ if (match(&I, m_c_Xor(m_c_And(m_Not(m_Value(A)), m_Value(B)), m_Deferred(A)))) return BinaryOperator::CreateOr(A, B); + // (~A | B) ^ A --> ~(A & B) -- There are 4 commuted variants. + if (match(&I, m_c_Xor(m_c_Or(m_Not(m_Value(A)), m_Value(B)), m_Deferred(A)))) + return BinaryOperator::CreateNot(Builder.CreateAnd(A, B)); + // (A | B) ^ (A | C) --> (B ^ C) & ~A -- There are 4 commuted variants. // TODO: Loosen one-use restriction if common operand is a constant. Value *D; diff --git a/llvm/test/Transforms/InstCombine/xor.ll b/llvm/test/Transforms/InstCombine/xor.ll --- a/llvm/test/Transforms/InstCombine/xor.ll +++ b/llvm/test/Transforms/InstCombine/xor.ll @@ -1231,3 +1231,59 @@ %z = xor i32 %a, %r ret i32 %z } + +; (~A | B) ^ A --> ~(A & B) + +define i64 @xor_orn(i64 %a, i64 %b) { +; CHECK-LABEL: @xor_orn( +; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[Z:%.*]] = xor i64 [[TMP1]], -1 +; CHECK-NEXT: ret i64 [[Z]] +; + %nota = xor i64 %a, -1 + %l = or i64 %nota, %b + %z = xor i64 %l, %a + ret i64 %z +} + +; A ^ (~A | B) --> ~(A & B) + +define <4 x i8> @xor_orn_commute1(<4 x i8> %a, <4 x i8> %b) { +; CHECK-LABEL: @xor_orn_commute1( +; CHECK-NEXT: [[TMP1:%.*]] = and <4 x i8> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[Z:%.*]] = xor <4 x i8> [[TMP1]], +; CHECK-NEXT: ret <4 x i8> [[Z]] +; + %nota = xor <4 x i8> %a, + %l = or <4 x i8> %nota, %b + %z = xor <4 x i8> %a, %l + ret <4 x i8> %z +} + +; (B | ~A) ^ A --> ~(A & B) + +define i32 @xor_orn_commute2(i32 %a, i32 %b) { +; CHECK-LABEL: @xor_orn_commute2( +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[Z:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: ret i32 [[Z]] +; + %nota = xor i32 %a, -1 + %l = or i32 %b, %nota + %z = xor i32 %l, %a + ret i32 %z +} + +; A ^ (B | ~A) --> ~(A & B) + +define i67 @xor_orn_commute3(i67 %a, i67 %b) { +; CHECK-LABEL: @xor_orn_commute3( +; CHECK-NEXT: [[TMP1:%.*]] = and i67 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[Z:%.*]] = xor i67 [[TMP1]], -1 +; CHECK-NEXT: ret i67 [[Z]] +; + %nota = xor i67 %a, -1 + %l = or i67 %b, %nota + %z = xor i67 %a, %l + ret i67 %z +}