OLD | NEW |
---|---|
(Empty) | |
1 ; RUN: opt %s -simplify-struct-reg-signatures -S | FileCheck %s | |
2 | |
3 declare i32 @__gxx_personality_v0(...) | |
4 | |
5 %struct = type { i32, i32 } | |
6 %rec_struct = type {%rec_struct*} | |
7 %rec_problem_struct = type{void (%rec_problem_struct)*} | |
8 %rec_pair_1 = type {%rec_pair_2*} | |
9 %rec_pair_2 = type {%rec_pair_1*} | |
10 %rec_returning = type { %rec_returning (%rec_returning)* } | |
11 %direct_def = type { void(%struct)*, %struct } | |
12 | |
13 ; new type declarations: | |
14 ; CHECK: %struct = type { i32, i32 } | |
15 ; CHECK-NEXT: %rec_struct = type { %rec_struct* } | |
16 ; CHECK-NEXT: %rec_problem_struct.simplified = type { void (%rec_problem_struct. simplified*)* } | |
17 ; CHECK-NEXT: %rec_pair_1 = type { %rec_pair_2* } | |
18 ; CHECK-NEXT: %rec_pair_2 = type { %rec_pair_1* } | |
19 ; CHECK-NEXT: %rec_returning.simplified = type { void (%rec_returning.simplified *, %rec_returning.simplified*)* } | |
20 ; CHECK-NEXT: %direct_def.simplified = type { void (%struct*)*, %struct } | |
21 | |
22 ; externs | |
23 declare void @extern_func(%struct) | |
24 declare %struct @struct_returning_extern(i32, %struct) | |
25 | |
26 ; verify that parameters are mapped correctly: single param, two, and combo | |
27 ; with non-struct regs | |
28 ; CHECK-NOT: declare void @extern_func(%struct) | |
29 ; CHECK-NOT: declare %struct @struct_returning_extern(i32, %struct) | |
30 ; CHECK-LABEL: declare void @extern_func(%struct* byval) | |
31 ; CHECK-LABEL: declare void @struct_returning_extern(%struct* sret, i32, %struct * byval) | |
32 | |
33 define void @main(%struct* byval %ptr) { | |
34 %val = load %struct* %ptr | |
35 call void @extern_func(%struct %val) | |
36 ret void | |
37 } | |
38 | |
39 define void @two_param_func(%struct %val1, %struct %val2) { | |
40 call void @extern_func(%struct %val1) | |
41 call void @extern_func(%struct %val2) | |
42 ret void | |
43 } | |
44 | |
45 ; CHECK-LABEL: define void @two_param_func(%struct* byval %val1.ptr, %struct* by val %val2.ptr) | |
46 ; CHECK-NOT: define void @two_param_func(%struct %val1, %struct %val2) | |
47 | |
48 define i32 @another_func(i32 %a, %struct %str, i64 %b) { | |
49 call void @two_param_func(%struct %str, %struct %str) | |
50 call void @extern_func(%struct %str) | |
51 ret i32 0 | |
52 } | |
53 | |
54 ; CHECK-LABEL: define i32 @another_func(i32 %a, %struct* byval %str.ptr, i64 %b) | |
55 ; CHECK: call void @two_param_func(%struct* byval %str.sreg.ptr, %struct* byval %str.sreg.ptr1) | |
56 | |
57 define %struct @returns_struct(i32 %an_int, %struct %val) { | |
58 %tmp = call %struct @struct_returning_extern(i32 %an_int, %struct %val) | |
59 %tmp2 = invoke %struct @struct_returning_extern(i32 1, %struct %tmp) to label %Cont unwind label %Cleanup | |
JF
2015/03/19 16:21:25
Put the "to label ..." on the next line, it'll be
Mircea Trofin
2015/03/19 22:30:49
Done.
| |
60 | |
61 Cont: | |
62 ret %struct %tmp2 | |
63 Cleanup: | |
64 %exn = landingpad {i8*, i32} personality i32 (...)* @__gxx_personality_v0 | |
65 cleanup | |
66 ret %struct %tmp | |
67 } | |
68 | |
69 ; verify return value and codegen | |
70 ; CHECK-LABEL: define void @returns_struct(%struct* sret %retVal, i32 %an_int, % struct* byval %val.ptr) | |
71 ; CHECK-NEXT: %val.sreg = load %struct* %val.ptr | |
72 ; CHECK-NEXT: %tmp = alloca %struct | |
73 ; CHECK-NEXT: %val.sreg.ptr = alloca %struct | |
74 ; CHECK-NEXT: store %struct %val.sreg, %struct* %val.sreg.ptr | |
75 ; CHECK-NEXT: call void @struct_returning_extern(%struct* sret %tmp, i32 %an_in t, %struct* byval %val.sreg.ptr) | |
76 ; CHECK-NEXT: %tmp.sreg = load %struct* %tmp | |
77 ; CHECK-NEXT: %tmp2 = alloca %struct | |
78 ; CHECK-NEXT: %tmp.sreg.ptr = alloca %struct | |
79 ; CHECK-NEXT: store %struct %tmp.sreg, %struct* %tmp.sreg.ptr | |
80 ; CHECK-NEXT: invoke void @struct_returning_extern(%struct* sret %tmp2, i32 1, %struct* byval %tmp.sreg.ptr) | |
81 ; CHECK-NEXT: to label %Cont unwind label %Cleanup | |
82 ; CHECK-DAG: Cont: | |
83 ; CHECK-NEXT: %tmp2.sreg = load %struct* %tmp2 | |
84 ; CHECK-NEXT: store %struct %tmp2.sreg, %struct* %retVal | |
85 ; CHECK-NEXT: ret void | |
86 ; CHECK-DAG: Cleanup: | |
87 ; CHECK-NEXT: %exn = landingpad { i8*, i32 } personality i32 (...)* @__gxx_pe rsonality_v0 | |
JF
2015/03/19 16:21:25
Could you also add a separate test for resume with
Mircea Trofin
2015/03/19 22:30:49
We decided not to support that scenario, explicitl
| |
88 ; CHECK-NEXT: cleanup | |
89 ; CHECK-NEXT: store %struct %tmp.sreg, %struct* %retVal | |
90 ; CHECK-NEXT: ret void | |
91 | |
92 | |
93 define i32 @lots_of_call_attrs() { | |
94 %tmp.0 = insertvalue %struct undef, i32 1, 0 | |
95 %tmp.1 = insertvalue %struct %tmp.0, i32 2, 1 | |
96 %ret = tail call zeroext i32 @another_func(i32 1, %struct %tmp.1, i64 2) reado nly | |
97 ret i32 %ret | |
98 } | |
99 | |
100 ; verify attributes are copied | |
101 ; CHECK_LABEL: @lots_of_call_attrs | |
102 ; CHECK: %ret = tail call zeroext i32 @another_func(i32 1, %struct* byval %tmp.1 .ptr, i64 2) #0 | |
103 ; CHECK-NEXT: ret i32 %ret | |
104 | |
105 declare void @rec_struct_ok(%rec_struct*) | |
106 declare void @rec_struct_mod(%rec_struct) | |
107 | |
108 ; compliant recursive structs are kept as-is | |
109 ; CHECK-LABEL: declare void @rec_struct_ok(%rec_struct*) | |
110 ; CHECK-LABEL: declare void @rec_struct_mod(%rec_struct* byval) | |
111 | |
112 define void @rec_call_sreg(%rec_problem_struct %r) { | |
113 %tmp = extractvalue %rec_problem_struct %r, 0 | |
114 call void %tmp(%rec_problem_struct %r) | |
115 ret void | |
116 } | |
117 | |
118 ; non-compliant structs are correctly mapped and calls are changed | |
119 ; CHECK-LABEL: define void @rec_call_sreg(%rec_problem_struct.simplified* byval %r.ptr) | |
120 ; CHECK: call void %tmp(%rec_problem_struct.simplified* byval %r.sreg.ptr) | |
121 | |
122 declare void @pairs(%rec_pair_1) | |
123 | |
124 define %rec_returning @rec_returning_fun(%rec_returning %str) { | |
125 %tmp = extractvalue %rec_returning %str, 0 | |
126 %ret = call %rec_returning %tmp(%rec_returning %str) | |
127 ret %rec_returning %ret | |
128 } | |
129 | |
130 ; pair structs | |
131 ; CHECK-LABEL: declare void @pairs(%rec_pair_1* byval) | |
132 ; CHECK-LABEL: define void @rec_returning_fun(%rec_returning.simplified* sret %r etVal, %rec_returning.simplified* byval %str.ptr) | |
133 ; CHECK-NEXT: %str.sreg = load %rec_returning.simplified* %str.ptr | |
134 ; CHECK-NEXT: %tmp = extractvalue %rec_returning.simplified %str.sreg, 0 | |
135 ; CHECK-NEXT: %ret = alloca %rec_returning.simplified | |
136 ; CHECK-NEXT: %str.sreg.ptr = alloca %rec_returning.simplified | |
137 ; CHECK-NEXT: store %rec_returning.simplified %str.sreg, %rec_returning.simpli fied* %str.sreg.ptr | |
138 ; CHECK-NEXT: call void %tmp(%rec_returning.simplified* sret %ret, %rec_return ing.simplified* byval %str.sreg.ptr) | |
139 ; CHECK-NEXT: %ret.sreg = load %rec_returning.simplified* %ret | |
140 ; CHECK-NEXT: store %rec_returning.simplified %ret.sreg, %rec_returning.simpli fied* %retVal | |
141 ; CHECK-NEXT: ret void | |
142 | |
143 define void @direct_caller(%direct_def %def) { | |
144 %func = extractvalue %direct_def %def, 0 | |
145 %param = extractvalue %direct_def %def, 1 | |
146 call void %func(%struct %param) | |
147 ret void | |
148 } | |
149 | |
150 ; CHECK-LABEL: define void @direct_caller(%direct_def.simplified* byval %def.ptr ) | |
151 ; CHECK-NEXT: %def.sreg = load %direct_def.simplified* %def.ptr | |
152 ; CHECK-NEXT: %func = extractvalue %direct_def.simplified %def.sreg, 0 | |
153 ; CHECK-NEXT: %param = extractvalue %direct_def.simplified %def.sreg, 1 | |
154 ; CHECK-NEXT: %param.ptr = alloca %struct | |
155 ; CHECK-NEXT: store %struct %param, %struct* %param.ptr | |
156 ; CHECK-NEXT: call void %func(%struct* byval %param.ptr) | |
157 ; CHECK-NEXT: ret void | |
158 | |
159 ; vararg functions are converted correctly | |
160 declare void @vararg_ok(i32, ...) | |
161 ; CHECK-LABEL: declare void @vararg_ok(i32, ...) | |
162 | |
163 define void @vararg_problem(%rec_problem_struct %arg1, ...) { | |
164 ; CHECK-LABEL: define void @vararg_problem(%rec_problem_struct.simplified* byv al %arg1.ptr, ...) | |
165 ret void | |
166 } | |
167 | |
168 %vararg_fp_struct = type { i32, void (i32, ...)* } | |
169 declare void @vararg_fp_fct(%vararg_fp_struct %arg) | |
170 ;CHECK-LABEL declare void @vararg_fp_fct(%vararg_fp_struct.simplified* byval %ar g) | |
JF
2015/03/19 16:21:25
Here and below you're missing the colons for `CHEC
Mircea Trofin
2015/03/19 22:30:49
Done.
| |
171 | |
172 define void @call_vararg(%vararg_fp_struct %param1, ...) { | |
173 %fptr = extractvalue %vararg_fp_struct %param1, 1 | |
174 call void (i32, ...)* %fptr(i32 0, i32 1) | |
175 ret void | |
176 } | |
177 | |
178 ; CHECK-LABEL define void @call_vararg(%vararg_fp_struct* byval %param1.ptr, ... ) | |
179 ; CHECK-NEXT %param1.sreg = load %vararg_fp_struct* %param1.ptr | |
180 ; CHECK-NEXT %fptr = extractvalue %vararg_fp_struct %param1.sreg, 1 | |
181 ; CHECK-NEXTcall void (i32, ...)* %fptr(i32 0) | |
JF
2015/03/19 16:21:25
The second param disappeared?
Mircea Trofin
2015/03/19 22:30:49
Yes, and fixed the bug. Thanks!
| |
182 ; CHECK-NEXT ret void | |
183 | |
184 %vararg_fp_problem_struct = type { void(%vararg_fp_problem_struct)* } | |
185 define void @vararg_fp_problem_call(%vararg_fp_problem_struct* byval %param) { | |
186 %fct_ptr = getelementptr %vararg_fp_problem_struct* %param, i32 0, i32 0 | |
187 %fct = load void(%vararg_fp_problem_struct)** %fct_ptr | |
188 %param_for_call = load %vararg_fp_problem_struct* %param | |
189 call void %fct(%vararg_fp_problem_struct %param_for_call) | |
190 ret void | |
191 } | |
192 | |
193 ; CHECK-LABEL define void @vararg_fp_problem_call(%vararg_fp_problem_struct.simp lified* byval %param) | |
194 ; CHECK-NEXT %fct_ptr = getelementptr %vararg_fp_problem_struct.simplified* %pa ram, i32 0, i32 0 | |
195 ; CHECK-NEXT %fct = load void (%vararg_fp_problem_struct.simplified*)** %fct_pt r | |
196 ; CHECK-NEXT %param_for_call = load %vararg_fp_problem_struct.simplified* %para m | |
197 ; CHECK-NEXT %param_for_call.ptr = alloca %vararg_fp_problem_struct.simplified | |
198 ; CHECK-NEXT store %vararg_fp_problem_struct.simplified %param_for_call, %varar g_fp_problem_struct.simplified* %param_for_call.ptr | |
199 ; CHECK-NEXT call void %fct(%vararg_fp_problem_struct.simplified* byval %param_ for_call.ptr) | |
200 ; CHECK-NEXT ret void | |
201 | |
202 define void @call_with_array([4 x void(%struct)*] %fptrs, %struct %str) { | |
203 %fptr = extractvalue [4 x void(%struct)*] %fptrs, 2 | |
204 call void %fptr(%struct %str) | |
205 ret void | |
206 } | |
207 | |
208 ; CHECK-LABEL: define void @call_with_array([4 x void (%struct*)*]* byval %fptrs .ptr, %struct* byval %str.ptr) | |
209 ; CHECK-NEXT: %fptrs.sreg = load [4 x void (%struct*)*]* %fptrs.ptr | |
210 ; CHECK-NEXT: %str.sreg = load %struct* %str.ptr | |
211 ; CHECK-NEXT: %fptr = extractvalue [4 x void (%struct*)*] %fptrs.sreg, 2 | |
212 ; CHECK-NEXT: %str.sreg.ptr = alloca %struct | |
213 ; CHECK-NEXT: store %struct %str.sreg, %struct* %str.sreg.ptr | |
214 ; CHECK-NEXT: call void %fptr(%struct* byval %str.sreg.ptr) | |
215 ; CHECK-NEXT: ret void | |
216 | |
217 define void @call_with_array_ptr([4 x void(%struct)*]* %fptrs, %struct %str) { | |
218 %fptr_ptr = getelementptr [4 x void(%struct)*]* %fptrs, i32 0, i32 2 | |
219 %fptr = load void(%struct)** %fptr_ptr | |
220 call void %fptr(%struct %str) | |
221 ret void | |
222 } | |
223 | |
224 ; CHECK-LABEL: define void @call_with_array_ptr([4 x void (%struct*)*]* %fptrs, %struct* byval %str.ptr) | |
225 ; CHECK-NEXT: %str.sreg = load %struct* %str.ptr | |
226 ; CHECK-NEXT: %fptr_ptr = getelementptr [4 x void (%struct*)*]* %fptrs, i32 0, i32 2 | |
227 ; CHECK-NEXT: %fptr = load void (%struct*)** %fptr_ptr | |
228 ; CHECK-NEXT: %str.sreg.ptr = alloca %struct | |
229 ; CHECK-NEXT: store %struct %str.sreg, %struct* %str.sreg.ptr | |
230 ; CHECK-NEXT: call void %fptr(%struct* byval %str.sreg.ptr) | |
231 ; CHECK-NEXT: ret void | |
232 | |
233 define void @call_with_vector(<4 x void (%struct)*> %fptrs, %struct %str) { | |
234 %fptr = extractelement <4 x void (%struct)*> %fptrs, i32 2 | |
235 call void %fptr(%struct %str) | |
236 ret void | |
237 } | |
238 | |
239 ; CHECK-LABEL: define void @call_with_vector(<4 x void (%struct*)*> %fptrs, %str uct* byval %str.ptr) | |
240 ; CHECK-NEXT: %str.sreg = load %struct* %str.ptr | |
241 ; CHECK-NEXT: %fptr = extractelement <4 x void (%struct*)*> %fptrs, i32 2 | |
242 ; CHECK-NEXT: %str.sreg.ptr = alloca %struct | |
243 ; CHECK-NEXT: store %struct %str.sreg, %struct* %str.sreg.ptr | |
244 ; CHECK-NEXT: call void %fptr(%struct* byval %str.sreg.ptr) | |
245 ; CHECK-NEXT: ret void | |
246 | |
247 define void @call_with_array_vect([4 x <2 x void(%struct)*>] %fptrs, %struct %st r) { | |
248 %vect = extractvalue [4 x <2 x void(%struct)*>] %fptrs, 2 | |
249 %fptr = extractelement <2 x void (%struct)*> %vect, i32 1 | |
250 call void %fptr(%struct %str) | |
251 ret void | |
252 } | |
253 | |
254 ; CHECK-LABEL: define void @call_with_array_vect([4 x <2 x void (%struct*)*>]* b yval %fptrs.ptr, %struct* byval %str.ptr) | |
255 ; CHECK-NEXT: %fptrs.sreg = load [4 x <2 x void (%struct*)*>]* %fptrs.ptr | |
256 ; CHECK-NEXT: %str.sreg = load %struct* %str.ptr | |
257 ; CHECK-NEXT: %vect = extractvalue [4 x <2 x void (%struct*)*>] %fptrs.sreg, 2 | |
258 ; CHECK-NEXT: %fptr = extractelement <2 x void (%struct*)*> %vect, i32 1 | |
259 ; CHECK-NEXT: %str.sreg.ptr = alloca %struct | |
260 ; CHECK-NEXT: store %struct %str.sreg, %struct* %str.sreg.ptr | |
261 ; CHECK-NEXT: call void %fptr(%struct* byval %str.sreg.ptr) | |
262 ; CHECK-NEXT: ret void | |
263 | |
264 ; this is at the end, corresponds to the call marked as readonly | |
265 ; CHECK: attributes #0 = { readonly } | |
OLD | NEW |