-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[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
[SimplifyCFG] Mark div/rem as not-cheap to sink if we are replacing const denominator #109007
Conversation
@llvm/pr-subscribers-llvm-transforms Author: None (goldsteinn) Changes
Full diff: https://github.com/llvm/llvm-project/pull/109007.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 5a694b5e7f204b..5e08d4d3ffe7f8 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -1954,6 +1954,16 @@ static bool isLifeTimeMarker(const Instruction *I) {
// into variables.
static bool replacingOperandWithVariableIsCheap(const Instruction *I,
int OpIdx) {
+ switch (I->getOpcode()) {
+ // Divide/Remainder by constant is typically much cheaper than by variable.
+ case Instruction::UDiv:
+ case Instruction::SDiv:
+ case Instruction::URem:
+ case Instruction::SRem:
+ return OpIdx != 1;
+ default:
+ break;
+ }
return !isa<IntrinsicInst>(I);
}
diff --git a/llvm/test/Transforms/SimplifyCFG/sink-and-convert-switch.ll b/llvm/test/Transforms/SimplifyCFG/sink-and-convert-switch.ll
index 4c93837f1422a9..87d64932ef0935 100644
--- a/llvm/test/Transforms/SimplifyCFG/sink-and-convert-switch.ll
+++ b/llvm/test/Transforms/SimplifyCFG/sink-and-convert-switch.ll
@@ -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
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@@ -1954,6 +1954,16 @@ static bool isLifeTimeMarker(const Instruction *I) { | |||
// into variables. | |||
static bool replacingOperandWithVariableIsCheap(const Instruction *I, | |||
int OpIdx) { | |||
switch (I->getOpcode()) { | |||
// Divide/Remainder by constant is typically much cheaper than by variable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use I->isIntDivRem()
here.
…onst denominator Close llvm#109007
…onst denominator Close llvm#109007
Divide by a constant (usually done by multiply) is MUCH cheaper than divide by a variable.