From 8da2fa856f1b7ddd079e7b0637082f1413d97ea2 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Thu, 6 Oct 2022 12:31:42 -0400 Subject: [PATCH] [InstCombine] fold sdiv with hidden common factor (X * Y) s/ (X << Z) --> Y s/ (1 << Z) https://alive2.llvm.org/ce/z/yRSddG issue #58137 --- .../InstCombine/InstCombineMulDivRem.cpp | 7 +++- llvm/test/Transforms/InstCombine/div-shift.ll | 38 +++++++++++++------ .../PhaseOrdering/reassociate-instcombine.ll | 6 +-- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index 2267e00fee24..73afae663852 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -970,12 +970,17 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) { auto *OBO0 = cast(Op0); auto *OBO1 = cast(Op1); bool HasNUW = OBO0->hasNoUnsignedWrap() && OBO1->hasNoUnsignedWrap(); + bool HasNSW = OBO0->hasNoSignedWrap() && OBO1->hasNoSignedWrap(); // (X * Y) u/ (X << Z) --> Y u>> Z if (!IsSigned && HasNUW) return BinaryOperator::CreateLShr(Y, Z); - // TODO: Handle signed division. + // (X * Y) s/ (X << Z) --> Y s/ (1 << Z) + if (IsSigned && HasNSW && (Op0->hasOneUse() || Op1->hasOneUse())) { + Value *Shl = Builder.CreateShl(ConstantInt::get(Ty, 1), Z); + return BinaryOperator::CreateSDiv(Y, Shl); + } } return nullptr; diff --git a/llvm/test/Transforms/InstCombine/div-shift.ll b/llvm/test/Transforms/InstCombine/div-shift.ll index cfa8d55ff6d7..85c2fc3e53e1 100644 --- a/llvm/test/Transforms/InstCombine/div-shift.ll +++ b/llvm/test/Transforms/InstCombine/div-shift.ll @@ -295,11 +295,12 @@ define <2 x i32> @t16(<2 x i32> %x, <2 x i32> %y) { ret <2 x i32> %r } +; (X * Y) s/ (X << Z) --> Y s/ (1 << Z) + define i5 @sdiv_mul_shl_nsw(i5 %x, i5 %y, i5 %z) { ; CHECK-LABEL: @sdiv_mul_shl_nsw( -; CHECK-NEXT: [[M1:%.*]] = mul nsw i5 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[M2:%.*]] = shl nsw i5 [[X]], [[Z:%.*]] -; CHECK-NEXT: [[D:%.*]] = sdiv i5 [[M1]], [[M2]] +; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i5 1, [[Z:%.*]] +; CHECK-NEXT: [[D:%.*]] = sdiv i5 [[Y:%.*]], [[TMP1]] ; CHECK-NEXT: ret i5 [[D]] ; %m1 = mul nsw i5 %x, %y @@ -308,11 +309,12 @@ define i5 @sdiv_mul_shl_nsw(i5 %x, i5 %y, i5 %z) { ret i5 %d } +; (Y * Z) s/ (X << Z) --> Y s/ (1 << Z) + define i5 @sdiv_mul_shl_nsw_commute1(i5 %x, i5 %y, i5 %z) { ; CHECK-LABEL: @sdiv_mul_shl_nsw_commute1( -; CHECK-NEXT: [[M1:%.*]] = mul nsw i5 [[Y:%.*]], [[X:%.*]] -; CHECK-NEXT: [[M2:%.*]] = shl nsw i5 [[X]], [[Z:%.*]] -; CHECK-NEXT: [[D:%.*]] = sdiv i5 [[M1]], [[M2]] +; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i5 1, [[Z:%.*]] +; CHECK-NEXT: [[D:%.*]] = sdiv i5 [[Y:%.*]], [[TMP1]] ; CHECK-NEXT: ret i5 [[D]] ; %m1 = mul nsw i5 %y, %x @@ -321,6 +323,8 @@ define i5 @sdiv_mul_shl_nsw_commute1(i5 %x, i5 %y, i5 %z) { ret i5 %d } +; negative test - shl is not commutative + define i5 @sdiv_mul_shl_nsw_commute2(i5 %x, i5 %y, i5 %z) { ; CHECK-LABEL: @sdiv_mul_shl_nsw_commute2( ; CHECK-NEXT: [[M1:%.*]] = mul nsw i5 [[Y:%.*]], [[X:%.*]] @@ -334,12 +338,14 @@ define i5 @sdiv_mul_shl_nsw_commute2(i5 %x, i5 %y, i5 %z) { ret i5 %d } +; extra use is ok + define i8 @sdiv_mul_shl_nsw_use1(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @sdiv_mul_shl_nsw_use1( ; CHECK-NEXT: [[M1:%.*]] = mul nsw i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: call void @use(i8 [[M1]]) -; CHECK-NEXT: [[M2:%.*]] = shl nsw i8 [[X]], [[Z:%.*]] -; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[M1]], [[M2]] +; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i8 1, [[Z:%.*]] +; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[Y]], [[TMP1]] ; CHECK-NEXT: ret i8 [[D]] ; %m1 = mul nsw i8 %x, %y @@ -349,12 +355,14 @@ define i8 @sdiv_mul_shl_nsw_use1(i8 %x, i8 %y, i8 %z) { ret i8 %d } +; extra use is ok + define i8 @sdiv_mul_shl_nsw_use2(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @sdiv_mul_shl_nsw_use2( -; CHECK-NEXT: [[M1:%.*]] = mul nsw i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[M2:%.*]] = shl nsw i8 [[X]], [[Z:%.*]] +; CHECK-NEXT: [[M2:%.*]] = shl nsw i8 [[X:%.*]], [[Z:%.*]] ; CHECK-NEXT: call void @use(i8 [[M2]]) -; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[M1]], [[M2]] +; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i8 1, [[Z]] +; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[Y:%.*]], [[TMP1]] ; CHECK-NEXT: ret i8 [[D]] ; %m1 = mul nsw i8 %x, %y @@ -364,6 +372,8 @@ define i8 @sdiv_mul_shl_nsw_use2(i8 %x, i8 %y, i8 %z) { ret i8 %d } +; negative test - both operands can't have extra uses + define i8 @sdiv_mul_shl_nsw_use3(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @sdiv_mul_shl_nsw_use3( ; CHECK-NEXT: [[M1:%.*]] = mul nsw i8 [[X:%.*]], [[Y:%.*]] @@ -381,6 +391,8 @@ define i8 @sdiv_mul_shl_nsw_use3(i8 %x, i8 %y, i8 %z) { ret i8 %d } +; negative test - shl must be divisor + define i5 @sdiv_shl_mul_nsw(i5 %x, i5 %y, i5 %z) { ; CHECK-LABEL: @sdiv_shl_mul_nsw( ; CHECK-NEXT: [[M1:%.*]] = shl nsw i5 [[Z:%.*]], [[X:%.*]] @@ -394,6 +406,8 @@ define i5 @sdiv_shl_mul_nsw(i5 %x, i5 %y, i5 %z) { ret i5 %d } +; negative test - wrong no-wrap + define i5 @sdiv_mul_shl_missing_nsw1(i5 %x, i5 %y, i5 %z) { ; CHECK-LABEL: @sdiv_mul_shl_missing_nsw1( ; CHECK-NEXT: [[M1:%.*]] = mul nsw i5 [[X:%.*]], [[Y:%.*]] @@ -407,6 +421,8 @@ define i5 @sdiv_mul_shl_missing_nsw1(i5 %x, i5 %y, i5 %z) { ret i5 %d } +; negative test - wrong no-wrap + define i5 @sdiv_mul_shl_missing_nsw2(i5 %x, i5 %y, i5 %z) { ; CHECK-LABEL: @sdiv_mul_shl_missing_nsw2( ; CHECK-NEXT: [[M1:%.*]] = mul nuw i5 [[X:%.*]], [[Y:%.*]] diff --git a/llvm/test/Transforms/PhaseOrdering/reassociate-instcombine.ll b/llvm/test/Transforms/PhaseOrdering/reassociate-instcombine.ll index 2fc37b79e529..fb9e5d0f5694 100644 --- a/llvm/test/Transforms/PhaseOrdering/reassociate-instcombine.ll +++ b/llvm/test/Transforms/PhaseOrdering/reassociate-instcombine.ll @@ -39,11 +39,7 @@ define i32 @not_reassociate_or_or_not(i32 %a, i32 %b, i32 %c, i32 %d) { define i32 @PR58137(i32 %a, i32 %b) { ; CHECK-LABEL: @PR58137( -; CHECK-NEXT: [[MUL:%.*]] = shl i32 [[A:%.*]], 1 -; CHECK-NEXT: [[MUL1:%.*]] = mul i32 [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[MUL2:%.*]] = shl nsw i32 [[A]], 1 -; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[MUL1]], [[MUL2]] -; CHECK-NEXT: ret i32 [[DIV]] +; CHECK-NEXT: ret i32 [[B:%.*]] ; %mul = mul nsw i32 2, %b %mul1 = mul nsw i32 %mul, %a