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 @@ -2772,6 +2772,21 @@ if (Value *V = matchSelectFromAndOr(D, B, C, A)) return replaceInstUsesWith(I, V); } + + // (a & b) | (~a & c) -> ((b ^ c_) & a) ^ c_ with c_ = freeze(c) + { + Value *A, *B, *C; + if (Op0->hasOneUse() && Op1->hasOneUse() && + (match(&I, m_BinOp(m_c_And(m_Value(A), m_Value(B)), + m_c_And(m_Not(m_Deferred(A)), m_Value(C)))) || + match(&I, m_BinOp(m_c_And(m_Not(m_Value(A)), m_Value(C)), + m_c_And(m_Deferred(A), m_Value(B)))))) { + Value *FrozenC = Builder.CreateFreeze(C); + Value *Xor0 = Builder.CreateXor(B, FrozenC); + Value *And = Builder.CreateAnd(Xor0, A); + return BinaryOperator::CreateXor(And, FrozenC); + } + } } // (A ^ B) | ((B ^ C) ^ A) -> (A ^ B) | C diff --git a/llvm/test/Transforms/InstCombine/masked-merge-add.ll b/llvm/test/Transforms/InstCombine/masked-merge-add.ll --- a/llvm/test/Transforms/InstCombine/masked-merge-add.ll +++ b/llvm/test/Transforms/InstCombine/masked-merge-add.ll @@ -177,122 +177,6 @@ ; Commutativity. ; ============================================================================ ; -; Used to make sure that the IR complexity sorting does not interfere. -declare i32 @gen32() - -define i32 @p_commutative0(i32 %x, i32 %y, i32 %m) { -; CHECK-LABEL: @p_commutative0( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] -; CHECK-NEXT: ret i32 [[RET]] -; - %and = and i32 %m, %x ; swapped order - %neg = xor i32 %m, -1 - %and1 = and i32 %neg, %y - %ret = add i32 %and, %and1 - ret i32 %ret -} - -define i32 @p_commutative1(i32 %x, i32 %m) { -; CHECK-LABEL: @p_commutative1( -; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] -; CHECK-NEXT: ret i32 [[RET]] -; - %y = call i32 @gen32() - %and = and i32 %x, %m - %neg = xor i32 %m, -1 - %and1 = and i32 %y, %neg; swapped order - %ret = add i32 %and, %and1 - ret i32 %ret -} - -define i32 @p_commutative2(i32 %x, i32 %y, i32 %m) { -; CHECK-LABEL: @p_commutative2( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] -; CHECK-NEXT: ret i32 [[RET]] -; - %and = and i32 %x, %m - %neg = xor i32 %m, -1 - %and1 = and i32 %neg, %y - %ret = add i32 %and1, %and ; swapped order - ret i32 %ret -} - -define i32 @p_commutative3(i32 %x, i32 %m) { -; CHECK-LABEL: @p_commutative3( -; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() -; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] -; CHECK-NEXT: ret i32 [[RET]] -; - %y = call i32 @gen32() - %and = and i32 %m, %x ; swapped order - %neg = xor i32 %m, -1 - %and1 = and i32 %y, %neg; swapped order - %ret = add i32 %and, %and1 - ret i32 %ret -} - -define i32 @p_commutative4(i32 %x, i32 %y, i32 %m) { -; CHECK-LABEL: @p_commutative4( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] -; CHECK-NEXT: ret i32 [[RET]] -; - %and = and i32 %m, %x ; swapped order - %neg = xor i32 %m, -1 - %and1 = and i32 %neg, %y - %ret = add i32 %and1, %and ; swapped order - ret i32 %ret -} - -define i32 @p_commutative5(i32 %x, i32 %m) { -; CHECK-LABEL: @p_commutative5( -; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] -; CHECK-NEXT: ret i32 [[RET]] -; - %y = call i32 @gen32() - %and = and i32 %x, %m - %neg = xor i32 %m, -1 - %and1 = and i32 %y, %neg; swapped order - %ret = add i32 %and1, %and ; swapped order - ret i32 %ret -} - -define i32 @p_commutative6(i32 %x, i32 %m) { -; CHECK-LABEL: @p_commutative6( -; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() -; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] -; CHECK-NEXT: ret i32 [[RET]] -; - %y = call i32 @gen32() - %and = and i32 %m, %x ; swapped order - %neg = xor i32 %m, -1 - %and1 = and i32 %y, %neg; swapped order - %ret = add i32 %and1, %and ; swapped order - ret i32 %ret -} - define i32 @p_constmask_commutative(i32 %x, i32 %y) { ; CHECK-LABEL: @p_constmask_commutative( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 65280 diff --git a/llvm/test/Transforms/InstCombine/masked-merge-or.ll b/llvm/test/Transforms/InstCombine/masked-merge-or.ll --- a/llvm/test/Transforms/InstCombine/masked-merge-or.ll +++ b/llvm/test/Transforms/InstCombine/masked-merge-or.ll @@ -177,122 +177,6 @@ ; Commutativity. ; ============================================================================ ; -; Used to make sure that the IR complexity sorting does not interfere. -declare i32 @gen32() - -define i32 @p_commutative0(i32 %x, i32 %y, i32 %m) { -; CHECK-LABEL: @p_commutative0( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] -; CHECK-NEXT: ret i32 [[RET]] -; - %and = and i32 %m, %x ; swapped order - %neg = xor i32 %m, -1 - %and1 = and i32 %neg, %y - %ret = or i32 %and, %and1 - ret i32 %ret -} - -define i32 @p_commutative1(i32 %x, i32 %m) { -; CHECK-LABEL: @p_commutative1( -; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] -; CHECK-NEXT: ret i32 [[RET]] -; - %y = call i32 @gen32() - %and = and i32 %x, %m - %neg = xor i32 %m, -1 - %and1 = and i32 %y, %neg; swapped order - %ret = or i32 %and, %and1 - ret i32 %ret -} - -define i32 @p_commutative2(i32 %x, i32 %y, i32 %m) { -; CHECK-LABEL: @p_commutative2( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] -; CHECK-NEXT: ret i32 [[RET]] -; - %and = and i32 %x, %m - %neg = xor i32 %m, -1 - %and1 = and i32 %neg, %y - %ret = or i32 %and1, %and ; swapped order - ret i32 %ret -} - -define i32 @p_commutative3(i32 %x, i32 %m) { -; CHECK-LABEL: @p_commutative3( -; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() -; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] -; CHECK-NEXT: ret i32 [[RET]] -; - %y = call i32 @gen32() - %and = and i32 %m, %x ; swapped order - %neg = xor i32 %m, -1 - %and1 = and i32 %y, %neg; swapped order - %ret = or i32 %and, %and1 - ret i32 %ret -} - -define i32 @p_commutative4(i32 %x, i32 %y, i32 %m) { -; CHECK-LABEL: @p_commutative4( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] -; CHECK-NEXT: ret i32 [[RET]] -; - %and = and i32 %m, %x ; swapped order - %neg = xor i32 %m, -1 - %and1 = and i32 %neg, %y - %ret = or i32 %and1, %and ; swapped order - ret i32 %ret -} - -define i32 @p_commutative5(i32 %x, i32 %m) { -; CHECK-LABEL: @p_commutative5( -; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] -; CHECK-NEXT: ret i32 [[RET]] -; - %y = call i32 @gen32() - %and = and i32 %x, %m - %neg = xor i32 %m, -1 - %and1 = and i32 %y, %neg; swapped order - %ret = or i32 %and1, %and ; swapped order - ret i32 %ret -} - -define i32 @p_commutative6(i32 %x, i32 %m) { -; CHECK-LABEL: @p_commutative6( -; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() -; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] -; CHECK-NEXT: ret i32 [[RET]] -; - %y = call i32 @gen32() - %and = and i32 %m, %x ; swapped order - %neg = xor i32 %m, -1 - %and1 = and i32 %y, %neg; swapped order - %ret = or i32 %and1, %and ; swapped order - ret i32 %ret -} - define i32 @p_constmask_commutative(i32 %x, i32 %y) { ; CHECK-LABEL: @p_constmask_commutative( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 65280 diff --git a/llvm/test/Transforms/InstCombine/masked-merge-xor.ll b/llvm/test/Transforms/InstCombine/masked-merge-xor.ll --- a/llvm/test/Transforms/InstCombine/masked-merge-xor.ll +++ b/llvm/test/Transforms/InstCombine/masked-merge-xor.ll @@ -177,122 +177,6 @@ ; Commutativity. ; ============================================================================ ; -; Used to make sure that the IR complexity sorting does not interfere. -declare i32 @gen32() - -define i32 @p_commutative0(i32 %x, i32 %y, i32 %m) { -; CHECK-LABEL: @p_commutative0( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] -; CHECK-NEXT: ret i32 [[RET]] -; - %and = and i32 %m, %x ; swapped order - %neg = xor i32 %m, -1 - %and1 = and i32 %neg, %y - %ret = xor i32 %and, %and1 - ret i32 %ret -} - -define i32 @p_commutative1(i32 %x, i32 %m) { -; CHECK-LABEL: @p_commutative1( -; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] -; CHECK-NEXT: ret i32 [[RET]] -; - %y = call i32 @gen32() - %and = and i32 %x, %m - %neg = xor i32 %m, -1 - %and1 = and i32 %y, %neg; swapped order - %ret = xor i32 %and, %and1 - ret i32 %ret -} - -define i32 @p_commutative2(i32 %x, i32 %y, i32 %m) { -; CHECK-LABEL: @p_commutative2( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] -; CHECK-NEXT: ret i32 [[RET]] -; - %and = and i32 %x, %m - %neg = xor i32 %m, -1 - %and1 = and i32 %neg, %y - %ret = xor i32 %and1, %and ; swapped order - ret i32 %ret -} - -define i32 @p_commutative3(i32 %x, i32 %m) { -; CHECK-LABEL: @p_commutative3( -; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() -; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] -; CHECK-NEXT: ret i32 [[RET]] -; - %y = call i32 @gen32() - %and = and i32 %m, %x ; swapped order - %neg = xor i32 %m, -1 - %and1 = and i32 %y, %neg; swapped order - %ret = xor i32 %and, %and1 - ret i32 %ret -} - -define i32 @p_commutative4(i32 %x, i32 %y, i32 %m) { -; CHECK-LABEL: @p_commutative4( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] -; CHECK-NEXT: ret i32 [[RET]] -; - %and = and i32 %m, %x ; swapped order - %neg = xor i32 %m, -1 - %and1 = and i32 %neg, %y - %ret = xor i32 %and1, %and ; swapped order - ret i32 %ret -} - -define i32 @p_commutative5(i32 %x, i32 %m) { -; CHECK-LABEL: @p_commutative5( -; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] -; CHECK-NEXT: ret i32 [[RET]] -; - %y = call i32 @gen32() - %and = and i32 %x, %m - %neg = xor i32 %m, -1 - %and1 = and i32 %y, %neg; swapped order - %ret = xor i32 %and1, %and ; swapped order - ret i32 %ret -} - -define i32 @p_commutative6(i32 %x, i32 %m) { -; CHECK-LABEL: @p_commutative6( -; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() -; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] -; CHECK-NEXT: ret i32 [[RET]] -; - %y = call i32 @gen32() - %and = and i32 %m, %x ; swapped order - %neg = xor i32 %m, -1 - %and1 = and i32 %y, %neg; swapped order - %ret = xor i32 %and1, %and ; swapped order - ret i32 %ret -} - define i32 @p_constmask_commutative(i32 %x, i32 %y) { ; CHECK-LABEL: @p_constmask_commutative( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 65280 diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll --- a/llvm/test/Transforms/InstCombine/or.ll +++ b/llvm/test/Transforms/InstCombine/or.ll @@ -1385,3 +1385,33 @@ %or1 = or i32 %xor, %neg ret i32 %or1 } + +define i32 @test_or_and_and_not(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @test_or_and_and_not( +; CHECK-NEXT: [[TMP1:%.*]] = freeze i32 [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], [[A:%.*]] +; CHECK-NEXT: [[OR:%.*]] = xor i32 [[TMP3]], [[TMP1]] +; CHECK-NEXT: ret i32 [[OR]] +; + %and0 = and i32 %a, %b + %not_a = xor i32 %a, -1 + %and1 = and i32 %not_a, %c + %or = or i32 %and0, %and1 + ret i32 %or +} + +define i32 @test_or_and_and_not2(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @test_or_and_and_not2( +; CHECK-NEXT: [[TMP1:%.*]] = freeze i32 [[A:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], [[B:%.*]] +; CHECK-NEXT: [[OR:%.*]] = xor i32 [[TMP3]], [[TMP1]] +; CHECK-NEXT: ret i32 [[OR]] +; + %not_b = xor i32 %b, -1 + %and0 = and i32 %a, %not_b + %and1 = and i32 %b, %c + %or = or i32 %and0, %and1 + ret i32 %or +}