Skip to content

Commit 45d12f1

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 8851b3e commit 45d12f1

File tree

2 files changed

+38
-11
lines changed

2 files changed

+38
-11
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: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,7 @@ entry:
10801080
define i32 @ashr_shift_mul(i32 %x) {
10811081
; CHECK-LABEL: @ashr_shift_mul(
10821082
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
1083-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
1083+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[X]], [[A]]
10841084
; CHECK-NEXT: ret i32 [[RES]]
10851085
;
10861086
%a = ashr exact i32 %x, 3
@@ -1090,8 +1090,8 @@ define i32 @ashr_shift_mul(i32 %x) {
10901090

10911091
define i32 @ashr_shift_mul_nuw(i32 %x) {
10921092
; CHECK-LABEL: @ashr_shift_mul_nuw(
1093-
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
1094-
; 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]]
10951095
; CHECK-NEXT: ret i32 [[RES]]
10961096
;
10971097
%a = ashr exact i32 %x, 3
@@ -1102,7 +1102,7 @@ define i32 @ashr_shift_mul_nuw(i32 %x) {
11021102
define i32 @ashr_shift_mul_nsw(i32 %x) {
11031103
; CHECK-LABEL: @ashr_shift_mul_nsw(
11041104
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
1105-
; CHECK-NEXT: [[RES:%.*]] = mul nsw i32 [[A]], 9
1105+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X]], [[A]]
11061106
; CHECK-NEXT: ret i32 [[RES]]
11071107
;
11081108
%a = ashr exact i32 %x, 3
@@ -1113,7 +1113,7 @@ define i32 @ashr_shift_mul_nsw(i32 %x) {
11131113
define i32 @lshr_shift_mul_nuw(i32 %x) {
11141114
; CHECK-LABEL: @lshr_shift_mul_nuw(
11151115
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
1116-
; CHECK-NEXT: [[RES:%.*]] = mul nuw i32 [[A]], 9
1116+
; CHECK-NEXT: [[RES:%.*]] = add nuw i32 [[X]], [[A]]
11171117
; CHECK-NEXT: ret i32 [[RES]]
11181118
;
11191119
%a = lshr exact i32 %x, 3
@@ -1124,7 +1124,7 @@ define i32 @lshr_shift_mul_nuw(i32 %x) {
11241124
define i32 @lshr_shift_mul(i32 %x) {
11251125
; CHECK-LABEL: @lshr_shift_mul(
11261126
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
1127-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
1127+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[X]], [[A]]
11281128
; CHECK-NEXT: ret i32 [[RES]]
11291129
;
11301130
%a = lshr exact i32 %x, 3
@@ -1135,7 +1135,7 @@ define i32 @lshr_shift_mul(i32 %x) {
11351135
define i32 @lshr_shift_mul_nsw(i32 %x) {
11361136
; CHECK-LABEL: @lshr_shift_mul_nsw(
11371137
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
1138-
; CHECK-NEXT: [[RES:%.*]] = mul nuw nsw i32 [[A]], 9
1138+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X]], [[A]]
11391139
; CHECK-NEXT: ret i32 [[RES]]
11401140
;
11411141
%a = lshr exact i32 %x, 3
@@ -1173,7 +1173,7 @@ define i32 @lshr_multiuse(i32 %x) {
11731173
; CHECK-LABEL: @lshr_multiuse(
11741174
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
11751175
; CHECK-NEXT: call void @use(i32 [[A]])
1176-
; CHECK-NEXT: [[RES:%.*]] = mul nuw nsw i32 [[A]], 9
1176+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X]], [[A]]
11771177
; CHECK-NEXT: ret i32 [[RES]]
11781178
;
11791179
%a = lshr exact i32 %x, 3
@@ -1186,7 +1186,7 @@ define i32 @lshr_multiuse_no_flags(i32 %x) {
11861186
; CHECK-LABEL: @lshr_multiuse_no_flags(
11871187
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
11881188
; CHECK-NEXT: call void @use(i32 [[A]])
1189-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
1189+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[X]], [[A]]
11901190
; CHECK-NEXT: ret i32 [[RES]]
11911191
;
11921192
%a = lshr exact i32 %x, 3
@@ -1199,7 +1199,7 @@ define i32 @ashr_multiuse_no_flags(i32 %x) {
11991199
; CHECK-LABEL: @ashr_multiuse_no_flags(
12001200
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
12011201
; CHECK-NEXT: call void @use(i32 [[A]])
1202-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
1202+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[X]], [[A]]
12031203
; CHECK-NEXT: ret i32 [[RES]]
12041204
;
12051205
%a = ashr exact i32 %x, 3
@@ -1212,7 +1212,7 @@ define i32 @ashr_multiuse(i32 %x) {
12121212
; CHECK-LABEL: @ashr_multiuse(
12131213
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
12141214
; CHECK-NEXT: call void @use(i32 [[A]])
1215-
; CHECK-NEXT: [[RES:%.*]] = mul nsw i32 [[A]], 9
1215+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[X]], [[A]]
12161216
; CHECK-NEXT: ret i32 [[RES]]
12171217
;
12181218
%a = ashr exact i32 %x, 3

0 commit comments

Comments
 (0)