]>
Commit | Line | Data |
---|---|---|
e440a328 | 1 | // gogo-tree.cc -- convert Go frontend Gogo IR to gcc trees. |
2 | ||
3 | // Copyright 2009 The Go Authors. All rights reserved. | |
4 | // Use of this source code is governed by a BSD-style | |
5 | // license that can be found in the LICENSE file. | |
6 | ||
7 | #include "go-system.h" | |
8 | ||
e440a328 | 9 | #include "toplev.h" |
10 | #include "tree.h" | |
9ed99284 | 11 | #include "stringpool.h" |
12 | #include "stor-layout.h" | |
13 | #include "varasm.h" | |
e440a328 | 14 | #include "gimple.h" |
af2db0a9 | 15 | #include "gimplify.h" |
e440a328 | 16 | #include "tree-iterator.h" |
17 | #include "cgraph.h" | |
18 | #include "langhooks.h" | |
19 | #include "convert.h" | |
20 | #include "output.h" | |
21 | #include "diagnostic.h" | |
e440a328 | 22 | #include "go-c.h" |
d5ad4d4c | 23 | |
e440a328 | 24 | #include "types.h" |
25 | #include "expressions.h" | |
26 | #include "statements.h" | |
ca51434e | 27 | #include "runtime.h" |
fe2f84cf | 28 | #include "backend.h" |
e440a328 | 29 | #include "gogo.h" |
30 | ||
31 | // Whether we have seen any errors. | |
32 | ||
33 | bool | |
34 | saw_errors() | |
35 | { | |
36 | return errorcount != 0 || sorrycount != 0; | |
37 | } | |
38 | ||
39 | // A helper function. | |
40 | ||
41 | static inline tree | |
42 | get_identifier_from_string(const std::string& str) | |
43 | { | |
44 | return get_identifier_with_length(str.data(), str.length()); | |
45 | } | |
46 | ||
47 | // Builtin functions. | |
48 | ||
49 | static std::map<std::string, tree> builtin_functions; | |
50 | ||
51 | // Define a builtin function. BCODE is the builtin function code | |
52 | // defined by builtins.def. NAME is the name of the builtin function. | |
53 | // LIBNAME is the name of the corresponding library function, and is | |
54 | // NULL if there isn't one. FNTYPE is the type of the function. | |
55 | // CONST_P is true if the function has the const attribute. | |
56 | ||
57 | static void | |
58 | define_builtin(built_in_function bcode, const char* name, const char* libname, | |
59 | tree fntype, bool const_p) | |
60 | { | |
61 | tree decl = add_builtin_function(name, fntype, bcode, BUILT_IN_NORMAL, | |
62 | libname, NULL_TREE); | |
63 | if (const_p) | |
64 | TREE_READONLY(decl) = 1; | |
9c73a43a | 65 | set_builtin_decl(bcode, decl, true); |
e440a328 | 66 | builtin_functions[name] = decl; |
67 | if (libname != NULL) | |
68 | { | |
69 | decl = add_builtin_function(libname, fntype, bcode, BUILT_IN_NORMAL, | |
70 | NULL, NULL_TREE); | |
71 | if (const_p) | |
72 | TREE_READONLY(decl) = 1; | |
73 | builtin_functions[libname] = decl; | |
74 | } | |
75 | } | |
76 | ||
77 | // Create trees for implicit builtin functions. | |
78 | ||
79 | void | |
80 | Gogo::define_builtin_function_trees() | |
81 | { | |
82 | /* We need to define the fetch_and_add functions, since we use them | |
83 | for ++ and --. */ | |
84 | tree t = go_type_for_size(BITS_PER_UNIT, 1); | |
85 | tree p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE)); | |
5ef9c912 | 86 | define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_1, "__sync_fetch_and_add_1", NULL, |
e440a328 | 87 | build_function_type_list(t, p, t, NULL_TREE), false); |
88 | ||
89 | t = go_type_for_size(BITS_PER_UNIT * 2, 1); | |
90 | p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE)); | |
5ef9c912 | 91 | define_builtin (BUILT_IN_SYNC_ADD_AND_FETCH_2, "__sync_fetch_and_add_2", NULL, |
e440a328 | 92 | build_function_type_list(t, p, t, NULL_TREE), false); |
93 | ||
94 | t = go_type_for_size(BITS_PER_UNIT * 4, 1); | |
95 | p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE)); | |
5ef9c912 | 96 | define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_4, "__sync_fetch_and_add_4", NULL, |
e440a328 | 97 | build_function_type_list(t, p, t, NULL_TREE), false); |
98 | ||
99 | t = go_type_for_size(BITS_PER_UNIT * 8, 1); | |
100 | p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE)); | |
5ef9c912 | 101 | define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_8, "__sync_fetch_and_add_8", NULL, |
e440a328 | 102 | build_function_type_list(t, p, t, NULL_TREE), false); |
103 | ||
104 | // We use __builtin_expect for magic import functions. | |
105 | define_builtin(BUILT_IN_EXPECT, "__builtin_expect", NULL, | |
106 | build_function_type_list(long_integer_type_node, | |
107 | long_integer_type_node, | |
108 | long_integer_type_node, | |
109 | NULL_TREE), | |
110 | true); | |
111 | ||
e9d3367e | 112 | // We use __builtin_memcmp for struct comparisons. |
113 | define_builtin(BUILT_IN_MEMCMP, "__builtin_memcmp", "memcmp", | |
114 | build_function_type_list(integer_type_node, | |
115 | const_ptr_type_node, | |
e440a328 | 116 | const_ptr_type_node, |
117 | size_type_node, | |
118 | NULL_TREE), | |
119 | false); | |
120 | ||
26ae0101 | 121 | // We provide some functions for the math library. |
122 | tree math_function_type = build_function_type_list(double_type_node, | |
123 | double_type_node, | |
124 | NULL_TREE); | |
125 | tree math_function_type_long = | |
126 | build_function_type_list(long_double_type_node, long_double_type_node, | |
127 | long_double_type_node, NULL_TREE); | |
128 | tree math_function_type_two = build_function_type_list(double_type_node, | |
129 | double_type_node, | |
130 | double_type_node, | |
131 | NULL_TREE); | |
132 | tree math_function_type_long_two = | |
133 | build_function_type_list(long_double_type_node, long_double_type_node, | |
134 | long_double_type_node, NULL_TREE); | |
135 | define_builtin(BUILT_IN_ACOS, "__builtin_acos", "acos", | |
136 | math_function_type, true); | |
137 | define_builtin(BUILT_IN_ACOSL, "__builtin_acosl", "acosl", | |
138 | math_function_type_long, true); | |
139 | define_builtin(BUILT_IN_ASIN, "__builtin_asin", "asin", | |
140 | math_function_type, true); | |
141 | define_builtin(BUILT_IN_ASINL, "__builtin_asinl", "asinl", | |
142 | math_function_type_long, true); | |
143 | define_builtin(BUILT_IN_ATAN, "__builtin_atan", "atan", | |
144 | math_function_type, true); | |
145 | define_builtin(BUILT_IN_ATANL, "__builtin_atanl", "atanl", | |
146 | math_function_type_long, true); | |
147 | define_builtin(BUILT_IN_ATAN2, "__builtin_atan2", "atan2", | |
148 | math_function_type_two, true); | |
149 | define_builtin(BUILT_IN_ATAN2L, "__builtin_atan2l", "atan2l", | |
150 | math_function_type_long_two, true); | |
151 | define_builtin(BUILT_IN_CEIL, "__builtin_ceil", "ceil", | |
152 | math_function_type, true); | |
153 | define_builtin(BUILT_IN_CEILL, "__builtin_ceill", "ceill", | |
154 | math_function_type_long, true); | |
155 | define_builtin(BUILT_IN_COS, "__builtin_cos", "cos", | |
156 | math_function_type, true); | |
157 | define_builtin(BUILT_IN_COSL, "__builtin_cosl", "cosl", | |
158 | math_function_type_long, true); | |
159 | define_builtin(BUILT_IN_EXP, "__builtin_exp", "exp", | |
160 | math_function_type, true); | |
161 | define_builtin(BUILT_IN_EXPL, "__builtin_expl", "expl", | |
162 | math_function_type_long, true); | |
163 | define_builtin(BUILT_IN_EXPM1, "__builtin_expm1", "expm1", | |
164 | math_function_type, true); | |
165 | define_builtin(BUILT_IN_EXPM1L, "__builtin_expm1l", "expm1l", | |
166 | math_function_type_long, true); | |
167 | define_builtin(BUILT_IN_FABS, "__builtin_fabs", "fabs", | |
168 | math_function_type, true); | |
169 | define_builtin(BUILT_IN_FABSL, "__builtin_fabsl", "fabsl", | |
170 | math_function_type_long, true); | |
171 | define_builtin(BUILT_IN_FLOOR, "__builtin_floor", "floor", | |
172 | math_function_type, true); | |
173 | define_builtin(BUILT_IN_FLOORL, "__builtin_floorl", "floorl", | |
174 | math_function_type_long, true); | |
175 | define_builtin(BUILT_IN_FMOD, "__builtin_fmod", "fmod", | |
176 | math_function_type_two, true); | |
177 | define_builtin(BUILT_IN_FMODL, "__builtin_fmodl", "fmodl", | |
178 | math_function_type_long_two, true); | |
179 | define_builtin(BUILT_IN_LDEXP, "__builtin_ldexp", "ldexp", | |
e440a328 | 180 | build_function_type_list(double_type_node, |
181 | double_type_node, | |
26ae0101 | 182 | integer_type_node, |
e440a328 | 183 | NULL_TREE), |
184 | true); | |
26ae0101 | 185 | define_builtin(BUILT_IN_LDEXPL, "__builtin_ldexpl", "ldexpl", |
e440a328 | 186 | build_function_type_list(long_double_type_node, |
187 | long_double_type_node, | |
26ae0101 | 188 | integer_type_node, |
e440a328 | 189 | NULL_TREE), |
190 | true); | |
26ae0101 | 191 | define_builtin(BUILT_IN_LOG, "__builtin_log", "log", |
192 | math_function_type, true); | |
193 | define_builtin(BUILT_IN_LOGL, "__builtin_logl", "logl", | |
194 | math_function_type_long, true); | |
195 | define_builtin(BUILT_IN_LOG1P, "__builtin_log1p", "log1p", | |
196 | math_function_type, true); | |
197 | define_builtin(BUILT_IN_LOG1PL, "__builtin_log1pl", "log1pl", | |
198 | math_function_type_long, true); | |
199 | define_builtin(BUILT_IN_LOG10, "__builtin_log10", "log10", | |
200 | math_function_type, true); | |
201 | define_builtin(BUILT_IN_LOG10L, "__builtin_log10l", "log10l", | |
202 | math_function_type_long, true); | |
203 | define_builtin(BUILT_IN_LOG2, "__builtin_log2", "log2", | |
204 | math_function_type, true); | |
205 | define_builtin(BUILT_IN_LOG2L, "__builtin_log2l", "log2l", | |
206 | math_function_type_long, true); | |
207 | define_builtin(BUILT_IN_SIN, "__builtin_sin", "sin", | |
208 | math_function_type, true); | |
209 | define_builtin(BUILT_IN_SINL, "__builtin_sinl", "sinl", | |
210 | math_function_type_long, true); | |
211 | define_builtin(BUILT_IN_SQRT, "__builtin_sqrt", "sqrt", | |
212 | math_function_type, true); | |
213 | define_builtin(BUILT_IN_SQRTL, "__builtin_sqrtl", "sqrtl", | |
214 | math_function_type_long, true); | |
215 | define_builtin(BUILT_IN_TAN, "__builtin_tan", "tan", | |
216 | math_function_type, true); | |
217 | define_builtin(BUILT_IN_TANL, "__builtin_tanl", "tanl", | |
218 | math_function_type_long, true); | |
219 | define_builtin(BUILT_IN_TRUNC, "__builtin_trunc", "trunc", | |
220 | math_function_type, true); | |
221 | define_builtin(BUILT_IN_TRUNCL, "__builtin_truncl", "truncl", | |
222 | math_function_type_long, true); | |
e440a328 | 223 | |
224 | // We use __builtin_return_address in the thunk we build for | |
225 | // functions which call recover. | |
226 | define_builtin(BUILT_IN_RETURN_ADDRESS, "__builtin_return_address", NULL, | |
227 | build_function_type_list(ptr_type_node, | |
228 | unsigned_type_node, | |
229 | NULL_TREE), | |
230 | false); | |
231 | ||
232 | // The compiler uses __builtin_trap for some exception handling | |
233 | // cases. | |
234 | define_builtin(BUILT_IN_TRAP, "__builtin_trap", NULL, | |
235 | build_function_type(void_type_node, void_list_node), | |
236 | false); | |
237 | } | |
238 | ||
239 | // Get the name to use for the import control function. If there is a | |
240 | // global function or variable, then we know that that name must be | |
241 | // unique in the link, and we use it as the basis for our name. | |
242 | ||
243 | const std::string& | |
244 | Gogo::get_init_fn_name() | |
245 | { | |
246 | if (this->init_fn_name_.empty()) | |
247 | { | |
c484d925 | 248 | go_assert(this->package_ != NULL); |
2b0adbff | 249 | if (this->is_main_package()) |
e440a328 | 250 | { |
251 | // Use a name which the runtime knows. | |
252 | this->init_fn_name_ = "__go_init_main"; | |
253 | } | |
254 | else | |
255 | { | |
2a2647e2 | 256 | std::string s = this->pkgpath_symbol(); |
e440a328 | 257 | s.append("..import"); |
258 | this->init_fn_name_ = s; | |
259 | } | |
260 | } | |
261 | ||
262 | return this->init_fn_name_; | |
263 | } | |
264 | ||
265 | // Add statements to INIT_STMT_LIST which run the initialization | |
266 | // functions for imported packages. This is only used for the "main" | |
267 | // package. | |
268 | ||
269 | void | |
270 | Gogo::init_imports(tree* init_stmt_list) | |
271 | { | |
c484d925 | 272 | go_assert(this->is_main_package()); |
e440a328 | 273 | |
274 | if (this->imported_init_fns_.empty()) | |
275 | return; | |
276 | ||
277 | tree fntype = build_function_type(void_type_node, void_list_node); | |
278 | ||
279 | // We must call them in increasing priority order. | |
280 | std::vector<Import_init> v; | |
281 | for (std::set<Import_init>::const_iterator p = | |
282 | this->imported_init_fns_.begin(); | |
283 | p != this->imported_init_fns_.end(); | |
284 | ++p) | |
285 | v.push_back(*p); | |
286 | std::sort(v.begin(), v.end()); | |
287 | ||
288 | for (std::vector<Import_init>::const_iterator p = v.begin(); | |
289 | p != v.end(); | |
290 | ++p) | |
291 | { | |
292 | std::string user_name = p->package_name() + ".init"; | |
293 | tree decl = build_decl(UNKNOWN_LOCATION, FUNCTION_DECL, | |
294 | get_identifier_from_string(user_name), | |
295 | fntype); | |
296 | const std::string& init_name(p->init_name()); | |
297 | SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(init_name)); | |
298 | TREE_PUBLIC(decl) = 1; | |
299 | DECL_EXTERNAL(decl) = 1; | |
300 | append_to_statement_list(build_call_expr(decl, 0), init_stmt_list); | |
301 | } | |
302 | } | |
303 | ||
304 | // Register global variables with the garbage collector. We need to | |
305 | // register all variables which can hold a pointer value. They become | |
306 | // roots during the mark phase. We build a struct that is easy to | |
307 | // hook into a list of roots. | |
308 | ||
309 | // struct __go_gc_root_list | |
310 | // { | |
311 | // struct __go_gc_root_list* __next; | |
312 | // struct __go_gc_root | |
313 | // { | |
314 | // void* __decl; | |
315 | // size_t __size; | |
316 | // } __roots[]; | |
317 | // }; | |
318 | ||
319 | // The last entry in the roots array has a NULL decl field. | |
320 | ||
321 | void | |
322 | Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc, | |
323 | tree* init_stmt_list) | |
324 | { | |
325 | if (var_gc.empty()) | |
326 | return; | |
327 | ||
328 | size_t count = var_gc.size(); | |
329 | ||
330 | tree root_type = Gogo::builtin_struct(NULL, "__go_gc_root", NULL_TREE, 2, | |
331 | "__next", | |
332 | ptr_type_node, | |
333 | "__size", | |
334 | sizetype); | |
335 | ||
336 | tree index_type = build_index_type(size_int(count)); | |
337 | tree array_type = build_array_type(root_type, index_type); | |
338 | ||
339 | tree root_list_type = make_node(RECORD_TYPE); | |
340 | root_list_type = Gogo::builtin_struct(NULL, "__go_gc_root_list", | |
341 | root_list_type, 2, | |
342 | "__next", | |
343 | build_pointer_type(root_list_type), | |
344 | "__roots", | |
345 | array_type); | |
346 | ||
347 | // Build an initialier for the __roots array. | |
348 | ||
95f84544 | 349 | vec<constructor_elt, va_gc> *roots_init; |
350 | vec_alloc(roots_init, count + 1); | |
e440a328 | 351 | |
352 | size_t i = 0; | |
353 | for (std::vector<Named_object*>::const_iterator p = var_gc.begin(); | |
354 | p != var_gc.end(); | |
355 | ++p, ++i) | |
356 | { | |
95f84544 | 357 | vec<constructor_elt, va_gc> *init; |
358 | vec_alloc(init, 2); | |
e440a328 | 359 | |
e82e4eb5 | 360 | constructor_elt empty = {NULL, NULL}; |
95f84544 | 361 | constructor_elt* elt = init->quick_push(empty); |
e440a328 | 362 | tree field = TYPE_FIELDS(root_type); |
363 | elt->index = field; | |
fe2f84cf | 364 | Bvariable* bvar = (*p)->get_backend_variable(this, NULL); |
365 | tree decl = var_to_tree(bvar); | |
c484d925 | 366 | go_assert(TREE_CODE(decl) == VAR_DECL); |
e440a328 | 367 | elt->value = build_fold_addr_expr(decl); |
368 | ||
95f84544 | 369 | elt = init->quick_push(empty); |
e440a328 | 370 | field = DECL_CHAIN(field); |
371 | elt->index = field; | |
372 | elt->value = DECL_SIZE_UNIT(decl); | |
373 | ||
95f84544 | 374 | elt = roots_init->quick_push(empty); |
e440a328 | 375 | elt->index = size_int(i); |
376 | elt->value = build_constructor(root_type, init); | |
377 | } | |
378 | ||
379 | // The list ends with a NULL entry. | |
380 | ||
95f84544 | 381 | vec<constructor_elt, va_gc> *init; |
382 | vec_alloc(init, 2); | |
e440a328 | 383 | |
e82e4eb5 | 384 | constructor_elt empty = {NULL, NULL}; |
95f84544 | 385 | constructor_elt* elt = init->quick_push(empty); |
e440a328 | 386 | tree field = TYPE_FIELDS(root_type); |
387 | elt->index = field; | |
388 | elt->value = fold_convert(TREE_TYPE(field), null_pointer_node); | |
389 | ||
95f84544 | 390 | elt = init->quick_push(empty); |
e440a328 | 391 | field = DECL_CHAIN(field); |
392 | elt->index = field; | |
393 | elt->value = size_zero_node; | |
394 | ||
95f84544 | 395 | elt = roots_init->quick_push(empty); |
e440a328 | 396 | elt->index = size_int(i); |
397 | elt->value = build_constructor(root_type, init); | |
398 | ||
399 | // Build a constructor for the struct. | |
400 | ||
95f84544 | 401 | vec<constructor_elt, va_gc> *root_list_init; |
402 | vec_alloc(root_list_init, 2); | |
e440a328 | 403 | |
95f84544 | 404 | elt = root_list_init->quick_push(empty); |
e440a328 | 405 | field = TYPE_FIELDS(root_list_type); |
406 | elt->index = field; | |
407 | elt->value = fold_convert(TREE_TYPE(field), null_pointer_node); | |
408 | ||
95f84544 | 409 | elt = root_list_init->quick_push(empty); |
e440a328 | 410 | field = DECL_CHAIN(field); |
411 | elt->index = field; | |
412 | elt->value = build_constructor(array_type, roots_init); | |
413 | ||
414 | // Build a decl to register. | |
415 | ||
416 | tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, | |
417 | create_tmp_var_name("gc"), root_list_type); | |
418 | DECL_EXTERNAL(decl) = 0; | |
419 | TREE_PUBLIC(decl) = 0; | |
420 | TREE_STATIC(decl) = 1; | |
421 | DECL_ARTIFICIAL(decl) = 1; | |
422 | DECL_INITIAL(decl) = build_constructor(root_list_type, root_list_init); | |
423 | rest_of_decl_compilation(decl, 1, 0); | |
424 | ||
425 | static tree register_gc_fndecl; | |
b13c66cd | 426 | tree call = Gogo::call_builtin(®ister_gc_fndecl, |
427 | Linemap::predeclared_location(), | |
428 | "__go_register_gc_roots", | |
e440a328 | 429 | 1, |
430 | void_type_node, | |
431 | build_pointer_type(root_list_type), | |
432 | build_fold_addr_expr(decl)); | |
5fb82b5e | 433 | if (call != error_mark_node) |
434 | append_to_statement_list(call, init_stmt_list); | |
e440a328 | 435 | } |
436 | ||
437 | // Build the decl for the initialization function. | |
438 | ||
439 | tree | |
440 | Gogo::initialization_function_decl() | |
441 | { | |
442 | // The tedious details of building your own function. There doesn't | |
443 | // seem to be a helper function for this. | |
444 | std::string name = this->package_name() + ".init"; | |
266fa788 | 445 | tree fndecl = build_decl(this->package_->location().gcc_location(), |
446 | FUNCTION_DECL, get_identifier_from_string(name), | |
e440a328 | 447 | build_function_type(void_type_node, |
448 | void_list_node)); | |
449 | const std::string& asm_name(this->get_init_fn_name()); | |
450 | SET_DECL_ASSEMBLER_NAME(fndecl, get_identifier_from_string(asm_name)); | |
451 | ||
266fa788 | 452 | tree resdecl = build_decl(this->package_->location().gcc_location(), |
453 | RESULT_DECL, NULL_TREE, void_type_node); | |
e440a328 | 454 | DECL_ARTIFICIAL(resdecl) = 1; |
455 | DECL_CONTEXT(resdecl) = fndecl; | |
456 | DECL_RESULT(fndecl) = resdecl; | |
457 | ||
458 | TREE_STATIC(fndecl) = 1; | |
459 | TREE_USED(fndecl) = 1; | |
460 | DECL_ARTIFICIAL(fndecl) = 1; | |
461 | TREE_PUBLIC(fndecl) = 1; | |
462 | ||
463 | DECL_INITIAL(fndecl) = make_node(BLOCK); | |
464 | TREE_USED(DECL_INITIAL(fndecl)) = 1; | |
465 | ||
466 | return fndecl; | |
467 | } | |
468 | ||
469 | // Create the magic initialization function. INIT_STMT_LIST is the | |
470 | // code that it needs to run. | |
471 | ||
472 | void | |
473 | Gogo::write_initialization_function(tree fndecl, tree init_stmt_list) | |
474 | { | |
475 | // Make sure that we thought we needed an initialization function, | |
476 | // as otherwise we will not have reported it in the export data. | |
c484d925 | 477 | go_assert(this->is_main_package() || this->need_init_fn_); |
e440a328 | 478 | |
479 | if (fndecl == NULL_TREE) | |
480 | fndecl = this->initialization_function_decl(); | |
481 | ||
482 | DECL_SAVED_TREE(fndecl) = init_stmt_list; | |
483 | ||
e440a328 | 484 | if (DECL_STRUCT_FUNCTION(fndecl) == NULL) |
485 | push_struct_function(fndecl); | |
486 | else | |
487 | push_cfun(DECL_STRUCT_FUNCTION(fndecl)); | |
266fa788 | 488 | cfun->function_start_locus = this->package_->location().gcc_location(); |
489 | cfun->function_end_locus = cfun->function_start_locus; | |
e440a328 | 490 | |
491 | gimplify_function_tree(fndecl); | |
492 | ||
493 | cgraph_add_new_function(fndecl, false); | |
e440a328 | 494 | |
e440a328 | 495 | pop_cfun(); |
496 | } | |
497 | ||
498 | // Search for references to VAR in any statements or called functions. | |
499 | ||
500 | class Find_var : public Traverse | |
501 | { | |
502 | public: | |
503 | // A hash table we use to avoid looping. The index is the name of a | |
504 | // named object. We only look through objects defined in this | |
505 | // package. | |
a4a43c62 | 506 | typedef Unordered_set(const void*) Seen_objects; |
e440a328 | 507 | |
508 | Find_var(Named_object* var, Seen_objects* seen_objects) | |
509 | : Traverse(traverse_expressions), | |
510 | var_(var), seen_objects_(seen_objects), found_(false) | |
511 | { } | |
512 | ||
513 | // Whether the variable was found. | |
514 | bool | |
515 | found() const | |
516 | { return this->found_; } | |
517 | ||
518 | int | |
519 | expression(Expression**); | |
520 | ||
521 | private: | |
522 | // The variable we are looking for. | |
523 | Named_object* var_; | |
524 | // Names of objects we have already seen. | |
525 | Seen_objects* seen_objects_; | |
526 | // True if the variable was found. | |
527 | bool found_; | |
528 | }; | |
529 | ||
530 | // See if EXPR refers to VAR, looking through function calls and | |
531 | // variable initializations. | |
532 | ||
533 | int | |
534 | Find_var::expression(Expression** pexpr) | |
535 | { | |
536 | Expression* e = *pexpr; | |
537 | ||
538 | Var_expression* ve = e->var_expression(); | |
539 | if (ve != NULL) | |
540 | { | |
541 | Named_object* v = ve->named_object(); | |
542 | if (v == this->var_) | |
543 | { | |
544 | this->found_ = true; | |
545 | return TRAVERSE_EXIT; | |
546 | } | |
547 | ||
548 | if (v->is_variable() && v->package() == NULL) | |
549 | { | |
550 | Expression* init = v->var_value()->init(); | |
551 | if (init != NULL) | |
552 | { | |
553 | std::pair<Seen_objects::iterator, bool> ins = | |
a4a43c62 | 554 | this->seen_objects_->insert(v); |
e440a328 | 555 | if (ins.second) |
556 | { | |
557 | // This is the first time we have seen this name. | |
558 | if (Expression::traverse(&init, this) == TRAVERSE_EXIT) | |
559 | return TRAVERSE_EXIT; | |
560 | } | |
561 | } | |
562 | } | |
563 | } | |
564 | ||
565 | // We traverse the code of any function we see. Note that this | |
566 | // means that we will traverse the code of a function whose address | |
567 | // is taken even if it is not called. | |
568 | Func_expression* fe = e->func_expression(); | |
569 | if (fe != NULL) | |
570 | { | |
571 | const Named_object* f = fe->named_object(); | |
572 | if (f->is_function() && f->package() == NULL) | |
573 | { | |
574 | std::pair<Seen_objects::iterator, bool> ins = | |
a4a43c62 | 575 | this->seen_objects_->insert(f); |
e440a328 | 576 | if (ins.second) |
577 | { | |
578 | // This is the first time we have seen this name. | |
579 | if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT) | |
580 | return TRAVERSE_EXIT; | |
581 | } | |
582 | } | |
583 | } | |
584 | ||
a4a43c62 | 585 | Temporary_reference_expression* tre = e->temporary_reference_expression(); |
586 | if (tre != NULL) | |
587 | { | |
588 | Temporary_statement* ts = tre->statement(); | |
589 | Expression* init = ts->init(); | |
590 | if (init != NULL) | |
591 | { | |
592 | std::pair<Seen_objects::iterator, bool> ins = | |
593 | this->seen_objects_->insert(ts); | |
594 | if (ins.second) | |
595 | { | |
596 | // This is the first time we have seen this temporary | |
597 | // statement. | |
598 | if (Expression::traverse(&init, this) == TRAVERSE_EXIT) | |
599 | return TRAVERSE_EXIT; | |
600 | } | |
601 | } | |
602 | } | |
603 | ||
e440a328 | 604 | return TRAVERSE_CONTINUE; |
605 | } | |
606 | ||
e528aa1f | 607 | // Return true if EXPR, PREINIT, or DEP refers to VAR. |
e440a328 | 608 | |
609 | static bool | |
e528aa1f | 610 | expression_requires(Expression* expr, Block* preinit, Named_object* dep, |
611 | Named_object* var) | |
e440a328 | 612 | { |
613 | Find_var::Seen_objects seen_objects; | |
614 | Find_var find_var(var, &seen_objects); | |
615 | if (expr != NULL) | |
616 | Expression::traverse(&expr, &find_var); | |
617 | if (preinit != NULL) | |
618 | preinit->traverse(&find_var); | |
e528aa1f | 619 | if (dep != NULL) |
620 | { | |
621 | Expression* init = dep->var_value()->init(); | |
622 | if (init != NULL) | |
623 | Expression::traverse(&init, &find_var); | |
624 | if (dep->var_value()->has_pre_init()) | |
625 | dep->var_value()->preinit()->traverse(&find_var); | |
626 | } | |
627 | ||
e440a328 | 628 | return find_var.found(); |
629 | } | |
630 | ||
631 | // Sort variable initializations. If the initialization expression | |
632 | // for variable A refers directly or indirectly to the initialization | |
633 | // expression for variable B, then we must initialize B before A. | |
634 | ||
635 | class Var_init | |
636 | { | |
637 | public: | |
638 | Var_init() | |
a4a43c62 | 639 | : var_(NULL), init_(NULL_TREE) |
e440a328 | 640 | { } |
641 | ||
642 | Var_init(Named_object* var, tree init) | |
a4a43c62 | 643 | : var_(var), init_(init) |
e440a328 | 644 | { } |
645 | ||
646 | // Return the variable. | |
647 | Named_object* | |
648 | var() const | |
649 | { return this->var_; } | |
650 | ||
651 | // Return the initialization expression. | |
652 | tree | |
653 | init() const | |
654 | { return this->init_; } | |
655 | ||
e440a328 | 656 | private: |
657 | // The variable being initialized. | |
658 | Named_object* var_; | |
659 | // The initialization expression to run. | |
660 | tree init_; | |
e440a328 | 661 | }; |
662 | ||
663 | typedef std::list<Var_init> Var_inits; | |
664 | ||
665 | // Sort the variable initializations. The rule we follow is that we | |
666 | // emit them in the order they appear in the array, except that if the | |
667 | // initialization expression for a variable V1 depends upon another | |
668 | // variable V2 then we initialize V1 after V2. | |
669 | ||
670 | static void | |
e528aa1f | 671 | sort_var_inits(Gogo* gogo, Var_inits* var_inits) |
e440a328 | 672 | { |
a4a43c62 | 673 | typedef std::pair<Named_object*, Named_object*> No_no; |
674 | typedef std::map<No_no, bool> Cache; | |
675 | Cache cache; | |
676 | ||
e440a328 | 677 | Var_inits ready; |
678 | while (!var_inits->empty()) | |
679 | { | |
680 | Var_inits::iterator p1 = var_inits->begin(); | |
681 | Named_object* var = p1->var(); | |
682 | Expression* init = var->var_value()->init(); | |
683 | Block* preinit = var->var_value()->preinit(); | |
e528aa1f | 684 | Named_object* dep = gogo->var_depends_on(var->var_value()); |
e440a328 | 685 | |
686 | // Start walking through the list to see which variables VAR | |
a4a43c62 | 687 | // needs to wait for. |
e440a328 | 688 | Var_inits::iterator p2 = p1; |
689 | ++p2; | |
e440a328 | 690 | |
691 | for (; p2 != var_inits->end(); ++p2) | |
692 | { | |
e528aa1f | 693 | Named_object* p2var = p2->var(); |
a4a43c62 | 694 | No_no key(var, p2var); |
695 | std::pair<Cache::iterator, bool> ins = | |
696 | cache.insert(std::make_pair(key, false)); | |
697 | if (ins.second) | |
698 | ins.first->second = expression_requires(init, preinit, dep, p2var); | |
699 | if (ins.first->second) | |
e440a328 | 700 | { |
701 | // Check for cycles. | |
a4a43c62 | 702 | key = std::make_pair(p2var, var); |
703 | ins = cache.insert(std::make_pair(key, false)); | |
704 | if (ins.second) | |
705 | ins.first->second = | |
706 | expression_requires(p2var->var_value()->init(), | |
e528aa1f | 707 | p2var->var_value()->preinit(), |
708 | gogo->var_depends_on(p2var->var_value()), | |
a4a43c62 | 709 | var); |
710 | if (ins.first->second) | |
e440a328 | 711 | { |
712 | error_at(var->location(), | |
713 | ("initialization expressions for %qs and " | |
714 | "%qs depend upon each other"), | |
715 | var->message_name().c_str(), | |
e528aa1f | 716 | p2var->message_name().c_str()); |
e440a328 | 717 | inform(p2->var()->location(), "%qs defined here", |
e528aa1f | 718 | p2var->message_name().c_str()); |
e440a328 | 719 | p2 = var_inits->end(); |
720 | } | |
721 | else | |
722 | { | |
723 | // We can't emit P1 until P2 is emitted. Move P1. | |
e440a328 | 724 | Var_inits::iterator p3 = p2; |
a4a43c62 | 725 | ++p3; |
e440a328 | 726 | var_inits->splice(p3, *var_inits, p1); |
727 | } | |
728 | break; | |
729 | } | |
730 | } | |
731 | ||
732 | if (p2 == var_inits->end()) | |
733 | { | |
734 | // VAR does not depends upon any other initialization expressions. | |
735 | ||
736 | // Check for a loop of VAR on itself. We only do this if | |
e528aa1f | 737 | // INIT is not NULL and there is no dependency; when INIT is |
738 | // NULL, it means that PREINIT sets VAR, which we will | |
739 | // interpret as a loop. | |
740 | if (init != NULL && dep == NULL | |
741 | && expression_requires(init, preinit, NULL, var)) | |
e440a328 | 742 | error_at(var->location(), |
743 | "initialization expression for %qs depends upon itself", | |
744 | var->message_name().c_str()); | |
745 | ready.splice(ready.end(), *var_inits, p1); | |
746 | } | |
747 | } | |
748 | ||
749 | // Now READY is the list in the desired initialization order. | |
750 | var_inits->swap(ready); | |
751 | } | |
752 | ||
753 | // Write out the global definitions. | |
754 | ||
755 | void | |
756 | Gogo::write_globals() | |
757 | { | |
9aa9e2df | 758 | this->convert_named_types(); |
759 | this->build_interface_method_tables(); | |
760 | ||
e440a328 | 761 | Bindings* bindings = this->current_bindings(); |
8381eda7 | 762 | |
763 | for (Bindings::const_declarations_iterator p = bindings->begin_declarations(); | |
764 | p != bindings->end_declarations(); | |
765 | ++p) | |
766 | { | |
767 | // If any function declarations needed a descriptor, make sure | |
768 | // we build it. | |
769 | Named_object* no = p->second; | |
770 | if (no->is_function_declaration()) | |
771 | no->func_declaration_value()->build_backend_descriptor(this); | |
772 | } | |
773 | ||
e9d3367e | 774 | size_t count_definitions = bindings->size_definitions(); |
775 | size_t count = count_definitions; | |
e440a328 | 776 | |
777 | tree* vec = new tree[count]; | |
778 | ||
779 | tree init_fndecl = NULL_TREE; | |
780 | tree init_stmt_list = NULL_TREE; | |
781 | ||
2b0adbff | 782 | if (this->is_main_package()) |
e440a328 | 783 | this->init_imports(&init_stmt_list); |
784 | ||
785 | // A list of variable initializations. | |
786 | Var_inits var_inits; | |
787 | ||
788 | // A list of variables which need to be registered with the garbage | |
789 | // collector. | |
790 | std::vector<Named_object*> var_gc; | |
791 | var_gc.reserve(count); | |
792 | ||
793 | tree var_init_stmt_list = NULL_TREE; | |
794 | size_t i = 0; | |
795 | for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); | |
796 | p != bindings->end_definitions(); | |
797 | ++p, ++i) | |
798 | { | |
799 | Named_object* no = *p; | |
800 | ||
8381eda7 | 801 | go_assert(i < count); |
802 | ||
c484d925 | 803 | go_assert(!no->is_type_declaration() && !no->is_function_declaration()); |
e440a328 | 804 | // There is nothing to do for a package. |
805 | if (no->is_package()) | |
806 | { | |
807 | --i; | |
808 | --count; | |
809 | continue; | |
810 | } | |
811 | ||
812 | // There is nothing to do for an object which was imported from | |
813 | // a different package into the global scope. | |
814 | if (no->package() != NULL) | |
815 | { | |
816 | --i; | |
817 | --count; | |
818 | continue; | |
819 | } | |
820 | ||
7f54d14c | 821 | // Skip blank named functions and constants. |
822 | if ((no->is_function() && no->func_value()->is_sink()) | |
823 | || (no->is_const() && no->const_value()->is_sink())) | |
824 | { | |
825 | --i; | |
826 | --count; | |
827 | continue; | |
828 | } | |
829 | ||
e440a328 | 830 | // There is nothing useful we can output for constants which |
e528aa1f | 831 | // have ideal or non-integral type. |
e440a328 | 832 | if (no->is_const()) |
833 | { | |
834 | Type* type = no->const_value()->type(); | |
835 | if (type == NULL) | |
836 | type = no->const_value()->expr()->type(); | |
837 | if (type->is_abstract() || type->integer_type() == NULL) | |
838 | { | |
839 | --i; | |
840 | --count; | |
841 | continue; | |
842 | } | |
843 | } | |
844 | ||
fe2f84cf | 845 | if (!no->is_variable()) |
e440a328 | 846 | { |
fe2f84cf | 847 | vec[i] = no->get_tree(this, NULL); |
848 | if (vec[i] == error_mark_node) | |
849 | { | |
c484d925 | 850 | go_assert(saw_errors()); |
fe2f84cf | 851 | --i; |
852 | --count; | |
853 | continue; | |
854 | } | |
e440a328 | 855 | } |
fe2f84cf | 856 | else |
e440a328 | 857 | { |
fe2f84cf | 858 | Bvariable* var = no->get_backend_variable(this, NULL); |
859 | vec[i] = var_to_tree(var); | |
860 | if (vec[i] == error_mark_node) | |
861 | { | |
c484d925 | 862 | go_assert(saw_errors()); |
fe2f84cf | 863 | --i; |
864 | --count; | |
865 | continue; | |
866 | } | |
e440a328 | 867 | |
fe2f84cf | 868 | // Check for a sink variable, which may be used to run an |
869 | // initializer purely for its side effects. | |
e440a328 | 870 | bool is_sink = no->name()[0] == '_' && no->name()[1] == '.'; |
871 | ||
872 | tree var_init_tree = NULL_TREE; | |
873 | if (!no->var_value()->has_pre_init()) | |
874 | { | |
875 | tree init = no->var_value()->get_init_tree(this, NULL); | |
876 | if (init == error_mark_node) | |
c484d925 | 877 | go_assert(saw_errors()); |
e440a328 | 878 | else if (init == NULL_TREE) |
879 | ; | |
880 | else if (TREE_CONSTANT(init)) | |
999392dd | 881 | { |
e528aa1f | 882 | if (expression_requires(no->var_value()->init(), NULL, |
883 | this->var_depends_on(no->var_value()), | |
884 | no)) | |
999392dd | 885 | error_at(no->location(), |
886 | "initialization expression for %qs depends " | |
887 | "upon itself", | |
888 | no->message_name().c_str()); | |
889 | this->backend()->global_variable_set_init(var, | |
890 | tree_to_expr(init)); | |
891 | } | |
6e27a000 | 892 | else if (is_sink |
893 | || int_size_in_bytes(TREE_TYPE(init)) == 0 | |
894 | || int_size_in_bytes(TREE_TYPE(vec[i])) == 0) | |
e440a328 | 895 | var_init_tree = init; |
896 | else | |
b13c66cd | 897 | var_init_tree = fold_build2_loc(no->location().gcc_location(), |
898 | MODIFY_EXPR, void_type_node, | |
899 | vec[i], init); | |
e440a328 | 900 | } |
901 | else | |
902 | { | |
903 | // We are going to create temporary variables which | |
904 | // means that we need an fndecl. | |
905 | if (init_fndecl == NULL_TREE) | |
906 | init_fndecl = this->initialization_function_decl(); | |
e440a328 | 907 | if (DECL_STRUCT_FUNCTION(init_fndecl) == NULL) |
908 | push_struct_function(init_fndecl); | |
909 | else | |
910 | push_cfun(DECL_STRUCT_FUNCTION(init_fndecl)); | |
e440a328 | 911 | tree var_decl = is_sink ? NULL_TREE : vec[i]; |
912 | var_init_tree = no->var_value()->get_init_block(this, NULL, | |
913 | var_decl); | |
e440a328 | 914 | pop_cfun(); |
915 | } | |
916 | ||
f5c95e30 | 917 | if (var_init_tree != NULL_TREE && var_init_tree != error_mark_node) |
e440a328 | 918 | { |
919 | if (no->var_value()->init() == NULL | |
920 | && !no->var_value()->has_pre_init()) | |
921 | append_to_statement_list(var_init_tree, &var_init_stmt_list); | |
922 | else | |
923 | var_inits.push_back(Var_init(no, var_init_tree)); | |
924 | } | |
e528aa1f | 925 | else if (this->var_depends_on(no->var_value()) != NULL) |
926 | { | |
927 | // This variable is initialized from something that is | |
928 | // not in its init or preinit. This variable needs to | |
929 | // participate in dependency analysis sorting, in case | |
930 | // some other variable depends on this one. | |
931 | var_inits.push_back(Var_init(no, integer_zero_node)); | |
932 | } | |
e440a328 | 933 | |
934 | if (!is_sink && no->var_value()->type()->has_pointer()) | |
935 | var_gc.push_back(no); | |
936 | } | |
937 | } | |
938 | ||
939 | // Register global variables with the garbage collector. | |
940 | this->register_gc_vars(var_gc, &init_stmt_list); | |
941 | ||
942 | // Simple variable initializations, after all variables are | |
943 | // registered. | |
944 | append_to_statement_list(var_init_stmt_list, &init_stmt_list); | |
945 | ||
946 | // Complex variable initializations, first sorting them into a | |
947 | // workable order. | |
948 | if (!var_inits.empty()) | |
949 | { | |
e528aa1f | 950 | sort_var_inits(this, &var_inits); |
e440a328 | 951 | for (Var_inits::const_iterator p = var_inits.begin(); |
952 | p != var_inits.end(); | |
953 | ++p) | |
954 | append_to_statement_list(p->init(), &init_stmt_list); | |
955 | } | |
956 | ||
957 | // After all the variables are initialized, call the "init" | |
958 | // functions if there are any. | |
959 | for (std::vector<Named_object*>::const_iterator p = | |
960 | this->init_functions_.begin(); | |
961 | p != this->init_functions_.end(); | |
962 | ++p) | |
963 | { | |
964 | tree decl = (*p)->get_tree(this, NULL); | |
965 | tree call = build_call_expr(decl, 0); | |
966 | append_to_statement_list(call, &init_stmt_list); | |
967 | } | |
968 | ||
969 | // Set up a magic function to do all the initialization actions. | |
970 | // This will be called if this package is imported. | |
971 | if (init_stmt_list != NULL_TREE | |
972 | || this->need_init_fn_ | |
2b0adbff | 973 | || this->is_main_package()) |
e440a328 | 974 | this->write_initialization_function(init_fndecl, init_stmt_list); |
975 | ||
e9d3367e | 976 | // We should not have seen any new bindings created during the |
977 | // conversion. | |
978 | go_assert(count_definitions == this->current_bindings()->size_definitions()); | |
979 | ||
e440a328 | 980 | // Pass everything back to the middle-end. |
981 | ||
e440a328 | 982 | wrapup_global_declarations(vec, count); |
983 | ||
cf951b1a | 984 | finalize_compilation_unit(); |
e440a328 | 985 | |
986 | check_global_declarations(vec, count); | |
987 | emit_debug_global_declarations(vec, count); | |
988 | ||
989 | delete[] vec; | |
990 | } | |
991 | ||
e440a328 | 992 | // Get a tree for a named object. |
993 | ||
994 | tree | |
995 | Named_object::get_tree(Gogo* gogo, Named_object* function) | |
996 | { | |
997 | if (this->tree_ != NULL_TREE) | |
fe2f84cf | 998 | return this->tree_; |
e440a328 | 999 | |
c6d96ab1 | 1000 | if (Gogo::is_erroneous_name(this->name_)) |
1001 | { | |
1002 | this->tree_ = error_mark_node; | |
1003 | return error_mark_node; | |
1004 | } | |
1005 | ||
e440a328 | 1006 | tree decl; |
1007 | switch (this->classification_) | |
1008 | { | |
1009 | case NAMED_OBJECT_CONST: | |
1010 | { | |
1011 | Named_constant* named_constant = this->u_.const_value; | |
7e84be55 | 1012 | Translate_context subcontext(gogo, function, NULL, NULL); |
e440a328 | 1013 | tree expr_tree = named_constant->expr()->get_tree(&subcontext); |
1014 | if (expr_tree == error_mark_node) | |
1015 | decl = error_mark_node; | |
1016 | else | |
1017 | { | |
1018 | Type* type = named_constant->type(); | |
1019 | if (type != NULL && !type->is_abstract()) | |
e253959f | 1020 | { |
9f0e0513 | 1021 | if (type->is_error()) |
5c13bd80 | 1022 | expr_tree = error_mark_node; |
9f0e0513 | 1023 | else |
1024 | { | |
1025 | Btype* btype = type->get_backend(gogo); | |
1026 | expr_tree = fold_convert(type_to_tree(btype), expr_tree); | |
1027 | } | |
e253959f | 1028 | } |
e440a328 | 1029 | if (expr_tree == error_mark_node) |
1030 | decl = error_mark_node; | |
1031 | else if (INTEGRAL_TYPE_P(TREE_TYPE(expr_tree))) | |
1032 | { | |
cf3cae55 | 1033 | tree name = get_identifier_from_string(this->get_id(gogo)); |
b13c66cd | 1034 | decl = build_decl(named_constant->location().gcc_location(), |
1035 | CONST_DECL, name, TREE_TYPE(expr_tree)); | |
e440a328 | 1036 | DECL_INITIAL(decl) = expr_tree; |
1037 | TREE_CONSTANT(decl) = 1; | |
1038 | TREE_READONLY(decl) = 1; | |
1039 | } | |
1040 | else | |
1041 | { | |
1042 | // A CONST_DECL is only for an enum constant, so we | |
1043 | // shouldn't use for non-integral types. Instead we | |
1044 | // just return the constant itself, rather than a | |
1045 | // decl. | |
1046 | decl = expr_tree; | |
1047 | } | |
1048 | } | |
1049 | } | |
1050 | break; | |
1051 | ||
1052 | case NAMED_OBJECT_TYPE: | |
1053 | { | |
1054 | Named_type* named_type = this->u_.type_value; | |
9f0e0513 | 1055 | tree type_tree = type_to_tree(named_type->get_backend(gogo)); |
e440a328 | 1056 | if (type_tree == error_mark_node) |
1057 | decl = error_mark_node; | |
1058 | else | |
1059 | { | |
1060 | decl = TYPE_NAME(type_tree); | |
c484d925 | 1061 | go_assert(decl != NULL_TREE); |
e440a328 | 1062 | |
1063 | // We need to produce a type descriptor for every named | |
1064 | // type, and for a pointer to every named type, since | |
1065 | // other files or packages might refer to them. We need | |
1066 | // to do this even for hidden types, because they might | |
1067 | // still be returned by some function. Simply calling the | |
1068 | // type_descriptor method is enough to create the type | |
1069 | // descriptor, even though we don't do anything with it. | |
1070 | if (this->package_ == NULL) | |
1071 | { | |
b13c66cd | 1072 | named_type-> |
1073 | type_descriptor_pointer(gogo, | |
1074 | Linemap::predeclared_location()); | |
e440a328 | 1075 | Type* pn = Type::make_pointer_type(named_type); |
b13c66cd | 1076 | pn->type_descriptor_pointer(gogo, |
1077 | Linemap::predeclared_location()); | |
e440a328 | 1078 | } |
1079 | } | |
1080 | } | |
1081 | break; | |
1082 | ||
1083 | case NAMED_OBJECT_TYPE_DECLARATION: | |
1084 | error("reference to undefined type %qs", | |
1085 | this->message_name().c_str()); | |
1086 | return error_mark_node; | |
1087 | ||
1088 | case NAMED_OBJECT_VAR: | |
e440a328 | 1089 | case NAMED_OBJECT_RESULT_VAR: |
e440a328 | 1090 | case NAMED_OBJECT_SINK: |
c3e6f413 | 1091 | go_unreachable(); |
e440a328 | 1092 | |
1093 | case NAMED_OBJECT_FUNC: | |
1094 | { | |
1095 | Function* func = this->u_.func_value; | |
97267c39 | 1096 | decl = function_to_tree(func->get_or_make_decl(gogo, this)); |
e440a328 | 1097 | if (decl != error_mark_node) |
1098 | { | |
1099 | if (func->block() != NULL) | |
1100 | { | |
1101 | if (DECL_STRUCT_FUNCTION(decl) == NULL) | |
1102 | push_struct_function(decl); | |
1103 | else | |
1104 | push_cfun(DECL_STRUCT_FUNCTION(decl)); | |
1105 | ||
266fa788 | 1106 | cfun->function_start_locus = func->location().gcc_location(); |
b13c66cd | 1107 | cfun->function_end_locus = |
1108 | func->block()->end_location().gcc_location(); | |
e440a328 | 1109 | |
e440a328 | 1110 | func->build_tree(gogo, this); |
1111 | ||
1112 | gimplify_function_tree(decl); | |
1113 | ||
1114 | cgraph_finalize_function(decl, true); | |
1115 | ||
e440a328 | 1116 | pop_cfun(); |
1117 | } | |
1118 | } | |
1119 | } | |
1120 | break; | |
1121 | ||
acf8e158 | 1122 | case NAMED_OBJECT_ERRONEOUS: |
1123 | decl = error_mark_node; | |
1124 | break; | |
1125 | ||
e440a328 | 1126 | default: |
c3e6f413 | 1127 | go_unreachable(); |
e440a328 | 1128 | } |
1129 | ||
1130 | if (TREE_TYPE(decl) == error_mark_node) | |
1131 | decl = error_mark_node; | |
1132 | ||
1133 | tree ret = decl; | |
1134 | ||
e440a328 | 1135 | this->tree_ = ret; |
1136 | ||
1137 | if (ret != error_mark_node) | |
1138 | go_preserve_from_gc(ret); | |
1139 | ||
1140 | return ret; | |
1141 | } | |
1142 | ||
1143 | // Get the initial value of a variable as a tree. This does not | |
1144 | // consider whether the variable is in the heap--it returns the | |
1145 | // initial value as though it were always stored in the stack. | |
1146 | ||
1147 | tree | |
1148 | Variable::get_init_tree(Gogo* gogo, Named_object* function) | |
1149 | { | |
c484d925 | 1150 | go_assert(this->preinit_ == NULL); |
e440a328 | 1151 | if (this->init_ == NULL) |
1152 | { | |
c484d925 | 1153 | go_assert(!this->is_parameter_); |
63697958 | 1154 | if (this->is_global_ || this->is_in_heap()) |
1155 | return NULL; | |
1156 | Btype* btype = this->type_->get_backend(gogo); | |
1157 | return expr_to_tree(gogo->backend()->zero_expression(btype)); | |
e440a328 | 1158 | } |
1159 | else | |
1160 | { | |
7e84be55 | 1161 | Translate_context context(gogo, function, NULL, NULL); |
e440a328 | 1162 | tree rhs_tree = this->init_->get_tree(&context); |
1163 | return Expression::convert_for_assignment(&context, this->type(), | |
1164 | this->init_->type(), | |
1165 | rhs_tree, this->location()); | |
1166 | } | |
1167 | } | |
1168 | ||
1169 | // Get the initial value of a variable when a block is required. | |
1170 | // VAR_DECL is the decl to set; it may be NULL for a sink variable. | |
1171 | ||
1172 | tree | |
1173 | Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl) | |
1174 | { | |
c484d925 | 1175 | go_assert(this->preinit_ != NULL); |
e440a328 | 1176 | |
1177 | // We want to add the variable assignment to the end of the preinit | |
1178 | // block. The preinit block may have a TRY_FINALLY_EXPR and a | |
1179 | // TRY_CATCH_EXPR; if it does, we want to add to the end of the | |
1180 | // regular statements. | |
1181 | ||
7e84be55 | 1182 | Translate_context context(gogo, function, NULL, NULL); |
1183 | Bblock* bblock = this->preinit_->get_backend(&context); | |
1184 | tree block_tree = block_to_tree(bblock); | |
f5c95e30 | 1185 | if (block_tree == error_mark_node) |
1186 | return error_mark_node; | |
c484d925 | 1187 | go_assert(TREE_CODE(block_tree) == BIND_EXPR); |
e440a328 | 1188 | tree statements = BIND_EXPR_BODY(block_tree); |
f5c95e30 | 1189 | while (statements != NULL_TREE |
1190 | && (TREE_CODE(statements) == TRY_FINALLY_EXPR | |
1191 | || TREE_CODE(statements) == TRY_CATCH_EXPR)) | |
e440a328 | 1192 | statements = TREE_OPERAND(statements, 0); |
1193 | ||
1194 | // It's possible to have pre-init statements without an initializer | |
1195 | // if the pre-init statements set the variable. | |
1196 | if (this->init_ != NULL) | |
1197 | { | |
1198 | tree rhs_tree = this->init_->get_tree(&context); | |
f5c95e30 | 1199 | if (rhs_tree == error_mark_node) |
1200 | return error_mark_node; | |
e440a328 | 1201 | if (var_decl == NULL_TREE) |
1202 | append_to_statement_list(rhs_tree, &statements); | |
1203 | else | |
1204 | { | |
1205 | tree val = Expression::convert_for_assignment(&context, this->type(), | |
1206 | this->init_->type(), | |
1207 | rhs_tree, | |
1208 | this->location()); | |
f5c95e30 | 1209 | if (val == error_mark_node) |
1210 | return error_mark_node; | |
b13c66cd | 1211 | tree set = fold_build2_loc(this->location().gcc_location(), |
1212 | MODIFY_EXPR, void_type_node, var_decl, | |
1213 | val); | |
e440a328 | 1214 | append_to_statement_list(set, &statements); |
1215 | } | |
1216 | } | |
1217 | ||
1218 | return block_tree; | |
1219 | } | |
1220 | ||
97267c39 | 1221 | // Get the backend representation. |
e440a328 | 1222 | |
97267c39 | 1223 | Bfunction* |
cf3cae55 | 1224 | Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no) |
e440a328 | 1225 | { |
cf3cae55 | 1226 | if (this->fndecl_ == NULL) |
e440a328 | 1227 | { |
1228 | // Let Go code use an asm declaration to pick up a builtin | |
1229 | // function. | |
1230 | if (!this->asm_name_.empty()) | |
1231 | { | |
1232 | std::map<std::string, tree>::const_iterator p = | |
1233 | builtin_functions.find(this->asm_name_); | |
1234 | if (p != builtin_functions.end()) | |
1235 | { | |
cf3cae55 | 1236 | this->fndecl_ = tree_to_function(p->second); |
97267c39 | 1237 | return this->fndecl_; |
e440a328 | 1238 | } |
1239 | } | |
1240 | ||
cf3cae55 | 1241 | std::string asm_name; |
1242 | if (this->asm_name_.empty()) | |
1243 | { | |
1244 | asm_name = (no->package() == NULL | |
1245 | ? gogo->pkgpath_symbol() | |
1246 | : no->package()->pkgpath_symbol()); | |
1247 | asm_name.append(1, '.'); | |
1248 | asm_name.append(Gogo::unpack_hidden_name(no->name())); | |
1249 | if (this->fntype_->is_method()) | |
1250 | { | |
1251 | asm_name.append(1, '.'); | |
1252 | Type* rtype = this->fntype_->receiver()->type(); | |
1253 | asm_name.append(rtype->mangled_name(gogo)); | |
1254 | } | |
1255 | } | |
8381eda7 | 1256 | |
cf3cae55 | 1257 | Btype* functype = this->fntype_->get_backend_fntype(gogo); |
1258 | this->fndecl_ = | |
1259 | gogo->backend()->function(functype, no->get_id(gogo), asm_name, | |
1260 | true, true, true, false, false, | |
1261 | this->location()); | |
1262 | } | |
8381eda7 | 1263 | |
97267c39 | 1264 | return this->fndecl_; |
cf3cae55 | 1265 | } |
e440a328 | 1266 | |
cf3cae55 | 1267 | // Return the function's decl after it has been built. |
1268 | ||
1269 | tree | |
1270 | Function::get_decl() const | |
1271 | { | |
1272 | go_assert(this->fndecl_ != NULL); | |
1273 | return function_to_tree(this->fndecl_); | |
e440a328 | 1274 | } |
1275 | ||
1276 | // We always pass the receiver to a method as a pointer. If the | |
1277 | // receiver is actually declared as a non-pointer type, then we copy | |
1278 | // the value into a local variable, so that it has the right type. In | |
1279 | // this function we create the real PARM_DECL to use, and set | |
1280 | // DEC_INITIAL of the var_decl to be the value passed in. | |
1281 | ||
1282 | tree | |
1283 | Function::make_receiver_parm_decl(Gogo* gogo, Named_object* no, tree var_decl) | |
1284 | { | |
0c88ddd8 | 1285 | if (var_decl == error_mark_node) |
1286 | return error_mark_node; | |
c484d925 | 1287 | go_assert(TREE_CODE(var_decl) == VAR_DECL); |
fe2f84cf | 1288 | tree val_type = TREE_TYPE(var_decl); |
e440a328 | 1289 | bool is_in_heap = no->var_value()->is_in_heap(); |
fe2f84cf | 1290 | if (is_in_heap) |
e440a328 | 1291 | { |
c484d925 | 1292 | go_assert(POINTER_TYPE_P(val_type)); |
fe2f84cf | 1293 | val_type = TREE_TYPE(val_type); |
e440a328 | 1294 | } |
fe2f84cf | 1295 | |
e440a328 | 1296 | source_location loc = DECL_SOURCE_LOCATION(var_decl); |
1297 | std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl)); | |
1298 | name += ".pointer"; | |
1299 | tree id = get_identifier_from_string(name); | |
1300 | tree parm_decl = build_decl(loc, PARM_DECL, id, build_pointer_type(val_type)); | |
1301 | DECL_CONTEXT(parm_decl) = current_function_decl; | |
1302 | DECL_ARG_TYPE(parm_decl) = TREE_TYPE(parm_decl); | |
1303 | ||
c484d925 | 1304 | go_assert(DECL_INITIAL(var_decl) == NULL_TREE); |
43c5cb70 | 1305 | tree init = build_fold_indirect_ref_loc(loc, parm_decl); |
e440a328 | 1306 | |
1307 | if (is_in_heap) | |
1308 | { | |
1309 | tree size = TYPE_SIZE_UNIT(val_type); | |
1310 | tree space = gogo->allocate_memory(no->var_value()->type(), size, | |
1311 | no->location()); | |
1312 | space = save_expr(space); | |
1313 | space = fold_convert(build_pointer_type(val_type), space); | |
b13c66cd | 1314 | tree spaceref = build_fold_indirect_ref_loc(no->location().gcc_location(), |
1315 | space); | |
e440a328 | 1316 | TREE_THIS_NOTRAP(spaceref) = 1; |
e440a328 | 1317 | tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node, |
43c5cb70 | 1318 | spaceref, init); |
1319 | init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space), set, space); | |
e440a328 | 1320 | } |
1321 | ||
1322 | DECL_INITIAL(var_decl) = init; | |
1323 | ||
1324 | return parm_decl; | |
1325 | } | |
1326 | ||
1327 | // If we take the address of a parameter, then we need to copy it into | |
1328 | // the heap. We will access it as a local variable via an | |
1329 | // indirection. | |
1330 | ||
1331 | tree | |
fe2f84cf | 1332 | Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree var_decl) |
e440a328 | 1333 | { |
0c88ddd8 | 1334 | if (var_decl == error_mark_node) |
1335 | return error_mark_node; | |
c484d925 | 1336 | go_assert(TREE_CODE(var_decl) == VAR_DECL); |
b13c66cd | 1337 | Location loc(DECL_SOURCE_LOCATION(var_decl)); |
e440a328 | 1338 | |
1339 | std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl)); | |
1340 | name += ".param"; | |
1341 | tree id = get_identifier_from_string(name); | |
1342 | ||
1343 | tree type = TREE_TYPE(var_decl); | |
c484d925 | 1344 | go_assert(POINTER_TYPE_P(type)); |
e440a328 | 1345 | type = TREE_TYPE(type); |
1346 | ||
b13c66cd | 1347 | tree parm_decl = build_decl(loc.gcc_location(), PARM_DECL, id, type); |
e440a328 | 1348 | DECL_CONTEXT(parm_decl) = current_function_decl; |
1349 | DECL_ARG_TYPE(parm_decl) = type; | |
1350 | ||
1351 | tree size = TYPE_SIZE_UNIT(type); | |
1352 | tree space = gogo->allocate_memory(no->var_value()->type(), size, loc); | |
1353 | space = save_expr(space); | |
1354 | space = fold_convert(TREE_TYPE(var_decl), space); | |
b13c66cd | 1355 | tree spaceref = build_fold_indirect_ref_loc(loc.gcc_location(), space); |
e440a328 | 1356 | TREE_THIS_NOTRAP(spaceref) = 1; |
1357 | tree init = build2(COMPOUND_EXPR, TREE_TYPE(space), | |
1358 | build2(MODIFY_EXPR, void_type_node, spaceref, parm_decl), | |
1359 | space); | |
1360 | DECL_INITIAL(var_decl) = init; | |
1361 | ||
1362 | return parm_decl; | |
1363 | } | |
1364 | ||
1365 | // Get a tree for function code. | |
1366 | ||
1367 | void | |
1368 | Function::build_tree(Gogo* gogo, Named_object* named_function) | |
1369 | { | |
cf3cae55 | 1370 | tree fndecl = this->get_decl(); |
c484d925 | 1371 | go_assert(fndecl != NULL_TREE); |
e440a328 | 1372 | |
1373 | tree params = NULL_TREE; | |
1374 | tree* pp = ¶ms; | |
1375 | ||
1376 | tree declare_vars = NULL_TREE; | |
1377 | for (Bindings::const_definitions_iterator p = | |
1378 | this->block_->bindings()->begin_definitions(); | |
1379 | p != this->block_->bindings()->end_definitions(); | |
1380 | ++p) | |
1381 | { | |
1382 | if ((*p)->is_variable() && (*p)->var_value()->is_parameter()) | |
1383 | { | |
fe2f84cf | 1384 | Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function); |
1385 | *pp = var_to_tree(bvar); | |
e440a328 | 1386 | |
1387 | // We always pass the receiver to a method as a pointer. If | |
1388 | // the receiver is declared as a non-pointer type, then we | |
1389 | // copy the value into a local variable. | |
1390 | if ((*p)->var_value()->is_receiver() | |
1391 | && (*p)->var_value()->type()->points_to() == NULL) | |
1392 | { | |
1393 | tree parm_decl = this->make_receiver_parm_decl(gogo, *p, *pp); | |
1394 | tree var = *pp; | |
0c88ddd8 | 1395 | if (var != error_mark_node) |
1396 | { | |
c484d925 | 1397 | go_assert(TREE_CODE(var) == VAR_DECL); |
0c88ddd8 | 1398 | DECL_CHAIN(var) = declare_vars; |
1399 | declare_vars = var; | |
1400 | } | |
e440a328 | 1401 | *pp = parm_decl; |
1402 | } | |
1403 | else if ((*p)->var_value()->is_in_heap()) | |
1404 | { | |
1405 | // If we take the address of a parameter, then we need | |
1406 | // to copy it into the heap. | |
1407 | tree parm_decl = this->copy_parm_to_heap(gogo, *p, *pp); | |
fe2f84cf | 1408 | tree var = *pp; |
1409 | if (var != error_mark_node) | |
0c88ddd8 | 1410 | { |
c484d925 | 1411 | go_assert(TREE_CODE(var) == VAR_DECL); |
fe2f84cf | 1412 | DECL_CHAIN(var) = declare_vars; |
1413 | declare_vars = var; | |
0c88ddd8 | 1414 | } |
e440a328 | 1415 | *pp = parm_decl; |
1416 | } | |
1417 | ||
1418 | if (*pp != error_mark_node) | |
1419 | { | |
c484d925 | 1420 | go_assert(TREE_CODE(*pp) == PARM_DECL); |
e440a328 | 1421 | pp = &DECL_CHAIN(*pp); |
1422 | } | |
1423 | } | |
1424 | else if ((*p)->is_result_variable()) | |
1425 | { | |
fe2f84cf | 1426 | Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function); |
1427 | tree var_decl = var_to_tree(bvar); | |
1428 | ||
1429 | Type* type = (*p)->result_var_value()->type(); | |
1430 | tree init; | |
1431 | if (!(*p)->result_var_value()->is_in_heap()) | |
63697958 | 1432 | { |
1433 | Btype* btype = type->get_backend(gogo); | |
1434 | init = expr_to_tree(gogo->backend()->zero_expression(btype)); | |
1435 | } | |
fe2f84cf | 1436 | else |
e440a328 | 1437 | { |
b13c66cd | 1438 | Location loc = (*p)->location(); |
9f0e0513 | 1439 | tree type_tree = type_to_tree(type->get_backend(gogo)); |
fe2f84cf | 1440 | tree space = gogo->allocate_memory(type, |
1441 | TYPE_SIZE_UNIT(type_tree), | |
1442 | loc); | |
1443 | tree ptr_type_tree = build_pointer_type(type_tree); | |
b13c66cd | 1444 | init = fold_convert_loc(loc.gcc_location(), ptr_type_tree, space); |
e440a328 | 1445 | } |
fe2f84cf | 1446 | |
ccb63574 | 1447 | if (var_decl != error_mark_node) |
1448 | { | |
c484d925 | 1449 | go_assert(TREE_CODE(var_decl) == VAR_DECL); |
fe2f84cf | 1450 | DECL_INITIAL(var_decl) = init; |
ccb63574 | 1451 | DECL_CHAIN(var_decl) = declare_vars; |
1452 | declare_vars = var_decl; | |
1453 | } | |
e440a328 | 1454 | } |
1455 | } | |
8381eda7 | 1456 | |
f8bdf81a | 1457 | *pp = NULL_TREE; |
1458 | ||
1459 | DECL_ARGUMENTS(fndecl) = params; | |
1460 | ||
1461 | // If we need a closure variable, fetch it by calling a runtime | |
1462 | // function. The caller will have called __go_set_closure before | |
1463 | // the function call. | |
8381eda7 | 1464 | if (this->closure_var_ != NULL) |
1465 | { | |
1466 | Bvariable* bvar = | |
1467 | this->closure_var_->get_backend_variable(gogo, named_function); | |
1468 | tree var_decl = var_to_tree(bvar); | |
1469 | if (var_decl != error_mark_node) | |
1470 | { | |
f8bdf81a | 1471 | go_assert(TREE_CODE(var_decl) == VAR_DECL); |
1472 | static tree get_closure_fndecl; | |
1473 | tree get_closure = Gogo::call_builtin(&get_closure_fndecl, | |
1474 | this->location_, | |
1475 | "__go_get_closure", | |
1476 | 0, | |
1477 | ptr_type_node); | |
1478 | ||
1479 | // Mark the __go_get_closure function as pure, since it | |
1480 | // depends only on the global variable g. | |
1481 | DECL_PURE_P(get_closure_fndecl) = 1; | |
1482 | ||
1483 | get_closure = fold_convert_loc(this->location_.gcc_location(), | |
1484 | TREE_TYPE(var_decl), get_closure); | |
1485 | DECL_INITIAL(var_decl) = get_closure; | |
1486 | DECL_CHAIN(var_decl) = declare_vars; | |
1487 | declare_vars = var_decl; | |
8381eda7 | 1488 | } |
1489 | } | |
e440a328 | 1490 | |
1491 | if (this->block_ != NULL) | |
1492 | { | |
c484d925 | 1493 | go_assert(DECL_INITIAL(fndecl) == NULL_TREE); |
e440a328 | 1494 | |
1495 | // Declare variables if necessary. | |
1496 | tree bind = NULL_TREE; | |
ca51434e | 1497 | tree defer_init = NULL_TREE; |
1498 | if (declare_vars != NULL_TREE || this->defer_stack_ != NULL) | |
e440a328 | 1499 | { |
1500 | tree block = make_node(BLOCK); | |
1501 | BLOCK_SUPERCONTEXT(block) = fndecl; | |
1502 | DECL_INITIAL(fndecl) = block; | |
1503 | BLOCK_VARS(block) = declare_vars; | |
1504 | TREE_USED(block) = 1; | |
ca51434e | 1505 | |
7e84be55 | 1506 | bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block), |
1507 | NULL_TREE, block); | |
1508 | TREE_SIDE_EFFECTS(bind) = 1; | |
1509 | ||
ca51434e | 1510 | if (this->defer_stack_ != NULL) |
1511 | { | |
1512 | Translate_context dcontext(gogo, named_function, this->block_, | |
7e84be55 | 1513 | tree_to_block(bind)); |
4cf30692 | 1514 | Bstatement* bdi = this->defer_stack_->get_backend(&dcontext); |
1515 | defer_init = stat_to_tree(bdi); | |
ca51434e | 1516 | } |
e440a328 | 1517 | } |
1518 | ||
1519 | // Build the trees for all the statements in the function. | |
7e84be55 | 1520 | Translate_context context(gogo, named_function, NULL, NULL); |
1521 | Bblock* bblock = this->block_->get_backend(&context); | |
1522 | tree code = block_to_tree(bblock); | |
e440a328 | 1523 | |
1524 | tree init = NULL_TREE; | |
1525 | tree except = NULL_TREE; | |
1526 | tree fini = NULL_TREE; | |
1527 | ||
1528 | // Initialize variables if necessary. | |
1529 | for (tree v = declare_vars; v != NULL_TREE; v = DECL_CHAIN(v)) | |
1530 | { | |
1531 | tree dv = build1(DECL_EXPR, void_type_node, v); | |
1532 | SET_EXPR_LOCATION(dv, DECL_SOURCE_LOCATION(v)); | |
1533 | append_to_statement_list(dv, &init); | |
1534 | } | |
1535 | ||
1536 | // If we have a defer stack, initialize it at the start of a | |
1537 | // function. | |
ca51434e | 1538 | if (defer_init != NULL_TREE && defer_init != error_mark_node) |
e440a328 | 1539 | { |
b13c66cd | 1540 | SET_EXPR_LOCATION(defer_init, |
1541 | this->block_->start_location().gcc_location()); | |
e440a328 | 1542 | append_to_statement_list(defer_init, &init); |
1543 | ||
1544 | // Clean up the defer stack when we leave the function. | |
1545 | this->build_defer_wrapper(gogo, named_function, &except, &fini); | |
1546 | } | |
1547 | ||
1548 | if (code != NULL_TREE && code != error_mark_node) | |
1549 | { | |
1550 | if (init != NULL_TREE) | |
1551 | code = build2(COMPOUND_EXPR, void_type_node, init, code); | |
1552 | if (except != NULL_TREE) | |
1553 | code = build2(TRY_CATCH_EXPR, void_type_node, code, | |
1554 | build2(CATCH_EXPR, void_type_node, NULL, except)); | |
1555 | if (fini != NULL_TREE) | |
1556 | code = build2(TRY_FINALLY_EXPR, void_type_node, code, fini); | |
1557 | } | |
1558 | ||
1559 | // Stick the code into the block we built for the receiver, if | |
1560 | // we built on. | |
1561 | if (bind != NULL_TREE && code != NULL_TREE && code != error_mark_node) | |
1562 | { | |
1563 | BIND_EXPR_BODY(bind) = code; | |
1564 | code = bind; | |
1565 | } | |
1566 | ||
1567 | DECL_SAVED_TREE(fndecl) = code; | |
1568 | } | |
8381eda7 | 1569 | |
1570 | // If we created a descriptor for the function, make sure we emit it. | |
1571 | if (this->descriptor_ != NULL) | |
1572 | { | |
1573 | Translate_context context(gogo, NULL, NULL, NULL); | |
1574 | this->descriptor_->get_tree(&context); | |
1575 | } | |
e440a328 | 1576 | } |
1577 | ||
1578 | // Build the wrappers around function code needed if the function has | |
1579 | // any defer statements. This sets *EXCEPT to an exception handler | |
1580 | // and *FINI to a finally handler. | |
1581 | ||
1582 | void | |
1583 | Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function, | |
1584 | tree *except, tree *fini) | |
1585 | { | |
b13c66cd | 1586 | Location end_loc = this->block_->end_location(); |
e440a328 | 1587 | |
1588 | // Add an exception handler. This is used if a panic occurs. Its | |
1589 | // purpose is to stop the stack unwinding if a deferred function | |
1590 | // calls recover. There are more details in | |
1591 | // libgo/runtime/go-unwind.c. | |
ca51434e | 1592 | |
e440a328 | 1593 | tree stmt_list = NULL_TREE; |
ca51434e | 1594 | |
1595 | Expression* call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1, | |
1596 | this->defer_stack(end_loc)); | |
1597 | Translate_context context(gogo, named_function, NULL, NULL); | |
1598 | tree call_tree = call->get_tree(&context); | |
1599 | if (call_tree != error_mark_node) | |
1600 | append_to_statement_list(call_tree, &stmt_list); | |
e440a328 | 1601 | |
1602 | tree retval = this->return_value(gogo, named_function, end_loc, &stmt_list); | |
1603 | tree set; | |
1604 | if (retval == NULL_TREE) | |
1605 | set = NULL_TREE; | |
1606 | else | |
b13c66cd | 1607 | set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node, |
cf3cae55 | 1608 | DECL_RESULT(this->get_decl()), retval); |
b13c66cd | 1609 | tree ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR, |
1610 | void_type_node, set); | |
e440a328 | 1611 | append_to_statement_list(ret_stmt, &stmt_list); |
1612 | ||
c484d925 | 1613 | go_assert(*except == NULL_TREE); |
e440a328 | 1614 | *except = stmt_list; |
1615 | ||
1616 | // Add some finally code to run the defer functions. This is used | |
1617 | // both in the normal case, when no panic occurs, and also if a | |
1618 | // panic occurs to run any further defer functions. Of course, it | |
1619 | // is possible for a defer function to call panic which should be | |
1620 | // caught by another defer function. To handle that we use a loop. | |
1621 | // finish: | |
1622 | // try { __go_undefer(); } catch { __go_check_defer(); goto finish; } | |
1623 | // if (return values are named) return named_vals; | |
1624 | ||
1625 | stmt_list = NULL; | |
1626 | ||
b13c66cd | 1627 | tree label = create_artificial_label(end_loc.gcc_location()); |
1628 | tree define_label = fold_build1_loc(end_loc.gcc_location(), LABEL_EXPR, | |
1629 | void_type_node, label); | |
e440a328 | 1630 | append_to_statement_list(define_label, &stmt_list); |
1631 | ||
ca51434e | 1632 | call = Runtime::make_call(Runtime::UNDEFER, end_loc, 1, |
1633 | this->defer_stack(end_loc)); | |
1634 | tree undefer = call->get_tree(&context); | |
1635 | ||
1636 | call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1, | |
1637 | this->defer_stack(end_loc)); | |
1638 | tree defer = call->get_tree(&context); | |
1639 | ||
1640 | if (undefer == error_mark_node || defer == error_mark_node) | |
1641 | return; | |
1642 | ||
b13c66cd | 1643 | tree jump = fold_build1_loc(end_loc.gcc_location(), GOTO_EXPR, void_type_node, |
1644 | label); | |
e440a328 | 1645 | tree catch_body = build2(COMPOUND_EXPR, void_type_node, defer, jump); |
1646 | catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body); | |
1647 | tree try_catch = build2(TRY_CATCH_EXPR, void_type_node, undefer, catch_body); | |
1648 | ||
1649 | append_to_statement_list(try_catch, &stmt_list); | |
1650 | ||
1651 | if (this->type_->results() != NULL | |
1652 | && !this->type_->results()->empty() | |
1653 | && !this->type_->results()->front().name().empty()) | |
1654 | { | |
05d63fcf | 1655 | // If the result variables are named, and we are returning from |
1656 | // this function rather than panicing through it, we need to | |
1657 | // return them again, because they might have been changed by a | |
1658 | // defer function. The runtime routines set the defer_stack | |
1659 | // variable to true if we are returning from this function. | |
e440a328 | 1660 | retval = this->return_value(gogo, named_function, end_loc, |
1661 | &stmt_list); | |
b13c66cd | 1662 | set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node, |
cf3cae55 | 1663 | DECL_RESULT(this->get_decl()), retval); |
b13c66cd | 1664 | ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR, |
1665 | void_type_node, set); | |
05d63fcf | 1666 | |
1667 | Expression* ref = | |
1668 | Expression::make_temporary_reference(this->defer_stack_, end_loc); | |
1669 | tree tref = ref->get_tree(&context); | |
b13c66cd | 1670 | tree s = build3_loc(end_loc.gcc_location(), COND_EXPR, void_type_node, |
1671 | tref, ret_stmt, NULL_TREE); | |
05d63fcf | 1672 | |
1673 | append_to_statement_list(s, &stmt_list); | |
1674 | ||
e440a328 | 1675 | } |
1676 | ||
c484d925 | 1677 | go_assert(*fini == NULL_TREE); |
e440a328 | 1678 | *fini = stmt_list; |
1679 | } | |
1680 | ||
cf3cae55 | 1681 | // Return the value to assign to DECL_RESULT(this->get_decl()). This may |
e440a328 | 1682 | // also add statements to STMT_LIST, which need to be executed before |
1683 | // the assignment. This is used for a return statement with no | |
1684 | // explicit values. | |
1685 | ||
1686 | tree | |
1687 | Function::return_value(Gogo* gogo, Named_object* named_function, | |
b13c66cd | 1688 | Location location, tree* stmt_list) const |
e440a328 | 1689 | { |
1690 | const Typed_identifier_list* results = this->type_->results(); | |
1691 | if (results == NULL || results->empty()) | |
1692 | return NULL_TREE; | |
1693 | ||
c484d925 | 1694 | go_assert(this->results_ != NULL); |
be2fc38d | 1695 | if (this->results_->size() != results->size()) |
2b714b74 | 1696 | { |
c484d925 | 1697 | go_assert(saw_errors()); |
be2fc38d | 1698 | return error_mark_node; |
2b714b74 | 1699 | } |
e440a328 | 1700 | |
1701 | tree retval; | |
1702 | if (results->size() == 1) | |
fe2f84cf | 1703 | { |
1704 | Bvariable* bvar = | |
1705 | this->results_->front()->get_backend_variable(gogo, | |
1706 | named_function); | |
1707 | tree ret = var_to_tree(bvar); | |
1708 | if (this->results_->front()->result_var_value()->is_in_heap()) | |
b13c66cd | 1709 | ret = build_fold_indirect_ref_loc(location.gcc_location(), ret); |
fe2f84cf | 1710 | return ret; |
1711 | } | |
e440a328 | 1712 | else |
1713 | { | |
cf3cae55 | 1714 | tree rettype = TREE_TYPE(DECL_RESULT(this->get_decl())); |
e440a328 | 1715 | retval = create_tmp_var(rettype, "RESULT"); |
1716 | tree field = TYPE_FIELDS(rettype); | |
1717 | int index = 0; | |
1718 | for (Typed_identifier_list::const_iterator pr = results->begin(); | |
1719 | pr != results->end(); | |
1720 | ++pr, ++index, field = DECL_CHAIN(field)) | |
1721 | { | |
c484d925 | 1722 | go_assert(field != NULL); |
fe2f84cf | 1723 | Named_object* no = (*this->results_)[index]; |
1724 | Bvariable* bvar = no->get_backend_variable(gogo, named_function); | |
1725 | tree val = var_to_tree(bvar); | |
1726 | if (no->result_var_value()->is_in_heap()) | |
b13c66cd | 1727 | val = build_fold_indirect_ref_loc(location.gcc_location(), val); |
1728 | tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR, | |
1729 | void_type_node, | |
e440a328 | 1730 | build3(COMPONENT_REF, TREE_TYPE(field), |
1731 | retval, field, NULL_TREE), | |
1732 | val); | |
1733 | append_to_statement_list(set, stmt_list); | |
1734 | } | |
1735 | return retval; | |
1736 | } | |
1737 | } | |
1738 | ||
8381eda7 | 1739 | // Build the descriptor for a function declaration. This won't |
1740 | // necessarily happen if the package has just a declaration for the | |
1741 | // function and no other reference to it, but we may still need the | |
1742 | // descriptor for references from other packages. | |
1743 | void | |
1744 | Function_declaration::build_backend_descriptor(Gogo* gogo) | |
1745 | { | |
1746 | if (this->descriptor_ != NULL) | |
1747 | { | |
1748 | Translate_context context(gogo, NULL, NULL, NULL); | |
1749 | this->descriptor_->get_tree(&context); | |
1750 | } | |
1751 | } | |
1752 | ||
e440a328 | 1753 | // Return the integer type to use for a size. |
1754 | ||
1755 | GO_EXTERN_C | |
1756 | tree | |
1757 | go_type_for_size(unsigned int bits, int unsignedp) | |
1758 | { | |
1759 | const char* name; | |
1760 | switch (bits) | |
1761 | { | |
1762 | case 8: | |
1763 | name = unsignedp ? "uint8" : "int8"; | |
1764 | break; | |
1765 | case 16: | |
1766 | name = unsignedp ? "uint16" : "int16"; | |
1767 | break; | |
1768 | case 32: | |
1769 | name = unsignedp ? "uint32" : "int32"; | |
1770 | break; | |
1771 | case 64: | |
1772 | name = unsignedp ? "uint64" : "int64"; | |
1773 | break; | |
1774 | default: | |
1775 | if (bits == POINTER_SIZE && unsignedp) | |
1776 | name = "uintptr"; | |
1777 | else | |
1778 | return NULL_TREE; | |
1779 | } | |
1780 | Type* type = Type::lookup_integer_type(name); | |
9f0e0513 | 1781 | return type_to_tree(type->get_backend(go_get_gogo())); |
e440a328 | 1782 | } |
1783 | ||
1784 | // Return the type to use for a mode. | |
1785 | ||
1786 | GO_EXTERN_C | |
1787 | tree | |
1788 | go_type_for_mode(enum machine_mode mode, int unsignedp) | |
1789 | { | |
1790 | // FIXME: This static_cast should be in machmode.h. | |
1791 | enum mode_class mc = static_cast<enum mode_class>(GET_MODE_CLASS(mode)); | |
1792 | if (mc == MODE_INT) | |
1793 | return go_type_for_size(GET_MODE_BITSIZE(mode), unsignedp); | |
1794 | else if (mc == MODE_FLOAT) | |
1795 | { | |
1796 | Type* type; | |
1797 | switch (GET_MODE_BITSIZE (mode)) | |
1798 | { | |
1799 | case 32: | |
1800 | type = Type::lookup_float_type("float32"); | |
1801 | break; | |
1802 | case 64: | |
1803 | type = Type::lookup_float_type("float64"); | |
1804 | break; | |
1805 | default: | |
1806 | // We have to check for long double in order to support | |
1807 | // i386 excess precision. | |
1808 | if (mode == TYPE_MODE(long_double_type_node)) | |
1809 | return long_double_type_node; | |
1810 | return NULL_TREE; | |
1811 | } | |
9f0e0513 | 1812 | return type_to_tree(type->get_backend(go_get_gogo())); |
e440a328 | 1813 | } |
1814 | else if (mc == MODE_COMPLEX_FLOAT) | |
1815 | { | |
1816 | Type *type; | |
1817 | switch (GET_MODE_BITSIZE (mode)) | |
1818 | { | |
1819 | case 64: | |
1820 | type = Type::lookup_complex_type("complex64"); | |
1821 | break; | |
1822 | case 128: | |
1823 | type = Type::lookup_complex_type("complex128"); | |
1824 | break; | |
1825 | default: | |
1826 | // We have to check for long double in order to support | |
1827 | // i386 excess precision. | |
1828 | if (mode == TYPE_MODE(complex_long_double_type_node)) | |
1829 | return complex_long_double_type_node; | |
1830 | return NULL_TREE; | |
1831 | } | |
9f0e0513 | 1832 | return type_to_tree(type->get_backend(go_get_gogo())); |
e440a328 | 1833 | } |
1834 | else | |
1835 | return NULL_TREE; | |
1836 | } | |
1837 | ||
1838 | // Return a tree which allocates SIZE bytes which will holds value of | |
1839 | // type TYPE. | |
1840 | ||
1841 | tree | |
b13c66cd | 1842 | Gogo::allocate_memory(Type* type, tree size, Location location) |
e440a328 | 1843 | { |
1844 | // If the package imports unsafe, then it may play games with | |
1845 | // pointers that look like integers. | |
1846 | if (this->imported_unsafe_ || type->has_pointer()) | |
1847 | { | |
1848 | static tree new_fndecl; | |
1849 | return Gogo::call_builtin(&new_fndecl, | |
1850 | location, | |
1851 | "__go_new", | |
1852 | 1, | |
1853 | ptr_type_node, | |
1854 | sizetype, | |
1855 | size); | |
1856 | } | |
1857 | else | |
1858 | { | |
1859 | static tree new_nopointers_fndecl; | |
1860 | return Gogo::call_builtin(&new_nopointers_fndecl, | |
1861 | location, | |
1862 | "__go_new_nopointers", | |
1863 | 1, | |
1864 | ptr_type_node, | |
1865 | sizetype, | |
1866 | size); | |
1867 | } | |
1868 | } | |
1869 | ||
1870 | // Build a builtin struct with a list of fields. The name is | |
1871 | // STRUCT_NAME. STRUCT_TYPE is NULL_TREE or an empty RECORD_TYPE | |
1872 | // node; this exists so that the struct can have fields which point to | |
1873 | // itself. If PTYPE is not NULL, store the result in *PTYPE. There | |
1874 | // are NFIELDS fields. Each field is a name (a const char*) followed | |
1875 | // by a type (a tree). | |
1876 | ||
1877 | tree | |
1878 | Gogo::builtin_struct(tree* ptype, const char* struct_name, tree struct_type, | |
1879 | int nfields, ...) | |
1880 | { | |
1881 | if (ptype != NULL && *ptype != NULL_TREE) | |
1882 | return *ptype; | |
1883 | ||
1884 | va_list ap; | |
1885 | va_start(ap, nfields); | |
1886 | ||
1887 | tree fields = NULL_TREE; | |
1888 | for (int i = 0; i < nfields; ++i) | |
1889 | { | |
1890 | const char* field_name = va_arg(ap, const char*); | |
1891 | tree type = va_arg(ap, tree); | |
1892 | if (type == error_mark_node) | |
1893 | { | |
1894 | if (ptype != NULL) | |
1895 | *ptype = error_mark_node; | |
1896 | return error_mark_node; | |
1897 | } | |
1898 | tree field = build_decl(BUILTINS_LOCATION, FIELD_DECL, | |
1899 | get_identifier(field_name), type); | |
1900 | DECL_CHAIN(field) = fields; | |
1901 | fields = field; | |
1902 | } | |
1903 | ||
1904 | va_end(ap); | |
1905 | ||
1906 | if (struct_type == NULL_TREE) | |
1907 | struct_type = make_node(RECORD_TYPE); | |
1908 | finish_builtin_struct(struct_type, struct_name, fields, NULL_TREE); | |
1909 | ||
1910 | if (ptype != NULL) | |
1911 | { | |
1912 | go_preserve_from_gc(struct_type); | |
1913 | *ptype = struct_type; | |
1914 | } | |
1915 | ||
1916 | return struct_type; | |
1917 | } | |
1918 | ||
1919 | // Return a type to use for pointer to const char for a string. | |
1920 | ||
1921 | tree | |
1922 | Gogo::const_char_pointer_type_tree() | |
1923 | { | |
1924 | static tree type; | |
1925 | if (type == NULL_TREE) | |
1926 | { | |
1927 | tree const_char_type = build_qualified_type(unsigned_char_type_node, | |
1928 | TYPE_QUAL_CONST); | |
1929 | type = build_pointer_type(const_char_type); | |
1930 | go_preserve_from_gc(type); | |
1931 | } | |
1932 | return type; | |
1933 | } | |
1934 | ||
1935 | // Return a tree for a string constant. | |
1936 | ||
1937 | tree | |
1938 | Gogo::string_constant_tree(const std::string& val) | |
1939 | { | |
1940 | tree index_type = build_index_type(size_int(val.length())); | |
1941 | tree const_char_type = build_qualified_type(unsigned_char_type_node, | |
1942 | TYPE_QUAL_CONST); | |
1943 | tree string_type = build_array_type(const_char_type, index_type); | |
1944 | string_type = build_variant_type_copy(string_type); | |
1945 | TYPE_STRING_FLAG(string_type) = 1; | |
1946 | tree string_val = build_string(val.length(), val.data()); | |
1947 | TREE_TYPE(string_val) = string_type; | |
1948 | return string_val; | |
1949 | } | |
1950 | ||
1951 | // Return a tree for a Go string constant. | |
1952 | ||
1953 | tree | |
1954 | Gogo::go_string_constant_tree(const std::string& val) | |
1955 | { | |
9f0e0513 | 1956 | tree string_type = type_to_tree(Type::make_string_type()->get_backend(this)); |
e440a328 | 1957 | |
95f84544 | 1958 | vec<constructor_elt, va_gc> *init; |
1959 | vec_alloc(init, 2); | |
e440a328 | 1960 | |
e82e4eb5 | 1961 | constructor_elt empty = {NULL, NULL}; |
95f84544 | 1962 | constructor_elt* elt = init->quick_push(empty); |
e440a328 | 1963 | tree field = TYPE_FIELDS(string_type); |
c484d925 | 1964 | go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__data") == 0); |
e440a328 | 1965 | elt->index = field; |
1966 | tree str = Gogo::string_constant_tree(val); | |
1967 | elt->value = fold_convert(TREE_TYPE(field), | |
1968 | build_fold_addr_expr(str)); | |
1969 | ||
95f84544 | 1970 | elt = init->quick_push(empty); |
e440a328 | 1971 | field = DECL_CHAIN(field); |
c484d925 | 1972 | go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__length") == 0); |
e440a328 | 1973 | elt->index = field; |
1974 | elt->value = build_int_cst_type(TREE_TYPE(field), val.length()); | |
1975 | ||
1976 | tree constructor = build_constructor(string_type, init); | |
1977 | TREE_READONLY(constructor) = 1; | |
1978 | TREE_CONSTANT(constructor) = 1; | |
1979 | ||
1980 | return constructor; | |
1981 | } | |
1982 | ||
1983 | // Return a tree for a pointer to a Go string constant. This is only | |
1984 | // used for type descriptors, so we return a pointer to a constant | |
1985 | // decl. | |
1986 | ||
1987 | tree | |
1988 | Gogo::ptr_go_string_constant_tree(const std::string& val) | |
1989 | { | |
1990 | tree pval = this->go_string_constant_tree(val); | |
1991 | ||
1992 | tree decl = build_decl(UNKNOWN_LOCATION, VAR_DECL, | |
1993 | create_tmp_var_name("SP"), TREE_TYPE(pval)); | |
1994 | DECL_EXTERNAL(decl) = 0; | |
1995 | TREE_PUBLIC(decl) = 0; | |
1996 | TREE_USED(decl) = 1; | |
1997 | TREE_READONLY(decl) = 1; | |
1998 | TREE_CONSTANT(decl) = 1; | |
1999 | TREE_STATIC(decl) = 1; | |
2000 | DECL_ARTIFICIAL(decl) = 1; | |
2001 | DECL_INITIAL(decl) = pval; | |
2002 | rest_of_decl_compilation(decl, 1, 0); | |
2003 | ||
2004 | return build_fold_addr_expr(decl); | |
2005 | } | |
2006 | ||
e440a328 | 2007 | // Build a constructor for a slice. SLICE_TYPE_TREE is the type of |
2008 | // the slice. VALUES is the value pointer and COUNT is the number of | |
2009 | // entries. If CAPACITY is not NULL, it is the capacity; otherwise | |
2010 | // the capacity and the count are the same. | |
2011 | ||
2012 | tree | |
2013 | Gogo::slice_constructor(tree slice_type_tree, tree values, tree count, | |
2014 | tree capacity) | |
2015 | { | |
c484d925 | 2016 | go_assert(TREE_CODE(slice_type_tree) == RECORD_TYPE); |
e440a328 | 2017 | |
95f84544 | 2018 | vec<constructor_elt, va_gc> *init; |
2019 | vec_alloc(init, 3); | |
e440a328 | 2020 | |
2021 | tree field = TYPE_FIELDS(slice_type_tree); | |
c484d925 | 2022 | go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0); |
e82e4eb5 | 2023 | constructor_elt empty = {NULL, NULL}; |
95f84544 | 2024 | constructor_elt* elt = init->quick_push(empty); |
e440a328 | 2025 | elt->index = field; |
c484d925 | 2026 | go_assert(TYPE_MAIN_VARIANT(TREE_TYPE(field)) |
e440a328 | 2027 | == TYPE_MAIN_VARIANT(TREE_TYPE(values))); |
2028 | elt->value = values; | |
2029 | ||
2030 | count = fold_convert(sizetype, count); | |
2031 | if (capacity == NULL_TREE) | |
2032 | { | |
2033 | count = save_expr(count); | |
2034 | capacity = count; | |
2035 | } | |
2036 | ||
2037 | field = DECL_CHAIN(field); | |
c484d925 | 2038 | go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0); |
95f84544 | 2039 | elt = init->quick_push(empty); |
e440a328 | 2040 | elt->index = field; |
2041 | elt->value = fold_convert(TREE_TYPE(field), count); | |
2042 | ||
2043 | field = DECL_CHAIN(field); | |
c484d925 | 2044 | go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0); |
95f84544 | 2045 | elt = init->quick_push(empty); |
e440a328 | 2046 | elt->index = field; |
2047 | elt->value = fold_convert(TREE_TYPE(field), capacity); | |
2048 | ||
2049 | return build_constructor(slice_type_tree, init); | |
2050 | } | |
2051 | ||
e440a328 | 2052 | // Build an interface method table for a type: a list of function |
2053 | // pointers, one for each interface method. This is used for | |
2054 | // interfaces. | |
2055 | ||
2056 | tree | |
2057 | Gogo::interface_method_table_for_type(const Interface_type* interface, | |
c0cab2ec | 2058 | Type* type, bool is_pointer) |
e440a328 | 2059 | { |
2060 | const Typed_identifier_list* interface_methods = interface->methods(); | |
c484d925 | 2061 | go_assert(!interface_methods->empty()); |
e440a328 | 2062 | |
2063 | std::string mangled_name = ((is_pointer ? "__go_pimt__" : "__go_imt_") | |
2064 | + interface->mangled_name(this) | |
2065 | + "__" | |
2066 | + type->mangled_name(this)); | |
2067 | ||
2068 | tree id = get_identifier_from_string(mangled_name); | |
2069 | ||
2070 | // See whether this interface has any hidden methods. | |
2071 | bool has_hidden_methods = false; | |
2072 | for (Typed_identifier_list::const_iterator p = interface_methods->begin(); | |
2073 | p != interface_methods->end(); | |
2074 | ++p) | |
2075 | { | |
2076 | if (Gogo::is_hidden_name(p->name())) | |
2077 | { | |
2078 | has_hidden_methods = true; | |
2079 | break; | |
2080 | } | |
2081 | } | |
2082 | ||
2083 | // We already know that the named type is convertible to the | |
2084 | // interface. If the interface has hidden methods, and the named | |
2085 | // type is defined in a different package, then the interface | |
2086 | // conversion table will be defined by that other package. | |
c0cab2ec | 2087 | if (has_hidden_methods |
2088 | && type->named_type() != NULL | |
2089 | && type->named_type()->named_object()->package() != NULL) | |
e440a328 | 2090 | { |
2091 | tree array_type = build_array_type(const_ptr_type_node, NULL); | |
2092 | tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type); | |
2093 | TREE_READONLY(decl) = 1; | |
2094 | TREE_CONSTANT(decl) = 1; | |
2095 | TREE_PUBLIC(decl) = 1; | |
2096 | DECL_EXTERNAL(decl) = 1; | |
2097 | go_preserve_from_gc(decl); | |
2098 | return decl; | |
2099 | } | |
2100 | ||
2101 | size_t count = interface_methods->size(); | |
95f84544 | 2102 | vec<constructor_elt, va_gc> *pointers; |
2103 | vec_alloc(pointers, count + 1); | |
e440a328 | 2104 | |
2105 | // The first element is the type descriptor. | |
e82e4eb5 | 2106 | constructor_elt empty = {NULL, NULL}; |
95f84544 | 2107 | constructor_elt* elt = pointers->quick_push(empty); |
e440a328 | 2108 | elt->index = size_zero_node; |
2109 | Type* td_type; | |
2110 | if (!is_pointer) | |
2111 | td_type = type; | |
2112 | else | |
2113 | td_type = Type::make_pointer_type(type); | |
175a4612 | 2114 | |
2115 | Location loc = Linemap::predeclared_location(); | |
2116 | Bexpression* tdp_bexpr = td_type->type_descriptor_pointer(this, loc); | |
2117 | tree tdp = expr_to_tree(tdp_bexpr); | |
a1d23b41 | 2118 | elt->value = fold_convert(const_ptr_type_node, tdp); |
e440a328 | 2119 | |
c0cab2ec | 2120 | Named_type* nt = type->named_type(); |
2121 | Struct_type* st = type->struct_type(); | |
2122 | go_assert(nt != NULL || st != NULL); | |
e440a328 | 2123 | size_t i = 1; |
2124 | for (Typed_identifier_list::const_iterator p = interface_methods->begin(); | |
2125 | p != interface_methods->end(); | |
2126 | ++p, ++i) | |
2127 | { | |
2128 | bool is_ambiguous; | |
c0cab2ec | 2129 | Method* m; |
2130 | if (nt != NULL) | |
2131 | m = nt->method_function(p->name(), &is_ambiguous); | |
2132 | else | |
2133 | m = st->method_function(p->name(), &is_ambiguous); | |
c484d925 | 2134 | go_assert(m != NULL); |
e440a328 | 2135 | |
2136 | Named_object* no = m->named_object(); | |
97267c39 | 2137 | Bfunction* bf; |
e440a328 | 2138 | if (no->is_function()) |
97267c39 | 2139 | bf = no->func_value()->get_or_make_decl(this, no); |
e440a328 | 2140 | else if (no->is_function_declaration()) |
97267c39 | 2141 | bf = no->func_declaration_value()->get_or_make_decl(this, no); |
e440a328 | 2142 | else |
c3e6f413 | 2143 | go_unreachable(); |
97267c39 | 2144 | tree fndecl = build_fold_addr_expr(function_to_tree(bf)); |
e440a328 | 2145 | |
95f84544 | 2146 | elt = pointers->quick_push(empty); |
e440a328 | 2147 | elt->index = size_int(i); |
2148 | elt->value = fold_convert(const_ptr_type_node, fndecl); | |
2149 | } | |
c484d925 | 2150 | go_assert(i == count + 1); |
e440a328 | 2151 | |
2152 | tree array_type = build_array_type(const_ptr_type_node, | |
2153 | build_index_type(size_int(count))); | |
2154 | tree constructor = build_constructor(array_type, pointers); | |
2155 | ||
2156 | tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type); | |
2157 | TREE_STATIC(decl) = 1; | |
2158 | TREE_USED(decl) = 1; | |
2159 | TREE_READONLY(decl) = 1; | |
2160 | TREE_CONSTANT(decl) = 1; | |
2161 | DECL_INITIAL(decl) = constructor; | |
2162 | ||
c3865819 | 2163 | // If the interface type has hidden methods, and the table is for a |
2164 | // named type, then this is the only definition of the table. | |
2165 | // Otherwise it is a comdat table which may be defined in multiple | |
2166 | // packages. | |
2167 | if (has_hidden_methods && type->named_type() != NULL) | |
2cd86edf | 2168 | TREE_PUBLIC(decl) = 1; |
e440a328 | 2169 | else |
2170 | { | |
2171 | make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl)); | |
2172 | resolve_unique_section(decl, 1, 0); | |
2173 | } | |
2174 | ||
2175 | rest_of_decl_compilation(decl, 1, 0); | |
2176 | ||
2177 | go_preserve_from_gc(decl); | |
2178 | ||
2179 | return decl; | |
2180 | } | |
2181 | ||
2182 | // Mark a function as a builtin library function. | |
2183 | ||
2184 | void | |
2185 | Gogo::mark_fndecl_as_builtin_library(tree fndecl) | |
2186 | { | |
2187 | DECL_EXTERNAL(fndecl) = 1; | |
2188 | TREE_PUBLIC(fndecl) = 1; | |
2189 | DECL_ARTIFICIAL(fndecl) = 1; | |
2190 | TREE_NOTHROW(fndecl) = 1; | |
2191 | DECL_VISIBILITY(fndecl) = VISIBILITY_DEFAULT; | |
2192 | DECL_VISIBILITY_SPECIFIED(fndecl) = 1; | |
2193 | } | |
2194 | ||
2195 | // Build a call to a builtin function. | |
2196 | ||
2197 | tree | |
b13c66cd | 2198 | Gogo::call_builtin(tree* pdecl, Location location, const char* name, |
e440a328 | 2199 | int nargs, tree rettype, ...) |
2200 | { | |
2201 | if (rettype == error_mark_node) | |
2202 | return error_mark_node; | |
2203 | ||
2204 | tree* types = new tree[nargs]; | |
2205 | tree* args = new tree[nargs]; | |
2206 | ||
2207 | va_list ap; | |
2208 | va_start(ap, rettype); | |
2209 | for (int i = 0; i < nargs; ++i) | |
2210 | { | |
2211 | types[i] = va_arg(ap, tree); | |
2212 | args[i] = va_arg(ap, tree); | |
2213 | if (types[i] == error_mark_node || args[i] == error_mark_node) | |
cf609de4 | 2214 | { |
2215 | delete[] types; | |
2216 | delete[] args; | |
2217 | return error_mark_node; | |
2218 | } | |
e440a328 | 2219 | } |
2220 | va_end(ap); | |
2221 | ||
2222 | if (*pdecl == NULL_TREE) | |
2223 | { | |
2224 | tree fnid = get_identifier(name); | |
2225 | ||
2226 | tree argtypes = NULL_TREE; | |
2227 | tree* pp = &argtypes; | |
2228 | for (int i = 0; i < nargs; ++i) | |
2229 | { | |
2230 | *pp = tree_cons(NULL_TREE, types[i], NULL_TREE); | |
2231 | pp = &TREE_CHAIN(*pp); | |
2232 | } | |
2233 | *pp = void_list_node; | |
2234 | ||
2235 | tree fntype = build_function_type(rettype, argtypes); | |
2236 | ||
2237 | *pdecl = build_decl(BUILTINS_LOCATION, FUNCTION_DECL, fnid, fntype); | |
2238 | Gogo::mark_fndecl_as_builtin_library(*pdecl); | |
2239 | go_preserve_from_gc(*pdecl); | |
2240 | } | |
2241 | ||
2242 | tree fnptr = build_fold_addr_expr(*pdecl); | |
2243 | if (CAN_HAVE_LOCATION_P(fnptr)) | |
b13c66cd | 2244 | SET_EXPR_LOCATION(fnptr, location.gcc_location()); |
e440a328 | 2245 | |
2246 | tree ret = build_call_array(rettype, fnptr, nargs, args); | |
b13c66cd | 2247 | SET_EXPR_LOCATION(ret, location.gcc_location()); |
e440a328 | 2248 | |
2249 | delete[] types; | |
2250 | delete[] args; | |
2251 | ||
2252 | return ret; | |
2253 | } | |
2254 | ||
2255 | // Build a call to the runtime error function. | |
2256 | ||
2257 | tree | |
b13c66cd | 2258 | Gogo::runtime_error(int code, Location location) |
e440a328 | 2259 | { |
1b1f2abf | 2260 | Type* int32_type = Type::lookup_integer_type("int32"); |
2261 | tree int32_type_tree = type_to_tree(int32_type->get_backend(this)); | |
2262 | ||
e440a328 | 2263 | static tree runtime_error_fndecl; |
2264 | tree ret = Gogo::call_builtin(&runtime_error_fndecl, | |
2265 | location, | |
2266 | "__go_runtime_error", | |
2267 | 1, | |
2268 | void_type_node, | |
1b1f2abf | 2269 | int32_type_tree, |
2270 | build_int_cst(int32_type_tree, code)); | |
5fb82b5e | 2271 | if (ret == error_mark_node) |
2272 | return error_mark_node; | |
e440a328 | 2273 | // The runtime error function panics and does not return. |
2274 | TREE_NOTHROW(runtime_error_fndecl) = 0; | |
2275 | TREE_THIS_VOLATILE(runtime_error_fndecl) = 1; | |
2276 | return ret; | |
2277 | } | |
2278 | ||
e440a328 | 2279 | // Return a tree for receiving a value of type TYPE_TREE on CHANNEL. |
f24f10bb | 2280 | // TYPE_DESCRIPTOR_TREE is the channel's type descriptor. This does a |
2281 | // blocking receive and returns the value read from the channel. | |
e440a328 | 2282 | |
2283 | tree | |
f24f10bb | 2284 | Gogo::receive_from_channel(tree type_tree, tree type_descriptor_tree, |
2285 | tree channel, Location location) | |
e440a328 | 2286 | { |
df7a26e9 | 2287 | if (type_tree == error_mark_node || channel == error_mark_node) |
2288 | return error_mark_node; | |
2289 | ||
e440a328 | 2290 | if (int_size_in_bytes(type_tree) <= 8 |
2291 | && !AGGREGATE_TYPE_P(type_tree) | |
2292 | && !FLOAT_TYPE_P(type_tree)) | |
2293 | { | |
2294 | static tree receive_small_fndecl; | |
2295 | tree call = Gogo::call_builtin(&receive_small_fndecl, | |
2296 | location, | |
2297 | "__go_receive_small", | |
2298 | 2, | |
2299 | uint64_type_node, | |
f24f10bb | 2300 | TREE_TYPE(type_descriptor_tree), |
2301 | type_descriptor_tree, | |
e440a328 | 2302 | ptr_type_node, |
f24f10bb | 2303 | channel); |
5fb82b5e | 2304 | if (call == error_mark_node) |
2305 | return error_mark_node; | |
e440a328 | 2306 | // This can panic if there are too many operations on a closed |
2307 | // channel. | |
2308 | TREE_NOTHROW(receive_small_fndecl) = 0; | |
2309 | int bitsize = GET_MODE_BITSIZE(TYPE_MODE(type_tree)); | |
2310 | tree int_type_tree = go_type_for_size(bitsize, 1); | |
b13c66cd | 2311 | return fold_convert_loc(location.gcc_location(), type_tree, |
2312 | fold_convert_loc(location.gcc_location(), | |
2313 | int_type_tree, call)); | |
e440a328 | 2314 | } |
2315 | else | |
2316 | { | |
2317 | tree tmp = create_tmp_var(type_tree, get_name(type_tree)); | |
2318 | DECL_IGNORED_P(tmp) = 0; | |
2319 | TREE_ADDRESSABLE(tmp) = 1; | |
2320 | tree make_tmp = build1(DECL_EXPR, void_type_node, tmp); | |
b13c66cd | 2321 | SET_EXPR_LOCATION(make_tmp, location.gcc_location()); |
e440a328 | 2322 | tree tmpaddr = build_fold_addr_expr(tmp); |
2323 | tmpaddr = fold_convert(ptr_type_node, tmpaddr); | |
2324 | static tree receive_big_fndecl; | |
2325 | tree call = Gogo::call_builtin(&receive_big_fndecl, | |
2326 | location, | |
2327 | "__go_receive_big", | |
2328 | 3, | |
f24f10bb | 2329 | void_type_node, |
2330 | TREE_TYPE(type_descriptor_tree), | |
2331 | type_descriptor_tree, | |
e440a328 | 2332 | ptr_type_node, |
2333 | channel, | |
2334 | ptr_type_node, | |
f24f10bb | 2335 | tmpaddr); |
5fb82b5e | 2336 | if (call == error_mark_node) |
2337 | return error_mark_node; | |
e440a328 | 2338 | // This can panic if there are too many operations on a closed |
2339 | // channel. | |
2340 | TREE_NOTHROW(receive_big_fndecl) = 0; | |
2341 | return build2(COMPOUND_EXPR, type_tree, make_tmp, | |
2342 | build2(COMPOUND_EXPR, type_tree, call, tmp)); | |
2343 | } | |
2344 | } |