Skip to content

Commit 0faada2

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 b52125e commit 0faada2

File tree

2 files changed

+44
-15
lines changed

2 files changed

+44
-15
lines changed

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,33 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
255255
}
256256
}
257257

258+
// mul (shr exact X, N), (2^N + 1) -> add (X, shr exact (X, N))
259+
{
260+
Value *NewOp;
261+
const APInt *ShiftC;
262+
const APInt *MulAP;
263+
if (BitWidth > 2 &&
264+
match(&I, m_Mul(m_Exact(m_Shr(m_Value(NewOp), m_APInt(ShiftC))),
265+
m_APInt(MulAP))) &&
266+
(*MulAP - 1).isPowerOf2() && *ShiftC == MulAP->logBase2()) {
267+
Value *BinOp = Op0;
268+
BinaryOperator *OpBO = cast<BinaryOperator>(Op0);
269+
270+
// mul nuw (ashr exact X, N) -> add nuw (X, lshr exact (X, N))
271+
if (HasNUW && OpBO->getOpcode() == Instruction::AShr && OpBO->hasOneUse())
272+
BinOp = Builder.CreateLShr(NewOp, ConstantInt::get(Ty, *ShiftC), "",
273+
/*isExact=*/true);
274+
275+
auto *NewAdd = BinaryOperator::CreateAdd(NewOp, BinOp);
276+
if (HasNSW && (HasNUW || OpBO->getOpcode() == Instruction::LShr ||
277+
ShiftC->getZExtValue() < BitWidth - 1))
278+
NewAdd->setHasNoSignedWrap(true);
279+
280+
NewAdd->setHasNoUnsignedWrap(HasNUW);
281+
return NewAdd;
282+
}
283+
}
284+
258285
if (Op0->hasOneUse() && match(Op1, m_NegatedPower2())) {
259286
// Interpret X * (-1<<C) as (-X) * (1<<C) and try to sink the negation.
260287
// The "* (1<<C)" thus becomes a potential shifting opportunity.

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

Lines changed: 17 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,8 @@ 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: [[A:%.*]] = lshr exact i32 [[X_FR:%.*]], 3
1175+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X_FR]], [[A]]
11741176
; CHECK-NEXT: ret i32 [[RES]]
11751177
;
11761178
%a = lshr exact i32 %x, 3
@@ -1180,8 +1182,8 @@ define i32 @lshr_no_undef(i32 %x) {
11801182

11811183
define i32 @ashr_no_undef(i32 %x) {
11821184
; CHECK-LABEL: @ashr_no_undef(
1183-
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
1184-
; CHECK-NEXT: [[RES:%.*]] = mul nsw i32 [[A]], 9
1185+
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X_FR:%.*]], 3
1186+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X_FR]], [[A]]
11851187
; CHECK-NEXT: ret i32 [[RES]]
11861188
;
11871189
%a = ashr exact i32 %x, 3
@@ -1193,7 +1195,7 @@ define i32 @lshr_multiuse(i32 noundef %x) {
11931195
; CHECK-LABEL: @lshr_multiuse(
11941196
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
11951197
; CHECK-NEXT: call void @use(i32 [[A]])
1196-
; CHECK-NEXT: [[RES:%.*]] = mul nuw nsw i32 [[A]], 9
1198+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X]], [[A]]
11971199
; CHECK-NEXT: ret i32 [[RES]]
11981200
;
11991201
%a = lshr exact i32 %x, 3
@@ -1206,7 +1208,7 @@ define i32 @lshr_multiuse_no_flags(i32 noundef %x) {
12061208
; CHECK-LABEL: @lshr_multiuse_no_flags(
12071209
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
12081210
; CHECK-NEXT: call void @use(i32 [[A]])
1209-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
1211+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[X]], [[A]]
12101212
; CHECK-NEXT: ret i32 [[RES]]
12111213
;
12121214
%a = lshr exact i32 %x, 3
@@ -1219,7 +1221,7 @@ define i32 @ashr_multiuse_no_flags(i32 noundef %x) {
12191221
; CHECK-LABEL: @ashr_multiuse_no_flags(
12201222
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
12211223
; CHECK-NEXT: call void @use(i32 [[A]])
1222-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
1224+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[X]], [[A]]
12231225
; CHECK-NEXT: ret i32 [[RES]]
12241226
;
12251227
%a = ashr exact i32 %x, 3
@@ -1232,7 +1234,7 @@ define i32 @ashr_multiuse(i32 noundef %x) {
12321234
; CHECK-LABEL: @ashr_multiuse(
12331235
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
12341236
; CHECK-NEXT: call void @use(i32 [[A]])
1235-
; CHECK-NEXT: [[RES:%.*]] = mul nsw i32 [[A]], 9
1237+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X]], [[A]]
12361238
; CHECK-NEXT: ret i32 [[RES]]
12371239
;
12381240
%a = ashr exact i32 %x, 3

0 commit comments

Comments
 (0)