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