diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -373,11 +373,12 @@ 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 @@ 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 @@ 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 @@ 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; } diff --git a/llvm/test/Transforms/InstCombine/shift-add.ll b/llvm/test/Transforms/InstCombine/shift-add.ll --- a/llvm/test/Transforms/InstCombine/shift-add.ll +++ b/llvm/test/Transforms/InstCombine/shift-add.ll @@ -224,8 +224,7 @@ 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 @@ ; 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 <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:%.*]], -; CHECK-NEXT: [[R:%.*]] = lshr exact <2 x i9> , [[A]] +; CHECK-NEXT: [[R:%.*]] = lshr exact <2 x i9> , [[X:%.*]] ; CHECK-NEXT: ret <2 x i9> [[R]] ; %a = add <2 x i9> %x, @@ -309,8 +307,7 @@ 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 @@ ; 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 <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:%.*]], -; CHECK-NEXT: [[R:%.*]] = ashr exact <2 x i7> , [[A]] +; CHECK-NEXT: [[R:%.*]] = ashr exact <2 x i7> , [[X:%.*]] ; CHECK-NEXT: ret <2 x i7> [[R]] ; %a = add <2 x i7> %x,