1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2023 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)
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/>. */
24 #include "coretypes.h"
27 #include "stringpool.h"
33 #include "stor-layout.h"
34 #include "print-tree.h"
36 #include "gcc-driver-name.h"
39 #include "fold-const.h"
40 #include "opt-suggestions.h"
42 #include "diagnostic.h"
45 #include "jit-playback.h"
46 #include "jit-result.h"
47 #include "jit-builtins.h"
48 #include "jit-tempdir.h"
54 /* Compare with gcc/c-family/c-common.h: 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 for casts that can be simplified
65 (truncation, extension). */
66 extern tree
convert (tree type
, tree expr
);
69 convert (tree dst_type
, tree expr
)
72 t_ret
= targetm
.convert_to_type (dst_type
, expr
);
75 switch (TREE_CODE (dst_type
))
79 return fold (convert_to_integer (dst_type
, expr
));
82 gcc_assert (gcc::jit::active_playback_ctxt
);
83 gcc::jit::active_playback_ctxt
->add_error (NULL
, "unhandled conversion");
84 fprintf (stderr
, "input expression:\n");
86 fprintf (stderr
, "requested type:\n");
87 debug_tree (dst_type
);
88 return error_mark_node
;
95 /**********************************************************************
97 **********************************************************************/
99 /* Fold a readonly non-volatile variable with an initial constant value,
102 Otherwise return the argument unchanged.
104 This fold is needed for setting a variable's DECL_INITIAL to the value
105 of a const variable. The c-frontend does this in its own special
106 fold (), so we lift this part out and do it explicitly where there is a
107 potential for variables to be used as rvalues. */
109 fold_const_var (tree node
)
111 /* See c_fully_fold_internal in c-fold.cc and decl_constant_value_1
114 && TREE_READONLY (node
)
115 && !TREE_THIS_VOLATILE (node
)
116 && DECL_INITIAL (node
) != NULL_TREE
117 /* "This is invalid if initial value is not constant.
118 If it has either a function call, a memory reference,
119 or a variable, then re-evaluating it could give different
121 && TREE_CONSTANT (DECL_INITIAL (node
)))
123 tree ret
= DECL_INITIAL (node
);
124 /* "Avoid unwanted tree sharing between the initializer and current
125 function's body where the tree can be modified e.g. by the
127 if (TREE_STATIC (node
))
128 ret
= unshare_expr (ret
);
136 /* Build a STRING_CST tree for STR, or return NULL if it is NULL.
137 The TREE_TYPE is not initialized. */
140 build_string (const char *str
)
143 return ::build_string (strlen (str
), str
);
148 /* The constructor for gcc::jit::playback::context. */
150 playback::context::context (recording::context
*ctxt
)
151 : log_user (ctxt
->get_logger ()),
152 m_recording_ctxt (ctxt
),
154 m_const_char_ptr (NULL
)
156 JIT_LOG_SCOPE (get_logger ());
157 m_functions
.create (0);
158 m_globals
.create (0);
159 m_source_files
.create (0);
160 m_cached_locations
.create (0);
163 /* The destructor for gcc::jit::playback::context. */
165 playback::context::~context ()
167 JIT_LOG_SCOPE (get_logger ());
169 /* Normally the playback::context is responsible for cleaning up the
170 tempdir (including "fake.so" within the filesystem).
172 In the normal case, clean it up now.
174 However m_tempdir can be NULL if the context has handed over
175 responsibility for the tempdir cleanup to the jit::result object, so
176 that the cleanup can be delayed (see PR jit/64206). If that's the
177 case this "delete NULL;" is a no-op. */
180 m_functions
.release ();
183 /* A playback::context can reference GC-managed pointers. Mark them
184 ("by hand", rather than by gengtype).
186 This is called on the active playback context (if any) by the
187 my_ggc_walker hook in the jit_root_table in dummy-frontend.cc. */
195 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
197 if (ggc_test_and_set_mark (func
))
202 /* Given an enum gcc_jit_types value, get a "tree" type. */
206 get_tree_node_for_type (enum gcc_jit_types type_
)
210 case GCC_JIT_TYPE_VOID
:
211 return void_type_node
;
213 case GCC_JIT_TYPE_VOID_PTR
:
214 return ptr_type_node
;
216 case GCC_JIT_TYPE_BOOL
:
217 return boolean_type_node
;
219 case GCC_JIT_TYPE_CHAR
:
220 return char_type_node
;
221 case GCC_JIT_TYPE_SIGNED_CHAR
:
222 return signed_char_type_node
;
223 case GCC_JIT_TYPE_UNSIGNED_CHAR
:
224 return unsigned_char_type_node
;
226 case GCC_JIT_TYPE_SHORT
:
227 return short_integer_type_node
;
228 case GCC_JIT_TYPE_UNSIGNED_SHORT
:
229 return short_unsigned_type_node
;
231 case GCC_JIT_TYPE_CONST_CHAR_PTR
:
232 return m_const_char_ptr
;
234 case GCC_JIT_TYPE_INT
:
235 return integer_type_node
;
236 case GCC_JIT_TYPE_UNSIGNED_INT
:
237 return unsigned_type_node
;
239 case GCC_JIT_TYPE_UINT8_T
:
240 return unsigned_intQI_type_node
;
241 case GCC_JIT_TYPE_UINT16_T
:
242 return uint16_type_node
;
243 case GCC_JIT_TYPE_UINT32_T
:
244 return uint32_type_node
;
245 case GCC_JIT_TYPE_UINT64_T
:
246 return uint64_type_node
;
247 case GCC_JIT_TYPE_UINT128_T
:
248 if (targetm
.scalar_mode_supported_p (TImode
))
249 return uint128_type_node
;
251 add_error (NULL
, "gcc_jit_types value unsupported on this target: %i",
255 case GCC_JIT_TYPE_INT8_T
:
256 return intQI_type_node
;
257 case GCC_JIT_TYPE_INT16_T
:
258 return intHI_type_node
;
259 case GCC_JIT_TYPE_INT32_T
:
260 return intSI_type_node
;
261 case GCC_JIT_TYPE_INT64_T
:
262 return intDI_type_node
;
263 case GCC_JIT_TYPE_INT128_T
:
264 if (targetm
.scalar_mode_supported_p (TImode
))
265 return intTI_type_node
;
267 add_error (NULL
, "gcc_jit_types value unsupported on this target: %i",
271 case GCC_JIT_TYPE_LONG
:
272 return long_integer_type_node
;
273 case GCC_JIT_TYPE_UNSIGNED_LONG
:
274 return long_unsigned_type_node
;
276 case GCC_JIT_TYPE_LONG_LONG
:
277 return long_long_integer_type_node
;
278 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG
:
279 return long_long_unsigned_type_node
;
281 case GCC_JIT_TYPE_FLOAT
:
282 return float_type_node
;
283 case GCC_JIT_TYPE_DOUBLE
:
284 return double_type_node
;
285 case GCC_JIT_TYPE_LONG_DOUBLE
:
286 return long_double_type_node
;
288 case GCC_JIT_TYPE_SIZE_T
:
289 return size_type_node
;
291 case GCC_JIT_TYPE_FILE_PTR
:
292 return fileptr_type_node
;
294 case GCC_JIT_TYPE_COMPLEX_FLOAT
:
295 return complex_float_type_node
;
296 case GCC_JIT_TYPE_COMPLEX_DOUBLE
:
297 return complex_double_type_node
;
298 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE
:
299 return complex_long_double_type_node
;
302 add_error (NULL
, "unrecognized (enum gcc_jit_types) value: %i",
308 /* Construct a playback::type instance (wrapping a tree) for the given
313 get_type (enum gcc_jit_types type_
)
315 tree type_node
= get_tree_node_for_type (type_
);
316 if (type_node
== NULL
)
319 return new type (type_node
);
322 /* Construct a playback::type instance (wrapping a tree) for the given
327 new_array_type (playback::location
*loc
,
328 playback::type
*element_type
,
331 gcc_assert (element_type
);
333 tree t
= build_array_type_nelts (element_type
->as_tree (),
338 set_tree_location (t
, loc
);
343 /* Construct a playback::field instance (wrapping a tree). */
347 new_field (location
*loc
,
354 /* compare with c/c-decl.cc:grokfield and grokdeclarator. */
355 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
356 get_identifier (name
), type
->as_tree ());
359 set_tree_location (decl
, loc
);
361 return new field (decl
);
364 /* Construct a playback::bitfield instance (wrapping a tree). */
368 new_bitfield (location
*loc
,
377 /* compare with c/c-decl.cc:grokfield, grokdeclarator and
378 check_bitfield_type_and_width. */
380 tree tree_type
= type
->as_tree ();
381 gcc_assert (INTEGRAL_TYPE_P (tree_type
));
382 tree tree_width
= build_int_cst (integer_type_node
, width
);
383 if (compare_tree_int (tree_width
, TYPE_PRECISION (tree_type
)) > 0)
387 "width of bit-field %s (width: %i) is wider than its type (width: %i)",
388 name
, width
, TYPE_PRECISION (tree_type
));
392 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
393 get_identifier (name
), type
->as_tree ());
394 DECL_NONADDRESSABLE_P (decl
) = true;
395 DECL_INITIAL (decl
) = tree_width
;
396 SET_DECL_JIT_BIT_FIELD (decl
);
399 set_tree_location (decl
, loc
);
401 return new field (decl
);
404 /* Construct a playback::compound_type instance (wrapping a tree). */
406 playback::compound_type
*
408 new_compound_type (location
*loc
,
410 bool is_struct
) /* else is union */
414 /* Compare with c/c-decl.cc: start_struct. */
416 tree t
= make_node (is_struct
? RECORD_TYPE
: UNION_TYPE
);
417 TYPE_NAME (t
) = get_identifier (name
);
421 set_tree_location (t
, loc
);
423 return new compound_type (t
);
427 playback::compound_type::set_fields (const auto_vec
<playback::field
*> *fields
)
429 /* Compare with c/c-decl.cc: finish_struct. */
432 tree fieldlist
= NULL
;
433 for (unsigned i
= 0; i
< fields
->length (); i
++)
435 field
*f
= (*fields
)[i
];
436 tree x
= f
->as_tree ();
437 DECL_CONTEXT (x
) = t
;
438 if (DECL_JIT_BIT_FIELD (x
))
440 unsigned HOST_WIDE_INT width
= tree_to_uhwi (DECL_INITIAL (x
));
441 DECL_SIZE (x
) = bitsize_int (width
);
442 DECL_BIT_FIELD (x
) = 1;
444 fieldlist
= chainon (x
, fieldlist
);
446 fieldlist
= nreverse (fieldlist
);
447 TYPE_FIELDS (t
) = fieldlist
;
452 /* Construct a playback::type instance (wrapping a tree) for a function
457 new_function_type (type
*return_type
,
458 const auto_vec
<type
*> *param_types
,
464 tree
*arg_types
= (tree
*)xcalloc(param_types
->length (), sizeof(tree
*));
466 FOR_EACH_VEC_ELT (*param_types
, i
, param_type
)
467 arg_types
[i
] = param_type
->as_tree ();
472 build_varargs_function_type_array (return_type
->as_tree (),
473 param_types
->length (),
476 fn_type
= build_function_type_array (return_type
->as_tree (),
477 param_types
->length (),
481 return new type (fn_type
);
484 /* Construct a playback::param instance (wrapping a tree). */
488 new_param (location
*loc
,
494 tree inner
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
495 get_identifier (name
), type
->as_tree ());
497 set_tree_location (inner
, loc
);
499 return new param (this, inner
);
502 /* Construct a playback::function instance. */
506 new_function (location
*loc
,
507 enum gcc_jit_function_kind kind
,
510 const auto_vec
<param
*> *params
,
512 enum built_in_function builtin_id
)
517 //can return_type be NULL?
520 tree
*arg_types
= (tree
*)xcalloc(params
->length (), sizeof(tree
*));
521 FOR_EACH_VEC_ELT (*params
, i
, param
)
522 arg_types
[i
] = TREE_TYPE (param
->as_tree ());
526 fn_type
= build_varargs_function_type_array (return_type
->as_tree (),
527 params
->length (), arg_types
);
529 fn_type
= build_function_type_array (return_type
->as_tree (),
530 params
->length (), arg_types
);
533 /* FIXME: this uses input_location: */
534 tree fndecl
= build_fn_decl (name
, fn_type
);
537 set_tree_location (fndecl
, loc
);
539 tree resdecl
= build_decl (UNKNOWN_LOCATION
, RESULT_DECL
,
540 NULL_TREE
, return_type
->as_tree ());
541 DECL_ARTIFICIAL (resdecl
) = 1;
542 DECL_IGNORED_P (resdecl
) = 1;
543 DECL_RESULT (fndecl
) = resdecl
;
544 DECL_CONTEXT (resdecl
) = fndecl
;
548 gcc_assert (loc
== NULL
);
549 DECL_SOURCE_LOCATION (fndecl
) = BUILTINS_LOCATION
;
551 built_in_class fclass
= builtins_manager::get_class (builtin_id
);
552 set_decl_built_in_function (fndecl
, fclass
, builtin_id
);
553 set_builtin_decl (builtin_id
, fndecl
,
554 builtins_manager::implicit_p (builtin_id
));
556 builtins_manager
*bm
= get_builtins_manager ();
557 tree attrs
= bm
->get_attrs_tree (builtin_id
);
559 decl_attributes (&fndecl
, attrs
, ATTR_FLAG_BUILT_IN
);
561 decl_attributes (&fndecl
, NULL_TREE
, 0);
564 if (kind
!= GCC_JIT_FUNCTION_IMPORTED
)
566 tree param_decl_list
= NULL
;
567 FOR_EACH_VEC_ELT (*params
, i
, param
)
569 param_decl_list
= chainon (param
->as_tree (), param_decl_list
);
572 /* The param list was created in reverse order; fix it: */
573 param_decl_list
= nreverse (param_decl_list
);
576 for (t
= param_decl_list
; t
; t
= DECL_CHAIN (t
))
578 DECL_CONTEXT (t
) = fndecl
;
579 DECL_ARG_TYPE (t
) = TREE_TYPE (t
);
582 /* Set it up on DECL_ARGUMENTS */
583 DECL_ARGUMENTS(fndecl
) = param_decl_list
;
586 if (kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
588 DECL_DECLARED_INLINE_P (fndecl
) = 1;
590 /* Add attribute "always_inline": */
591 DECL_ATTRIBUTES (fndecl
) =
592 tree_cons (get_identifier ("always_inline"),
594 DECL_ATTRIBUTES (fndecl
));
597 function
*func
= new function (this, fndecl
, kind
);
598 m_functions
.safe_push (func
);
602 /* In use by new_global and new_global_initialized. */
606 global_new_decl (location
*loc
,
607 enum gcc_jit_global_kind kind
,
610 enum global_var_flags flags
)
615 tree type_tree
= type
->as_tree ();
617 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
618 get_identifier (name
),
621 TREE_PUBLIC (inner
) = (kind
!= GCC_JIT_GLOBAL_INTERNAL
);
624 int will_be_init
= flags
& (GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT
|
625 GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT
);
627 /* A VAR_DECL with DECL_INITIAL will not end up in .common section. */
629 DECL_COMMON (inner
) = 1;
636 case GCC_JIT_GLOBAL_EXPORTED
:
637 TREE_STATIC (inner
) = 1;
640 case GCC_JIT_GLOBAL_INTERNAL
:
641 TREE_STATIC (inner
) = 1;
644 case GCC_JIT_GLOBAL_IMPORTED
:
645 DECL_EXTERNAL (inner
) = 1;
649 if (TYPE_READONLY (type_tree
))
650 TREE_READONLY (inner
) = 1;
653 set_tree_location (inner
, loc
);
658 /* In use by new_global and new_global_initialized. */
662 global_finalize_lvalue (tree inner
)
664 m_globals
.safe_push (inner
);
666 return new lvalue (this, inner
);
669 /* Construct a playback::lvalue instance (wrapping a tree). */
673 new_global (location
*loc
,
674 enum gcc_jit_global_kind kind
,
677 enum global_var_flags flags
)
680 global_new_decl (loc
, kind
, type
, name
, flags
);
682 return global_finalize_lvalue (inner
);
687 global_set_init_rvalue (lvalue
* variable
,
690 tree inner
= variable
->as_tree ();
692 /* We need to fold all expressions as much as possible. The code
693 for a DECL_INITIAL only handles some operations,
694 etc addition, minus, 'address of'. See output_addressed_constants ()
696 tree init_tree
= init
->as_tree ();
697 tree folded
= fold_const_var (init_tree
);
699 if (!TREE_CONSTANT (folded
))
701 tree name
= DECL_NAME (inner
);
703 if (name
!= NULL_TREE
)
705 "unable to convert initial value for the global variable %s"
706 " to a compile-time constant",
707 IDENTIFIER_POINTER (name
));
710 "unable to convert initial value for global variable"
711 " to a compile-time constant");
715 DECL_INITIAL (inner
) = folded
;
720 new_ctor (location
*loc
,
722 const auto_vec
<field
*> *fields
,
723 const auto_vec
<rvalue
*> *rvalues
)
725 tree type_tree
= type
->as_tree ();
727 /* Handle empty ctors first. I.e. set everything to 0. */
728 if (rvalues
->length () == 0)
729 return new rvalue (this, build_constructor (type_tree
, NULL
));
731 /* Handle arrays (and return). */
732 if (TREE_CODE (type_tree
) == ARRAY_TYPE
)
734 int n
= rvalues
->length ();
735 /* The vec for the constructor node. */
736 vec
<constructor_elt
, va_gc
> *v
= NULL
;
739 for (int i
= 0; i
< n
; i
++)
741 rvalue
*rv
= (*rvalues
)[i
];
742 /* null rvalues indicate that the element should be zeroed. */
744 CONSTRUCTOR_APPEND_ELT (v
,
745 build_int_cst (size_type_node
, i
),
748 CONSTRUCTOR_APPEND_ELT (v
,
749 build_int_cst (size_type_node
, i
),
750 build_zero_cst (TREE_TYPE (type_tree
)));
753 tree ctor
= build_constructor (type_tree
, v
);
756 set_tree_location (ctor
, loc
);
758 return new rvalue (this, ctor
);
761 /* Handle structs and unions. */
762 int n
= fields
->length ();
764 /* The vec for the constructor node. */
765 vec
<constructor_elt
, va_gc
> *v
= NULL
;
768 /* Iterate over the fields, building initializations. */
769 for (int i
= 0;i
< n
; i
++)
771 tree field
= (*fields
)[i
]->as_tree ();
772 rvalue
*rv
= (*rvalues
)[i
];
773 /* If the value is NULL, it means we should zero the field. */
775 CONSTRUCTOR_APPEND_ELT (v
, field
, rv
->as_tree ());
778 tree zero_cst
= build_zero_cst (TREE_TYPE (field
));
779 CONSTRUCTOR_APPEND_ELT (v
, field
, zero_cst
);
783 tree ctor
= build_constructor (type_tree
, v
);
786 set_tree_location (ctor
, loc
);
788 return new rvalue (this, build_constructor (type_tree
, v
));
791 /* Fill 'constructor_elements' with the memory content of
792 'initializer'. Each element of the initializer is of the size of
793 type T. In use by new_global_initialized.*/
797 load_blob_in_ctor (vec
<constructor_elt
, va_gc
> *&constructor_elements
,
799 const void *initializer
)
801 /* Loosely based on 'output_init_element' c-typeck.cc:9691. */
802 const T
*p
= (const T
*)initializer
;
803 tree node
= make_unsigned_type (BITS_PER_UNIT
* sizeof (T
));
804 for (size_t i
= 0; i
< num_elem
; i
++)
806 constructor_elt celt
=
807 { build_int_cst (long_unsigned_type_node
, i
),
808 build_int_cst (node
, p
[i
]) };
809 vec_safe_push (constructor_elements
, celt
);
813 /* Construct an initialized playback::lvalue instance (wrapping a
818 new_global_initialized (location
*loc
,
819 enum gcc_jit_global_kind kind
,
822 size_t initializer_num_elem
,
823 const void *initializer
,
825 enum global_var_flags flags
)
827 tree inner
= global_new_decl (loc
, kind
, type
, name
, flags
);
829 vec
<constructor_elt
, va_gc
> *constructor_elements
= NULL
;
831 switch (element_size
)
834 load_blob_in_ctor
<uint8_t> (constructor_elements
, initializer_num_elem
,
838 load_blob_in_ctor
<uint16_t> (constructor_elements
, initializer_num_elem
,
842 load_blob_in_ctor
<uint32_t> (constructor_elements
, initializer_num_elem
,
846 load_blob_in_ctor
<uint64_t> (constructor_elements
, initializer_num_elem
,
850 /* This function is serving on sizes returned by 'get_size',
851 these are all covered by the previous cases. */
854 /* Compare with 'pop_init_level' c-typeck.cc:8780. */
855 tree ctor
= build_constructor (type
->as_tree (), constructor_elements
);
856 constructor_elements
= NULL
;
858 /* Compare with 'store_init_value' c-typeck.cc:7555. */
859 DECL_INITIAL (inner
) = ctor
;
861 return global_finalize_lvalue (inner
);
864 /* Implementation of the various
865 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
867 Each of these constructs a playback::rvalue instance (wrapping a tree).
869 These specializations are required to be in the same namespace
870 as the template, hence we now have to enter the gcc::jit::playback
876 /* Specialization of making an rvalue from a const, for host <int>. */
881 new_rvalue_from_const
<int> (type
*type
,
884 // FIXME: type-checking, or coercion?
885 tree inner_type
= type
->as_tree ();
886 if (INTEGRAL_TYPE_P (inner_type
))
888 tree inner
= build_int_cst (inner_type
, value
);
889 return new rvalue (this, inner
);
893 REAL_VALUE_TYPE real_value
;
894 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
895 tree inner
= build_real (inner_type
, real_value
);
896 return new rvalue (this, inner
);
900 /* Specialization of making an rvalue from a const, for host <long>. */
905 new_rvalue_from_const
<long> (type
*type
,
908 // FIXME: type-checking, or coercion?
909 tree inner_type
= type
->as_tree ();
910 if (INTEGRAL_TYPE_P (inner_type
))
912 tree inner
= build_int_cst (inner_type
, value
);
913 return new rvalue (this, inner
);
917 REAL_VALUE_TYPE real_value
;
918 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
919 tree inner
= build_real (inner_type
, real_value
);
920 return new rvalue (this, inner
);
924 /* Specialization of making an rvalue from a const, for host <double>. */
929 new_rvalue_from_const
<double> (type
*type
,
932 // FIXME: type-checking, or coercion?
933 tree inner_type
= type
->as_tree ();
935 /* We have a "double", we want a REAL_VALUE_TYPE.
937 real.cc:real_from_target appears to require the representation to be
938 split into 32-bit values, and then sent as an pair of host long
940 REAL_VALUE_TYPE real_value
;
944 uint32_t as_uint32s
[2];
947 long int as_long_ints
[2];
948 as_long_ints
[0] = u
.as_uint32s
[0];
949 as_long_ints
[1] = u
.as_uint32s
[1];
950 real_from_target (&real_value
, as_long_ints
, DFmode
);
951 tree inner
= build_real (inner_type
, real_value
);
952 return new rvalue (this, inner
);
955 /* Specialization of making an rvalue from a const, for host <void *>. */
960 new_rvalue_from_const
<void *> (type
*type
,
963 tree inner_type
= type
->as_tree ();
964 /* FIXME: how to ensure we have a wide enough type? */
965 tree inner
= build_int_cstu (inner_type
, (unsigned HOST_WIDE_INT
)value
);
966 return new rvalue (this, inner
);
969 /* We're done implementing the specializations of
970 gcc::jit::playback::context::new_rvalue_from_const <T>
971 so we can exit the gcc::jit::playback namespace. */
973 } // namespace playback
975 /* Construct a playback::rvalue instance (wrapping a tree). */
979 new_string_literal (const char *value
)
981 /* Compare with c-family/c-common.cc: fix_string_type. */
982 size_t len
= strlen (value
);
983 tree i_type
= build_index_type (size_int (len
));
984 tree a_type
= build_array_type (char_type_node
, i_type
);
985 /* build_string len parameter must include NUL terminator when
986 building C strings. */
987 tree t_str
= ::build_string (len
+ 1, value
);
988 TREE_TYPE (t_str
) = a_type
;
990 /* Convert to (const char*), loosely based on
991 c/c-typeck.cc: array_to_pointer_conversion,
992 by taking address of start of string. */
993 tree t_addr
= build1 (ADDR_EXPR
, m_const_char_ptr
, t_str
);
995 return new rvalue (this, t_addr
);
998 /* Construct a playback::rvalue instance (wrapping a tree) for a
1002 playback::context::new_rvalue_from_vector (location
*,
1004 const auto_vec
<rvalue
*> &elements
)
1006 vec
<constructor_elt
, va_gc
> *v
;
1007 vec_alloc (v
, elements
.length ());
1008 for (unsigned i
= 0; i
< elements
.length (); ++i
)
1009 CONSTRUCTOR_APPEND_ELT (v
, NULL_TREE
, elements
[i
]->as_tree ());
1010 tree t_ctor
= build_constructor (type
->as_tree (), v
);
1011 return new rvalue (this, t_ctor
);
1014 /* Coerce a tree expression into a boolean tree expression. */
1018 as_truth_value (tree expr
, location
*loc
)
1020 /* Compare to c-typeck.cc:c_objc_common_truthvalue_conversion */
1021 tree typed_zero
= fold_build1 (CONVERT_EXPR
,
1025 set_tree_location (typed_zero
, loc
);
1027 tree type
= TREE_TYPE (expr
);
1028 expr
= fold_build2_loc (UNKNOWN_LOCATION
,
1029 NE_EXPR
, type
, expr
, typed_zero
);
1031 set_tree_location (expr
, loc
);
1036 /* Add a "top-level" basic asm statement (i.e. one outside of any functions)
1037 containing ASM_STMTS.
1039 Compare with c_parser_asm_definition. */
1042 playback::context::add_top_level_asm (const char *asm_stmts
)
1044 tree asm_str
= build_string (asm_stmts
);
1045 symtab
->finalize_toplevel_asm (asm_str
);
1048 /* Construct a playback::rvalue instance (wrapping a tree) for a
1053 new_unary_op (location
*loc
,
1054 enum gcc_jit_unary_op op
,
1058 // FIXME: type-checking, or coercion?
1059 enum tree_code inner_op
;
1061 gcc_assert (result_type
);
1064 tree node
= a
->as_tree ();
1065 node
= fold_const_var (node
);
1067 tree inner_result
= NULL
;
1072 add_error (loc
, "unrecognized (enum gcc_jit_unary_op) value: %i", op
);
1075 case GCC_JIT_UNARY_OP_MINUS
:
1076 inner_op
= NEGATE_EXPR
;
1079 case GCC_JIT_UNARY_OP_BITWISE_NEGATE
:
1080 inner_op
= BIT_NOT_EXPR
;
1083 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE
:
1084 node
= as_truth_value (node
, loc
);
1085 inner_result
= invert_truthvalue (node
);
1087 set_tree_location (inner_result
, loc
);
1088 return new rvalue (this, inner_result
);
1090 case GCC_JIT_UNARY_OP_ABS
:
1091 inner_op
= ABS_EXPR
;
1095 inner_result
= build1 (inner_op
,
1096 result_type
->as_tree (),
1100 inner_result
= fold (inner_result
);
1103 set_tree_location (inner_result
, loc
);
1105 return new rvalue (this, inner_result
);
1108 /* Construct a playback::rvalue instance (wrapping a tree) for a
1113 new_binary_op (location
*loc
,
1114 enum gcc_jit_binary_op op
,
1116 rvalue
*a
, rvalue
*b
)
1118 // FIXME: type-checking, or coercion?
1119 enum tree_code inner_op
;
1121 gcc_assert (result_type
);
1125 tree node_a
= a
->as_tree ();
1126 node_a
= fold_const_var (node_a
);
1128 tree node_b
= b
->as_tree ();
1129 node_b
= fold_const_var (node_b
);
1134 add_error (loc
, "unrecognized (enum gcc_jit_binary_op) value: %i", op
);
1137 case GCC_JIT_BINARY_OP_PLUS
:
1138 inner_op
= PLUS_EXPR
;
1141 case GCC_JIT_BINARY_OP_MINUS
:
1142 inner_op
= MINUS_EXPR
;
1145 case GCC_JIT_BINARY_OP_MULT
:
1146 inner_op
= MULT_EXPR
;
1149 case GCC_JIT_BINARY_OP_DIVIDE
:
1150 if (FLOAT_TYPE_P (result_type
->as_tree ()))
1151 /* Floating-point division: */
1152 inner_op
= RDIV_EXPR
;
1154 /* Truncating to zero: */
1155 inner_op
= TRUNC_DIV_EXPR
;
1158 case GCC_JIT_BINARY_OP_MODULO
:
1159 inner_op
= TRUNC_MOD_EXPR
;
1162 case GCC_JIT_BINARY_OP_BITWISE_AND
:
1163 inner_op
= BIT_AND_EXPR
;
1166 case GCC_JIT_BINARY_OP_BITWISE_XOR
:
1167 inner_op
= BIT_XOR_EXPR
;
1170 case GCC_JIT_BINARY_OP_BITWISE_OR
:
1171 inner_op
= BIT_IOR_EXPR
;
1174 case GCC_JIT_BINARY_OP_LOGICAL_AND
:
1175 node_a
= as_truth_value (node_a
, loc
);
1176 node_b
= as_truth_value (node_b
, loc
);
1177 inner_op
= TRUTH_ANDIF_EXPR
;
1180 case GCC_JIT_BINARY_OP_LOGICAL_OR
:
1181 node_a
= as_truth_value (node_a
, loc
);
1182 node_b
= as_truth_value (node_b
, loc
);
1183 inner_op
= TRUTH_ORIF_EXPR
;
1186 case GCC_JIT_BINARY_OP_LSHIFT
:
1187 inner_op
= LSHIFT_EXPR
;
1190 case GCC_JIT_BINARY_OP_RSHIFT
:
1191 inner_op
= RSHIFT_EXPR
;
1195 tree inner_expr
= build2 (inner_op
,
1196 result_type
->as_tree (),
1200 /* Try to fold the expression. */
1201 inner_expr
= fold (inner_expr
);
1204 set_tree_location (inner_expr
, loc
);
1206 return new rvalue (this, inner_expr
);
1209 /* Construct a playback::rvalue instance (wrapping a tree) for a
1214 new_comparison (location
*loc
,
1215 enum gcc_jit_comparison op
,
1216 rvalue
*a
, rvalue
*b
, type
*vec_result_type
)
1218 // FIXME: type-checking, or coercion?
1219 enum tree_code inner_op
;
1227 add_error (loc
, "unrecognized (enum gcc_jit_comparison) value: %i", op
);
1230 case GCC_JIT_COMPARISON_EQ
:
1233 case GCC_JIT_COMPARISON_NE
:
1236 case GCC_JIT_COMPARISON_LT
:
1239 case GCC_JIT_COMPARISON_LE
:
1242 case GCC_JIT_COMPARISON_GT
:
1245 case GCC_JIT_COMPARISON_GE
:
1250 tree node_a
= a
->as_tree ();
1251 node_a
= fold_const_var (node_a
);
1252 tree node_b
= b
->as_tree ();
1253 node_b
= fold_const_var (node_b
);
1256 tree a_type
= TREE_TYPE (node_a
);
1257 if (VECTOR_TYPE_P (a_type
))
1259 /* Build a vector comparison. See build_vec_cmp in c-typeck.cc for
1261 tree t_vec_result_type
= vec_result_type
->as_tree ();
1262 tree zero_vec
= build_zero_cst (t_vec_result_type
);
1263 tree minus_one_vec
= build_minus_one_cst (t_vec_result_type
);
1264 tree cmp_type
= truth_type_for (a_type
);
1265 tree cmp
= build2 (inner_op
, cmp_type
, node_a
, node_b
);
1266 inner_expr
= build3 (VEC_COND_EXPR
, t_vec_result_type
, cmp
, minus_one_vec
,
1271 inner_expr
= build2 (inner_op
,
1278 inner_expr
= fold (inner_expr
);
1281 set_tree_location (inner_expr
, loc
);
1282 return new rvalue (this, inner_expr
);
1285 /* Construct a playback::rvalue instance (wrapping a tree) for a
1290 build_call (location
*loc
,
1292 const auto_vec
<rvalue
*> *args
,
1293 bool require_tail_call
)
1295 vec
<tree
, va_gc
> *tree_args
;
1296 vec_alloc (tree_args
, args
->length ());
1297 for (unsigned i
= 0; i
< args
->length (); i
++)
1298 tree_args
->quick_push ((*args
)[i
]->as_tree ());
1301 set_tree_location (fn_ptr
, loc
);
1303 tree fn
= TREE_TYPE (fn_ptr
);
1304 tree fn_type
= TREE_TYPE (fn
);
1305 tree return_type
= TREE_TYPE (fn_type
);
1307 tree call
= build_call_vec (return_type
,
1310 if (require_tail_call
)
1311 CALL_EXPR_MUST_TAIL_CALL (call
) = 1;
1313 return new rvalue (this, call
);
1315 /* see c-typeck.cc: build_function_call
1316 which calls build_function_call_vec
1318 which does lots of checking, then:
1319 result = build_call_array_loc (loc, TREE_TYPE (fntype),
1320 function, nargs, argarray);
1322 (see also build_call_vec)
1326 /* Construct a playback::rvalue instance (wrapping a tree) for a
1327 call to a specific function. */
1331 new_call (location
*loc
,
1333 const auto_vec
<rvalue
*> *args
,
1334 bool require_tail_call
)
1340 fndecl
= func
->as_fndecl ();
1342 tree fntype
= TREE_TYPE (fndecl
);
1344 tree fn
= build1 (ADDR_EXPR
, build_pointer_type (fntype
), fndecl
);
1346 return build_call (loc
, fn
, args
, require_tail_call
);
1349 /* Construct a playback::rvalue instance (wrapping a tree) for a
1350 call through a function pointer. */
1354 new_call_through_ptr (location
*loc
,
1356 const auto_vec
<rvalue
*> *args
,
1357 bool require_tail_call
)
1359 gcc_assert (fn_ptr
);
1360 tree t_fn_ptr
= fn_ptr
->as_tree ();
1362 return build_call (loc
, t_fn_ptr
, args
, require_tail_call
);
1365 /* Construct a tree for a cast. */
1368 playback::context::build_cast (playback::location
*loc
,
1369 playback::rvalue
*expr
,
1370 playback::type
*type_
)
1372 /* For comparison, see:
1373 - c/c-typeck.cc:build_c_cast
1374 - c/c-convert.cc: convert
1377 Only some kinds of cast are currently supported here. */
1378 tree t_expr
= expr
->as_tree ();
1379 t_expr
= fold_const_var (t_expr
);
1381 tree t_dst_type
= type_
->as_tree ();
1383 t_ret
= targetm
.convert_to_type (t_dst_type
, t_expr
);
1386 enum tree_code dst_code
= TREE_CODE (t_dst_type
);
1391 t_ret
= convert_to_integer (t_dst_type
, t_expr
);
1395 /* Compare with c_objc_common_truthvalue_conversion and
1396 c_common_truthvalue_conversion. */
1397 /* For now, convert to: (t_expr != 0) */
1398 t_ret
= build2 (NE_EXPR
, t_dst_type
,
1400 build_int_cst (TREE_TYPE (t_expr
), 0));
1404 t_ret
= convert_to_real (t_dst_type
, t_expr
);
1408 t_ret
= build1 (NOP_EXPR
, t_dst_type
, t_expr
);
1412 add_error (loc
, "couldn't handle cast during playback");
1413 fprintf (stderr
, "input expression:\n");
1414 debug_tree (t_expr
);
1415 fprintf (stderr
, "requested type:\n");
1416 debug_tree (t_dst_type
);
1417 return error_mark_node
;
1420 if (TREE_CODE (t_ret
) != C_MAYBE_CONST_EXPR
)
1421 t_ret
= fold (t_ret
);
1426 /* Construct a playback::rvalue instance (wrapping a tree) for a
1431 new_cast (playback::location
*loc
,
1432 playback::rvalue
*expr
,
1433 playback::type
*type_
)
1436 tree t_cast
= build_cast (loc
, expr
, type_
);
1438 set_tree_location (t_cast
, loc
);
1439 return new rvalue (this, t_cast
);
1442 /* Construct a playback::rvalue instance (wrapping a tree) for a
1447 new_bitcast (location
*loc
,
1451 tree expr_size
= TYPE_SIZE (expr
->get_type ()->as_tree ());
1452 tree type_size
= TYPE_SIZE (type_
->as_tree ());
1453 tree t_expr
= expr
->as_tree ();
1454 tree t_dst_type
= type_
->as_tree ();
1455 if (expr_size
!= type_size
)
1457 active_playback_ctxt
->add_error (loc
,
1458 "bitcast with types of different sizes");
1459 fprintf (stderr
, "input expression (size: %ld):\n",
1460 (long) tree_to_uhwi (expr_size
));
1461 debug_tree (t_expr
);
1462 fprintf (stderr
, "requested type (size: %ld):\n",
1463 (long) tree_to_uhwi (type_size
));
1464 debug_tree (t_dst_type
);
1466 tree t_bitcast
= build1 (VIEW_CONVERT_EXPR
, t_dst_type
, t_expr
);
1468 set_tree_location (t_bitcast
, loc
);
1469 return new rvalue (this, t_bitcast
);
1472 /* Construct a playback::lvalue instance (wrapping a tree) for an
1477 new_array_access (location
*loc
,
1484 /* For comparison, see:
1485 c/c-typeck.cc: build_array_ref
1486 c-family/c-common.cc: pointer_int_sum
1488 tree t_ptr
= ptr
->as_tree ();
1489 t_ptr
= fold_const_var (t_ptr
);
1490 tree t_index
= index
->as_tree ();
1491 t_index
= fold_const_var (t_index
);
1493 tree t_type_ptr
= TREE_TYPE (t_ptr
);
1494 tree t_type_star_ptr
= TREE_TYPE (t_type_ptr
);
1496 if (TREE_CODE (t_type_ptr
) == ARRAY_TYPE
)
1498 tree t_result
= build4 (ARRAY_REF
, t_type_star_ptr
, t_ptr
, t_index
,
1499 NULL_TREE
, NULL_TREE
);
1500 t_result
= fold (t_result
);
1502 set_tree_location (t_result
, loc
);
1503 return new lvalue (this, t_result
);
1507 /* Convert index to an offset in bytes. */
1508 tree t_sizeof
= size_in_bytes (t_type_star_ptr
);
1509 t_index
= fold_build1 (CONVERT_EXPR
, sizetype
, t_index
);
1510 tree t_offset
= fold_build2_loc (UNKNOWN_LOCATION
,
1511 MULT_EXPR
, sizetype
, t_index
, t_sizeof
);
1513 /* Locate (ptr + offset). */
1514 tree t_address
= fold_build2_loc (UNKNOWN_LOCATION
,
1515 POINTER_PLUS_EXPR
, t_type_ptr
, t_ptr
, t_offset
);
1517 tree t_indirection
= fold_build1 (INDIRECT_REF
, t_type_star_ptr
, t_address
);
1520 set_tree_location (t_sizeof
, loc
);
1521 set_tree_location (t_offset
, loc
);
1522 set_tree_location (t_address
, loc
);
1523 set_tree_location (t_indirection
, loc
);
1526 return new lvalue (this, t_indirection
);
1530 /* Construct a tree for a field access. */
1534 new_field_access (location
*loc
,
1541 /* Compare with c/c-typeck.cc:lookup_field, build_indirect_ref, and
1542 build_component_ref. */
1543 tree type
= TREE_TYPE (datum
);
1545 gcc_assert (TREE_CODE (type
) != POINTER_TYPE
);
1547 tree t_field
= field
->as_tree ();
1548 tree ref
= build3 (COMPONENT_REF
, TREE_TYPE (t_field
), datum
,
1549 t_field
, NULL_TREE
);
1551 set_tree_location (ref
, loc
);
1555 /* Construct a tree for a dereference. */
1559 new_dereference (tree ptr
,
1564 tree type
= TREE_TYPE (TREE_TYPE(ptr
));
1565 tree datum
= fold_build1 (INDIRECT_REF
, type
, ptr
);
1567 set_tree_location (datum
, loc
);
1571 /* Construct a playback::type instance (wrapping a tree)
1572 with the given alignment. */
1576 get_aligned (size_t alignment_in_bytes
) const
1578 tree t_new_type
= build_variant_type_copy (m_inner
);
1580 SET_TYPE_ALIGN (t_new_type
, alignment_in_bytes
* BITS_PER_UNIT
);
1581 TYPE_USER_ALIGN (t_new_type
) = 1;
1583 return new type (t_new_type
);
1586 /* Construct a playback::type instance (wrapping a tree)
1587 for the given vector type. */
1591 get_vector (size_t num_units
) const
1593 tree t_new_type
= build_vector_type (m_inner
, num_units
);
1594 return new type (t_new_type
);
1597 /* Construct a playback::lvalue instance (wrapping a tree) for a
1602 access_field (location
*loc
,
1605 tree datum
= as_tree ();
1606 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1609 return new lvalue (get_context (), ref
);
1612 /* Construct a playback::rvalue instance (wrapping a tree) for a
1617 access_field (location
*loc
,
1620 tree datum
= as_tree ();
1621 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1624 return new rvalue (get_context (), ref
);
1627 /* Construct a playback::lvalue instance (wrapping a tree) for a
1628 dereferenced field access. */
1632 dereference_field (location
*loc
,
1635 tree ptr
= as_tree ();
1636 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1639 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1642 return new lvalue (get_context (), ref
);
1645 /* Construct a playback::lvalue instance (wrapping a tree) for a
1650 dereference (location
*loc
)
1652 tree ptr
= as_tree ();
1653 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1654 return new lvalue (get_context (), datum
);
1657 /* Mark the lvalue saying that we need to be able to take the
1658 address of it; it should not be allocated in a register.
1659 Compare with e.g. c/c-typeck.cc: c_mark_addressable really_atomic_lvalue.
1660 Returns false if a failure occurred (an error will already have been
1661 added to the active context for this case). */
1665 mark_addressable (location
*loc
)
1667 tree x
= as_tree ();
1670 switch (TREE_CODE (x
))
1673 if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x
, 1)))
1675 gcc_assert (gcc::jit::active_playback_ctxt
);
1677 active_playback_ctxt
->add_error (loc
,
1678 "cannot take address of "
1687 x
= TREE_OPERAND (x
, 0);
1690 case COMPOUND_LITERAL_EXPR
:
1692 TREE_ADDRESSABLE (x
) = 1;
1699 /* (we don't have a concept of a "register" declaration) */
1702 TREE_ADDRESSABLE (x
) = 1;
1709 /* Construct a playback::rvalue instance (wrapping a tree) for an
1714 get_address (location
*loc
)
1716 tree t_lvalue
= as_tree ();
1717 tree t_thistype
= TREE_TYPE (t_lvalue
);
1718 tree t_ptrtype
= build_pointer_type (t_thistype
);
1719 tree ptr
= fold_build1 (ADDR_EXPR
, t_ptrtype
, t_lvalue
);
1721 get_context ()->set_tree_location (ptr
, loc
);
1722 if (mark_addressable (loc
))
1723 return new rvalue (get_context (), ptr
);
1728 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1729 Provide this finalization hook for calling then they are collected,
1730 which calls the finalizer vfunc. This allows them to call "release"
1731 on any vec<> within them. */
1734 wrapper_finalizer (void *ptr
)
1736 playback::wrapper
*wrapper
= reinterpret_cast <playback::wrapper
*> (ptr
);
1737 wrapper
->finalizer ();
1740 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1741 allocate them using ggc_internal_cleared_alloc. */
1745 operator new (size_t sz
)
1747 return ggc_internal_cleared_alloc (sz
, wrapper_finalizer
, 0, 1);
1751 /* Constructor for gcc:jit::playback::function. */
1753 playback::function::
1754 function (context
*ctxt
,
1756 enum gcc_jit_function_kind kind
)
1758 m_inner_fndecl (fndecl
),
1759 m_inner_bind_expr (NULL
),
1763 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1765 /* Create a BIND_EXPR, and within it, a statement list. */
1766 m_stmt_list
= alloc_stmt_list ();
1767 m_stmt_iter
= tsi_start (m_stmt_list
);
1768 m_inner_block
= make_node (BLOCK
);
1770 build3 (BIND_EXPR
, void_type_node
, NULL
, m_stmt_list
, m_inner_block
);
1774 m_inner_block
= NULL
;
1779 /* Hand-written GC-marking hook for playback functions. */
1782 playback::function::
1785 gt_ggc_m_9tree_node (m_inner_fndecl
);
1786 gt_ggc_m_9tree_node (m_inner_bind_expr
);
1787 gt_ggc_m_9tree_node (m_stmt_list
);
1788 gt_ggc_m_9tree_node (m_inner_block
);
1791 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1795 playback::function::finalizer ()
1797 m_blocks
.release ();
1800 /* Get the return type of a playback function, in tree form. */
1803 playback::function::
1804 get_return_type_as_tree () const
1806 return TREE_TYPE (TREE_TYPE(m_inner_fndecl
));
1809 /* Construct a new local within this playback::function. */
1812 playback::function::
1813 new_local (location
*loc
,
1819 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
1820 get_identifier (name
),
1822 DECL_CONTEXT (inner
) = this->m_inner_fndecl
;
1824 /* Prepend to BIND_EXPR_VARS: */
1825 DECL_CHAIN (inner
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1826 BIND_EXPR_VARS (m_inner_bind_expr
) = inner
;
1829 set_tree_location (inner
, loc
);
1830 return new lvalue (m_ctxt
, inner
);
1833 /* Construct a new block within this playback::function. */
1836 playback::function::
1837 new_block (const char *name
)
1839 gcc_assert (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
);
1841 block
*result
= new playback::block (this, name
);
1842 m_blocks
.safe_push (result
);
1846 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1847 this playback::function. */
1850 playback::function::get_address (location
*loc
)
1852 tree t_fndecl
= as_fndecl ();
1853 tree t_fntype
= TREE_TYPE (t_fndecl
);
1854 tree t_fnptr
= build1 (ADDR_EXPR
, build_pointer_type (t_fntype
), t_fndecl
);
1856 m_ctxt
->set_tree_location (t_fnptr
, loc
);
1857 return new rvalue (m_ctxt
, t_fnptr
);
1860 /* Build a statement list for the function as a whole out of the
1861 lists of statements for the individual blocks, building labels
1865 playback::function::
1871 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1873 FOR_EACH_VEC_ELT (m_blocks
, i
, b
)
1878 b
->m_label_expr
= build1 (LABEL_EXPR
,
1880 b
->as_label_decl ());
1881 tsi_link_after (&m_stmt_iter
, b
->m_label_expr
, TSI_CONTINUE_LINKING
);
1883 FOR_EACH_VEC_ELT (b
->m_stmts
, j
, stmt
)
1884 tsi_link_after (&m_stmt_iter
, stmt
, TSI_CONTINUE_LINKING
);
1888 /* Finish compiling the given function, potentially running the
1890 The function will have a statement list by now.
1891 Amongst other things, this gimplifies the statement list,
1892 and calls cgraph_node::finalize_function on the function. */
1895 playback::function::
1898 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1900 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
))
1901 debug_tree (m_stmt_list
);
1903 /* Do we need this to force cgraphunit.cc to output the function? */
1904 if (m_kind
== GCC_JIT_FUNCTION_EXPORTED
)
1906 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1907 DECL_PRESERVE_P (m_inner_fndecl
) = 1;
1910 if (m_kind
== GCC_JIT_FUNCTION_INTERNAL
1911 ||m_kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
1913 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1914 TREE_PUBLIC (m_inner_fndecl
) = 0;
1917 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1919 /* Seem to need this in gimple-low.cc: */
1920 gcc_assert (m_inner_block
);
1921 DECL_INITIAL (m_inner_fndecl
) = m_inner_block
;
1923 /* how to add to function? the following appears to be how to
1924 set the body of a m_inner_fndecl: */
1925 DECL_SAVED_TREE(m_inner_fndecl
) = m_inner_bind_expr
;
1927 /* Ensure that locals appear in the debuginfo. */
1928 BLOCK_VARS (m_inner_block
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1930 //debug_tree (m_inner_fndecl);
1932 /* Convert to gimple: */
1933 //printf("about to gimplify_function_tree\n");
1934 gimplify_function_tree (m_inner_fndecl
);
1935 //printf("finished gimplify_function_tree\n");
1937 current_function_decl
= m_inner_fndecl
;
1938 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
))
1939 dump_function_to_file (m_inner_fndecl
, stderr
, TDF_VOPS
|TDF_MEMSYMS
|TDF_LINENO
);
1940 //debug_tree (m_inner_fndecl);
1942 //printf("about to add to cgraph\n");
1943 /* Add to cgraph: */
1944 cgraph_node::finalize_function (m_inner_fndecl
, false);
1945 /* This can trigger a collection, so we need to have all of
1946 the funcs as roots. */
1948 current_function_decl
= NULL
;
1952 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1956 playback::block::finalizer ()
1961 /* Add an eval of the rvalue to the function's statement list. */
1965 add_eval (location
*loc
,
1968 gcc_assert (rvalue
);
1971 set_tree_location (rvalue
->as_tree (), loc
);
1973 add_stmt (rvalue
->as_tree ());
1976 /* Add an assignment to the function's statement list. */
1980 add_assignment (location
*loc
,
1984 gcc_assert (lvalue
);
1985 gcc_assert (rvalue
);
1987 tree t_lvalue
= lvalue
->as_tree ();
1988 tree t_rvalue
= rvalue
->as_tree ();
1989 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1991 t_rvalue
= build1 (CONVERT_EXPR
,
1992 TREE_TYPE (t_lvalue
),
1995 set_tree_location (t_rvalue
, loc
);
1999 build2 (MODIFY_EXPR
, TREE_TYPE (t_lvalue
),
2000 t_lvalue
, t_rvalue
);
2002 set_tree_location (stmt
, loc
);
2006 /* Add a comment to the function's statement list.
2007 For now this is done by adding a dummy label. */
2011 add_comment (location
*loc
,
2014 /* Wrap the text in C-style comment delimiters. */
2016 (3 /* opening delim */
2018 + 3 /* closing delim */
2019 + 1 /* terminator */);
2020 char *wrapped
= (char *)ggc_internal_alloc (sz
);
2021 snprintf (wrapped
, sz
, "/* %s */", text
);
2023 /* For now we simply implement this by adding a dummy label with a name
2024 containing the given text. */
2025 tree identifier
= get_identifier (wrapped
);
2026 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
2027 identifier
, void_type_node
);
2028 DECL_CONTEXT (label_decl
) = m_func
->as_fndecl ();
2030 tree label_expr
= build1 (LABEL_EXPR
, void_type_node
, label_decl
);
2032 set_tree_location (label_expr
, loc
);
2033 add_stmt (label_expr
);
2036 /* Add a conditional jump statement to the function's statement list. */
2040 add_conditional (location
*loc
,
2045 gcc_assert (boolval
);
2046 gcc_assert (on_true
);
2047 gcc_assert (on_false
);
2049 /* COND_EXPR wants statement lists for the true/false operands, but we
2051 Shim it by creating jumps to the labels */
2052 tree true_jump
= build1 (GOTO_EXPR
, void_type_node
,
2053 on_true
->as_label_decl ());
2055 set_tree_location (true_jump
, loc
);
2057 tree false_jump
= build1 (GOTO_EXPR
, void_type_node
,
2058 on_false
->as_label_decl ());
2060 set_tree_location (false_jump
, loc
);
2063 build3 (COND_EXPR
, void_type_node
, boolval
->as_tree (),
2064 true_jump
, false_jump
);
2066 set_tree_location (stmt
, loc
);
2070 /* Add an unconditional jump statement to the function's statement list. */
2074 add_jump (location
*loc
,
2077 gcc_assert (target
);
2079 // see c_finish_loop
2080 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
2083 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
2084 TREE_USED (target
->as_label_decl ()) = 1;
2085 tree stmt
= build1 (GOTO_EXPR
, void_type_node
, target
->as_label_decl ());
2087 set_tree_location (stmt
, loc
);
2093 c_finish_goto_label (location_t loc, tree label)
2095 tree decl = lookup_label_for_goto (loc, label);
2098 TREE_USED (decl) = 1;
2100 tree t = build1 (GOTO_EXPR, void_type_node, decl);
2101 SET_EXPR_LOCATION (t, loc);
2102 return add_stmt (t);
2109 /* Add a return statement to the function's statement list. */
2113 add_return (location
*loc
,
2116 tree modify_retval
= NULL
;
2117 tree return_type
= m_func
->get_return_type_as_tree ();
2120 tree t_lvalue
= DECL_RESULT (m_func
->as_fndecl ());
2121 tree t_rvalue
= rvalue
->as_tree ();
2122 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
2123 t_rvalue
= build1 (CONVERT_EXPR
,
2124 TREE_TYPE (t_lvalue
),
2126 modify_retval
= build2 (MODIFY_EXPR
, return_type
,
2127 t_lvalue
, t_rvalue
);
2129 set_tree_location (modify_retval
, loc
);
2131 tree return_stmt
= build1 (RETURN_EXPR
, return_type
,
2134 set_tree_location (return_stmt
, loc
);
2136 add_stmt (return_stmt
);
2139 /* Helper function for playback::block::add_switch.
2140 Construct a case label for the given range, followed by a goto stmt
2141 to the given block, appending them to stmt list *ptr_t_switch_body. */
2144 add_case (tree
*ptr_t_switch_body
,
2147 playback::block
*dest_block
)
2149 tree t_label
= create_artificial_label (UNKNOWN_LOCATION
);
2150 DECL_CONTEXT (t_label
) = dest_block
->get_function ()->as_fndecl ();
2153 build_case_label (t_low_value
, t_high_value
, t_label
);
2154 append_to_statement_list (t_case_label
, ptr_t_switch_body
);
2157 build1 (GOTO_EXPR
, void_type_node
, dest_block
->as_label_decl ());
2158 append_to_statement_list (t_goto_stmt
, ptr_t_switch_body
);
2161 /* Add a switch statement to the function's statement list.
2163 We create a switch body, and populate it with case labels, each
2164 followed by a goto to the desired block. */
2168 add_switch (location
*loc
,
2170 block
*default_block
,
2171 const auto_vec
<case_
> *cases
)
2174 - c/c-typeck.cc: c_start_case
2175 - c-family/c-common.cc:c_add_case_label
2176 - java/expr.cc:expand_java_switch and expand_java_add_case
2177 We've already rejected overlaps and duplicates in
2178 libgccjit.cc:case_range_validator::validate. */
2180 tree t_expr
= expr
->as_tree ();
2181 tree t_type
= TREE_TYPE (t_expr
);
2183 tree t_switch_body
= alloc_stmt_list ();
2187 FOR_EACH_VEC_ELT (*cases
, i
, c
)
2189 tree t_low_value
= c
->m_min_value
->as_tree ();
2190 tree t_high_value
= c
->m_max_value
->as_tree ();
2191 add_case (&t_switch_body
, t_low_value
, t_high_value
, c
->m_dest_block
);
2193 /* Default label. */
2194 add_case (&t_switch_body
, NULL_TREE
, NULL_TREE
, default_block
);
2196 tree switch_stmt
= build2 (SWITCH_EXPR
, t_type
, t_expr
, t_switch_body
);
2198 set_tree_location (switch_stmt
, loc
);
2199 add_stmt (switch_stmt
);
2202 /* Convert OPERANDS to a tree-based chain suitable for creating an
2204 Compare with c_parser_asm_operands. */
2207 build_operand_chain (const auto_vec
<playback::asm_operand
> *operands
)
2209 tree result
= NULL_TREE
;
2211 playback::asm_operand
*asm_op
;
2212 FOR_EACH_VEC_ELT (*operands
, i
, asm_op
)
2214 tree name
= build_string (asm_op
->m_asm_symbolic_name
);
2215 tree str
= build_string (asm_op
->m_constraint
);
2216 tree value
= asm_op
->m_expr
;
2217 result
= chainon (result
,
2218 build_tree_list (build_tree_list (name
, str
),
2224 /* Convert CLOBBERS to a tree-based list suitable for creating an
2226 Compare with c_parser_asm_clobbers. */
2229 build_clobbers (const auto_vec
<const char *> *clobbers
)
2231 tree list
= NULL_TREE
;
2233 const char *clobber
;
2234 FOR_EACH_VEC_ELT (*clobbers
, i
, clobber
)
2236 tree str
= build_string (clobber
);
2237 list
= tree_cons (NULL_TREE
, str
, list
);
2242 /* Convert BLOCKS to a tree-based list suitable for creating an
2244 Compare with c_parser_asm_goto_operands. */
2247 build_goto_operands (const auto_vec
<playback::block
*> *blocks
)
2249 tree list
= NULL_TREE
;
2252 FOR_EACH_VEC_ELT (*blocks
, i
, b
)
2254 tree label
= b
->as_label_decl ();
2255 tree name
= build_string (IDENTIFIER_POINTER (DECL_NAME (label
)));
2256 TREE_USED (label
) = 1;
2257 list
= tree_cons (name
, label
, list
);
2259 return nreverse (list
);
2262 /* Add an extended asm statement to this block.
2264 Compare with c_parser_asm_statement (in c/c-parser.cc)
2265 and build_asm_expr (in c/c-typeck.cc). */
2268 playback::block::add_extended_asm (location
*loc
,
2269 const char *asm_template
,
2272 const auto_vec
<asm_operand
> *outputs
,
2273 const auto_vec
<asm_operand
> *inputs
,
2274 const auto_vec
<const char *> *clobbers
,
2275 const auto_vec
<block
*> *goto_blocks
)
2277 tree t_string
= build_string (asm_template
);
2278 tree t_outputs
= build_operand_chain (outputs
);
2279 tree t_inputs
= build_operand_chain (inputs
);
2280 tree t_clobbers
= build_clobbers (clobbers
);
2281 tree t_labels
= build_goto_operands (goto_blocks
);
2283 = resolve_asm_operand_names (t_string
, t_outputs
, t_inputs
, t_labels
);
2285 = build5 (ASM_EXPR
, void_type_node
,
2286 t_string
, t_outputs
, t_inputs
, t_clobbers
, t_labels
);
2288 /* asm statements without outputs, including simple ones, are treated
2290 ASM_VOLATILE_P (asm_stmt
) = (outputs
->length () == 0);
2291 ASM_INPUT_P (asm_stmt
) = 0; /* extended asm stmts are not "simple". */
2292 ASM_INLINE_P (asm_stmt
) = is_inline
;
2294 ASM_VOLATILE_P (asm_stmt
) = 1;
2296 set_tree_location (asm_stmt
, loc
);
2297 add_stmt (asm_stmt
);
2300 /* Constructor for gcc::jit::playback::block. */
2303 block (function
*func
,
2313 identifier
= get_identifier (name
);
2316 m_label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
2317 identifier
, void_type_node
);
2318 DECL_CONTEXT (m_label_decl
) = func
->as_fndecl ();
2319 m_label_expr
= NULL
;
2322 // This is basically std::lock_guard but it can call the private lock/unlock
2323 // members of playback::context.
2324 struct playback::context::scoped_lock
2326 scoped_lock (context
&ctx
) : m_ctx (&ctx
) { m_ctx
->lock (); }
2327 ~scoped_lock () { m_ctx
->unlock (); }
2331 // Not movable or copyable.
2332 scoped_lock (scoped_lock
&&) = delete;
2333 scoped_lock
&operator= (scoped_lock
&&) = delete;
2336 /* Compile a playback::context:
2338 - Use the context's options to cconstruct command-line options, and
2339 call into the rest of GCC (toplev::main).
2340 - Assuming it succeeds, we have a .s file.
2341 - We then run the "postprocess" vfunc:
2343 (A) In-memory compile ("gcc_jit_context_compile")
2345 For an in-memory compile we have the playback::compile_to_memory
2346 subclass; "postprocess" will convert the .s file to a .so DSO,
2347 and load it in memory (via dlopen), wrapping the result up as
2348 a jit::result and returning it.
2350 (B) Compile to file ("gcc_jit_context_compile_to_file")
2352 When compiling to a file, we have the playback::compile_to_file
2353 subclass; "postprocess" will either copy the .s file to the
2354 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
2355 the driver to convert it as necessary, copying the result. */
2361 JIT_LOG_SCOPE (get_logger ());
2363 const char *ctxt_progname
;
2365 int keep_intermediates
=
2366 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
);
2368 m_tempdir
= new tempdir (get_logger (), keep_intermediates
);
2369 if (!m_tempdir
->create ())
2372 /* Call into the rest of gcc.
2373 For now, we have to assemble command-line options to pass into
2374 toplev::main, so that they can be parsed. */
2376 /* Pass in user-provided program name as argv0, if any, so that it
2377 makes it into GCC's "progname" global, used in various diagnostics. */
2378 ctxt_progname
= get_str_option (GCC_JIT_STR_OPTION_PROGNAME
);
2381 ctxt_progname
= "libgccjit.so";
2383 auto_vec
<recording::requested_dump
> requested_dumps
;
2384 m_recording_ctxt
->get_all_requested_dumps (&requested_dumps
);
2386 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
2387 scoped_lock
lock(*this);
2389 auto_string_vec fake_args
;
2390 make_fake_args (&fake_args
, ctxt_progname
, &requested_dumps
);
2391 if (errors_occurred ())
2394 /* This runs the compiler. */
2395 toplev
toplev (get_timer (), /* external_timer */
2396 false); /* init_signals */
2397 enter_scope ("toplev::main");
2399 for (unsigned i
= 0; i
< fake_args
.length (); i
++)
2400 get_logger ()->log ("argv[%i]: %s", i
, fake_args
[i
]);
2401 toplev
.main (fake_args
.length (),
2402 const_cast <char **> (fake_args
.address ()));
2403 exit_scope ("toplev::main");
2405 /* Extracting dumps makes use of the gcc::dump_manager, hence we
2406 need to do it between toplev::main (which creates the dump manager)
2407 and toplev::finalize (which deletes it). */
2408 extract_any_requested_dumps (&requested_dumps
);
2410 /* Clean up the compiler. */
2411 enter_scope ("toplev::finalize");
2413 exit_scope ("toplev::finalize");
2415 /* Ideally we would release the jit mutex here, but we can't yet since
2416 followup activities use timevars, which are global state. */
2418 if (errors_occurred ())
2421 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
))
2422 dump_generated_code ();
2424 /* We now have a .s file.
2426 Run any postprocessing steps. This will either convert the .s file to
2427 a .so DSO, and load it in memory (playback::compile_to_memory), or
2428 convert the .s file to the requested output format, and copy it to a
2429 given file (playback::compile_to_file). */
2430 postprocess (ctxt_progname
);
2433 /* Implementation of class gcc::jit::playback::compile_to_memory,
2434 a subclass of gcc::jit::playback::context. */
2436 /* playback::compile_to_memory's trivial constructor. */
2438 playback::compile_to_memory::compile_to_memory (recording::context
*ctxt
) :
2439 playback::context (ctxt
),
2442 JIT_LOG_SCOPE (get_logger ());
2445 /* Implementation of the playback::context::process vfunc for compiling
2448 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
2449 wrapping the result up as a jit::result and returning it. */
2452 playback::compile_to_memory::postprocess (const char *ctxt_progname
)
2454 JIT_LOG_SCOPE (get_logger ());
2455 convert_to_dso (ctxt_progname
);
2456 if (errors_occurred ())
2458 m_result
= dlopen_built_dso ();
2461 /* Implementation of class gcc::jit::playback::compile_to_file,
2462 a subclass of gcc::jit::playback::context. */
2464 /* playback::compile_to_file's trivial constructor. */
2466 playback::compile_to_file::compile_to_file (recording::context
*ctxt
,
2467 enum gcc_jit_output_kind output_kind
,
2468 const char *output_path
) :
2469 playback::context (ctxt
),
2470 m_output_kind (output_kind
),
2471 m_output_path (output_path
)
2473 JIT_LOG_SCOPE (get_logger ());
2476 /* Implementation of the playback::context::process vfunc for compiling
2479 Either copy the .s file to the given destination (for
2480 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
2481 as necessary, copying the result. */
2484 playback::compile_to_file::postprocess (const char *ctxt_progname
)
2486 JIT_LOG_SCOPE (get_logger ());
2488 /* The driver takes different actions based on the filename, so
2489 we provide a filename with an appropriate suffix for the
2490 output kind, and then copy it up to the user-provided path,
2491 rather than directly compiling it to the requested output path. */
2493 switch (m_output_kind
)
2498 case GCC_JIT_OUTPUT_KIND_ASSEMBLER
:
2499 copy_file (get_tempdir ()->get_path_s_file (),
2501 /* The .s file is automatically unlinked by tempdir::~tempdir. */
2504 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE
:
2506 char *tmp_o_path
= ::concat (get_tempdir ()->get_path (),
2509 invoke_driver (ctxt_progname
,
2510 get_tempdir ()->get_path_s_file (),
2513 false, /* bool shared, */
2514 false);/* bool run_linker */
2515 if (!errors_occurred ())
2517 copy_file (tmp_o_path
,
2519 get_tempdir ()->add_temp_file (tmp_o_path
);
2526 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY
:
2527 invoke_driver (ctxt_progname
,
2528 get_tempdir ()->get_path_s_file (),
2529 get_tempdir ()->get_path_so_file (),
2531 true, /* bool shared, */
2532 true);/* bool run_linker */
2533 if (!errors_occurred ())
2534 copy_file (get_tempdir ()->get_path_so_file (),
2536 /* The .so file is automatically unlinked by tempdir::~tempdir. */
2539 case GCC_JIT_OUTPUT_KIND_EXECUTABLE
:
2541 char *tmp_exe_path
= ::concat (get_tempdir ()->get_path (),
2544 invoke_driver (ctxt_progname
,
2545 get_tempdir ()->get_path_s_file (),
2548 false, /* bool shared, */
2549 true);/* bool run_linker */
2550 if (!errors_occurred ())
2552 copy_file (tmp_exe_path
,
2554 get_tempdir ()->add_temp_file (tmp_exe_path
);
2557 free (tmp_exe_path
);
2565 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2566 the "executable" bits).
2568 Any errors that occur are reported on the context and hence count as
2569 a failure of the compile.
2571 We can't in general hardlink or use "rename" from the tempdir since
2572 it might be on a different filesystem to the destination. For example,
2573 I get EXDEV: "Invalid cross-device link". */
2576 playback::compile_to_file::copy_file (const char *src_path
,
2577 const char *dst_path
)
2579 JIT_LOG_SCOPE (get_logger ());
2582 get_logger ()->log ("src_path: %s", src_path
);
2583 get_logger ()->log ("dst_path: %s", dst_path
);
2588 size_t total_sz_in
= 0;
2589 size_t total_sz_out
= 0;
2592 struct stat stat_buf
;
2594 f_in
= fopen (src_path
, "rb");
2598 "unable to open %s for reading: %s",
2604 /* Use stat on the filedescriptor to get the mode,
2605 so that we can copy it over (in particular, the
2606 "executable" bits). */
2607 if (fstat (fileno (f_in
), &stat_buf
) == -1)
2610 "unable to fstat %s: %s",
2617 f_out
= fopen (dst_path
, "wb");
2621 "unable to open %s for writing: %s",
2628 while ( (sz_in
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2630 total_sz_in
+= sz_in
;
2631 size_t sz_out_remaining
= sz_in
;
2632 size_t sz_out_so_far
= 0;
2633 while (sz_out_remaining
)
2635 size_t sz_out
= fwrite (buf
+ sz_out_so_far
,
2639 gcc_assert (sz_out
<= sz_out_remaining
);
2643 "error writing to %s: %s",
2650 total_sz_out
+= sz_out
;
2651 sz_out_so_far
+= sz_out
;
2652 sz_out_remaining
-= sz_out
;
2654 gcc_assert (sz_out_so_far
== sz_in
);
2659 "error reading from %s: %s",
2665 gcc_assert (total_sz_in
== total_sz_out
);
2667 get_logger ()->log ("total bytes copied: %zu", total_sz_out
);
2669 /* fchmod does not exist in Windows. */
2671 /* Set the permissions of the copy to those of the original file,
2672 in particular the "executable" bits. */
2673 if (fchmod (fileno (f_out
), stat_buf
.st_mode
) == -1)
2675 "error setting mode of %s: %s",
2683 /* Helper functions for gcc::jit::playback::context::compile. */
2685 /* This mutex guards gcc::jit::recording::context::compile, so that only
2686 one thread can be accessing the bulk of GCC's state at once. */
2688 static std::mutex jit_mutex
;
2690 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2693 playback::context::lock ()
2695 auto_timevar
tv (get_timer (), TV_JIT_ACQUIRING_MUTEX
);
2697 /* Acquire the big GCC mutex. */
2698 JIT_LOG_SCOPE (get_logger ());
2700 gcc_assert (active_playback_ctxt
== NULL
);
2701 active_playback_ctxt
= this;
2704 /* Release jit_mutex and clear the active playback ctxt. */
2707 playback::context::unlock ()
2709 /* Release the big GCC mutex. */
2710 JIT_LOG_SCOPE (get_logger ());
2711 gcc_assert (active_playback_ctxt
== this);
2712 active_playback_ctxt
= NULL
;
2713 jit_mutex
.unlock ();
2716 /* Callback used by gcc::jit::playback::context::make_fake_args when
2717 invoking driver_get_configure_time_options.
2718 Populate a vec <char * > with the configure-time options. */
2721 append_arg_from_driver (const char *option
, void *user_data
)
2723 gcc_assert (option
);
2724 gcc_assert (user_data
);
2725 vec
<char *> *argvec
= static_cast <vec
<char *> *> (user_data
);
2726 argvec
->safe_push (concat ("-", option
, NULL
));
2729 /* Build a fake argv for toplev::main from the options set
2730 by the user on the context . */
2734 make_fake_args (vec
<char *> *argvec
,
2735 const char *ctxt_progname
,
2736 vec
<recording::requested_dump
> *requested_dumps
)
2738 JIT_LOG_SCOPE (get_logger ());
2740 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2741 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2743 ADD_ARG (ctxt_progname
);
2744 ADD_ARG (get_path_c_file ());
2747 /* Handle int options: */
2748 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
))
2752 "unrecognized optimization level: %i",
2753 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
));
2772 /* What about -Os? */
2774 /* Handle bool options: */
2775 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2778 /* Suppress timing (and other) info. */
2779 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
))
2785 /* Aggressively garbage-collect, to shake out bugs: */
2786 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC
))
2788 ADD_ARG ("--param=ggc-min-expand=0");
2789 ADD_ARG ("--param=ggc-min-heapsize=0");
2792 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
))
2794 ADD_ARG ("-fdump-tree-all");
2795 ADD_ARG ("-fdump-rtl-all");
2796 ADD_ARG ("-fdump-ipa-all");
2799 /* Add "-fdump-" options for any calls to
2800 gcc_jit_context_enable_dump. */
2803 recording::requested_dump
*d
;
2804 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2806 char *arg
= concat ("-fdump-", d
->m_dumpname
, NULL
);
2807 ADD_ARG_TAKE_OWNERSHIP (arg
);
2811 /* PR jit/64810: Add any target-specific default options
2812 from OPTION_DEFAULT_SPECS, normally provided by the driver
2813 in the non-jit case.
2815 The target-specific code can define OPTION_DEFAULT_SPECS:
2816 default command options in the form of spec macros for the
2817 driver to expand ().
2819 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2820 if not overriden, injects the defaults as extra arguments to
2822 For the jit case, we need to add these arguments here. The
2823 input format (using the specs language) means that we have to run
2824 part of the driver code here (driver_get_configure_time_options).
2826 To avoid running the spec-expansion code every time, we just do
2827 it the first time (via a function-static flag), saving the result
2828 into a function-static vec.
2829 This flag and vec are global state (i.e. per-process).
2830 They are guarded by the jit mutex. */
2832 static bool have_configure_time_options
= false;
2833 static vec
<char *> configure_time_options
;
2835 if (have_configure_time_options
)
2836 log ("reusing cached configure-time options");
2839 have_configure_time_options
= true;
2840 log ("getting configure-time options from driver");
2841 driver_get_configure_time_options (append_arg_from_driver
,
2842 &configure_time_options
);
2849 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2850 log ("configure_time_options[%i]: %s", i
, opt
);
2852 /* configure_time_options should now contain the expanded options
2853 from OPTION_DEFAULT_SPECS (if any). */
2854 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2857 gcc_assert (opt
[0] == '-');
2863 ADD_ARG ("-ftime-report");
2865 /* Add any user-provided extra options, starting with any from
2867 m_recording_ctxt
->append_command_line_options (argvec
);
2870 #undef ADD_ARG_TAKE_OWNERSHIP
2873 /* The second half of the implementation of gcc_jit_context_enable_dump.
2874 Iterate through the requested dumps, reading the underlying files
2875 into heap-allocated buffers, writing pointers to the buffers into
2876 the char ** pointers provided by client code.
2877 Client code is responsible for calling free on the results. */
2881 extract_any_requested_dumps (vec
<recording::requested_dump
> *requested_dumps
)
2883 JIT_LOG_SCOPE (get_logger ());
2886 recording::requested_dump
*d
;
2887 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2889 dump_file_info
*dfi
;
2893 dfi
= g
->get_dumps ()->get_dump_file_info_by_switch (d
->m_dumpname
);
2896 add_error (NULL
, "unrecognized dump: %s", d
->m_dumpname
);
2900 filename
= g
->get_dumps ()->get_dump_file_name (dfi
);
2901 content
= read_dump_file (filename
);
2902 *(d
->m_out_ptr
) = content
;
2903 m_tempdir
->add_temp_file (filename
);
2907 /* Helper function for playback::context::extract_any_requested_dumps
2908 (itself for use in implementation of gcc_jit_context_enable_dump).
2910 Attempt to read the complete file at the given path, returning the
2911 bytes found there as a buffer.
2912 The caller is responsible for calling free on the result.
2913 Errors will be reported on the context, and lead to NULL being
2914 returned; an out-of-memory error will terminate the process. */
2917 playback::context::read_dump_file (const char *path
)
2919 char *result
= NULL
;
2920 size_t total_sz
= 0;
2925 f_in
= fopen (path
, "r");
2928 add_error (NULL
, "unable to open %s for reading", path
);
2932 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2934 size_t old_total_sz
= total_sz
;
2936 result
= reinterpret_cast <char *> (xrealloc (result
, total_sz
+ 1));
2937 memcpy (result
+ old_total_sz
, buf
, sz
);
2942 add_error (NULL
, "error reading from %s", path
);
2952 result
[total_sz
] = '\0';
2956 return xstrdup ("");
2959 /* Part of playback::context::compile ().
2961 We have a .s file; we want a .so file.
2962 We could reuse parts of gcc/gcc.cc to do this.
2963 For now, just use the driver binary from the install, as
2964 named in gcc-driver-name.h
2965 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2969 convert_to_dso (const char *ctxt_progname
)
2971 JIT_LOG_SCOPE (get_logger ());
2973 invoke_driver (ctxt_progname
,
2974 m_tempdir
->get_path_s_file (),
2975 m_tempdir
->get_path_so_file (),
2977 true, /* bool shared, */
2978 true);/* bool run_linker */
2981 static const char * const gcc_driver_name
= GCC_DRIVER_NAME
;
2985 invoke_driver (const char *ctxt_progname
,
2986 const char *input_file
,
2987 const char *output_file
,
2992 JIT_LOG_SCOPE (get_logger ());
2994 bool embedded_driver
2995 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER
);
2997 /* Currently this lumps together both assembling and linking into
2999 auto_timevar
assemble_timevar (get_timer (), tv_id
);
3000 auto_string_vec argvec
;
3001 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
3003 ADD_ARG (gcc_driver_name
);
3005 add_multilib_driver_arguments (&argvec
);
3008 ADD_ARG ("-shared");
3013 ADD_ARG (input_file
);
3015 ADD_ARG (output_file
);
3017 /* Don't use the linker plugin.
3018 If running with just a "make" and not a "make install", then we'd
3020 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
3021 libto_plugin is a .la at build time, with it becoming installed with
3022 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
3024 ADD_ARG ("-fno-use-linker-plugin");
3026 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
3027 /* OS X's linker defaults to treating undefined symbols as errors.
3028 If the context has any imported functions or globals they will be
3029 undefined until the .so is dynamically-linked into the process.
3030 Ensure that the driver passes in "-undefined dynamic_lookup" to the
3032 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
3038 /* Add any user-provided driver extra options. */
3040 m_recording_ctxt
->append_driver_options (&argvec
);
3044 /* pex_one's error-handling requires pname to be non-NULL. */
3045 gcc_assert (ctxt_progname
);
3048 for (unsigned i
= 0; i
< argvec
.length (); i
++)
3049 get_logger ()->log ("argv[%i]: %s", i
, argvec
[i
]);
3051 if (embedded_driver
)
3052 invoke_embedded_driver (&argvec
);
3054 invoke_external_driver (ctxt_progname
, &argvec
);
3059 invoke_embedded_driver (const vec
<char *> *argvec
)
3061 JIT_LOG_SCOPE (get_logger ());
3062 driver
d (true, /* can_finalize */
3064 int result
= d
.main (argvec
->length (),
3065 const_cast <char **> (argvec
->address ()));
3068 add_error (NULL
, "error invoking gcc driver");
3073 invoke_external_driver (const char *ctxt_progname
,
3074 vec
<char *> *argvec
)
3076 JIT_LOG_SCOPE (get_logger ());
3078 int exit_status
= 0;
3081 /* pex argv arrays are NULL-terminated. */
3082 argvec
->safe_push (NULL
);
3084 errmsg
= pex_one (PEX_SEARCH
, /* int flags, */
3086 const_cast <char *const *> (argvec
->address ()),
3087 ctxt_progname
, /* const char *pname */
3088 NULL
, /* const char *outname */
3089 NULL
, /* const char *errname */
3090 &exit_status
, /* int *status */
3091 &err
); /* int *err*/
3094 add_error (NULL
, "error invoking gcc driver: %s", errmsg
);
3098 /* pex_one can return a NULL errmsg when the executable wasn't
3099 found (or doesn't exist), so trap these cases also. */
3100 if (exit_status
|| err
)
3103 "error invoking gcc driver: exit_status: %i err: %i",
3106 "whilst attempting to run a driver named: %s",
3115 /* Extract the target-specific MULTILIB_DEFAULTS to
3116 multilib_defaults_raw for use by
3117 playback::context::add_multilib_driver_arguments (). */
3119 #ifndef MULTILIB_DEFAULTS
3120 #define MULTILIB_DEFAULTS { "" }
3123 static const char *const multilib_defaults_raw
[] = MULTILIB_DEFAULTS
;
3125 /* Helper function for playback::context::invoke_driver ().
3127 32-bit and 64-bit multilib peer builds of libgccjit.so may share
3128 a driver binary. We need to pass in options to the shared driver
3129 to get the appropriate assembler/linker options for this multilib
3134 add_multilib_driver_arguments (vec
<char *> *argvec
)
3136 JIT_LOG_SCOPE (get_logger ());
3138 /* Add copies of the arguments in multilib_defaults_raw to argvec,
3139 prepending each with a "-". */
3140 for (size_t i
= 0; i
< ARRAY_SIZE (multilib_defaults_raw
); i
++)
3141 if (multilib_defaults_raw
[i
][0])
3142 argvec
->safe_push (concat ("-", multilib_defaults_raw
[i
], NULL
));
3145 /* Dynamically-link the built DSO file into this process, using dlopen.
3146 Wrap it up within a jit::result *, and return that.
3147 Return NULL if any errors occur, reporting them on this context. */
3153 JIT_LOG_SCOPE (get_logger ());
3154 auto_timevar
load_timevar (get_timer (), TV_LOAD
);
3155 result::handle handle
= NULL
;
3156 result
*result_obj
= NULL
;
3159 /* Clear any existing error. */
3162 handle
= LoadLibrary(m_tempdir
->get_path_so_file ());
3163 if (GetLastError() != 0) {
3167 const char *error
= NULL
;
3168 /* Clear any existing error. */
3171 handle
= dlopen (m_tempdir
->get_path_so_file (),
3172 RTLD_NOW
| RTLD_LOCAL
);
3173 if ((error
= dlerror()) != NULL
) {
3174 add_error (NULL
, "%s", error
);
3180 /* We've successfully dlopened the result; create a
3181 jit::result object to wrap it.
3183 We're done with the tempdir for now, but if the user
3184 has requested debugging, the user's debugger might not
3185 be capable of dealing with the .so file being unlinked
3186 immediately, so keep it around until after the result
3187 is released. We do this by handing over ownership of
3188 the jit::tempdir to the result. See PR jit/64206. */
3189 tempdir
*handover_tempdir
;
3190 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
3192 handover_tempdir
= m_tempdir
;
3194 /* The tempdir will eventually be cleaned up in the
3195 jit::result's dtor. */
3196 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
3197 " handing over tempdir to jit::result");
3201 handover_tempdir
= NULL
;
3202 /* ... and retain ownership of m_tempdir so we clean it
3203 up it the playback::context's dtor. */
3204 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
3205 " retaining ownership of tempdir");
3208 result_obj
= new result (get_logger (), handle
, handover_tempdir
);
3216 /* Top-level hook for playing back a recording context.
3218 This plays back m_recording_ctxt, and, if no errors
3219 occurred builds statement lists for and then postprocesses
3220 every function in the result. */
3226 JIT_LOG_SCOPE (get_logger ());
3230 /* Replay the recorded events: */
3231 timevar_push (TV_JIT_REPLAY
);
3233 /* Ensure that builtins that could be needed during optimization
3234 get created ahead of time. */
3235 builtins_manager
*bm
= m_recording_ctxt
->get_builtins_manager ();
3236 bm
->ensure_optimization_builtins_exist ();
3238 m_recording_ctxt
->replay_into (this);
3240 /* Clean away the temporary references from recording objects
3241 to playback objects. We have to do this now since the
3242 latter are GC-allocated, but the former don't mark these
3243 refs. Hence we must stop using them before the GC can run. */
3244 m_recording_ctxt
->disassociate_from_playback ();
3246 /* The builtins_manager is associated with the recording::context
3247 and might be reused for future compiles on other playback::contexts,
3248 but its m_attributes array is not GTY-labeled and hence will become
3249 nonsense if the GC runs. Purge this state. */
3250 bm
->finish_playback ();
3252 timevar_pop (TV_JIT_REPLAY
);
3254 if (!errors_occurred ())
3259 /* No GC can happen yet; process the cached source locations. */
3260 handle_locations ();
3262 /* Finalize globals. See how FORTRAN 95 does it in gfc_be_parse_file()
3263 for a simple reference. */
3264 FOR_EACH_VEC_ELT (m_globals
, i
, global
)
3265 rest_of_decl_compilation (global
, true, true);
3267 wrapup_global_declarations (m_globals
.address(), m_globals
.length());
3269 /* We've now created tree nodes for the stmts in the various blocks
3270 in each function, but we haven't built each function's single stmt
3271 list yet. Do so now. */
3272 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
3273 func
->build_stmt_list ();
3275 /* No GC can have happened yet. */
3277 /* Postprocess the functions. This could trigger GC. */
3278 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
3281 func
->postprocess ();
3286 /* Dump the generated .s file to stderr. */
3290 dump_generated_code ()
3292 JIT_LOG_SCOPE (get_logger ());
3295 FILE *f_in
= fopen (get_path_s_file (), "r");
3299 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
3300 fwrite (buf
, 1, sz
, stderr
);
3305 /* Get the supposed path of the notional "fake.c" file within the
3306 tempdir. This file doesn't exist, but the rest of the compiler
3311 get_path_c_file () const
3313 return m_tempdir
->get_path_c_file ();
3316 /* Get the path of the assembler output file "fake.s" file within the
3321 get_path_s_file () const
3323 return m_tempdir
->get_path_s_file ();
3326 /* Get the path of the DSO object file "fake.so" file within the
3331 get_path_so_file () const
3333 return m_tempdir
->get_path_so_file ();
3336 /* qsort comparator for comparing pairs of playback::source_line *,
3337 ordering them by line number. */
3340 line_comparator (const void *lhs
, const void *rhs
)
3342 const playback::source_line
*line_lhs
= \
3343 *static_cast<const playback::source_line
* const*> (lhs
);
3344 const playback::source_line
*line_rhs
= \
3345 *static_cast<const playback::source_line
* const*> (rhs
);
3346 return line_lhs
->get_line_num () - line_rhs
->get_line_num ();
3349 /* qsort comparator for comparing pairs of playback::location *,
3350 ordering them by column number. */
3353 location_comparator (const void *lhs
, const void *rhs
)
3355 const playback::location
*loc_lhs
= \
3356 *static_cast<const playback::location
* const *> (lhs
);
3357 const playback::location
*loc_rhs
= \
3358 *static_cast<const playback::location
* const *> (rhs
);
3359 return loc_lhs
->get_column_num () - loc_rhs
->get_column_num ();
3362 /* Initialize the NAME_TYPE of the primitive types as well as some
3368 /* See lto_init() in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc
3369 for reference. If TYPE_NAME is not set, debug info will not contain types */
3370 #define NAME_TYPE(t,n) \
3372 TYPE_NAME (t) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, \
3373 get_identifier (n), t)
3375 NAME_TYPE (integer_type_node
, "int");
3376 NAME_TYPE (char_type_node
, "char");
3377 NAME_TYPE (long_integer_type_node
, "long int");
3378 NAME_TYPE (unsigned_type_node
, "unsigned int");
3379 NAME_TYPE (long_unsigned_type_node
, "long unsigned int");
3380 NAME_TYPE (long_long_integer_type_node
, "long long int");
3381 NAME_TYPE (long_long_unsigned_type_node
, "long long unsigned int");
3382 NAME_TYPE (short_integer_type_node
, "short int");
3383 NAME_TYPE (short_unsigned_type_node
, "short unsigned int");
3384 if (signed_char_type_node
!= char_type_node
)
3385 NAME_TYPE (signed_char_type_node
, "signed char");
3386 if (unsigned_char_type_node
!= char_type_node
)
3387 NAME_TYPE (unsigned_char_type_node
, "unsigned char");
3388 NAME_TYPE (float_type_node
, "float");
3389 NAME_TYPE (double_type_node
, "double");
3390 NAME_TYPE (long_double_type_node
, "long double");
3391 NAME_TYPE (void_type_node
, "void");
3392 NAME_TYPE (boolean_type_node
, "bool");
3393 NAME_TYPE (complex_float_type_node
, "complex float");
3394 NAME_TYPE (complex_double_type_node
, "complex double");
3395 NAME_TYPE (complex_long_double_type_node
, "complex long double");
3397 m_const_char_ptr
= build_pointer_type(
3398 build_qualified_type (char_type_node
, TYPE_QUAL_CONST
));
3400 NAME_TYPE (m_const_char_ptr
, "char");
3401 NAME_TYPE (size_type_node
, "size_t");
3402 NAME_TYPE (fileptr_type_node
, "FILE");
3406 /* Our API allows locations to be created in arbitrary orders, but the
3407 linemap API requires locations to be created in ascending order
3408 as if we were tokenizing files.
3410 This hook sorts all of the locations that have been created, and
3411 calls into the linemap API, creating linemap entries in sorted order
3412 for our locations. */
3418 /* Create the source code locations, following the ordering rules
3419 imposed by the linemap API.
3421 line_table is a global. */
3422 JIT_LOG_SCOPE (get_logger ());
3426 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
3428 linemap_add (line_table
, LC_ENTER
, false, file
->get_filename (), 0);
3430 /* Sort lines by ascending line numbers. */
3431 file
->m_source_lines
.qsort (&line_comparator
);
3435 FOR_EACH_VEC_ELT (file
->m_source_lines
, j
, line
)
3440 /* Sort locations in line by ascending column numbers. */
3441 line
->m_locations
.qsort (&location_comparator
);
3443 /* Determine maximum column within this line. */
3444 gcc_assert (line
->m_locations
.length () > 0);
3445 location
*final_column
=
3446 line
->m_locations
[line
->m_locations
.length () - 1];
3447 int max_col
= final_column
->get_column_num ();
3449 linemap_line_start (line_table
, line
->get_line_num (), max_col
);
3450 FOR_EACH_VEC_ELT (line
->m_locations
, k
, loc
)
3453 linemap_position_for_column (line_table
, loc
->get_column_num ());
3457 linemap_add (line_table
, LC_LEAVE
, false, NULL
, 0);
3460 /* line_table should now be populated; every playback::location should
3461 now have an m_srcloc. */
3463 /* Now assign them to tree nodes as appropriate. */
3464 std::pair
<tree
, location
*> *cached_location
;
3466 FOR_EACH_VEC_ELT (m_cached_locations
, i
, cached_location
)
3468 tree t
= cached_location
->first
;
3469 location_t srcloc
= cached_location
->second
->m_srcloc
;
3471 /* This covers expressions: */
3472 if (CAN_HAVE_LOCATION_P (t
))
3473 SET_EXPR_LOCATION (t
, srcloc
);
3474 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t
), TS_DECL_MINIMAL
))
3475 DECL_SOURCE_LOCATION (t
) = srcloc
;
3478 /* Don't know how to set location on this node. */
3483 /* We handle errors on a playback::context by adding them to the
3484 corresponding recording::context. */
3488 add_error (location
*loc
, const char *fmt
, ...)
3492 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
3497 /* We handle errors on a playback::context by adding them to the
3498 corresponding recording::context. */
3502 add_error_va (location
*loc
, const char *fmt
, va_list ap
)
3504 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
3508 /* Report a diagnostic up to the jit context as an error,
3509 so that the compilation is treated as a failure.
3510 For now, any kind of diagnostic is treated as an error by the jit
3515 add_diagnostic (struct diagnostic_context
*diag_context
,
3516 struct diagnostic_info
*diagnostic
)
3518 /* At this point the text has been formatted into the pretty-printer's
3520 pretty_printer
*pp
= diag_context
->printer
;
3521 const char *text
= pp_formatted_text (pp
);
3523 /* Get location information (if any) from the diagnostic.
3524 The recording::context::add_error[_va] methods require a
3525 recording::location. We can't lookup the playback::location
3526 from the file/line/column since any playback location instances
3527 may have been garbage-collected away by now, so instead we create
3528 another recording::location directly. */
3529 location_t gcc_loc
= diagnostic_location (diagnostic
);
3530 recording::location
*rec_loc
= NULL
;
3533 expanded_location exploc
= expand_location (gcc_loc
);
3535 rec_loc
= m_recording_ctxt
->new_location (exploc
.file
,
3541 m_recording_ctxt
->add_error (rec_loc
, "%s", text
);
3542 pp_clear_output_area (pp
);
3545 /* Dealing with the linemap API. */
3547 /* Construct a playback::location for a recording::location, if it
3548 doesn't exist already. */
3550 playback::location
*
3552 new_location (recording::location
*rloc
,
3553 const char *filename
,
3557 /* Get the source_file for filename, creating if necessary. */
3558 source_file
*src_file
= get_source_file (filename
);
3559 /* Likewise for the line within the file. */
3560 source_line
*src_line
= src_file
->get_source_line (line
);
3561 /* Likewise for the column within the line. */
3562 location
*loc
= src_line
->get_location (rloc
, column
);
3566 /* Deferred setting of the location for a given tree, by adding the
3567 (tree, playback::location) pair to a list of deferred associations.
3568 We will actually set the location on the tree later on once
3569 the location_t for the playback::location exists. */
3573 set_tree_location (tree t
, location
*loc
)
3576 m_cached_locations
.safe_push (std::make_pair (t
, loc
));
3580 /* Construct a playback::source_file for the given source
3581 filename, if it doesn't exist already. */
3583 playback::source_file
*
3585 get_source_file (const char *filename
)
3588 For simplicitly, this is currently a linear search.
3589 Replace with a hash if this shows up in the profile. */
3592 tree ident_filename
= get_identifier (filename
);
3594 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
3595 if (file
->filename_as_tree () == ident_filename
)
3599 file
= new source_file (ident_filename
);
3600 m_source_files
.safe_push (file
);
3604 /* Constructor for gcc::jit::playback::source_file. */
3606 playback::source_file::source_file (tree filename
) :
3608 m_filename (filename
)
3612 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3616 playback::source_file::finalizer ()
3618 m_source_lines
.release ();
3621 /* Construct a playback::source_line for the given line
3622 within this source file, if one doesn't exist already. */
3624 playback::source_line
*
3625 playback::source_file::
3626 get_source_line (int line_num
)
3629 For simplicitly, this is currently a linear search.
3630 Replace with a hash if this shows up in the profile. */
3634 FOR_EACH_VEC_ELT (m_source_lines
, i
, line
)
3635 if (line
->get_line_num () == line_num
)
3639 line
= new source_line (this, line_num
);
3640 m_source_lines
.safe_push (line
);
3644 /* Constructor for gcc::jit::playback::source_line. */
3646 playback::source_line::source_line (source_file
*file
, int line_num
) :
3648 m_source_file (file
),
3649 m_line_num (line_num
)
3653 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3657 playback::source_line::finalizer ()
3659 m_locations
.release ();
3662 /* Construct a playback::location for the given column
3663 within this line of a specific source file, if one doesn't exist
3666 playback::location
*
3667 playback::source_line::
3668 get_location (recording::location
*rloc
, int column_num
)
3673 /* Another linear search that probably should be a hash table. */
3674 FOR_EACH_VEC_ELT (m_locations
, i
, loc
)
3675 if (loc
->get_column_num () == column_num
)
3679 loc
= new location (rloc
, this, column_num
);
3680 m_locations
.safe_push (loc
);
3684 /* Constructor for gcc::jit::playback::location. */
3686 playback::location::location (recording::location
*loc
,
3689 m_srcloc (UNKNOWN_LOCATION
),
3690 m_recording_loc (loc
),
3692 m_column_num(column_num
)
3696 /* The active gcc::jit::playback::context instance. This is a singleton,
3697 guarded by jit_mutex. */
3699 playback::context
*active_playback_ctxt
;
3701 } // namespace gcc::jit