rtl: ICE with thread_local and inline asm [PR104777]
[official-gcc.git] / gcc / jit / jit-playback.cc
blobd1835c798636977b72e937a0c4295712d4ffb596
1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2022 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
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.
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.
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/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "target.h"
25 #include "tree.h"
26 #include "stringpool.h"
27 #include "cgraph.h"
28 #include "dumpfile.h"
29 #include "toplev.h"
30 #include "tree-cfg.h"
31 #include "convert.h"
32 #include "stor-layout.h"
33 #include "print-tree.h"
34 #include "gimplify.h"
35 #include "gcc-driver-name.h"
36 #include "attribs.h"
37 #include "context.h"
38 #include "fold-const.h"
39 #include "opt-suggestions.h"
40 #include "gcc.h"
41 #include "diagnostic.h"
42 #include "stmt.h"
44 #include <pthread.h>
46 #include "jit-playback.h"
47 #include "jit-result.h"
48 #include "jit-builtins.h"
49 #include "jit-tempdir.h"
51 #ifdef _WIN32
52 #include "jit-w32.h"
53 #endif
55 /* Compare with gcc/c-family/c-common.h: DECL_C_BIT_FIELD,
56 SET_DECL_C_BIT_FIELD.
57 These are redefined here to avoid depending from the C frontend. */
58 #define DECL_JIT_BIT_FIELD(NODE) \
59 (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1)
60 #define SET_DECL_JIT_BIT_FIELD(NODE) \
61 (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1)
63 /* gcc::jit::playback::context::build_cast uses the convert.h API,
64 which in turn requires the frontend to provide a "convert"
65 function, apparently as a fallback for casts that can be simplified
66 (truncation, extension). */
67 extern tree convert (tree type, tree expr);
69 tree
70 convert (tree dst_type, tree expr)
72 tree t_ret = NULL;
73 t_ret = targetm.convert_to_type (dst_type, expr);
74 if (t_ret)
75 return t_ret;
76 switch (TREE_CODE (dst_type))
78 case INTEGER_TYPE:
79 case ENUMERAL_TYPE:
80 return fold (convert_to_integer (dst_type, expr));
82 default:
83 gcc_assert (gcc::jit::active_playback_ctxt);
84 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
85 fprintf (stderr, "input expression:\n");
86 debug_tree (expr);
87 fprintf (stderr, "requested type:\n");
88 debug_tree (dst_type);
89 return error_mark_node;
93 namespace gcc {
94 namespace jit {
96 /**********************************************************************
97 Playback.
98 **********************************************************************/
100 /* Fold a readonly non-volatile variable with an initial constant value,
101 to that value.
103 Otherwise return the argument unchanged.
105 This fold is needed for setting a variable's DECL_INITIAL to the value
106 of a const variable. The c-frontend does this in its own special
107 fold (), so we lift this part out and do it explicitly where there is a
108 potential for variables to be used as rvalues. */
109 static tree
110 fold_const_var (tree node)
112 /* See c_fully_fold_internal in c-fold.cc and decl_constant_value_1
113 in c-typeck.cc. */
114 if (VAR_P (node)
115 && TREE_READONLY (node)
116 && !TREE_THIS_VOLATILE (node)
117 && DECL_INITIAL (node) != NULL_TREE
118 /* "This is invalid if initial value is not constant.
119 If it has either a function call, a memory reference,
120 or a variable, then re-evaluating it could give different
121 results." */
122 && TREE_CONSTANT (DECL_INITIAL (node)))
124 tree ret = DECL_INITIAL (node);
125 /* "Avoid unwanted tree sharing between the initializer and current
126 function's body where the tree can be modified e.g. by the
127 gimplifier." */
128 if (TREE_STATIC (node))
129 ret = unshare_expr (ret);
131 return ret;
134 return node;
137 /* Build a STRING_CST tree for STR, or return NULL if it is NULL.
138 The TREE_TYPE is not initialized. */
140 static tree
141 build_string (const char *str)
143 if (str)
144 return ::build_string (strlen (str), str);
145 else
146 return NULL_TREE;
149 /* The constructor for gcc::jit::playback::context. */
151 playback::context::context (recording::context *ctxt)
152 : log_user (ctxt->get_logger ()),
153 m_recording_ctxt (ctxt),
154 m_tempdir (NULL),
155 m_const_char_ptr (NULL)
157 JIT_LOG_SCOPE (get_logger ());
158 m_functions.create (0);
159 m_globals.create (0);
160 m_source_files.create (0);
161 m_cached_locations.create (0);
164 /* The destructor for gcc::jit::playback::context. */
166 playback::context::~context ()
168 JIT_LOG_SCOPE (get_logger ());
170 /* Normally the playback::context is responsible for cleaning up the
171 tempdir (including "fake.so" within the filesystem).
173 In the normal case, clean it up now.
175 However m_tempdir can be NULL if the context has handed over
176 responsibility for the tempdir cleanup to the jit::result object, so
177 that the cleanup can be delayed (see PR jit/64206). If that's the
178 case this "delete NULL;" is a no-op. */
179 delete m_tempdir;
181 m_functions.release ();
184 /* A playback::context can reference GC-managed pointers. Mark them
185 ("by hand", rather than by gengtype).
187 This is called on the active playback context (if any) by the
188 my_ggc_walker hook in the jit_root_table in dummy-frontend.cc. */
190 void
191 playback::context::
192 gt_ggc_mx ()
194 int i;
195 function *func;
196 FOR_EACH_VEC_ELT (m_functions, i, func)
198 if (ggc_test_and_set_mark (func))
199 func->gt_ggc_mx ();
203 /* Given an enum gcc_jit_types value, get a "tree" type. */
205 tree
206 playback::context::
207 get_tree_node_for_type (enum gcc_jit_types type_)
209 switch (type_)
211 case GCC_JIT_TYPE_VOID:
212 return void_type_node;
214 case GCC_JIT_TYPE_VOID_PTR:
215 return ptr_type_node;
217 case GCC_JIT_TYPE_BOOL:
218 return boolean_type_node;
220 case GCC_JIT_TYPE_CHAR:
221 return char_type_node;
222 case GCC_JIT_TYPE_SIGNED_CHAR:
223 return signed_char_type_node;
224 case GCC_JIT_TYPE_UNSIGNED_CHAR:
225 return unsigned_char_type_node;
227 case GCC_JIT_TYPE_SHORT:
228 return short_integer_type_node;
229 case GCC_JIT_TYPE_UNSIGNED_SHORT:
230 return short_unsigned_type_node;
232 case GCC_JIT_TYPE_CONST_CHAR_PTR:
233 return m_const_char_ptr;
235 case GCC_JIT_TYPE_INT:
236 return integer_type_node;
237 case GCC_JIT_TYPE_UNSIGNED_INT:
238 return unsigned_type_node;
240 case GCC_JIT_TYPE_LONG:
241 return long_integer_type_node;
242 case GCC_JIT_TYPE_UNSIGNED_LONG:
243 return long_unsigned_type_node;
245 case GCC_JIT_TYPE_LONG_LONG:
246 return long_long_integer_type_node;
247 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
248 return long_long_unsigned_type_node;
250 case GCC_JIT_TYPE_FLOAT:
251 return float_type_node;
252 case GCC_JIT_TYPE_DOUBLE:
253 return double_type_node;
254 case GCC_JIT_TYPE_LONG_DOUBLE:
255 return long_double_type_node;
257 case GCC_JIT_TYPE_SIZE_T:
258 return size_type_node;
260 case GCC_JIT_TYPE_FILE_PTR:
261 return fileptr_type_node;
263 case GCC_JIT_TYPE_COMPLEX_FLOAT:
264 return complex_float_type_node;
265 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
266 return complex_double_type_node;
267 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
268 return complex_long_double_type_node;
271 return NULL;
274 /* Construct a playback::type instance (wrapping a tree) for the given
275 enum value. */
277 playback::type *
278 playback::context::
279 get_type (enum gcc_jit_types type_)
281 tree type_node = get_tree_node_for_type (type_);
282 if (type_node == NULL)
284 add_error (NULL, "unrecognized (enum gcc_jit_types) value: %i", type_);
285 return NULL;
288 return new type (type_node);
291 /* Construct a playback::type instance (wrapping a tree) for the given
292 array type. */
294 playback::type *
295 playback::context::
296 new_array_type (playback::location *loc,
297 playback::type *element_type,
298 int num_elements)
300 gcc_assert (element_type);
302 tree t = build_array_type_nelts (element_type->as_tree (),
303 num_elements);
304 layout_type (t);
306 if (loc)
307 set_tree_location (t, loc);
309 return new type (t);
312 /* Construct a playback::field instance (wrapping a tree). */
314 playback::field *
315 playback::context::
316 new_field (location *loc,
317 type *type,
318 const char *name)
320 gcc_assert (type);
321 gcc_assert (name);
323 /* compare with c/c-decl.cc:grokfield and grokdeclarator. */
324 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
325 get_identifier (name), type->as_tree ());
327 if (loc)
328 set_tree_location (decl, loc);
330 return new field (decl);
333 /* Construct a playback::bitfield instance (wrapping a tree). */
335 playback::field *
336 playback::context::
337 new_bitfield (location *loc,
338 type *type,
339 int width,
340 const char *name)
342 gcc_assert (type);
343 gcc_assert (name);
344 gcc_assert (width);
346 /* compare with c/c-decl.cc:grokfield, grokdeclarator and
347 check_bitfield_type_and_width. */
349 tree tree_type = type->as_tree ();
350 gcc_assert (INTEGRAL_TYPE_P (tree_type));
351 tree tree_width = build_int_cst (integer_type_node, width);
352 if (compare_tree_int (tree_width, TYPE_PRECISION (tree_type)) > 0)
354 add_error (
355 loc,
356 "width of bit-field %s (width: %i) is wider than its type (width: %i)",
357 name, width, TYPE_PRECISION (tree_type));
358 return NULL;
361 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
362 get_identifier (name), type->as_tree ());
363 DECL_NONADDRESSABLE_P (decl) = true;
364 DECL_INITIAL (decl) = tree_width;
365 SET_DECL_JIT_BIT_FIELD (decl);
367 if (loc)
368 set_tree_location (decl, loc);
370 return new field (decl);
373 /* Construct a playback::compound_type instance (wrapping a tree). */
375 playback::compound_type *
376 playback::context::
377 new_compound_type (location *loc,
378 const char *name,
379 bool is_struct) /* else is union */
381 gcc_assert (name);
383 /* Compare with c/c-decl.cc: start_struct. */
385 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
386 TYPE_NAME (t) = get_identifier (name);
387 TYPE_SIZE (t) = 0;
389 if (loc)
390 set_tree_location (t, loc);
392 return new compound_type (t);
395 void
396 playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
398 /* Compare with c/c-decl.cc: finish_struct. */
399 tree t = as_tree ();
401 tree fieldlist = NULL;
402 for (unsigned i = 0; i < fields->length (); i++)
404 field *f = (*fields)[i];
405 tree x = f->as_tree ();
406 DECL_CONTEXT (x) = t;
407 if (DECL_JIT_BIT_FIELD (x))
409 unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (x));
410 DECL_SIZE (x) = bitsize_int (width);
411 DECL_BIT_FIELD (x) = 1;
413 fieldlist = chainon (x, fieldlist);
415 fieldlist = nreverse (fieldlist);
416 TYPE_FIELDS (t) = fieldlist;
418 layout_type (t);
421 /* Construct a playback::type instance (wrapping a tree) for a function
422 type. */
424 playback::type *
425 playback::context::
426 new_function_type (type *return_type,
427 const auto_vec<type *> *param_types,
428 int is_variadic)
430 int i;
431 type *param_type;
433 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
435 FOR_EACH_VEC_ELT (*param_types, i, param_type)
436 arg_types[i] = param_type->as_tree ();
438 tree fn_type;
439 if (is_variadic)
440 fn_type =
441 build_varargs_function_type_array (return_type->as_tree (),
442 param_types->length (),
443 arg_types);
444 else
445 fn_type = build_function_type_array (return_type->as_tree (),
446 param_types->length (),
447 arg_types);
448 free (arg_types);
450 return new type (fn_type);
453 /* Construct a playback::param instance (wrapping a tree). */
455 playback::param *
456 playback::context::
457 new_param (location *loc,
458 type *type,
459 const char *name)
461 gcc_assert (type);
462 gcc_assert (name);
463 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
464 get_identifier (name), type->as_tree ());
465 if (loc)
466 set_tree_location (inner, loc);
468 return new param (this, inner);
471 /* Construct a playback::function instance. */
473 playback::function *
474 playback::context::
475 new_function (location *loc,
476 enum gcc_jit_function_kind kind,
477 type *return_type,
478 const char *name,
479 const auto_vec<param *> *params,
480 int is_variadic,
481 enum built_in_function builtin_id)
483 int i;
484 param *param;
486 //can return_type be NULL?
487 gcc_assert (name);
489 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
490 FOR_EACH_VEC_ELT (*params, i, param)
491 arg_types[i] = TREE_TYPE (param->as_tree ());
493 tree fn_type;
494 if (is_variadic)
495 fn_type = build_varargs_function_type_array (return_type->as_tree (),
496 params->length (), arg_types);
497 else
498 fn_type = build_function_type_array (return_type->as_tree (),
499 params->length (), arg_types);
500 free (arg_types);
502 /* FIXME: this uses input_location: */
503 tree fndecl = build_fn_decl (name, fn_type);
505 if (loc)
506 set_tree_location (fndecl, loc);
508 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
509 NULL_TREE, return_type->as_tree ());
510 DECL_ARTIFICIAL (resdecl) = 1;
511 DECL_IGNORED_P (resdecl) = 1;
512 DECL_RESULT (fndecl) = resdecl;
513 DECL_CONTEXT (resdecl) = fndecl;
515 if (builtin_id)
517 gcc_assert (loc == NULL);
518 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
520 built_in_class fclass = builtins_manager::get_class (builtin_id);
521 set_decl_built_in_function (fndecl, fclass, builtin_id);
522 set_builtin_decl (builtin_id, fndecl,
523 builtins_manager::implicit_p (builtin_id));
525 builtins_manager *bm = get_builtins_manager ();
526 tree attrs = bm->get_attrs_tree (builtin_id);
527 if (attrs)
528 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
529 else
530 decl_attributes (&fndecl, NULL_TREE, 0);
533 if (kind != GCC_JIT_FUNCTION_IMPORTED)
535 tree param_decl_list = NULL;
536 FOR_EACH_VEC_ELT (*params, i, param)
538 param_decl_list = chainon (param->as_tree (), param_decl_list);
541 /* The param list was created in reverse order; fix it: */
542 param_decl_list = nreverse (param_decl_list);
544 tree t;
545 for (t = param_decl_list; t; t = DECL_CHAIN (t))
547 DECL_CONTEXT (t) = fndecl;
548 DECL_ARG_TYPE (t) = TREE_TYPE (t);
551 /* Set it up on DECL_ARGUMENTS */
552 DECL_ARGUMENTS(fndecl) = param_decl_list;
555 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
557 DECL_DECLARED_INLINE_P (fndecl) = 1;
559 /* Add attribute "always_inline": */
560 DECL_ATTRIBUTES (fndecl) =
561 tree_cons (get_identifier ("always_inline"),
562 NULL,
563 DECL_ATTRIBUTES (fndecl));
566 function *func = new function (this, fndecl, kind);
567 m_functions.safe_push (func);
568 return func;
571 /* In use by new_global and new_global_initialized. */
573 tree
574 playback::context::
575 global_new_decl (location *loc,
576 enum gcc_jit_global_kind kind,
577 type *type,
578 const char *name,
579 enum global_var_flags flags)
581 gcc_assert (type);
582 gcc_assert (name);
584 tree type_tree = type->as_tree ();
586 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
587 get_identifier (name),
588 type_tree);
590 TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
593 int will_be_init = flags & (GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT |
594 GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT);
596 /* A VAR_DECL with DECL_INITIAL will not end up in .common section. */
597 if (!will_be_init)
598 DECL_COMMON (inner) = 1;
600 switch (kind)
602 default:
603 gcc_unreachable ();
605 case GCC_JIT_GLOBAL_EXPORTED:
606 TREE_STATIC (inner) = 1;
607 break;
609 case GCC_JIT_GLOBAL_INTERNAL:
610 TREE_STATIC (inner) = 1;
611 break;
613 case GCC_JIT_GLOBAL_IMPORTED:
614 DECL_EXTERNAL (inner) = 1;
615 break;
618 if (TYPE_READONLY (type_tree))
619 TREE_READONLY (inner) = 1;
621 if (loc)
622 set_tree_location (inner, loc);
624 return inner;
627 /* In use by new_global and new_global_initialized. */
629 playback::lvalue *
630 playback::context::
631 global_finalize_lvalue (tree inner)
633 m_globals.safe_push (inner);
635 return new lvalue (this, inner);
638 /* Construct a playback::lvalue instance (wrapping a tree). */
640 playback::lvalue *
641 playback::context::
642 new_global (location *loc,
643 enum gcc_jit_global_kind kind,
644 type *type,
645 const char *name,
646 enum global_var_flags flags)
648 tree inner =
649 global_new_decl (loc, kind, type, name, flags);
651 return global_finalize_lvalue (inner);
654 void
655 playback::context::
656 global_set_init_rvalue (lvalue* variable,
657 rvalue* init)
659 tree inner = variable->as_tree ();
661 /* We need to fold all expressions as much as possible. The code
662 for a DECL_INITIAL only handles some operations,
663 etc addition, minus, 'address of'. See output_addressed_constants ()
664 in varasm.cc. */
665 tree init_tree = init->as_tree ();
666 tree folded = fold_const_var (init_tree);
668 if (!TREE_CONSTANT (folded))
670 tree name = DECL_NAME (inner);
672 if (name != NULL_TREE)
673 add_error (NULL,
674 "unable to convert initial value for the global variable %s"
675 " to a compile-time constant",
676 IDENTIFIER_POINTER (name));
677 else
678 add_error (NULL,
679 "unable to convert initial value for global variable"
680 " to a compile-time constant");
681 return;
684 DECL_INITIAL (inner) = folded;
687 playback::rvalue *
688 playback::context::
689 new_ctor (location *loc,
690 type *type,
691 const auto_vec<field*> *fields,
692 const auto_vec<rvalue*> *rvalues)
694 tree type_tree = type->as_tree ();
696 /* Handle empty ctors first. I.e. set everything to 0. */
697 if (rvalues->length () == 0)
698 return new rvalue (this, build_constructor (type_tree, NULL));
700 /* Handle arrays (and return). */
701 if (TREE_CODE (type_tree) == ARRAY_TYPE)
703 int n = rvalues->length ();
704 /* The vec for the constructor node. */
705 vec<constructor_elt, va_gc> *v = NULL;
706 vec_alloc (v, n);
708 for (int i = 0; i < n; i++)
710 rvalue *rv = (*rvalues)[i];
711 /* null rvalues indicate that the element should be zeroed. */
712 if (rv)
713 CONSTRUCTOR_APPEND_ELT (v,
714 build_int_cst (size_type_node, i),
715 rv->as_tree ());
716 else
717 CONSTRUCTOR_APPEND_ELT (v,
718 build_int_cst (size_type_node, i),
719 build_zero_cst (TREE_TYPE (type_tree)));
722 tree ctor = build_constructor (type_tree, v);
724 if (loc)
725 set_tree_location (ctor, loc);
727 return new rvalue (this, ctor);
730 /* Handle structs and unions. */
731 int n = fields->length ();
733 /* The vec for the constructor node. */
734 vec<constructor_elt, va_gc> *v = NULL;
735 vec_alloc (v, n);
737 /* Iterate over the fields, building initializations. */
738 for (int i = 0;i < n; i++)
740 tree field = (*fields)[i]->as_tree ();
741 rvalue *rv = (*rvalues)[i];
742 /* If the value is NULL, it means we should zero the field. */
743 if (rv)
744 CONSTRUCTOR_APPEND_ELT (v, field, rv->as_tree ());
745 else
747 tree zero_cst = build_zero_cst (TREE_TYPE (field));
748 CONSTRUCTOR_APPEND_ELT (v, field, zero_cst);
752 tree ctor = build_constructor (type_tree, v);
754 if (loc)
755 set_tree_location (ctor, loc);
757 return new rvalue (this, build_constructor (type_tree, v));
760 /* Fill 'constructor_elements' with the memory content of
761 'initializer'. Each element of the initializer is of the size of
762 type T. In use by new_global_initialized.*/
764 template<typename T>
765 static void
766 load_blob_in_ctor (vec<constructor_elt, va_gc> *&constructor_elements,
767 size_t num_elem,
768 const void *initializer)
770 /* Loosely based on 'output_init_element' c-typeck.cc:9691. */
771 const T *p = (const T *)initializer;
772 tree node = make_unsigned_type (BITS_PER_UNIT * sizeof (T));
773 for (size_t i = 0; i < num_elem; i++)
775 constructor_elt celt =
776 { build_int_cst (long_unsigned_type_node, i),
777 build_int_cst (node, p[i]) };
778 vec_safe_push (constructor_elements, celt);
782 /* Construct an initialized playback::lvalue instance (wrapping a
783 tree). */
785 playback::lvalue *
786 playback::context::
787 new_global_initialized (location *loc,
788 enum gcc_jit_global_kind kind,
789 type *type,
790 size_t element_size,
791 size_t initializer_num_elem,
792 const void *initializer,
793 const char *name,
794 enum global_var_flags flags)
796 tree inner = global_new_decl (loc, kind, type, name, flags);
798 vec<constructor_elt, va_gc> *constructor_elements = NULL;
800 switch (element_size)
802 case 1:
803 load_blob_in_ctor<uint8_t> (constructor_elements, initializer_num_elem,
804 initializer);
805 break;
806 case 2:
807 load_blob_in_ctor<uint16_t> (constructor_elements, initializer_num_elem,
808 initializer);
809 break;
810 case 4:
811 load_blob_in_ctor<uint32_t> (constructor_elements, initializer_num_elem,
812 initializer);
813 break;
814 case 8:
815 load_blob_in_ctor<uint64_t> (constructor_elements, initializer_num_elem,
816 initializer);
817 break;
818 default:
819 /* This function is serving on sizes returned by 'get_size',
820 these are all covered by the previous cases. */
821 gcc_unreachable ();
823 /* Compare with 'pop_init_level' c-typeck.cc:8780. */
824 tree ctor = build_constructor (type->as_tree (), constructor_elements);
825 constructor_elements = NULL;
827 /* Compare with 'store_init_value' c-typeck.cc:7555. */
828 DECL_INITIAL (inner) = ctor;
830 return global_finalize_lvalue (inner);
833 /* Implementation of the various
834 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
835 methods.
836 Each of these constructs a playback::rvalue instance (wrapping a tree).
838 These specializations are required to be in the same namespace
839 as the template, hence we now have to enter the gcc::jit::playback
840 namespace. */
842 namespace playback
845 /* Specialization of making an rvalue from a const, for host <int>. */
847 template <>
848 rvalue *
849 context::
850 new_rvalue_from_const <int> (type *type,
851 int value)
853 // FIXME: type-checking, or coercion?
854 tree inner_type = type->as_tree ();
855 if (INTEGRAL_TYPE_P (inner_type))
857 tree inner = build_int_cst (inner_type, value);
858 return new rvalue (this, inner);
860 else
862 REAL_VALUE_TYPE real_value;
863 real_from_integer (&real_value, VOIDmode, value, SIGNED);
864 tree inner = build_real (inner_type, real_value);
865 return new rvalue (this, inner);
869 /* Specialization of making an rvalue from a const, for host <long>. */
871 template <>
872 rvalue *
873 context::
874 new_rvalue_from_const <long> (type *type,
875 long value)
877 // FIXME: type-checking, or coercion?
878 tree inner_type = type->as_tree ();
879 if (INTEGRAL_TYPE_P (inner_type))
881 tree inner = build_int_cst (inner_type, value);
882 return new rvalue (this, inner);
884 else
886 REAL_VALUE_TYPE real_value;
887 real_from_integer (&real_value, VOIDmode, value, SIGNED);
888 tree inner = build_real (inner_type, real_value);
889 return new rvalue (this, inner);
893 /* Specialization of making an rvalue from a const, for host <double>. */
895 template <>
896 rvalue *
897 context::
898 new_rvalue_from_const <double> (type *type,
899 double value)
901 // FIXME: type-checking, or coercion?
902 tree inner_type = type->as_tree ();
904 /* We have a "double", we want a REAL_VALUE_TYPE.
906 real.cc:real_from_target appears to require the representation to be
907 split into 32-bit values, and then sent as an pair of host long
908 ints. */
909 REAL_VALUE_TYPE real_value;
910 union
912 double as_double;
913 uint32_t as_uint32s[2];
914 } u;
915 u.as_double = value;
916 long int as_long_ints[2];
917 as_long_ints[0] = u.as_uint32s[0];
918 as_long_ints[1] = u.as_uint32s[1];
919 real_from_target (&real_value, as_long_ints, DFmode);
920 tree inner = build_real (inner_type, real_value);
921 return new rvalue (this, inner);
924 /* Specialization of making an rvalue from a const, for host <void *>. */
926 template <>
927 rvalue *
928 context::
929 new_rvalue_from_const <void *> (type *type,
930 void *value)
932 tree inner_type = type->as_tree ();
933 /* FIXME: how to ensure we have a wide enough type? */
934 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
935 return new rvalue (this, inner);
938 /* We're done implementing the specializations of
939 gcc::jit::playback::context::new_rvalue_from_const <T>
940 so we can exit the gcc::jit::playback namespace. */
942 } // namespace playback
944 /* Construct a playback::rvalue instance (wrapping a tree). */
946 playback::rvalue *
947 playback::context::
948 new_string_literal (const char *value)
950 /* Compare with c-family/c-common.cc: fix_string_type. */
951 size_t len = strlen (value);
952 tree i_type = build_index_type (size_int (len));
953 tree a_type = build_array_type (char_type_node, i_type);
954 /* build_string len parameter must include NUL terminator when
955 building C strings. */
956 tree t_str = ::build_string (len + 1, value);
957 TREE_TYPE (t_str) = a_type;
959 /* Convert to (const char*), loosely based on
960 c/c-typeck.cc: array_to_pointer_conversion,
961 by taking address of start of string. */
962 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
964 return new rvalue (this, t_addr);
967 /* Construct a playback::rvalue instance (wrapping a tree) for a
968 vector. */
970 playback::rvalue *
971 playback::context::new_rvalue_from_vector (location *,
972 type *type,
973 const auto_vec<rvalue *> &elements)
975 vec<constructor_elt, va_gc> *v;
976 vec_alloc (v, elements.length ());
977 for (unsigned i = 0; i < elements.length (); ++i)
978 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
979 tree t_ctor = build_constructor (type->as_tree (), v);
980 return new rvalue (this, t_ctor);
983 /* Coerce a tree expression into a boolean tree expression. */
985 tree
986 playback::context::
987 as_truth_value (tree expr, location *loc)
989 /* Compare to c-typeck.cc:c_objc_common_truthvalue_conversion */
990 tree typed_zero = fold_build1 (CONVERT_EXPR,
991 TREE_TYPE (expr),
992 integer_zero_node);
993 if (loc)
994 set_tree_location (typed_zero, loc);
996 expr = fold_build2_loc (UNKNOWN_LOCATION,
997 NE_EXPR, integer_type_node, expr, typed_zero);
998 if (loc)
999 set_tree_location (expr, loc);
1001 return expr;
1004 /* Add a "top-level" basic asm statement (i.e. one outside of any functions)
1005 containing ASM_STMTS.
1007 Compare with c_parser_asm_definition. */
1009 void
1010 playback::context::add_top_level_asm (const char *asm_stmts)
1012 tree asm_str = build_string (asm_stmts);
1013 symtab->finalize_toplevel_asm (asm_str);
1016 /* Construct a playback::rvalue instance (wrapping a tree) for a
1017 unary op. */
1019 playback::rvalue *
1020 playback::context::
1021 new_unary_op (location *loc,
1022 enum gcc_jit_unary_op op,
1023 type *result_type,
1024 rvalue *a)
1026 // FIXME: type-checking, or coercion?
1027 enum tree_code inner_op;
1029 gcc_assert (result_type);
1030 gcc_assert (a);
1032 tree node = a->as_tree ();
1033 node = fold_const_var (node);
1035 tree inner_result = NULL;
1037 switch (op)
1039 default:
1040 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
1041 return NULL;
1043 case GCC_JIT_UNARY_OP_MINUS:
1044 inner_op = NEGATE_EXPR;
1045 break;
1047 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
1048 inner_op = BIT_NOT_EXPR;
1049 break;
1051 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
1052 node = as_truth_value (node, loc);
1053 inner_result = invert_truthvalue (node);
1054 if (loc)
1055 set_tree_location (inner_result, loc);
1056 return new rvalue (this, inner_result);
1058 case GCC_JIT_UNARY_OP_ABS:
1059 inner_op = ABS_EXPR;
1060 break;
1063 inner_result = build1 (inner_op,
1064 result_type->as_tree (),
1065 node);
1067 /* Try to fold. */
1068 inner_result = fold (inner_result);
1070 if (loc)
1071 set_tree_location (inner_result, loc);
1073 return new rvalue (this, inner_result);
1076 /* Construct a playback::rvalue instance (wrapping a tree) for a
1077 binary op. */
1079 playback::rvalue *
1080 playback::context::
1081 new_binary_op (location *loc,
1082 enum gcc_jit_binary_op op,
1083 type *result_type,
1084 rvalue *a, rvalue *b)
1086 // FIXME: type-checking, or coercion?
1087 enum tree_code inner_op;
1089 gcc_assert (result_type);
1090 gcc_assert (a);
1091 gcc_assert (b);
1093 tree node_a = a->as_tree ();
1094 node_a = fold_const_var (node_a);
1096 tree node_b = b->as_tree ();
1097 node_b = fold_const_var (node_b);
1099 switch (op)
1101 default:
1102 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
1103 return NULL;
1105 case GCC_JIT_BINARY_OP_PLUS:
1106 inner_op = PLUS_EXPR;
1107 break;
1109 case GCC_JIT_BINARY_OP_MINUS:
1110 inner_op = MINUS_EXPR;
1111 break;
1113 case GCC_JIT_BINARY_OP_MULT:
1114 inner_op = MULT_EXPR;
1115 break;
1117 case GCC_JIT_BINARY_OP_DIVIDE:
1118 if (FLOAT_TYPE_P (result_type->as_tree ()))
1119 /* Floating-point division: */
1120 inner_op = RDIV_EXPR;
1121 else
1122 /* Truncating to zero: */
1123 inner_op = TRUNC_DIV_EXPR;
1124 break;
1126 case GCC_JIT_BINARY_OP_MODULO:
1127 inner_op = TRUNC_MOD_EXPR;
1128 break;
1130 case GCC_JIT_BINARY_OP_BITWISE_AND:
1131 inner_op = BIT_AND_EXPR;
1132 break;
1134 case GCC_JIT_BINARY_OP_BITWISE_XOR:
1135 inner_op = BIT_XOR_EXPR;
1136 break;
1138 case GCC_JIT_BINARY_OP_BITWISE_OR:
1139 inner_op = BIT_IOR_EXPR;
1140 break;
1142 case GCC_JIT_BINARY_OP_LOGICAL_AND:
1143 node_a = as_truth_value (node_a, loc);
1144 node_b = as_truth_value (node_b, loc);
1145 inner_op = TRUTH_ANDIF_EXPR;
1146 break;
1148 case GCC_JIT_BINARY_OP_LOGICAL_OR:
1149 node_a = as_truth_value (node_a, loc);
1150 node_b = as_truth_value (node_b, loc);
1151 inner_op = TRUTH_ORIF_EXPR;
1152 break;
1154 case GCC_JIT_BINARY_OP_LSHIFT:
1155 inner_op = LSHIFT_EXPR;
1156 break;
1158 case GCC_JIT_BINARY_OP_RSHIFT:
1159 inner_op = RSHIFT_EXPR;
1160 break;
1163 tree inner_expr = build2 (inner_op,
1164 result_type->as_tree (),
1165 node_a,
1166 node_b);
1168 /* Try to fold the expression. */
1169 inner_expr = fold (inner_expr);
1171 if (loc)
1172 set_tree_location (inner_expr, loc);
1174 return new rvalue (this, inner_expr);
1177 /* Construct a playback::rvalue instance (wrapping a tree) for a
1178 comparison. */
1180 playback::rvalue *
1181 playback::context::
1182 new_comparison (location *loc,
1183 enum gcc_jit_comparison op,
1184 rvalue *a, rvalue *b)
1186 // FIXME: type-checking, or coercion?
1187 enum tree_code inner_op;
1189 gcc_assert (a);
1190 gcc_assert (b);
1192 switch (op)
1194 default:
1195 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
1196 return NULL;
1198 case GCC_JIT_COMPARISON_EQ:
1199 inner_op = EQ_EXPR;
1200 break;
1201 case GCC_JIT_COMPARISON_NE:
1202 inner_op = NE_EXPR;
1203 break;
1204 case GCC_JIT_COMPARISON_LT:
1205 inner_op = LT_EXPR;
1206 break;
1207 case GCC_JIT_COMPARISON_LE:
1208 inner_op = LE_EXPR;
1209 break;
1210 case GCC_JIT_COMPARISON_GT:
1211 inner_op = GT_EXPR;
1212 break;
1213 case GCC_JIT_COMPARISON_GE:
1214 inner_op = GE_EXPR;
1215 break;
1218 tree node_a = a->as_tree ();
1219 node_a = fold_const_var (node_a);
1220 tree node_b = b->as_tree ();
1221 node_b = fold_const_var (node_b);
1223 tree inner_expr = build2 (inner_op,
1224 boolean_type_node,
1225 node_a,
1226 node_b);
1228 /* Try to fold. */
1229 inner_expr = fold (inner_expr);
1231 if (loc)
1232 set_tree_location (inner_expr, loc);
1233 return new rvalue (this, inner_expr);
1236 /* Construct a playback::rvalue instance (wrapping a tree) for a
1237 function call. */
1239 playback::rvalue *
1240 playback::context::
1241 build_call (location *loc,
1242 tree fn_ptr,
1243 const auto_vec<rvalue *> *args,
1244 bool require_tail_call)
1246 vec<tree, va_gc> *tree_args;
1247 vec_alloc (tree_args, args->length ());
1248 for (unsigned i = 0; i < args->length (); i++)
1249 tree_args->quick_push ((*args)[i]->as_tree ());
1251 if (loc)
1252 set_tree_location (fn_ptr, loc);
1254 tree fn = TREE_TYPE (fn_ptr);
1255 tree fn_type = TREE_TYPE (fn);
1256 tree return_type = TREE_TYPE (fn_type);
1258 tree call = build_call_vec (return_type,
1259 fn_ptr, tree_args);
1261 if (require_tail_call)
1262 CALL_EXPR_MUST_TAIL_CALL (call) = 1;
1264 return new rvalue (this, call);
1266 /* see c-typeck.cc: build_function_call
1267 which calls build_function_call_vec
1269 which does lots of checking, then:
1270 result = build_call_array_loc (loc, TREE_TYPE (fntype),
1271 function, nargs, argarray);
1272 which is in tree.cc
1273 (see also build_call_vec)
1277 /* Construct a playback::rvalue instance (wrapping a tree) for a
1278 call to a specific function. */
1280 playback::rvalue *
1281 playback::context::
1282 new_call (location *loc,
1283 function *func,
1284 const auto_vec<rvalue *> *args,
1285 bool require_tail_call)
1287 tree fndecl;
1289 gcc_assert (func);
1291 fndecl = func->as_fndecl ();
1293 tree fntype = TREE_TYPE (fndecl);
1295 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
1297 return build_call (loc, fn, args, require_tail_call);
1300 /* Construct a playback::rvalue instance (wrapping a tree) for a
1301 call through a function pointer. */
1303 playback::rvalue *
1304 playback::context::
1305 new_call_through_ptr (location *loc,
1306 rvalue *fn_ptr,
1307 const auto_vec<rvalue *> *args,
1308 bool require_tail_call)
1310 gcc_assert (fn_ptr);
1311 tree t_fn_ptr = fn_ptr->as_tree ();
1313 return build_call (loc, t_fn_ptr, args, require_tail_call);
1316 /* Construct a tree for a cast. */
1318 tree
1319 playback::context::build_cast (playback::location *loc,
1320 playback::rvalue *expr,
1321 playback::type *type_)
1323 /* For comparison, see:
1324 - c/c-typeck.cc:build_c_cast
1325 - c/c-convert.cc: convert
1326 - convert.h
1328 Only some kinds of cast are currently supported here. */
1329 tree t_expr = expr->as_tree ();
1330 t_expr = fold_const_var (t_expr);
1332 tree t_dst_type = type_->as_tree ();
1333 tree t_ret = NULL;
1334 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
1335 if (t_ret)
1336 return t_ret;
1337 enum tree_code dst_code = TREE_CODE (t_dst_type);
1338 switch (dst_code)
1340 case INTEGER_TYPE:
1341 case ENUMERAL_TYPE:
1342 t_ret = convert_to_integer (t_dst_type, t_expr);
1343 goto maybe_fold;
1345 case BOOLEAN_TYPE:
1346 /* Compare with c_objc_common_truthvalue_conversion and
1347 c_common_truthvalue_conversion. */
1348 /* For now, convert to: (t_expr != 0) */
1349 t_ret = build2 (NE_EXPR, t_dst_type,
1350 t_expr,
1351 build_int_cst (TREE_TYPE (t_expr), 0));
1352 goto maybe_fold;
1354 case REAL_TYPE:
1355 t_ret = convert_to_real (t_dst_type, t_expr);
1356 goto maybe_fold;
1358 case POINTER_TYPE:
1359 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
1360 goto maybe_fold;
1362 default:
1363 add_error (loc, "couldn't handle cast during playback");
1364 fprintf (stderr, "input expression:\n");
1365 debug_tree (t_expr);
1366 fprintf (stderr, "requested type:\n");
1367 debug_tree (t_dst_type);
1368 return error_mark_node;
1370 maybe_fold:
1371 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
1372 t_ret = fold (t_ret);
1373 return t_ret;
1377 /* Construct a playback::rvalue instance (wrapping a tree) for a
1378 cast. */
1380 playback::rvalue *
1381 playback::context::
1382 new_cast (playback::location *loc,
1383 playback::rvalue *expr,
1384 playback::type *type_)
1387 tree t_cast = build_cast (loc, expr, type_);
1388 if (loc)
1389 set_tree_location (t_cast, loc);
1390 return new rvalue (this, t_cast);
1393 /* Construct a playback::lvalue instance (wrapping a tree) for an
1394 array access. */
1396 playback::lvalue *
1397 playback::context::
1398 new_array_access (location *loc,
1399 rvalue *ptr,
1400 rvalue *index)
1402 gcc_assert (ptr);
1403 gcc_assert (index);
1405 /* For comparison, see:
1406 c/c-typeck.cc: build_array_ref
1407 c-family/c-common.cc: pointer_int_sum
1409 tree t_ptr = ptr->as_tree ();
1410 t_ptr = fold_const_var (t_ptr);
1411 tree t_index = index->as_tree ();
1412 t_index = fold_const_var (t_index);
1414 tree t_type_ptr = TREE_TYPE (t_ptr);
1415 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1417 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1419 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1420 NULL_TREE, NULL_TREE);
1421 t_result = fold (t_result);
1422 if (loc)
1423 set_tree_location (t_result, loc);
1424 return new lvalue (this, t_result);
1426 else
1428 /* Convert index to an offset in bytes. */
1429 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1430 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1431 tree t_offset = fold_build2_loc (UNKNOWN_LOCATION,
1432 MULT_EXPR, sizetype, t_index, t_sizeof);
1434 /* Locate (ptr + offset). */
1435 tree t_address = fold_build2_loc (UNKNOWN_LOCATION,
1436 POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1438 tree t_indirection = fold_build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1439 if (loc)
1441 set_tree_location (t_sizeof, loc);
1442 set_tree_location (t_offset, loc);
1443 set_tree_location (t_address, loc);
1444 set_tree_location (t_indirection, loc);
1447 return new lvalue (this, t_indirection);
1451 /* Construct a tree for a field access. */
1453 tree
1454 playback::context::
1455 new_field_access (location *loc,
1456 tree datum,
1457 field *field)
1459 gcc_assert (datum);
1460 gcc_assert (field);
1462 /* Compare with c/c-typeck.cc:lookup_field, build_indirect_ref, and
1463 build_component_ref. */
1464 tree type = TREE_TYPE (datum);
1465 gcc_assert (type);
1466 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1468 tree t_field = field->as_tree ();
1469 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1470 t_field, NULL_TREE);
1471 if (loc)
1472 set_tree_location (ref, loc);
1473 return ref;
1476 /* Construct a tree for a dereference. */
1478 tree
1479 playback::context::
1480 new_dereference (tree ptr,
1481 location *loc)
1483 gcc_assert (ptr);
1485 tree type = TREE_TYPE (TREE_TYPE(ptr));
1486 tree datum = fold_build1 (INDIRECT_REF, type, ptr);
1487 if (loc)
1488 set_tree_location (datum, loc);
1489 return datum;
1492 /* Construct a playback::type instance (wrapping a tree)
1493 with the given alignment. */
1495 playback::type *
1496 playback::type::
1497 get_aligned (size_t alignment_in_bytes) const
1499 tree t_new_type = build_variant_type_copy (m_inner);
1501 SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT);
1502 TYPE_USER_ALIGN (t_new_type) = 1;
1504 return new type (t_new_type);
1507 /* Construct a playback::type instance (wrapping a tree)
1508 for the given vector type. */
1510 playback::type *
1511 playback::type::
1512 get_vector (size_t num_units) const
1514 tree t_new_type = build_vector_type (m_inner, num_units);
1515 return new type (t_new_type);
1518 /* Construct a playback::lvalue instance (wrapping a tree) for a
1519 field access. */
1521 playback::lvalue *
1522 playback::lvalue::
1523 access_field (location *loc,
1524 field *field)
1526 tree datum = as_tree ();
1527 tree ref = get_context ()->new_field_access (loc, datum, field);
1528 if (!ref)
1529 return NULL;
1530 return new lvalue (get_context (), ref);
1533 /* Construct a playback::rvalue instance (wrapping a tree) for a
1534 field access. */
1536 playback::rvalue *
1537 playback::rvalue::
1538 access_field (location *loc,
1539 field *field)
1541 tree datum = as_tree ();
1542 tree ref = get_context ()->new_field_access (loc, datum, field);
1543 if (!ref)
1544 return NULL;
1545 return new rvalue (get_context (), ref);
1548 /* Construct a playback::lvalue instance (wrapping a tree) for a
1549 dereferenced field access. */
1551 playback::lvalue *
1552 playback::rvalue::
1553 dereference_field (location *loc,
1554 field *field)
1556 tree ptr = as_tree ();
1557 tree datum = get_context ()->new_dereference (ptr, loc);
1558 if (!datum)
1559 return NULL;
1560 tree ref = get_context ()->new_field_access (loc, datum, field);
1561 if (!ref)
1562 return NULL;
1563 return new lvalue (get_context (), ref);
1566 /* Construct a playback::lvalue instance (wrapping a tree) for a
1567 dereference. */
1569 playback::lvalue *
1570 playback::rvalue::
1571 dereference (location *loc)
1573 tree ptr = as_tree ();
1574 tree datum = get_context ()->new_dereference (ptr, loc);
1575 return new lvalue (get_context (), datum);
1578 /* Mark the lvalue saying that we need to be able to take the
1579 address of it; it should not be allocated in a register.
1580 Compare with e.g. c/c-typeck.cc: c_mark_addressable really_atomic_lvalue.
1581 Returns false if a failure occurred (an error will already have been
1582 added to the active context for this case). */
1584 bool
1585 playback::lvalue::
1586 mark_addressable (location *loc)
1588 tree x = as_tree ();;
1590 while (1)
1591 switch (TREE_CODE (x))
1593 case COMPONENT_REF:
1594 if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x, 1)))
1596 gcc_assert (gcc::jit::active_playback_ctxt);
1597 gcc::jit::
1598 active_playback_ctxt->add_error (loc,
1599 "cannot take address of "
1600 "bit-field");
1601 return false;
1603 /* fallthrough */
1604 case ADDR_EXPR:
1605 case ARRAY_REF:
1606 case REALPART_EXPR:
1607 case IMAGPART_EXPR:
1608 x = TREE_OPERAND (x, 0);
1609 break;
1611 case COMPOUND_LITERAL_EXPR:
1612 case CONSTRUCTOR:
1613 TREE_ADDRESSABLE (x) = 1;
1614 return true;
1616 case VAR_DECL:
1617 case CONST_DECL:
1618 case PARM_DECL:
1619 case RESULT_DECL:
1620 /* (we don't have a concept of a "register" declaration) */
1621 /* fallthrough */
1622 case FUNCTION_DECL:
1623 TREE_ADDRESSABLE (x) = 1;
1624 /* fallthrough */
1625 default:
1626 return true;
1630 /* Construct a playback::rvalue instance (wrapping a tree) for an
1631 address-lookup. */
1633 playback::rvalue *
1634 playback::lvalue::
1635 get_address (location *loc)
1637 tree t_lvalue = as_tree ();
1638 tree t_thistype = TREE_TYPE (t_lvalue);
1639 tree t_ptrtype = build_pointer_type (t_thistype);
1640 tree ptr = fold_build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1641 if (loc)
1642 get_context ()->set_tree_location (ptr, loc);
1643 if (mark_addressable (loc))
1644 return new rvalue (get_context (), ptr);
1645 else
1646 return NULL;
1649 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1650 Provide this finalization hook for calling then they are collected,
1651 which calls the finalizer vfunc. This allows them to call "release"
1652 on any vec<> within them. */
1654 static void
1655 wrapper_finalizer (void *ptr)
1657 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1658 wrapper->finalizer ();
1661 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1662 allocate them using ggc_internal_cleared_alloc. */
1664 void *
1665 playback::wrapper::
1666 operator new (size_t sz)
1668 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1672 /* Constructor for gcc:jit::playback::function. */
1674 playback::function::
1675 function (context *ctxt,
1676 tree fndecl,
1677 enum gcc_jit_function_kind kind)
1678 : m_ctxt(ctxt),
1679 m_inner_fndecl (fndecl),
1680 m_inner_bind_expr (NULL),
1681 m_kind (kind),
1682 m_blocks ()
1684 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1686 /* Create a BIND_EXPR, and within it, a statement list. */
1687 m_stmt_list = alloc_stmt_list ();
1688 m_stmt_iter = tsi_start (m_stmt_list);
1689 m_inner_block = make_node (BLOCK);
1690 m_inner_bind_expr =
1691 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1693 else
1695 m_inner_block = NULL;
1696 m_stmt_list = NULL;
1700 /* Hand-written GC-marking hook for playback functions. */
1702 void
1703 playback::function::
1704 gt_ggc_mx ()
1706 gt_ggc_m_9tree_node (m_inner_fndecl);
1707 gt_ggc_m_9tree_node (m_inner_bind_expr);
1708 gt_ggc_m_9tree_node (m_stmt_list);
1709 gt_ggc_m_9tree_node (m_inner_block);
1712 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1713 GC-ed. */
1715 void
1716 playback::function::finalizer ()
1718 m_blocks.release ();
1721 /* Get the return type of a playback function, in tree form. */
1723 tree
1724 playback::function::
1725 get_return_type_as_tree () const
1727 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1730 /* Construct a new local within this playback::function. */
1732 playback::lvalue *
1733 playback::function::
1734 new_local (location *loc,
1735 type *type,
1736 const char *name)
1738 gcc_assert (type);
1739 gcc_assert (name);
1740 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1741 get_identifier (name),
1742 type->as_tree ());
1743 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1745 /* Prepend to BIND_EXPR_VARS: */
1746 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1747 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1749 if (loc)
1750 set_tree_location (inner, loc);
1751 return new lvalue (m_ctxt, inner);
1754 /* Construct a new block within this playback::function. */
1756 playback::block *
1757 playback::function::
1758 new_block (const char *name)
1760 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1762 block *result = new playback::block (this, name);
1763 m_blocks.safe_push (result);
1764 return result;
1767 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1768 this playback::function. */
1770 playback::rvalue *
1771 playback::function::get_address (location *loc)
1773 tree t_fndecl = as_fndecl ();
1774 tree t_fntype = TREE_TYPE (t_fndecl);
1775 tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
1776 if (loc)
1777 m_ctxt->set_tree_location (t_fnptr, loc);
1778 return new rvalue (m_ctxt, t_fnptr);
1781 /* Build a statement list for the function as a whole out of the
1782 lists of statements for the individual blocks, building labels
1783 for each block. */
1785 void
1786 playback::function::
1787 build_stmt_list ()
1789 int i;
1790 block *b;
1792 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1794 FOR_EACH_VEC_ELT (m_blocks, i, b)
1796 int j;
1797 tree stmt;
1799 b->m_label_expr = build1 (LABEL_EXPR,
1800 void_type_node,
1801 b->as_label_decl ());
1802 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1804 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1805 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1809 /* Finish compiling the given function, potentially running the
1810 garbage-collector.
1811 The function will have a statement list by now.
1812 Amongst other things, this gimplifies the statement list,
1813 and calls cgraph_node::finalize_function on the function. */
1815 void
1816 playback::function::
1817 postprocess ()
1819 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1821 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1822 debug_tree (m_stmt_list);
1824 /* Do we need this to force cgraphunit.cc to output the function? */
1825 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1827 DECL_EXTERNAL (m_inner_fndecl) = 0;
1828 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1831 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1832 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1834 DECL_EXTERNAL (m_inner_fndecl) = 0;
1835 TREE_PUBLIC (m_inner_fndecl) = 0;
1838 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1840 /* Seem to need this in gimple-low.cc: */
1841 gcc_assert (m_inner_block);
1842 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1844 /* how to add to function? the following appears to be how to
1845 set the body of a m_inner_fndecl: */
1846 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1848 /* Ensure that locals appear in the debuginfo. */
1849 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1851 //debug_tree (m_inner_fndecl);
1853 /* Convert to gimple: */
1854 //printf("about to gimplify_function_tree\n");
1855 gimplify_function_tree (m_inner_fndecl);
1856 //printf("finished gimplify_function_tree\n");
1858 current_function_decl = m_inner_fndecl;
1859 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1860 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1861 //debug_tree (m_inner_fndecl);
1863 //printf("about to add to cgraph\n");
1864 /* Add to cgraph: */
1865 cgraph_node::finalize_function (m_inner_fndecl, false);
1866 /* This can trigger a collection, so we need to have all of
1867 the funcs as roots. */
1869 current_function_decl = NULL;
1873 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1874 GC-ed. */
1876 void
1877 playback::block::finalizer ()
1879 m_stmts.release ();
1882 /* Add an eval of the rvalue to the function's statement list. */
1884 void
1885 playback::block::
1886 add_eval (location *loc,
1887 rvalue *rvalue)
1889 gcc_assert (rvalue);
1891 if (loc)
1892 set_tree_location (rvalue->as_tree (), loc);
1894 add_stmt (rvalue->as_tree ());
1897 /* Add an assignment to the function's statement list. */
1899 void
1900 playback::block::
1901 add_assignment (location *loc,
1902 lvalue *lvalue,
1903 rvalue *rvalue)
1905 gcc_assert (lvalue);
1906 gcc_assert (rvalue);
1908 tree t_lvalue = lvalue->as_tree ();
1909 tree t_rvalue = rvalue->as_tree ();
1910 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1912 t_rvalue = build1 (CONVERT_EXPR,
1913 TREE_TYPE (t_lvalue),
1914 t_rvalue);
1915 if (loc)
1916 set_tree_location (t_rvalue, loc);
1919 tree stmt =
1920 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1921 t_lvalue, t_rvalue);
1922 if (loc)
1923 set_tree_location (stmt, loc);
1924 add_stmt (stmt);
1927 /* Add a comment to the function's statement list.
1928 For now this is done by adding a dummy label. */
1930 void
1931 playback::block::
1932 add_comment (location *loc,
1933 const char *text)
1935 /* Wrap the text in C-style comment delimiters. */
1936 size_t sz =
1937 (3 /* opening delim */
1938 + strlen (text)
1939 + 3 /* closing delim */
1940 + 1 /* terminator */);
1941 char *wrapped = (char *)ggc_internal_alloc (sz);
1942 snprintf (wrapped, sz, "/* %s */", text);
1944 /* For now we simply implement this by adding a dummy label with a name
1945 containing the given text. */
1946 tree identifier = get_identifier (wrapped);
1947 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1948 identifier, void_type_node);
1949 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1951 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1952 if (loc)
1953 set_tree_location (label_expr, loc);
1954 add_stmt (label_expr);
1957 /* Add a conditional jump statement to the function's statement list. */
1959 void
1960 playback::block::
1961 add_conditional (location *loc,
1962 rvalue *boolval,
1963 block *on_true,
1964 block *on_false)
1966 gcc_assert (boolval);
1967 gcc_assert (on_true);
1968 gcc_assert (on_false);
1970 /* COND_EXPR wants statement lists for the true/false operands, but we
1971 want labels.
1972 Shim it by creating jumps to the labels */
1973 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1974 on_true->as_label_decl ());
1975 if (loc)
1976 set_tree_location (true_jump, loc);
1978 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1979 on_false->as_label_decl ());
1980 if (loc)
1981 set_tree_location (false_jump, loc);
1983 tree stmt =
1984 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1985 true_jump, false_jump);
1986 if (loc)
1987 set_tree_location (stmt, loc);
1988 add_stmt (stmt);
1991 /* Add an unconditional jump statement to the function's statement list. */
1993 void
1994 playback::block::
1995 add_jump (location *loc,
1996 block *target)
1998 gcc_assert (target);
2000 // see c_finish_loop
2001 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
2002 //add_stmt (top);
2004 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
2005 TREE_USED (target->as_label_decl ()) = 1;
2006 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
2007 if (loc)
2008 set_tree_location (stmt, loc);
2009 add_stmt (stmt);
2012 from c-typeck.cc:
2013 tree
2014 c_finish_goto_label (location_t loc, tree label)
2016 tree decl = lookup_label_for_goto (loc, label);
2017 if (!decl)
2018 return NULL_TREE;
2019 TREE_USED (decl) = 1;
2021 tree t = build1 (GOTO_EXPR, void_type_node, decl);
2022 SET_EXPR_LOCATION (t, loc);
2023 return add_stmt (t);
2030 /* Add a return statement to the function's statement list. */
2032 void
2033 playback::block::
2034 add_return (location *loc,
2035 rvalue *rvalue)
2037 tree modify_retval = NULL;
2038 tree return_type = m_func->get_return_type_as_tree ();
2039 if (rvalue)
2041 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
2042 tree t_rvalue = rvalue->as_tree ();
2043 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
2044 t_rvalue = build1 (CONVERT_EXPR,
2045 TREE_TYPE (t_lvalue),
2046 t_rvalue);
2047 modify_retval = build2 (MODIFY_EXPR, return_type,
2048 t_lvalue, t_rvalue);
2049 if (loc)
2050 set_tree_location (modify_retval, loc);
2052 tree return_stmt = build1 (RETURN_EXPR, return_type,
2053 modify_retval);
2054 if (loc)
2055 set_tree_location (return_stmt, loc);
2057 add_stmt (return_stmt);
2060 /* Helper function for playback::block::add_switch.
2061 Construct a case label for the given range, followed by a goto stmt
2062 to the given block, appending them to stmt list *ptr_t_switch_body. */
2064 static void
2065 add_case (tree *ptr_t_switch_body,
2066 tree t_low_value,
2067 tree t_high_value,
2068 playback::block *dest_block)
2070 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
2071 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
2073 tree t_case_label =
2074 build_case_label (t_low_value, t_high_value, t_label);
2075 append_to_statement_list (t_case_label, ptr_t_switch_body);
2077 tree t_goto_stmt =
2078 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
2079 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
2082 /* Add a switch statement to the function's statement list.
2084 We create a switch body, and populate it with case labels, each
2085 followed by a goto to the desired block. */
2087 void
2088 playback::block::
2089 add_switch (location *loc,
2090 rvalue *expr,
2091 block *default_block,
2092 const auto_vec <case_> *cases)
2094 /* Compare with:
2095 - c/c-typeck.cc: c_start_case
2096 - c-family/c-common.cc:c_add_case_label
2097 - java/expr.cc:expand_java_switch and expand_java_add_case
2098 We've already rejected overlaps and duplicates in
2099 libgccjit.cc:case_range_validator::validate. */
2101 tree t_expr = expr->as_tree ();
2102 tree t_type = TREE_TYPE (t_expr);
2104 tree t_switch_body = alloc_stmt_list ();
2106 int i;
2107 case_ *c;
2108 FOR_EACH_VEC_ELT (*cases, i, c)
2110 tree t_low_value = c->m_min_value->as_tree ();
2111 tree t_high_value = c->m_max_value->as_tree ();
2112 add_case (&t_switch_body, t_low_value, t_high_value, c->m_dest_block);
2114 /* Default label. */
2115 add_case (&t_switch_body, NULL_TREE, NULL_TREE, default_block);
2117 tree switch_stmt = build2 (SWITCH_EXPR, t_type, t_expr, t_switch_body);
2118 if (loc)
2119 set_tree_location (switch_stmt, loc);
2120 add_stmt (switch_stmt);
2123 /* Convert OPERANDS to a tree-based chain suitable for creating an
2124 extended asm stmt.
2125 Compare with c_parser_asm_operands. */
2127 static tree
2128 build_operand_chain (const auto_vec <playback::asm_operand> *operands)
2130 tree result = NULL_TREE;
2131 unsigned i;
2132 playback::asm_operand *asm_op;
2133 FOR_EACH_VEC_ELT (*operands, i, asm_op)
2135 tree name = build_string (asm_op->m_asm_symbolic_name);
2136 tree str = build_string (asm_op->m_constraint);
2137 tree value = asm_op->m_expr;
2138 result = chainon (result,
2139 build_tree_list (build_tree_list (name, str),
2140 value));
2142 return result;
2145 /* Convert CLOBBERS to a tree-based list suitable for creating an
2146 extended asm stmt.
2147 Compare with c_parser_asm_clobbers. */
2149 static tree
2150 build_clobbers (const auto_vec <const char *> *clobbers)
2152 tree list = NULL_TREE;
2153 unsigned i;
2154 const char *clobber;
2155 FOR_EACH_VEC_ELT (*clobbers, i, clobber)
2157 tree str = build_string (clobber);
2158 list = tree_cons (NULL_TREE, str, list);
2160 return list;
2163 /* Convert BLOCKS to a tree-based list suitable for creating an
2164 extended asm stmt.
2165 Compare with c_parser_asm_goto_operands. */
2167 static tree
2168 build_goto_operands (const auto_vec <playback::block *> *blocks)
2170 tree list = NULL_TREE;
2171 unsigned i;
2172 playback::block *b;
2173 FOR_EACH_VEC_ELT (*blocks, i, b)
2175 tree label = b->as_label_decl ();
2176 tree name = build_string (IDENTIFIER_POINTER (DECL_NAME (label)));
2177 TREE_USED (label) = 1;
2178 list = tree_cons (name, label, list);
2180 return nreverse (list);
2183 /* Add an extended asm statement to this block.
2185 Compare with c_parser_asm_statement (in c/c-parser.cc)
2186 and build_asm_expr (in c/c-typeck.cc). */
2188 void
2189 playback::block::add_extended_asm (location *loc,
2190 const char *asm_template,
2191 bool is_volatile,
2192 bool is_inline,
2193 const auto_vec <asm_operand> *outputs,
2194 const auto_vec <asm_operand> *inputs,
2195 const auto_vec <const char *> *clobbers,
2196 const auto_vec <block *> *goto_blocks)
2198 tree t_string = build_string (asm_template);
2199 tree t_outputs = build_operand_chain (outputs);
2200 tree t_inputs = build_operand_chain (inputs);
2201 tree t_clobbers = build_clobbers (clobbers);
2202 tree t_labels = build_goto_operands (goto_blocks);
2203 t_string
2204 = resolve_asm_operand_names (t_string, t_outputs, t_inputs, t_labels);
2205 tree asm_stmt
2206 = build5 (ASM_EXPR, void_type_node,
2207 t_string, t_outputs, t_inputs, t_clobbers, t_labels);
2209 /* asm statements without outputs, including simple ones, are treated
2210 as volatile. */
2211 ASM_VOLATILE_P (asm_stmt) = (outputs->length () == 0);
2212 ASM_INPUT_P (asm_stmt) = 0; /* extended asm stmts are not "simple". */
2213 ASM_INLINE_P (asm_stmt) = is_inline;
2214 if (is_volatile)
2215 ASM_VOLATILE_P (asm_stmt) = 1;
2216 if (loc)
2217 set_tree_location (asm_stmt, loc);
2218 add_stmt (asm_stmt);
2221 /* Constructor for gcc::jit::playback::block. */
2223 playback::block::
2224 block (function *func,
2225 const char *name)
2226 : m_func (func),
2227 m_stmts ()
2229 tree identifier;
2231 gcc_assert (func);
2232 // name can be NULL
2233 if (name)
2234 identifier = get_identifier (name);
2235 else
2236 identifier = NULL;
2237 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
2238 identifier, void_type_node);
2239 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
2240 m_label_expr = NULL;
2243 /* Compile a playback::context:
2245 - Use the context's options to cconstruct command-line options, and
2246 call into the rest of GCC (toplev::main).
2247 - Assuming it succeeds, we have a .s file.
2248 - We then run the "postprocess" vfunc:
2250 (A) In-memory compile ("gcc_jit_context_compile")
2252 For an in-memory compile we have the playback::compile_to_memory
2253 subclass; "postprocess" will convert the .s file to a .so DSO,
2254 and load it in memory (via dlopen), wrapping the result up as
2255 a jit::result and returning it.
2257 (B) Compile to file ("gcc_jit_context_compile_to_file")
2259 When compiling to a file, we have the playback::compile_to_file
2260 subclass; "postprocess" will either copy the .s file to the
2261 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
2262 the driver to convert it as necessary, copying the result. */
2264 void
2265 playback::context::
2266 compile ()
2268 JIT_LOG_SCOPE (get_logger ());
2270 const char *ctxt_progname;
2272 int keep_intermediates =
2273 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
2275 m_tempdir = new tempdir (get_logger (), keep_intermediates);
2276 if (!m_tempdir->create ())
2277 return;
2279 /* Call into the rest of gcc.
2280 For now, we have to assemble command-line options to pass into
2281 toplev::main, so that they can be parsed. */
2283 /* Pass in user-provided program name as argv0, if any, so that it
2284 makes it into GCC's "progname" global, used in various diagnostics. */
2285 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
2287 if (!ctxt_progname)
2288 ctxt_progname = "libgccjit.so";
2290 auto_vec <recording::requested_dump> requested_dumps;
2291 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
2293 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
2294 acquire_mutex ();
2296 auto_string_vec fake_args;
2297 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
2298 if (errors_occurred ())
2300 release_mutex ();
2301 return;
2304 /* This runs the compiler. */
2305 toplev toplev (get_timer (), /* external_timer */
2306 false); /* init_signals */
2307 enter_scope ("toplev::main");
2308 if (get_logger ())
2309 for (unsigned i = 0; i < fake_args.length (); i++)
2310 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
2311 toplev.main (fake_args.length (),
2312 const_cast <char **> (fake_args.address ()));
2313 exit_scope ("toplev::main");
2315 /* Extracting dumps makes use of the gcc::dump_manager, hence we
2316 need to do it between toplev::main (which creates the dump manager)
2317 and toplev::finalize (which deletes it). */
2318 extract_any_requested_dumps (&requested_dumps);
2320 /* Clean up the compiler. */
2321 enter_scope ("toplev::finalize");
2322 toplev.finalize ();
2323 exit_scope ("toplev::finalize");
2325 /* Ideally we would release the jit mutex here, but we can't yet since
2326 followup activities use timevars, which are global state. */
2328 if (errors_occurred ())
2330 release_mutex ();
2331 return;
2334 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
2335 dump_generated_code ();
2337 /* We now have a .s file.
2339 Run any postprocessing steps. This will either convert the .s file to
2340 a .so DSO, and load it in memory (playback::compile_to_memory), or
2341 convert the .s file to the requested output format, and copy it to a
2342 given file (playback::compile_to_file). */
2343 postprocess (ctxt_progname);
2345 release_mutex ();
2348 /* Implementation of class gcc::jit::playback::compile_to_memory,
2349 a subclass of gcc::jit::playback::context. */
2351 /* playback::compile_to_memory's trivial constructor. */
2353 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
2354 playback::context (ctxt),
2355 m_result (NULL)
2357 JIT_LOG_SCOPE (get_logger ());
2360 /* Implementation of the playback::context::process vfunc for compiling
2361 to memory.
2363 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
2364 wrapping the result up as a jit::result and returning it. */
2366 void
2367 playback::compile_to_memory::postprocess (const char *ctxt_progname)
2369 JIT_LOG_SCOPE (get_logger ());
2370 convert_to_dso (ctxt_progname);
2371 if (errors_occurred ())
2372 return;
2373 m_result = dlopen_built_dso ();
2376 /* Implementation of class gcc::jit::playback::compile_to_file,
2377 a subclass of gcc::jit::playback::context. */
2379 /* playback::compile_to_file's trivial constructor. */
2381 playback::compile_to_file::compile_to_file (recording::context *ctxt,
2382 enum gcc_jit_output_kind output_kind,
2383 const char *output_path) :
2384 playback::context (ctxt),
2385 m_output_kind (output_kind),
2386 m_output_path (output_path)
2388 JIT_LOG_SCOPE (get_logger ());
2391 /* Implementation of the playback::context::process vfunc for compiling
2392 to a file.
2394 Either copy the .s file to the given destination (for
2395 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
2396 as necessary, copying the result. */
2398 void
2399 playback::compile_to_file::postprocess (const char *ctxt_progname)
2401 JIT_LOG_SCOPE (get_logger ());
2403 /* The driver takes different actions based on the filename, so
2404 we provide a filename with an appropriate suffix for the
2405 output kind, and then copy it up to the user-provided path,
2406 rather than directly compiling it to the requested output path. */
2408 switch (m_output_kind)
2410 default:
2411 gcc_unreachable ();
2413 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
2414 copy_file (get_tempdir ()->get_path_s_file (),
2415 m_output_path);
2416 /* The .s file is automatically unlinked by tempdir::~tempdir. */
2417 break;
2419 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
2421 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
2422 "/fake.o",
2423 NULL);
2424 invoke_driver (ctxt_progname,
2425 get_tempdir ()->get_path_s_file (),
2426 tmp_o_path,
2427 TV_ASSEMBLE,
2428 false, /* bool shared, */
2429 false);/* bool run_linker */
2430 if (!errors_occurred ())
2432 copy_file (tmp_o_path,
2433 m_output_path);
2434 get_tempdir ()->add_temp_file (tmp_o_path);
2436 else
2437 free (tmp_o_path);
2439 break;
2441 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
2442 invoke_driver (ctxt_progname,
2443 get_tempdir ()->get_path_s_file (),
2444 get_tempdir ()->get_path_so_file (),
2445 TV_ASSEMBLE,
2446 true, /* bool shared, */
2447 true);/* bool run_linker */
2448 if (!errors_occurred ())
2449 copy_file (get_tempdir ()->get_path_so_file (),
2450 m_output_path);
2451 /* The .so file is automatically unlinked by tempdir::~tempdir. */
2452 break;
2454 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
2456 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
2457 "/fake.exe",
2458 NULL);
2459 invoke_driver (ctxt_progname,
2460 get_tempdir ()->get_path_s_file (),
2461 tmp_exe_path,
2462 TV_ASSEMBLE,
2463 false, /* bool shared, */
2464 true);/* bool run_linker */
2465 if (!errors_occurred ())
2467 copy_file (tmp_exe_path,
2468 m_output_path);
2469 get_tempdir ()->add_temp_file (tmp_exe_path);
2471 else
2472 free (tmp_exe_path);
2474 break;
2480 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2481 the "executable" bits).
2483 Any errors that occur are reported on the context and hence count as
2484 a failure of the compile.
2486 We can't in general hardlink or use "rename" from the tempdir since
2487 it might be on a different filesystem to the destination. For example,
2488 I get EXDEV: "Invalid cross-device link". */
2490 void
2491 playback::compile_to_file::copy_file (const char *src_path,
2492 const char *dst_path)
2494 JIT_LOG_SCOPE (get_logger ());
2495 if (get_logger ())
2497 get_logger ()->log ("src_path: %s", src_path);
2498 get_logger ()->log ("dst_path: %s", dst_path);
2501 FILE *f_in = NULL;
2502 FILE *f_out = NULL;
2503 size_t total_sz_in = 0;
2504 size_t total_sz_out = 0;
2505 char buf[4096];
2506 size_t sz_in;
2507 struct stat stat_buf;
2509 f_in = fopen (src_path, "rb");
2510 if (!f_in)
2512 add_error (NULL,
2513 "unable to open %s for reading: %s",
2514 src_path,
2515 xstrerror (errno));
2516 return;
2519 /* Use stat on the filedescriptor to get the mode,
2520 so that we can copy it over (in particular, the
2521 "executable" bits). */
2522 if (fstat (fileno (f_in), &stat_buf) == -1)
2524 add_error (NULL,
2525 "unable to fstat %s: %s",
2526 src_path,
2527 xstrerror (errno));
2528 fclose (f_in);
2529 return;
2532 f_out = fopen (dst_path, "wb");
2533 if (!f_out)
2535 add_error (NULL,
2536 "unable to open %s for writing: %s",
2537 dst_path,
2538 xstrerror (errno));
2539 fclose (f_in);
2540 return;
2543 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2545 total_sz_in += sz_in;
2546 size_t sz_out_remaining = sz_in;
2547 size_t sz_out_so_far = 0;
2548 while (sz_out_remaining)
2550 size_t sz_out = fwrite (buf + sz_out_so_far,
2552 sz_out_remaining,
2553 f_out);
2554 gcc_assert (sz_out <= sz_out_remaining);
2555 if (!sz_out)
2557 add_error (NULL,
2558 "error writing to %s: %s",
2559 dst_path,
2560 xstrerror (errno));
2561 fclose (f_in);
2562 fclose (f_out);
2563 return;
2565 total_sz_out += sz_out;
2566 sz_out_so_far += sz_out;
2567 sz_out_remaining -= sz_out;
2569 gcc_assert (sz_out_so_far == sz_in);
2572 if (!feof (f_in))
2573 add_error (NULL,
2574 "error reading from %s: %s",
2575 src_path,
2576 xstrerror (errno));
2578 fclose (f_in);
2580 gcc_assert (total_sz_in == total_sz_out);
2581 if (get_logger ())
2582 get_logger ()->log ("total bytes copied: %zu", total_sz_out);
2584 /* fchmod does not exist in Windows. */
2585 #ifndef _WIN32
2586 /* Set the permissions of the copy to those of the original file,
2587 in particular the "executable" bits. */
2588 if (fchmod (fileno (f_out), stat_buf.st_mode) == -1)
2589 add_error (NULL,
2590 "error setting mode of %s: %s",
2591 dst_path,
2592 xstrerror (errno));
2593 #endif
2595 fclose (f_out);
2598 /* Helper functions for gcc::jit::playback::context::compile. */
2600 /* This mutex guards gcc::jit::recording::context::compile, so that only
2601 one thread can be accessing the bulk of GCC's state at once. */
2603 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2605 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2607 void
2608 playback::context::acquire_mutex ()
2610 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2612 /* Acquire the big GCC mutex. */
2613 JIT_LOG_SCOPE (get_logger ());
2614 pthread_mutex_lock (&jit_mutex);
2615 gcc_assert (active_playback_ctxt == NULL);
2616 active_playback_ctxt = this;
2619 /* Release jit_mutex and clear the active playback ctxt. */
2621 void
2622 playback::context::release_mutex ()
2624 /* Release the big GCC mutex. */
2625 JIT_LOG_SCOPE (get_logger ());
2626 gcc_assert (active_playback_ctxt == this);
2627 active_playback_ctxt = NULL;
2628 pthread_mutex_unlock (&jit_mutex);
2631 /* Callback used by gcc::jit::playback::context::make_fake_args when
2632 invoking driver_get_configure_time_options.
2633 Populate a vec <char * > with the configure-time options. */
2635 static void
2636 append_arg_from_driver (const char *option, void *user_data)
2638 gcc_assert (option);
2639 gcc_assert (user_data);
2640 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2641 argvec->safe_push (concat ("-", option, NULL));
2644 /* Build a fake argv for toplev::main from the options set
2645 by the user on the context . */
2647 void
2648 playback::context::
2649 make_fake_args (vec <char *> *argvec,
2650 const char *ctxt_progname,
2651 vec <recording::requested_dump> *requested_dumps)
2653 JIT_LOG_SCOPE (get_logger ());
2655 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2656 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2658 ADD_ARG (ctxt_progname);
2659 ADD_ARG (get_path_c_file ());
2660 ADD_ARG ("-fPIC");
2662 /* Handle int options: */
2663 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2665 default:
2666 add_error (NULL,
2667 "unrecognized optimization level: %i",
2668 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2669 return;
2671 case 0:
2672 ADD_ARG ("-O0");
2673 break;
2675 case 1:
2676 ADD_ARG ("-O1");
2677 break;
2679 case 2:
2680 ADD_ARG ("-O2");
2681 break;
2683 case 3:
2684 ADD_ARG ("-O3");
2685 break;
2687 /* What about -Os? */
2689 /* Handle bool options: */
2690 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2691 ADD_ARG ("-g");
2693 /* Suppress timing (and other) info. */
2694 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2696 ADD_ARG ("-quiet");
2697 quiet_flag = 1;
2700 /* Aggressively garbage-collect, to shake out bugs: */
2701 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2703 ADD_ARG ("--param=ggc-min-expand=0");
2704 ADD_ARG ("--param=ggc-min-heapsize=0");
2707 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2709 ADD_ARG ("-fdump-tree-all");
2710 ADD_ARG ("-fdump-rtl-all");
2711 ADD_ARG ("-fdump-ipa-all");
2714 /* Add "-fdump-" options for any calls to
2715 gcc_jit_context_enable_dump. */
2717 int i;
2718 recording::requested_dump *d;
2719 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2721 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2722 ADD_ARG_TAKE_OWNERSHIP (arg);
2726 /* PR jit/64810: Add any target-specific default options
2727 from OPTION_DEFAULT_SPECS, normally provided by the driver
2728 in the non-jit case.
2730 The target-specific code can define OPTION_DEFAULT_SPECS:
2731 default command options in the form of spec macros for the
2732 driver to expand ().
2734 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2735 if not overriden, injects the defaults as extra arguments to
2736 cc1 etc.
2737 For the jit case, we need to add these arguments here. The
2738 input format (using the specs language) means that we have to run
2739 part of the driver code here (driver_get_configure_time_options).
2741 To avoid running the spec-expansion code every time, we just do
2742 it the first time (via a function-static flag), saving the result
2743 into a function-static vec.
2744 This flag and vec are global state (i.e. per-process).
2745 They are guarded by the jit mutex. */
2747 static bool have_configure_time_options = false;
2748 static vec <char *> configure_time_options;
2750 if (have_configure_time_options)
2751 log ("reusing cached configure-time options");
2752 else
2754 have_configure_time_options = true;
2755 log ("getting configure-time options from driver");
2756 driver_get_configure_time_options (append_arg_from_driver,
2757 &configure_time_options);
2760 int i;
2761 char *opt;
2763 if (get_logger ())
2764 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2765 log ("configure_time_options[%i]: %s", i, opt);
2767 /* configure_time_options should now contain the expanded options
2768 from OPTION_DEFAULT_SPECS (if any). */
2769 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2771 gcc_assert (opt);
2772 gcc_assert (opt[0] == '-');
2773 ADD_ARG (opt);
2777 if (get_timer ())
2778 ADD_ARG ("-ftime-report");
2780 /* Add any user-provided extra options, starting with any from
2781 parent contexts. */
2782 m_recording_ctxt->append_command_line_options (argvec);
2784 #undef ADD_ARG
2785 #undef ADD_ARG_TAKE_OWNERSHIP
2788 /* The second half of the implementation of gcc_jit_context_enable_dump.
2789 Iterate through the requested dumps, reading the underlying files
2790 into heap-allocated buffers, writing pointers to the buffers into
2791 the char ** pointers provided by client code.
2792 Client code is responsible for calling free on the results. */
2794 void
2795 playback::context::
2796 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2798 JIT_LOG_SCOPE (get_logger ());
2800 int i;
2801 recording::requested_dump *d;
2802 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2804 dump_file_info *dfi;
2805 char *filename;
2806 char *content;
2808 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2809 if (!dfi)
2811 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2812 continue;
2815 filename = g->get_dumps ()->get_dump_file_name (dfi);
2816 content = read_dump_file (filename);
2817 *(d->m_out_ptr) = content;
2818 m_tempdir->add_temp_file (filename);
2822 /* Helper function for playback::context::extract_any_requested_dumps
2823 (itself for use in implementation of gcc_jit_context_enable_dump).
2825 Attempt to read the complete file at the given path, returning the
2826 bytes found there as a buffer.
2827 The caller is responsible for calling free on the result.
2828 Errors will be reported on the context, and lead to NULL being
2829 returned; an out-of-memory error will terminate the process. */
2831 char *
2832 playback::context::read_dump_file (const char *path)
2834 char *result = NULL;
2835 size_t total_sz = 0;
2836 char buf[4096];
2837 size_t sz;
2838 FILE *f_in;
2840 f_in = fopen (path, "r");
2841 if (!f_in)
2843 add_error (NULL, "unable to open %s for reading", path);
2844 return NULL;
2847 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2849 size_t old_total_sz = total_sz;
2850 total_sz += sz;
2851 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2852 memcpy (result + old_total_sz, buf, sz);
2855 if (!feof (f_in))
2857 add_error (NULL, "error reading from %s", path);
2858 free (result);
2859 fclose (f_in);
2860 return NULL;
2863 fclose (f_in);
2865 if (result)
2867 result[total_sz] = '\0';
2868 return result;
2870 else
2871 return xstrdup ("");
2874 /* Part of playback::context::compile ().
2876 We have a .s file; we want a .so file.
2877 We could reuse parts of gcc/gcc.cc to do this.
2878 For now, just use the driver binary from the install, as
2879 named in gcc-driver-name.h
2880 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2882 void
2883 playback::context::
2884 convert_to_dso (const char *ctxt_progname)
2886 JIT_LOG_SCOPE (get_logger ());
2888 invoke_driver (ctxt_progname,
2889 m_tempdir->get_path_s_file (),
2890 m_tempdir->get_path_so_file (),
2891 TV_ASSEMBLE,
2892 true, /* bool shared, */
2893 true);/* bool run_linker */
2896 static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2898 void
2899 playback::context::
2900 invoke_driver (const char *ctxt_progname,
2901 const char *input_file,
2902 const char *output_file,
2903 timevar_id_t tv_id,
2904 bool shared,
2905 bool run_linker)
2907 JIT_LOG_SCOPE (get_logger ());
2909 bool embedded_driver
2910 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
2912 /* Currently this lumps together both assembling and linking into
2913 TV_ASSEMBLE. */
2914 auto_timevar assemble_timevar (get_timer (), tv_id);
2915 auto_string_vec argvec;
2916 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2918 ADD_ARG (gcc_driver_name);
2920 add_multilib_driver_arguments (&argvec);
2922 if (shared)
2923 ADD_ARG ("-shared");
2925 if (!run_linker)
2926 ADD_ARG ("-c");
2928 ADD_ARG (input_file);
2929 ADD_ARG ("-o");
2930 ADD_ARG (output_file);
2932 /* Don't use the linker plugin.
2933 If running with just a "make" and not a "make install", then we'd
2934 run into
2935 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2936 libto_plugin is a .la at build time, with it becoming installed with
2937 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2938 time. */
2939 ADD_ARG ("-fno-use-linker-plugin");
2941 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2942 /* OS X's linker defaults to treating undefined symbols as errors.
2943 If the context has any imported functions or globals they will be
2944 undefined until the .so is dynamically-linked into the process.
2945 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2946 linker. */
2947 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2948 #endif
2950 if (0)
2951 ADD_ARG ("-v");
2953 /* Add any user-provided driver extra options. */
2955 m_recording_ctxt->append_driver_options (&argvec);
2957 #undef ADD_ARG
2959 /* pex_one's error-handling requires pname to be non-NULL. */
2960 gcc_assert (ctxt_progname);
2962 if (get_logger ())
2963 for (unsigned i = 0; i < argvec.length (); i++)
2964 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2966 if (embedded_driver)
2967 invoke_embedded_driver (&argvec);
2968 else
2969 invoke_external_driver (ctxt_progname, &argvec);
2972 void
2973 playback::context::
2974 invoke_embedded_driver (const vec <char *> *argvec)
2976 JIT_LOG_SCOPE (get_logger ());
2977 driver d (true, /* can_finalize */
2978 false); /* debug */
2979 int result = d.main (argvec->length (),
2980 const_cast <char **> (argvec->address ()));
2981 d.finalize ();
2982 if (result)
2983 add_error (NULL, "error invoking gcc driver");
2986 void
2987 playback::context::
2988 invoke_external_driver (const char *ctxt_progname,
2989 vec <char *> *argvec)
2991 JIT_LOG_SCOPE (get_logger ());
2992 const char *errmsg;
2993 int exit_status = 0;
2994 int err = 0;
2996 /* pex argv arrays are NULL-terminated. */
2997 argvec->safe_push (NULL);
2999 errmsg = pex_one (PEX_SEARCH, /* int flags, */
3000 gcc_driver_name,
3001 const_cast <char *const *> (argvec->address ()),
3002 ctxt_progname, /* const char *pname */
3003 NULL, /* const char *outname */
3004 NULL, /* const char *errname */
3005 &exit_status, /* int *status */
3006 &err); /* int *err*/
3007 if (errmsg)
3009 add_error (NULL, "error invoking gcc driver: %s", errmsg);
3010 return;
3013 /* pex_one can return a NULL errmsg when the executable wasn't
3014 found (or doesn't exist), so trap these cases also. */
3015 if (exit_status || err)
3017 add_error (NULL,
3018 "error invoking gcc driver: exit_status: %i err: %i",
3019 exit_status, err);
3020 add_error (NULL,
3021 "whilst attempting to run a driver named: %s",
3022 gcc_driver_name);
3023 add_error (NULL,
3024 "PATH was: %s",
3025 getenv ("PATH"));
3026 return;
3030 /* Extract the target-specific MULTILIB_DEFAULTS to
3031 multilib_defaults_raw for use by
3032 playback::context::add_multilib_driver_arguments (). */
3034 #ifndef MULTILIB_DEFAULTS
3035 #define MULTILIB_DEFAULTS { "" }
3036 #endif
3038 static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
3040 /* Helper function for playback::context::invoke_driver ().
3042 32-bit and 64-bit multilib peer builds of libgccjit.so may share
3043 a driver binary. We need to pass in options to the shared driver
3044 to get the appropriate assembler/linker options for this multilib
3045 peer. */
3047 void
3048 playback::context::
3049 add_multilib_driver_arguments (vec <char *> *argvec)
3051 JIT_LOG_SCOPE (get_logger ());
3053 /* Add copies of the arguments in multilib_defaults_raw to argvec,
3054 prepending each with a "-". */
3055 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
3056 if (multilib_defaults_raw[i][0])
3057 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
3060 /* Dynamically-link the built DSO file into this process, using dlopen.
3061 Wrap it up within a jit::result *, and return that.
3062 Return NULL if any errors occur, reporting them on this context. */
3064 result *
3065 playback::context::
3066 dlopen_built_dso ()
3068 JIT_LOG_SCOPE (get_logger ());
3069 auto_timevar load_timevar (get_timer (), TV_LOAD);
3070 result::handle handle = NULL;
3071 result *result_obj = NULL;
3073 #ifdef _WIN32
3074 /* Clear any existing error. */
3075 SetLastError(0);
3077 handle = LoadLibrary(m_tempdir->get_path_so_file ());
3078 if (GetLastError() != 0) {
3079 print_last_error();
3081 #else
3082 const char *error = NULL;
3083 /* Clear any existing error. */
3084 dlerror ();
3086 handle = dlopen (m_tempdir->get_path_so_file (),
3087 RTLD_NOW | RTLD_LOCAL);
3088 if ((error = dlerror()) != NULL) {
3089 add_error (NULL, "%s", error);
3091 #endif
3093 if (handle)
3095 /* We've successfully dlopened the result; create a
3096 jit::result object to wrap it.
3098 We're done with the tempdir for now, but if the user
3099 has requested debugging, the user's debugger might not
3100 be capable of dealing with the .so file being unlinked
3101 immediately, so keep it around until after the result
3102 is released. We do this by handing over ownership of
3103 the jit::tempdir to the result. See PR jit/64206. */
3104 tempdir *handover_tempdir;
3105 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
3107 handover_tempdir = m_tempdir;
3108 m_tempdir = NULL;
3109 /* The tempdir will eventually be cleaned up in the
3110 jit::result's dtor. */
3111 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
3112 " handing over tempdir to jit::result");
3114 else
3116 handover_tempdir = NULL;
3117 /* ... and retain ownership of m_tempdir so we clean it
3118 up it the playback::context's dtor. */
3119 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
3120 " retaining ownership of tempdir");
3123 result_obj = new result (get_logger (), handle, handover_tempdir);
3125 else
3126 result_obj = NULL;
3128 return result_obj;
3131 /* Top-level hook for playing back a recording context.
3133 This plays back m_recording_ctxt, and, if no errors
3134 occurred builds statement lists for and then postprocesses
3135 every function in the result. */
3137 void
3138 playback::context::
3139 replay ()
3141 JIT_LOG_SCOPE (get_logger ());
3143 init_types ();
3145 /* Replay the recorded events: */
3146 timevar_push (TV_JIT_REPLAY);
3148 /* Ensure that builtins that could be needed during optimization
3149 get created ahead of time. */
3150 builtins_manager *bm = m_recording_ctxt->get_builtins_manager ();
3151 bm->ensure_optimization_builtins_exist ();
3153 m_recording_ctxt->replay_into (this);
3155 /* Clean away the temporary references from recording objects
3156 to playback objects. We have to do this now since the
3157 latter are GC-allocated, but the former don't mark these
3158 refs. Hence we must stop using them before the GC can run. */
3159 m_recording_ctxt->disassociate_from_playback ();
3161 /* The builtins_manager is associated with the recording::context
3162 and might be reused for future compiles on other playback::contexts,
3163 but its m_attributes array is not GTY-labeled and hence will become
3164 nonsense if the GC runs. Purge this state. */
3165 bm->finish_playback ();
3167 timevar_pop (TV_JIT_REPLAY);
3169 if (!errors_occurred ())
3171 int i;
3172 function *func;
3173 tree global;
3174 /* No GC can happen yet; process the cached source locations. */
3175 handle_locations ();
3177 /* Finalize globals. See how FORTRAN 95 does it in gfc_be_parse_file()
3178 for a simple reference. */
3179 FOR_EACH_VEC_ELT (m_globals, i, global)
3180 rest_of_decl_compilation (global, true, true);
3182 wrapup_global_declarations (m_globals.address(), m_globals.length());
3184 /* We've now created tree nodes for the stmts in the various blocks
3185 in each function, but we haven't built each function's single stmt
3186 list yet. Do so now. */
3187 FOR_EACH_VEC_ELT (m_functions, i, func)
3188 func->build_stmt_list ();
3190 /* No GC can have happened yet. */
3192 /* Postprocess the functions. This could trigger GC. */
3193 FOR_EACH_VEC_ELT (m_functions, i, func)
3195 gcc_assert (func);
3196 func->postprocess ();
3201 /* Dump the generated .s file to stderr. */
3203 void
3204 playback::context::
3205 dump_generated_code ()
3207 JIT_LOG_SCOPE (get_logger ());
3208 char buf[4096];
3209 size_t sz;
3210 FILE *f_in = fopen (get_path_s_file (), "r");
3211 if (!f_in)
3212 return;
3214 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
3215 fwrite (buf, 1, sz, stderr);
3217 fclose (f_in);
3220 /* Get the supposed path of the notional "fake.c" file within the
3221 tempdir. This file doesn't exist, but the rest of the compiler
3222 needs a name. */
3224 const char *
3225 playback::context::
3226 get_path_c_file () const
3228 return m_tempdir->get_path_c_file ();
3231 /* Get the path of the assembler output file "fake.s" file within the
3232 tempdir. */
3234 const char *
3235 playback::context::
3236 get_path_s_file () const
3238 return m_tempdir->get_path_s_file ();
3241 /* Get the path of the DSO object file "fake.so" file within the
3242 tempdir. */
3244 const char *
3245 playback::context::
3246 get_path_so_file () const
3248 return m_tempdir->get_path_so_file ();
3251 /* qsort comparator for comparing pairs of playback::source_line *,
3252 ordering them by line number. */
3254 static int
3255 line_comparator (const void *lhs, const void *rhs)
3257 const playback::source_line *line_lhs = \
3258 *static_cast<const playback::source_line * const*> (lhs);
3259 const playback::source_line *line_rhs = \
3260 *static_cast<const playback::source_line * const*> (rhs);
3261 return line_lhs->get_line_num () - line_rhs->get_line_num ();
3264 /* qsort comparator for comparing pairs of playback::location *,
3265 ordering them by column number. */
3267 static int
3268 location_comparator (const void *lhs, const void *rhs)
3270 const playback::location *loc_lhs = \
3271 *static_cast<const playback::location * const *> (lhs);
3272 const playback::location *loc_rhs = \
3273 *static_cast<const playback::location * const *> (rhs);
3274 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
3277 /* Initialize the NAME_TYPE of the primitive types as well as some
3278 others. */
3279 void
3280 playback::context::
3281 init_types ()
3283 /* See lto_init() in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc
3284 for reference. If TYPE_NAME is not set, debug info will not contain types */
3285 #define NAME_TYPE(t,n) \
3286 if (t) \
3287 TYPE_NAME (t) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, \
3288 get_identifier (n), t)
3290 NAME_TYPE (integer_type_node, "int");
3291 NAME_TYPE (char_type_node, "char");
3292 NAME_TYPE (long_integer_type_node, "long int");
3293 NAME_TYPE (unsigned_type_node, "unsigned int");
3294 NAME_TYPE (long_unsigned_type_node, "long unsigned int");
3295 NAME_TYPE (long_long_integer_type_node, "long long int");
3296 NAME_TYPE (long_long_unsigned_type_node, "long long unsigned int");
3297 NAME_TYPE (short_integer_type_node, "short int");
3298 NAME_TYPE (short_unsigned_type_node, "short unsigned int");
3299 if (signed_char_type_node != char_type_node)
3300 NAME_TYPE (signed_char_type_node, "signed char");
3301 if (unsigned_char_type_node != char_type_node)
3302 NAME_TYPE (unsigned_char_type_node, "unsigned char");
3303 NAME_TYPE (float_type_node, "float");
3304 NAME_TYPE (double_type_node, "double");
3305 NAME_TYPE (long_double_type_node, "long double");
3306 NAME_TYPE (void_type_node, "void");
3307 NAME_TYPE (boolean_type_node, "bool");
3308 NAME_TYPE (complex_float_type_node, "complex float");
3309 NAME_TYPE (complex_double_type_node, "complex double");
3310 NAME_TYPE (complex_long_double_type_node, "complex long double");
3312 m_const_char_ptr = build_pointer_type(
3313 build_qualified_type (char_type_node, TYPE_QUAL_CONST));
3315 NAME_TYPE (m_const_char_ptr, "char");
3316 NAME_TYPE (size_type_node, "size_t");
3317 NAME_TYPE (fileptr_type_node, "FILE");
3318 #undef NAME_TYPE
3321 /* Our API allows locations to be created in arbitrary orders, but the
3322 linemap API requires locations to be created in ascending order
3323 as if we were tokenizing files.
3325 This hook sorts all of the locations that have been created, and
3326 calls into the linemap API, creating linemap entries in sorted order
3327 for our locations. */
3329 void
3330 playback::context::
3331 handle_locations ()
3333 /* Create the source code locations, following the ordering rules
3334 imposed by the linemap API.
3336 line_table is a global. */
3337 JIT_LOG_SCOPE (get_logger ());
3338 int i;
3339 source_file *file;
3341 FOR_EACH_VEC_ELT (m_source_files, i, file)
3343 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
3345 /* Sort lines by ascending line numbers. */
3346 file->m_source_lines.qsort (&line_comparator);
3348 int j;
3349 source_line *line;
3350 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
3352 int k;
3353 location *loc;
3355 /* Sort locations in line by ascending column numbers. */
3356 line->m_locations.qsort (&location_comparator);
3358 /* Determine maximum column within this line. */
3359 gcc_assert (line->m_locations.length () > 0);
3360 location *final_column =
3361 line->m_locations[line->m_locations.length () - 1];
3362 int max_col = final_column->get_column_num ();
3364 linemap_line_start (line_table, line->get_line_num (), max_col);
3365 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
3367 loc->m_srcloc = \
3368 linemap_position_for_column (line_table, loc->get_column_num ());
3372 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
3375 /* line_table should now be populated; every playback::location should
3376 now have an m_srcloc. */
3378 /* Now assign them to tree nodes as appropriate. */
3379 std::pair<tree, location *> *cached_location;
3381 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
3383 tree t = cached_location->first;
3384 location_t srcloc = cached_location->second->m_srcloc;
3386 /* This covers expressions: */
3387 if (CAN_HAVE_LOCATION_P (t))
3388 SET_EXPR_LOCATION (t, srcloc);
3389 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
3390 DECL_SOURCE_LOCATION (t) = srcloc;
3391 else
3393 /* Don't know how to set location on this node. */
3398 /* We handle errors on a playback::context by adding them to the
3399 corresponding recording::context. */
3401 void
3402 playback::context::
3403 add_error (location *loc, const char *fmt, ...)
3405 va_list ap;
3406 va_start (ap, fmt);
3407 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
3408 fmt, ap);
3409 va_end (ap);
3412 /* We handle errors on a playback::context by adding them to the
3413 corresponding recording::context. */
3415 void
3416 playback::context::
3417 add_error_va (location *loc, const char *fmt, va_list ap)
3419 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
3420 fmt, ap);
3423 /* Report a diagnostic up to the jit context as an error,
3424 so that the compilation is treated as a failure.
3425 For now, any kind of diagnostic is treated as an error by the jit
3426 API. */
3428 void
3429 playback::context::
3430 add_diagnostic (struct diagnostic_context *diag_context,
3431 struct diagnostic_info *diagnostic)
3433 /* At this point the text has been formatted into the pretty-printer's
3434 output buffer. */
3435 pretty_printer *pp = diag_context->printer;
3436 const char *text = pp_formatted_text (pp);
3438 /* Get location information (if any) from the diagnostic.
3439 The recording::context::add_error[_va] methods require a
3440 recording::location. We can't lookup the playback::location
3441 from the file/line/column since any playback location instances
3442 may have been garbage-collected away by now, so instead we create
3443 another recording::location directly. */
3444 location_t gcc_loc = diagnostic_location (diagnostic);
3445 recording::location *rec_loc = NULL;
3446 if (gcc_loc)
3448 expanded_location exploc = expand_location (gcc_loc);
3449 if (exploc.file)
3450 rec_loc = m_recording_ctxt->new_location (exploc.file,
3451 exploc.line,
3452 exploc.column,
3453 false);
3456 m_recording_ctxt->add_error (rec_loc, "%s", text);
3457 pp_clear_output_area (pp);
3460 /* Dealing with the linemap API. */
3462 /* Construct a playback::location for a recording::location, if it
3463 doesn't exist already. */
3465 playback::location *
3466 playback::context::
3467 new_location (recording::location *rloc,
3468 const char *filename,
3469 int line,
3470 int column)
3472 /* Get the source_file for filename, creating if necessary. */
3473 source_file *src_file = get_source_file (filename);
3474 /* Likewise for the line within the file. */
3475 source_line *src_line = src_file->get_source_line (line);
3476 /* Likewise for the column within the line. */
3477 location *loc = src_line->get_location (rloc, column);
3478 return loc;
3481 /* Deferred setting of the location for a given tree, by adding the
3482 (tree, playback::location) pair to a list of deferred associations.
3483 We will actually set the location on the tree later on once
3484 the location_t for the playback::location exists. */
3486 void
3487 playback::context::
3488 set_tree_location (tree t, location *loc)
3490 gcc_assert (loc);
3491 m_cached_locations.safe_push (std::make_pair (t, loc));
3495 /* Construct a playback::source_file for the given source
3496 filename, if it doesn't exist already. */
3498 playback::source_file *
3499 playback::context::
3500 get_source_file (const char *filename)
3502 /* Locate the file.
3503 For simplicitly, this is currently a linear search.
3504 Replace with a hash if this shows up in the profile. */
3505 int i;
3506 source_file *file;
3507 tree ident_filename = get_identifier (filename);
3509 FOR_EACH_VEC_ELT (m_source_files, i, file)
3510 if (file->filename_as_tree () == ident_filename)
3511 return file;
3513 /* Not found. */
3514 file = new source_file (ident_filename);
3515 m_source_files.safe_push (file);
3516 return file;
3519 /* Constructor for gcc::jit::playback::source_file. */
3521 playback::source_file::source_file (tree filename) :
3522 m_source_lines (),
3523 m_filename (filename)
3527 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3528 GC-ed. */
3530 void
3531 playback::source_file::finalizer ()
3533 m_source_lines.release ();
3536 /* Construct a playback::source_line for the given line
3537 within this source file, if one doesn't exist already. */
3539 playback::source_line *
3540 playback::source_file::
3541 get_source_line (int line_num)
3543 /* Locate the line.
3544 For simplicitly, this is currently a linear search.
3545 Replace with a hash if this shows up in the profile. */
3546 int i;
3547 source_line *line;
3549 FOR_EACH_VEC_ELT (m_source_lines, i, line)
3550 if (line->get_line_num () == line_num)
3551 return line;
3553 /* Not found. */
3554 line = new source_line (this, line_num);
3555 m_source_lines.safe_push (line);
3556 return line;
3559 /* Constructor for gcc::jit::playback::source_line. */
3561 playback::source_line::source_line (source_file *file, int line_num) :
3562 m_locations (),
3563 m_source_file (file),
3564 m_line_num (line_num)
3568 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3569 GC-ed. */
3571 void
3572 playback::source_line::finalizer ()
3574 m_locations.release ();
3577 /* Construct a playback::location for the given column
3578 within this line of a specific source file, if one doesn't exist
3579 already. */
3581 playback::location *
3582 playback::source_line::
3583 get_location (recording::location *rloc, int column_num)
3585 int i;
3586 location *loc;
3588 /* Another linear search that probably should be a hash table. */
3589 FOR_EACH_VEC_ELT (m_locations, i, loc)
3590 if (loc->get_column_num () == column_num)
3591 return loc;
3593 /* Not found. */
3594 loc = new location (rloc, this, column_num);
3595 m_locations.safe_push (loc);
3596 return loc;
3599 /* Constructor for gcc::jit::playback::location. */
3601 playback::location::location (recording::location *loc,
3602 source_line *line,
3603 int column_num) :
3604 m_srcloc (UNKNOWN_LOCATION),
3605 m_recording_loc (loc),
3606 m_line (line),
3607 m_column_num(column_num)
3611 /* The active gcc::jit::playback::context instance. This is a singleton,
3612 guarded by jit_mutex. */
3614 playback::context *active_playback_ctxt;
3616 } // namespace gcc::jit
3618 } // namespace gcc