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