[InstCombine] fold sdiv with common shl amount in operands

(X << Z) / (Y << Z) --> X / Y

https://alive2.llvm.org/ce/z/CLKzqT

This requires a surprising "nuw" constraint because we have
to guard against immediate UB via signed-div overflow with
-1 divisor.

This extends 008a89037a and is another transform
derived from issue #58137.
This commit is contained in:
Sanjay Patel 2022-10-12 11:18:55 -04:00
parent 4c19439d24
commit 7b9482df3d
2 changed files with 16 additions and 7 deletions

View File

@ -862,7 +862,11 @@ static Instruction *foldIDivShl(BinaryOperator &I,
if (!IsSigned && Shl0->hasNoUnsignedWrap() && Shl1->hasNoUnsignedWrap())
Ret = BinaryOperator::CreateUDiv(X, Y);
// TODO: Handle sdiv.
// For signed div, we need 'nsw' on both shifts + 'nuw' on the divisor.
// (X << Z) / (Y << Z) --> X / Y
if (IsSigned && Shl0->hasNoSignedWrap() && Shl1->hasNoSignedWrap() &&
Shl1->hasNoUnsignedWrap())
Ret = BinaryOperator::CreateSDiv(X, Y);
}
if (!Ret)

View File

@ -742,13 +742,11 @@ define i8 @sdiv_lshr_mul_nsw(i8 %x, i8 %y, i8 %z) {
ret i8 %div
}
; TODO: (X << Z) / (Y << Z) --> X / Y
; (X << Z) / (Y << Z) --> X / Y
define i8 @sdiv_shl_shl_nsw2_nuw(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @sdiv_shl_shl_nsw2_nuw(
; CHECK-NEXT: [[XZ:%.*]] = shl nsw i8 [[X:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[YZ:%.*]] = shl nuw nsw i8 [[Y:%.*]], [[Z]]
; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[XZ]], [[YZ]]
; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i8 [[D]]
;
%xz = shl nsw i8 %x, %z
@ -757,12 +755,13 @@ define i8 @sdiv_shl_shl_nsw2_nuw(i8 %x, i8 %y, i8 %z) {
ret i8 %d
}
; extra uses are ok and 'exact' propagates
define i8 @sdiv_shl_shl_nsw2_nuw_exact_use(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @sdiv_shl_shl_nsw2_nuw_exact_use(
; CHECK-NEXT: [[XZ:%.*]] = shl nsw i8 [[X:%.*]], [[Z:%.*]]
; CHECK-NEXT: call void @use(i8 [[XZ]])
; CHECK-NEXT: [[YZ:%.*]] = shl nuw nsw i8 [[Y:%.*]], [[Z]]
; CHECK-NEXT: [[D:%.*]] = sdiv exact i8 [[XZ]], [[YZ]]
; CHECK-NEXT: [[D:%.*]] = sdiv exact i8 [[X]], [[Y:%.*]]
; CHECK-NEXT: ret i8 [[D]]
;
%xz = shl nsw i8 %x, %z
@ -772,6 +771,8 @@ define i8 @sdiv_shl_shl_nsw2_nuw_exact_use(i8 %x, i8 %y, i8 %z) {
ret i8 %d
}
; negative test - wrong wrap
define i8 @sdiv_shl_shl_nsw_nuw2(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @sdiv_shl_shl_nsw_nuw2(
; CHECK-NEXT: [[XZ:%.*]] = shl nuw i8 [[X:%.*]], [[Z:%.*]]
@ -785,6 +786,8 @@ define i8 @sdiv_shl_shl_nsw_nuw2(i8 %x, i8 %y, i8 %z) {
ret i8 %d
}
; negative test - wrong wrap
define i8 @sdiv_shl_shl_nsw_nuw(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @sdiv_shl_shl_nsw_nuw(
; CHECK-NEXT: [[XZ:%.*]] = shl nsw i8 [[X:%.*]], [[Z:%.*]]
@ -798,6 +801,8 @@ define i8 @sdiv_shl_shl_nsw_nuw(i8 %x, i8 %y, i8 %z) {
ret i8 %d
}
; negative test - wrong wrap
define i8 @sdiv_shl_shl_nuw_nsw2(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @sdiv_shl_shl_nuw_nsw2(
; CHECK-NEXT: [[XZ:%.*]] = shl nuw nsw i8 [[X:%.*]], [[Z:%.*]]