]>
Commit | Line | Data |
---|---|---|
35485da9 | 1 | /* Internals of libgccjit: classes for playing back recorded API calls. |
7adcbafe | 2 | Copyright (C) 2013-2022 Free Software Foundation, Inc. |
35485da9 DM |
3 | Contributed by David Malcolm <dmalcolm@redhat.com>. |
4 | ||
5 | This file is part of GCC. | |
6 | ||
7 | GCC is free software; you can redistribute it and/or modify it | |
8 | under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GCC is distributed in the hope that it will be useful, but | |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GCC; see the file COPYING3. If not see | |
19 | <http://www.gnu.org/licenses/>. */ | |
20 | ||
21 | #include "config.h" | |
22 | #include "system.h" | |
23 | #include "coretypes.h" | |
2adfab87 | 24 | #include "target.h" |
2adfab87 | 25 | #include "tree.h" |
2adfab87 AM |
26 | #include "stringpool.h" |
27 | #include "cgraph.h" | |
35485da9 | 28 | #include "dumpfile.h" |
35485da9 | 29 | #include "toplev.h" |
35485da9 | 30 | #include "tree-cfg.h" |
35485da9 | 31 | #include "convert.h" |
35485da9 DM |
32 | #include "stor-layout.h" |
33 | #include "print-tree.h" | |
34 | #include "gimplify.h" | |
35 | #include "gcc-driver-name.h" | |
eeafb319 | 36 | #include "attribs.h" |
463366a0 | 37 | #include "context.h" |
860e981c | 38 | #include "fold-const.h" |
98086b2b | 39 | #include "opt-suggestions.h" |
2cb844ce | 40 | #include "gcc.h" |
6b5423a5 | 41 | #include "diagnostic.h" |
421d0d0f | 42 | #include "stmt.h" |
35485da9 | 43 | |
1c652ccb IB |
44 | #include <pthread.h> |
45 | ||
35485da9 | 46 | #include "jit-playback.h" |
56dea35f | 47 | #include "jit-result.h" |
eeafb319 | 48 | #include "jit-builtins.h" |
d1e5f2c7 | 49 | #include "jit-tempdir.h" |
35485da9 | 50 | |
c83027f3 NB |
51 | #ifdef _WIN32 |
52 | #include "jit-w32.h" | |
53 | #endif | |
54 | ||
ee118c14 AC |
55 | /* Compare with gcc/c-family/c-common.h: DECL_C_BIT_FIELD, |
56 | SET_DECL_C_BIT_FIELD. | |
57 | These are redefined here to avoid depending from the C frontend. */ | |
58 | #define DECL_JIT_BIT_FIELD(NODE) \ | |
59 | (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1) | |
60 | #define SET_DECL_JIT_BIT_FIELD(NODE) \ | |
61 | (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1) | |
35485da9 DM |
62 | |
63 | /* gcc::jit::playback::context::build_cast uses the convert.h API, | |
64 | which in turn requires the frontend to provide a "convert" | |
5cca4131 AB |
65 | function, apparently as a fallback for casts that can be simplified |
66 | (truncation, extension). */ | |
35485da9 DM |
67 | extern tree convert (tree type, tree expr); |
68 | ||
69 | tree | |
70 | convert (tree dst_type, tree expr) | |
71 | { | |
5cca4131 AB |
72 | tree t_ret = NULL; |
73 | t_ret = targetm.convert_to_type (dst_type, expr); | |
74 | if (t_ret) | |
75 | return t_ret; | |
76 | switch (TREE_CODE (dst_type)) | |
77 | { | |
78 | case INTEGER_TYPE: | |
79 | case ENUMERAL_TYPE: | |
80 | return fold (convert_to_integer (dst_type, expr)); | |
81 | ||
82 | default: | |
83 | gcc_assert (gcc::jit::active_playback_ctxt); | |
84 | gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion"); | |
85 | fprintf (stderr, "input expression:\n"); | |
86 | debug_tree (expr); | |
87 | fprintf (stderr, "requested type:\n"); | |
88 | debug_tree (dst_type); | |
89 | return error_mark_node; | |
90 | } | |
35485da9 DM |
91 | } |
92 | ||
93 | namespace gcc { | |
94 | namespace jit { | |
95 | ||
96 | /********************************************************************** | |
97 | Playback. | |
98 | **********************************************************************/ | |
99 | ||
37368378 PT |
100 | /* Fold a readonly non-volatile variable with an initial constant value, |
101 | to that value. | |
102 | ||
103 | Otherwise return the argument unchanged. | |
104 | ||
105 | This fold is needed for setting a variable's DECL_INITIAL to the value | |
106 | of a const variable. The c-frontend does this in its own special | |
107 | fold (), so we lift this part out and do it explicitly where there is a | |
108 | potential for variables to be used as rvalues. */ | |
109 | static tree | |
110 | fold_const_var (tree node) | |
111 | { | |
e53b6e56 ML |
112 | /* See c_fully_fold_internal in c-fold.cc and decl_constant_value_1 |
113 | in c-typeck.cc. */ | |
37368378 PT |
114 | if (VAR_P (node) |
115 | && TREE_READONLY (node) | |
116 | && !TREE_THIS_VOLATILE (node) | |
117 | && DECL_INITIAL (node) != NULL_TREE | |
118 | /* "This is invalid if initial value is not constant. | |
119 | If it has either a function call, a memory reference, | |
120 | or a variable, then re-evaluating it could give different | |
121 | results." */ | |
122 | && TREE_CONSTANT (DECL_INITIAL (node))) | |
123 | { | |
124 | tree ret = DECL_INITIAL (node); | |
125 | /* "Avoid unwanted tree sharing between the initializer and current | |
126 | function's body where the tree can be modified e.g. by the | |
127 | gimplifier." */ | |
128 | if (TREE_STATIC (node)) | |
129 | ret = unshare_expr (ret); | |
130 | ||
131 | return ret; | |
132 | } | |
133 | ||
134 | return node; | |
135 | } | |
136 | ||
421d0d0f DM |
137 | /* Build a STRING_CST tree for STR, or return NULL if it is NULL. |
138 | The TREE_TYPE is not initialized. */ | |
139 | ||
140 | static tree | |
141 | build_string (const char *str) | |
142 | { | |
143 | if (str) | |
144 | return ::build_string (strlen (str), str); | |
145 | else | |
146 | return NULL_TREE; | |
147 | } | |
148 | ||
35485da9 DM |
149 | /* The constructor for gcc::jit::playback::context. */ |
150 | ||
151 | playback::context::context (recording::context *ctxt) | |
eb4c16eb DM |
152 | : log_user (ctxt->get_logger ()), |
153 | m_recording_ctxt (ctxt), | |
d1e5f2c7 | 154 | m_tempdir (NULL), |
35485da9 DM |
155 | m_const_char_ptr (NULL) |
156 | { | |
eb4c16eb | 157 | JIT_LOG_SCOPE (get_logger ()); |
35485da9 | 158 | m_functions.create (0); |
791cfef8 | 159 | m_globals.create (0); |
35485da9 DM |
160 | m_source_files.create (0); |
161 | m_cached_locations.create (0); | |
162 | } | |
163 | ||
164 | /* The destructor for gcc::jit::playback::context. */ | |
165 | ||
166 | playback::context::~context () | |
167 | { | |
eb4c16eb | 168 | JIT_LOG_SCOPE (get_logger ()); |
d2286af3 DM |
169 | |
170 | /* Normally the playback::context is responsible for cleaning up the | |
171 | tempdir (including "fake.so" within the filesystem). | |
172 | ||
173 | In the normal case, clean it up now. | |
174 | ||
175 | However m_tempdir can be NULL if the context has handed over | |
176 | responsibility for the tempdir cleanup to the jit::result object, so | |
177 | that the cleanup can be delayed (see PR jit/64206). If that's the | |
178 | case this "delete NULL;" is a no-op. */ | |
179 | delete m_tempdir; | |
180 | ||
35485da9 DM |
181 | m_functions.release (); |
182 | } | |
183 | ||
184 | /* A playback::context can reference GC-managed pointers. Mark them | |
185 | ("by hand", rather than by gengtype). | |
186 | ||
187 | This is called on the active playback context (if any) by the | |
e53b6e56 | 188 | my_ggc_walker hook in the jit_root_table in dummy-frontend.cc. */ |
35485da9 DM |
189 | |
190 | void | |
191 | playback::context:: | |
192 | gt_ggc_mx () | |
193 | { | |
194 | int i; | |
195 | function *func; | |
196 | FOR_EACH_VEC_ELT (m_functions, i, func) | |
197 | { | |
198 | if (ggc_test_and_set_mark (func)) | |
199 | func->gt_ggc_mx (); | |
200 | } | |
201 | } | |
202 | ||
203 | /* Given an enum gcc_jit_types value, get a "tree" type. */ | |
204 | ||
332a9f76 PT |
205 | tree |
206 | playback::context:: | |
35485da9 DM |
207 | get_tree_node_for_type (enum gcc_jit_types type_) |
208 | { | |
209 | switch (type_) | |
210 | { | |
211 | case GCC_JIT_TYPE_VOID: | |
212 | return void_type_node; | |
213 | ||
214 | case GCC_JIT_TYPE_VOID_PTR: | |
215 | return ptr_type_node; | |
216 | ||
217 | case GCC_JIT_TYPE_BOOL: | |
218 | return boolean_type_node; | |
219 | ||
220 | case GCC_JIT_TYPE_CHAR: | |
221 | return char_type_node; | |
222 | case GCC_JIT_TYPE_SIGNED_CHAR: | |
223 | return signed_char_type_node; | |
224 | case GCC_JIT_TYPE_UNSIGNED_CHAR: | |
225 | return unsigned_char_type_node; | |
226 | ||
227 | case GCC_JIT_TYPE_SHORT: | |
228 | return short_integer_type_node; | |
229 | case GCC_JIT_TYPE_UNSIGNED_SHORT: | |
230 | return short_unsigned_type_node; | |
231 | ||
232 | case GCC_JIT_TYPE_CONST_CHAR_PTR: | |
332a9f76 | 233 | return m_const_char_ptr; |
35485da9 DM |
234 | |
235 | case GCC_JIT_TYPE_INT: | |
236 | return integer_type_node; | |
237 | case GCC_JIT_TYPE_UNSIGNED_INT: | |
238 | return unsigned_type_node; | |
239 | ||
240 | case GCC_JIT_TYPE_LONG: | |
241 | return long_integer_type_node; | |
242 | case GCC_JIT_TYPE_UNSIGNED_LONG: | |
243 | return long_unsigned_type_node; | |
244 | ||
245 | case GCC_JIT_TYPE_LONG_LONG: | |
246 | return long_long_integer_type_node; | |
247 | case GCC_JIT_TYPE_UNSIGNED_LONG_LONG: | |
248 | return long_long_unsigned_type_node; | |
249 | ||
250 | case GCC_JIT_TYPE_FLOAT: | |
251 | return float_type_node; | |
252 | case GCC_JIT_TYPE_DOUBLE: | |
253 | return double_type_node; | |
254 | case GCC_JIT_TYPE_LONG_DOUBLE: | |
255 | return long_double_type_node; | |
256 | ||
257 | case GCC_JIT_TYPE_SIZE_T: | |
258 | return size_type_node; | |
259 | ||
260 | case GCC_JIT_TYPE_FILE_PTR: | |
261 | return fileptr_type_node; | |
eeafb319 DM |
262 | |
263 | case GCC_JIT_TYPE_COMPLEX_FLOAT: | |
264 | return complex_float_type_node; | |
265 | case GCC_JIT_TYPE_COMPLEX_DOUBLE: | |
266 | return complex_double_type_node; | |
267 | case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE: | |
268 | return complex_long_double_type_node; | |
35485da9 DM |
269 | } |
270 | ||
271 | return NULL; | |
272 | } | |
273 | ||
274 | /* Construct a playback::type instance (wrapping a tree) for the given | |
275 | enum value. */ | |
276 | ||
277 | playback::type * | |
278 | playback::context:: | |
279 | get_type (enum gcc_jit_types type_) | |
280 | { | |
281 | tree type_node = get_tree_node_for_type (type_); | |
01512446 | 282 | if (type_node == NULL) |
35485da9 | 283 | { |
01512446 | 284 | add_error (NULL, "unrecognized (enum gcc_jit_types) value: %i", type_); |
35485da9 DM |
285 | return NULL; |
286 | } | |
287 | ||
288 | return new type (type_node); | |
289 | } | |
290 | ||
291 | /* Construct a playback::type instance (wrapping a tree) for the given | |
292 | array type. */ | |
293 | ||
294 | playback::type * | |
295 | playback::context:: | |
296 | new_array_type (playback::location *loc, | |
297 | playback::type *element_type, | |
298 | int num_elements) | |
299 | { | |
300 | gcc_assert (element_type); | |
301 | ||
302 | tree t = build_array_type_nelts (element_type->as_tree (), | |
303 | num_elements); | |
304 | layout_type (t); | |
305 | ||
306 | if (loc) | |
307 | set_tree_location (t, loc); | |
308 | ||
309 | return new type (t); | |
310 | } | |
311 | ||
312 | /* Construct a playback::field instance (wrapping a tree). */ | |
313 | ||
314 | playback::field * | |
315 | playback::context:: | |
316 | new_field (location *loc, | |
317 | type *type, | |
318 | const char *name) | |
319 | { | |
320 | gcc_assert (type); | |
321 | gcc_assert (name); | |
322 | ||
e53b6e56 | 323 | /* compare with c/c-decl.cc:grokfield and grokdeclarator. */ |
35485da9 DM |
324 | tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL, |
325 | get_identifier (name), type->as_tree ()); | |
326 | ||
327 | if (loc) | |
328 | set_tree_location (decl, loc); | |
329 | ||
330 | return new field (decl); | |
331 | } | |
332 | ||
ee118c14 AC |
333 | /* Construct a playback::bitfield instance (wrapping a tree). */ |
334 | ||
335 | playback::field * | |
336 | playback::context:: | |
337 | new_bitfield (location *loc, | |
338 | type *type, | |
339 | int width, | |
340 | const char *name) | |
341 | { | |
342 | gcc_assert (type); | |
343 | gcc_assert (name); | |
344 | gcc_assert (width); | |
345 | ||
e53b6e56 | 346 | /* compare with c/c-decl.cc:grokfield, grokdeclarator and |
ee118c14 AC |
347 | check_bitfield_type_and_width. */ |
348 | ||
349 | tree tree_type = type->as_tree (); | |
350 | gcc_assert (INTEGRAL_TYPE_P (tree_type)); | |
351 | tree tree_width = build_int_cst (integer_type_node, width); | |
352 | if (compare_tree_int (tree_width, TYPE_PRECISION (tree_type)) > 0) | |
353 | { | |
354 | add_error ( | |
355 | loc, | |
356 | "width of bit-field %s (width: %i) is wider than its type (width: %i)", | |
357 | name, width, TYPE_PRECISION (tree_type)); | |
358 | return NULL; | |
359 | } | |
360 | ||
361 | tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL, | |
362 | get_identifier (name), type->as_tree ()); | |
363 | DECL_NONADDRESSABLE_P (decl) = true; | |
364 | DECL_INITIAL (decl) = tree_width; | |
365 | SET_DECL_JIT_BIT_FIELD (decl); | |
366 | ||
367 | if (loc) | |
368 | set_tree_location (decl, loc); | |
369 | ||
370 | return new field (decl); | |
371 | } | |
372 | ||
35485da9 DM |
373 | /* Construct a playback::compound_type instance (wrapping a tree). */ |
374 | ||
375 | playback::compound_type * | |
376 | playback::context:: | |
377 | new_compound_type (location *loc, | |
378 | const char *name, | |
379 | bool is_struct) /* else is union */ | |
380 | { | |
381 | gcc_assert (name); | |
382 | ||
e53b6e56 | 383 | /* Compare with c/c-decl.cc: start_struct. */ |
35485da9 DM |
384 | |
385 | tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE); | |
386 | TYPE_NAME (t) = get_identifier (name); | |
387 | TYPE_SIZE (t) = 0; | |
388 | ||
389 | if (loc) | |
390 | set_tree_location (t, loc); | |
391 | ||
392 | return new compound_type (t); | |
393 | } | |
394 | ||
395 | void | |
b957b2e0 | 396 | playback::compound_type::set_fields (const auto_vec<playback::field *> *fields) |
35485da9 | 397 | { |
e53b6e56 | 398 | /* Compare with c/c-decl.cc: finish_struct. */ |
35485da9 DM |
399 | tree t = as_tree (); |
400 | ||
401 | tree fieldlist = NULL; | |
b957b2e0 | 402 | for (unsigned i = 0; i < fields->length (); i++) |
35485da9 | 403 | { |
b957b2e0 | 404 | field *f = (*fields)[i]; |
ee118c14 AC |
405 | tree x = f->as_tree (); |
406 | DECL_CONTEXT (x) = t; | |
407 | if (DECL_JIT_BIT_FIELD (x)) | |
408 | { | |
409 | unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (x)); | |
410 | DECL_SIZE (x) = bitsize_int (width); | |
411 | DECL_BIT_FIELD (x) = 1; | |
412 | } | |
413 | fieldlist = chainon (x, fieldlist); | |
35485da9 DM |
414 | } |
415 | fieldlist = nreverse (fieldlist); | |
416 | TYPE_FIELDS (t) = fieldlist; | |
417 | ||
418 | layout_type (t); | |
419 | } | |
420 | ||
421 | /* Construct a playback::type instance (wrapping a tree) for a function | |
422 | type. */ | |
423 | ||
424 | playback::type * | |
425 | playback::context:: | |
426 | new_function_type (type *return_type, | |
b957b2e0 | 427 | const auto_vec<type *> *param_types, |
35485da9 DM |
428 | int is_variadic) |
429 | { | |
430 | int i; | |
431 | type *param_type; | |
432 | ||
433 | tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*)); | |
434 | ||
435 | FOR_EACH_VEC_ELT (*param_types, i, param_type) | |
436 | arg_types[i] = param_type->as_tree (); | |
437 | ||
438 | tree fn_type; | |
439 | if (is_variadic) | |
440 | fn_type = | |
441 | build_varargs_function_type_array (return_type->as_tree (), | |
442 | param_types->length (), | |
443 | arg_types); | |
444 | else | |
445 | fn_type = build_function_type_array (return_type->as_tree (), | |
446 | param_types->length (), | |
447 | arg_types); | |
448 | free (arg_types); | |
449 | ||
450 | return new type (fn_type); | |
451 | } | |
452 | ||
453 | /* Construct a playback::param instance (wrapping a tree). */ | |
454 | ||
455 | playback::param * | |
456 | playback::context:: | |
457 | new_param (location *loc, | |
458 | type *type, | |
459 | const char *name) | |
460 | { | |
461 | gcc_assert (type); | |
462 | gcc_assert (name); | |
463 | tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL, | |
464 | get_identifier (name), type->as_tree ()); | |
465 | if (loc) | |
466 | set_tree_location (inner, loc); | |
467 | ||
468 | return new param (this, inner); | |
469 | } | |
470 | ||
471 | /* Construct a playback::function instance. */ | |
472 | ||
473 | playback::function * | |
474 | playback::context:: | |
475 | new_function (location *loc, | |
476 | enum gcc_jit_function_kind kind, | |
477 | type *return_type, | |
478 | const char *name, | |
b957b2e0 | 479 | const auto_vec<param *> *params, |
35485da9 DM |
480 | int is_variadic, |
481 | enum built_in_function builtin_id) | |
482 | { | |
483 | int i; | |
484 | param *param; | |
485 | ||
486 | //can return_type be NULL? | |
487 | gcc_assert (name); | |
488 | ||
489 | tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*)); | |
490 | FOR_EACH_VEC_ELT (*params, i, param) | |
491 | arg_types[i] = TREE_TYPE (param->as_tree ()); | |
492 | ||
493 | tree fn_type; | |
494 | if (is_variadic) | |
495 | fn_type = build_varargs_function_type_array (return_type->as_tree (), | |
496 | params->length (), arg_types); | |
497 | else | |
498 | fn_type = build_function_type_array (return_type->as_tree (), | |
499 | params->length (), arg_types); | |
500 | free (arg_types); | |
501 | ||
502 | /* FIXME: this uses input_location: */ | |
503 | tree fndecl = build_fn_decl (name, fn_type); | |
504 | ||
505 | if (loc) | |
506 | set_tree_location (fndecl, loc); | |
507 | ||
508 | tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, | |
509 | NULL_TREE, return_type->as_tree ()); | |
510 | DECL_ARTIFICIAL (resdecl) = 1; | |
511 | DECL_IGNORED_P (resdecl) = 1; | |
512 | DECL_RESULT (fndecl) = resdecl; | |
a2f4b4b7 | 513 | DECL_CONTEXT (resdecl) = fndecl; |
35485da9 DM |
514 | |
515 | if (builtin_id) | |
516 | { | |
35485da9 DM |
517 | gcc_assert (loc == NULL); |
518 | DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION; | |
eeafb319 | 519 | |
4d732405 RS |
520 | built_in_class fclass = builtins_manager::get_class (builtin_id); |
521 | set_decl_built_in_function (fndecl, fclass, builtin_id); | |
eeafb319 DM |
522 | set_builtin_decl (builtin_id, fndecl, |
523 | builtins_manager::implicit_p (builtin_id)); | |
524 | ||
525 | builtins_manager *bm = get_builtins_manager (); | |
526 | tree attrs = bm->get_attrs_tree (builtin_id); | |
527 | if (attrs) | |
528 | decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN); | |
529 | else | |
530 | decl_attributes (&fndecl, NULL_TREE, 0); | |
35485da9 DM |
531 | } |
532 | ||
533 | if (kind != GCC_JIT_FUNCTION_IMPORTED) | |
534 | { | |
535 | tree param_decl_list = NULL; | |
536 | FOR_EACH_VEC_ELT (*params, i, param) | |
537 | { | |
538 | param_decl_list = chainon (param->as_tree (), param_decl_list); | |
539 | } | |
540 | ||
541 | /* The param list was created in reverse order; fix it: */ | |
542 | param_decl_list = nreverse (param_decl_list); | |
543 | ||
544 | tree t; | |
545 | for (t = param_decl_list; t; t = DECL_CHAIN (t)) | |
546 | { | |
547 | DECL_CONTEXT (t) = fndecl; | |
548 | DECL_ARG_TYPE (t) = TREE_TYPE (t); | |
549 | } | |
550 | ||
551 | /* Set it up on DECL_ARGUMENTS */ | |
552 | DECL_ARGUMENTS(fndecl) = param_decl_list; | |
553 | } | |
554 | ||
555 | if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE) | |
556 | { | |
557 | DECL_DECLARED_INLINE_P (fndecl) = 1; | |
558 | ||
559 | /* Add attribute "always_inline": */ | |
560 | DECL_ATTRIBUTES (fndecl) = | |
561 | tree_cons (get_identifier ("always_inline"), | |
562 | NULL, | |
563 | DECL_ATTRIBUTES (fndecl)); | |
564 | } | |
565 | ||
566 | function *func = new function (this, fndecl, kind); | |
567 | m_functions.safe_push (func); | |
568 | return func; | |
569 | } | |
570 | ||
4ecc0061 | 571 | /* In use by new_global and new_global_initialized. */ |
35485da9 | 572 | |
4ecc0061 | 573 | tree |
35485da9 | 574 | playback::context:: |
4ecc0061 AC |
575 | global_new_decl (location *loc, |
576 | enum gcc_jit_global_kind kind, | |
577 | type *type, | |
37368378 PT |
578 | const char *name, |
579 | enum global_var_flags flags) | |
35485da9 DM |
580 | { |
581 | gcc_assert (type); | |
582 | gcc_assert (name); | |
37368378 PT |
583 | |
584 | tree type_tree = type->as_tree (); | |
585 | ||
35485da9 DM |
586 | tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL, |
587 | get_identifier (name), | |
37368378 PT |
588 | type_tree); |
589 | ||
791cfef8 | 590 | TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL); |
37368378 PT |
591 | |
592 | ||
593 | int will_be_init = flags & (GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT | | |
594 | GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT); | |
595 | ||
596 | /* A VAR_DECL with DECL_INITIAL will not end up in .common section. */ | |
597 | if (!will_be_init) | |
598 | DECL_COMMON (inner) = 1; | |
599 | ||
791cfef8 DM |
600 | switch (kind) |
601 | { | |
602 | default: | |
603 | gcc_unreachable (); | |
604 | ||
605 | case GCC_JIT_GLOBAL_EXPORTED: | |
606 | TREE_STATIC (inner) = 1; | |
607 | break; | |
608 | ||
609 | case GCC_JIT_GLOBAL_INTERNAL: | |
610 | TREE_STATIC (inner) = 1; | |
611 | break; | |
612 | ||
613 | case GCC_JIT_GLOBAL_IMPORTED: | |
614 | DECL_EXTERNAL (inner) = 1; | |
615 | break; | |
616 | } | |
35485da9 | 617 | |
37368378 PT |
618 | if (TYPE_READONLY (type_tree)) |
619 | TREE_READONLY (inner) = 1; | |
620 | ||
35485da9 DM |
621 | if (loc) |
622 | set_tree_location (inner, loc); | |
623 | ||
4ecc0061 AC |
624 | return inner; |
625 | } | |
626 | ||
627 | /* In use by new_global and new_global_initialized. */ | |
628 | ||
629 | playback::lvalue * | |
630 | playback::context:: | |
631 | global_finalize_lvalue (tree inner) | |
632 | { | |
791cfef8 DM |
633 | m_globals.safe_push (inner); |
634 | ||
35485da9 DM |
635 | return new lvalue (this, inner); |
636 | } | |
637 | ||
4ecc0061 AC |
638 | /* Construct a playback::lvalue instance (wrapping a tree). */ |
639 | ||
640 | playback::lvalue * | |
641 | playback::context:: | |
642 | new_global (location *loc, | |
643 | enum gcc_jit_global_kind kind, | |
644 | type *type, | |
37368378 PT |
645 | const char *name, |
646 | enum global_var_flags flags) | |
4ecc0061 | 647 | { |
37368378 PT |
648 | tree inner = |
649 | global_new_decl (loc, kind, type, name, flags); | |
4ecc0061 AC |
650 | |
651 | return global_finalize_lvalue (inner); | |
652 | } | |
653 | ||
37368378 PT |
654 | void |
655 | playback::context:: | |
656 | global_set_init_rvalue (lvalue* variable, | |
657 | rvalue* init) | |
658 | { | |
659 | tree inner = variable->as_tree (); | |
660 | ||
661 | /* We need to fold all expressions as much as possible. The code | |
662 | for a DECL_INITIAL only handles some operations, | |
663 | etc addition, minus, 'address of'. See output_addressed_constants () | |
e53b6e56 | 664 | in varasm.cc. */ |
37368378 PT |
665 | tree init_tree = init->as_tree (); |
666 | tree folded = fold_const_var (init_tree); | |
667 | ||
668 | if (!TREE_CONSTANT (folded)) | |
669 | { | |
670 | tree name = DECL_NAME (inner); | |
671 | ||
672 | if (name != NULL_TREE) | |
673 | add_error (NULL, | |
674 | "unable to convert initial value for the global variable %s" | |
675 | " to a compile-time constant", | |
676 | IDENTIFIER_POINTER (name)); | |
677 | else | |
678 | add_error (NULL, | |
679 | "unable to convert initial value for global variable" | |
680 | " to a compile-time constant"); | |
681 | return; | |
682 | } | |
683 | ||
684 | DECL_INITIAL (inner) = folded; | |
685 | } | |
686 | ||
687 | playback::rvalue * | |
688 | playback::context:: | |
689 | new_ctor (location *loc, | |
690 | type *type, | |
691 | const auto_vec<field*> *fields, | |
692 | const auto_vec<rvalue*> *rvalues) | |
693 | { | |
694 | tree type_tree = type->as_tree (); | |
695 | ||
696 | /* Handle empty ctors first. I.e. set everything to 0. */ | |
697 | if (rvalues->length () == 0) | |
698 | return new rvalue (this, build_constructor (type_tree, NULL)); | |
699 | ||
700 | /* Handle arrays (and return). */ | |
701 | if (TREE_CODE (type_tree) == ARRAY_TYPE) | |
702 | { | |
703 | int n = rvalues->length (); | |
704 | /* The vec for the constructor node. */ | |
705 | vec<constructor_elt, va_gc> *v = NULL; | |
706 | vec_alloc (v, n); | |
707 | ||
708 | for (int i = 0; i < n; i++) | |
709 | { | |
710 | rvalue *rv = (*rvalues)[i]; | |
711 | /* null rvalues indicate that the element should be zeroed. */ | |
712 | if (rv) | |
713 | CONSTRUCTOR_APPEND_ELT (v, | |
714 | build_int_cst (size_type_node, i), | |
715 | rv->as_tree ()); | |
716 | else | |
717 | CONSTRUCTOR_APPEND_ELT (v, | |
718 | build_int_cst (size_type_node, i), | |
719 | build_zero_cst (TREE_TYPE (type_tree))); | |
720 | } | |
721 | ||
722 | tree ctor = build_constructor (type_tree, v); | |
723 | ||
724 | if (loc) | |
725 | set_tree_location (ctor, loc); | |
726 | ||
727 | return new rvalue (this, ctor); | |
728 | } | |
729 | ||
730 | /* Handle structs and unions. */ | |
731 | int n = fields->length (); | |
732 | ||
733 | /* The vec for the constructor node. */ | |
734 | vec<constructor_elt, va_gc> *v = NULL; | |
735 | vec_alloc (v, n); | |
736 | ||
737 | /* Iterate over the fields, building initializations. */ | |
738 | for (int i = 0;i < n; i++) | |
739 | { | |
740 | tree field = (*fields)[i]->as_tree (); | |
741 | rvalue *rv = (*rvalues)[i]; | |
742 | /* If the value is NULL, it means we should zero the field. */ | |
743 | if (rv) | |
744 | CONSTRUCTOR_APPEND_ELT (v, field, rv->as_tree ()); | |
745 | else | |
746 | { | |
747 | tree zero_cst = build_zero_cst (TREE_TYPE (field)); | |
748 | CONSTRUCTOR_APPEND_ELT (v, field, zero_cst); | |
749 | } | |
750 | } | |
751 | ||
752 | tree ctor = build_constructor (type_tree, v); | |
753 | ||
754 | if (loc) | |
755 | set_tree_location (ctor, loc); | |
756 | ||
757 | return new rvalue (this, build_constructor (type_tree, v)); | |
758 | } | |
759 | ||
4ecc0061 AC |
760 | /* Fill 'constructor_elements' with the memory content of |
761 | 'initializer'. Each element of the initializer is of the size of | |
762 | type T. In use by new_global_initialized.*/ | |
763 | ||
764 | template<typename T> | |
765 | static void | |
766 | load_blob_in_ctor (vec<constructor_elt, va_gc> *&constructor_elements, | |
767 | size_t num_elem, | |
768 | const void *initializer) | |
769 | { | |
e53b6e56 | 770 | /* Loosely based on 'output_init_element' c-typeck.cc:9691. */ |
4ecc0061 AC |
771 | const T *p = (const T *)initializer; |
772 | tree node = make_unsigned_type (BITS_PER_UNIT * sizeof (T)); | |
773 | for (size_t i = 0; i < num_elem; i++) | |
774 | { | |
775 | constructor_elt celt = | |
776 | { build_int_cst (long_unsigned_type_node, i), | |
777 | build_int_cst (node, p[i]) }; | |
778 | vec_safe_push (constructor_elements, celt); | |
779 | } | |
780 | } | |
781 | ||
782 | /* Construct an initialized playback::lvalue instance (wrapping a | |
783 | tree). */ | |
784 | ||
785 | playback::lvalue * | |
786 | playback::context:: | |
787 | new_global_initialized (location *loc, | |
788 | enum gcc_jit_global_kind kind, | |
789 | type *type, | |
790 | size_t element_size, | |
791 | size_t initializer_num_elem, | |
792 | const void *initializer, | |
37368378 PT |
793 | const char *name, |
794 | enum global_var_flags flags) | |
4ecc0061 | 795 | { |
37368378 | 796 | tree inner = global_new_decl (loc, kind, type, name, flags); |
4ecc0061 AC |
797 | |
798 | vec<constructor_elt, va_gc> *constructor_elements = NULL; | |
799 | ||
800 | switch (element_size) | |
801 | { | |
802 | case 1: | |
803 | load_blob_in_ctor<uint8_t> (constructor_elements, initializer_num_elem, | |
804 | initializer); | |
805 | break; | |
806 | case 2: | |
807 | load_blob_in_ctor<uint16_t> (constructor_elements, initializer_num_elem, | |
808 | initializer); | |
809 | break; | |
810 | case 4: | |
811 | load_blob_in_ctor<uint32_t> (constructor_elements, initializer_num_elem, | |
812 | initializer); | |
813 | break; | |
814 | case 8: | |
815 | load_blob_in_ctor<uint64_t> (constructor_elements, initializer_num_elem, | |
816 | initializer); | |
817 | break; | |
818 | default: | |
819 | /* This function is serving on sizes returned by 'get_size', | |
820 | these are all covered by the previous cases. */ | |
821 | gcc_unreachable (); | |
822 | } | |
e53b6e56 | 823 | /* Compare with 'pop_init_level' c-typeck.cc:8780. */ |
4ecc0061 AC |
824 | tree ctor = build_constructor (type->as_tree (), constructor_elements); |
825 | constructor_elements = NULL; | |
826 | ||
e53b6e56 | 827 | /* Compare with 'store_init_value' c-typeck.cc:7555. */ |
4ecc0061 AC |
828 | DECL_INITIAL (inner) = ctor; |
829 | ||
830 | return global_finalize_lvalue (inner); | |
831 | } | |
832 | ||
ccce3b2a DM |
833 | /* Implementation of the various |
834 | gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE> | |
835 | methods. | |
836 | Each of these constructs a playback::rvalue instance (wrapping a tree). | |
35485da9 | 837 | |
ccce3b2a DM |
838 | These specializations are required to be in the same namespace |
839 | as the template, hence we now have to enter the gcc::jit::playback | |
840 | namespace. */ | |
841 | ||
842 | namespace playback | |
843 | { | |
844 | ||
845 | /* Specialization of making an rvalue from a const, for host <int>. */ | |
846 | ||
847 | template <> | |
848 | rvalue * | |
849 | context:: | |
850 | new_rvalue_from_const <int> (type *type, | |
851 | int value) | |
35485da9 DM |
852 | { |
853 | // FIXME: type-checking, or coercion? | |
854 | tree inner_type = type->as_tree (); | |
855 | if (INTEGRAL_TYPE_P (inner_type)) | |
856 | { | |
857 | tree inner = build_int_cst (inner_type, value); | |
858 | return new rvalue (this, inner); | |
859 | } | |
860 | else | |
861 | { | |
862 | REAL_VALUE_TYPE real_value; | |
863 | real_from_integer (&real_value, VOIDmode, value, SIGNED); | |
864 | tree inner = build_real (inner_type, real_value); | |
865 | return new rvalue (this, inner); | |
866 | } | |
867 | } | |
868 | ||
ccce3b2a | 869 | /* Specialization of making an rvalue from a const, for host <long>. */ |
35485da9 | 870 | |
ccce3b2a DM |
871 | template <> |
872 | rvalue * | |
873 | context:: | |
874 | new_rvalue_from_const <long> (type *type, | |
875 | long value) | |
876 | { | |
877 | // FIXME: type-checking, or coercion? | |
878 | tree inner_type = type->as_tree (); | |
879 | if (INTEGRAL_TYPE_P (inner_type)) | |
880 | { | |
881 | tree inner = build_int_cst (inner_type, value); | |
882 | return new rvalue (this, inner); | |
883 | } | |
884 | else | |
885 | { | |
886 | REAL_VALUE_TYPE real_value; | |
887 | real_from_integer (&real_value, VOIDmode, value, SIGNED); | |
888 | tree inner = build_real (inner_type, real_value); | |
889 | return new rvalue (this, inner); | |
890 | } | |
891 | } | |
892 | ||
893 | /* Specialization of making an rvalue from a const, for host <double>. */ | |
894 | ||
895 | template <> | |
896 | rvalue * | |
897 | context:: | |
898 | new_rvalue_from_const <double> (type *type, | |
899 | double value) | |
35485da9 DM |
900 | { |
901 | // FIXME: type-checking, or coercion? | |
902 | tree inner_type = type->as_tree (); | |
903 | ||
904 | /* We have a "double", we want a REAL_VALUE_TYPE. | |
905 | ||
e53b6e56 | 906 | real.cc:real_from_target appears to require the representation to be |
35485da9 DM |
907 | split into 32-bit values, and then sent as an pair of host long |
908 | ints. */ | |
909 | REAL_VALUE_TYPE real_value; | |
910 | union | |
911 | { | |
912 | double as_double; | |
913 | uint32_t as_uint32s[2]; | |
914 | } u; | |
915 | u.as_double = value; | |
916 | long int as_long_ints[2]; | |
917 | as_long_ints[0] = u.as_uint32s[0]; | |
918 | as_long_ints[1] = u.as_uint32s[1]; | |
919 | real_from_target (&real_value, as_long_ints, DFmode); | |
920 | tree inner = build_real (inner_type, real_value); | |
921 | return new rvalue (this, inner); | |
922 | } | |
923 | ||
ccce3b2a | 924 | /* Specialization of making an rvalue from a const, for host <void *>. */ |
35485da9 | 925 | |
ccce3b2a DM |
926 | template <> |
927 | rvalue * | |
928 | context:: | |
929 | new_rvalue_from_const <void *> (type *type, | |
930 | void *value) | |
35485da9 DM |
931 | { |
932 | tree inner_type = type->as_tree (); | |
933 | /* FIXME: how to ensure we have a wide enough type? */ | |
934 | tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value); | |
935 | return new rvalue (this, inner); | |
936 | } | |
937 | ||
ccce3b2a DM |
938 | /* We're done implementing the specializations of |
939 | gcc::jit::playback::context::new_rvalue_from_const <T> | |
940 | so we can exit the gcc::jit::playback namespace. */ | |
941 | ||
942 | } // namespace playback | |
943 | ||
35485da9 DM |
944 | /* Construct a playback::rvalue instance (wrapping a tree). */ |
945 | ||
946 | playback::rvalue * | |
947 | playback::context:: | |
948 | new_string_literal (const char *value) | |
949 | { | |
e53b6e56 | 950 | /* Compare with c-family/c-common.cc: fix_string_type. */ |
0cd55f9d A |
951 | size_t len = strlen (value); |
952 | tree i_type = build_index_type (size_int (len)); | |
953 | tree a_type = build_array_type (char_type_node, i_type); | |
954 | /* build_string len parameter must include NUL terminator when | |
955 | building C strings. */ | |
421d0d0f | 956 | tree t_str = ::build_string (len + 1, value); |
0cd55f9d | 957 | TREE_TYPE (t_str) = a_type; |
35485da9 DM |
958 | |
959 | /* Convert to (const char*), loosely based on | |
e53b6e56 | 960 | c/c-typeck.cc: array_to_pointer_conversion, |
35485da9 DM |
961 | by taking address of start of string. */ |
962 | tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str); | |
963 | ||
964 | return new rvalue (this, t_addr); | |
965 | } | |
966 | ||
6069fe72 DM |
967 | /* Construct a playback::rvalue instance (wrapping a tree) for a |
968 | vector. */ | |
969 | ||
970 | playback::rvalue * | |
971 | playback::context::new_rvalue_from_vector (location *, | |
972 | type *type, | |
973 | const auto_vec<rvalue *> &elements) | |
974 | { | |
975 | vec<constructor_elt, va_gc> *v; | |
976 | vec_alloc (v, elements.length ()); | |
977 | for (unsigned i = 0; i < elements.length (); ++i) | |
978 | CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ()); | |
979 | tree t_ctor = build_constructor (type->as_tree (), v); | |
980 | return new rvalue (this, t_ctor); | |
981 | } | |
982 | ||
35485da9 DM |
983 | /* Coerce a tree expression into a boolean tree expression. */ |
984 | ||
985 | tree | |
986 | playback::context:: | |
987 | as_truth_value (tree expr, location *loc) | |
988 | { | |
e53b6e56 | 989 | /* Compare to c-typeck.cc:c_objc_common_truthvalue_conversion */ |
35485da9 DM |
990 | tree typed_zero = fold_build1 (CONVERT_EXPR, |
991 | TREE_TYPE (expr), | |
992 | integer_zero_node); | |
993 | if (loc) | |
994 | set_tree_location (typed_zero, loc); | |
995 | ||
37368378 PT |
996 | expr = fold_build2_loc (UNKNOWN_LOCATION, |
997 | NE_EXPR, integer_type_node, expr, typed_zero); | |
35485da9 DM |
998 | if (loc) |
999 | set_tree_location (expr, loc); | |
1000 | ||
1001 | return expr; | |
1002 | } | |
1003 | ||
421d0d0f DM |
1004 | /* Add a "top-level" basic asm statement (i.e. one outside of any functions) |
1005 | containing ASM_STMTS. | |
1006 | ||
1007 | Compare with c_parser_asm_definition. */ | |
1008 | ||
1009 | void | |
1010 | playback::context::add_top_level_asm (const char *asm_stmts) | |
1011 | { | |
1012 | tree asm_str = build_string (asm_stmts); | |
1013 | symtab->finalize_toplevel_asm (asm_str); | |
1014 | } | |
1015 | ||
35485da9 DM |
1016 | /* Construct a playback::rvalue instance (wrapping a tree) for a |
1017 | unary op. */ | |
1018 | ||
1019 | playback::rvalue * | |
1020 | playback::context:: | |
1021 | new_unary_op (location *loc, | |
1022 | enum gcc_jit_unary_op op, | |
1023 | type *result_type, | |
1024 | rvalue *a) | |
1025 | { | |
1026 | // FIXME: type-checking, or coercion? | |
1027 | enum tree_code inner_op; | |
1028 | ||
1029 | gcc_assert (result_type); | |
1030 | gcc_assert (a); | |
1031 | ||
1032 | tree node = a->as_tree (); | |
37368378 PT |
1033 | node = fold_const_var (node); |
1034 | ||
35485da9 DM |
1035 | tree inner_result = NULL; |
1036 | ||
1037 | switch (op) | |
1038 | { | |
1039 | default: | |
1040 | add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op); | |
1041 | return NULL; | |
1042 | ||
1043 | case GCC_JIT_UNARY_OP_MINUS: | |
1044 | inner_op = NEGATE_EXPR; | |
1045 | break; | |
1046 | ||
1047 | case GCC_JIT_UNARY_OP_BITWISE_NEGATE: | |
1048 | inner_op = BIT_NOT_EXPR; | |
1049 | break; | |
1050 | ||
1051 | case GCC_JIT_UNARY_OP_LOGICAL_NEGATE: | |
1052 | node = as_truth_value (node, loc); | |
1053 | inner_result = invert_truthvalue (node); | |
1054 | if (loc) | |
1055 | set_tree_location (inner_result, loc); | |
1056 | return new rvalue (this, inner_result); | |
18146f45 DM |
1057 | |
1058 | case GCC_JIT_UNARY_OP_ABS: | |
1059 | inner_op = ABS_EXPR; | |
1060 | break; | |
35485da9 DM |
1061 | } |
1062 | ||
1063 | inner_result = build1 (inner_op, | |
1064 | result_type->as_tree (), | |
1065 | node); | |
37368378 PT |
1066 | |
1067 | /* Try to fold. */ | |
1068 | inner_result = fold (inner_result); | |
1069 | ||
35485da9 DM |
1070 | if (loc) |
1071 | set_tree_location (inner_result, loc); | |
1072 | ||
1073 | return new rvalue (this, inner_result); | |
1074 | } | |
1075 | ||
1076 | /* Construct a playback::rvalue instance (wrapping a tree) for a | |
1077 | binary op. */ | |
1078 | ||
1079 | playback::rvalue * | |
1080 | playback::context:: | |
1081 | new_binary_op (location *loc, | |
1082 | enum gcc_jit_binary_op op, | |
1083 | type *result_type, | |
1084 | rvalue *a, rvalue *b) | |
1085 | { | |
1086 | // FIXME: type-checking, or coercion? | |
1087 | enum tree_code inner_op; | |
1088 | ||
1089 | gcc_assert (result_type); | |
1090 | gcc_assert (a); | |
1091 | gcc_assert (b); | |
1092 | ||
1093 | tree node_a = a->as_tree (); | |
37368378 PT |
1094 | node_a = fold_const_var (node_a); |
1095 | ||
35485da9 | 1096 | tree node_b = b->as_tree (); |
37368378 | 1097 | node_b = fold_const_var (node_b); |
35485da9 DM |
1098 | |
1099 | switch (op) | |
1100 | { | |
1101 | default: | |
1102 | add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op); | |
1103 | return NULL; | |
1104 | ||
1105 | case GCC_JIT_BINARY_OP_PLUS: | |
1106 | inner_op = PLUS_EXPR; | |
1107 | break; | |
1108 | ||
1109 | case GCC_JIT_BINARY_OP_MINUS: | |
1110 | inner_op = MINUS_EXPR; | |
1111 | break; | |
1112 | ||
1113 | case GCC_JIT_BINARY_OP_MULT: | |
1114 | inner_op = MULT_EXPR; | |
1115 | break; | |
1116 | ||
1117 | case GCC_JIT_BINARY_OP_DIVIDE: | |
1118 | if (FLOAT_TYPE_P (result_type->as_tree ())) | |
1119 | /* Floating-point division: */ | |
1120 | inner_op = RDIV_EXPR; | |
1121 | else | |
1122 | /* Truncating to zero: */ | |
1123 | inner_op = TRUNC_DIV_EXPR; | |
1124 | break; | |
1125 | ||
1126 | case GCC_JIT_BINARY_OP_MODULO: | |
1127 | inner_op = TRUNC_MOD_EXPR; | |
1128 | break; | |
1129 | ||
1130 | case GCC_JIT_BINARY_OP_BITWISE_AND: | |
1131 | inner_op = BIT_AND_EXPR; | |
1132 | break; | |
1133 | ||
1134 | case GCC_JIT_BINARY_OP_BITWISE_XOR: | |
1135 | inner_op = BIT_XOR_EXPR; | |
1136 | break; | |
1137 | ||
1138 | case GCC_JIT_BINARY_OP_BITWISE_OR: | |
1139 | inner_op = BIT_IOR_EXPR; | |
1140 | break; | |
1141 | ||
1142 | case GCC_JIT_BINARY_OP_LOGICAL_AND: | |
1143 | node_a = as_truth_value (node_a, loc); | |
1144 | node_b = as_truth_value (node_b, loc); | |
1145 | inner_op = TRUTH_ANDIF_EXPR; | |
1146 | break; | |
1147 | ||
1148 | case GCC_JIT_BINARY_OP_LOGICAL_OR: | |
1149 | node_a = as_truth_value (node_a, loc); | |
1150 | node_b = as_truth_value (node_b, loc); | |
1151 | inner_op = TRUTH_ORIF_EXPR; | |
1152 | break; | |
1153 | ||
1154 | case GCC_JIT_BINARY_OP_LSHIFT: | |
1155 | inner_op = LSHIFT_EXPR; | |
1156 | break; | |
1157 | ||
1158 | case GCC_JIT_BINARY_OP_RSHIFT: | |
1159 | inner_op = RSHIFT_EXPR; | |
1160 | break; | |
1161 | } | |
1162 | ||
1163 | tree inner_expr = build2 (inner_op, | |
1164 | result_type->as_tree (), | |
1165 | node_a, | |
1166 | node_b); | |
37368378 PT |
1167 | |
1168 | /* Try to fold the expression. */ | |
1169 | inner_expr = fold (inner_expr); | |
1170 | ||
35485da9 DM |
1171 | if (loc) |
1172 | set_tree_location (inner_expr, loc); | |
1173 | ||
1174 | return new rvalue (this, inner_expr); | |
1175 | } | |
1176 | ||
1177 | /* Construct a playback::rvalue instance (wrapping a tree) for a | |
1178 | comparison. */ | |
1179 | ||
1180 | playback::rvalue * | |
1181 | playback::context:: | |
1182 | new_comparison (location *loc, | |
1183 | enum gcc_jit_comparison op, | |
1184 | rvalue *a, rvalue *b) | |
1185 | { | |
1186 | // FIXME: type-checking, or coercion? | |
1187 | enum tree_code inner_op; | |
1188 | ||
1189 | gcc_assert (a); | |
1190 | gcc_assert (b); | |
1191 | ||
1192 | switch (op) | |
1193 | { | |
1194 | default: | |
1195 | add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op); | |
1196 | return NULL; | |
1197 | ||
1198 | case GCC_JIT_COMPARISON_EQ: | |
1199 | inner_op = EQ_EXPR; | |
1200 | break; | |
1201 | case GCC_JIT_COMPARISON_NE: | |
1202 | inner_op = NE_EXPR; | |
1203 | break; | |
1204 | case GCC_JIT_COMPARISON_LT: | |
1205 | inner_op = LT_EXPR; | |
1206 | break; | |
1207 | case GCC_JIT_COMPARISON_LE: | |
1208 | inner_op = LE_EXPR; | |
1209 | break; | |
1210 | case GCC_JIT_COMPARISON_GT: | |
1211 | inner_op = GT_EXPR; | |
1212 | break; | |
1213 | case GCC_JIT_COMPARISON_GE: | |
1214 | inner_op = GE_EXPR; | |
1215 | break; | |
1216 | } | |
1217 | ||
37368378 PT |
1218 | tree node_a = a->as_tree (); |
1219 | node_a = fold_const_var (node_a); | |
1220 | tree node_b = b->as_tree (); | |
1221 | node_b = fold_const_var (node_b); | |
1222 | ||
35485da9 DM |
1223 | tree inner_expr = build2 (inner_op, |
1224 | boolean_type_node, | |
37368378 PT |
1225 | node_a, |
1226 | node_b); | |
1227 | ||
1228 | /* Try to fold. */ | |
1229 | inner_expr = fold (inner_expr); | |
1230 | ||
35485da9 DM |
1231 | if (loc) |
1232 | set_tree_location (inner_expr, loc); | |
1233 | return new rvalue (this, inner_expr); | |
1234 | } | |
1235 | ||
1236 | /* Construct a playback::rvalue instance (wrapping a tree) for a | |
1237 | function call. */ | |
1238 | ||
1239 | playback::rvalue * | |
1240 | playback::context:: | |
1241 | build_call (location *loc, | |
1242 | tree fn_ptr, | |
15c671a7 DM |
1243 | const auto_vec<rvalue *> *args, |
1244 | bool require_tail_call) | |
35485da9 DM |
1245 | { |
1246 | vec<tree, va_gc> *tree_args; | |
b957b2e0 DM |
1247 | vec_alloc (tree_args, args->length ()); |
1248 | for (unsigned i = 0; i < args->length (); i++) | |
1249 | tree_args->quick_push ((*args)[i]->as_tree ()); | |
35485da9 DM |
1250 | |
1251 | if (loc) | |
1252 | set_tree_location (fn_ptr, loc); | |
1253 | ||
1254 | tree fn = TREE_TYPE (fn_ptr); | |
1255 | tree fn_type = TREE_TYPE (fn); | |
1256 | tree return_type = TREE_TYPE (fn_type); | |
1257 | ||
15c671a7 DM |
1258 | tree call = build_call_vec (return_type, |
1259 | fn_ptr, tree_args); | |
1260 | ||
1261 | if (require_tail_call) | |
1262 | CALL_EXPR_MUST_TAIL_CALL (call) = 1; | |
1263 | ||
1264 | return new rvalue (this, call); | |
35485da9 | 1265 | |
e53b6e56 | 1266 | /* see c-typeck.cc: build_function_call |
35485da9 DM |
1267 | which calls build_function_call_vec |
1268 | ||
1269 | which does lots of checking, then: | |
1270 | result = build_call_array_loc (loc, TREE_TYPE (fntype), | |
1271 | function, nargs, argarray); | |
e53b6e56 | 1272 | which is in tree.cc |
35485da9 DM |
1273 | (see also build_call_vec) |
1274 | */ | |
1275 | } | |
1276 | ||
1277 | /* Construct a playback::rvalue instance (wrapping a tree) for a | |
1278 | call to a specific function. */ | |
1279 | ||
1280 | playback::rvalue * | |
1281 | playback::context:: | |
1282 | new_call (location *loc, | |
1283 | function *func, | |
15c671a7 DM |
1284 | const auto_vec<rvalue *> *args, |
1285 | bool require_tail_call) | |
35485da9 DM |
1286 | { |
1287 | tree fndecl; | |
1288 | ||
1289 | gcc_assert (func); | |
1290 | ||
1291 | fndecl = func->as_fndecl (); | |
1292 | ||
1293 | tree fntype = TREE_TYPE (fndecl); | |
1294 | ||
1295 | tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl); | |
1296 | ||
15c671a7 | 1297 | return build_call (loc, fn, args, require_tail_call); |
35485da9 DM |
1298 | } |
1299 | ||
1300 | /* Construct a playback::rvalue instance (wrapping a tree) for a | |
1301 | call through a function pointer. */ | |
1302 | ||
1303 | playback::rvalue * | |
1304 | playback::context:: | |
1305 | new_call_through_ptr (location *loc, | |
1306 | rvalue *fn_ptr, | |
15c671a7 DM |
1307 | const auto_vec<rvalue *> *args, |
1308 | bool require_tail_call) | |
35485da9 DM |
1309 | { |
1310 | gcc_assert (fn_ptr); | |
1311 | tree t_fn_ptr = fn_ptr->as_tree (); | |
1312 | ||
15c671a7 | 1313 | return build_call (loc, t_fn_ptr, args, require_tail_call); |
35485da9 DM |
1314 | } |
1315 | ||
1316 | /* Construct a tree for a cast. */ | |
1317 | ||
1318 | tree | |
1319 | playback::context::build_cast (playback::location *loc, | |
1320 | playback::rvalue *expr, | |
1321 | playback::type *type_) | |
1322 | { | |
1323 | /* For comparison, see: | |
e53b6e56 ML |
1324 | - c/c-typeck.cc:build_c_cast |
1325 | - c/c-convert.cc: convert | |
35485da9 DM |
1326 | - convert.h |
1327 | ||
1328 | Only some kinds of cast are currently supported here. */ | |
1329 | tree t_expr = expr->as_tree (); | |
37368378 PT |
1330 | t_expr = fold_const_var (t_expr); |
1331 | ||
35485da9 DM |
1332 | tree t_dst_type = type_->as_tree (); |
1333 | tree t_ret = NULL; | |
1334 | t_ret = targetm.convert_to_type (t_dst_type, t_expr); | |
1335 | if (t_ret) | |
1336 | return t_ret; | |
1337 | enum tree_code dst_code = TREE_CODE (t_dst_type); | |
1338 | switch (dst_code) | |
1339 | { | |
1340 | case INTEGER_TYPE: | |
1341 | case ENUMERAL_TYPE: | |
1342 | t_ret = convert_to_integer (t_dst_type, t_expr); | |
1343 | goto maybe_fold; | |
1344 | ||
1345 | case BOOLEAN_TYPE: | |
1346 | /* Compare with c_objc_common_truthvalue_conversion and | |
1347 | c_common_truthvalue_conversion. */ | |
1348 | /* For now, convert to: (t_expr != 0) */ | |
1349 | t_ret = build2 (NE_EXPR, t_dst_type, | |
e8af59bc DM |
1350 | t_expr, |
1351 | build_int_cst (TREE_TYPE (t_expr), 0)); | |
35485da9 DM |
1352 | goto maybe_fold; |
1353 | ||
1354 | case REAL_TYPE: | |
1355 | t_ret = convert_to_real (t_dst_type, t_expr); | |
1356 | goto maybe_fold; | |
1357 | ||
1358 | case POINTER_TYPE: | |
1359 | t_ret = build1 (NOP_EXPR, t_dst_type, t_expr); | |
1360 | goto maybe_fold; | |
1361 | ||
1362 | default: | |
1363 | add_error (loc, "couldn't handle cast during playback"); | |
1364 | fprintf (stderr, "input expression:\n"); | |
1365 | debug_tree (t_expr); | |
1366 | fprintf (stderr, "requested type:\n"); | |
1367 | debug_tree (t_dst_type); | |
1368 | return error_mark_node; | |
1369 | ||
1370 | maybe_fold: | |
1371 | if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR) | |
1372 | t_ret = fold (t_ret); | |
1373 | return t_ret; | |
1374 | } | |
1375 | } | |
1376 | ||
1377 | /* Construct a playback::rvalue instance (wrapping a tree) for a | |
1378 | cast. */ | |
1379 | ||
1380 | playback::rvalue * | |
1381 | playback::context:: | |
1382 | new_cast (playback::location *loc, | |
1383 | playback::rvalue *expr, | |
1384 | playback::type *type_) | |
1385 | { | |
1386 | ||
1387 | tree t_cast = build_cast (loc, expr, type_); | |
1388 | if (loc) | |
1389 | set_tree_location (t_cast, loc); | |
1390 | return new rvalue (this, t_cast); | |
1391 | } | |
1392 | ||
1393 | /* Construct a playback::lvalue instance (wrapping a tree) for an | |
1394 | array access. */ | |
1395 | ||
1396 | playback::lvalue * | |
1397 | playback::context:: | |
1398 | new_array_access (location *loc, | |
1399 | rvalue *ptr, | |
1400 | rvalue *index) | |
1401 | { | |
1402 | gcc_assert (ptr); | |
1403 | gcc_assert (index); | |
1404 | ||
1405 | /* For comparison, see: | |
e53b6e56 ML |
1406 | c/c-typeck.cc: build_array_ref |
1407 | c-family/c-common.cc: pointer_int_sum | |
35485da9 DM |
1408 | */ |
1409 | tree t_ptr = ptr->as_tree (); | |
37368378 | 1410 | t_ptr = fold_const_var (t_ptr); |
35485da9 | 1411 | tree t_index = index->as_tree (); |
37368378 PT |
1412 | t_index = fold_const_var (t_index); |
1413 | ||
35485da9 DM |
1414 | tree t_type_ptr = TREE_TYPE (t_ptr); |
1415 | tree t_type_star_ptr = TREE_TYPE (t_type_ptr); | |
1416 | ||
1417 | if (TREE_CODE (t_type_ptr) == ARRAY_TYPE) | |
1418 | { | |
1419 | tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index, | |
1420 | NULL_TREE, NULL_TREE); | |
37368378 | 1421 | t_result = fold (t_result); |
35485da9 | 1422 | if (loc) |
c168eab9 | 1423 | set_tree_location (t_result, loc); |
35485da9 DM |
1424 | return new lvalue (this, t_result); |
1425 | } | |
1426 | else | |
1427 | { | |
1428 | /* Convert index to an offset in bytes. */ | |
1429 | tree t_sizeof = size_in_bytes (t_type_star_ptr); | |
1430 | t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index); | |
37368378 PT |
1431 | tree t_offset = fold_build2_loc (UNKNOWN_LOCATION, |
1432 | MULT_EXPR, sizetype, t_index, t_sizeof); | |
35485da9 DM |
1433 | |
1434 | /* Locate (ptr + offset). */ | |
37368378 PT |
1435 | tree t_address = fold_build2_loc (UNKNOWN_LOCATION, |
1436 | POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset); | |
35485da9 | 1437 | |
37368378 | 1438 | tree t_indirection = fold_build1 (INDIRECT_REF, t_type_star_ptr, t_address); |
35485da9 | 1439 | if (loc) |
c168eab9 UD |
1440 | { |
1441 | set_tree_location (t_sizeof, loc); | |
1442 | set_tree_location (t_offset, loc); | |
1443 | set_tree_location (t_address, loc); | |
1444 | set_tree_location (t_indirection, loc); | |
1445 | } | |
35485da9 DM |
1446 | |
1447 | return new lvalue (this, t_indirection); | |
1448 | } | |
1449 | } | |
1450 | ||
1451 | /* Construct a tree for a field access. */ | |
1452 | ||
1453 | tree | |
1454 | playback::context:: | |
1455 | new_field_access (location *loc, | |
1456 | tree datum, | |
1457 | field *field) | |
1458 | { | |
1459 | gcc_assert (datum); | |
1460 | gcc_assert (field); | |
1461 | ||
e53b6e56 | 1462 | /* Compare with c/c-typeck.cc:lookup_field, build_indirect_ref, and |
35485da9 DM |
1463 | build_component_ref. */ |
1464 | tree type = TREE_TYPE (datum); | |
1465 | gcc_assert (type); | |
1466 | gcc_assert (TREE_CODE (type) != POINTER_TYPE); | |
1467 | ||
1468 | tree t_field = field->as_tree (); | |
1469 | tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum, | |
1470 | t_field, NULL_TREE); | |
1471 | if (loc) | |
1472 | set_tree_location (ref, loc); | |
1473 | return ref; | |
1474 | } | |
1475 | ||
1476 | /* Construct a tree for a dereference. */ | |
1477 | ||
1478 | tree | |
1479 | playback::context:: | |
1480 | new_dereference (tree ptr, | |
1481 | location *loc) | |
1482 | { | |
1483 | gcc_assert (ptr); | |
1484 | ||
1485 | tree type = TREE_TYPE (TREE_TYPE(ptr)); | |
37368378 | 1486 | tree datum = fold_build1 (INDIRECT_REF, type, ptr); |
35485da9 DM |
1487 | if (loc) |
1488 | set_tree_location (datum, loc); | |
1489 | return datum; | |
1490 | } | |
1491 | ||
0ebd1f00 DM |
1492 | /* Construct a playback::type instance (wrapping a tree) |
1493 | with the given alignment. */ | |
1494 | ||
1495 | playback::type * | |
1496 | playback::type:: | |
1497 | get_aligned (size_t alignment_in_bytes) const | |
1498 | { | |
1499 | tree t_new_type = build_variant_type_copy (m_inner); | |
1500 | ||
1501 | SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT); | |
1502 | TYPE_USER_ALIGN (t_new_type) = 1; | |
1503 | ||
1504 | return new type (t_new_type); | |
1505 | } | |
1506 | ||
47ee1b7c DM |
1507 | /* Construct a playback::type instance (wrapping a tree) |
1508 | for the given vector type. */ | |
1509 | ||
1510 | playback::type * | |
1511 | playback::type:: | |
1512 | get_vector (size_t num_units) const | |
1513 | { | |
1514 | tree t_new_type = build_vector_type (m_inner, num_units); | |
1515 | return new type (t_new_type); | |
1516 | } | |
1517 | ||
35485da9 DM |
1518 | /* Construct a playback::lvalue instance (wrapping a tree) for a |
1519 | field access. */ | |
1520 | ||
1521 | playback::lvalue * | |
1522 | playback::lvalue:: | |
1523 | access_field (location *loc, | |
1524 | field *field) | |
1525 | { | |
1526 | tree datum = as_tree (); | |
1527 | tree ref = get_context ()->new_field_access (loc, datum, field); | |
1528 | if (!ref) | |
1529 | return NULL; | |
1530 | return new lvalue (get_context (), ref); | |
1531 | } | |
1532 | ||
1533 | /* Construct a playback::rvalue instance (wrapping a tree) for a | |
1534 | field access. */ | |
1535 | ||
1536 | playback::rvalue * | |
1537 | playback::rvalue:: | |
1538 | access_field (location *loc, | |
1539 | field *field) | |
1540 | { | |
1541 | tree datum = as_tree (); | |
1542 | tree ref = get_context ()->new_field_access (loc, datum, field); | |
1543 | if (!ref) | |
1544 | return NULL; | |
1545 | return new rvalue (get_context (), ref); | |
1546 | } | |
1547 | ||
1548 | /* Construct a playback::lvalue instance (wrapping a tree) for a | |
1549 | dereferenced field access. */ | |
1550 | ||
1551 | playback::lvalue * | |
1552 | playback::rvalue:: | |
1553 | dereference_field (location *loc, | |
1554 | field *field) | |
1555 | { | |
1556 | tree ptr = as_tree (); | |
1557 | tree datum = get_context ()->new_dereference (ptr, loc); | |
1558 | if (!datum) | |
1559 | return NULL; | |
1560 | tree ref = get_context ()->new_field_access (loc, datum, field); | |
1561 | if (!ref) | |
1562 | return NULL; | |
1563 | return new lvalue (get_context (), ref); | |
1564 | } | |
1565 | ||
1566 | /* Construct a playback::lvalue instance (wrapping a tree) for a | |
1567 | dereference. */ | |
1568 | ||
1569 | playback::lvalue * | |
1570 | playback::rvalue:: | |
1571 | dereference (location *loc) | |
1572 | { | |
1573 | tree ptr = as_tree (); | |
1574 | tree datum = get_context ()->new_dereference (ptr, loc); | |
1575 | return new lvalue (get_context (), datum); | |
1576 | } | |
1577 | ||
ee118c14 | 1578 | /* Mark the lvalue saying that we need to be able to take the |
e09abfa4 | 1579 | address of it; it should not be allocated in a register. |
e53b6e56 | 1580 | Compare with e.g. c/c-typeck.cc: c_mark_addressable really_atomic_lvalue. |
ee118c14 AC |
1581 | Returns false if a failure occurred (an error will already have been |
1582 | added to the active context for this case). */ | |
e09abfa4 | 1583 | |
ee118c14 AC |
1584 | bool |
1585 | playback::lvalue:: | |
1586 | mark_addressable (location *loc) | |
e09abfa4 | 1587 | { |
ee118c14 | 1588 | tree x = as_tree ();; |
e09abfa4 DM |
1589 | |
1590 | while (1) | |
1591 | switch (TREE_CODE (x)) | |
1592 | { | |
1593 | case COMPONENT_REF: | |
ee118c14 AC |
1594 | if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x, 1))) |
1595 | { | |
1596 | gcc_assert (gcc::jit::active_playback_ctxt); | |
1597 | gcc::jit:: | |
1598 | active_playback_ctxt->add_error (loc, | |
1599 | "cannot take address of " | |
1600 | "bit-field"); | |
1601 | return false; | |
1602 | } | |
e09abfa4 DM |
1603 | /* fallthrough */ |
1604 | case ADDR_EXPR: | |
1605 | case ARRAY_REF: | |
1606 | case REALPART_EXPR: | |
1607 | case IMAGPART_EXPR: | |
1608 | x = TREE_OPERAND (x, 0); | |
1609 | break; | |
1610 | ||
1611 | case COMPOUND_LITERAL_EXPR: | |
1612 | case CONSTRUCTOR: | |
1613 | TREE_ADDRESSABLE (x) = 1; | |
ee118c14 | 1614 | return true; |
e09abfa4 DM |
1615 | |
1616 | case VAR_DECL: | |
1617 | case CONST_DECL: | |
1618 | case PARM_DECL: | |
1619 | case RESULT_DECL: | |
1620 | /* (we don't have a concept of a "register" declaration) */ | |
1621 | /* fallthrough */ | |
1622 | case FUNCTION_DECL: | |
1623 | TREE_ADDRESSABLE (x) = 1; | |
1624 | /* fallthrough */ | |
1625 | default: | |
ee118c14 | 1626 | return true; |
e09abfa4 DM |
1627 | } |
1628 | } | |
1629 | ||
35485da9 DM |
1630 | /* Construct a playback::rvalue instance (wrapping a tree) for an |
1631 | address-lookup. */ | |
1632 | ||
1633 | playback::rvalue * | |
1634 | playback::lvalue:: | |
1635 | get_address (location *loc) | |
1636 | { | |
1637 | tree t_lvalue = as_tree (); | |
1638 | tree t_thistype = TREE_TYPE (t_lvalue); | |
1639 | tree t_ptrtype = build_pointer_type (t_thistype); | |
37368378 | 1640 | tree ptr = fold_build1 (ADDR_EXPR, t_ptrtype, t_lvalue); |
35485da9 DM |
1641 | if (loc) |
1642 | get_context ()->set_tree_location (ptr, loc); | |
ee118c14 AC |
1643 | if (mark_addressable (loc)) |
1644 | return new rvalue (get_context (), ptr); | |
1645 | else | |
1646 | return NULL; | |
35485da9 DM |
1647 | } |
1648 | ||
b957b2e0 DM |
1649 | /* The wrapper subclasses are GC-managed, but can own non-GC memory. |
1650 | Provide this finalization hook for calling then they are collected, | |
1651 | which calls the finalizer vfunc. This allows them to call "release" | |
1652 | on any vec<> within them. */ | |
1653 | ||
1654 | static void | |
1655 | wrapper_finalizer (void *ptr) | |
1656 | { | |
1657 | playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr); | |
1658 | wrapper->finalizer (); | |
1659 | } | |
1660 | ||
35485da9 DM |
1661 | /* gcc::jit::playback::wrapper subclasses are GC-managed: |
1662 | allocate them using ggc_internal_cleared_alloc. */ | |
1663 | ||
1664 | void * | |
1665 | playback::wrapper:: | |
1666 | operator new (size_t sz) | |
1667 | { | |
b957b2e0 DM |
1668 | return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1); |
1669 | ||
35485da9 DM |
1670 | } |
1671 | ||
1672 | /* Constructor for gcc:jit::playback::function. */ | |
1673 | ||
1674 | playback::function:: | |
1675 | function (context *ctxt, | |
1676 | tree fndecl, | |
1677 | enum gcc_jit_function_kind kind) | |
1678 | : m_ctxt(ctxt), | |
1679 | m_inner_fndecl (fndecl), | |
1680 | m_inner_bind_expr (NULL), | |
c2e68105 ML |
1681 | m_kind (kind), |
1682 | m_blocks () | |
35485da9 DM |
1683 | { |
1684 | if (m_kind != GCC_JIT_FUNCTION_IMPORTED) | |
1685 | { | |
1686 | /* Create a BIND_EXPR, and within it, a statement list. */ | |
1687 | m_stmt_list = alloc_stmt_list (); | |
1688 | m_stmt_iter = tsi_start (m_stmt_list); | |
1689 | m_inner_block = make_node (BLOCK); | |
1690 | m_inner_bind_expr = | |
1691 | build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block); | |
1692 | } | |
1693 | else | |
1694 | { | |
1695 | m_inner_block = NULL; | |
1696 | m_stmt_list = NULL; | |
1697 | } | |
1698 | } | |
1699 | ||
1700 | /* Hand-written GC-marking hook for playback functions. */ | |
1701 | ||
1702 | void | |
1703 | playback::function:: | |
1704 | gt_ggc_mx () | |
1705 | { | |
1706 | gt_ggc_m_9tree_node (m_inner_fndecl); | |
1707 | gt_ggc_m_9tree_node (m_inner_bind_expr); | |
1708 | gt_ggc_m_9tree_node (m_stmt_list); | |
1709 | gt_ggc_m_9tree_node (m_inner_block); | |
1710 | } | |
1711 | ||
b957b2e0 DM |
1712 | /* Don't leak vec's internal buffer (in non-GC heap) when we are |
1713 | GC-ed. */ | |
1714 | ||
1715 | void | |
1716 | playback::function::finalizer () | |
1717 | { | |
1718 | m_blocks.release (); | |
1719 | } | |
1720 | ||
35485da9 DM |
1721 | /* Get the return type of a playback function, in tree form. */ |
1722 | ||
1723 | tree | |
1724 | playback::function:: | |
1725 | get_return_type_as_tree () const | |
1726 | { | |
1727 | return TREE_TYPE (TREE_TYPE(m_inner_fndecl)); | |
1728 | } | |
1729 | ||
1730 | /* Construct a new local within this playback::function. */ | |
1731 | ||
1732 | playback::lvalue * | |
1733 | playback::function:: | |
1734 | new_local (location *loc, | |
1735 | type *type, | |
1736 | const char *name) | |
1737 | { | |
1738 | gcc_assert (type); | |
1739 | gcc_assert (name); | |
1740 | tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL, | |
1741 | get_identifier (name), | |
1742 | type->as_tree ()); | |
1743 | DECL_CONTEXT (inner) = this->m_inner_fndecl; | |
1744 | ||
1745 | /* Prepend to BIND_EXPR_VARS: */ | |
1746 | DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr); | |
1747 | BIND_EXPR_VARS (m_inner_bind_expr) = inner; | |
1748 | ||
1749 | if (loc) | |
1750 | set_tree_location (inner, loc); | |
1751 | return new lvalue (m_ctxt, inner); | |
1752 | } | |
1753 | ||
1754 | /* Construct a new block within this playback::function. */ | |
1755 | ||
1756 | playback::block * | |
1757 | playback::function:: | |
1758 | new_block (const char *name) | |
1759 | { | |
1760 | gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED); | |
1761 | ||
1762 | block *result = new playback::block (this, name); | |
1763 | m_blocks.safe_push (result); | |
1764 | return result; | |
1765 | } | |
1766 | ||
15a65e63 DM |
1767 | /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for |
1768 | this playback::function. */ | |
1769 | ||
1770 | playback::rvalue * | |
1771 | playback::function::get_address (location *loc) | |
1772 | { | |
1773 | tree t_fndecl = as_fndecl (); | |
1774 | tree t_fntype = TREE_TYPE (t_fndecl); | |
1775 | tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl); | |
1776 | if (loc) | |
1777 | m_ctxt->set_tree_location (t_fnptr, loc); | |
1778 | return new rvalue (m_ctxt, t_fnptr); | |
1779 | } | |
1780 | ||
35485da9 DM |
1781 | /* Build a statement list for the function as a whole out of the |
1782 | lists of statements for the individual blocks, building labels | |
1783 | for each block. */ | |
1784 | ||
1785 | void | |
1786 | playback::function:: | |
1787 | build_stmt_list () | |
1788 | { | |
1789 | int i; | |
1790 | block *b; | |
1791 | ||
eb4c16eb DM |
1792 | JIT_LOG_SCOPE (m_ctxt->get_logger ()); |
1793 | ||
35485da9 DM |
1794 | FOR_EACH_VEC_ELT (m_blocks, i, b) |
1795 | { | |
1796 | int j; | |
1797 | tree stmt; | |
1798 | ||
1799 | b->m_label_expr = build1 (LABEL_EXPR, | |
1800 | void_type_node, | |
1801 | b->as_label_decl ()); | |
1802 | tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING); | |
1803 | ||
1804 | FOR_EACH_VEC_ELT (b->m_stmts, j, stmt) | |
1805 | tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING); | |
1806 | } | |
1807 | } | |
1808 | ||
1809 | /* Finish compiling the given function, potentially running the | |
1810 | garbage-collector. | |
1811 | The function will have a statement list by now. | |
1812 | Amongst other things, this gimplifies the statement list, | |
1813 | and calls cgraph_node::finalize_function on the function. */ | |
1814 | ||
1815 | void | |
1816 | playback::function:: | |
1817 | postprocess () | |
1818 | { | |
eb4c16eb DM |
1819 | JIT_LOG_SCOPE (m_ctxt->get_logger ()); |
1820 | ||
35485da9 DM |
1821 | if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE)) |
1822 | debug_tree (m_stmt_list); | |
1823 | ||
e53b6e56 | 1824 | /* Do we need this to force cgraphunit.cc to output the function? */ |
35485da9 DM |
1825 | if (m_kind == GCC_JIT_FUNCTION_EXPORTED) |
1826 | { | |
1827 | DECL_EXTERNAL (m_inner_fndecl) = 0; | |
1828 | DECL_PRESERVE_P (m_inner_fndecl) = 1; | |
1829 | } | |
1830 | ||
1831 | if (m_kind == GCC_JIT_FUNCTION_INTERNAL | |
1832 | ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE) | |
1833 | { | |
1834 | DECL_EXTERNAL (m_inner_fndecl) = 0; | |
1835 | TREE_PUBLIC (m_inner_fndecl) = 0; | |
1836 | } | |
1837 | ||
1838 | if (m_kind != GCC_JIT_FUNCTION_IMPORTED) | |
1839 | { | |
e53b6e56 | 1840 | /* Seem to need this in gimple-low.cc: */ |
35485da9 DM |
1841 | gcc_assert (m_inner_block); |
1842 | DECL_INITIAL (m_inner_fndecl) = m_inner_block; | |
1843 | ||
1844 | /* how to add to function? the following appears to be how to | |
1845 | set the body of a m_inner_fndecl: */ | |
1846 | DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr; | |
1847 | ||
1848 | /* Ensure that locals appear in the debuginfo. */ | |
1849 | BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr); | |
1850 | ||
1851 | //debug_tree (m_inner_fndecl); | |
1852 | ||
1853 | /* Convert to gimple: */ | |
1854 | //printf("about to gimplify_function_tree\n"); | |
1855 | gimplify_function_tree (m_inner_fndecl); | |
1856 | //printf("finished gimplify_function_tree\n"); | |
1857 | ||
1858 | current_function_decl = m_inner_fndecl; | |
1859 | if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE)) | |
1860 | dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO); | |
1861 | //debug_tree (m_inner_fndecl); | |
1862 | ||
1863 | //printf("about to add to cgraph\n"); | |
1864 | /* Add to cgraph: */ | |
1865 | cgraph_node::finalize_function (m_inner_fndecl, false); | |
1866 | /* This can trigger a collection, so we need to have all of | |
1867 | the funcs as roots. */ | |
1868 | ||
1869 | current_function_decl = NULL; | |
1870 | } | |
1871 | } | |
1872 | ||
b957b2e0 DM |
1873 | /* Don't leak vec's internal buffer (in non-GC heap) when we are |
1874 | GC-ed. */ | |
1875 | ||
1876 | void | |
1877 | playback::block::finalizer () | |
1878 | { | |
1879 | m_stmts.release (); | |
1880 | } | |
1881 | ||
35485da9 DM |
1882 | /* Add an eval of the rvalue to the function's statement list. */ |
1883 | ||
1884 | void | |
1885 | playback::block:: | |
1886 | add_eval (location *loc, | |
1887 | rvalue *rvalue) | |
1888 | { | |
1889 | gcc_assert (rvalue); | |
1890 | ||
1891 | if (loc) | |
1892 | set_tree_location (rvalue->as_tree (), loc); | |
1893 | ||
1894 | add_stmt (rvalue->as_tree ()); | |
1895 | } | |
1896 | ||
1897 | /* Add an assignment to the function's statement list. */ | |
1898 | ||
1899 | void | |
1900 | playback::block:: | |
1901 | add_assignment (location *loc, | |
1902 | lvalue *lvalue, | |
1903 | rvalue *rvalue) | |
1904 | { | |
1905 | gcc_assert (lvalue); | |
1906 | gcc_assert (rvalue); | |
1907 | ||
1908 | tree t_lvalue = lvalue->as_tree (); | |
1909 | tree t_rvalue = rvalue->as_tree (); | |
1910 | if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue)) | |
1911 | { | |
1912 | t_rvalue = build1 (CONVERT_EXPR, | |
c168eab9 UD |
1913 | TREE_TYPE (t_lvalue), |
1914 | t_rvalue); | |
35485da9 DM |
1915 | if (loc) |
1916 | set_tree_location (t_rvalue, loc); | |
1917 | } | |
1918 | ||
1919 | tree stmt = | |
1920 | build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue), | |
1921 | t_lvalue, t_rvalue); | |
1922 | if (loc) | |
1923 | set_tree_location (stmt, loc); | |
1924 | add_stmt (stmt); | |
1925 | } | |
1926 | ||
1927 | /* Add a comment to the function's statement list. | |
1928 | For now this is done by adding a dummy label. */ | |
1929 | ||
1930 | void | |
1931 | playback::block:: | |
1932 | add_comment (location *loc, | |
1933 | const char *text) | |
1934 | { | |
1935 | /* Wrap the text in C-style comment delimiters. */ | |
1936 | size_t sz = | |
1937 | (3 /* opening delim */ | |
1938 | + strlen (text) | |
1939 | + 3 /* closing delim */ | |
1940 | + 1 /* terminator */); | |
1941 | char *wrapped = (char *)ggc_internal_alloc (sz); | |
1942 | snprintf (wrapped, sz, "/* %s */", text); | |
1943 | ||
1944 | /* For now we simply implement this by adding a dummy label with a name | |
1945 | containing the given text. */ | |
1946 | tree identifier = get_identifier (wrapped); | |
1947 | tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL, | |
1948 | identifier, void_type_node); | |
1949 | DECL_CONTEXT (label_decl) = m_func->as_fndecl (); | |
1950 | ||
1951 | tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl); | |
1952 | if (loc) | |
1953 | set_tree_location (label_expr, loc); | |
1954 | add_stmt (label_expr); | |
1955 | } | |
1956 | ||
1957 | /* Add a conditional jump statement to the function's statement list. */ | |
1958 | ||
1959 | void | |
1960 | playback::block:: | |
1961 | add_conditional (location *loc, | |
1962 | rvalue *boolval, | |
1963 | block *on_true, | |
1964 | block *on_false) | |
1965 | { | |
1966 | gcc_assert (boolval); | |
1967 | gcc_assert (on_true); | |
1968 | gcc_assert (on_false); | |
1969 | ||
1970 | /* COND_EXPR wants statement lists for the true/false operands, but we | |
1971 | want labels. | |
1972 | Shim it by creating jumps to the labels */ | |
1973 | tree true_jump = build1 (GOTO_EXPR, void_type_node, | |
1974 | on_true->as_label_decl ()); | |
1975 | if (loc) | |
1976 | set_tree_location (true_jump, loc); | |
1977 | ||
1978 | tree false_jump = build1 (GOTO_EXPR, void_type_node, | |
1979 | on_false->as_label_decl ()); | |
1980 | if (loc) | |
1981 | set_tree_location (false_jump, loc); | |
1982 | ||
1983 | tree stmt = | |
1984 | build3 (COND_EXPR, void_type_node, boolval->as_tree (), | |
1985 | true_jump, false_jump); | |
1986 | if (loc) | |
1987 | set_tree_location (stmt, loc); | |
1988 | add_stmt (stmt); | |
1989 | } | |
1990 | ||
1991 | /* Add an unconditional jump statement to the function's statement list. */ | |
1992 | ||
1993 | void | |
1994 | playback::block:: | |
1995 | add_jump (location *loc, | |
1996 | block *target) | |
1997 | { | |
1998 | gcc_assert (target); | |
1999 | ||
2000 | // see c_finish_loop | |
2001 | //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE); | |
2002 | //add_stmt (top); | |
2003 | ||
2004 | //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_)); | |
2005 | TREE_USED (target->as_label_decl ()) = 1; | |
2006 | tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ()); | |
2007 | if (loc) | |
2008 | set_tree_location (stmt, loc); | |
2009 | add_stmt (stmt); | |
2010 | ||
2011 | /* | |
e53b6e56 | 2012 | from c-typeck.cc: |
35485da9 DM |
2013 | tree |
2014 | c_finish_goto_label (location_t loc, tree label) | |
2015 | { | |
2016 | tree decl = lookup_label_for_goto (loc, label); | |
2017 | if (!decl) | |
2018 | return NULL_TREE; | |
2019 | TREE_USED (decl) = 1; | |
2020 | { | |
2021 | tree t = build1 (GOTO_EXPR, void_type_node, decl); | |
2022 | SET_EXPR_LOCATION (t, loc); | |
2023 | return add_stmt (t); | |
2024 | } | |
2025 | } | |
2026 | */ | |
2027 | ||
2028 | } | |
2029 | ||
2030 | /* Add a return statement to the function's statement list. */ | |
2031 | ||
2032 | void | |
2033 | playback::block:: | |
2034 | add_return (location *loc, | |
2035 | rvalue *rvalue) | |
2036 | { | |
2037 | tree modify_retval = NULL; | |
2038 | tree return_type = m_func->get_return_type_as_tree (); | |
2039 | if (rvalue) | |
2040 | { | |
2041 | tree t_lvalue = DECL_RESULT (m_func->as_fndecl ()); | |
2042 | tree t_rvalue = rvalue->as_tree (); | |
2043 | if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue)) | |
2044 | t_rvalue = build1 (CONVERT_EXPR, | |
2045 | TREE_TYPE (t_lvalue), | |
2046 | t_rvalue); | |
2047 | modify_retval = build2 (MODIFY_EXPR, return_type, | |
2048 | t_lvalue, t_rvalue); | |
2049 | if (loc) | |
2050 | set_tree_location (modify_retval, loc); | |
2051 | } | |
2052 | tree return_stmt = build1 (RETURN_EXPR, return_type, | |
2053 | modify_retval); | |
2054 | if (loc) | |
2055 | set_tree_location (return_stmt, loc); | |
2056 | ||
2057 | add_stmt (return_stmt); | |
2058 | } | |
2059 | ||
ec5d0088 DM |
2060 | /* Helper function for playback::block::add_switch. |
2061 | Construct a case label for the given range, followed by a goto stmt | |
2062 | to the given block, appending them to stmt list *ptr_t_switch_body. */ | |
2063 | ||
2064 | static void | |
2065 | add_case (tree *ptr_t_switch_body, | |
2066 | tree t_low_value, | |
2067 | tree t_high_value, | |
2068 | playback::block *dest_block) | |
2069 | { | |
2070 | tree t_label = create_artificial_label (UNKNOWN_LOCATION); | |
2071 | DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl (); | |
2072 | ||
2073 | tree t_case_label = | |
2074 | build_case_label (t_low_value, t_high_value, t_label); | |
2075 | append_to_statement_list (t_case_label, ptr_t_switch_body); | |
2076 | ||
2077 | tree t_goto_stmt = | |
2078 | build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ()); | |
2079 | append_to_statement_list (t_goto_stmt, ptr_t_switch_body); | |
2080 | } | |
2081 | ||
2082 | /* Add a switch statement to the function's statement list. | |
2083 | ||
9e851845 | 2084 | We create a switch body, and populate it with case labels, each |
ec5d0088 DM |
2085 | followed by a goto to the desired block. */ |
2086 | ||
2087 | void | |
2088 | playback::block:: | |
2089 | add_switch (location *loc, | |
2090 | rvalue *expr, | |
2091 | block *default_block, | |
2092 | const auto_vec <case_> *cases) | |
2093 | { | |
2094 | /* Compare with: | |
e53b6e56 ML |
2095 | - c/c-typeck.cc: c_start_case |
2096 | - c-family/c-common.cc:c_add_case_label | |
2097 | - java/expr.cc:expand_java_switch and expand_java_add_case | |
ec5d0088 | 2098 | We've already rejected overlaps and duplicates in |
e53b6e56 | 2099 | libgccjit.cc:case_range_validator::validate. */ |
ec5d0088 DM |
2100 | |
2101 | tree t_expr = expr->as_tree (); | |
2102 | tree t_type = TREE_TYPE (t_expr); | |
2103 | ||
2104 | tree t_switch_body = alloc_stmt_list (); | |
2105 | ||
2106 | int i; | |
2107 | case_ *c; | |
2108 | FOR_EACH_VEC_ELT (*cases, i, c) | |
2109 | { | |
2110 | tree t_low_value = c->m_min_value->as_tree (); | |
2111 | tree t_high_value = c->m_max_value->as_tree (); | |
9e851845 | 2112 | add_case (&t_switch_body, t_low_value, t_high_value, c->m_dest_block); |
ec5d0088 DM |
2113 | } |
2114 | /* Default label. */ | |
9e851845 | 2115 | add_case (&t_switch_body, NULL_TREE, NULL_TREE, default_block); |
ec5d0088 | 2116 | |
9e851845 | 2117 | tree switch_stmt = build2 (SWITCH_EXPR, t_type, t_expr, t_switch_body); |
ec5d0088 DM |
2118 | if (loc) |
2119 | set_tree_location (switch_stmt, loc); | |
2120 | add_stmt (switch_stmt); | |
2121 | } | |
2122 | ||
421d0d0f DM |
2123 | /* Convert OPERANDS to a tree-based chain suitable for creating an |
2124 | extended asm stmt. | |
2125 | Compare with c_parser_asm_operands. */ | |
2126 | ||
2127 | static tree | |
2128 | build_operand_chain (const auto_vec <playback::asm_operand> *operands) | |
2129 | { | |
2130 | tree result = NULL_TREE; | |
2131 | unsigned i; | |
2132 | playback::asm_operand *asm_op; | |
2133 | FOR_EACH_VEC_ELT (*operands, i, asm_op) | |
2134 | { | |
2135 | tree name = build_string (asm_op->m_asm_symbolic_name); | |
2136 | tree str = build_string (asm_op->m_constraint); | |
2137 | tree value = asm_op->m_expr; | |
2138 | result = chainon (result, | |
2139 | build_tree_list (build_tree_list (name, str), | |
2140 | value)); | |
2141 | } | |
2142 | return result; | |
2143 | } | |
2144 | ||
2145 | /* Convert CLOBBERS to a tree-based list suitable for creating an | |
2146 | extended asm stmt. | |
2147 | Compare with c_parser_asm_clobbers. */ | |
2148 | ||
2149 | static tree | |
2150 | build_clobbers (const auto_vec <const char *> *clobbers) | |
2151 | { | |
2152 | tree list = NULL_TREE; | |
2153 | unsigned i; | |
2154 | const char *clobber; | |
2155 | FOR_EACH_VEC_ELT (*clobbers, i, clobber) | |
2156 | { | |
2157 | tree str = build_string (clobber); | |
2158 | list = tree_cons (NULL_TREE, str, list); | |
2159 | } | |
2160 | return list; | |
2161 | } | |
2162 | ||
2163 | /* Convert BLOCKS to a tree-based list suitable for creating an | |
2164 | extended asm stmt. | |
2165 | Compare with c_parser_asm_goto_operands. */ | |
2166 | ||
2167 | static tree | |
2168 | build_goto_operands (const auto_vec <playback::block *> *blocks) | |
2169 | { | |
2170 | tree list = NULL_TREE; | |
2171 | unsigned i; | |
2172 | playback::block *b; | |
2173 | FOR_EACH_VEC_ELT (*blocks, i, b) | |
2174 | { | |
2175 | tree label = b->as_label_decl (); | |
2176 | tree name = build_string (IDENTIFIER_POINTER (DECL_NAME (label))); | |
2177 | TREE_USED (label) = 1; | |
2178 | list = tree_cons (name, label, list); | |
2179 | } | |
2180 | return nreverse (list); | |
2181 | } | |
2182 | ||
2183 | /* Add an extended asm statement to this block. | |
2184 | ||
e53b6e56 ML |
2185 | Compare with c_parser_asm_statement (in c/c-parser.cc) |
2186 | and build_asm_expr (in c/c-typeck.cc). */ | |
421d0d0f DM |
2187 | |
2188 | void | |
2189 | playback::block::add_extended_asm (location *loc, | |
2190 | const char *asm_template, | |
2191 | bool is_volatile, | |
2192 | bool is_inline, | |
2193 | const auto_vec <asm_operand> *outputs, | |
2194 | const auto_vec <asm_operand> *inputs, | |
2195 | const auto_vec <const char *> *clobbers, | |
2196 | const auto_vec <block *> *goto_blocks) | |
2197 | { | |
2198 | tree t_string = build_string (asm_template); | |
2199 | tree t_outputs = build_operand_chain (outputs); | |
2200 | tree t_inputs = build_operand_chain (inputs); | |
2201 | tree t_clobbers = build_clobbers (clobbers); | |
2202 | tree t_labels = build_goto_operands (goto_blocks); | |
2203 | t_string | |
2204 | = resolve_asm_operand_names (t_string, t_outputs, t_inputs, t_labels); | |
2205 | tree asm_stmt | |
2206 | = build5 (ASM_EXPR, void_type_node, | |
2207 | t_string, t_outputs, t_inputs, t_clobbers, t_labels); | |
2208 | ||
2209 | /* asm statements without outputs, including simple ones, are treated | |
2210 | as volatile. */ | |
2211 | ASM_VOLATILE_P (asm_stmt) = (outputs->length () == 0); | |
2212 | ASM_INPUT_P (asm_stmt) = 0; /* extended asm stmts are not "simple". */ | |
2213 | ASM_INLINE_P (asm_stmt) = is_inline; | |
2214 | if (is_volatile) | |
2215 | ASM_VOLATILE_P (asm_stmt) = 1; | |
2216 | if (loc) | |
2217 | set_tree_location (asm_stmt, loc); | |
2218 | add_stmt (asm_stmt); | |
2219 | } | |
2220 | ||
35485da9 DM |
2221 | /* Constructor for gcc::jit::playback::block. */ |
2222 | ||
2223 | playback::block:: | |
2224 | block (function *func, | |
2225 | const char *name) | |
2226 | : m_func (func), | |
2227 | m_stmts () | |
2228 | { | |
2229 | tree identifier; | |
2230 | ||
2231 | gcc_assert (func); | |
2232 | // name can be NULL | |
2233 | if (name) | |
2234 | identifier = get_identifier (name); | |
2235 | else | |
2236 | identifier = NULL; | |
2237 | m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL, | |
2238 | identifier, void_type_node); | |
2239 | DECL_CONTEXT (m_label_decl) = func->as_fndecl (); | |
2240 | m_label_expr = NULL; | |
2241 | } | |
2242 | ||
35485da9 DM |
2243 | /* Compile a playback::context: |
2244 | ||
2245 | - Use the context's options to cconstruct command-line options, and | |
2246 | call into the rest of GCC (toplev::main). | |
fdce7209 DM |
2247 | - Assuming it succeeds, we have a .s file. |
2248 | - We then run the "postprocess" vfunc: | |
35485da9 | 2249 | |
fdce7209 DM |
2250 | (A) In-memory compile ("gcc_jit_context_compile") |
2251 | ||
2252 | For an in-memory compile we have the playback::compile_to_memory | |
2253 | subclass; "postprocess" will convert the .s file to a .so DSO, | |
2254 | and load it in memory (via dlopen), wrapping the result up as | |
2255 | a jit::result and returning it. | |
2256 | ||
2257 | (B) Compile to file ("gcc_jit_context_compile_to_file") | |
2258 | ||
2259 | When compiling to a file, we have the playback::compile_to_file | |
2260 | subclass; "postprocess" will either copy the .s file to the | |
2261 | destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke | |
2262 | the driver to convert it as necessary, copying the result. */ | |
2263 | ||
2264 | void | |
35485da9 DM |
2265 | playback::context:: |
2266 | compile () | |
2267 | { | |
eb4c16eb DM |
2268 | JIT_LOG_SCOPE (get_logger ()); |
2269 | ||
35485da9 | 2270 | const char *ctxt_progname; |
35485da9 | 2271 | |
d1e5f2c7 DM |
2272 | int keep_intermediates = |
2273 | get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES); | |
35485da9 | 2274 | |
d2286af3 | 2275 | m_tempdir = new tempdir (get_logger (), keep_intermediates); |
d1e5f2c7 | 2276 | if (!m_tempdir->create ()) |
fdce7209 | 2277 | return; |
35485da9 DM |
2278 | |
2279 | /* Call into the rest of gcc. | |
2280 | For now, we have to assemble command-line options to pass into | |
2281 | toplev::main, so that they can be parsed. */ | |
2282 | ||
2283 | /* Pass in user-provided program name as argv0, if any, so that it | |
2284 | makes it into GCC's "progname" global, used in various diagnostics. */ | |
2285 | ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME); | |
35485da9 | 2286 | |
c985705a DM |
2287 | if (!ctxt_progname) |
2288 | ctxt_progname = "libgccjit.so"; | |
2289 | ||
463366a0 DM |
2290 | auto_vec <recording::requested_dump> requested_dumps; |
2291 | m_recording_ctxt->get_all_requested_dumps (&requested_dumps); | |
2292 | ||
2cb844ce DM |
2293 | /* Acquire the JIT mutex and set "this" as the active playback ctxt. */ |
2294 | acquire_mutex (); | |
2295 | ||
3de37a5d | 2296 | auto_string_vec fake_args; |
463366a0 | 2297 | make_fake_args (&fake_args, ctxt_progname, &requested_dumps); |
8f50ee3c | 2298 | if (errors_occurred ()) |
2cb844ce DM |
2299 | { |
2300 | release_mutex (); | |
2301 | return; | |
2302 | } | |
38771e4e | 2303 | |
463366a0 | 2304 | /* This runs the compiler. */ |
afed3459 | 2305 | toplev toplev (get_timer (), /* external_timer */ |
6fc2d0f3 | 2306 | false); /* init_signals */ |
eb4c16eb DM |
2307 | enter_scope ("toplev::main"); |
2308 | if (get_logger ()) | |
2309 | for (unsigned i = 0; i < fake_args.length (); i++) | |
2310 | get_logger ()->log ("argv[%i]: %s", i, fake_args[i]); | |
8f50ee3c DM |
2311 | toplev.main (fake_args.length (), |
2312 | const_cast <char **> (fake_args.address ())); | |
eb4c16eb | 2313 | exit_scope ("toplev::main"); |
463366a0 DM |
2314 | |
2315 | /* Extracting dumps makes use of the gcc::dump_manager, hence we | |
2316 | need to do it between toplev::main (which creates the dump manager) | |
2317 | and toplev::finalize (which deletes it). */ | |
2318 | extract_any_requested_dumps (&requested_dumps); | |
2319 | ||
2320 | /* Clean up the compiler. */ | |
eb4c16eb | 2321 | enter_scope ("toplev::finalize"); |
35485da9 | 2322 | toplev.finalize (); |
eb4c16eb | 2323 | exit_scope ("toplev::finalize"); |
35485da9 | 2324 | |
38771e4e DM |
2325 | /* Ideally we would release the jit mutex here, but we can't yet since |
2326 | followup activities use timevars, which are global state. */ | |
35485da9 DM |
2327 | |
2328 | if (errors_occurred ()) | |
38771e4e DM |
2329 | { |
2330 | release_mutex (); | |
fdce7209 | 2331 | return; |
38771e4e | 2332 | } |
35485da9 DM |
2333 | |
2334 | if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE)) | |
c6760a13 | 2335 | dump_generated_code (); |
35485da9 | 2336 | |
fdce7209 DM |
2337 | /* We now have a .s file. |
2338 | ||
2339 | Run any postprocessing steps. This will either convert the .s file to | |
2340 | a .so DSO, and load it in memory (playback::compile_to_memory), or | |
2341 | convert the .s file to the requested output format, and copy it to a | |
2342 | given file (playback::compile_to_file). */ | |
2343 | postprocess (ctxt_progname); | |
2344 | ||
2345 | release_mutex (); | |
2346 | } | |
2347 | ||
2348 | /* Implementation of class gcc::jit::playback::compile_to_memory, | |
2349 | a subclass of gcc::jit::playback::context. */ | |
2350 | ||
2351 | /* playback::compile_to_memory's trivial constructor. */ | |
2352 | ||
2353 | playback::compile_to_memory::compile_to_memory (recording::context *ctxt) : | |
2354 | playback::context (ctxt), | |
2355 | m_result (NULL) | |
2356 | { | |
2357 | JIT_LOG_SCOPE (get_logger ()); | |
2358 | } | |
2359 | ||
2360 | /* Implementation of the playback::context::process vfunc for compiling | |
2361 | to memory. | |
2362 | ||
2363 | Convert the .s file to a .so DSO, and load it in memory (via dlopen), | |
2364 | wrapping the result up as a jit::result and returning it. */ | |
2365 | ||
2366 | void | |
2367 | playback::compile_to_memory::postprocess (const char *ctxt_progname) | |
2368 | { | |
2369 | JIT_LOG_SCOPE (get_logger ()); | |
c6760a13 DM |
2370 | convert_to_dso (ctxt_progname); |
2371 | if (errors_occurred ()) | |
fdce7209 DM |
2372 | return; |
2373 | m_result = dlopen_built_dso (); | |
2374 | } | |
2375 | ||
2376 | /* Implementation of class gcc::jit::playback::compile_to_file, | |
2377 | a subclass of gcc::jit::playback::context. */ | |
2378 | ||
2379 | /* playback::compile_to_file's trivial constructor. */ | |
2380 | ||
2381 | playback::compile_to_file::compile_to_file (recording::context *ctxt, | |
2382 | enum gcc_jit_output_kind output_kind, | |
2383 | const char *output_path) : | |
2384 | playback::context (ctxt), | |
2385 | m_output_kind (output_kind), | |
2386 | m_output_path (output_path) | |
2387 | { | |
2388 | JIT_LOG_SCOPE (get_logger ()); | |
2389 | } | |
2390 | ||
2391 | /* Implementation of the playback::context::process vfunc for compiling | |
2392 | to a file. | |
2393 | ||
2394 | Either copy the .s file to the given destination (for | |
2395 | GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it | |
2396 | as necessary, copying the result. */ | |
2397 | ||
2398 | void | |
2399 | playback::compile_to_file::postprocess (const char *ctxt_progname) | |
2400 | { | |
2401 | JIT_LOG_SCOPE (get_logger ()); | |
2402 | ||
2403 | /* The driver takes different actions based on the filename, so | |
2404 | we provide a filename with an appropriate suffix for the | |
2405 | output kind, and then copy it up to the user-provided path, | |
2406 | rather than directly compiling it to the requested output path. */ | |
2407 | ||
2408 | switch (m_output_kind) | |
38771e4e | 2409 | { |
fdce7209 DM |
2410 | default: |
2411 | gcc_unreachable (); | |
2412 | ||
2413 | case GCC_JIT_OUTPUT_KIND_ASSEMBLER: | |
2414 | copy_file (get_tempdir ()->get_path_s_file (), | |
2415 | m_output_path); | |
199501ea | 2416 | /* The .s file is automatically unlinked by tempdir::~tempdir. */ |
fdce7209 DM |
2417 | break; |
2418 | ||
2419 | case GCC_JIT_OUTPUT_KIND_OBJECT_FILE: | |
2420 | { | |
2421 | char *tmp_o_path = ::concat (get_tempdir ()->get_path (), | |
2422 | "/fake.o", | |
2423 | NULL); | |
2424 | invoke_driver (ctxt_progname, | |
2425 | get_tempdir ()->get_path_s_file (), | |
2426 | tmp_o_path, | |
2427 | TV_ASSEMBLE, | |
2428 | false, /* bool shared, */ | |
2429 | false);/* bool run_linker */ | |
2430 | if (!errors_occurred ()) | |
199501ea DM |
2431 | { |
2432 | copy_file (tmp_o_path, | |
2433 | m_output_path); | |
2434 | get_tempdir ()->add_temp_file (tmp_o_path); | |
2435 | } | |
2436 | else | |
2437 | free (tmp_o_path); | |
fdce7209 DM |
2438 | } |
2439 | break; | |
2440 | ||
2441 | case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY: | |
2442 | invoke_driver (ctxt_progname, | |
2443 | get_tempdir ()->get_path_s_file (), | |
2444 | get_tempdir ()->get_path_so_file (), | |
2445 | TV_ASSEMBLE, | |
2446 | true, /* bool shared, */ | |
2447 | true);/* bool run_linker */ | |
2448 | if (!errors_occurred ()) | |
2449 | copy_file (get_tempdir ()->get_path_so_file (), | |
2450 | m_output_path); | |
199501ea | 2451 | /* The .so file is automatically unlinked by tempdir::~tempdir. */ |
fdce7209 DM |
2452 | break; |
2453 | ||
2454 | case GCC_JIT_OUTPUT_KIND_EXECUTABLE: | |
2455 | { | |
2456 | char *tmp_exe_path = ::concat (get_tempdir ()->get_path (), | |
2457 | "/fake.exe", | |
2458 | NULL); | |
2459 | invoke_driver (ctxt_progname, | |
2460 | get_tempdir ()->get_path_s_file (), | |
2461 | tmp_exe_path, | |
2462 | TV_ASSEMBLE, | |
2463 | false, /* bool shared, */ | |
2464 | true);/* bool run_linker */ | |
2465 | if (!errors_occurred ()) | |
199501ea DM |
2466 | { |
2467 | copy_file (tmp_exe_path, | |
2468 | m_output_path); | |
2469 | get_tempdir ()->add_temp_file (tmp_exe_path); | |
2470 | } | |
2471 | else | |
2472 | free (tmp_exe_path); | |
fdce7209 DM |
2473 | } |
2474 | break; | |
2475 | ||
38771e4e | 2476 | } |
35485da9 | 2477 | |
fdce7209 | 2478 | } |
35485da9 | 2479 | |
fdce7209 DM |
2480 | /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular, |
2481 | the "executable" bits). | |
2482 | ||
2483 | Any errors that occur are reported on the context and hence count as | |
2484 | a failure of the compile. | |
2485 | ||
2486 | We can't in general hardlink or use "rename" from the tempdir since | |
2487 | it might be on a different filesystem to the destination. For example, | |
2488 | I get EXDEV: "Invalid cross-device link". */ | |
2489 | ||
2490 | void | |
2491 | playback::compile_to_file::copy_file (const char *src_path, | |
2492 | const char *dst_path) | |
2493 | { | |
2494 | JIT_LOG_SCOPE (get_logger ()); | |
2495 | if (get_logger ()) | |
2496 | { | |
2497 | get_logger ()->log ("src_path: %s", src_path); | |
2498 | get_logger ()->log ("dst_path: %s", dst_path); | |
2499 | } | |
2500 | ||
2501 | FILE *f_in = NULL; | |
2502 | FILE *f_out = NULL; | |
2503 | size_t total_sz_in = 0; | |
2504 | size_t total_sz_out = 0; | |
2505 | char buf[4096]; | |
2506 | size_t sz_in; | |
2507 | struct stat stat_buf; | |
2508 | ||
2509 | f_in = fopen (src_path, "rb"); | |
2510 | if (!f_in) | |
2511 | { | |
2512 | add_error (NULL, | |
2513 | "unable to open %s for reading: %s", | |
2514 | src_path, | |
2515 | xstrerror (errno)); | |
2516 | return; | |
2517 | } | |
38771e4e | 2518 | |
fdce7209 DM |
2519 | /* Use stat on the filedescriptor to get the mode, |
2520 | so that we can copy it over (in particular, the | |
2521 | "executable" bits). */ | |
01512446 | 2522 | if (fstat (fileno (f_in), &stat_buf) == -1) |
fdce7209 DM |
2523 | { |
2524 | add_error (NULL, | |
2525 | "unable to fstat %s: %s", | |
2526 | src_path, | |
2527 | xstrerror (errno)); | |
2528 | fclose (f_in); | |
2529 | return; | |
2530 | } | |
2531 | ||
2532 | f_out = fopen (dst_path, "wb"); | |
2533 | if (!f_out) | |
2534 | { | |
2535 | add_error (NULL, | |
2536 | "unable to open %s for writing: %s", | |
2537 | dst_path, | |
2538 | xstrerror (errno)); | |
2539 | fclose (f_in); | |
2540 | return; | |
2541 | } | |
2542 | ||
2543 | while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) ) | |
2544 | { | |
2545 | total_sz_in += sz_in; | |
2546 | size_t sz_out_remaining = sz_in; | |
2547 | size_t sz_out_so_far = 0; | |
2548 | while (sz_out_remaining) | |
2549 | { | |
2550 | size_t sz_out = fwrite (buf + sz_out_so_far, | |
2551 | 1, | |
2552 | sz_out_remaining, | |
2553 | f_out); | |
2554 | gcc_assert (sz_out <= sz_out_remaining); | |
2555 | if (!sz_out) | |
2556 | { | |
2557 | add_error (NULL, | |
2558 | "error writing to %s: %s", | |
2559 | dst_path, | |
2560 | xstrerror (errno)); | |
2561 | fclose (f_in); | |
2562 | fclose (f_out); | |
2563 | return; | |
2564 | } | |
2565 | total_sz_out += sz_out; | |
2566 | sz_out_so_far += sz_out; | |
2567 | sz_out_remaining -= sz_out; | |
2568 | } | |
2569 | gcc_assert (sz_out_so_far == sz_in); | |
2570 | } | |
2571 | ||
2572 | if (!feof (f_in)) | |
2573 | add_error (NULL, | |
2574 | "error reading from %s: %s", | |
2575 | src_path, | |
2576 | xstrerror (errno)); | |
2577 | ||
2578 | fclose (f_in); | |
2579 | ||
2580 | gcc_assert (total_sz_in == total_sz_out); | |
2581 | if (get_logger ()) | |
c83027f3 | 2582 | get_logger ()->log ("total bytes copied: %zu", total_sz_out); |
fdce7209 | 2583 | |
c83027f3 NB |
2584 | /* fchmod does not exist in Windows. */ |
2585 | #ifndef _WIN32 | |
fdce7209 DM |
2586 | /* Set the permissions of the copy to those of the original file, |
2587 | in particular the "executable" bits. */ | |
01512446 | 2588 | if (fchmod (fileno (f_out), stat_buf.st_mode) == -1) |
fdce7209 DM |
2589 | add_error (NULL, |
2590 | "error setting mode of %s: %s", | |
2591 | dst_path, | |
2592 | xstrerror (errno)); | |
c83027f3 | 2593 | #endif |
fdce7209 DM |
2594 | |
2595 | fclose (f_out); | |
35485da9 DM |
2596 | } |
2597 | ||
8f50ee3c DM |
2598 | /* Helper functions for gcc::jit::playback::context::compile. */ |
2599 | ||
38771e4e DM |
2600 | /* This mutex guards gcc::jit::recording::context::compile, so that only |
2601 | one thread can be accessing the bulk of GCC's state at once. */ | |
2602 | ||
2603 | static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER; | |
2604 | ||
2605 | /* Acquire jit_mutex and set "this" as the active playback ctxt. */ | |
2606 | ||
2607 | void | |
2608 | playback::context::acquire_mutex () | |
2609 | { | |
afed3459 DM |
2610 | auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX); |
2611 | ||
38771e4e | 2612 | /* Acquire the big GCC mutex. */ |
eb4c16eb | 2613 | JIT_LOG_SCOPE (get_logger ()); |
38771e4e | 2614 | pthread_mutex_lock (&jit_mutex); |
01512446 | 2615 | gcc_assert (active_playback_ctxt == NULL); |
38771e4e DM |
2616 | active_playback_ctxt = this; |
2617 | } | |
2618 | ||
2619 | /* Release jit_mutex and clear the active playback ctxt. */ | |
2620 | ||
2621 | void | |
2622 | playback::context::release_mutex () | |
2623 | { | |
2624 | /* Release the big GCC mutex. */ | |
eb4c16eb | 2625 | JIT_LOG_SCOPE (get_logger ()); |
38771e4e DM |
2626 | gcc_assert (active_playback_ctxt == this); |
2627 | active_playback_ctxt = NULL; | |
2628 | pthread_mutex_unlock (&jit_mutex); | |
2629 | } | |
2630 | ||
2cb844ce DM |
2631 | /* Callback used by gcc::jit::playback::context::make_fake_args when |
2632 | invoking driver_get_configure_time_options. | |
2633 | Populate a vec <char * > with the configure-time options. */ | |
2634 | ||
2635 | static void | |
2636 | append_arg_from_driver (const char *option, void *user_data) | |
2637 | { | |
2638 | gcc_assert (option); | |
2639 | gcc_assert (user_data); | |
2640 | vec <char *> *argvec = static_cast <vec <char *> *> (user_data); | |
2641 | argvec->safe_push (concat ("-", option, NULL)); | |
2642 | } | |
2643 | ||
8f50ee3c DM |
2644 | /* Build a fake argv for toplev::main from the options set |
2645 | by the user on the context . */ | |
2646 | ||
2647 | void | |
2648 | playback::context:: | |
463366a0 DM |
2649 | make_fake_args (vec <char *> *argvec, |
2650 | const char *ctxt_progname, | |
2651 | vec <recording::requested_dump> *requested_dumps) | |
8f50ee3c | 2652 | { |
eb4c16eb DM |
2653 | JIT_LOG_SCOPE (get_logger ()); |
2654 | ||
463366a0 DM |
2655 | #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg)) |
2656 | #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg) | |
8f50ee3c DM |
2657 | |
2658 | ADD_ARG (ctxt_progname); | |
d1e5f2c7 | 2659 | ADD_ARG (get_path_c_file ()); |
8f50ee3c DM |
2660 | ADD_ARG ("-fPIC"); |
2661 | ||
2662 | /* Handle int options: */ | |
2663 | switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL)) | |
2664 | { | |
2665 | default: | |
2666 | add_error (NULL, | |
2667 | "unrecognized optimization level: %i", | |
2668 | get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL)); | |
2669 | return; | |
2670 | ||
2671 | case 0: | |
2672 | ADD_ARG ("-O0"); | |
2673 | break; | |
2674 | ||
2675 | case 1: | |
2676 | ADD_ARG ("-O1"); | |
2677 | break; | |
2678 | ||
2679 | case 2: | |
2680 | ADD_ARG ("-O2"); | |
2681 | break; | |
2682 | ||
2683 | case 3: | |
2684 | ADD_ARG ("-O3"); | |
2685 | break; | |
2686 | } | |
2687 | /* What about -Os? */ | |
2688 | ||
2689 | /* Handle bool options: */ | |
2690 | if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO)) | |
2691 | ADD_ARG ("-g"); | |
2692 | ||
2693 | /* Suppress timing (and other) info. */ | |
2694 | if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY)) | |
2695 | { | |
2696 | ADD_ARG ("-quiet"); | |
2697 | quiet_flag = 1; | |
2698 | } | |
2699 | ||
2700 | /* Aggressively garbage-collect, to shake out bugs: */ | |
2701 | if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC)) | |
2702 | { | |
56e04525 DM |
2703 | ADD_ARG ("--param=ggc-min-expand=0"); |
2704 | ADD_ARG ("--param=ggc-min-heapsize=0"); | |
8f50ee3c DM |
2705 | } |
2706 | ||
2707 | if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING)) | |
2708 | { | |
2709 | ADD_ARG ("-fdump-tree-all"); | |
2710 | ADD_ARG ("-fdump-rtl-all"); | |
2711 | ADD_ARG ("-fdump-ipa-all"); | |
2712 | } | |
463366a0 DM |
2713 | |
2714 | /* Add "-fdump-" options for any calls to | |
2715 | gcc_jit_context_enable_dump. */ | |
2716 | { | |
2717 | int i; | |
2718 | recording::requested_dump *d; | |
2719 | FOR_EACH_VEC_ELT (*requested_dumps, i, d) | |
2720 | { | |
2721 | char *arg = concat ("-fdump-", d->m_dumpname, NULL); | |
2722 | ADD_ARG_TAKE_OWNERSHIP (arg); | |
2723 | } | |
2724 | } | |
2725 | ||
2cb844ce DM |
2726 | /* PR jit/64810: Add any target-specific default options |
2727 | from OPTION_DEFAULT_SPECS, normally provided by the driver | |
2728 | in the non-jit case. | |
2729 | ||
2730 | The target-specific code can define OPTION_DEFAULT_SPECS: | |
2731 | default command options in the form of spec macros for the | |
2732 | driver to expand (). | |
2733 | ||
2734 | For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and, | |
2735 | if not overriden, injects the defaults as extra arguments to | |
2736 | cc1 etc. | |
2737 | For the jit case, we need to add these arguments here. The | |
2738 | input format (using the specs language) means that we have to run | |
2739 | part of the driver code here (driver_get_configure_time_options). | |
2740 | ||
2741 | To avoid running the spec-expansion code every time, we just do | |
2742 | it the first time (via a function-static flag), saving the result | |
2743 | into a function-static vec. | |
2744 | This flag and vec are global state (i.e. per-process). | |
2745 | They are guarded by the jit mutex. */ | |
2746 | { | |
2747 | static bool have_configure_time_options = false; | |
2748 | static vec <char *> configure_time_options; | |
2749 | ||
2750 | if (have_configure_time_options) | |
2751 | log ("reusing cached configure-time options"); | |
2752 | else | |
2753 | { | |
2754 | have_configure_time_options = true; | |
2755 | log ("getting configure-time options from driver"); | |
2756 | driver_get_configure_time_options (append_arg_from_driver, | |
2757 | &configure_time_options); | |
2758 | } | |
2759 | ||
2760 | int i; | |
2761 | char *opt; | |
2762 | ||
2763 | if (get_logger ()) | |
2764 | FOR_EACH_VEC_ELT (configure_time_options, i, opt) | |
2765 | log ("configure_time_options[%i]: %s", i, opt); | |
2766 | ||
2767 | /* configure_time_options should now contain the expanded options | |
2768 | from OPTION_DEFAULT_SPECS (if any). */ | |
2769 | FOR_EACH_VEC_ELT (configure_time_options, i, opt) | |
2770 | { | |
2771 | gcc_assert (opt); | |
2772 | gcc_assert (opt[0] == '-'); | |
2773 | ADD_ARG (opt); | |
2774 | } | |
2775 | } | |
2776 | ||
afed3459 DM |
2777 | if (get_timer ()) |
2778 | ADD_ARG ("-ftime-report"); | |
2779 | ||
fa22c20d DM |
2780 | /* Add any user-provided extra options, starting with any from |
2781 | parent contexts. */ | |
2782 | m_recording_ctxt->append_command_line_options (argvec); | |
2783 | ||
8f50ee3c | 2784 | #undef ADD_ARG |
463366a0 DM |
2785 | #undef ADD_ARG_TAKE_OWNERSHIP |
2786 | } | |
2787 | ||
2788 | /* The second half of the implementation of gcc_jit_context_enable_dump. | |
2789 | Iterate through the requested dumps, reading the underlying files | |
2790 | into heap-allocated buffers, writing pointers to the buffers into | |
2791 | the char ** pointers provided by client code. | |
2792 | Client code is responsible for calling free on the results. */ | |
2793 | ||
2794 | void | |
2795 | playback::context:: | |
2796 | extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps) | |
2797 | { | |
eb4c16eb DM |
2798 | JIT_LOG_SCOPE (get_logger ()); |
2799 | ||
463366a0 DM |
2800 | int i; |
2801 | recording::requested_dump *d; | |
2802 | FOR_EACH_VEC_ELT (*requested_dumps, i, d) | |
2803 | { | |
2804 | dump_file_info *dfi; | |
2805 | char *filename; | |
2806 | char *content; | |
2807 | ||
2808 | dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname); | |
2809 | if (!dfi) | |
2810 | { | |
2811 | add_error (NULL, "unrecognized dump: %s", d->m_dumpname); | |
2812 | continue; | |
2813 | } | |
2814 | ||
2815 | filename = g->get_dumps ()->get_dump_file_name (dfi); | |
2816 | content = read_dump_file (filename); | |
2817 | *(d->m_out_ptr) = content; | |
199501ea | 2818 | m_tempdir->add_temp_file (filename); |
463366a0 DM |
2819 | } |
2820 | } | |
2821 | ||
2822 | /* Helper function for playback::context::extract_any_requested_dumps | |
2823 | (itself for use in implementation of gcc_jit_context_enable_dump). | |
2824 | ||
2825 | Attempt to read the complete file at the given path, returning the | |
2826 | bytes found there as a buffer. | |
2827 | The caller is responsible for calling free on the result. | |
2828 | Errors will be reported on the context, and lead to NULL being | |
2829 | returned; an out-of-memory error will terminate the process. */ | |
2830 | ||
2831 | char * | |
2832 | playback::context::read_dump_file (const char *path) | |
2833 | { | |
2834 | char *result = NULL; | |
2835 | size_t total_sz = 0; | |
2836 | char buf[4096]; | |
2837 | size_t sz; | |
2838 | FILE *f_in; | |
2839 | ||
2840 | f_in = fopen (path, "r"); | |
2841 | if (!f_in) | |
2842 | { | |
2843 | add_error (NULL, "unable to open %s for reading", path); | |
2844 | return NULL; | |
2845 | } | |
2846 | ||
2847 | while ( (sz = fread (buf, 1, sizeof (buf), f_in)) ) | |
2848 | { | |
2849 | size_t old_total_sz = total_sz; | |
2850 | total_sz += sz; | |
2851 | result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1)); | |
2852 | memcpy (result + old_total_sz, buf, sz); | |
2853 | } | |
2854 | ||
2855 | if (!feof (f_in)) | |
2856 | { | |
2857 | add_error (NULL, "error reading from %s", path); | |
2858 | free (result); | |
1c35cc2c | 2859 | fclose (f_in); |
463366a0 DM |
2860 | return NULL; |
2861 | } | |
2862 | ||
2863 | fclose (f_in); | |
2864 | ||
2865 | if (result) | |
2866 | { | |
2867 | result[total_sz] = '\0'; | |
2868 | return result; | |
2869 | } | |
2870 | else | |
2871 | return xstrdup (""); | |
8f50ee3c DM |
2872 | } |
2873 | ||
c6760a13 DM |
2874 | /* Part of playback::context::compile (). |
2875 | ||
2876 | We have a .s file; we want a .so file. | |
e53b6e56 | 2877 | We could reuse parts of gcc/gcc.cc to do this. |
c6760a13 DM |
2878 | For now, just use the driver binary from the install, as |
2879 | named in gcc-driver-name.h | |
2880 | e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */ | |
2881 | ||
2882 | void | |
2883 | playback::context:: | |
2884 | convert_to_dso (const char *ctxt_progname) | |
fdce7209 DM |
2885 | { |
2886 | JIT_LOG_SCOPE (get_logger ()); | |
2887 | ||
2888 | invoke_driver (ctxt_progname, | |
2889 | m_tempdir->get_path_s_file (), | |
2890 | m_tempdir->get_path_so_file (), | |
2891 | TV_ASSEMBLE, | |
2892 | true, /* bool shared, */ | |
2893 | true);/* bool run_linker */ | |
2894 | } | |
2895 | ||
9376dd63 DM |
2896 | static const char * const gcc_driver_name = GCC_DRIVER_NAME; |
2897 | ||
fdce7209 DM |
2898 | void |
2899 | playback::context:: | |
2900 | invoke_driver (const char *ctxt_progname, | |
2901 | const char *input_file, | |
2902 | const char *output_file, | |
2903 | timevar_id_t tv_id, | |
2904 | bool shared, | |
2905 | bool run_linker) | |
c6760a13 | 2906 | { |
eb4c16eb | 2907 | JIT_LOG_SCOPE (get_logger ()); |
9376dd63 DM |
2908 | |
2909 | bool embedded_driver | |
2910 | = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER); | |
2911 | ||
c6760a13 DM |
2912 | /* Currently this lumps together both assembling and linking into |
2913 | TV_ASSEMBLE. */ | |
afed3459 | 2914 | auto_timevar assemble_timevar (get_timer (), tv_id); |
3de37a5d | 2915 | auto_string_vec argvec; |
eb3982c1 | 2916 | #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg)) |
c6760a13 | 2917 | |
c168eab9 | 2918 | ADD_ARG (gcc_driver_name); |
fdce7209 | 2919 | |
eb3982c1 DM |
2920 | add_multilib_driver_arguments (&argvec); |
2921 | ||
fdce7209 DM |
2922 | if (shared) |
2923 | ADD_ARG ("-shared"); | |
2924 | ||
2925 | if (!run_linker) | |
2926 | ADD_ARG ("-c"); | |
2927 | ||
2928 | ADD_ARG (input_file); | |
c168eab9 | 2929 | ADD_ARG ("-o"); |
fdce7209 | 2930 | ADD_ARG (output_file); |
c6760a13 DM |
2931 | |
2932 | /* Don't use the linker plugin. | |
2933 | If running with just a "make" and not a "make install", then we'd | |
2934 | run into | |
2935 | "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found" | |
2936 | libto_plugin is a .la at build time, with it becoming installed with | |
2937 | ".so" suffix: i.e. it doesn't exist with a .so suffix until install | |
2938 | time. */ | |
c168eab9 | 2939 | ADD_ARG ("-fno-use-linker-plugin"); |
c6760a13 | 2940 | |
baf3fbad DM |
2941 | #if defined (DARWIN_X86) || defined (DARWIN_PPC) |
2942 | /* OS X's linker defaults to treating undefined symbols as errors. | |
2943 | If the context has any imported functions or globals they will be | |
2944 | undefined until the .so is dynamically-linked into the process. | |
2945 | Ensure that the driver passes in "-undefined dynamic_lookup" to the | |
2946 | linker. */ | |
2947 | ADD_ARG ("-Wl,-undefined,dynamic_lookup"); | |
2948 | #endif | |
2949 | ||
9376dd63 DM |
2950 | if (0) |
2951 | ADD_ARG ("-v"); | |
2952 | ||
216090cc AC |
2953 | /* Add any user-provided driver extra options. */ |
2954 | ||
2955 | m_recording_ctxt->append_driver_options (&argvec); | |
2956 | ||
9376dd63 | 2957 | #undef ADD_ARG |
c6760a13 DM |
2958 | |
2959 | /* pex_one's error-handling requires pname to be non-NULL. */ | |
2960 | gcc_assert (ctxt_progname); | |
2961 | ||
eb4c16eb DM |
2962 | if (get_logger ()) |
2963 | for (unsigned i = 0; i < argvec.length (); i++) | |
2964 | get_logger ()->log ("argv[%i]: %s", i, argvec[i]); | |
2965 | ||
9376dd63 DM |
2966 | if (embedded_driver) |
2967 | invoke_embedded_driver (&argvec); | |
2968 | else | |
2969 | invoke_external_driver (ctxt_progname, &argvec); | |
2970 | } | |
2971 | ||
2972 | void | |
2973 | playback::context:: | |
2974 | invoke_embedded_driver (const vec <char *> *argvec) | |
2975 | { | |
2976 | JIT_LOG_SCOPE (get_logger ()); | |
2977 | driver d (true, /* can_finalize */ | |
2978 | false); /* debug */ | |
2979 | int result = d.main (argvec->length (), | |
2980 | const_cast <char **> (argvec->address ())); | |
2981 | d.finalize (); | |
2982 | if (result) | |
2983 | add_error (NULL, "error invoking gcc driver"); | |
2984 | } | |
2985 | ||
2986 | void | |
2987 | playback::context:: | |
2988 | invoke_external_driver (const char *ctxt_progname, | |
2989 | vec <char *> *argvec) | |
2990 | { | |
2991 | JIT_LOG_SCOPE (get_logger ()); | |
2992 | const char *errmsg; | |
2993 | int exit_status = 0; | |
2994 | int err = 0; | |
2995 | ||
2996 | /* pex argv arrays are NULL-terminated. */ | |
2997 | argvec->safe_push (NULL); | |
2998 | ||
c6760a13 DM |
2999 | errmsg = pex_one (PEX_SEARCH, /* int flags, */ |
3000 | gcc_driver_name, | |
9376dd63 | 3001 | const_cast <char *const *> (argvec->address ()), |
c6760a13 DM |
3002 | ctxt_progname, /* const char *pname */ |
3003 | NULL, /* const char *outname */ | |
3004 | NULL, /* const char *errname */ | |
3005 | &exit_status, /* int *status */ | |
3006 | &err); /* int *err*/ | |
3007 | if (errmsg) | |
3008 | { | |
3009 | add_error (NULL, "error invoking gcc driver: %s", errmsg); | |
3010 | return; | |
3011 | } | |
3012 | ||
3013 | /* pex_one can return a NULL errmsg when the executable wasn't | |
3014 | found (or doesn't exist), so trap these cases also. */ | |
3015 | if (exit_status || err) | |
3016 | { | |
3017 | add_error (NULL, | |
3018 | "error invoking gcc driver: exit_status: %i err: %i", | |
3019 | exit_status, err); | |
3020 | add_error (NULL, | |
3021 | "whilst attempting to run a driver named: %s", | |
3022 | gcc_driver_name); | |
3023 | add_error (NULL, | |
3024 | "PATH was: %s", | |
3025 | getenv ("PATH")); | |
3026 | return; | |
3027 | } | |
3028 | } | |
3029 | ||
eb3982c1 DM |
3030 | /* Extract the target-specific MULTILIB_DEFAULTS to |
3031 | multilib_defaults_raw for use by | |
3032 | playback::context::add_multilib_driver_arguments (). */ | |
3033 | ||
3034 | #ifndef MULTILIB_DEFAULTS | |
3035 | #define MULTILIB_DEFAULTS { "" } | |
3036 | #endif | |
3037 | ||
3038 | static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS; | |
3039 | ||
3040 | /* Helper function for playback::context::invoke_driver (). | |
3041 | ||
3042 | 32-bit and 64-bit multilib peer builds of libgccjit.so may share | |
3043 | a driver binary. We need to pass in options to the shared driver | |
3044 | to get the appropriate assembler/linker options for this multilib | |
3045 | peer. */ | |
3046 | ||
3047 | void | |
3048 | playback::context:: | |
3049 | add_multilib_driver_arguments (vec <char *> *argvec) | |
3050 | { | |
3051 | JIT_LOG_SCOPE (get_logger ()); | |
3052 | ||
3053 | /* Add copies of the arguments in multilib_defaults_raw to argvec, | |
3054 | prepending each with a "-". */ | |
3055 | for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++) | |
3056 | if (multilib_defaults_raw[i][0]) | |
3057 | argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL)); | |
3058 | } | |
3059 | ||
38f4f641 DM |
3060 | /* Dynamically-link the built DSO file into this process, using dlopen. |
3061 | Wrap it up within a jit::result *, and return that. | |
3062 | Return NULL if any errors occur, reporting them on this context. */ | |
3063 | ||
3064 | result * | |
3065 | playback::context:: | |
3066 | dlopen_built_dso () | |
3067 | { | |
eb4c16eb | 3068 | JIT_LOG_SCOPE (get_logger ()); |
afed3459 | 3069 | auto_timevar load_timevar (get_timer (), TV_LOAD); |
c83027f3 | 3070 | result::handle handle = NULL; |
38f4f641 DM |
3071 | result *result_obj = NULL; |
3072 | ||
c83027f3 NB |
3073 | #ifdef _WIN32 |
3074 | /* Clear any existing error. */ | |
3075 | SetLastError(0); | |
3076 | ||
3077 | handle = LoadLibrary(m_tempdir->get_path_so_file ()); | |
3078 | if (GetLastError() != 0) { | |
3079 | print_last_error(); | |
3080 | } | |
3081 | #else | |
3082 | const char *error = NULL; | |
38f4f641 DM |
3083 | /* Clear any existing error. */ |
3084 | dlerror (); | |
3085 | ||
d1e5f2c7 DM |
3086 | handle = dlopen (m_tempdir->get_path_so_file (), |
3087 | RTLD_NOW | RTLD_LOCAL); | |
38f4f641 DM |
3088 | if ((error = dlerror()) != NULL) { |
3089 | add_error (NULL, "%s", error); | |
3090 | } | |
c83027f3 NB |
3091 | #endif |
3092 | ||
38f4f641 | 3093 | if (handle) |
d2286af3 DM |
3094 | { |
3095 | /* We've successfully dlopened the result; create a | |
3096 | jit::result object to wrap it. | |
3097 | ||
3098 | We're done with the tempdir for now, but if the user | |
3099 | has requested debugging, the user's debugger might not | |
3100 | be capable of dealing with the .so file being unlinked | |
3101 | immediately, so keep it around until after the result | |
3102 | is released. We do this by handing over ownership of | |
3103 | the jit::tempdir to the result. See PR jit/64206. */ | |
3104 | tempdir *handover_tempdir; | |
3105 | if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO)) | |
3106 | { | |
3107 | handover_tempdir = m_tempdir; | |
3108 | m_tempdir = NULL; | |
3109 | /* The tempdir will eventually be cleaned up in the | |
3110 | jit::result's dtor. */ | |
3111 | log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:" | |
3112 | " handing over tempdir to jit::result"); | |
3113 | } | |
3114 | else | |
3115 | { | |
3116 | handover_tempdir = NULL; | |
3117 | /* ... and retain ownership of m_tempdir so we clean it | |
3118 | up it the playback::context's dtor. */ | |
3119 | log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:" | |
3120 | " retaining ownership of tempdir"); | |
3121 | } | |
3122 | ||
3123 | result_obj = new result (get_logger (), handle, handover_tempdir); | |
3124 | } | |
38f4f641 DM |
3125 | else |
3126 | result_obj = NULL; | |
3127 | ||
3128 | return result_obj; | |
3129 | } | |
3130 | ||
35485da9 DM |
3131 | /* Top-level hook for playing back a recording context. |
3132 | ||
3133 | This plays back m_recording_ctxt, and, if no errors | |
3134 | occurred builds statement lists for and then postprocesses | |
3135 | every function in the result. */ | |
3136 | ||
3137 | void | |
3138 | playback::context:: | |
3139 | replay () | |
3140 | { | |
eb4c16eb | 3141 | JIT_LOG_SCOPE (get_logger ()); |
35485da9 | 3142 | |
332a9f76 | 3143 | init_types (); |
35485da9 DM |
3144 | |
3145 | /* Replay the recorded events: */ | |
3146 | timevar_push (TV_JIT_REPLAY); | |
3147 | ||
b258e263 DM |
3148 | /* Ensure that builtins that could be needed during optimization |
3149 | get created ahead of time. */ | |
3150 | builtins_manager *bm = m_recording_ctxt->get_builtins_manager (); | |
3151 | bm->ensure_optimization_builtins_exist (); | |
3152 | ||
35485da9 DM |
3153 | m_recording_ctxt->replay_into (this); |
3154 | ||
3155 | /* Clean away the temporary references from recording objects | |
3156 | to playback objects. We have to do this now since the | |
3157 | latter are GC-allocated, but the former don't mark these | |
3158 | refs. Hence we must stop using them before the GC can run. */ | |
3159 | m_recording_ctxt->disassociate_from_playback (); | |
3160 | ||
b258e263 | 3161 | /* The builtins_manager is associated with the recording::context |
eeafb319 DM |
3162 | and might be reused for future compiles on other playback::contexts, |
3163 | but its m_attributes array is not GTY-labeled and hence will become | |
3164 | nonsense if the GC runs. Purge this state. */ | |
b258e263 | 3165 | bm->finish_playback (); |
eeafb319 | 3166 | |
35485da9 DM |
3167 | timevar_pop (TV_JIT_REPLAY); |
3168 | ||
3169 | if (!errors_occurred ()) | |
3170 | { | |
3171 | int i; | |
3172 | function *func; | |
332a9f76 | 3173 | tree global; |
35485da9 DM |
3174 | /* No GC can happen yet; process the cached source locations. */ |
3175 | handle_locations (); | |
3176 | ||
332a9f76 PT |
3177 | /* Finalize globals. See how FORTRAN 95 does it in gfc_be_parse_file() |
3178 | for a simple reference. */ | |
3179 | FOR_EACH_VEC_ELT (m_globals, i, global) | |
3180 | rest_of_decl_compilation (global, true, true); | |
3181 | ||
3182 | wrapup_global_declarations (m_globals.address(), m_globals.length()); | |
3183 | ||
35485da9 DM |
3184 | /* We've now created tree nodes for the stmts in the various blocks |
3185 | in each function, but we haven't built each function's single stmt | |
3186 | list yet. Do so now. */ | |
3187 | FOR_EACH_VEC_ELT (m_functions, i, func) | |
3188 | func->build_stmt_list (); | |
3189 | ||
3190 | /* No GC can have happened yet. */ | |
3191 | ||
3192 | /* Postprocess the functions. This could trigger GC. */ | |
3193 | FOR_EACH_VEC_ELT (m_functions, i, func) | |
3194 | { | |
3195 | gcc_assert (func); | |
3196 | func->postprocess (); | |
3197 | } | |
3198 | } | |
3199 | } | |
3200 | ||
3201 | /* Dump the generated .s file to stderr. */ | |
3202 | ||
3203 | void | |
3204 | playback::context:: | |
3205 | dump_generated_code () | |
3206 | { | |
eb4c16eb | 3207 | JIT_LOG_SCOPE (get_logger ()); |
35485da9 DM |
3208 | char buf[4096]; |
3209 | size_t sz; | |
d1e5f2c7 | 3210 | FILE *f_in = fopen (get_path_s_file (), "r"); |
35485da9 DM |
3211 | if (!f_in) |
3212 | return; | |
3213 | ||
3214 | while ( (sz = fread (buf, 1, sizeof (buf), f_in)) ) | |
3215 | fwrite (buf, 1, sz, stderr); | |
3216 | ||
3217 | fclose (f_in); | |
3218 | } | |
3219 | ||
d1e5f2c7 DM |
3220 | /* Get the supposed path of the notional "fake.c" file within the |
3221 | tempdir. This file doesn't exist, but the rest of the compiler | |
3222 | needs a name. */ | |
3223 | ||
3224 | const char * | |
3225 | playback::context:: | |
3226 | get_path_c_file () const | |
3227 | { | |
3228 | return m_tempdir->get_path_c_file (); | |
3229 | } | |
3230 | ||
3231 | /* Get the path of the assembler output file "fake.s" file within the | |
3232 | tempdir. */ | |
3233 | ||
3234 | const char * | |
3235 | playback::context:: | |
3236 | get_path_s_file () const | |
3237 | { | |
3238 | return m_tempdir->get_path_s_file (); | |
3239 | } | |
3240 | ||
3241 | /* Get the path of the DSO object file "fake.so" file within the | |
3242 | tempdir. */ | |
3243 | ||
3244 | const char * | |
3245 | playback::context:: | |
3246 | get_path_so_file () const | |
3247 | { | |
3248 | return m_tempdir->get_path_so_file (); | |
3249 | } | |
3250 | ||
35485da9 DM |
3251 | /* qsort comparator for comparing pairs of playback::source_line *, |
3252 | ordering them by line number. */ | |
3253 | ||
3254 | static int | |
3255 | line_comparator (const void *lhs, const void *rhs) | |
3256 | { | |
3257 | const playback::source_line *line_lhs = \ | |
3258 | *static_cast<const playback::source_line * const*> (lhs); | |
3259 | const playback::source_line *line_rhs = \ | |
3260 | *static_cast<const playback::source_line * const*> (rhs); | |
3261 | return line_lhs->get_line_num () - line_rhs->get_line_num (); | |
3262 | } | |
3263 | ||
3264 | /* qsort comparator for comparing pairs of playback::location *, | |
3265 | ordering them by column number. */ | |
3266 | ||
3267 | static int | |
3268 | location_comparator (const void *lhs, const void *rhs) | |
3269 | { | |
3270 | const playback::location *loc_lhs = \ | |
3271 | *static_cast<const playback::location * const *> (lhs); | |
3272 | const playback::location *loc_rhs = \ | |
3273 | *static_cast<const playback::location * const *> (rhs); | |
3274 | return loc_lhs->get_column_num () - loc_rhs->get_column_num (); | |
3275 | } | |
3276 | ||
332a9f76 PT |
3277 | /* Initialize the NAME_TYPE of the primitive types as well as some |
3278 | others. */ | |
3279 | void | |
3280 | playback::context:: | |
3281 | init_types () | |
3282 | { | |
e53b6e56 | 3283 | /* See lto_init() in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc |
332a9f76 PT |
3284 | for reference. If TYPE_NAME is not set, debug info will not contain types */ |
3285 | #define NAME_TYPE(t,n) \ | |
3286 | if (t) \ | |
3287 | TYPE_NAME (t) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, \ | |
3288 | get_identifier (n), t) | |
3289 | ||
3290 | NAME_TYPE (integer_type_node, "int"); | |
3291 | NAME_TYPE (char_type_node, "char"); | |
3292 | NAME_TYPE (long_integer_type_node, "long int"); | |
3293 | NAME_TYPE (unsigned_type_node, "unsigned int"); | |
3294 | NAME_TYPE (long_unsigned_type_node, "long unsigned int"); | |
3295 | NAME_TYPE (long_long_integer_type_node, "long long int"); | |
3296 | NAME_TYPE (long_long_unsigned_type_node, "long long unsigned int"); | |
3297 | NAME_TYPE (short_integer_type_node, "short int"); | |
3298 | NAME_TYPE (short_unsigned_type_node, "short unsigned int"); | |
3299 | if (signed_char_type_node != char_type_node) | |
3300 | NAME_TYPE (signed_char_type_node, "signed char"); | |
3301 | if (unsigned_char_type_node != char_type_node) | |
3302 | NAME_TYPE (unsigned_char_type_node, "unsigned char"); | |
3303 | NAME_TYPE (float_type_node, "float"); | |
3304 | NAME_TYPE (double_type_node, "double"); | |
3305 | NAME_TYPE (long_double_type_node, "long double"); | |
3306 | NAME_TYPE (void_type_node, "void"); | |
3307 | NAME_TYPE (boolean_type_node, "bool"); | |
3308 | NAME_TYPE (complex_float_type_node, "complex float"); | |
3309 | NAME_TYPE (complex_double_type_node, "complex double"); | |
3310 | NAME_TYPE (complex_long_double_type_node, "complex long double"); | |
3311 | ||
3312 | m_const_char_ptr = build_pointer_type( | |
3313 | build_qualified_type (char_type_node, TYPE_QUAL_CONST)); | |
3314 | ||
3315 | NAME_TYPE (m_const_char_ptr, "char"); | |
3316 | NAME_TYPE (size_type_node, "size_t"); | |
3317 | NAME_TYPE (fileptr_type_node, "FILE"); | |
3318 | #undef NAME_TYPE | |
3319 | } | |
3320 | ||
35485da9 DM |
3321 | /* Our API allows locations to be created in arbitrary orders, but the |
3322 | linemap API requires locations to be created in ascending order | |
3323 | as if we were tokenizing files. | |
3324 | ||
026c3cfd | 3325 | This hook sorts all of the locations that have been created, and |
35485da9 DM |
3326 | calls into the linemap API, creating linemap entries in sorted order |
3327 | for our locations. */ | |
3328 | ||
3329 | void | |
3330 | playback::context:: | |
3331 | handle_locations () | |
3332 | { | |
3333 | /* Create the source code locations, following the ordering rules | |
3334 | imposed by the linemap API. | |
3335 | ||
3336 | line_table is a global. */ | |
eb4c16eb | 3337 | JIT_LOG_SCOPE (get_logger ()); |
35485da9 DM |
3338 | int i; |
3339 | source_file *file; | |
3340 | ||
3341 | FOR_EACH_VEC_ELT (m_source_files, i, file) | |
3342 | { | |
3343 | linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0); | |
3344 | ||
3345 | /* Sort lines by ascending line numbers. */ | |
3346 | file->m_source_lines.qsort (&line_comparator); | |
3347 | ||
3348 | int j; | |
3349 | source_line *line; | |
3350 | FOR_EACH_VEC_ELT (file->m_source_lines, j, line) | |
3351 | { | |
3352 | int k; | |
3353 | location *loc; | |
3354 | ||
3355 | /* Sort locations in line by ascending column numbers. */ | |
3356 | line->m_locations.qsort (&location_comparator); | |
3357 | ||
3358 | /* Determine maximum column within this line. */ | |
3359 | gcc_assert (line->m_locations.length () > 0); | |
3360 | location *final_column = | |
3361 | line->m_locations[line->m_locations.length () - 1]; | |
3362 | int max_col = final_column->get_column_num (); | |
3363 | ||
3364 | linemap_line_start (line_table, line->get_line_num (), max_col); | |
3365 | FOR_EACH_VEC_ELT (line->m_locations, k, loc) | |
3366 | { | |
3367 | loc->m_srcloc = \ | |
3368 | linemap_position_for_column (line_table, loc->get_column_num ()); | |
3369 | } | |
3370 | } | |
3371 | ||
3372 | linemap_add (line_table, LC_LEAVE, false, NULL, 0); | |
3373 | } | |
3374 | ||
3375 | /* line_table should now be populated; every playback::location should | |
3376 | now have an m_srcloc. */ | |
3377 | ||
3378 | /* Now assign them to tree nodes as appropriate. */ | |
3379 | std::pair<tree, location *> *cached_location; | |
3380 | ||
3381 | FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location) | |
3382 | { | |
3383 | tree t = cached_location->first; | |
620e594b | 3384 | location_t srcloc = cached_location->second->m_srcloc; |
35485da9 DM |
3385 | |
3386 | /* This covers expressions: */ | |
3387 | if (CAN_HAVE_LOCATION_P (t)) | |
3388 | SET_EXPR_LOCATION (t, srcloc); | |
3389 | else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL)) | |
3390 | DECL_SOURCE_LOCATION (t) = srcloc; | |
3391 | else | |
3392 | { | |
3393 | /* Don't know how to set location on this node. */ | |
3394 | } | |
3395 | } | |
3396 | } | |
3397 | ||
3398 | /* We handle errors on a playback::context by adding them to the | |
3399 | corresponding recording::context. */ | |
3400 | ||
3401 | void | |
3402 | playback::context:: | |
3403 | add_error (location *loc, const char *fmt, ...) | |
3404 | { | |
3405 | va_list ap; | |
3406 | va_start (ap, fmt); | |
3407 | m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL, | |
3408 | fmt, ap); | |
3409 | va_end (ap); | |
3410 | } | |
3411 | ||
3412 | /* We handle errors on a playback::context by adding them to the | |
3413 | corresponding recording::context. */ | |
3414 | ||
3415 | void | |
3416 | playback::context:: | |
3417 | add_error_va (location *loc, const char *fmt, va_list ap) | |
3418 | { | |
3419 | m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL, | |
3420 | fmt, ap); | |
3421 | } | |
3422 | ||
6b5423a5 DM |
3423 | /* Report a diagnostic up to the jit context as an error, |
3424 | so that the compilation is treated as a failure. | |
3425 | For now, any kind of diagnostic is treated as an error by the jit | |
3426 | API. */ | |
3427 | ||
3428 | void | |
3429 | playback::context:: | |
3430 | add_diagnostic (struct diagnostic_context *diag_context, | |
3431 | struct diagnostic_info *diagnostic) | |
3432 | { | |
3433 | /* At this point the text has been formatted into the pretty-printer's | |
3434 | output buffer. */ | |
3435 | pretty_printer *pp = diag_context->printer; | |
3436 | const char *text = pp_formatted_text (pp); | |
3437 | ||
3438 | /* Get location information (if any) from the diagnostic. | |
3439 | The recording::context::add_error[_va] methods require a | |
3440 | recording::location. We can't lookup the playback::location | |
3441 | from the file/line/column since any playback location instances | |
3442 | may have been garbage-collected away by now, so instead we create | |
3443 | another recording::location directly. */ | |
3444 | location_t gcc_loc = diagnostic_location (diagnostic); | |
3445 | recording::location *rec_loc = NULL; | |
3446 | if (gcc_loc) | |
3447 | { | |
3448 | expanded_location exploc = expand_location (gcc_loc); | |
3449 | if (exploc.file) | |
3450 | rec_loc = m_recording_ctxt->new_location (exploc.file, | |
3451 | exploc.line, | |
3452 | exploc.column, | |
3453 | false); | |
3454 | } | |
3455 | ||
3456 | m_recording_ctxt->add_error (rec_loc, "%s", text); | |
3457 | pp_clear_output_area (pp); | |
3458 | } | |
3459 | ||
35485da9 DM |
3460 | /* Dealing with the linemap API. */ |
3461 | ||
3462 | /* Construct a playback::location for a recording::location, if it | |
3463 | doesn't exist already. */ | |
3464 | ||
3465 | playback::location * | |
3466 | playback::context:: | |
3467 | new_location (recording::location *rloc, | |
3468 | const char *filename, | |
3469 | int line, | |
3470 | int column) | |
3471 | { | |
3472 | /* Get the source_file for filename, creating if necessary. */ | |
3473 | source_file *src_file = get_source_file (filename); | |
3474 | /* Likewise for the line within the file. */ | |
3475 | source_line *src_line = src_file->get_source_line (line); | |
3476 | /* Likewise for the column within the line. */ | |
3477 | location *loc = src_line->get_location (rloc, column); | |
3478 | return loc; | |
3479 | } | |
3480 | ||
3481 | /* Deferred setting of the location for a given tree, by adding the | |
3482 | (tree, playback::location) pair to a list of deferred associations. | |
3483 | We will actually set the location on the tree later on once | |
620e594b | 3484 | the location_t for the playback::location exists. */ |
35485da9 DM |
3485 | |
3486 | void | |
3487 | playback::context:: | |
3488 | set_tree_location (tree t, location *loc) | |
3489 | { | |
3490 | gcc_assert (loc); | |
3491 | m_cached_locations.safe_push (std::make_pair (t, loc)); | |
3492 | } | |
3493 | ||
3494 | ||
3495 | /* Construct a playback::source_file for the given source | |
3496 | filename, if it doesn't exist already. */ | |
3497 | ||
3498 | playback::source_file * | |
3499 | playback::context:: | |
3500 | get_source_file (const char *filename) | |
3501 | { | |
3502 | /* Locate the file. | |
3503 | For simplicitly, this is currently a linear search. | |
3504 | Replace with a hash if this shows up in the profile. */ | |
3505 | int i; | |
3506 | source_file *file; | |
3507 | tree ident_filename = get_identifier (filename); | |
3508 | ||
3509 | FOR_EACH_VEC_ELT (m_source_files, i, file) | |
3510 | if (file->filename_as_tree () == ident_filename) | |
3511 | return file; | |
3512 | ||
3513 | /* Not found. */ | |
3514 | file = new source_file (ident_filename); | |
3515 | m_source_files.safe_push (file); | |
3516 | return file; | |
3517 | } | |
3518 | ||
3519 | /* Constructor for gcc::jit::playback::source_file. */ | |
3520 | ||
3521 | playback::source_file::source_file (tree filename) : | |
3522 | m_source_lines (), | |
3523 | m_filename (filename) | |
3524 | { | |
3525 | } | |
3526 | ||
b957b2e0 DM |
3527 | /* Don't leak vec's internal buffer (in non-GC heap) when we are |
3528 | GC-ed. */ | |
3529 | ||
3530 | void | |
3531 | playback::source_file::finalizer () | |
3532 | { | |
3533 | m_source_lines.release (); | |
3534 | } | |
3535 | ||
35485da9 DM |
3536 | /* Construct a playback::source_line for the given line |
3537 | within this source file, if one doesn't exist already. */ | |
3538 | ||
3539 | playback::source_line * | |
3540 | playback::source_file:: | |
3541 | get_source_line (int line_num) | |
3542 | { | |
3543 | /* Locate the line. | |
3544 | For simplicitly, this is currently a linear search. | |
3545 | Replace with a hash if this shows up in the profile. */ | |
3546 | int i; | |
3547 | source_line *line; | |
3548 | ||
3549 | FOR_EACH_VEC_ELT (m_source_lines, i, line) | |
3550 | if (line->get_line_num () == line_num) | |
3551 | return line; | |
3552 | ||
3553 | /* Not found. */ | |
3554 | line = new source_line (this, line_num); | |
3555 | m_source_lines.safe_push (line); | |
3556 | return line; | |
3557 | } | |
3558 | ||
3559 | /* Constructor for gcc::jit::playback::source_line. */ | |
3560 | ||
3561 | playback::source_line::source_line (source_file *file, int line_num) : | |
3562 | m_locations (), | |
3563 | m_source_file (file), | |
3564 | m_line_num (line_num) | |
3565 | { | |
3566 | } | |
b957b2e0 DM |
3567 | |
3568 | /* Don't leak vec's internal buffer (in non-GC heap) when we are | |
3569 | GC-ed. */ | |
3570 | ||
3571 | void | |
3572 | playback::source_line::finalizer () | |
3573 | { | |
3574 | m_locations.release (); | |
3575 | } | |
35485da9 DM |
3576 | |
3577 | /* Construct a playback::location for the given column | |
3578 | within this line of a specific source file, if one doesn't exist | |
3579 | already. */ | |
3580 | ||
3581 | playback::location * | |
3582 | playback::source_line:: | |
3583 | get_location (recording::location *rloc, int column_num) | |
3584 | { | |
3585 | int i; | |
3586 | location *loc; | |
3587 | ||
3588 | /* Another linear search that probably should be a hash table. */ | |
3589 | FOR_EACH_VEC_ELT (m_locations, i, loc) | |
3590 | if (loc->get_column_num () == column_num) | |
3591 | return loc; | |
3592 | ||
3593 | /* Not found. */ | |
3594 | loc = new location (rloc, this, column_num); | |
3595 | m_locations.safe_push (loc); | |
3596 | return loc; | |
3597 | } | |
3598 | ||
3599 | /* Constructor for gcc::jit::playback::location. */ | |
3600 | ||
3601 | playback::location::location (recording::location *loc, | |
3602 | source_line *line, | |
3603 | int column_num) : | |
3604 | m_srcloc (UNKNOWN_LOCATION), | |
3605 | m_recording_loc (loc), | |
3606 | m_line (line), | |
3607 | m_column_num(column_num) | |
3608 | { | |
3609 | } | |
3610 | ||
3611 | /* The active gcc::jit::playback::context instance. This is a singleton, | |
3612 | guarded by jit_mutex. */ | |
3613 | ||
3614 | playback::context *active_playback_ctxt; | |
3615 | ||
3616 | } // namespace gcc::jit | |
3617 | ||
3618 | } // namespace gcc |