Improve costs for DImode shifts of interger constants.
[official-gcc.git] / gcc / jit / jit-playback.c
blob4fac64dcab7e6502bd3fd570e5808174eb62f952
1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2020 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"
43 #include <pthread.h>
45 #include "jit-playback.h"
46 #include "jit-result.h"
47 #include "jit-builtins.h"
48 #include "jit-tempdir.h"
50 #ifdef _WIN32
51 #include "jit-w32.h"
52 #endif
54 /* Compare with gcc/c-family/c-common.h: DECL_C_BIT_FIELD,
55 SET_DECL_C_BIT_FIELD.
56 These are redefined here to avoid depending from the C frontend. */
57 #define DECL_JIT_BIT_FIELD(NODE) \
58 (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1)
59 #define SET_DECL_JIT_BIT_FIELD(NODE) \
60 (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1)
62 /* gcc::jit::playback::context::build_cast uses the convert.h API,
63 which in turn requires the frontend to provide a "convert"
64 function, apparently as a fallback.
66 Hence we provide this dummy one, with the requirement that any casts
67 are handled before reaching this. */
68 extern tree convert (tree type, tree expr);
70 tree
71 convert (tree dst_type, tree expr)
73 gcc_assert (gcc::jit::active_playback_ctxt);
74 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
75 fprintf (stderr, "input expression:\n");
76 debug_tree (expr);
77 fprintf (stderr, "requested type:\n");
78 debug_tree (dst_type);
79 return error_mark_node;
82 namespace gcc {
83 namespace jit {
85 /**********************************************************************
86 Playback.
87 **********************************************************************/
89 /* The constructor for gcc::jit::playback::context. */
91 playback::context::context (recording::context *ctxt)
92 : log_user (ctxt->get_logger ()),
93 m_recording_ctxt (ctxt),
94 m_tempdir (NULL),
95 m_const_char_ptr (NULL)
97 JIT_LOG_SCOPE (get_logger ());
98 m_functions.create (0);
99 m_globals.create (0);
100 m_source_files.create (0);
101 m_cached_locations.create (0);
104 /* The destructor for gcc::jit::playback::context. */
106 playback::context::~context ()
108 JIT_LOG_SCOPE (get_logger ());
110 /* Normally the playback::context is responsible for cleaning up the
111 tempdir (including "fake.so" within the filesystem).
113 In the normal case, clean it up now.
115 However m_tempdir can be NULL if the context has handed over
116 responsibility for the tempdir cleanup to the jit::result object, so
117 that the cleanup can be delayed (see PR jit/64206). If that's the
118 case this "delete NULL;" is a no-op. */
119 delete m_tempdir;
121 m_functions.release ();
124 /* A playback::context can reference GC-managed pointers. Mark them
125 ("by hand", rather than by gengtype).
127 This is called on the active playback context (if any) by the
128 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
130 void
131 playback::context::
132 gt_ggc_mx ()
134 int i;
135 function *func;
136 FOR_EACH_VEC_ELT (m_functions, i, func)
138 if (ggc_test_and_set_mark (func))
139 func->gt_ggc_mx ();
143 /* Given an enum gcc_jit_types value, get a "tree" type. */
145 static tree
146 get_tree_node_for_type (enum gcc_jit_types type_)
148 switch (type_)
150 case GCC_JIT_TYPE_VOID:
151 return void_type_node;
153 case GCC_JIT_TYPE_VOID_PTR:
154 return ptr_type_node;
156 case GCC_JIT_TYPE_BOOL:
157 return boolean_type_node;
159 case GCC_JIT_TYPE_CHAR:
160 return char_type_node;
161 case GCC_JIT_TYPE_SIGNED_CHAR:
162 return signed_char_type_node;
163 case GCC_JIT_TYPE_UNSIGNED_CHAR:
164 return unsigned_char_type_node;
166 case GCC_JIT_TYPE_SHORT:
167 return short_integer_type_node;
168 case GCC_JIT_TYPE_UNSIGNED_SHORT:
169 return short_unsigned_type_node;
171 case GCC_JIT_TYPE_CONST_CHAR_PTR:
173 tree const_char = build_qualified_type (char_type_node,
174 TYPE_QUAL_CONST);
175 return build_pointer_type (const_char);
178 case GCC_JIT_TYPE_INT:
179 return integer_type_node;
180 case GCC_JIT_TYPE_UNSIGNED_INT:
181 return unsigned_type_node;
183 case GCC_JIT_TYPE_LONG:
184 return long_integer_type_node;
185 case GCC_JIT_TYPE_UNSIGNED_LONG:
186 return long_unsigned_type_node;
188 case GCC_JIT_TYPE_LONG_LONG:
189 return long_long_integer_type_node;
190 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
191 return long_long_unsigned_type_node;
193 case GCC_JIT_TYPE_FLOAT:
194 return float_type_node;
195 case GCC_JIT_TYPE_DOUBLE:
196 return double_type_node;
197 case GCC_JIT_TYPE_LONG_DOUBLE:
198 return long_double_type_node;
200 case GCC_JIT_TYPE_SIZE_T:
201 return size_type_node;
203 case GCC_JIT_TYPE_FILE_PTR:
204 return fileptr_type_node;
206 case GCC_JIT_TYPE_COMPLEX_FLOAT:
207 return complex_float_type_node;
208 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
209 return complex_double_type_node;
210 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
211 return complex_long_double_type_node;
214 return NULL;
217 /* Construct a playback::type instance (wrapping a tree) for the given
218 enum value. */
220 playback::type *
221 playback::context::
222 get_type (enum gcc_jit_types type_)
224 tree type_node = get_tree_node_for_type (type_);
225 if (type_node == NULL)
227 add_error (NULL, "unrecognized (enum gcc_jit_types) value: %i", type_);
228 return NULL;
231 return new type (type_node);
234 /* Construct a playback::type instance (wrapping a tree) for the given
235 array type. */
237 playback::type *
238 playback::context::
239 new_array_type (playback::location *loc,
240 playback::type *element_type,
241 int num_elements)
243 gcc_assert (element_type);
245 tree t = build_array_type_nelts (element_type->as_tree (),
246 num_elements);
247 layout_type (t);
249 if (loc)
250 set_tree_location (t, loc);
252 return new type (t);
255 /* Construct a playback::field instance (wrapping a tree). */
257 playback::field *
258 playback::context::
259 new_field (location *loc,
260 type *type,
261 const char *name)
263 gcc_assert (type);
264 gcc_assert (name);
266 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
267 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
268 get_identifier (name), type->as_tree ());
270 if (loc)
271 set_tree_location (decl, loc);
273 return new field (decl);
276 /* Construct a playback::bitfield instance (wrapping a tree). */
278 playback::field *
279 playback::context::
280 new_bitfield (location *loc,
281 type *type,
282 int width,
283 const char *name)
285 gcc_assert (type);
286 gcc_assert (name);
287 gcc_assert (width);
289 /* compare with c/c-decl.c:grokfield, grokdeclarator and
290 check_bitfield_type_and_width. */
292 tree tree_type = type->as_tree ();
293 gcc_assert (INTEGRAL_TYPE_P (tree_type));
294 tree tree_width = build_int_cst (integer_type_node, width);
295 if (compare_tree_int (tree_width, TYPE_PRECISION (tree_type)) > 0)
297 add_error (
298 loc,
299 "width of bit-field %s (width: %i) is wider than its type (width: %i)",
300 name, width, TYPE_PRECISION (tree_type));
301 return NULL;
304 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
305 get_identifier (name), type->as_tree ());
306 DECL_NONADDRESSABLE_P (decl) = true;
307 DECL_INITIAL (decl) = tree_width;
308 SET_DECL_JIT_BIT_FIELD (decl);
310 if (loc)
311 set_tree_location (decl, loc);
313 return new field (decl);
316 /* Construct a playback::compound_type instance (wrapping a tree). */
318 playback::compound_type *
319 playback::context::
320 new_compound_type (location *loc,
321 const char *name,
322 bool is_struct) /* else is union */
324 gcc_assert (name);
326 /* Compare with c/c-decl.c: start_struct. */
328 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
329 TYPE_NAME (t) = get_identifier (name);
330 TYPE_SIZE (t) = 0;
332 if (loc)
333 set_tree_location (t, loc);
335 return new compound_type (t);
338 void
339 playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
341 /* Compare with c/c-decl.c: finish_struct. */
342 tree t = as_tree ();
344 tree fieldlist = NULL;
345 for (unsigned i = 0; i < fields->length (); i++)
347 field *f = (*fields)[i];
348 tree x = f->as_tree ();
349 DECL_CONTEXT (x) = t;
350 if (DECL_JIT_BIT_FIELD (x))
352 unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (x));
353 DECL_SIZE (x) = bitsize_int (width);
354 DECL_BIT_FIELD (x) = 1;
356 fieldlist = chainon (x, fieldlist);
358 fieldlist = nreverse (fieldlist);
359 TYPE_FIELDS (t) = fieldlist;
361 layout_type (t);
364 /* Construct a playback::type instance (wrapping a tree) for a function
365 type. */
367 playback::type *
368 playback::context::
369 new_function_type (type *return_type,
370 const auto_vec<type *> *param_types,
371 int is_variadic)
373 int i;
374 type *param_type;
376 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
378 FOR_EACH_VEC_ELT (*param_types, i, param_type)
379 arg_types[i] = param_type->as_tree ();
381 tree fn_type;
382 if (is_variadic)
383 fn_type =
384 build_varargs_function_type_array (return_type->as_tree (),
385 param_types->length (),
386 arg_types);
387 else
388 fn_type = build_function_type_array (return_type->as_tree (),
389 param_types->length (),
390 arg_types);
391 free (arg_types);
393 return new type (fn_type);
396 /* Construct a playback::param instance (wrapping a tree). */
398 playback::param *
399 playback::context::
400 new_param (location *loc,
401 type *type,
402 const char *name)
404 gcc_assert (type);
405 gcc_assert (name);
406 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
407 get_identifier (name), type->as_tree ());
408 if (loc)
409 set_tree_location (inner, loc);
411 return new param (this, inner);
414 /* Construct a playback::function instance. */
416 playback::function *
417 playback::context::
418 new_function (location *loc,
419 enum gcc_jit_function_kind kind,
420 type *return_type,
421 const char *name,
422 const auto_vec<param *> *params,
423 int is_variadic,
424 enum built_in_function builtin_id)
426 int i;
427 param *param;
429 //can return_type be NULL?
430 gcc_assert (name);
432 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
433 FOR_EACH_VEC_ELT (*params, i, param)
434 arg_types[i] = TREE_TYPE (param->as_tree ());
436 tree fn_type;
437 if (is_variadic)
438 fn_type = build_varargs_function_type_array (return_type->as_tree (),
439 params->length (), arg_types);
440 else
441 fn_type = build_function_type_array (return_type->as_tree (),
442 params->length (), arg_types);
443 free (arg_types);
445 /* FIXME: this uses input_location: */
446 tree fndecl = build_fn_decl (name, fn_type);
448 if (loc)
449 set_tree_location (fndecl, loc);
451 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
452 NULL_TREE, return_type->as_tree ());
453 DECL_ARTIFICIAL (resdecl) = 1;
454 DECL_IGNORED_P (resdecl) = 1;
455 DECL_RESULT (fndecl) = resdecl;
457 if (builtin_id)
459 gcc_assert (loc == NULL);
460 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
462 built_in_class fclass = builtins_manager::get_class (builtin_id);
463 set_decl_built_in_function (fndecl, fclass, builtin_id);
464 set_builtin_decl (builtin_id, fndecl,
465 builtins_manager::implicit_p (builtin_id));
467 builtins_manager *bm = get_builtins_manager ();
468 tree attrs = bm->get_attrs_tree (builtin_id);
469 if (attrs)
470 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
471 else
472 decl_attributes (&fndecl, NULL_TREE, 0);
475 if (kind != GCC_JIT_FUNCTION_IMPORTED)
477 tree param_decl_list = NULL;
478 FOR_EACH_VEC_ELT (*params, i, param)
480 param_decl_list = chainon (param->as_tree (), param_decl_list);
483 /* The param list was created in reverse order; fix it: */
484 param_decl_list = nreverse (param_decl_list);
486 tree t;
487 for (t = param_decl_list; t; t = DECL_CHAIN (t))
489 DECL_CONTEXT (t) = fndecl;
490 DECL_ARG_TYPE (t) = TREE_TYPE (t);
493 /* Set it up on DECL_ARGUMENTS */
494 DECL_ARGUMENTS(fndecl) = param_decl_list;
497 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
499 DECL_DECLARED_INLINE_P (fndecl) = 1;
501 /* Add attribute "always_inline": */
502 DECL_ATTRIBUTES (fndecl) =
503 tree_cons (get_identifier ("always_inline"),
504 NULL,
505 DECL_ATTRIBUTES (fndecl));
508 function *func = new function (this, fndecl, kind);
509 m_functions.safe_push (func);
510 return func;
513 /* In use by new_global and new_global_initialized. */
515 tree
516 playback::context::
517 global_new_decl (location *loc,
518 enum gcc_jit_global_kind kind,
519 type *type,
520 const char *name)
522 gcc_assert (type);
523 gcc_assert (name);
524 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
525 get_identifier (name),
526 type->as_tree ());
527 TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
528 DECL_COMMON (inner) = 1;
529 switch (kind)
531 default:
532 gcc_unreachable ();
534 case GCC_JIT_GLOBAL_EXPORTED:
535 TREE_STATIC (inner) = 1;
536 break;
538 case GCC_JIT_GLOBAL_INTERNAL:
539 TREE_STATIC (inner) = 1;
540 break;
542 case GCC_JIT_GLOBAL_IMPORTED:
543 DECL_EXTERNAL (inner) = 1;
544 break;
547 if (loc)
548 set_tree_location (inner, loc);
550 return inner;
553 /* In use by new_global and new_global_initialized. */
555 playback::lvalue *
556 playback::context::
557 global_finalize_lvalue (tree inner)
559 varpool_node::get_create (inner);
561 varpool_node::finalize_decl (inner);
563 m_globals.safe_push (inner);
565 return new lvalue (this, inner);
568 /* Construct a playback::lvalue instance (wrapping a tree). */
570 playback::lvalue *
571 playback::context::
572 new_global (location *loc,
573 enum gcc_jit_global_kind kind,
574 type *type,
575 const char *name)
577 tree inner = global_new_decl (loc, kind, type, name);
579 return global_finalize_lvalue (inner);
582 /* Fill 'constructor_elements' with the memory content of
583 'initializer'. Each element of the initializer is of the size of
584 type T. In use by new_global_initialized.*/
586 template<typename T>
587 static void
588 load_blob_in_ctor (vec<constructor_elt, va_gc> *&constructor_elements,
589 size_t num_elem,
590 const void *initializer)
592 /* Loosely based on 'output_init_element' c-typeck.c:9691. */
593 const T *p = (const T *)initializer;
594 tree node = make_unsigned_type (BITS_PER_UNIT * sizeof (T));
595 for (size_t i = 0; i < num_elem; i++)
597 constructor_elt celt =
598 { build_int_cst (long_unsigned_type_node, i),
599 build_int_cst (node, p[i]) };
600 vec_safe_push (constructor_elements, celt);
604 /* Construct an initialized playback::lvalue instance (wrapping a
605 tree). */
607 playback::lvalue *
608 playback::context::
609 new_global_initialized (location *loc,
610 enum gcc_jit_global_kind kind,
611 type *type,
612 size_t element_size,
613 size_t initializer_num_elem,
614 const void *initializer,
615 const char *name)
617 tree inner = global_new_decl (loc, kind, type, name);
619 vec<constructor_elt, va_gc> *constructor_elements = NULL;
621 switch (element_size)
623 case 1:
624 load_blob_in_ctor<uint8_t> (constructor_elements, initializer_num_elem,
625 initializer);
626 break;
627 case 2:
628 load_blob_in_ctor<uint16_t> (constructor_elements, initializer_num_elem,
629 initializer);
630 break;
631 case 4:
632 load_blob_in_ctor<uint32_t> (constructor_elements, initializer_num_elem,
633 initializer);
634 break;
635 case 8:
636 load_blob_in_ctor<uint64_t> (constructor_elements, initializer_num_elem,
637 initializer);
638 break;
639 default:
640 /* This function is serving on sizes returned by 'get_size',
641 these are all covered by the previous cases. */
642 gcc_unreachable ();
644 /* Compare with 'pop_init_level' c-typeck.c:8780. */
645 tree ctor = build_constructor (type->as_tree (), constructor_elements);
646 constructor_elements = NULL;
648 /* Compare with 'store_init_value' c-typeck.c:7555. */
649 DECL_INITIAL (inner) = ctor;
651 return global_finalize_lvalue (inner);
654 /* Implementation of the various
655 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
656 methods.
657 Each of these constructs a playback::rvalue instance (wrapping a tree).
659 These specializations are required to be in the same namespace
660 as the template, hence we now have to enter the gcc::jit::playback
661 namespace. */
663 namespace playback
666 /* Specialization of making an rvalue from a const, for host <int>. */
668 template <>
669 rvalue *
670 context::
671 new_rvalue_from_const <int> (type *type,
672 int value)
674 // FIXME: type-checking, or coercion?
675 tree inner_type = type->as_tree ();
676 if (INTEGRAL_TYPE_P (inner_type))
678 tree inner = build_int_cst (inner_type, value);
679 return new rvalue (this, inner);
681 else
683 REAL_VALUE_TYPE real_value;
684 real_from_integer (&real_value, VOIDmode, value, SIGNED);
685 tree inner = build_real (inner_type, real_value);
686 return new rvalue (this, inner);
690 /* Specialization of making an rvalue from a const, for host <long>. */
692 template <>
693 rvalue *
694 context::
695 new_rvalue_from_const <long> (type *type,
696 long value)
698 // FIXME: type-checking, or coercion?
699 tree inner_type = type->as_tree ();
700 if (INTEGRAL_TYPE_P (inner_type))
702 tree inner = build_int_cst (inner_type, value);
703 return new rvalue (this, inner);
705 else
707 REAL_VALUE_TYPE real_value;
708 real_from_integer (&real_value, VOIDmode, value, SIGNED);
709 tree inner = build_real (inner_type, real_value);
710 return new rvalue (this, inner);
714 /* Specialization of making an rvalue from a const, for host <double>. */
716 template <>
717 rvalue *
718 context::
719 new_rvalue_from_const <double> (type *type,
720 double value)
722 // FIXME: type-checking, or coercion?
723 tree inner_type = type->as_tree ();
725 /* We have a "double", we want a REAL_VALUE_TYPE.
727 real.c:real_from_target appears to require the representation to be
728 split into 32-bit values, and then sent as an pair of host long
729 ints. */
730 REAL_VALUE_TYPE real_value;
731 union
733 double as_double;
734 uint32_t as_uint32s[2];
735 } u;
736 u.as_double = value;
737 long int as_long_ints[2];
738 as_long_ints[0] = u.as_uint32s[0];
739 as_long_ints[1] = u.as_uint32s[1];
740 real_from_target (&real_value, as_long_ints, DFmode);
741 tree inner = build_real (inner_type, real_value);
742 return new rvalue (this, inner);
745 /* Specialization of making an rvalue from a const, for host <void *>. */
747 template <>
748 rvalue *
749 context::
750 new_rvalue_from_const <void *> (type *type,
751 void *value)
753 tree inner_type = type->as_tree ();
754 /* FIXME: how to ensure we have a wide enough type? */
755 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
756 return new rvalue (this, inner);
759 /* We're done implementing the specializations of
760 gcc::jit::playback::context::new_rvalue_from_const <T>
761 so we can exit the gcc::jit::playback namespace. */
763 } // namespace playback
765 /* Construct a playback::rvalue instance (wrapping a tree). */
767 playback::rvalue *
768 playback::context::
769 new_string_literal (const char *value)
771 /* Compare with c-family/c-common.c: fix_string_type. */
772 size_t len = strlen (value);
773 tree i_type = build_index_type (size_int (len));
774 tree a_type = build_array_type (char_type_node, i_type);
775 /* build_string len parameter must include NUL terminator when
776 building C strings. */
777 tree t_str = build_string (len + 1, value);
778 TREE_TYPE (t_str) = a_type;
780 /* Convert to (const char*), loosely based on
781 c/c-typeck.c: array_to_pointer_conversion,
782 by taking address of start of string. */
783 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
785 return new rvalue (this, t_addr);
788 /* Construct a playback::rvalue instance (wrapping a tree) for a
789 vector. */
791 playback::rvalue *
792 playback::context::new_rvalue_from_vector (location *,
793 type *type,
794 const auto_vec<rvalue *> &elements)
796 vec<constructor_elt, va_gc> *v;
797 vec_alloc (v, elements.length ());
798 for (unsigned i = 0; i < elements.length (); ++i)
799 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
800 tree t_ctor = build_constructor (type->as_tree (), v);
801 return new rvalue (this, t_ctor);
804 /* Coerce a tree expression into a boolean tree expression. */
806 tree
807 playback::context::
808 as_truth_value (tree expr, location *loc)
810 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
811 tree typed_zero = fold_build1 (CONVERT_EXPR,
812 TREE_TYPE (expr),
813 integer_zero_node);
814 if (loc)
815 set_tree_location (typed_zero, loc);
817 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
818 if (loc)
819 set_tree_location (expr, loc);
821 return expr;
824 /* Construct a playback::rvalue instance (wrapping a tree) for a
825 unary op. */
827 playback::rvalue *
828 playback::context::
829 new_unary_op (location *loc,
830 enum gcc_jit_unary_op op,
831 type *result_type,
832 rvalue *a)
834 // FIXME: type-checking, or coercion?
835 enum tree_code inner_op;
837 gcc_assert (result_type);
838 gcc_assert (a);
840 tree node = a->as_tree ();
841 tree inner_result = NULL;
843 switch (op)
845 default:
846 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
847 return NULL;
849 case GCC_JIT_UNARY_OP_MINUS:
850 inner_op = NEGATE_EXPR;
851 break;
853 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
854 inner_op = BIT_NOT_EXPR;
855 break;
857 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
858 node = as_truth_value (node, loc);
859 inner_result = invert_truthvalue (node);
860 if (loc)
861 set_tree_location (inner_result, loc);
862 return new rvalue (this, inner_result);
864 case GCC_JIT_UNARY_OP_ABS:
865 inner_op = ABS_EXPR;
866 break;
869 inner_result = build1 (inner_op,
870 result_type->as_tree (),
871 node);
872 if (loc)
873 set_tree_location (inner_result, loc);
875 return new rvalue (this, inner_result);
878 /* Construct a playback::rvalue instance (wrapping a tree) for a
879 binary op. */
881 playback::rvalue *
882 playback::context::
883 new_binary_op (location *loc,
884 enum gcc_jit_binary_op op,
885 type *result_type,
886 rvalue *a, rvalue *b)
888 // FIXME: type-checking, or coercion?
889 enum tree_code inner_op;
891 gcc_assert (result_type);
892 gcc_assert (a);
893 gcc_assert (b);
895 tree node_a = a->as_tree ();
896 tree node_b = b->as_tree ();
898 switch (op)
900 default:
901 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
902 return NULL;
904 case GCC_JIT_BINARY_OP_PLUS:
905 inner_op = PLUS_EXPR;
906 break;
908 case GCC_JIT_BINARY_OP_MINUS:
909 inner_op = MINUS_EXPR;
910 break;
912 case GCC_JIT_BINARY_OP_MULT:
913 inner_op = MULT_EXPR;
914 break;
916 case GCC_JIT_BINARY_OP_DIVIDE:
917 if (FLOAT_TYPE_P (result_type->as_tree ()))
918 /* Floating-point division: */
919 inner_op = RDIV_EXPR;
920 else
921 /* Truncating to zero: */
922 inner_op = TRUNC_DIV_EXPR;
923 break;
925 case GCC_JIT_BINARY_OP_MODULO:
926 inner_op = TRUNC_MOD_EXPR;
927 break;
929 case GCC_JIT_BINARY_OP_BITWISE_AND:
930 inner_op = BIT_AND_EXPR;
931 break;
933 case GCC_JIT_BINARY_OP_BITWISE_XOR:
934 inner_op = BIT_XOR_EXPR;
935 break;
937 case GCC_JIT_BINARY_OP_BITWISE_OR:
938 inner_op = BIT_IOR_EXPR;
939 break;
941 case GCC_JIT_BINARY_OP_LOGICAL_AND:
942 node_a = as_truth_value (node_a, loc);
943 node_b = as_truth_value (node_b, loc);
944 inner_op = TRUTH_ANDIF_EXPR;
945 break;
947 case GCC_JIT_BINARY_OP_LOGICAL_OR:
948 node_a = as_truth_value (node_a, loc);
949 node_b = as_truth_value (node_b, loc);
950 inner_op = TRUTH_ORIF_EXPR;
951 break;
953 case GCC_JIT_BINARY_OP_LSHIFT:
954 inner_op = LSHIFT_EXPR;
955 break;
957 case GCC_JIT_BINARY_OP_RSHIFT:
958 inner_op = RSHIFT_EXPR;
959 break;
962 tree inner_expr = build2 (inner_op,
963 result_type->as_tree (),
964 node_a,
965 node_b);
966 if (loc)
967 set_tree_location (inner_expr, loc);
969 return new rvalue (this, inner_expr);
972 /* Construct a playback::rvalue instance (wrapping a tree) for a
973 comparison. */
975 playback::rvalue *
976 playback::context::
977 new_comparison (location *loc,
978 enum gcc_jit_comparison op,
979 rvalue *a, rvalue *b)
981 // FIXME: type-checking, or coercion?
982 enum tree_code inner_op;
984 gcc_assert (a);
985 gcc_assert (b);
987 switch (op)
989 default:
990 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
991 return NULL;
993 case GCC_JIT_COMPARISON_EQ:
994 inner_op = EQ_EXPR;
995 break;
996 case GCC_JIT_COMPARISON_NE:
997 inner_op = NE_EXPR;
998 break;
999 case GCC_JIT_COMPARISON_LT:
1000 inner_op = LT_EXPR;
1001 break;
1002 case GCC_JIT_COMPARISON_LE:
1003 inner_op = LE_EXPR;
1004 break;
1005 case GCC_JIT_COMPARISON_GT:
1006 inner_op = GT_EXPR;
1007 break;
1008 case GCC_JIT_COMPARISON_GE:
1009 inner_op = GE_EXPR;
1010 break;
1013 tree inner_expr = build2 (inner_op,
1014 boolean_type_node,
1015 a->as_tree (),
1016 b->as_tree ());
1017 if (loc)
1018 set_tree_location (inner_expr, loc);
1019 return new rvalue (this, inner_expr);
1022 /* Construct a playback::rvalue instance (wrapping a tree) for a
1023 function call. */
1025 playback::rvalue *
1026 playback::context::
1027 build_call (location *loc,
1028 tree fn_ptr,
1029 const auto_vec<rvalue *> *args,
1030 bool require_tail_call)
1032 vec<tree, va_gc> *tree_args;
1033 vec_alloc (tree_args, args->length ());
1034 for (unsigned i = 0; i < args->length (); i++)
1035 tree_args->quick_push ((*args)[i]->as_tree ());
1037 if (loc)
1038 set_tree_location (fn_ptr, loc);
1040 tree fn = TREE_TYPE (fn_ptr);
1041 tree fn_type = TREE_TYPE (fn);
1042 tree return_type = TREE_TYPE (fn_type);
1044 tree call = build_call_vec (return_type,
1045 fn_ptr, tree_args);
1047 if (require_tail_call)
1048 CALL_EXPR_MUST_TAIL_CALL (call) = 1;
1050 return new rvalue (this, call);
1052 /* see c-typeck.c: build_function_call
1053 which calls build_function_call_vec
1055 which does lots of checking, then:
1056 result = build_call_array_loc (loc, TREE_TYPE (fntype),
1057 function, nargs, argarray);
1058 which is in tree.c
1059 (see also build_call_vec)
1063 /* Construct a playback::rvalue instance (wrapping a tree) for a
1064 call to a specific function. */
1066 playback::rvalue *
1067 playback::context::
1068 new_call (location *loc,
1069 function *func,
1070 const auto_vec<rvalue *> *args,
1071 bool require_tail_call)
1073 tree fndecl;
1075 gcc_assert (func);
1077 fndecl = func->as_fndecl ();
1079 tree fntype = TREE_TYPE (fndecl);
1081 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
1083 return build_call (loc, fn, args, require_tail_call);
1086 /* Construct a playback::rvalue instance (wrapping a tree) for a
1087 call through a function pointer. */
1089 playback::rvalue *
1090 playback::context::
1091 new_call_through_ptr (location *loc,
1092 rvalue *fn_ptr,
1093 const auto_vec<rvalue *> *args,
1094 bool require_tail_call)
1096 gcc_assert (fn_ptr);
1097 tree t_fn_ptr = fn_ptr->as_tree ();
1099 return build_call (loc, t_fn_ptr, args, require_tail_call);
1102 /* Construct a tree for a cast. */
1104 tree
1105 playback::context::build_cast (playback::location *loc,
1106 playback::rvalue *expr,
1107 playback::type *type_)
1109 /* For comparison, see:
1110 - c/c-typeck.c:build_c_cast
1111 - c/c-convert.c: convert
1112 - convert.h
1114 Only some kinds of cast are currently supported here. */
1115 tree t_expr = expr->as_tree ();
1116 tree t_dst_type = type_->as_tree ();
1117 tree t_ret = NULL;
1118 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
1119 if (t_ret)
1120 return t_ret;
1121 enum tree_code dst_code = TREE_CODE (t_dst_type);
1122 switch (dst_code)
1124 case INTEGER_TYPE:
1125 case ENUMERAL_TYPE:
1126 t_ret = convert_to_integer (t_dst_type, t_expr);
1127 goto maybe_fold;
1129 case BOOLEAN_TYPE:
1130 /* Compare with c_objc_common_truthvalue_conversion and
1131 c_common_truthvalue_conversion. */
1132 /* For now, convert to: (t_expr != 0) */
1133 t_ret = build2 (NE_EXPR, t_dst_type,
1134 t_expr,
1135 build_int_cst (TREE_TYPE (t_expr), 0));
1136 goto maybe_fold;
1138 case REAL_TYPE:
1139 t_ret = convert_to_real (t_dst_type, t_expr);
1140 goto maybe_fold;
1142 case POINTER_TYPE:
1143 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
1144 goto maybe_fold;
1146 default:
1147 add_error (loc, "couldn't handle cast during playback");
1148 fprintf (stderr, "input expression:\n");
1149 debug_tree (t_expr);
1150 fprintf (stderr, "requested type:\n");
1151 debug_tree (t_dst_type);
1152 return error_mark_node;
1154 maybe_fold:
1155 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
1156 t_ret = fold (t_ret);
1157 return t_ret;
1161 /* Construct a playback::rvalue instance (wrapping a tree) for a
1162 cast. */
1164 playback::rvalue *
1165 playback::context::
1166 new_cast (playback::location *loc,
1167 playback::rvalue *expr,
1168 playback::type *type_)
1171 tree t_cast = build_cast (loc, expr, type_);
1172 if (loc)
1173 set_tree_location (t_cast, loc);
1174 return new rvalue (this, t_cast);
1177 /* Construct a playback::lvalue instance (wrapping a tree) for an
1178 array access. */
1180 playback::lvalue *
1181 playback::context::
1182 new_array_access (location *loc,
1183 rvalue *ptr,
1184 rvalue *index)
1186 gcc_assert (ptr);
1187 gcc_assert (index);
1189 /* For comparison, see:
1190 c/c-typeck.c: build_array_ref
1191 c-family/c-common.c: pointer_int_sum
1193 tree t_ptr = ptr->as_tree ();
1194 tree t_index = index->as_tree ();
1195 tree t_type_ptr = TREE_TYPE (t_ptr);
1196 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1198 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1200 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1201 NULL_TREE, NULL_TREE);
1202 if (loc)
1203 set_tree_location (t_result, loc);
1204 return new lvalue (this, t_result);
1206 else
1208 /* Convert index to an offset in bytes. */
1209 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1210 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1211 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
1213 /* Locate (ptr + offset). */
1214 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1216 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1217 if (loc)
1219 set_tree_location (t_sizeof, loc);
1220 set_tree_location (t_offset, loc);
1221 set_tree_location (t_address, loc);
1222 set_tree_location (t_indirection, loc);
1225 return new lvalue (this, t_indirection);
1229 /* Construct a tree for a field access. */
1231 tree
1232 playback::context::
1233 new_field_access (location *loc,
1234 tree datum,
1235 field *field)
1237 gcc_assert (datum);
1238 gcc_assert (field);
1240 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1241 build_component_ref. */
1242 tree type = TREE_TYPE (datum);
1243 gcc_assert (type);
1244 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1246 tree t_field = field->as_tree ();
1247 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1248 t_field, NULL_TREE);
1249 if (loc)
1250 set_tree_location (ref, loc);
1251 return ref;
1254 /* Construct a tree for a dereference. */
1256 tree
1257 playback::context::
1258 new_dereference (tree ptr,
1259 location *loc)
1261 gcc_assert (ptr);
1263 tree type = TREE_TYPE (TREE_TYPE(ptr));
1264 tree datum = build1 (INDIRECT_REF, type, ptr);
1265 if (loc)
1266 set_tree_location (datum, loc);
1267 return datum;
1270 /* Construct a playback::type instance (wrapping a tree)
1271 with the given alignment. */
1273 playback::type *
1274 playback::type::
1275 get_aligned (size_t alignment_in_bytes) const
1277 tree t_new_type = build_variant_type_copy (m_inner);
1279 SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT);
1280 TYPE_USER_ALIGN (t_new_type) = 1;
1282 return new type (t_new_type);
1285 /* Construct a playback::type instance (wrapping a tree)
1286 for the given vector type. */
1288 playback::type *
1289 playback::type::
1290 get_vector (size_t num_units) const
1292 tree t_new_type = build_vector_type (m_inner, num_units);
1293 return new type (t_new_type);
1296 /* Construct a playback::lvalue instance (wrapping a tree) for a
1297 field access. */
1299 playback::lvalue *
1300 playback::lvalue::
1301 access_field (location *loc,
1302 field *field)
1304 tree datum = as_tree ();
1305 tree ref = get_context ()->new_field_access (loc, datum, field);
1306 if (!ref)
1307 return NULL;
1308 return new lvalue (get_context (), ref);
1311 /* Construct a playback::rvalue instance (wrapping a tree) for a
1312 field access. */
1314 playback::rvalue *
1315 playback::rvalue::
1316 access_field (location *loc,
1317 field *field)
1319 tree datum = as_tree ();
1320 tree ref = get_context ()->new_field_access (loc, datum, field);
1321 if (!ref)
1322 return NULL;
1323 return new rvalue (get_context (), ref);
1326 /* Construct a playback::lvalue instance (wrapping a tree) for a
1327 dereferenced field access. */
1329 playback::lvalue *
1330 playback::rvalue::
1331 dereference_field (location *loc,
1332 field *field)
1334 tree ptr = as_tree ();
1335 tree datum = get_context ()->new_dereference (ptr, loc);
1336 if (!datum)
1337 return NULL;
1338 tree ref = get_context ()->new_field_access (loc, datum, field);
1339 if (!ref)
1340 return NULL;
1341 return new lvalue (get_context (), ref);
1344 /* Construct a playback::lvalue instance (wrapping a tree) for a
1345 dereference. */
1347 playback::lvalue *
1348 playback::rvalue::
1349 dereference (location *loc)
1351 tree ptr = as_tree ();
1352 tree datum = get_context ()->new_dereference (ptr, loc);
1353 return new lvalue (get_context (), datum);
1356 /* Mark the lvalue saying that we need to be able to take the
1357 address of it; it should not be allocated in a register.
1358 Compare with e.g. c/c-typeck.c: c_mark_addressable really_atomic_lvalue.
1359 Returns false if a failure occurred (an error will already have been
1360 added to the active context for this case). */
1362 bool
1363 playback::lvalue::
1364 mark_addressable (location *loc)
1366 tree x = as_tree ();;
1368 while (1)
1369 switch (TREE_CODE (x))
1371 case COMPONENT_REF:
1372 if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x, 1)))
1374 gcc_assert (gcc::jit::active_playback_ctxt);
1375 gcc::jit::
1376 active_playback_ctxt->add_error (loc,
1377 "cannot take address of "
1378 "bit-field");
1379 return false;
1381 /* fallthrough */
1382 case ADDR_EXPR:
1383 case ARRAY_REF:
1384 case REALPART_EXPR:
1385 case IMAGPART_EXPR:
1386 x = TREE_OPERAND (x, 0);
1387 break;
1389 case COMPOUND_LITERAL_EXPR:
1390 case CONSTRUCTOR:
1391 TREE_ADDRESSABLE (x) = 1;
1392 return true;
1394 case VAR_DECL:
1395 case CONST_DECL:
1396 case PARM_DECL:
1397 case RESULT_DECL:
1398 /* (we don't have a concept of a "register" declaration) */
1399 /* fallthrough */
1400 case FUNCTION_DECL:
1401 TREE_ADDRESSABLE (x) = 1;
1402 /* fallthrough */
1403 default:
1404 return true;
1408 /* Construct a playback::rvalue instance (wrapping a tree) for an
1409 address-lookup. */
1411 playback::rvalue *
1412 playback::lvalue::
1413 get_address (location *loc)
1415 tree t_lvalue = as_tree ();
1416 tree t_thistype = TREE_TYPE (t_lvalue);
1417 tree t_ptrtype = build_pointer_type (t_thistype);
1418 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1419 if (loc)
1420 get_context ()->set_tree_location (ptr, loc);
1421 if (mark_addressable (loc))
1422 return new rvalue (get_context (), ptr);
1423 else
1424 return NULL;
1427 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1428 Provide this finalization hook for calling then they are collected,
1429 which calls the finalizer vfunc. This allows them to call "release"
1430 on any vec<> within them. */
1432 static void
1433 wrapper_finalizer (void *ptr)
1435 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1436 wrapper->finalizer ();
1439 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1440 allocate them using ggc_internal_cleared_alloc. */
1442 void *
1443 playback::wrapper::
1444 operator new (size_t sz)
1446 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1450 /* Constructor for gcc:jit::playback::function. */
1452 playback::function::
1453 function (context *ctxt,
1454 tree fndecl,
1455 enum gcc_jit_function_kind kind)
1456 : m_ctxt(ctxt),
1457 m_inner_fndecl (fndecl),
1458 m_inner_bind_expr (NULL),
1459 m_kind (kind)
1461 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1463 /* Create a BIND_EXPR, and within it, a statement list. */
1464 m_stmt_list = alloc_stmt_list ();
1465 m_stmt_iter = tsi_start (m_stmt_list);
1466 m_inner_block = make_node (BLOCK);
1467 m_inner_bind_expr =
1468 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1470 else
1472 m_inner_block = NULL;
1473 m_stmt_list = NULL;
1477 /* Hand-written GC-marking hook for playback functions. */
1479 void
1480 playback::function::
1481 gt_ggc_mx ()
1483 gt_ggc_m_9tree_node (m_inner_fndecl);
1484 gt_ggc_m_9tree_node (m_inner_bind_expr);
1485 gt_ggc_m_9tree_node (m_stmt_list);
1486 gt_ggc_m_9tree_node (m_inner_block);
1489 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1490 GC-ed. */
1492 void
1493 playback::function::finalizer ()
1495 m_blocks.release ();
1498 /* Get the return type of a playback function, in tree form. */
1500 tree
1501 playback::function::
1502 get_return_type_as_tree () const
1504 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1507 /* Construct a new local within this playback::function. */
1509 playback::lvalue *
1510 playback::function::
1511 new_local (location *loc,
1512 type *type,
1513 const char *name)
1515 gcc_assert (type);
1516 gcc_assert (name);
1517 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1518 get_identifier (name),
1519 type->as_tree ());
1520 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1522 /* Prepend to BIND_EXPR_VARS: */
1523 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1524 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1526 if (loc)
1527 set_tree_location (inner, loc);
1528 return new lvalue (m_ctxt, inner);
1531 /* Construct a new block within this playback::function. */
1533 playback::block *
1534 playback::function::
1535 new_block (const char *name)
1537 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1539 block *result = new playback::block (this, name);
1540 m_blocks.safe_push (result);
1541 return result;
1544 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1545 this playback::function. */
1547 playback::rvalue *
1548 playback::function::get_address (location *loc)
1550 tree t_fndecl = as_fndecl ();
1551 tree t_fntype = TREE_TYPE (t_fndecl);
1552 tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
1553 if (loc)
1554 m_ctxt->set_tree_location (t_fnptr, loc);
1555 return new rvalue (m_ctxt, t_fnptr);
1558 /* Build a statement list for the function as a whole out of the
1559 lists of statements for the individual blocks, building labels
1560 for each block. */
1562 void
1563 playback::function::
1564 build_stmt_list ()
1566 int i;
1567 block *b;
1569 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1571 FOR_EACH_VEC_ELT (m_blocks, i, b)
1573 int j;
1574 tree stmt;
1576 b->m_label_expr = build1 (LABEL_EXPR,
1577 void_type_node,
1578 b->as_label_decl ());
1579 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1581 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1582 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1586 /* Finish compiling the given function, potentially running the
1587 garbage-collector.
1588 The function will have a statement list by now.
1589 Amongst other things, this gimplifies the statement list,
1590 and calls cgraph_node::finalize_function on the function. */
1592 void
1593 playback::function::
1594 postprocess ()
1596 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1598 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1599 debug_tree (m_stmt_list);
1601 /* Do we need this to force cgraphunit.c to output the function? */
1602 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1604 DECL_EXTERNAL (m_inner_fndecl) = 0;
1605 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1608 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1609 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1611 DECL_EXTERNAL (m_inner_fndecl) = 0;
1612 TREE_PUBLIC (m_inner_fndecl) = 0;
1615 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1617 /* Seem to need this in gimple-low.c: */
1618 gcc_assert (m_inner_block);
1619 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1621 /* how to add to function? the following appears to be how to
1622 set the body of a m_inner_fndecl: */
1623 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1625 /* Ensure that locals appear in the debuginfo. */
1626 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1628 //debug_tree (m_inner_fndecl);
1630 /* Convert to gimple: */
1631 //printf("about to gimplify_function_tree\n");
1632 gimplify_function_tree (m_inner_fndecl);
1633 //printf("finished gimplify_function_tree\n");
1635 current_function_decl = m_inner_fndecl;
1636 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1637 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1638 //debug_tree (m_inner_fndecl);
1640 //printf("about to add to cgraph\n");
1641 /* Add to cgraph: */
1642 cgraph_node::finalize_function (m_inner_fndecl, false);
1643 /* This can trigger a collection, so we need to have all of
1644 the funcs as roots. */
1646 current_function_decl = NULL;
1650 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1651 GC-ed. */
1653 void
1654 playback::block::finalizer ()
1656 m_stmts.release ();
1659 /* Add an eval of the rvalue to the function's statement list. */
1661 void
1662 playback::block::
1663 add_eval (location *loc,
1664 rvalue *rvalue)
1666 gcc_assert (rvalue);
1668 if (loc)
1669 set_tree_location (rvalue->as_tree (), loc);
1671 add_stmt (rvalue->as_tree ());
1674 /* Add an assignment to the function's statement list. */
1676 void
1677 playback::block::
1678 add_assignment (location *loc,
1679 lvalue *lvalue,
1680 rvalue *rvalue)
1682 gcc_assert (lvalue);
1683 gcc_assert (rvalue);
1685 tree t_lvalue = lvalue->as_tree ();
1686 tree t_rvalue = rvalue->as_tree ();
1687 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1689 t_rvalue = build1 (CONVERT_EXPR,
1690 TREE_TYPE (t_lvalue),
1691 t_rvalue);
1692 if (loc)
1693 set_tree_location (t_rvalue, loc);
1696 tree stmt =
1697 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1698 t_lvalue, t_rvalue);
1699 if (loc)
1700 set_tree_location (stmt, loc);
1701 add_stmt (stmt);
1704 /* Add a comment to the function's statement list.
1705 For now this is done by adding a dummy label. */
1707 void
1708 playback::block::
1709 add_comment (location *loc,
1710 const char *text)
1712 /* Wrap the text in C-style comment delimiters. */
1713 size_t sz =
1714 (3 /* opening delim */
1715 + strlen (text)
1716 + 3 /* closing delim */
1717 + 1 /* terminator */);
1718 char *wrapped = (char *)ggc_internal_alloc (sz);
1719 snprintf (wrapped, sz, "/* %s */", text);
1721 /* For now we simply implement this by adding a dummy label with a name
1722 containing the given text. */
1723 tree identifier = get_identifier (wrapped);
1724 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1725 identifier, void_type_node);
1726 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1728 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1729 if (loc)
1730 set_tree_location (label_expr, loc);
1731 add_stmt (label_expr);
1734 /* Add a conditional jump statement to the function's statement list. */
1736 void
1737 playback::block::
1738 add_conditional (location *loc,
1739 rvalue *boolval,
1740 block *on_true,
1741 block *on_false)
1743 gcc_assert (boolval);
1744 gcc_assert (on_true);
1745 gcc_assert (on_false);
1747 /* COND_EXPR wants statement lists for the true/false operands, but we
1748 want labels.
1749 Shim it by creating jumps to the labels */
1750 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1751 on_true->as_label_decl ());
1752 if (loc)
1753 set_tree_location (true_jump, loc);
1755 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1756 on_false->as_label_decl ());
1757 if (loc)
1758 set_tree_location (false_jump, loc);
1760 tree stmt =
1761 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1762 true_jump, false_jump);
1763 if (loc)
1764 set_tree_location (stmt, loc);
1765 add_stmt (stmt);
1768 /* Add an unconditional jump statement to the function's statement list. */
1770 void
1771 playback::block::
1772 add_jump (location *loc,
1773 block *target)
1775 gcc_assert (target);
1777 // see c_finish_loop
1778 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1779 //add_stmt (top);
1781 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1782 TREE_USED (target->as_label_decl ()) = 1;
1783 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1784 if (loc)
1785 set_tree_location (stmt, loc);
1786 add_stmt (stmt);
1789 from c-typeck.c:
1790 tree
1791 c_finish_goto_label (location_t loc, tree label)
1793 tree decl = lookup_label_for_goto (loc, label);
1794 if (!decl)
1795 return NULL_TREE;
1796 TREE_USED (decl) = 1;
1798 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1799 SET_EXPR_LOCATION (t, loc);
1800 return add_stmt (t);
1807 /* Add a return statement to the function's statement list. */
1809 void
1810 playback::block::
1811 add_return (location *loc,
1812 rvalue *rvalue)
1814 tree modify_retval = NULL;
1815 tree return_type = m_func->get_return_type_as_tree ();
1816 if (rvalue)
1818 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1819 tree t_rvalue = rvalue->as_tree ();
1820 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1821 t_rvalue = build1 (CONVERT_EXPR,
1822 TREE_TYPE (t_lvalue),
1823 t_rvalue);
1824 modify_retval = build2 (MODIFY_EXPR, return_type,
1825 t_lvalue, t_rvalue);
1826 if (loc)
1827 set_tree_location (modify_retval, loc);
1829 tree return_stmt = build1 (RETURN_EXPR, return_type,
1830 modify_retval);
1831 if (loc)
1832 set_tree_location (return_stmt, loc);
1834 add_stmt (return_stmt);
1837 /* Helper function for playback::block::add_switch.
1838 Construct a case label for the given range, followed by a goto stmt
1839 to the given block, appending them to stmt list *ptr_t_switch_body. */
1841 static void
1842 add_case (tree *ptr_t_switch_body,
1843 tree t_low_value,
1844 tree t_high_value,
1845 playback::block *dest_block)
1847 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
1848 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
1850 tree t_case_label =
1851 build_case_label (t_low_value, t_high_value, t_label);
1852 append_to_statement_list (t_case_label, ptr_t_switch_body);
1854 tree t_goto_stmt =
1855 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
1856 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
1859 /* Add a switch statement to the function's statement list.
1861 We create a switch body, and populate it with case labels, each
1862 followed by a goto to the desired block. */
1864 void
1865 playback::block::
1866 add_switch (location *loc,
1867 rvalue *expr,
1868 block *default_block,
1869 const auto_vec <case_> *cases)
1871 /* Compare with:
1872 - c/c-typeck.c: c_start_case
1873 - c-family/c-common.c:c_add_case_label
1874 - java/expr.c:expand_java_switch and expand_java_add_case
1875 We've already rejected overlaps and duplicates in
1876 libgccjit.c:case_range_validator::validate. */
1878 tree t_expr = expr->as_tree ();
1879 tree t_type = TREE_TYPE (t_expr);
1881 tree t_switch_body = alloc_stmt_list ();
1883 int i;
1884 case_ *c;
1885 FOR_EACH_VEC_ELT (*cases, i, c)
1887 tree t_low_value = c->m_min_value->as_tree ();
1888 tree t_high_value = c->m_max_value->as_tree ();
1889 add_case (&t_switch_body, t_low_value, t_high_value, c->m_dest_block);
1891 /* Default label. */
1892 add_case (&t_switch_body, NULL_TREE, NULL_TREE, default_block);
1894 tree switch_stmt = build2 (SWITCH_EXPR, t_type, t_expr, t_switch_body);
1895 if (loc)
1896 set_tree_location (switch_stmt, loc);
1897 add_stmt (switch_stmt);
1900 /* Constructor for gcc::jit::playback::block. */
1902 playback::block::
1903 block (function *func,
1904 const char *name)
1905 : m_func (func),
1906 m_stmts ()
1908 tree identifier;
1910 gcc_assert (func);
1911 // name can be NULL
1912 if (name)
1913 identifier = get_identifier (name);
1914 else
1915 identifier = NULL;
1916 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1917 identifier, void_type_node);
1918 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1919 m_label_expr = NULL;
1922 /* Compile a playback::context:
1924 - Use the context's options to cconstruct command-line options, and
1925 call into the rest of GCC (toplev::main).
1926 - Assuming it succeeds, we have a .s file.
1927 - We then run the "postprocess" vfunc:
1929 (A) In-memory compile ("gcc_jit_context_compile")
1931 For an in-memory compile we have the playback::compile_to_memory
1932 subclass; "postprocess" will convert the .s file to a .so DSO,
1933 and load it in memory (via dlopen), wrapping the result up as
1934 a jit::result and returning it.
1936 (B) Compile to file ("gcc_jit_context_compile_to_file")
1938 When compiling to a file, we have the playback::compile_to_file
1939 subclass; "postprocess" will either copy the .s file to the
1940 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1941 the driver to convert it as necessary, copying the result. */
1943 void
1944 playback::context::
1945 compile ()
1947 JIT_LOG_SCOPE (get_logger ());
1949 const char *ctxt_progname;
1951 int keep_intermediates =
1952 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
1954 m_tempdir = new tempdir (get_logger (), keep_intermediates);
1955 if (!m_tempdir->create ())
1956 return;
1958 /* Call into the rest of gcc.
1959 For now, we have to assemble command-line options to pass into
1960 toplev::main, so that they can be parsed. */
1962 /* Pass in user-provided program name as argv0, if any, so that it
1963 makes it into GCC's "progname" global, used in various diagnostics. */
1964 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1966 if (!ctxt_progname)
1967 ctxt_progname = "libgccjit.so";
1969 auto_vec <recording::requested_dump> requested_dumps;
1970 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1972 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1973 acquire_mutex ();
1975 auto_string_vec fake_args;
1976 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
1977 if (errors_occurred ())
1979 release_mutex ();
1980 return;
1983 /* This runs the compiler. */
1984 toplev toplev (get_timer (), /* external_timer */
1985 false); /* init_signals */
1986 enter_scope ("toplev::main");
1987 if (get_logger ())
1988 for (unsigned i = 0; i < fake_args.length (); i++)
1989 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
1990 toplev.main (fake_args.length (),
1991 const_cast <char **> (fake_args.address ()));
1992 exit_scope ("toplev::main");
1994 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1995 need to do it between toplev::main (which creates the dump manager)
1996 and toplev::finalize (which deletes it). */
1997 extract_any_requested_dumps (&requested_dumps);
1999 /* Clean up the compiler. */
2000 enter_scope ("toplev::finalize");
2001 toplev.finalize ();
2002 exit_scope ("toplev::finalize");
2004 /* Ideally we would release the jit mutex here, but we can't yet since
2005 followup activities use timevars, which are global state. */
2007 if (errors_occurred ())
2009 release_mutex ();
2010 return;
2013 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
2014 dump_generated_code ();
2016 /* We now have a .s file.
2018 Run any postprocessing steps. This will either convert the .s file to
2019 a .so DSO, and load it in memory (playback::compile_to_memory), or
2020 convert the .s file to the requested output format, and copy it to a
2021 given file (playback::compile_to_file). */
2022 postprocess (ctxt_progname);
2024 release_mutex ();
2027 /* Implementation of class gcc::jit::playback::compile_to_memory,
2028 a subclass of gcc::jit::playback::context. */
2030 /* playback::compile_to_memory's trivial constructor. */
2032 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
2033 playback::context (ctxt),
2034 m_result (NULL)
2036 JIT_LOG_SCOPE (get_logger ());
2039 /* Implementation of the playback::context::process vfunc for compiling
2040 to memory.
2042 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
2043 wrapping the result up as a jit::result and returning it. */
2045 void
2046 playback::compile_to_memory::postprocess (const char *ctxt_progname)
2048 JIT_LOG_SCOPE (get_logger ());
2049 convert_to_dso (ctxt_progname);
2050 if (errors_occurred ())
2051 return;
2052 m_result = dlopen_built_dso ();
2055 /* Implementation of class gcc::jit::playback::compile_to_file,
2056 a subclass of gcc::jit::playback::context. */
2058 /* playback::compile_to_file's trivial constructor. */
2060 playback::compile_to_file::compile_to_file (recording::context *ctxt,
2061 enum gcc_jit_output_kind output_kind,
2062 const char *output_path) :
2063 playback::context (ctxt),
2064 m_output_kind (output_kind),
2065 m_output_path (output_path)
2067 JIT_LOG_SCOPE (get_logger ());
2070 /* Implementation of the playback::context::process vfunc for compiling
2071 to a file.
2073 Either copy the .s file to the given destination (for
2074 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
2075 as necessary, copying the result. */
2077 void
2078 playback::compile_to_file::postprocess (const char *ctxt_progname)
2080 JIT_LOG_SCOPE (get_logger ());
2082 /* The driver takes different actions based on the filename, so
2083 we provide a filename with an appropriate suffix for the
2084 output kind, and then copy it up to the user-provided path,
2085 rather than directly compiling it to the requested output path. */
2087 switch (m_output_kind)
2089 default:
2090 gcc_unreachable ();
2092 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
2093 copy_file (get_tempdir ()->get_path_s_file (),
2094 m_output_path);
2095 /* The .s file is automatically unlinked by tempdir::~tempdir. */
2096 break;
2098 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
2100 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
2101 "/fake.o",
2102 NULL);
2103 invoke_driver (ctxt_progname,
2104 get_tempdir ()->get_path_s_file (),
2105 tmp_o_path,
2106 TV_ASSEMBLE,
2107 false, /* bool shared, */
2108 false);/* bool run_linker */
2109 if (!errors_occurred ())
2111 copy_file (tmp_o_path,
2112 m_output_path);
2113 get_tempdir ()->add_temp_file (tmp_o_path);
2115 else
2116 free (tmp_o_path);
2118 break;
2120 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
2121 invoke_driver (ctxt_progname,
2122 get_tempdir ()->get_path_s_file (),
2123 get_tempdir ()->get_path_so_file (),
2124 TV_ASSEMBLE,
2125 true, /* bool shared, */
2126 true);/* bool run_linker */
2127 if (!errors_occurred ())
2128 copy_file (get_tempdir ()->get_path_so_file (),
2129 m_output_path);
2130 /* The .so file is automatically unlinked by tempdir::~tempdir. */
2131 break;
2133 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
2135 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
2136 "/fake.exe",
2137 NULL);
2138 invoke_driver (ctxt_progname,
2139 get_tempdir ()->get_path_s_file (),
2140 tmp_exe_path,
2141 TV_ASSEMBLE,
2142 false, /* bool shared, */
2143 true);/* bool run_linker */
2144 if (!errors_occurred ())
2146 copy_file (tmp_exe_path,
2147 m_output_path);
2148 get_tempdir ()->add_temp_file (tmp_exe_path);
2150 else
2151 free (tmp_exe_path);
2153 break;
2159 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2160 the "executable" bits).
2162 Any errors that occur are reported on the context and hence count as
2163 a failure of the compile.
2165 We can't in general hardlink or use "rename" from the tempdir since
2166 it might be on a different filesystem to the destination. For example,
2167 I get EXDEV: "Invalid cross-device link". */
2169 void
2170 playback::compile_to_file::copy_file (const char *src_path,
2171 const char *dst_path)
2173 JIT_LOG_SCOPE (get_logger ());
2174 if (get_logger ())
2176 get_logger ()->log ("src_path: %s", src_path);
2177 get_logger ()->log ("dst_path: %s", dst_path);
2180 FILE *f_in = NULL;
2181 FILE *f_out = NULL;
2182 size_t total_sz_in = 0;
2183 size_t total_sz_out = 0;
2184 char buf[4096];
2185 size_t sz_in;
2186 struct stat stat_buf;
2188 f_in = fopen (src_path, "rb");
2189 if (!f_in)
2191 add_error (NULL,
2192 "unable to open %s for reading: %s",
2193 src_path,
2194 xstrerror (errno));
2195 return;
2198 /* Use stat on the filedescriptor to get the mode,
2199 so that we can copy it over (in particular, the
2200 "executable" bits). */
2201 if (fstat (fileno (f_in), &stat_buf) == -1)
2203 add_error (NULL,
2204 "unable to fstat %s: %s",
2205 src_path,
2206 xstrerror (errno));
2207 fclose (f_in);
2208 return;
2211 f_out = fopen (dst_path, "wb");
2212 if (!f_out)
2214 add_error (NULL,
2215 "unable to open %s for writing: %s",
2216 dst_path,
2217 xstrerror (errno));
2218 fclose (f_in);
2219 return;
2222 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2224 total_sz_in += sz_in;
2225 size_t sz_out_remaining = sz_in;
2226 size_t sz_out_so_far = 0;
2227 while (sz_out_remaining)
2229 size_t sz_out = fwrite (buf + sz_out_so_far,
2231 sz_out_remaining,
2232 f_out);
2233 gcc_assert (sz_out <= sz_out_remaining);
2234 if (!sz_out)
2236 add_error (NULL,
2237 "error writing to %s: %s",
2238 dst_path,
2239 xstrerror (errno));
2240 fclose (f_in);
2241 fclose (f_out);
2242 return;
2244 total_sz_out += sz_out;
2245 sz_out_so_far += sz_out;
2246 sz_out_remaining -= sz_out;
2248 gcc_assert (sz_out_so_far == sz_in);
2251 if (!feof (f_in))
2252 add_error (NULL,
2253 "error reading from %s: %s",
2254 src_path,
2255 xstrerror (errno));
2257 fclose (f_in);
2259 gcc_assert (total_sz_in == total_sz_out);
2260 if (get_logger ())
2261 get_logger ()->log ("total bytes copied: %zu", total_sz_out);
2263 /* fchmod does not exist in Windows. */
2264 #ifndef _WIN32
2265 /* Set the permissions of the copy to those of the original file,
2266 in particular the "executable" bits. */
2267 if (fchmod (fileno (f_out), stat_buf.st_mode) == -1)
2268 add_error (NULL,
2269 "error setting mode of %s: %s",
2270 dst_path,
2271 xstrerror (errno));
2272 #endif
2274 fclose (f_out);
2277 /* Helper functions for gcc::jit::playback::context::compile. */
2279 /* This mutex guards gcc::jit::recording::context::compile, so that only
2280 one thread can be accessing the bulk of GCC's state at once. */
2282 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2284 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2286 void
2287 playback::context::acquire_mutex ()
2289 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2291 /* Acquire the big GCC mutex. */
2292 JIT_LOG_SCOPE (get_logger ());
2293 pthread_mutex_lock (&jit_mutex);
2294 gcc_assert (active_playback_ctxt == NULL);
2295 active_playback_ctxt = this;
2298 /* Release jit_mutex and clear the active playback ctxt. */
2300 void
2301 playback::context::release_mutex ()
2303 /* Release the big GCC mutex. */
2304 JIT_LOG_SCOPE (get_logger ());
2305 gcc_assert (active_playback_ctxt == this);
2306 active_playback_ctxt = NULL;
2307 pthread_mutex_unlock (&jit_mutex);
2310 /* Callback used by gcc::jit::playback::context::make_fake_args when
2311 invoking driver_get_configure_time_options.
2312 Populate a vec <char * > with the configure-time options. */
2314 static void
2315 append_arg_from_driver (const char *option, void *user_data)
2317 gcc_assert (option);
2318 gcc_assert (user_data);
2319 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2320 argvec->safe_push (concat ("-", option, NULL));
2323 /* Build a fake argv for toplev::main from the options set
2324 by the user on the context . */
2326 void
2327 playback::context::
2328 make_fake_args (vec <char *> *argvec,
2329 const char *ctxt_progname,
2330 vec <recording::requested_dump> *requested_dumps)
2332 JIT_LOG_SCOPE (get_logger ());
2334 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2335 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2337 ADD_ARG (ctxt_progname);
2338 ADD_ARG (get_path_c_file ());
2339 ADD_ARG ("-fPIC");
2341 /* Handle int options: */
2342 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2344 default:
2345 add_error (NULL,
2346 "unrecognized optimization level: %i",
2347 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2348 return;
2350 case 0:
2351 ADD_ARG ("-O0");
2352 break;
2354 case 1:
2355 ADD_ARG ("-O1");
2356 break;
2358 case 2:
2359 ADD_ARG ("-O2");
2360 break;
2362 case 3:
2363 ADD_ARG ("-O3");
2364 break;
2366 /* What about -Os? */
2368 /* Handle bool options: */
2369 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2370 ADD_ARG ("-g");
2372 /* Suppress timing (and other) info. */
2373 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2375 ADD_ARG ("-quiet");
2376 quiet_flag = 1;
2379 /* Aggressively garbage-collect, to shake out bugs: */
2380 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2382 ADD_ARG ("--param=ggc-min-expand=0");
2383 ADD_ARG ("--param=ggc-min-heapsize=0");
2386 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2388 ADD_ARG ("-fdump-tree-all");
2389 ADD_ARG ("-fdump-rtl-all");
2390 ADD_ARG ("-fdump-ipa-all");
2393 /* Add "-fdump-" options for any calls to
2394 gcc_jit_context_enable_dump. */
2396 int i;
2397 recording::requested_dump *d;
2398 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2400 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2401 ADD_ARG_TAKE_OWNERSHIP (arg);
2405 /* PR jit/64810: Add any target-specific default options
2406 from OPTION_DEFAULT_SPECS, normally provided by the driver
2407 in the non-jit case.
2409 The target-specific code can define OPTION_DEFAULT_SPECS:
2410 default command options in the form of spec macros for the
2411 driver to expand ().
2413 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2414 if not overriden, injects the defaults as extra arguments to
2415 cc1 etc.
2416 For the jit case, we need to add these arguments here. The
2417 input format (using the specs language) means that we have to run
2418 part of the driver code here (driver_get_configure_time_options).
2420 To avoid running the spec-expansion code every time, we just do
2421 it the first time (via a function-static flag), saving the result
2422 into a function-static vec.
2423 This flag and vec are global state (i.e. per-process).
2424 They are guarded by the jit mutex. */
2426 static bool have_configure_time_options = false;
2427 static vec <char *> configure_time_options;
2429 if (have_configure_time_options)
2430 log ("reusing cached configure-time options");
2431 else
2433 have_configure_time_options = true;
2434 log ("getting configure-time options from driver");
2435 driver_get_configure_time_options (append_arg_from_driver,
2436 &configure_time_options);
2439 int i;
2440 char *opt;
2442 if (get_logger ())
2443 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2444 log ("configure_time_options[%i]: %s", i, opt);
2446 /* configure_time_options should now contain the expanded options
2447 from OPTION_DEFAULT_SPECS (if any). */
2448 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2450 gcc_assert (opt);
2451 gcc_assert (opt[0] == '-');
2452 ADD_ARG (opt);
2456 if (get_timer ())
2457 ADD_ARG ("-ftime-report");
2459 /* Add any user-provided extra options, starting with any from
2460 parent contexts. */
2461 m_recording_ctxt->append_command_line_options (argvec);
2463 #undef ADD_ARG
2464 #undef ADD_ARG_TAKE_OWNERSHIP
2467 /* The second half of the implementation of gcc_jit_context_enable_dump.
2468 Iterate through the requested dumps, reading the underlying files
2469 into heap-allocated buffers, writing pointers to the buffers into
2470 the char ** pointers provided by client code.
2471 Client code is responsible for calling free on the results. */
2473 void
2474 playback::context::
2475 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2477 JIT_LOG_SCOPE (get_logger ());
2479 int i;
2480 recording::requested_dump *d;
2481 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2483 dump_file_info *dfi;
2484 char *filename;
2485 char *content;
2487 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2488 if (!dfi)
2490 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2491 continue;
2494 filename = g->get_dumps ()->get_dump_file_name (dfi);
2495 content = read_dump_file (filename);
2496 *(d->m_out_ptr) = content;
2497 m_tempdir->add_temp_file (filename);
2501 /* Helper function for playback::context::extract_any_requested_dumps
2502 (itself for use in implementation of gcc_jit_context_enable_dump).
2504 Attempt to read the complete file at the given path, returning the
2505 bytes found there as a buffer.
2506 The caller is responsible for calling free on the result.
2507 Errors will be reported on the context, and lead to NULL being
2508 returned; an out-of-memory error will terminate the process. */
2510 char *
2511 playback::context::read_dump_file (const char *path)
2513 char *result = NULL;
2514 size_t total_sz = 0;
2515 char buf[4096];
2516 size_t sz;
2517 FILE *f_in;
2519 f_in = fopen (path, "r");
2520 if (!f_in)
2522 add_error (NULL, "unable to open %s for reading", path);
2523 return NULL;
2526 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2528 size_t old_total_sz = total_sz;
2529 total_sz += sz;
2530 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2531 memcpy (result + old_total_sz, buf, sz);
2534 if (!feof (f_in))
2536 add_error (NULL, "error reading from %s", path);
2537 free (result);
2538 fclose (f_in);
2539 return NULL;
2542 fclose (f_in);
2544 if (result)
2546 result[total_sz] = '\0';
2547 return result;
2549 else
2550 return xstrdup ("");
2553 /* Part of playback::context::compile ().
2555 We have a .s file; we want a .so file.
2556 We could reuse parts of gcc/gcc.c to do this.
2557 For now, just use the driver binary from the install, as
2558 named in gcc-driver-name.h
2559 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2561 void
2562 playback::context::
2563 convert_to_dso (const char *ctxt_progname)
2565 JIT_LOG_SCOPE (get_logger ());
2567 invoke_driver (ctxt_progname,
2568 m_tempdir->get_path_s_file (),
2569 m_tempdir->get_path_so_file (),
2570 TV_ASSEMBLE,
2571 true, /* bool shared, */
2572 true);/* bool run_linker */
2575 static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2577 void
2578 playback::context::
2579 invoke_driver (const char *ctxt_progname,
2580 const char *input_file,
2581 const char *output_file,
2582 timevar_id_t tv_id,
2583 bool shared,
2584 bool run_linker)
2586 JIT_LOG_SCOPE (get_logger ());
2588 bool embedded_driver
2589 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
2591 /* Currently this lumps together both assembling and linking into
2592 TV_ASSEMBLE. */
2593 auto_timevar assemble_timevar (get_timer (), tv_id);
2594 auto_string_vec argvec;
2595 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2597 ADD_ARG (gcc_driver_name);
2599 add_multilib_driver_arguments (&argvec);
2601 if (shared)
2602 ADD_ARG ("-shared");
2604 if (!run_linker)
2605 ADD_ARG ("-c");
2607 ADD_ARG (input_file);
2608 ADD_ARG ("-o");
2609 ADD_ARG (output_file);
2611 /* Don't use the linker plugin.
2612 If running with just a "make" and not a "make install", then we'd
2613 run into
2614 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2615 libto_plugin is a .la at build time, with it becoming installed with
2616 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2617 time. */
2618 ADD_ARG ("-fno-use-linker-plugin");
2620 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2621 /* OS X's linker defaults to treating undefined symbols as errors.
2622 If the context has any imported functions or globals they will be
2623 undefined until the .so is dynamically-linked into the process.
2624 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2625 linker. */
2626 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2627 #endif
2629 if (0)
2630 ADD_ARG ("-v");
2632 /* Add any user-provided driver extra options. */
2634 m_recording_ctxt->append_driver_options (&argvec);
2636 #undef ADD_ARG
2638 /* pex_one's error-handling requires pname to be non-NULL. */
2639 gcc_assert (ctxt_progname);
2641 if (get_logger ())
2642 for (unsigned i = 0; i < argvec.length (); i++)
2643 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2645 if (embedded_driver)
2646 invoke_embedded_driver (&argvec);
2647 else
2648 invoke_external_driver (ctxt_progname, &argvec);
2651 void
2652 playback::context::
2653 invoke_embedded_driver (const vec <char *> *argvec)
2655 JIT_LOG_SCOPE (get_logger ());
2656 driver d (true, /* can_finalize */
2657 false); /* debug */
2658 int result = d.main (argvec->length (),
2659 const_cast <char **> (argvec->address ()));
2660 d.finalize ();
2661 if (result)
2662 add_error (NULL, "error invoking gcc driver");
2665 void
2666 playback::context::
2667 invoke_external_driver (const char *ctxt_progname,
2668 vec <char *> *argvec)
2670 JIT_LOG_SCOPE (get_logger ());
2671 const char *errmsg;
2672 int exit_status = 0;
2673 int err = 0;
2675 /* pex argv arrays are NULL-terminated. */
2676 argvec->safe_push (NULL);
2678 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2679 gcc_driver_name,
2680 const_cast <char *const *> (argvec->address ()),
2681 ctxt_progname, /* const char *pname */
2682 NULL, /* const char *outname */
2683 NULL, /* const char *errname */
2684 &exit_status, /* int *status */
2685 &err); /* int *err*/
2686 if (errmsg)
2688 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2689 return;
2692 /* pex_one can return a NULL errmsg when the executable wasn't
2693 found (or doesn't exist), so trap these cases also. */
2694 if (exit_status || err)
2696 add_error (NULL,
2697 "error invoking gcc driver: exit_status: %i err: %i",
2698 exit_status, err);
2699 add_error (NULL,
2700 "whilst attempting to run a driver named: %s",
2701 gcc_driver_name);
2702 add_error (NULL,
2703 "PATH was: %s",
2704 getenv ("PATH"));
2705 return;
2709 /* Extract the target-specific MULTILIB_DEFAULTS to
2710 multilib_defaults_raw for use by
2711 playback::context::add_multilib_driver_arguments (). */
2713 #ifndef MULTILIB_DEFAULTS
2714 #define MULTILIB_DEFAULTS { "" }
2715 #endif
2717 static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
2719 /* Helper function for playback::context::invoke_driver ().
2721 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2722 a driver binary. We need to pass in options to the shared driver
2723 to get the appropriate assembler/linker options for this multilib
2724 peer. */
2726 void
2727 playback::context::
2728 add_multilib_driver_arguments (vec <char *> *argvec)
2730 JIT_LOG_SCOPE (get_logger ());
2732 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2733 prepending each with a "-". */
2734 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
2735 if (multilib_defaults_raw[i][0])
2736 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
2739 /* Dynamically-link the built DSO file into this process, using dlopen.
2740 Wrap it up within a jit::result *, and return that.
2741 Return NULL if any errors occur, reporting them on this context. */
2743 result *
2744 playback::context::
2745 dlopen_built_dso ()
2747 JIT_LOG_SCOPE (get_logger ());
2748 auto_timevar load_timevar (get_timer (), TV_LOAD);
2749 result::handle handle = NULL;
2750 result *result_obj = NULL;
2752 #ifdef _WIN32
2753 /* Clear any existing error. */
2754 SetLastError(0);
2756 handle = LoadLibrary(m_tempdir->get_path_so_file ());
2757 if (GetLastError() != 0) {
2758 print_last_error();
2760 #else
2761 const char *error = NULL;
2762 /* Clear any existing error. */
2763 dlerror ();
2765 handle = dlopen (m_tempdir->get_path_so_file (),
2766 RTLD_NOW | RTLD_LOCAL);
2767 if ((error = dlerror()) != NULL) {
2768 add_error (NULL, "%s", error);
2770 #endif
2772 if (handle)
2774 /* We've successfully dlopened the result; create a
2775 jit::result object to wrap it.
2777 We're done with the tempdir for now, but if the user
2778 has requested debugging, the user's debugger might not
2779 be capable of dealing with the .so file being unlinked
2780 immediately, so keep it around until after the result
2781 is released. We do this by handing over ownership of
2782 the jit::tempdir to the result. See PR jit/64206. */
2783 tempdir *handover_tempdir;
2784 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2786 handover_tempdir = m_tempdir;
2787 m_tempdir = NULL;
2788 /* The tempdir will eventually be cleaned up in the
2789 jit::result's dtor. */
2790 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2791 " handing over tempdir to jit::result");
2793 else
2795 handover_tempdir = NULL;
2796 /* ... and retain ownership of m_tempdir so we clean it
2797 up it the playback::context's dtor. */
2798 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2799 " retaining ownership of tempdir");
2802 result_obj = new result (get_logger (), handle, handover_tempdir);
2804 else
2805 result_obj = NULL;
2807 return result_obj;
2810 /* Top-level hook for playing back a recording context.
2812 This plays back m_recording_ctxt, and, if no errors
2813 occurred builds statement lists for and then postprocesses
2814 every function in the result. */
2816 void
2817 playback::context::
2818 replay ()
2820 JIT_LOG_SCOPE (get_logger ());
2822 m_const_char_ptr
2823 = build_pointer_type (build_qualified_type (char_type_node,
2824 TYPE_QUAL_CONST));
2826 /* Replay the recorded events: */
2827 timevar_push (TV_JIT_REPLAY);
2829 m_recording_ctxt->replay_into (this);
2831 /* Clean away the temporary references from recording objects
2832 to playback objects. We have to do this now since the
2833 latter are GC-allocated, but the former don't mark these
2834 refs. Hence we must stop using them before the GC can run. */
2835 m_recording_ctxt->disassociate_from_playback ();
2837 /* The builtins_manager, if any, is associated with the recording::context
2838 and might be reused for future compiles on other playback::contexts,
2839 but its m_attributes array is not GTY-labeled and hence will become
2840 nonsense if the GC runs. Purge this state. */
2841 builtins_manager *bm = get_builtins_manager ();
2842 if (bm)
2843 bm->finish_playback ();
2845 timevar_pop (TV_JIT_REPLAY);
2847 if (!errors_occurred ())
2849 int i;
2850 function *func;
2852 /* No GC can happen yet; process the cached source locations. */
2853 handle_locations ();
2855 /* We've now created tree nodes for the stmts in the various blocks
2856 in each function, but we haven't built each function's single stmt
2857 list yet. Do so now. */
2858 FOR_EACH_VEC_ELT (m_functions, i, func)
2859 func->build_stmt_list ();
2861 /* No GC can have happened yet. */
2863 /* Postprocess the functions. This could trigger GC. */
2864 FOR_EACH_VEC_ELT (m_functions, i, func)
2866 gcc_assert (func);
2867 func->postprocess ();
2872 /* Dump the generated .s file to stderr. */
2874 void
2875 playback::context::
2876 dump_generated_code ()
2878 JIT_LOG_SCOPE (get_logger ());
2879 char buf[4096];
2880 size_t sz;
2881 FILE *f_in = fopen (get_path_s_file (), "r");
2882 if (!f_in)
2883 return;
2885 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2886 fwrite (buf, 1, sz, stderr);
2888 fclose (f_in);
2891 /* Get the supposed path of the notional "fake.c" file within the
2892 tempdir. This file doesn't exist, but the rest of the compiler
2893 needs a name. */
2895 const char *
2896 playback::context::
2897 get_path_c_file () const
2899 return m_tempdir->get_path_c_file ();
2902 /* Get the path of the assembler output file "fake.s" file within the
2903 tempdir. */
2905 const char *
2906 playback::context::
2907 get_path_s_file () const
2909 return m_tempdir->get_path_s_file ();
2912 /* Get the path of the DSO object file "fake.so" file within the
2913 tempdir. */
2915 const char *
2916 playback::context::
2917 get_path_so_file () const
2919 return m_tempdir->get_path_so_file ();
2922 /* qsort comparator for comparing pairs of playback::source_line *,
2923 ordering them by line number. */
2925 static int
2926 line_comparator (const void *lhs, const void *rhs)
2928 const playback::source_line *line_lhs = \
2929 *static_cast<const playback::source_line * const*> (lhs);
2930 const playback::source_line *line_rhs = \
2931 *static_cast<const playback::source_line * const*> (rhs);
2932 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2935 /* qsort comparator for comparing pairs of playback::location *,
2936 ordering them by column number. */
2938 static int
2939 location_comparator (const void *lhs, const void *rhs)
2941 const playback::location *loc_lhs = \
2942 *static_cast<const playback::location * const *> (lhs);
2943 const playback::location *loc_rhs = \
2944 *static_cast<const playback::location * const *> (rhs);
2945 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2948 /* Our API allows locations to be created in arbitrary orders, but the
2949 linemap API requires locations to be created in ascending order
2950 as if we were tokenizing files.
2952 This hook sorts all of the locations that have been created, and
2953 calls into the linemap API, creating linemap entries in sorted order
2954 for our locations. */
2956 void
2957 playback::context::
2958 handle_locations ()
2960 /* Create the source code locations, following the ordering rules
2961 imposed by the linemap API.
2963 line_table is a global. */
2964 JIT_LOG_SCOPE (get_logger ());
2965 int i;
2966 source_file *file;
2968 FOR_EACH_VEC_ELT (m_source_files, i, file)
2970 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2972 /* Sort lines by ascending line numbers. */
2973 file->m_source_lines.qsort (&line_comparator);
2975 int j;
2976 source_line *line;
2977 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2979 int k;
2980 location *loc;
2982 /* Sort locations in line by ascending column numbers. */
2983 line->m_locations.qsort (&location_comparator);
2985 /* Determine maximum column within this line. */
2986 gcc_assert (line->m_locations.length () > 0);
2987 location *final_column =
2988 line->m_locations[line->m_locations.length () - 1];
2989 int max_col = final_column->get_column_num ();
2991 linemap_line_start (line_table, line->get_line_num (), max_col);
2992 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2994 loc->m_srcloc = \
2995 linemap_position_for_column (line_table, loc->get_column_num ());
2999 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
3002 /* line_table should now be populated; every playback::location should
3003 now have an m_srcloc. */
3005 /* Now assign them to tree nodes as appropriate. */
3006 std::pair<tree, location *> *cached_location;
3008 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
3010 tree t = cached_location->first;
3011 location_t srcloc = cached_location->second->m_srcloc;
3013 /* This covers expressions: */
3014 if (CAN_HAVE_LOCATION_P (t))
3015 SET_EXPR_LOCATION (t, srcloc);
3016 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
3017 DECL_SOURCE_LOCATION (t) = srcloc;
3018 else
3020 /* Don't know how to set location on this node. */
3025 /* We handle errors on a playback::context by adding them to the
3026 corresponding recording::context. */
3028 void
3029 playback::context::
3030 add_error (location *loc, const char *fmt, ...)
3032 va_list ap;
3033 va_start (ap, fmt);
3034 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
3035 fmt, ap);
3036 va_end (ap);
3039 /* We handle errors on a playback::context by adding them to the
3040 corresponding recording::context. */
3042 void
3043 playback::context::
3044 add_error_va (location *loc, const char *fmt, va_list ap)
3046 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
3047 fmt, ap);
3050 /* Report a diagnostic up to the jit context as an error,
3051 so that the compilation is treated as a failure.
3052 For now, any kind of diagnostic is treated as an error by the jit
3053 API. */
3055 void
3056 playback::context::
3057 add_diagnostic (struct diagnostic_context *diag_context,
3058 struct diagnostic_info *diagnostic)
3060 /* At this point the text has been formatted into the pretty-printer's
3061 output buffer. */
3062 pretty_printer *pp = diag_context->printer;
3063 const char *text = pp_formatted_text (pp);
3065 /* Get location information (if any) from the diagnostic.
3066 The recording::context::add_error[_va] methods require a
3067 recording::location. We can't lookup the playback::location
3068 from the file/line/column since any playback location instances
3069 may have been garbage-collected away by now, so instead we create
3070 another recording::location directly. */
3071 location_t gcc_loc = diagnostic_location (diagnostic);
3072 recording::location *rec_loc = NULL;
3073 if (gcc_loc)
3075 expanded_location exploc = expand_location (gcc_loc);
3076 if (exploc.file)
3077 rec_loc = m_recording_ctxt->new_location (exploc.file,
3078 exploc.line,
3079 exploc.column,
3080 false);
3083 m_recording_ctxt->add_error (rec_loc, "%s", text);
3084 pp_clear_output_area (pp);
3087 /* Dealing with the linemap API. */
3089 /* Construct a playback::location for a recording::location, if it
3090 doesn't exist already. */
3092 playback::location *
3093 playback::context::
3094 new_location (recording::location *rloc,
3095 const char *filename,
3096 int line,
3097 int column)
3099 /* Get the source_file for filename, creating if necessary. */
3100 source_file *src_file = get_source_file (filename);
3101 /* Likewise for the line within the file. */
3102 source_line *src_line = src_file->get_source_line (line);
3103 /* Likewise for the column within the line. */
3104 location *loc = src_line->get_location (rloc, column);
3105 return loc;
3108 /* Deferred setting of the location for a given tree, by adding the
3109 (tree, playback::location) pair to a list of deferred associations.
3110 We will actually set the location on the tree later on once
3111 the location_t for the playback::location exists. */
3113 void
3114 playback::context::
3115 set_tree_location (tree t, location *loc)
3117 gcc_assert (loc);
3118 m_cached_locations.safe_push (std::make_pair (t, loc));
3122 /* Construct a playback::source_file for the given source
3123 filename, if it doesn't exist already. */
3125 playback::source_file *
3126 playback::context::
3127 get_source_file (const char *filename)
3129 /* Locate the file.
3130 For simplicitly, this is currently a linear search.
3131 Replace with a hash if this shows up in the profile. */
3132 int i;
3133 source_file *file;
3134 tree ident_filename = get_identifier (filename);
3136 FOR_EACH_VEC_ELT (m_source_files, i, file)
3137 if (file->filename_as_tree () == ident_filename)
3138 return file;
3140 /* Not found. */
3141 file = new source_file (ident_filename);
3142 m_source_files.safe_push (file);
3143 return file;
3146 /* Constructor for gcc::jit::playback::source_file. */
3148 playback::source_file::source_file (tree filename) :
3149 m_source_lines (),
3150 m_filename (filename)
3154 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3155 GC-ed. */
3157 void
3158 playback::source_file::finalizer ()
3160 m_source_lines.release ();
3163 /* Construct a playback::source_line for the given line
3164 within this source file, if one doesn't exist already. */
3166 playback::source_line *
3167 playback::source_file::
3168 get_source_line (int line_num)
3170 /* Locate the line.
3171 For simplicitly, this is currently a linear search.
3172 Replace with a hash if this shows up in the profile. */
3173 int i;
3174 source_line *line;
3176 FOR_EACH_VEC_ELT (m_source_lines, i, line)
3177 if (line->get_line_num () == line_num)
3178 return line;
3180 /* Not found. */
3181 line = new source_line (this, line_num);
3182 m_source_lines.safe_push (line);
3183 return line;
3186 /* Constructor for gcc::jit::playback::source_line. */
3188 playback::source_line::source_line (source_file *file, int line_num) :
3189 m_locations (),
3190 m_source_file (file),
3191 m_line_num (line_num)
3195 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3196 GC-ed. */
3198 void
3199 playback::source_line::finalizer ()
3201 m_locations.release ();
3204 /* Construct a playback::location for the given column
3205 within this line of a specific source file, if one doesn't exist
3206 already. */
3208 playback::location *
3209 playback::source_line::
3210 get_location (recording::location *rloc, int column_num)
3212 int i;
3213 location *loc;
3215 /* Another linear search that probably should be a hash table. */
3216 FOR_EACH_VEC_ELT (m_locations, i, loc)
3217 if (loc->get_column_num () == column_num)
3218 return loc;
3220 /* Not found. */
3221 loc = new location (rloc, this, column_num);
3222 m_locations.safe_push (loc);
3223 return loc;
3226 /* Constructor for gcc::jit::playback::location. */
3228 playback::location::location (recording::location *loc,
3229 source_line *line,
3230 int column_num) :
3231 m_srcloc (UNKNOWN_LOCATION),
3232 m_recording_loc (loc),
3233 m_line (line),
3234 m_column_num(column_num)
3238 /* The active gcc::jit::playback::context instance. This is a singleton,
3239 guarded by jit_mutex. */
3241 playback::context *active_playback_ctxt;
3243 } // namespace gcc::jit
3245 } // namespace gcc