Skip to content

Commit 6cfc0e4

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

File tree

2 files changed

+39
-11
lines changed

2 files changed

+39
-11
lines changed

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

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

264+
{
265+
// mul (lshr exact X, N), (2^N + 1) -> add (X, lshr exact (X, N))
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+
isGuaranteedNotToBeUndef(NewOp, &AC, &I, &DT)) {
272+
if (BitWidth > 2 && (*MulAP - 1).isPowerOf2() &&
273+
*ShiftC == MulAP->logBase2()) {
274+
Value *BinOp = Op0;
275+
BinaryOperator *OpBO = cast<BinaryOperator>(Op0);
276+
if (HasNUW && OpBO->getOpcode() == Instruction::AShr &&
277+
OpBO->hasOneUse())
278+
BinOp = Builder.CreateLShr(NewOp, ConstantInt::get(Ty, *ShiftC), "",
279+
/*isExact=*/true);
280+
281+
auto *NewAdd = BinaryOperator::CreateAdd(NewOp, BinOp);
282+
if (HasNSW && (OpBO->getOpcode() == Instruction::LShr ||
283+
ShiftC->getZExtValue() < BitWidth - 1))
284+
NewAdd->setHasNoSignedWrap(true);
285+
286+
NewAdd->setHasNoUnsignedWrap(HasNUW);
287+
return NewAdd;
288+
}
289+
}
290+
}
291+
264292
if (Op0->hasOneUse() && match(Op1, m_NegatedPower2())) {
265293
// Interpret X * (-1<<C) as (-X) * (1<<C) and try to sink the negation.
266294
// 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
@@ -865,7 +865,7 @@ define i32 @ashr_mul_times_5_div_4_exact_2(i32 %x) {
865865
define i32 @ashr_shift_mul(i32 noundef %x) {
866866
; CHECK-LABEL: @ashr_shift_mul(
867867
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
868-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
868+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[A]], [[X]]
869869
; CHECK-NEXT: ret i32 [[RES]]
870870
;
871871
%a = ashr exact i32 %x, 3
@@ -875,8 +875,8 @@ define i32 @ashr_shift_mul(i32 noundef %x) {
875875

876876
define i32 @ashr_shift_mul_nuw(i32 noundef %x) {
877877
; CHECK-LABEL: @ashr_shift_mul_nuw(
878-
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
879-
; CHECK-NEXT: [[RES:%.*]] = mul nuw i32 [[A]], 9
878+
; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[X:%.*]], 3
879+
; CHECK-NEXT: [[RES:%.*]] = add nuw i32 [[TMP1]], [[X]]
880880
; CHECK-NEXT: ret i32 [[RES]]
881881
;
882882
%a = ashr exact i32 %x, 3
@@ -887,7 +887,7 @@ define i32 @ashr_shift_mul_nuw(i32 noundef %x) {
887887
define i32 @ashr_shift_mul_nsw(i32 noundef %x) {
888888
; CHECK-LABEL: @ashr_shift_mul_nsw(
889889
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
890-
; CHECK-NEXT: [[RES:%.*]] = mul nsw i32 [[A]], 9
890+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[A]], [[X]]
891891
; CHECK-NEXT: ret i32 [[RES]]
892892
;
893893
%a = ashr exact i32 %x, 3
@@ -898,7 +898,7 @@ define i32 @ashr_shift_mul_nsw(i32 noundef %x) {
898898
define i32 @lshr_shift_mul_nuw(i32 noundef %x) {
899899
; CHECK-LABEL: @lshr_shift_mul_nuw(
900900
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
901-
; CHECK-NEXT: [[RES:%.*]] = mul nuw i32 [[A]], 9
901+
; CHECK-NEXT: [[RES:%.*]] = add nuw i32 [[A]], [[X]]
902902
; CHECK-NEXT: ret i32 [[RES]]
903903
;
904904
%a = lshr exact i32 %x, 3
@@ -909,7 +909,7 @@ define i32 @lshr_shift_mul_nuw(i32 noundef %x) {
909909
define i32 @lshr_shift_mul(i32 noundef %x) {
910910
; CHECK-LABEL: @lshr_shift_mul(
911911
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
912-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
912+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[A]], [[X]]
913913
; CHECK-NEXT: ret i32 [[RES]]
914914
;
915915
%a = lshr exact i32 %x, 3
@@ -920,7 +920,7 @@ define i32 @lshr_shift_mul(i32 noundef %x) {
920920
define i32 @lshr_shift_mul_nsw(i32 noundef %x) {
921921
; CHECK-LABEL: @lshr_shift_mul_nsw(
922922
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
923-
; CHECK-NEXT: [[RES:%.*]] = mul nuw nsw i32 [[A]], 9
923+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[A]], [[X]]
924924
; CHECK-NEXT: ret i32 [[RES]]
925925
;
926926
%a = lshr exact i32 %x, 3
@@ -984,7 +984,7 @@ define i32 @lshr_multiuse(i32 noundef %x) {
984984
; CHECK-LABEL: @lshr_multiuse(
985985
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
986986
; CHECK-NEXT: call void @use(i32 [[A]])
987-
; CHECK-NEXT: [[RES:%.*]] = mul nuw nsw i32 [[A]], 9
987+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[A]], [[X]]
988988
; CHECK-NEXT: ret i32 [[RES]]
989989
;
990990
%a = lshr exact i32 %x, 3
@@ -997,7 +997,7 @@ define i32 @lshr_multiuse_no_flags(i32 noundef %x) {
997997
; CHECK-LABEL: @lshr_multiuse_no_flags(
998998
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
999999
; CHECK-NEXT: call void @use(i32 [[A]])
1000-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
1000+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[A]], [[X]]
10011001
; CHECK-NEXT: ret i32 [[RES]]
10021002
;
10031003
%a = lshr exact i32 %x, 3
@@ -1010,7 +1010,7 @@ define i32 @ashr_multiuse_no_flags(i32 noundef %x) {
10101010
; CHECK-LABEL: @ashr_multiuse_no_flags(
10111011
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
10121012
; CHECK-NEXT: call void @use(i32 [[A]])
1013-
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
1013+
; CHECK-NEXT: [[RES:%.*]] = add i32 [[A]], [[X]]
10141014
; CHECK-NEXT: ret i32 [[RES]]
10151015
;
10161016
%a = ashr exact i32 %x, 3
@@ -1023,7 +1023,7 @@ define i32 @ashr_multiuse(i32 noundef %x) {
10231023
; CHECK-LABEL: @ashr_multiuse(
10241024
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
10251025
; CHECK-NEXT: call void @use(i32 [[A]])
1026-
; CHECK-NEXT: [[RES:%.*]] = mul nsw i32 [[A]], 9
1026+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[A]], [[X]]
10271027
; CHECK-NEXT: ret i32 [[RES]]
10281028
;
10291029
%a = ashr exact i32 %x, 3

0 commit comments

Comments
 (0)