forked from OSchip/llvm-project
[InstCombine] C0 >> (X - C1) --> (C0 << C1) >> X
With the right pre-conditions, we can fold the offset into the shifted constant: https://alive2.llvm.org/ce/z/drMRBU https://alive2.llvm.org/ce/z/cUQv-_ Fixes #55016 Differential Revision: https://reviews.llvm.org/D124369
This commit is contained in:
parent
c2614b31d9
commit
f8a574bf4d
|
@ -373,11 +373,12 @@ Instruction *InstCombinerImpl::commonShiftTransforms(BinaryOperator &I) {
|
|||
|
||||
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
||||
assert(Op0->getType() == Op1->getType());
|
||||
Type *Ty = I.getType();
|
||||
|
||||
// If the shift amount is a one-use `sext`, we can demote it to `zext`.
|
||||
Value *Y;
|
||||
if (match(Op1, m_OneUse(m_SExt(m_Value(Y))))) {
|
||||
Value *NewExt = Builder.CreateZExt(Y, I.getType(), Op1->getName());
|
||||
Value *NewExt = Builder.CreateZExt(Y, Ty, Op1->getName());
|
||||
return BinaryOperator::Create(I.getOpcode(), Op0, NewExt);
|
||||
}
|
||||
|
||||
|
@ -409,6 +410,47 @@ Instruction *InstCombinerImpl::commonShiftTransforms(BinaryOperator &I) {
|
|||
return BinaryOperator::Create(I.getOpcode(), NewC, A);
|
||||
}
|
||||
|
||||
unsigned BitWidth = Ty->getScalarSizeInBits();
|
||||
|
||||
const APInt *AC, *AddC;
|
||||
// Try to pre-shift a constant shifted by a variable amount added with a
|
||||
// negative number:
|
||||
// C << (X - AddC) --> (C >> AddC) << X
|
||||
// and
|
||||
// C >> (X - AddC) --> (C << AddC) >> X
|
||||
if (match(Op0, m_APInt(AC)) && match(Op1, m_Add(m_Value(A), m_APInt(AddC))) &&
|
||||
AddC->isNegative() && (-*AddC).ult(BitWidth)) {
|
||||
assert(!AC->isZero() && "Expected simplify of shifted zero");
|
||||
unsigned PosOffset = (-*AddC).getZExtValue();
|
||||
|
||||
auto isSuitableForPreShift = [PosOffset, &I, AC]() {
|
||||
switch (I.getOpcode()) {
|
||||
default:
|
||||
return false;
|
||||
case Instruction::Shl:
|
||||
return (I.hasNoSignedWrap() || I.hasNoUnsignedWrap()) &&
|
||||
AC->eq(AC->lshr(PosOffset).shl(PosOffset));
|
||||
case Instruction::LShr:
|
||||
return I.isExact() && AC->eq(AC->shl(PosOffset).lshr(PosOffset));
|
||||
case Instruction::AShr:
|
||||
return I.isExact() && AC->eq(AC->shl(PosOffset).ashr(PosOffset));
|
||||
}
|
||||
};
|
||||
if (isSuitableForPreShift()) {
|
||||
Constant *NewC = ConstantInt::get(Ty, I.getOpcode() == Instruction::Shl
|
||||
? AC->lshr(PosOffset)
|
||||
: AC->shl(PosOffset));
|
||||
BinaryOperator *NewShiftOp =
|
||||
BinaryOperator::Create(I.getOpcode(), NewC, A);
|
||||
if (I.getOpcode() == Instruction::Shl) {
|
||||
NewShiftOp->setHasNoUnsignedWrap(I.hasNoUnsignedWrap());
|
||||
} else {
|
||||
NewShiftOp->setIsExact();
|
||||
}
|
||||
return NewShiftOp;
|
||||
}
|
||||
}
|
||||
|
||||
// X shift (A srem C) -> X shift (A and (C - 1)) iff C is a power of 2.
|
||||
// Because shifts by negative values (which could occur if A were negative)
|
||||
// are undefined.
|
||||
|
@ -416,7 +458,7 @@ Instruction *InstCombinerImpl::commonShiftTransforms(BinaryOperator &I) {
|
|||
match(C, m_Power2())) {
|
||||
// FIXME: Should this get moved into SimplifyDemandedBits by saying we don't
|
||||
// demand the sign bit (and many others) here??
|
||||
Constant *Mask = ConstantExpr::getSub(C, ConstantInt::get(I.getType(), 1));
|
||||
Constant *Mask = ConstantExpr::getSub(C, ConstantInt::get(Ty, 1));
|
||||
Value *Rem = Builder.CreateAnd(A, Mask, Op1->getName());
|
||||
return replaceOperand(I, 1, Rem);
|
||||
}
|
||||
|
@ -988,23 +1030,6 @@ Instruction *InstCombinerImpl::visitShl(BinaryOperator &I) {
|
|||
return BinaryOperator::CreateLShr(
|
||||
ConstantInt::get(Ty, APInt::getSignMask(BitWidth)), X);
|
||||
|
||||
// Try to pre-shift a constant shifted by a variable amount:
|
||||
// C << (X + AddC) --> (C >> -AddC) << X
|
||||
// This requires a no-wrap flag and negative offset constant.
|
||||
const APInt *AddC;
|
||||
if ((I.hasNoSignedWrap() || I.hasNoUnsignedWrap()) &&
|
||||
match(Op0, m_APInt(C)) && match(Op1, m_Add(m_Value(X), m_APInt(AddC))) &&
|
||||
AddC->isNegative() && (-*AddC).ult(BitWidth)) {
|
||||
assert(!C->isZero() && "Expected simplify of shifted zero");
|
||||
unsigned PosOffset = (-*AddC).getZExtValue();
|
||||
if (C->eq(C->lshr(PosOffset).shl(PosOffset))) {
|
||||
Constant *NewC = ConstantInt::get(Ty, C->lshr(PosOffset));
|
||||
Instruction *NewShl = BinaryOperator::CreateShl(NewC, X);
|
||||
NewShl->setHasNoUnsignedWrap(I.hasNoUnsignedWrap());
|
||||
return NewShl;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -224,8 +224,7 @@ define i32 @lshr_add_negative_shift_no_exact(i32 %x) {
|
|||
|
||||
define i32 @lshr_exact_add_negative_shift_positive(i32 %x) {
|
||||
; CHECK-LABEL: @lshr_exact_add_negative_shift_positive(
|
||||
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = lshr exact i32 2, [[A]]
|
||||
; CHECK-NEXT: [[R:%.*]] = lshr exact i32 4, [[X:%.*]]
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%a = add i32 %x, -1
|
||||
|
@ -237,7 +236,7 @@ define i8 @lshr_exact_add_negative_shift_positive_extra_use(i8 %x) {
|
|||
; CHECK-LABEL: @lshr_exact_add_negative_shift_positive_extra_use(
|
||||
; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], -1
|
||||
; CHECK-NEXT: call void @use(i8 [[A]])
|
||||
; CHECK-NEXT: [[R:%.*]] = lshr exact i8 64, [[A]]
|
||||
; CHECK-NEXT: [[R:%.*]] = lshr exact i8 -128, [[X]]
|
||||
; CHECK-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%a = add i8 %x, -1
|
||||
|
@ -248,8 +247,7 @@ define i8 @lshr_exact_add_negative_shift_positive_extra_use(i8 %x) {
|
|||
|
||||
define <2 x i9> @lshr_exact_add_negative_shift_positive_vec(<2 x i9> %x) {
|
||||
; CHECK-LABEL: @lshr_exact_add_negative_shift_positive_vec(
|
||||
; CHECK-NEXT: [[A:%.*]] = add <2 x i9> [[X:%.*]], <i9 -7, i9 -7>
|
||||
; CHECK-NEXT: [[R:%.*]] = lshr exact <2 x i9> <i9 2, i9 2>, [[A]]
|
||||
; CHECK-NEXT: [[R:%.*]] = lshr exact <2 x i9> <i9 -256, i9 -256>, [[X:%.*]]
|
||||
; CHECK-NEXT: ret <2 x i9> [[R]]
|
||||
;
|
||||
%a = add <2 x i9> %x, <i9 -7, i9 -7>
|
||||
|
@ -309,8 +307,7 @@ define i32 @ashr_add_negative_shift_no_exact(i32 %x) {
|
|||
|
||||
define i32 @ashr_exact_add_negative_shift_negative(i32 %x) {
|
||||
; CHECK-LABEL: @ashr_exact_add_negative_shift_negative(
|
||||
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = ashr exact i32 -2, [[A]]
|
||||
; CHECK-NEXT: [[R:%.*]] = ashr exact i32 -4, [[X:%.*]]
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%a = add i32 %x, -1
|
||||
|
@ -322,7 +319,7 @@ define i8 @ashr_exact_add_negative_shift_negative_extra_use(i8 %x) {
|
|||
; CHECK-LABEL: @ashr_exact_add_negative_shift_negative_extra_use(
|
||||
; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], -2
|
||||
; CHECK-NEXT: call void @use(i8 [[A]])
|
||||
; CHECK-NEXT: [[R:%.*]] = ashr exact i8 -32, [[A]]
|
||||
; CHECK-NEXT: [[R:%.*]] = ashr exact i8 -128, [[X]]
|
||||
; CHECK-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%a = add i8 %x, -2
|
||||
|
@ -333,8 +330,7 @@ define i8 @ashr_exact_add_negative_shift_negative_extra_use(i8 %x) {
|
|||
|
||||
define <2 x i7> @ashr_exact_add_negative_shift_negative_vec(<2 x i7> %x) {
|
||||
; CHECK-LABEL: @ashr_exact_add_negative_shift_negative_vec(
|
||||
; CHECK-NEXT: [[A:%.*]] = add <2 x i7> [[X:%.*]], <i7 -5, i7 -5>
|
||||
; CHECK-NEXT: [[R:%.*]] = ashr exact <2 x i7> <i7 -2, i7 -2>, [[A]]
|
||||
; CHECK-NEXT: [[R:%.*]] = ashr exact <2 x i7> <i7 -64, i7 -64>, [[X:%.*]]
|
||||
; CHECK-NEXT: ret <2 x i7> [[R]]
|
||||
;
|
||||
%a = add <2 x i7> %x, <i7 -5, i7 -5>
|
||||
|
|
Loading…
Reference in New Issue