Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2276,7 +2276,8 @@ /// A ^ B can be specified using other logic ops in a variety of patterns. We /// can fold these early and efficiently by morphing an existing instruction. -static Instruction *foldXorToXor(BinaryOperator &I) { +static Instruction *foldXorToXor(BinaryOperator &I, + InstCombiner::BuilderTy &Builder) { assert(I.getOpcode() == Instruction::Xor); Value *Op0 = I.getOperand(0); Value *Op1 = I.getOperand(1); @@ -2323,6 +2324,21 @@ return &I; } + // For the remaining cases we need to get rid of one of the operands. + if (!Op0->hasOneUse() && !Op1->hasOneUse()) + return nullptr; + + // (A | B) ^ ~(A & B) -> ~(A ^ B) + // (A | B) ^ ~(B & A) -> ~(A ^ B) + // (A & B) ^ ~(A | B) -> ~(A ^ B) + // (A & B) ^ ~(B | A) -> ~(A ^ B) + // Complexity sorting ensures the not will be on the right side. + if ((match(Op0, m_Or(m_Value(A), m_Value(B))) && + match(Op1, m_Not(m_c_And(m_Specific(A), m_Specific(B))))) || + (match(Op0, m_And(m_Value(A), m_Value(B))) && + match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(B)))))) + return BinaryOperator::CreateNot(Builder.CreateXor(A, B)); + return nullptr; } @@ -2381,7 +2397,7 @@ if (Value *V = SimplifyXorInst(Op0, Op1, SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); - if (Instruction *NewXor = foldXorToXor(I)) + if (Instruction *NewXor = foldXorToXor(I, *Builder)) return NewXor; // (A&B)^(A&C) -> A&(B^C) etc Index: test/Transforms/InstCombine/and-or-not.ll =================================================================== --- test/Transforms/InstCombine/and-or-not.ll +++ test/Transforms/InstCombine/and-or-not.ll @@ -570,10 +570,8 @@ ; CHECK-LABEL: @xor_to_xnor1( ; CHECK-NEXT: [[A:%.*]] = fptosi float [[FA:%.*]] to i32 ; CHECK-NEXT: [[B:%.*]] = fptosi float [[FB:%.*]] to i32 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A]], [[B]] -; CHECK-NEXT: [[OR2_DEMORGAN:%.*]] = and i32 [[A]], [[B]] -; CHECK-NEXT: [[OR2:%.*]] = xor i32 [[OR2_DEMORGAN]], -1 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], [[B]] +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[TMP1]], -1 ; CHECK-NEXT: ret i32 [[XOR]] ; %a = fptosi float %fa to i32 @@ -591,10 +589,8 @@ ; CHECK-LABEL: @xor_to_xnor2( ; CHECK-NEXT: [[A:%.*]] = fptosi float [[FA:%.*]] to i32 ; CHECK-NEXT: [[B:%.*]] = fptosi float [[FB:%.*]] to i32 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A]], [[B]] -; CHECK-NEXT: [[OR2_DEMORGAN:%.*]] = and i32 [[B]], [[A]] -; CHECK-NEXT: [[OR2:%.*]] = xor i32 [[OR2_DEMORGAN]], -1 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], [[B]] +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[TMP1]], -1 ; CHECK-NEXT: ret i32 [[XOR]] ; %a = fptosi float %fa to i32 @@ -612,10 +608,8 @@ ; CHECK-LABEL: @xor_to_xnor3( ; CHECK-NEXT: [[A:%.*]] = fptosi float [[FA:%.*]] to i32 ; CHECK-NEXT: [[B:%.*]] = fptosi float [[FB:%.*]] to i32 -; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and i32 [[A]], [[B]] -; CHECK-NEXT: [[OR1:%.*]] = xor i32 [[OR1_DEMORGAN]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[B]] -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[OR2]], [[OR1]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], [[B]] +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[TMP1]], -1 ; CHECK-NEXT: ret i32 [[XOR]] ; %a = fptosi float %fa to i32 @@ -633,10 +627,8 @@ ; CHECK-LABEL: @xor_to_xnor4( ; CHECK-NEXT: [[A:%.*]] = fptosi float [[FA:%.*]] to i32 ; CHECK-NEXT: [[B:%.*]] = fptosi float [[FB:%.*]] to i32 -; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and i32 [[A]], [[B]] -; CHECK-NEXT: [[OR1:%.*]] = xor i32 [[OR1_DEMORGAN]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[B]], [[A]] -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[OR2]], [[OR1]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[A]] +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[TMP1]], -1 ; CHECK-NEXT: ret i32 [[XOR]] ; %a = fptosi float %fa to i32 Index: test/Transforms/InstCombine/or-xor.ll =================================================================== --- test/Transforms/InstCombine/or-xor.ll +++ test/Transforms/InstCombine/or-xor.ll @@ -348,10 +348,8 @@ ; ((x | y) ^ (~x | ~y)) -> ~(x ^ y) define i32 @test19(i32 %x, i32 %y) { ; CHECK-LABEL: @test19( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[OR2_DEMORGAN:%.*]] = and i32 [[X]], [[Y]] -; CHECK-NEXT: [[OR2:%.*]] = xor i32 [[OR2_DEMORGAN]], -1 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[TMP1]], -1 ; CHECK-NEXT: ret i32 [[XOR]] ; %noty = xor i32 %y, -1 @@ -365,10 +363,8 @@ ; ((x | y) ^ (~y | ~x)) -> ~(x ^ y) define i32 @test20(i32 %x, i32 %y) { ; CHECK-LABEL: @test20( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[OR2_DEMORGAN:%.*]] = and i32 [[Y]], [[X]] -; CHECK-NEXT: [[OR2:%.*]] = xor i32 [[OR2_DEMORGAN]], -1 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[TMP1]], -1 ; CHECK-NEXT: ret i32 [[XOR]] ; %noty = xor i32 %y, -1 @@ -382,10 +378,8 @@ ; ((~x | ~y) ^ (x | y)) -> ~(x ^ y) define i32 @test21(i32 %x, i32 %y) { ; CHECK-LABEL: @test21( -; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and i32 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = xor i32 [[OR1_DEMORGAN]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[X]], [[Y]] -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[OR2]], [[OR1]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[TMP1]], -1 ; CHECK-NEXT: ret i32 [[XOR]] ; %noty = xor i32 %y, -1 @@ -399,10 +393,8 @@ ; ((~x | ~y) ^ (y | x)) -> ~(x ^ y) define i32 @test22(i32 %x, i32 %y) { ; CHECK-LABEL: @test22( -; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and i32 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = xor i32 [[OR1_DEMORGAN]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[Y]], [[X]] -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[OR2]], [[OR1]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[TMP1]], -1 ; CHECK-NEXT: ret i32 [[XOR]] ; %noty = xor i32 %y, -1