diff options
author | Sanjay Patel <spatel@rotateright.com> | 2017-05-08 20:49:59 +0000 |
---|---|---|
committer | Sanjay Patel <spatel@rotateright.com> | 2017-05-08 20:49:59 +0000 |
commit | a1c88148910f71841b3ab1deafb7d1b285a24a07 (patch) | |
tree | f044bb2ada370ef0bf52ee1876f8dc9151eab01e | |
parent | aa42a100513a040a2e8276287011a36c7e042e7b (diff) | |
download | bcm5719-llvm-a1c88148910f71841b3ab1deafb7d1b285a24a07.tar.gz bcm5719-llvm-a1c88148910f71841b3ab1deafb7d1b285a24a07.zip |
[InstCombine] add folds for not-of-shift-right
This is another step towards getting rid of dyn_castNotVal,
so we can recommit:
https://reviews.llvm.org/rL300977
As the tests show, we were missing the lshr case for constants
and both ashr/lshr vector splat folds. The ashr case with constant
was being performed inefficiently in 2 steps. It's also possible
there was a latent bug in that case because we can't do that fold
if the constant is positive:
http://rise4fun.com/Alive/Bge
llvm-svn: 302465
-rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 47 | ||||
-rw-r--r-- | llvm/test/Transforms/InstCombine/not.ll | 22 |
2 files changed, 48 insertions, 21 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index b114801cc1c..417e9136a56 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2399,27 +2399,44 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { } // Is this a 'not' (~) fed by a binary operator? - BinaryOperator *NotOp; - if (match(&I, m_Not(m_BinOp(NotOp)))) { - if (NotOp->getOpcode() == Instruction::And || - NotOp->getOpcode() == Instruction::Or) { + BinaryOperator *NotVal; + if (match(&I, m_Not(m_BinOp(NotVal)))) { + if (NotVal->getOpcode() == Instruction::And || + NotVal->getOpcode() == Instruction::Or) { // Apply DeMorgan's Law when inverts are free: // ~(X & Y) --> (~X | ~Y) // ~(X | Y) --> (~X & ~Y) - if (IsFreeToInvert(NotOp->getOperand(0), - NotOp->getOperand(0)->hasOneUse()) && - IsFreeToInvert(NotOp->getOperand(1), - NotOp->getOperand(1)->hasOneUse())) { - Value *NotX = Builder->CreateNot(NotOp->getOperand(0), "notlhs"); - Value *NotY = Builder->CreateNot(NotOp->getOperand(1), "notrhs"); - if (NotOp->getOpcode() == Instruction::And) + if (IsFreeToInvert(NotVal->getOperand(0), + NotVal->getOperand(0)->hasOneUse()) && + IsFreeToInvert(NotVal->getOperand(1), + NotVal->getOperand(1)->hasOneUse())) { + Value *NotX = Builder->CreateNot(NotVal->getOperand(0), "notlhs"); + Value *NotY = Builder->CreateNot(NotVal->getOperand(1), "notrhs"); + if (NotVal->getOpcode() == Instruction::And) return BinaryOperator::CreateOr(NotX, NotY); return BinaryOperator::CreateAnd(NotX, NotY); } - } else if (NotOp->getOpcode() == Instruction::AShr) { - // ~(~X >>s Y) --> (X >>s Y) - if (Value *Op0NotVal = dyn_castNotVal(NotOp->getOperand(0))) - return BinaryOperator::CreateAShr(Op0NotVal, NotOp->getOperand(1)); + } + + // ~(~X >>s Y) --> (X >>s Y) + if (match(NotVal, m_AShr(m_Not(m_Value(X)), m_Value(Y)))) + return BinaryOperator::CreateAShr(X, Y); + + // If we are inverting a right-shifted constant, we may be able to eliminate + // the 'not' by inverting the constant and using the opposite shift type. + // Canonicalization rules ensure that only a negative constant uses 'ashr', + // but we must check that in case that transform has not fired yet. + const APInt *C; + if (match(NotVal, m_AShr(m_APInt(C), m_Value(Y))) && C->isNegative()) { + // ~(C >>s Y) --> ~C >>u Y (when inverting the replicated sign bits) + Constant *NotC = ConstantInt::get(I.getType(), ~(*C)); + return BinaryOperator::CreateLShr(NotC, Y); + } + + if (match(NotVal, m_LShr(m_APInt(C), m_Value(Y))) && C->isNonNegative()) { + // ~(C >>u Y) --> ~C >>s Y (when inverting the replicated sign bits) + Constant *NotC = ConstantInt::get(I.getType(), ~(*C)); + return BinaryOperator::CreateAShr(NotC, Y); } } diff --git a/llvm/test/Transforms/InstCombine/not.ll b/llvm/test/Transforms/InstCombine/not.ll index 9f57b6a2702..6ff0a50318d 100644 --- a/llvm/test/Transforms/InstCombine/not.ll +++ b/llvm/test/Transforms/InstCombine/not.ll @@ -79,8 +79,7 @@ define i8 @not_ashr_const(i8 %x) { define <2 x i8> @not_ashr_const_splat(<2 x i8> %x) { ; CHECK-LABEL: @not_ashr_const_splat( -; CHECK-NEXT: [[SHR:%.*]] = ashr <2 x i8> <i8 -42, i8 -42>, %x -; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[SHR]], <i8 -1, i8 -1> +; CHECK-NEXT: [[NOT:%.*]] = lshr <2 x i8> <i8 41, i8 41>, %x ; CHECK-NEXT: ret <2 x i8> [[NOT]] ; %shr = ashr <2 x i8> <i8 -42, i8 -42>, %x @@ -88,10 +87,22 @@ define <2 x i8> @not_ashr_const_splat(<2 x i8> %x) { ret <2 x i8> %not } +; We can't get rid of the 'not' on a logical shift of a negative constant. + +define i8 @not_lshr_const_negative(i8 %x) { +; CHECK-LABEL: @not_lshr_const_negative( +; CHECK-NEXT: [[SHR:%.*]] = lshr i8 -42, %x +; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[SHR]], -1 +; CHECK-NEXT: ret i8 [[NOT]] +; + %shr = lshr i8 -42, %x + %not = xor i8 %shr, -1 + ret i8 %not +} + define i8 @not_lshr_const(i8 %x) { ; CHECK-LABEL: @not_lshr_const( -; CHECK-NEXT: [[SHR:%.*]] = lshr i8 42, %x -; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[SHR]], -1 +; CHECK-NEXT: [[NOT:%.*]] = ashr i8 -43, %x ; CHECK-NEXT: ret i8 [[NOT]] ; %shr = lshr i8 42, %x @@ -101,8 +112,7 @@ define i8 @not_lshr_const(i8 %x) { define <2 x i8> @not_lshr_const_splat(<2 x i8> %x) { ; CHECK-LABEL: @not_lshr_const_splat( -; CHECK-NEXT: [[SHR:%.*]] = lshr <2 x i8> <i8 42, i8 42>, %x -; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[SHR]], <i8 -1, i8 -1> +; CHECK-NEXT: [[NOT:%.*]] = ashr <2 x i8> <i8 -43, i8 -43>, %x ; CHECK-NEXT: ret <2 x i8> [[NOT]] ; %shr = lshr <2 x i8> <i8 42, i8 42>, %x |