Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -748,6 +748,9 @@ return nullptr; } +static Instruction *canonicalizeMaskedMerge(BinaryOperator &I, + InstCombiner::BuilderTy &Builder); + /// Try to fold a signed range checked with lower bound 0 to an unsigned icmp. /// Example: (icmp sge x, 0) & (icmp slt x, n) --> icmp ult x, n /// If \p Inverted is true then the check is for the inverted range, e.g. @@ -1648,6 +1651,9 @@ A->getType()->isIntOrIntVectorTy(1)) return SelectInst::Create(A, Op0, Constant::getNullValue(I.getType())); + if (Instruction *MM = canonicalizeMaskedMerge(I, Builder)) + return MM; + return Changed ? &I : nullptr; } @@ -2422,6 +2428,29 @@ return nullptr; } +/// The canonical unfolded masked merge pattern is +/// (x & m) | (y & ~m) +/// But there is a second, equivalend variant: +/// (x | ~m) & (y | m) +/// We should prefer one of them. And once the DAGCombine is ready, fold them. +static Instruction *canonicalizeMaskedMerge(BinaryOperator &I, + InstCombiner::BuilderTy &Builder) { + Value *X, *Y; + + Value *M, *NotM; + if (match(&I, + m_c_And(m_OneUse(m_c_Or(m_Value(X), m_CombineAnd(m_Not(m_Value(M)), + m_Value(NotM)))), + m_OneUse(m_c_Or(m_Value(Y), m_Deferred(M)))))) { + // FIXME: once the DAGCombine is ready, fold them. + Value *LHS = Builder.CreateAnd(X, M); + Value *RHS = Builder.CreateAnd(Y, NotM); + return BinaryOperator::CreateOr(LHS, RHS); + } + + return nullptr; +} + /// If we have a masked merge, in the canonical form of: /// (assuming that A only has one use.) /// | A | |B| Index: test/Transforms/InstCombine/and-or-not.ll =================================================================== --- test/Transforms/InstCombine/and-or-not.ll +++ test/Transforms/InstCombine/and-or-not.ll @@ -502,11 +502,10 @@ define i64 @PR32830(i64 %a, i64 %b, i64 %c) { ; CHECK-LABEL: @PR32830( -; CHECK-NEXT: [[NOTA:%.*]] = xor i64 [[A:%.*]], -1 -; CHECK-NEXT: [[NOTB:%.*]] = xor i64 [[B:%.*]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i64 [[NOTB]], [[A]] -; CHECK-NEXT: [[OR2:%.*]] = or i64 [[NOTA]], [[C:%.*]] -; CHECK-NEXT: [[AND:%.*]] = and i64 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[C:%.*]], [[A:%.*]] +; CHECK-NEXT: [[DOTDEMORGAN:%.*]] = or i64 [[B:%.*]], [[A]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i64 [[DOTDEMORGAN]], -1 +; CHECK-NEXT: [[AND:%.*]] = or i64 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i64 [[AND]] ; %nota = xor i64 %a, -1 Index: test/Transforms/InstCombine/masked-merge-and-of-ors.ll =================================================================== --- test/Transforms/InstCombine/masked-merge-and-of-ors.ll +++ test/Transforms/InstCombine/masked-merge-and-of-ors.ll @@ -17,9 +17,9 @@ define i32 @p(i32 %x, i32 %y, i32 %m) { ; CHECK-LABEL: @p( ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M:%.*]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]] -; CHECK-NEXT: [[RET:%.*]] = and i32 [[OR]], [[OR1]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], [[M]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[NEG]], [[Y:%.*]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i32 [[RET]] ; %neg = xor i32 %m, -1 @@ -32,9 +32,9 @@ define <2 x i32> @p_splatvec(<2 x i32> %x, <2 x i32> %y, <2 x i32> %m) { ; CHECK-LABEL: @p_splatvec( ; CHECK-NEXT: [[NEG:%.*]] = xor <2 x i32> [[M:%.*]], -; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[NEG]], [[X:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or <2 x i32> [[Y:%.*]], [[M]] -; CHECK-NEXT: [[RET:%.*]] = and <2 x i32> [[OR]], [[OR1]] +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[X:%.*]], [[M]] +; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i32> [[NEG]], [[Y:%.*]] +; CHECK-NEXT: [[RET:%.*]] = or <2 x i32> [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret <2 x i32> [[RET]] ; %neg = xor <2 x i32> %m, @@ -47,9 +47,9 @@ define <3 x i32> @p_vec_undef(<3 x i32> %x, <3 x i32> %y, <3 x i32> %m) { ; CHECK-LABEL: @p_vec_undef( ; CHECK-NEXT: [[NEG:%.*]] = xor <3 x i32> [[M:%.*]], -; CHECK-NEXT: [[OR:%.*]] = or <3 x i32> [[NEG]], [[X:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or <3 x i32> [[Y:%.*]], [[M]] -; CHECK-NEXT: [[RET:%.*]] = and <3 x i32> [[OR]], [[OR1]] +; CHECK-NEXT: [[TMP1:%.*]] = and <3 x i32> [[X:%.*]], [[M]] +; CHECK-NEXT: [[TMP2:%.*]] = and <3 x i32> [[NEG]], [[Y:%.*]] +; CHECK-NEXT: [[RET:%.*]] = or <3 x i32> [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret <3 x i32> [[RET]] ; %neg = xor <3 x i32> %m, @@ -125,9 +125,9 @@ define i32 @p_commutative0(i32 %x, i32 %y, i32 %m) { ; CHECK-LABEL: @p_commutative0( ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M:%.*]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]] -; CHECK-NEXT: [[RET:%.*]] = and i32 [[OR]], [[OR1]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], [[M]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[NEG]], [[Y:%.*]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i32 [[RET]] ; %neg = xor i32 %m, -1 @@ -141,9 +141,9 @@ ; CHECK-LABEL: @p_commutative1( ; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M:%.*]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[Y]], [[M]] -; CHECK-NEXT: [[RET:%.*]] = and i32 [[OR]], [[OR1]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], [[M]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[Y]], [[NEG]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i32 [[RET]] ; %y = call i32 @gen32() @@ -157,9 +157,9 @@ define i32 @p_commutative2(i32 %x, i32 %y, i32 %m) { ; CHECK-LABEL: @p_commutative2( ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M:%.*]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]] -; CHECK-NEXT: [[RET:%.*]] = and i32 [[OR1]], [[OR]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], [[M]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[NEG]], [[Y:%.*]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i32 [[RET]] ; %neg = xor i32 %m, -1 @@ -173,9 +173,9 @@ ; CHECK-LABEL: @p_commutative3( ; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M:%.*]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[Y]], [[M]] -; CHECK-NEXT: [[RET:%.*]] = and i32 [[OR]], [[OR1]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], [[M]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[Y]], [[NEG]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i32 [[RET]] ; %y = call i32 @gen32() @@ -189,9 +189,9 @@ define i32 @p_commutative4(i32 %x, i32 %y, i32 %m) { ; CHECK-LABEL: @p_commutative4( ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M:%.*]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]] -; CHECK-NEXT: [[RET:%.*]] = and i32 [[OR1]], [[OR]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], [[M]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[NEG]], [[Y:%.*]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i32 [[RET]] ; %neg = xor i32 %m, -1 @@ -205,9 +205,9 @@ ; CHECK-LABEL: @p_commutative5( ; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M:%.*]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[Y]], [[M]] -; CHECK-NEXT: [[RET:%.*]] = and i32 [[OR1]], [[OR]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], [[M]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[Y]], [[NEG]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i32 [[RET]] ; %y = call i32 @gen32() @@ -222,9 +222,9 @@ ; CHECK-LABEL: @p_commutative6( ; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M:%.*]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[Y]], [[M]] -; CHECK-NEXT: [[RET:%.*]] = and i32 [[OR1]], [[OR]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], [[M]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[Y]], [[NEG]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i32 [[RET]] ; %y = call i32 @gen32() @@ -259,9 +259,9 @@ define i32 @n0_oneuse_of_neg_is_ok_0(i32 %x, i32 %y, i32 %m) { ; CHECK-LABEL: @n0_oneuse_of_neg_is_ok_0( ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M:%.*]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]] -; CHECK-NEXT: [[RET:%.*]] = and i32 [[OR]], [[OR1]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], [[M]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[NEG]], [[Y:%.*]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: call void @use32(i32 [[NEG]]) ; CHECK-NEXT: ret i32 [[RET]] ;