From: Sanjay Patel Date: Mon, 31 Jul 2017 21:01:53 +0000 (+0000) Subject: [InstCombine] allow mask hoisting transform for vector types X-Git-Tag: android-x86-7.1-r4~12786 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=a1da952a2350fd45cb3108ca53a204ee16401279;p=android-x86%2Fexternal-llvm.git [InstCombine] allow mask hoisting transform for vector types git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@309627 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index fdc9c373b95..9d68201fc7a 100644 --- a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1284,14 +1284,35 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { if (Value *V = SimplifyBSwap(I, Builder)) return replaceInstUsesWith(I, V); - if (match(Op1, m_One())) { - // (1 << x) & 1 --> zext(x == 0) - // (1 >> x) & 1 --> zext(x == 0) - Value *X; - if (match(Op0, m_OneUse(m_LogicalShift(m_One(), m_Value(X))))) { + const APInt *C; + if (match(Op1, m_APInt(C))) { + Value *X, *Y; + if (match(Op0, m_OneUse(m_LogicalShift(m_One(), m_Value(X)))) && + C->isOneValue()) { + // (1 << X) & 1 --> zext(X == 0) + // (1 >> X) & 1 --> zext(X == 0) Value *IsZero = Builder.CreateICmpEQ(X, ConstantInt::get(I.getType(), 0)); return new ZExtInst(IsZero, I.getType()); } + + // If the mask is only needed on one incoming arm, push the 'and' op up. + if (match(Op0, m_OneUse(m_Xor(m_Value(X), m_Value(Y)))) || + match(Op0, m_OneUse(m_Or(m_Value(X), m_Value(Y))))) { + APInt NotAndMask(~(*C)); + BinaryOperator::BinaryOps BinOp = cast(Op0)->getOpcode(); + if (MaskedValueIsZero(X, NotAndMask, 0, &I)) { + // Not masking anything out for the LHS, move mask to RHS. + // and ({x}or X, Y), C --> {x}or X, (and Y, C) + Value *NewRHS = Builder.CreateAnd(Y, Op1, Y->getName() + ".masked"); + return BinaryOperator::Create(BinOp, X, NewRHS); + } + if (!isa(Y) && MaskedValueIsZero(Y, NotAndMask, 0, &I)) { + // Not masking anything out for the RHS, move mask to LHS. + // and ({x}or X, Y), C --> {x}or (and X, C), Y + Value *NewLHS = Builder.CreateAnd(X, Op1, X->getName() + ".masked"); + return BinaryOperator::Create(BinOp, NewLHS, Y); + } + } } if (ConstantInt *AndRHS = dyn_cast(Op1)) { @@ -1299,34 +1320,6 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { // Optimize a variety of ((val OP C1) & C2) combinations... if (BinaryOperator *Op0I = dyn_cast(Op0)) { - Value *Op0LHS = Op0I->getOperand(0); - Value *Op0RHS = Op0I->getOperand(1); - switch (Op0I->getOpcode()) { - default: break; - case Instruction::Xor: - case Instruction::Or: { - // If the mask is only needed on one incoming arm, push it up. - if (!Op0I->hasOneUse()) break; - - APInt NotAndRHS(~AndRHSMask); - if (MaskedValueIsZero(Op0LHS, NotAndRHS, 0, &I)) { - // Not masking anything out for the LHS, move to RHS. - Value *NewRHS = Builder.CreateAnd(Op0RHS, AndRHS, - Op0RHS->getName()+".masked"); - return BinaryOperator::Create(Op0I->getOpcode(), Op0LHS, NewRHS); - } - if (!isa(Op0RHS) && - MaskedValueIsZero(Op0RHS, NotAndRHS, 0, &I)) { - // Not masking anything out for the RHS, move to LHS. - Value *NewLHS = Builder.CreateAnd(Op0LHS, AndRHS, - Op0LHS->getName()+".masked"); - return BinaryOperator::Create(Op0I->getOpcode(), NewLHS, Op0RHS); - } - - break; - } - } - // ((C1 OP zext(X)) & C2) -> zext((C1-X) & C2) if C2 fits in the bitwidth // of X and OP behaves well when given trunc(C1) and X. switch (Op0I->getOpcode()) { @@ -1343,6 +1336,7 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { if (AndRHSMask.isIntN(X->getType()->getScalarSizeInBits())) { auto *TruncC1 = ConstantExpr::getTrunc(C1, X->getType()); Value *BinOp; + Value *Op0LHS = Op0I->getOperand(0); if (isa(Op0LHS)) BinOp = Builder.CreateBinOp(Op0I->getOpcode(), X, TruncC1); else diff --git a/test/Transforms/InstCombine/and-or.ll b/test/Transforms/InstCombine/and-or.ll index dbf5c59c932..fa8e158fb47 100644 --- a/test/Transforms/InstCombine/and-or.ll +++ b/test/Transforms/InstCombine/and-or.ll @@ -73,8 +73,8 @@ define i8 @and_or_hoist_mask(i8 %a, i8 %b) { define <2 x i8> @and_xor_hoist_mask_vec_splat(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @and_xor_hoist_mask_vec_splat( ; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i8> %a, -; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[SH]], %b -; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[XOR]], +; CHECK-NEXT: [[B_MASKED:%.*]] = and <2 x i8> %b, +; CHECK-NEXT: [[AND:%.*]] = xor <2 x i8> [[SH]], [[B_MASKED]] ; CHECK-NEXT: ret <2 x i8> [[AND]] ; %sh = lshr <2 x i8> %a, @@ -102,8 +102,8 @@ define <2 x i8> @and_or_hoist_mask_commute_vec_splat(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @and_or_hoist_mask_commute_vec_splat( ; CHECK-NEXT: [[C:%.*]] = mul <2 x i8> %b, ; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i8> %a, -; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[C]], [[SH]] -; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[OR]], +; CHECK-NEXT: [[C_MASKED:%.*]] = and <2 x i8> [[C]], +; CHECK-NEXT: [[AND:%.*]] = or <2 x i8> [[C_MASKED]], [[SH]] ; CHECK-NEXT: ret <2 x i8> [[AND]] ; %c = mul <2 x i8> %b, ; thwart complexity-based ordering