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 @@ -3648,6 +3648,16 @@ 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) + if (match(Op0, m_OneUse(m_c_Or(m_Not(m_Value(A)), m_Value(B)))) && + match(Op1, m_Deferred(A))) + return BinaryOperator::CreateNot(Builder.CreateAnd(A, B)); + + // A ^ (~A | B) --> ~(A & B) + if (match(Op1, m_OneUse(m_c_Or(m_Not(m_Value(A)), m_Value(B)))) && + match(Op0, 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 @@ -1236,9 +1236,8 @@ define <2 x i64> @xor_orn(<2 x i64> %a, <2 x i64> %b) { ; CHECK-LABEL: @xor_orn( -; CHECK-NEXT: [[NOTA:%.*]] = xor <2 x i64> [[A:%.*]], -; CHECK-NEXT: [[L:%.*]] = or <2 x i64> [[NOTA]], [[B:%.*]] -; CHECK-NEXT: [[Z:%.*]] = xor <2 x i64> [[L]], [[A]] +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i64> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[Z:%.*]] = xor <2 x i64> [[TMP1]], ; CHECK-NEXT: ret <2 x i64> [[Z]] ; %nota = xor <2 x i64> %a, @@ -1252,9 +1251,8 @@ define i8 @xor_orn_commute1(i8 %pa, i8 %b) { ; CHECK-LABEL: @xor_orn_commute1( ; CHECK-NEXT: [[A:%.*]] = udiv i8 42, [[PA:%.*]] -; CHECK-NEXT: [[NOTA:%.*]] = xor i8 [[A]], -1 -; CHECK-NEXT: [[L:%.*]] = or i8 [[NOTA]], [[B:%.*]] -; CHECK-NEXT: [[Z:%.*]] = xor i8 [[A]], [[L]] +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[A]], [[B:%.*]] +; CHECK-NEXT: [[Z:%.*]] = xor i8 [[TMP1]], -1 ; CHECK-NEXT: ret i8 [[Z]] ; %a = udiv i8 42, %pa @@ -1269,9 +1267,8 @@ define i32 @xor_orn_commute2(i32 %a, i32 %pb,i32* %s) { ; CHECK-LABEL: @xor_orn_commute2( ; CHECK-NEXT: [[B:%.*]] = udiv i32 42, [[PB:%.*]] -; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 -; CHECK-NEXT: [[L:%.*]] = or i32 [[B]], [[NOTA]] -; CHECK-NEXT: [[Z:%.*]] = xor i32 [[L]], [[A]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[A:%.*]] +; CHECK-NEXT: [[Z:%.*]] = xor i32 [[TMP1]], -1 ; CHECK-NEXT: ret i32 [[Z]] ; %b = udiv i32 42, %pb @@ -1286,9 +1283,9 @@ ; CHECK-LABEL: @xor_orn_commute2_1use( ; CHECK-NEXT: [[B:%.*]] = udiv i32 42, [[PB:%.*]] ; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 -; CHECK-NEXT: [[L:%.*]] = or i32 [[B]], [[NOTA]] ; CHECK-NEXT: store i32 [[NOTA]], i32* [[S:%.*]], align 4 -; CHECK-NEXT: [[Z:%.*]] = xor i32 [[L]], [[A]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[A]] +; CHECK-NEXT: [[Z:%.*]] = xor i32 [[TMP1]], -1 ; CHECK-NEXT: ret i32 [[Z]] ; %b = udiv i32 42, %pb @@ -1305,9 +1302,8 @@ ; CHECK-LABEL: @xor_orn_commute3( ; CHECK-NEXT: [[A:%.*]] = udiv i67 42, [[PA:%.*]] ; CHECK-NEXT: [[B:%.*]] = udiv i67 42, [[PB:%.*]] -; CHECK-NEXT: [[NOTA:%.*]] = xor i67 [[A]], -1 -; CHECK-NEXT: [[L:%.*]] = or i67 [[B]], [[NOTA]] -; CHECK-NEXT: [[Z:%.*]] = xor i67 [[A]], [[L]] +; CHECK-NEXT: [[TMP1:%.*]] = and i67 [[A]], [[B]] +; CHECK-NEXT: [[Z:%.*]] = xor i67 [[TMP1]], -1 ; CHECK-NEXT: ret i67 [[Z]] ; %a = udiv i67 42, %pa