Index: llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -1239,6 +1239,23 @@ return BinaryOperator::CreateAnd(Mask, X); } + // Try to pre-shift a constant shifted by a variable amount: + // C >> (X - AddC) --> (C << AddC) >> X + // This requires a negative offset constant. + const APInt *AddC; + unsigned BitWidth = Ty->getScalarSizeInBits(); + if (I.isExact() && 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->shl(PosOffset).lshr(PosOffset))) { + Constant *NewC = ConstantInt::get(Ty, C->shl(PosOffset)); + BinaryOperator *NewLShr = BinaryOperator::CreateLShr(NewC, X); + NewLShr->setIsExact(); + return NewLShr; + } + } + return nullptr; } @@ -1415,6 +1432,24 @@ if (Instruction *R = foldVariableSignZeroExtensionOfVariableHighBitExtract(I)) return R; + // Try to pre-shift a constant shifted by a variable amount: + // C >> (X - AddC) --> (C << AddC) >> X + // This requires the exact flag and a negative offset constant. + const APInt *AddC; + const APInt *C; + if (I.isExact() && 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->shl(PosOffset).ashr(PosOffset))) { + Constant *NewC = ConstantInt::get(Ty, C->shl(PosOffset)); + BinaryOperator *NewAShr = BinaryOperator::CreateAShr(NewC, X); + NewAShr->setIsExact(); + return NewAShr; + } + } + // See if we can turn a signed shr into an unsigned shr. if (MaskedValueIsZero(Op0, APInt::getSignMask(BitWidth), 0, &I)) return BinaryOperator::CreateLShr(Op0, Op1); Index: llvm/test/Transforms/InstCombine/shift-add.ll =================================================================== --- llvm/test/Transforms/InstCombine/shift-add.ll +++ llvm/test/Transforms/InstCombine/shift-add.ll @@ -157,6 +157,72 @@ ret i32 %r } +; Negative offset precondition check for lshr_add_negative_shift_positive +define i32 @lshr_add_positive_shift_positive(i32 %x) { +; CHECK-LABEL: @lshr_add_positive_shift_positive( +; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], 1 +; CHECK-NEXT: [[R:%.*]] = lshr exact i32 2, [[A:%.*]] +; CHECK-NEXT: ret i32 [[R]] +; + %a = add i32 %x, 1 + %r = lshr exact i32 2, %a + ret i32 %r +} + +; Positive constant precondition check for lshr_add_negative_shift_positive +define i32 @lshr_add_negative_shift_negative(i32 %x) { +; CHECK-LABEL: @lshr_add_negative_shift_negative( +; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -1 +; CHECK-NEXT: [[R:%.*]] = lshr exact i32 -2, [[A:%.*]] +; CHECK-NEXT: ret i32 [[R]] +; + %a = add i32 %x, -1 + %r = lshr exact i32 -2, %a + ret i32 %r +} + +define i32 @lshr_add_negative_shift_positive(i32 %x) { +; CHECK-LABEL: @lshr_add_negative_shift_positive( +; CHECK-NEXT: [[R:%.*]] = lshr exact i32 4, [[X:%.*]] +; CHECK-NEXT: ret i32 [[R]] +; + %a = add i32 %x, -1 + %r = lshr exact i32 2, %a + ret i32 %r +} + +; Precondition check for ashr_exact_add_negative_shift_positive +define i32 @ashr_exact_add_negative_shift_no_trailing_zeros(i32 %x) { +; CHECK-LABEL: @ashr_exact_add_negative_shift_no_trailing_zeros( +; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -1 +; CHECK-NEXT: [[R:%.*]] = lshr i32 1073741824, [[A:%.*]] +; CHECK-NEXT: ret i32 [[R]] +; + %a = add i32 %x, -1 + %r = ashr exact i32 1073741824, %a + ret i32 %r +} + +define i32 @ashr_exact_add_negative_shift_negative(i32 %x) { +; CHECK-LABEL: @ashr_exact_add_negative_shift_negative( +; CHECK-NEXT: [[R:%.*]] = ashr exact i32 -4, [[X:%.*]] +; CHECK-NEXT: ret i32 [[R]] +; + %a = add i32 %x, -1 + %r = ashr exact i32 -2, %a + ret i32 %r +} + +define i32 @ashr_exact_add_negative_shift_positive(i32 %x) { +; CHECK-LABEL: @ashr_exact_add_negative_shift_positive( +; CHECK-NEXT: [[R:%.*]] = lshr i32 4, [[X:%.*]] +; CHECK-NEXT: ret i32 [[R]] +; + %a = add i32 %x, -1 + %r = ashr exact i32 2, %a + ret i32 %r +} + ; negative test - must have 'nuw' define i32 @shl_add_nsw(i32 %x) {