forked from OSchip/llvm-project
[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:
parent
aa42a10051
commit
a1c8814891
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue