Skip to content

Commit 37b0139

Browse files
committed
[InstCombine] Fold mul (shr exact (X, N)), 2^N + 1 -> add (X , shr exact (X, N))
Alive2 Proofs: https://alive2.llvm.org/ce/z/aJnxyp https://alive2.llvm.org/ce/z/dyeGEv
1 parent 5bde6a4 commit 37b0139

File tree

2 files changed

+50
-15
lines changed

2 files changed

+50
-15
lines changed

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,37 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
261261
}
262262
}
263263

264+
// mul (shr exact X, N), (2^N + 1) -> add (X, shr exact (X, N))
265+
{
266+
Value *NewOp;
267+
const APInt *ShiftC;
268+
const APInt *MulAP;
269+
if (match(&I, m_Mul(m_Exact(m_Shr(m_Value(NewOp), m_APInt(ShiftC))),
270+
m_APInt(MulAP)))) {
271+
if (BitWidth > 2 && (*MulAP - 1).isPowerOf2() &&
272+
*ShiftC == MulAP->logBase2()) {
273+
Value *BinOp = Op0;
274+
BinaryOperator *OpBO = cast<BinaryOperator>(Op0);
275+
if (!isGuaranteedNotToBeUndef(NewOp, &AC, &I, &DT))
276+
NewOp = Builder.CreateFreeze(NewOp, NewOp->getName() + ".fr");
277+
278+
// mul (ashr nuw exact X, N) -> add (X, lshr nuw exact (X, N))
279+
if (HasNUW && OpBO->getOpcode() == Instruction::AShr &&
280+
OpBO->hasOneUse())
281+
BinOp = Builder.CreateLShr(NewOp, ConstantInt::get(Ty, *ShiftC), "",
282+
/*isExact=*/true);
283+
284+
auto *NewAdd = BinaryOperator::CreateAdd(NewOp, BinOp);
285+
if (HasNSW && (HasNUW || OpBO->getOpcode() == Instruction::LShr ||
286+
ShiftC->getZExtValue() < BitWidth - 1))
287+
NewAdd->setHasNoSignedWrap(true);
288+
289+
NewAdd->setHasNoUnsignedWrap(HasNUW);
290+
return NewAdd;
291+
}
292+
}
293+
}
294+
264295
if (Op0->hasOneUse() && match(Op1, m_NegatedPower2())) {
265296
// Interpret X * (-1<<C) as (-X) * (1<<C) and try to sink the negation.
266297
// The "* (1<<C)" thus becomes a potential shifting opportunity.

llvm/test/Transforms/InstCombine/ashr-lshr.ll

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,10 +1075,12 @@ entry:
10751075
call void @use(i32 %and)
10761076
%shr = ashr i32 %and, 31
10771077
ret i32 %shr
1078+
}
1079+
10781080
define i32 @ashr_shift_mul(i32 noundef %x) {
10791081
; CHECK-LABEL: @ashr_shift_mul(
10801082
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
1081-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
1083+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[X]], [[A]]
10821084
; CHECK-NEXT: ret i32 [[RES]]
10831085
;
10841086
%a = ashr exact i32 %x, 3
@@ -1088,8 +1090,8 @@ define i32 @ashr_shift_mul(i32 noundef %x) {
10881090

10891091
define i32 @ashr_shift_mul_nuw(i32 noundef %x) {
10901092
; CHECK-LABEL: @ashr_shift_mul_nuw(
1091-
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
1092-
; CHECK-NEXT: [[RES:%.*]] = mul nuw i32 [[A]], 9
1093+
; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[X:%.*]], 3
1094+
; CHECK-NEXT: [[RES:%.*]] = add nuw i32 [[X]], [[TMP1]]
10931095
; CHECK-NEXT: ret i32 [[RES]]
10941096
;
10951097
%a = ashr exact i32 %x, 3
@@ -1100,7 +1102,7 @@ define i32 @ashr_shift_mul_nuw(i32 noundef %x) {
11001102
define i32 @ashr_shift_mul_nsw(i32 noundef %x) {
11011103
; CHECK-LABEL: @ashr_shift_mul_nsw(
11021104
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
1103-
; CHECK-NEXT: [[RES:%.*]] = mul nsw i32 [[A]], 9
1105+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X]], [[A]]
11041106
; CHECK-NEXT: ret i32 [[RES]]
11051107
;
11061108
%a = ashr exact i32 %x, 3
@@ -1111,7 +1113,7 @@ define i32 @ashr_shift_mul_nsw(i32 noundef %x) {
11111113
define i32 @lshr_shift_mul_nuw(i32 noundef %x) {
11121114
; CHECK-LABEL: @lshr_shift_mul_nuw(
11131115
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
1114-
; CHECK-NEXT: [[RES:%.*]] = mul nuw i32 [[A]], 9
1116+
; CHECK-NEXT: [[RES:%.*]] = add nuw i32 [[X]], [[A]]
11151117
; CHECK-NEXT: ret i32 [[RES]]
11161118
;
11171119
%a = lshr exact i32 %x, 3
@@ -1122,7 +1124,7 @@ define i32 @lshr_shift_mul_nuw(i32 noundef %x) {
11221124
define i32 @lshr_shift_mul(i32 noundef %x) {
11231125
; CHECK-LABEL: @lshr_shift_mul(
11241126
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
1125-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
1127+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[X]], [[A]]
11261128
; CHECK-NEXT: ret i32 [[RES]]
11271129
;
11281130
%a = lshr exact i32 %x, 3
@@ -1133,7 +1135,7 @@ define i32 @lshr_shift_mul(i32 noundef %x) {
11331135
define i32 @lshr_shift_mul_nsw(i32 noundef %x) {
11341136
; CHECK-LABEL: @lshr_shift_mul_nsw(
11351137
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
1136-
; CHECK-NEXT: [[RES:%.*]] = mul nuw nsw i32 [[A]], 9
1138+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X]], [[A]]
11371139
; CHECK-NEXT: ret i32 [[RES]]
11381140
;
11391141
%a = lshr exact i32 %x, 3
@@ -1169,8 +1171,9 @@ define i32 @ashr_no_exact(i32 %x) {
11691171

11701172
define i32 @lshr_no_undef(i32 %x) {
11711173
; CHECK-LABEL: @lshr_no_undef(
1172-
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
1173-
; CHECK-NEXT: [[RES:%.*]] = mul nuw nsw i32 [[A]], 9
1174+
; CHECK-NEXT: [[X_FR:%.*]] = freeze i32 [[X:%.*]]
1175+
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X_FR]], 3
1176+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X_FR]], [[A]]
11741177
; CHECK-NEXT: ret i32 [[RES]]
11751178
;
11761179
%a = lshr exact i32 %x, 3
@@ -1180,8 +1183,9 @@ define i32 @lshr_no_undef(i32 %x) {
11801183

11811184
define i32 @ashr_no_undef(i32 %x) {
11821185
; CHECK-LABEL: @ashr_no_undef(
1183-
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
1184-
; CHECK-NEXT: [[RES:%.*]] = mul nsw i32 [[A]], 9
1186+
; CHECK-NEXT: [[X_FR:%.*]] = freeze i32 [[X:%.*]]
1187+
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X_FR]], 3
1188+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X_FR]], [[A]]
11851189
; CHECK-NEXT: ret i32 [[RES]]
11861190
;
11871191
%a = ashr exact i32 %x, 3
@@ -1193,7 +1197,7 @@ define i32 @lshr_multiuse(i32 noundef %x) {
11931197
; CHECK-LABEL: @lshr_multiuse(
11941198
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
11951199
; CHECK-NEXT: call void @use(i32 [[A]])
1196-
; CHECK-NEXT: [[RES:%.*]] = mul nuw nsw i32 [[A]], 9
1200+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X]], [[A]]
11971201
; CHECK-NEXT: ret i32 [[RES]]
11981202
;
11991203
%a = lshr exact i32 %x, 3
@@ -1206,7 +1210,7 @@ define i32 @lshr_multiuse_no_flags(i32 noundef %x) {
12061210
; CHECK-LABEL: @lshr_multiuse_no_flags(
12071211
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
12081212
; CHECK-NEXT: call void @use(i32 [[A]])
1209-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
1213+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[X]], [[A]]
12101214
; CHECK-NEXT: ret i32 [[RES]]
12111215
;
12121216
%a = lshr exact i32 %x, 3
@@ -1219,7 +1223,7 @@ define i32 @ashr_multiuse_no_flags(i32 noundef %x) {
12191223
; CHECK-LABEL: @ashr_multiuse_no_flags(
12201224
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
12211225
; CHECK-NEXT: call void @use(i32 [[A]])
1222-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
1226+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[X]], [[A]]
12231227
; CHECK-NEXT: ret i32 [[RES]]
12241228
;
12251229
%a = ashr exact i32 %x, 3
@@ -1232,7 +1236,7 @@ define i32 @ashr_multiuse(i32 noundef %x) {
12321236
; CHECK-LABEL: @ashr_multiuse(
12331237
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
12341238
; CHECK-NEXT: call void @use(i32 [[A]])
1235-
; CHECK-NEXT: [[RES:%.*]] = mul nsw i32 [[A]], 9
1239+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X]], [[A]]
12361240
; CHECK-NEXT: ret i32 [[RES]]
12371241
;
12381242
%a = ashr exact i32 %x, 3

0 commit comments

Comments
 (0)