Index: llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1306,6 +1306,19 @@ // X % C0 + (( X / C0 ) % C1) * C0 => X % (C0 * C1) if (Value *V = SimplifyAddWithRemainder(I)) return replaceInstUsesWith(I, V); + // ((X / C1) << C2) + X => X % -C1 + // where -C1 = 1 << C2 + const APInt *C1, *C2; + if (match(LHS, m_Shl(m_SDiv(m_Value(A), m_APInt(C1)), m_APInt(C2)))) { + if ((RHS == A) && C1->abs().isPowerOf2() && C1->isNegative()) { + APInt one(C2->getBitWidth(), 1); + if ((C1->abs() == one.shl(*C2)) && C2->sgt(one)) { + Constant *NewRHS = ConstantInt::get(RHS->getType(), C1->abs()); + return BinaryOperator::CreateSRem(RHS, NewRHS); + } + } + } + // A+B --> A|B iff A and B have no bits set in common. if (haveNoCommonBitsSet(LHS, RHS, DL, &AC, &I, &DT)) return BinaryOperator::CreateOr(LHS, RHS); Index: llvm/test/Transforms/InstCombine/add-shl-sdiv-to-srem.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/add-shl-sdiv-to-srem.ll @@ -0,0 +1,142 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s + +define i8 @add-shl-sdiv-i8-2(i8 %x) { +; CHECK-LABEL: @add-shl-sdiv-i8-2( +; CHECK-NEXT: [[RZ:%.*]] = srem i8 [[X:%.*]], 4 +; CHECK-NEXT: ret i8 [[RZ]] +; + %sd = sdiv i8 %x, -4 + %sl = shl i8 %sd, 2 + %rz = add i8 %sl, %x + ret i8 %rz +} + +define i8 @add-shl-sdiv-i8-6(i8 %x) { +; CHECK-LABEL: @add-shl-sdiv-i8-6( +; CHECK-NEXT: [[RZ:%.*]] = srem i8 [[X:%.*]], 64 +; CHECK-NEXT: ret i8 [[RZ]] +; + %sd = sdiv i8 %x, -64 + %sl = shl i8 %sd, 6 + %rz = add i8 %sl, %x + ret i8 %rz +} + +define i32 @add-shl-sdiv-i32-30(i32 %x) { +; CHECK-LABEL: @add-shl-sdiv-i32-30( +; CHECK-NEXT: [[RZ:%.*]] = srem i32 [[X:%.*]], 1073741824 +; CHECK-NEXT: ret i32 [[RZ]] +; + %sd = sdiv i32 %x, -1073741824 + %sl = shl i32 %sd, 30 + %rz = add i32 %sl, %x + ret i32 %rz +} + +; Splat vectors + +define <3 x i8> @add-shl-sdiv-3xi8-2(<3 x i8> %x) { +; CHECK-LABEL: @add-shl-sdiv-3xi8-2( +; CHECK-NEXT: [[RZ:%.*]] = srem <3 x i8> [[X:%.*]], +; CHECK-NEXT: ret <3 x i8> [[RZ]] +; + %sd = sdiv <3 x i8> %x, + %sl = shl <3 x i8> %sd, + %rz = add <3 x i8> %sl, %x + ret <3 x i8> %rz +} + +define <2 x i64> @add-shl-sdiv-2xi64-5(<2 x i64> %x) { +; CHECK-LABEL: @add-shl-sdiv-2xi64-5( +; CHECK-NEXT: [[RZ:%.*]] = srem <2 x i64> [[X:%.*]], +; CHECK-NEXT: ret <2 x i64> [[RZ]] +; + %sd = sdiv <2 x i64> %x, + %sl = shl <2 x i64> %sd, + %rz = add <2 x i64> %sl, %x + ret <2 x i64> %rz +} + +; One-use tests + +declare void @use32(i32) +define i32 @add-shl-sdiv-i32-4-use-1(i32 %x) { +; CHECK-LABEL: @add-shl-sdiv-i32-4-use-1( +; CHECK-NEXT: call void @use32(i32 [[X:%.*]]) +; CHECK-NEXT: [[RZ:%.*]] = srem i32 [[X]], 16 +; CHECK-NEXT: ret i32 [[RZ]] +; + call void @use32(i32 %x) + %sd = sdiv i32 %x, -16 + %sl = shl i32 %sd, 4 + %rz = add i32 %sl, %x + ret i32 %rz +} + +define i32 @add-shl-sdiv-i32-4-use-2(i32 %x) { +; CHECK-LABEL: @add-shl-sdiv-i32-4-use-2( +; CHECK-NEXT: [[SD:%.*]] = sdiv i32 [[X:%.*]], -16 +; CHECK-NEXT: call void @use32(i32 [[SD]]) +; CHECK-NEXT: [[RZ:%.*]] = srem i32 [[X]], 16 +; CHECK-NEXT: ret i32 [[RZ]] +; + %sd = sdiv i32 %x, -16 + call void @use32(i32 %sd) + %sl = shl i32 %sd, 4 + %rz = add i32 %sl, %x + ret i32 %rz +} + +define i32 @add-shl-sdiv-i32-4-use-3(i32 %x) { +; CHECK-LABEL: @add-shl-sdiv-i32-4-use-3( +; CHECK-NEXT: [[SD:%.*]] = sdiv i32 [[X:%.*]], -16 +; CHECK-NEXT: [[SL:%.*]] = shl i32 [[SD]], 4 +; CHECK-NEXT: call void @use32(i32 [[SL]]) +; CHECK-NEXT: [[RZ:%.*]] = srem i32 [[X]], 16 +; CHECK-NEXT: ret i32 [[RZ]] +; + %sd = sdiv i32 %x, -16 + %sl = shl i32 %sd, 4 + call void @use32(i32 %sl) + %rz = add i32 %sl, %x + ret i32 %rz +} + +; Negative + +define i8 @add-shl-sdiv-negative-1(i8 %x) { +; CHECK-LABEL: @add-shl-sdiv-negative-1( +; CHECK-NEXT: [[SD:%.*]] = sdiv i8 [[X:%.*]], 4 +; CHECK-NEXT: [[SL:%.*]] = shl nsw i8 [[SD]], 2 +; CHECK-NEXT: [[RZ:%.*]] = add i8 [[SL]], [[X]] +; CHECK-NEXT: ret i8 [[RZ]] +; + %sd = sdiv i8 %x, 4 + %sl = shl i8 %sd, 2 + %rz = add i8 %sl, %x + ret i8 %rz +} + +define <3 x i8> @add-shl-sdiv-negative-2(<3 x i8> %x) { +; CHECK-LABEL: @add-shl-sdiv-negative-2( +; CHECK-NEXT: [[SD:%.*]] = sdiv <3 x i8> [[X:%.*]], +; CHECK-NEXT: [[SL:%.*]] = shl <3 x i8> [[SD]], +; CHECK-NEXT: [[RZ:%.*]] = add <3 x i8> [[SL]], [[X]] +; CHECK-NEXT: ret <3 x i8> [[RZ]] +; + %sd = sdiv <3 x i8> %x, + %sl = shl <3 x i8> %sd, + %rz = add <3 x i8> %sl, %x + ret <3 x i8> %rz +} + +define <2 x i64> @add-shl-sdiv-negative-3(<2 x i64> %x) { +; CHECK-LABEL: @add-shl-sdiv-negative-3( +; CHECK-NEXT: ret <2 x i64> undef +; + %sd = sdiv <2 x i64> %x, + %sl = shl <2 x i64> %sd, + %rz = add <2 x i64> %sl, %x + ret <2 x i64> %rz +}