[llvm] 889854b - [InstCombine] Avoid unprofitable add with remainder transform (#147319)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 8 05:29:34 PDT 2025
Author: Nikita Popov
Date: 2025-07-08T14:29:31+02:00
New Revision: 889854bef14a7a9df4a730b20abc3cad3140f644
URL: https://github.com/llvm/llvm-project/commit/889854bef14a7a9df4a730b20abc3cad3140f644
DIFF: https://github.com/llvm/llvm-project/commit/889854bef14a7a9df4a730b20abc3cad3140f644.diff
LOG: [InstCombine] Avoid unprofitable add with remainder transform (#147319)
If C1 is 1 and we're working with a power of two divisor, this will end
up replacing the `and` for the remainder with a multiply and a longer
dependency chain.
Fixes https://github.com/llvm/llvm-project/issues/147176.
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
llvm/test/Transforms/InstCombine/add4.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 1ba548b6ff062..981c5271fb3f6 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1194,7 +1194,9 @@ Value *InstCombinerImpl::SimplifyAddWithRemainder(BinaryOperator &I) {
Value *DivOpV;
APInt DivOpC;
if (MatchRem(Rem, X, C0, IsSigned) &&
- MatchDiv(Div, DivOpV, DivOpC, IsSigned) && X == DivOpV && C0 == DivOpC) {
+ MatchDiv(Div, DivOpV, DivOpC, IsSigned) && X == DivOpV && C0 == DivOpC &&
+ // Avoid unprofitable replacement of and with mul.
+ !(C1.isOne() && !IsSigned && DivOpC.isPowerOf2() && DivOpC != 2)) {
APInt NewC = C1 - C2 * C0;
if (!NewC.isZero() && !Rem->hasOneUse())
return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/add4.ll b/llvm/test/Transforms/InstCombine/add4.ll
index 0e97deb4d98ad..15feb8a093e99 100644
--- a/llvm/test/Transforms/InstCombine/add4.ll
+++ b/llvm/test/Transforms/InstCombine/add4.ll
@@ -289,3 +289,126 @@ entry:
%add = add i32 %shl, %rem
ret i32 %add
}
+
+define i32 @fold_add_udiv_urem_no_mul(i32 noundef %val) {
+; CHECK-LABEL: @fold_add_udiv_urem_no_mul(
+; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[VAL:%.*]], 10
+; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[DIV]], -9
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[TMP1]], [[VAL]]
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %div = udiv i32 %val, 10
+ %rem = urem i32 %val, 10
+ %add = add i32 %div, %rem
+ ret i32 %add
+}
+
+define i32 @fold_add_udiv_urem_rem_mul(i32 noundef %val) {
+; CHECK-LABEL: @fold_add_udiv_urem_rem_mul(
+; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[VAL:%.*]], 10
+; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[VAL]], 3
+; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[DIV]], -29
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[TMP2]], [[TMP1]]
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %div = udiv i32 %val, 10
+ %rem = urem i32 %val, 10
+ %mul = mul i32 %rem, 3
+ %add = add i32 %div, %mul
+ ret i32 %add
+}
+
+define i32 @fold_add_udiv_urem_pow2_no_mul(i32 noundef %arg) {
+; CHECK-LABEL: @fold_add_udiv_urem_pow2_no_mul(
+; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ARG:%.*]], 4
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[ARG]], 15
+; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LSHR]], [[AND]]
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %lshr = lshr i32 %arg, 4
+ %and = and i32 %arg, 15
+ %add = add i32 %lshr, %and
+ ret i32 %add
+}
+
+define i32 @fold_add_udiv_urem_pow2_div_mul(i32 noundef %arg) {
+; CHECK-LABEL: @fold_add_udiv_urem_pow2_div_mul(
+; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ARG:%.*]], 4
+; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[LSHR]], -13
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[TMP1]], [[ARG]]
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %lshr = lshr i32 %arg, 4
+ %mul = mul i32 %lshr, 3
+ %and = and i32 %arg, 15
+ %add = add i32 %mul, %and
+ ret i32 %add
+}
+
+define i32 @fold_add_sdiv_srem_no_mul(i32 noundef %val) {
+; CHECK-LABEL: @fold_add_sdiv_srem_no_mul(
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[VAL:%.*]], 10
+; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[DIV]], -9
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[TMP1]], [[VAL]]
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %div = sdiv i32 %val, 10
+ %rem = srem i32 %val, 10
+ %add = add i32 %div, %rem
+ ret i32 %add
+}
+
+define i32 @fold_add_udiv_urem_pow2_rem_mul(i32 noundef %arg) {
+; CHECK-LABEL: @fold_add_udiv_urem_pow2_rem_mul(
+; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ARG:%.*]], 4
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[ARG]], 15
+; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i32 [[AND]], 3
+; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LSHR]], [[MUL]]
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %lshr = lshr i32 %arg, 4
+ %and = and i32 %arg, 15
+ %mul = mul i32 %and, 3
+ %add = add i32 %lshr, %mul
+ ret i32 %add
+}
+
+define i32 @fold_add_udiv_urem_pow2_both_mul(i32 noundef %arg) {
+; CHECK-LABEL: @fold_add_udiv_urem_pow2_both_mul(
+; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ARG:%.*]], 4
+; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[ARG]], 3
+; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[LSHR]], -41
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[TMP2]], [[TMP1]]
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %lshr = lshr i32 %arg, 4
+ %mul1 = mul i32 %lshr, 7
+ %and = and i32 %arg, 15
+ %mul2 = mul i32 %and, 3
+ %add = add i32 %mul1, %mul2
+ ret i32 %add
+}
+
+define i32 @fold_add_udiv_urem_by_two_no_mul(i32 noundef %arg) {
+; CHECK-LABEL: @fold_add_udiv_urem_by_two_no_mul(
+; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ARG:%.*]], 1
+; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[ARG]], [[LSHR]]
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %lshr = lshr i32 %arg, 1
+ %and = and i32 %arg, 1
+ %add = add i32 %lshr, %and
+ ret i32 %add
+}
+
+define i32 @fold_add_sdiv_srem_by_two_no_mul(i32 noundef %arg) {
+; CHECK-LABEL: @fold_add_sdiv_srem_by_two_no_mul(
+; CHECK-NEXT: [[DIV_NEG:%.*]] = sdiv i32 [[ARG:%.*]], -2
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[DIV_NEG]], [[ARG]]
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %div = sdiv i32 %arg, 2
+ %rem = srem i32 %arg, 2
+ %add = add i32 %div, %rem
+ ret i32 %add
+}
More information about the llvm-commits
mailing list