Skip to content

Commit a413a52

Browse files
committed
llvm-reduce: Change function return types if function is not called
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.
1 parent 449b087 commit a413a52

File tree

2 files changed

+99
-3
lines changed

2 files changed

+99
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
; Test that llvm-reduce can move intermediate values by inserting
2+
; early returns when the function already has a different return type
3+
;
4+
; 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
5+
; RUN: FileCheck --check-prefix=RESULT %s < %t
6+
7+
8+
@gv = global i32 0, align 4
9+
@ptr_array = global [2 x ptr] [ptr @inst_to_return_has_different_type_but_no_func_call_use,
10+
ptr @multiple_callsites_wrong_return_type]
11+
12+
; Should rewrite this return from i64 to i32 since the function has no
13+
; uses.
14+
; INTERESTING-LABEL: @inst_to_return_has_different_type_but_no_func_call_use(
15+
; RESULT-LABEL: define i32 @inst_to_return_has_different_type_but_no_func_call_use(ptr %arg) {
16+
; RESULT-NEXT: %load = load i32, ptr %arg, align 4
17+
; RESULT-NEXT: ret i32 %load
18+
define i64 @inst_to_return_has_different_type_but_no_func_call_use(ptr %arg) {
19+
%load = load i32, ptr %arg
20+
store i32 %load, ptr @gv
21+
ret i64 0
22+
}
23+
24+
; INTERESTING-LABEL: @callsite_different_type_unused_0(
25+
; RESULT-LABEL: define i64 @inst_to_return_has_different_type_but_call_result_unused(
26+
; RESULT-NEXT: %load = load i32, ptr %arg
27+
; RESULT-NEXT: store i32 %load, ptr @gv
28+
; RESULT-NEXT: ret i64 0
29+
define void @callsite_different_type_unused_0(ptr %arg) {
30+
%unused0 = call i64 @inst_to_return_has_different_type_but_call_result_unused(ptr %arg)
31+
%unused1 = call i64 @inst_to_return_has_different_type_but_call_result_unused(ptr null)
32+
ret void
33+
}
34+
35+
; TODO: Could rewrite this return from i64 to i32 since the callsite is unused.
36+
; INTERESTING-LABEL: @inst_to_return_has_different_type_but_call_result_unused(
37+
; RESULT-LABEL: define i64 @inst_to_return_has_different_type_but_call_result_unused(
38+
; RESULT: ret i64 0
39+
define i64 @inst_to_return_has_different_type_but_call_result_unused(ptr %arg) {
40+
%load = load i32, ptr %arg
41+
store i32 %load, ptr @gv
42+
ret i64 0
43+
}
44+
45+
; INTERESTING-LABEL: @multiple_callsites_wrong_return_type(
46+
; RESULT-LABEL: define i64 @multiple_callsites_wrong_return_type(
47+
; RESULT: ret i64 0
48+
define i64 @multiple_callsites_wrong_return_type(ptr %arg) {
49+
%load = load i32, ptr %arg
50+
store i32 %load, ptr @gv
51+
ret i64 0
52+
}
53+
54+
; INTERESTING-LABEL: @unused_with_wrong_return_types(
55+
; RESULT-LABEL: define i64 @unused_with_wrong_return_types(
56+
; RESULT-NEXT: %unused0 = call i64 @multiple_callsites_wrong_return_type(ptr %arg)
57+
; RESULT-NEXT: ret i64 %unused0
58+
define void @unused_with_wrong_return_types(ptr %arg) {
59+
%unused0 = call i64 @multiple_callsites_wrong_return_type(ptr %arg)
60+
%unused1 = call i32 @multiple_callsites_wrong_return_type(ptr %arg)
61+
%unused2 = call ptr @multiple_callsites_wrong_return_type(ptr %arg)
62+
ret void
63+
}
64+
65+
; INTERESTING-LABEL: @multiple_returns_wrong_return_type(
66+
; INTERESTING: %load0 = load i32,
67+
68+
; RESULT-LABEL: define i32 @multiple_returns_wrong_return_type(
69+
; RESULT: ret i32
70+
; RESULT: ret i32
71+
; RESULT: ret i32
72+
define i32 @multiple_returns_wrong_return_type(ptr %arg, i1 %cond, i32 %arg2) {
73+
entry:
74+
br i1 %cond, label %bb0, label %bb1
75+
76+
bb0:
77+
%load0 = load i32, ptr %arg
78+
store i32 %load0, ptr @gv
79+
ret i32 234
80+
81+
bb1:
82+
ret i32 %arg2
83+
84+
bb2:
85+
ret i32 34
86+
}
87+
88+
; INTERESTING-LABEL: @call_multiple_returns_wrong_return_type(
89+
; RESULT-LABEL: define <2 x i32> @call_multiple_returns_wrong_return_type(
90+
; RESULT-NEXT: %unused = call <2 x i32> @multiple_returns_wrong_return_type(
91+
; RESULT-NEXT: ret <2 x i32> %unused
92+
define void @call_multiple_returns_wrong_return_type(ptr %arg, i1 %cond, i32 %arg2) {
93+
%unused = call <2 x i32> @multiple_returns_wrong_return_type(ptr %arg, i1 %cond, i32 %arg2)
94+
ret void
95+
}

llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,9 @@ static bool canReplaceFuncUsers(const Function &F, Type *NewRetTy) {
164164
if (CB->getType() == NewRetTy)
165165
continue;
166166

167-
LLVM_DEBUG(dbgs() << "Cannot replace callsite with wrong type: " << *CB
167+
// TODO: If all callsites have no uses, we could mutate the type of all the
168+
// callsites. This will complicate the visit and rewrite ordering though.
169+
LLVM_DEBUG(dbgs() << "Cannot replace used callsite with wrong type: " << *CB
168170
<< '\n');
169171
return false;
170172
}
@@ -200,8 +202,7 @@ static bool shouldForwardValueToReturn(const BasicBlock &BB, const Value *V,
200202
if (!isReallyValidReturnType(V->getType()))
201203
return false;
202204

203-
return (RetTy->isVoidTy() ||
204-
(RetTy == V->getType() && shouldReplaceNonVoidReturnValue(BB, V))) &&
205+
return (RetTy->isVoidTy() || shouldReplaceNonVoidReturnValue(BB, V)) &&
205206
canReplaceFuncUsers(*BB.getParent(), V->getType());
206207
}
207208

0 commit comments

Comments
 (0)