1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 02:52:53 +02:00

[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
This commit is contained in:
Sanjay Patel 2017-05-08 20:49:59 +00:00
parent f80014fd35
commit af36fe6110
2 changed files with 48 additions and 21 deletions

View File

@ -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);
}
}

View File

@ -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