Skip to content

[SimplifyCFG] Mark div/rem as not-cheap to sink if we are replacing const denominator #109007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1954,6 +1954,9 @@ static bool isLifeTimeMarker(const Instruction *I) {
// into variables.
static bool replacingOperandWithVariableIsCheap(const Instruction *I,
int OpIdx) {
// Divide/Remainder by constant is typically much cheaper than by variable.
if (I->isIntDivRem())
return OpIdx != 1;
return !isa<IntrinsicInst>(I);
}

Expand Down
101 changes: 101 additions & 0 deletions llvm/test/Transforms/SimplifyCFG/sink-and-convert-switch.ll
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,104 @@ bb5:
call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %y)
ret void
}

define i64 @dont_make_div_variable(i64 noundef %x, i64 noundef %i) {
; CHECK-LABEL: define i64 @dont_make_div_variable(
; CHECK-SAME: i64 noundef [[X:%.*]], i64 noundef [[I:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: switch i64 [[I]], label %[[SW_DEFAULT:.*]] [
; CHECK-NEXT: i64 9, label %[[SW_BB:.*]]
; CHECK-NEXT: i64 10, label %[[SW_BB1:.*]]
; CHECK-NEXT: i64 11, label %[[SW_BB3:.*]]
; CHECK-NEXT: i64 12, label %[[SW_BB5:.*]]
; CHECK-NEXT: ]
; CHECK: [[SW_BB]]:
; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[X]], 9
; CHECK-NEXT: br label %[[RETURN:.*]]
; CHECK: [[SW_BB1]]:
; CHECK-NEXT: [[DIV2:%.*]] = udiv i64 [[X]], 10
; CHECK-NEXT: br label %[[RETURN]]
; CHECK: [[SW_BB3]]:
; CHECK-NEXT: [[DIV4:%.*]] = udiv i64 [[X]], 11
; CHECK-NEXT: br label %[[RETURN]]
; CHECK: [[SW_BB5]]:
; CHECK-NEXT: [[DIV7:%.*]] = udiv i64 [[X]], 12
; CHECK-NEXT: br label %[[RETURN]]
; CHECK: [[SW_DEFAULT]]:
; CHECK-NEXT: unreachable
; CHECK: [[RETURN]]:
; CHECK-NEXT: [[DIV6:%.*]] = phi i64 [ [[DIV7]], %[[SW_BB5]] ], [ [[DIV4]], %[[SW_BB3]] ], [ [[DIV2]], %[[SW_BB1]] ], [ [[DIV]], %[[SW_BB]] ]
; CHECK-NEXT: ret i64 [[DIV6]]
;
entry:
switch i64 %i, label %sw.default [
i64 9, label %sw.bb
i64 10, label %sw.bb1
i64 11, label %sw.bb3
i64 12, label %sw.bb5
]

sw.bb:
%div = udiv i64 %x, 9
br label %return

sw.bb1:
%div2 = udiv i64 %x, 10
br label %return

sw.bb3:
%div4 = udiv i64 %x, 11
br label %return

sw.bb5:
%div6 = udiv i64 %x, 12
br label %return

sw.default:
unreachable

return:
%retval.0 = phi i64 [ %div6, %sw.bb5 ], [ %div4, %sw.bb3 ], [ %div2, %sw.bb1 ], [ %div, %sw.bb ]
ret i64 %retval.0
}

define i64 @okay_to_make_div_variable(i64 noundef %x, i64 noundef %i) {
; CHECK-LABEL: define i64 @okay_to_make_div_variable(
; CHECK-SAME: i64 noundef [[X:%.*]], i64 noundef [[I:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub nsw i64 [[I]], 9
; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add nsw i64 [[SWITCH_TABLEIDX]], 9
; CHECK-NEXT: [[DIV6:%.*]] = udiv i64 [[SWITCH_OFFSET]], [[X]]
; CHECK-NEXT: ret i64 [[DIV6]]
;
entry:
switch i64 %i, label %sw.default [
i64 9, label %sw.bb
i64 10, label %sw.bb1
i64 11, label %sw.bb3
i64 12, label %sw.bb5
]

sw.bb:
%div = udiv i64 9, %x
br label %return

sw.bb1:
%div2 = udiv i64 10, %x
br label %return

sw.bb3:
%div4 = udiv i64 11, %x
br label %return

sw.bb5:
%div6 = udiv i64 12, %x
br label %return

sw.default:
unreachable

return:
%retval.0 = phi i64 [ %div6, %sw.bb5 ], [ %div4, %sw.bb3 ], [ %div2, %sw.bb1 ], [ %div, %sw.bb ]
ret i64 %retval.0
}
Loading