-
Notifications
You must be signed in to change notification settings - Fork 13.3k
llvm-reduce: Change function return types if function is not called #134035
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
base: users/arsenm/llvm-reduce/add-reduce-values-to-return-argument-case
Are you sure you want to change the base?
Conversation
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
@llvm/pr-subscribers-llvm-ir Author: Matt Arsenault (arsenm) ChangesExtend the early return on value reduction to mutate the function return This is enough to cleanup the common case where we end up with one Full diff: https://github.com/llvm/llvm-project/pull/134035.diff 2 Files Affected:
diff --git a/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll b/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll
new file mode 100644
index 0000000000000..9ddbbe3def44f
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/reduce-values-to-return-new-return-type.ll
@@ -0,0 +1,95 @@
+; Test that llvm-reduce can move intermediate values by inserting
+; early returns when the function already has a different return type
+;
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=instructions-to-return --test FileCheck --test-arg --check-prefix=INTERESTING --test-arg %s --test-arg --input-file %s -o %t
+; RUN: FileCheck --check-prefix=RESULT %s < %t
+
+
+@gv = global i32 0, align 4
+@ptr_array = global [2 x ptr] [ptr @inst_to_return_has_different_type_but_no_func_call_use,
+ ptr @multiple_callsites_wrong_return_type]
+
+; Should rewrite this return from i64 to i32 since the function has no
+; uses.
+; INTERESTING-LABEL: @inst_to_return_has_different_type_but_no_func_call_use(
+; RESULT-LABEL: define i32 @inst_to_return_has_different_type_but_no_func_call_use(ptr %arg) {
+; RESULT-NEXT: %load = load i32, ptr %arg, align 4
+; RESULT-NEXT: ret i32 %load
+define i64 @inst_to_return_has_different_type_but_no_func_call_use(ptr %arg) {
+ %load = load i32, ptr %arg
+ store i32 %load, ptr @gv
+ ret i64 0
+}
+
+; INTERESTING-LABEL: @callsite_different_type_unused_0(
+; RESULT-LABEL: define i64 @inst_to_return_has_different_type_but_call_result_unused(
+; RESULT-NEXT: %load = load i32, ptr %arg
+; RESULT-NEXT: store i32 %load, ptr @gv
+; RESULT-NEXT: ret i64 0
+define void @callsite_different_type_unused_0(ptr %arg) {
+ %unused0 = call i64 @inst_to_return_has_different_type_but_call_result_unused(ptr %arg)
+ %unused1 = call i64 @inst_to_return_has_different_type_but_call_result_unused(ptr null)
+ ret void
+}
+
+; TODO: Could rewrite this return from i64 to i32 since the callsite is unused.
+; INTERESTING-LABEL: @inst_to_return_has_different_type_but_call_result_unused(
+; RESULT-LABEL: define i64 @inst_to_return_has_different_type_but_call_result_unused(
+; RESULT: ret i64 0
+define i64 @inst_to_return_has_different_type_but_call_result_unused(ptr %arg) {
+ %load = load i32, ptr %arg
+ store i32 %load, ptr @gv
+ ret i64 0
+}
+
+; INTERESTING-LABEL: @multiple_callsites_wrong_return_type(
+; RESULT-LABEL: define i64 @multiple_callsites_wrong_return_type(
+; RESULT: ret i64 0
+define i64 @multiple_callsites_wrong_return_type(ptr %arg) {
+ %load = load i32, ptr %arg
+ store i32 %load, ptr @gv
+ ret i64 0
+}
+
+; INTERESTING-LABEL: @unused_with_wrong_return_types(
+; RESULT-LABEL: define i64 @unused_with_wrong_return_types(
+; RESULT-NEXT: %unused0 = call i64 @multiple_callsites_wrong_return_type(ptr %arg)
+; RESULT-NEXT: ret i64 %unused0
+define void @unused_with_wrong_return_types(ptr %arg) {
+ %unused0 = call i64 @multiple_callsites_wrong_return_type(ptr %arg)
+ %unused1 = call i32 @multiple_callsites_wrong_return_type(ptr %arg)
+ %unused2 = call ptr @multiple_callsites_wrong_return_type(ptr %arg)
+ ret void
+}
+
+; INTERESTING-LABEL: @multiple_returns_wrong_return_type(
+; INTERESTING: %load0 = load i32,
+
+; RESULT-LABEL: define i32 @multiple_returns_wrong_return_type(
+; RESULT: ret i32
+; RESULT: ret i32
+; RESULT: ret i32
+define i32 @multiple_returns_wrong_return_type(ptr %arg, i1 %cond, i32 %arg2) {
+entry:
+ br i1 %cond, label %bb0, label %bb1
+
+bb0:
+ %load0 = load i32, ptr %arg
+ store i32 %load0, ptr @gv
+ ret i32 234
+
+bb1:
+ ret i32 %arg2
+
+bb2:
+ ret i32 34
+}
+
+; INTERESTING-LABEL: @call_multiple_returns_wrong_return_type(
+; RESULT-LABEL: define <2 x i32> @call_multiple_returns_wrong_return_type(
+; RESULT-NEXT: %unused = call <2 x i32> @multiple_returns_wrong_return_type(
+; RESULT-NEXT: ret <2 x i32> %unused
+define void @call_multiple_returns_wrong_return_type(ptr %arg, i1 %cond, i32 %arg2) {
+ %unused = call <2 x i32> @multiple_returns_wrong_return_type(ptr %arg, i1 %cond, i32 %arg2)
+ ret void
+}
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
index 3e400ffc89482..0a02298acc73e 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
@@ -164,7 +164,9 @@ static bool canReplaceFuncUsers(const Function &F, Type *NewRetTy) {
if (CB->getType() == NewRetTy)
continue;
- LLVM_DEBUG(dbgs() << "Cannot replace callsite with wrong type: " << *CB
+ // TODO: If all callsites have no uses, we could mutate the type of all the
+ // callsites. This will complicate the visit and rewrite ordering though.
+ LLVM_DEBUG(dbgs() << "Cannot replace used callsite with wrong type: " << *CB
<< '\n');
return false;
}
@@ -200,8 +202,7 @@ static bool shouldForwardValueToReturn(const BasicBlock &BB, const Value *V,
if (!isReallyValidReturnType(V->getType()))
return false;
- return (RetTy->isVoidTy() ||
- (RetTy == V->getType() && shouldReplaceNonVoidReturnValue(BB, V))) &&
+ return (RetTy->isVoidTy() || shouldReplaceNonVoidReturnValue(BB, V)) &&
canReplaceFuncUsers(*BB.getParent(), V->getType());
}
|
Forgot the part to fix the multiple return case |
a413a52
to
4baf45b
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
449b087
to
3e646d9
Compare
4baf45b
to
5490073
Compare
LGTM! |
5490073
to
f86430f
Compare
3e646d9
to
57ba2fd
Compare
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, thanks
@@ -55,8 +57,10 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) { | |||
BasicBlock::iterator NewValIt = | |||
NewRetI ? NewRetI->getIterator() : EntryBB.end(); | |||
|
|||
Type *OldRetTy = OldFuncTy->getReturnType(); | |||
|
|||
// Hack up any return values in other blocks, we can't leave them as ret void. |
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.
Comment needs updating?
// Hack up any return values in other blocks, we can't leave them as ret void. | |
// Hack up any return values in other blocks, we can't leave them as returning OldRetTy. |
f86430f
to
59926c0
Compare
57ba2fd
to
51fde94
Compare
Extend the early return on value reduction to mutate the function return type if the function has no call uses. This could be generalized to rewrite cases where all callsites are used, but it turns out that complicates the visitation order given we try to compute all opportunities up front. This is enough to cleanup the common case where we end up with one function with a return of an uninteresting constant.
59926c0
to
254c039
Compare
51fde94
to
19664d8
Compare
Extend the early return on value reduction to mutate the function return
type if the function has no call uses. This could be generalized to rewrite
cases where all callsites are used, but it turns out that complicates the
visitation order given we try to compute all opportunities up front.
This is enough to cleanup the common case where we end up with one
function with a return of an uninteresting constant.