Index: llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -1239,6 +1239,22 @@ 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 (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)); + Instruction *NewLShr = BinaryOperator::CreateLShr(NewC, X); + return NewLShr; + } + } + return nullptr; } @@ -1427,5 +1443,22 @@ return BinaryOperator::CreateNot(NewAShr); } + // 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)); + Instruction *NewAShr = BinaryOperator::CreateAShr(NewC, X); + return NewAShr; + } + } + return nullptr; } Index: llvm/test/Transforms/InstCombine/shift-add.ll =================================================================== --- llvm/test/Transforms/InstCombine/shift-add.ll +++ llvm/test/Transforms/InstCombine/shift-add.ll @@ -170,6 +170,26 @@ ret i32 %r } +define i32 @lshr_add_negative(i32 %x) { +; CHECK-LABEL: @lshr_add_positive( +; CHECK-NEXT: [[R:%.*]] = lshr i32 4, [[X:%.*]] +; CHECK-NEXT: ret i32 [[R]] +; + %a = add i32 %x, -1 + %r = lshr i32 2, %a + ret i32 %r +} + +define i32 @ashr_exact_add_negative(i32 %x) { +; CHECK-LABEL: @ashr_exact_add_negative( +; CHECK-NEXT: [[R:%.*]] = ashr i32 -4, [[X:%.*]] +; CHECK-NEXT: ret i32 [[R]] +; + %a = add i32 %x, -1 + %r = ashr exact i32 -2, %a + ret i32 %r +} + ; PR54890 define i32 @shl_nsw_add_negative(i32 %x) {