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 @@ -3477,14 +3477,8 @@ // (~x) ^ y // or into // x ^ (~y) -static Instruction *sinkNotIntoXor(BinaryOperator &I, +static Instruction *sinkNotIntoXor(BinaryOperator &I, Value *X, Value *Y, InstCombiner::BuilderTy &Builder) { - Value *X, *Y; - // FIXME: one-use check is not needed in general, but currently we are unable - // to fold 'not' into 'icmp', if that 'icmp' has multiple uses. (D35182) - if (!match(&I, m_Not(m_OneUse(m_Xor(m_Value(X), m_Value(Y)))))) - return nullptr; - // We only want to do the transform if it is free to do. if (InstCombiner::isFreeToInvert(X, X->hasOneUse())) { // Ok, good. @@ -3497,6 +3491,41 @@ return BinaryOperator::CreateXor(NotX, Y, I.getName() + ".demorgan"); } +static Instruction *foldNotXor(BinaryOperator &I, + InstCombiner::BuilderTy &Builder) { + Value *X, *Y; + // FIXME: one-use check is not needed in general, but currently we are unable + // to fold 'not' into 'icmp', if that 'icmp' has multiple uses. (D35182) + if (!match(&I, m_Not(m_OneUse(m_Xor(m_Value(X), m_Value(Y)))))) + return nullptr; + + if (Instruction *NewXor = sinkNotIntoXor(I, X, Y, Builder)) + return NewXor; + + auto hasCommonOperand = [](Value *A, Value *B, Value *C, Value *D) { + return A == C || A == D || B == C || B == D; + }; + + Value *A, *B, *C, *D; + // Canonicalize ~((A & B) ^ (A | ?)) -> (A & B) | ~(A | ?) + // 4 commuted variants + if (match(X, m_And(m_Value(A), m_Value(B))) && + match(Y, m_Or(m_Value(C), m_Value(D))) && hasCommonOperand(A, B, C, D)) { + Value *NotY = Builder.CreateNot(Y); + return BinaryOperator::CreateOr(X, NotY); + }; + + // Canonicalize ~((A | ?) ^ (A & B)) -> (A & B) | ~(A | ?) + // 4 commuted variants + if (match(Y, m_And(m_Value(A), m_Value(B))) && + match(X, m_Or(m_Value(C), m_Value(D))) && hasCommonOperand(A, B, C, D)) { + Value *NotX = Builder.CreateNot(X); + return BinaryOperator::CreateOr(Y, NotX); + }; + + return nullptr; +} + /// Canonicalize a shifty way to code absolute value to the more common pattern /// that uses negation and select. static Instruction *canonicalizeAbs(BinaryOperator &Xor, @@ -3741,7 +3770,7 @@ } } - if (Instruction *NewXor = sinkNotIntoXor(I, Builder)) + if (Instruction *NewXor = foldNotXor(I, Builder)) return NewXor; return nullptr; diff --git a/llvm/test/Transforms/InstCombine/xor2.ll b/llvm/test/Transforms/InstCombine/xor2.ll --- a/llvm/test/Transforms/InstCombine/xor2.ll +++ b/llvm/test/Transforms/InstCombine/xor2.ll @@ -520,14 +520,14 @@ ret i8 %res } -; TODO: Canonicalize ~((A & B) ^ (A | ?)) -> (A & B) | ~(A | ?) +; Canonicalize ~((A & B) ^ (A | ?)) -> (A & B) | ~(A | ?) define i3 @not_xor_to_or_not1(i3 %a, i3 %b, i3 %c) { ; CHECK-LABEL: @not_xor_to_or_not1( ; CHECK-NEXT: [[OR:%.*]] = or i3 [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[AND:%.*]] = and i3 [[A:%.*]], [[C]] -; CHECK-NEXT: [[XOR:%.*]] = xor i3 [[AND]], [[OR]] -; CHECK-NEXT: [[NOT:%.*]] = xor i3 [[XOR]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i3 [[OR]], -1 +; CHECK-NEXT: [[NOT:%.*]] = or i3 [[AND]], [[TMP1]] ; CHECK-NEXT: ret i3 [[NOT]] ; %or = or i3 %b, %c @@ -541,8 +541,8 @@ ; CHECK-LABEL: @not_xor_to_or_not2( ; CHECK-NEXT: [[OR:%.*]] = or i3 [[C:%.*]], [[B:%.*]] ; CHECK-NEXT: [[AND:%.*]] = and i3 [[A:%.*]], [[C]] -; CHECK-NEXT: [[XOR:%.*]] = xor i3 [[AND]], [[OR]] -; CHECK-NEXT: [[NOT:%.*]] = xor i3 [[XOR]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i3 [[OR]], -1 +; CHECK-NEXT: [[NOT:%.*]] = or i3 [[AND]], [[TMP1]] ; CHECK-NEXT: ret i3 [[NOT]] ; %or = or i3 %c, %b @@ -556,8 +556,8 @@ ; CHECK-LABEL: @not_xor_to_or_not3( ; CHECK-NEXT: [[OR:%.*]] = or i3 [[C:%.*]], [[B:%.*]] ; CHECK-NEXT: [[AND:%.*]] = and i3 [[C]], [[A:%.*]] -; CHECK-NEXT: [[XOR:%.*]] = xor i3 [[AND]], [[OR]] -; CHECK-NEXT: [[NOT:%.*]] = xor i3 [[XOR]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i3 [[OR]], -1 +; CHECK-NEXT: [[NOT:%.*]] = or i3 [[AND]], [[TMP1]] ; CHECK-NEXT: ret i3 [[NOT]] ; %or = or i3 %c, %b @@ -571,8 +571,8 @@ ; CHECK-LABEL: @not_xor_to_or_not4( ; CHECK-NEXT: [[OR:%.*]] = or i3 [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[AND:%.*]] = and i3 [[C]], [[A:%.*]] -; CHECK-NEXT: [[XOR:%.*]] = xor i3 [[AND]], [[OR]] -; CHECK-NEXT: [[NOT:%.*]] = xor i3 [[XOR]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i3 [[OR]], -1 +; CHECK-NEXT: [[NOT:%.*]] = or i3 [[AND]], [[TMP1]] ; CHECK-NEXT: ret i3 [[NOT]] ; %or = or i3 %b, %c @@ -586,8 +586,8 @@ ; CHECK-LABEL: @not_xor_to_or_not_vector( ; CHECK-NEXT: [[OR:%.*]] = or <3 x i5> [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[AND:%.*]] = and <3 x i5> [[A:%.*]], [[C]] -; CHECK-NEXT: [[XOR:%.*]] = xor <3 x i5> [[OR]], [[AND]] -; CHECK-NEXT: [[NOT:%.*]] = xor <3 x i5> [[XOR]], +; CHECK-NEXT: [[TMP1:%.*]] = xor <3 x i5> [[OR]], +; CHECK-NEXT: [[NOT:%.*]] = or <3 x i5> [[AND]], [[TMP1]] ; CHECK-NEXT: ret <3 x i5> [[NOT]] ; %or = or <3 x i5> %b, %c @@ -601,8 +601,8 @@ ; CHECK-LABEL: @not_xor_to_or_not_vector_poison( ; CHECK-NEXT: [[OR:%.*]] = or <3 x i5> [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[AND:%.*]] = and <3 x i5> [[A:%.*]], [[C]] -; CHECK-NEXT: [[XOR:%.*]] = xor <3 x i5> [[OR]], [[AND]] -; CHECK-NEXT: [[NOT:%.*]] = xor <3 x i5> [[XOR]], +; CHECK-NEXT: [[TMP1:%.*]] = xor <3 x i5> [[OR]], +; CHECK-NEXT: [[NOT:%.*]] = or <3 x i5> [[AND]], [[TMP1]] ; CHECK-NEXT: ret <3 x i5> [[NOT]] ; %or = or <3 x i5> %b, %c @@ -612,6 +612,8 @@ ret <3 x i5> %not } +; negative test : not one use + define i3 @not_xor_to_or_not_2use(i3 %a, i3 %b, i3 %c) { ; CHECK-LABEL: @not_xor_to_or_not_2use( ; CHECK-NEXT: [[OR:%.*]] = or i3 [[B:%.*]], [[C:%.*]] @@ -629,14 +631,14 @@ ret i3 %not } -; TODO: Canonicalize ~(A & B) ^ (A | ?) -> (A & B) | ~(A | ?) +; Canonicalize ~(A & B) ^ (A | ?) -> (A & B) | ~(A | ?) define i3 @xor_notand_to_or_not1(i3 %a, i3 %b, i3 %c) { ; CHECK-LABEL: @xor_notand_to_or_not1( ; CHECK-NEXT: [[OR:%.*]] = or i3 [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[AND:%.*]] = and i3 [[A:%.*]], [[C]] -; CHECK-NEXT: [[TMP1:%.*]] = xor i3 [[AND]], [[OR]] -; CHECK-NEXT: [[XOR:%.*]] = xor i3 [[TMP1]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i3 [[OR]], -1 +; CHECK-NEXT: [[XOR:%.*]] = or i3 [[AND]], [[TMP1]] ; CHECK-NEXT: ret i3 [[XOR]] ; %or = or i3 %b, %c @@ -650,8 +652,8 @@ ; CHECK-LABEL: @xor_notand_to_or_not2( ; CHECK-NEXT: [[OR:%.*]] = or i3 [[C:%.*]], [[B:%.*]] ; CHECK-NEXT: [[AND:%.*]] = and i3 [[A:%.*]], [[C]] -; CHECK-NEXT: [[TMP1:%.*]] = xor i3 [[AND]], [[OR]] -; CHECK-NEXT: [[XOR:%.*]] = xor i3 [[TMP1]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i3 [[OR]], -1 +; CHECK-NEXT: [[XOR:%.*]] = or i3 [[AND]], [[TMP1]] ; CHECK-NEXT: ret i3 [[XOR]] ; %or = or i3 %c, %b @@ -665,8 +667,8 @@ ; CHECK-LABEL: @xor_notand_to_or_not3( ; CHECK-NEXT: [[OR:%.*]] = or i3 [[C:%.*]], [[B:%.*]] ; CHECK-NEXT: [[AND:%.*]] = and i3 [[C]], [[A:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = xor i3 [[AND]], [[OR]] -; CHECK-NEXT: [[XOR:%.*]] = xor i3 [[TMP1]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i3 [[OR]], -1 +; CHECK-NEXT: [[XOR:%.*]] = or i3 [[AND]], [[TMP1]] ; CHECK-NEXT: ret i3 [[XOR]] ; %or = or i3 %c, %b @@ -680,8 +682,8 @@ ; CHECK-LABEL: @xor_notand_to_or_not4( ; CHECK-NEXT: [[OR:%.*]] = or i3 [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[AND:%.*]] = and i3 [[C]], [[A:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = xor i3 [[AND]], [[OR]] -; CHECK-NEXT: [[XOR:%.*]] = xor i3 [[TMP1]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i3 [[OR]], -1 +; CHECK-NEXT: [[XOR:%.*]] = or i3 [[AND]], [[TMP1]] ; CHECK-NEXT: ret i3 [[XOR]] ; %or = or i3 %b, %c @@ -695,8 +697,8 @@ ; CHECK-LABEL: @xor_notand_to_or_not_vector( ; CHECK-NEXT: [[OR:%.*]] = or <3 x i5> [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[AND:%.*]] = and <3 x i5> [[A:%.*]], [[C]] -; CHECK-NEXT: [[TMP1:%.*]] = xor <3 x i5> [[AND]], [[OR]] -; CHECK-NEXT: [[XOR:%.*]] = xor <3 x i5> [[TMP1]], +; CHECK-NEXT: [[TMP1:%.*]] = xor <3 x i5> [[OR]], +; CHECK-NEXT: [[XOR:%.*]] = or <3 x i5> [[AND]], [[TMP1]] ; CHECK-NEXT: ret <3 x i5> [[XOR]] ; %or = or <3 x i5> %b, %c @@ -710,8 +712,8 @@ ; CHECK-LABEL: @xor_notand_to_or_not_vector_poison( ; CHECK-NEXT: [[OR:%.*]] = or <3 x i5> [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[AND:%.*]] = and <3 x i5> [[A:%.*]], [[C]] -; CHECK-NEXT: [[TMP1:%.*]] = xor <3 x i5> [[AND]], [[OR]] -; CHECK-NEXT: [[XOR:%.*]] = xor <3 x i5> [[TMP1]], +; CHECK-NEXT: [[TMP1:%.*]] = xor <3 x i5> [[OR]], +; CHECK-NEXT: [[XOR:%.*]] = or <3 x i5> [[AND]], [[TMP1]] ; CHECK-NEXT: ret <3 x i5> [[XOR]] ; %or = or <3 x i5> %b, %c @@ -721,6 +723,8 @@ ret <3 x i5> %xor } +; negative test : not one use + define i3 @xor_notand_to_or_not_2use(i3 %a, i3 %b, i3 %c) { ; CHECK-LABEL: @xor_notand_to_or_not_2use( ; CHECK-NEXT: [[OR:%.*]] = or i3 [[B:%.*]], [[C:%.*]]