diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -1053,6 +1053,15 @@ } } + // (X << Z) / (X * Y) -> (1 << Z) / Y + if (match(Op0, m_NUWShl(m_Value(X), m_Value(Z))) && + match(Op1, m_c_Mul(m_Specific(X), m_Value(Y)))) { + bool HasNUW = cast(Op1)->hasNoUnsignedWrap(); + if (!IsSigned && HasNUW) + return BinaryOperator::CreateUDiv( + Builder.CreateShl(ConstantInt::get(Ty, 1), Z), Y); + } + if (Instruction *R = foldIDivShl(I, Builder)) return R; diff --git a/llvm/test/Transforms/InstCombine/div-shift.ll b/llvm/test/Transforms/InstCombine/div-shift.ll --- a/llvm/test/Transforms/InstCombine/div-shift.ll +++ b/llvm/test/Transforms/InstCombine/div-shift.ll @@ -528,13 +528,12 @@ ret i8 %d } -; TODO: This can fold to (1< (1 << Z) / Y define i5 @udiv_shl_mul_nuw(i5 %x, i5 %y, i5 %z) { ; CHECK-LABEL: @udiv_shl_mul_nuw( -; CHECK-NEXT: [[M1:%.*]] = shl nuw i5 [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[M2:%.*]] = mul nuw i5 [[X]], [[Y:%.*]] -; CHECK-NEXT: [[D:%.*]] = udiv i5 [[M1]], [[M2]] +; CHECK-NEXT: [[TMP1:%.*]] = shl i5 1, [[Z:%.*]] +; CHECK-NEXT: [[D:%.*]] = udiv i5 [[TMP1]], [[Y:%.*]] ; CHECK-NEXT: ret i5 [[D]] ; %m1 = shl nuw i5 %x, %z @@ -545,9 +544,8 @@ define i5 @udiv_shl_mul_nuw_swap(i5 %x, i5 %y, i5 %z) { ; CHECK-LABEL: @udiv_shl_mul_nuw_swap( -; CHECK-NEXT: [[M1:%.*]] = shl nuw i5 [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[M2:%.*]] = mul nuw i5 [[Y:%.*]], [[X]] -; CHECK-NEXT: [[D:%.*]] = udiv i5 [[M1]], [[M2]] +; CHECK-NEXT: [[TMP1:%.*]] = shl i5 1, [[Z:%.*]] +; CHECK-NEXT: [[D:%.*]] = udiv i5 [[TMP1]], [[Y:%.*]] ; CHECK-NEXT: ret i5 [[D]] ; %m1 = shl nuw i5 %x, %z