1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2022 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
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/>. */
23 #include "coretypes.h"
26 #include "stringpool.h"
32 #include "stor-layout.h"
33 #include "print-tree.h"
35 #include "gcc-driver-name.h"
38 #include "fold-const.h"
39 #include "opt-suggestions.h"
41 #include "diagnostic.h"
46 #include "jit-playback.h"
47 #include "jit-result.h"
48 #include "jit-builtins.h"
49 #include "jit-tempdir.h"
55 /* Compare with gcc/c-family/c-common.h: DECL_C_BIT_FIELD,
57 These are redefined here to avoid depending from the C frontend. */
58 #define DECL_JIT_BIT_FIELD(NODE) \
59 (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1)
60 #define SET_DECL_JIT_BIT_FIELD(NODE) \
61 (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1)
63 /* gcc::jit::playback::context::build_cast uses the convert.h API,
64 which in turn requires the frontend to provide a "convert"
65 function, apparently as a fallback for casts that can be simplified
66 (truncation, extension). */
67 extern tree
convert (tree type
, tree expr
);
70 convert (tree dst_type
, tree expr
)
73 t_ret
= targetm
.convert_to_type (dst_type
, expr
);
76 switch (TREE_CODE (dst_type
))
80 return fold (convert_to_integer (dst_type
, expr
));
83 gcc_assert (gcc::jit::active_playback_ctxt
);
84 gcc::jit::active_playback_ctxt
->add_error (NULL
, "unhandled conversion");
85 fprintf (stderr
, "input expression:\n");
87 fprintf (stderr
, "requested type:\n");
88 debug_tree (dst_type
);
89 return error_mark_node
;
96 /**********************************************************************
98 **********************************************************************/
100 /* Fold a readonly non-volatile variable with an initial constant value,
103 Otherwise return the argument unchanged.
105 This fold is needed for setting a variable's DECL_INITIAL to the value
106 of a const variable. The c-frontend does this in its own special
107 fold (), so we lift this part out and do it explicitly where there is a
108 potential for variables to be used as rvalues. */
110 fold_const_var (tree node
)
112 /* See c_fully_fold_internal in c-fold.cc and decl_constant_value_1
115 && TREE_READONLY (node
)
116 && !TREE_THIS_VOLATILE (node
)
117 && DECL_INITIAL (node
) != NULL_TREE
118 /* "This is invalid if initial value is not constant.
119 If it has either a function call, a memory reference,
120 or a variable, then re-evaluating it could give different
122 && TREE_CONSTANT (DECL_INITIAL (node
)))
124 tree ret
= DECL_INITIAL (node
);
125 /* "Avoid unwanted tree sharing between the initializer and current
126 function's body where the tree can be modified e.g. by the
128 if (TREE_STATIC (node
))
129 ret
= unshare_expr (ret
);
137 /* Build a STRING_CST tree for STR, or return NULL if it is NULL.
138 The TREE_TYPE is not initialized. */
141 build_string (const char *str
)
144 return ::build_string (strlen (str
), str
);
149 /* The constructor for gcc::jit::playback::context. */
151 playback::context::context (recording::context
*ctxt
)
152 : log_user (ctxt
->get_logger ()),
153 m_recording_ctxt (ctxt
),
155 m_const_char_ptr (NULL
)
157 JIT_LOG_SCOPE (get_logger ());
158 m_functions
.create (0);
159 m_globals
.create (0);
160 m_source_files
.create (0);
161 m_cached_locations
.create (0);
164 /* The destructor for gcc::jit::playback::context. */
166 playback::context::~context ()
168 JIT_LOG_SCOPE (get_logger ());
170 /* Normally the playback::context is responsible for cleaning up the
171 tempdir (including "fake.so" within the filesystem).
173 In the normal case, clean it up now.
175 However m_tempdir can be NULL if the context has handed over
176 responsibility for the tempdir cleanup to the jit::result object, so
177 that the cleanup can be delayed (see PR jit/64206). If that's the
178 case this "delete NULL;" is a no-op. */
181 m_functions
.release ();
184 /* A playback::context can reference GC-managed pointers. Mark them
185 ("by hand", rather than by gengtype).
187 This is called on the active playback context (if any) by the
188 my_ggc_walker hook in the jit_root_table in dummy-frontend.cc. */
196 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
198 if (ggc_test_and_set_mark (func
))
203 /* Given an enum gcc_jit_types value, get a "tree" type. */
207 get_tree_node_for_type (enum gcc_jit_types type_
)
211 case GCC_JIT_TYPE_VOID
:
212 return void_type_node
;
214 case GCC_JIT_TYPE_VOID_PTR
:
215 return ptr_type_node
;
217 case GCC_JIT_TYPE_BOOL
:
218 return boolean_type_node
;
220 case GCC_JIT_TYPE_CHAR
:
221 return char_type_node
;
222 case GCC_JIT_TYPE_SIGNED_CHAR
:
223 return signed_char_type_node
;
224 case GCC_JIT_TYPE_UNSIGNED_CHAR
:
225 return unsigned_char_type_node
;
227 case GCC_JIT_TYPE_SHORT
:
228 return short_integer_type_node
;
229 case GCC_JIT_TYPE_UNSIGNED_SHORT
:
230 return short_unsigned_type_node
;
232 case GCC_JIT_TYPE_CONST_CHAR_PTR
:
233 return m_const_char_ptr
;
235 case GCC_JIT_TYPE_INT
:
236 return integer_type_node
;
237 case GCC_JIT_TYPE_UNSIGNED_INT
:
238 return unsigned_type_node
;
240 case GCC_JIT_TYPE_LONG
:
241 return long_integer_type_node
;
242 case GCC_JIT_TYPE_UNSIGNED_LONG
:
243 return long_unsigned_type_node
;
245 case GCC_JIT_TYPE_LONG_LONG
:
246 return long_long_integer_type_node
;
247 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG
:
248 return long_long_unsigned_type_node
;
250 case GCC_JIT_TYPE_FLOAT
:
251 return float_type_node
;
252 case GCC_JIT_TYPE_DOUBLE
:
253 return double_type_node
;
254 case GCC_JIT_TYPE_LONG_DOUBLE
:
255 return long_double_type_node
;
257 case GCC_JIT_TYPE_SIZE_T
:
258 return size_type_node
;
260 case GCC_JIT_TYPE_FILE_PTR
:
261 return fileptr_type_node
;
263 case GCC_JIT_TYPE_COMPLEX_FLOAT
:
264 return complex_float_type_node
;
265 case GCC_JIT_TYPE_COMPLEX_DOUBLE
:
266 return complex_double_type_node
;
267 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE
:
268 return complex_long_double_type_node
;
274 /* Construct a playback::type instance (wrapping a tree) for the given
279 get_type (enum gcc_jit_types type_
)
281 tree type_node
= get_tree_node_for_type (type_
);
282 if (type_node
== NULL
)
284 add_error (NULL
, "unrecognized (enum gcc_jit_types) value: %i", type_
);
288 return new type (type_node
);
291 /* Construct a playback::type instance (wrapping a tree) for the given
296 new_array_type (playback::location
*loc
,
297 playback::type
*element_type
,
300 gcc_assert (element_type
);
302 tree t
= build_array_type_nelts (element_type
->as_tree (),
307 set_tree_location (t
, loc
);
312 /* Construct a playback::field instance (wrapping a tree). */
316 new_field (location
*loc
,
323 /* compare with c/c-decl.cc:grokfield and grokdeclarator. */
324 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
325 get_identifier (name
), type
->as_tree ());
328 set_tree_location (decl
, loc
);
330 return new field (decl
);
333 /* Construct a playback::bitfield instance (wrapping a tree). */
337 new_bitfield (location
*loc
,
346 /* compare with c/c-decl.cc:grokfield, grokdeclarator and
347 check_bitfield_type_and_width. */
349 tree tree_type
= type
->as_tree ();
350 gcc_assert (INTEGRAL_TYPE_P (tree_type
));
351 tree tree_width
= build_int_cst (integer_type_node
, width
);
352 if (compare_tree_int (tree_width
, TYPE_PRECISION (tree_type
)) > 0)
356 "width of bit-field %s (width: %i) is wider than its type (width: %i)",
357 name
, width
, TYPE_PRECISION (tree_type
));
361 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
362 get_identifier (name
), type
->as_tree ());
363 DECL_NONADDRESSABLE_P (decl
) = true;
364 DECL_INITIAL (decl
) = tree_width
;
365 SET_DECL_JIT_BIT_FIELD (decl
);
368 set_tree_location (decl
, loc
);
370 return new field (decl
);
373 /* Construct a playback::compound_type instance (wrapping a tree). */
375 playback::compound_type
*
377 new_compound_type (location
*loc
,
379 bool is_struct
) /* else is union */
383 /* Compare with c/c-decl.cc: start_struct. */
385 tree t
= make_node (is_struct
? RECORD_TYPE
: UNION_TYPE
);
386 TYPE_NAME (t
) = get_identifier (name
);
390 set_tree_location (t
, loc
);
392 return new compound_type (t
);
396 playback::compound_type::set_fields (const auto_vec
<playback::field
*> *fields
)
398 /* Compare with c/c-decl.cc: finish_struct. */
401 tree fieldlist
= NULL
;
402 for (unsigned i
= 0; i
< fields
->length (); i
++)
404 field
*f
= (*fields
)[i
];
405 tree x
= f
->as_tree ();
406 DECL_CONTEXT (x
) = t
;
407 if (DECL_JIT_BIT_FIELD (x
))
409 unsigned HOST_WIDE_INT width
= tree_to_uhwi (DECL_INITIAL (x
));
410 DECL_SIZE (x
) = bitsize_int (width
);
411 DECL_BIT_FIELD (x
) = 1;
413 fieldlist
= chainon (x
, fieldlist
);
415 fieldlist
= nreverse (fieldlist
);
416 TYPE_FIELDS (t
) = fieldlist
;
421 /* Construct a playback::type instance (wrapping a tree) for a function
426 new_function_type (type
*return_type
,
427 const auto_vec
<type
*> *param_types
,
433 tree
*arg_types
= (tree
*)xcalloc(param_types
->length (), sizeof(tree
*));
435 FOR_EACH_VEC_ELT (*param_types
, i
, param_type
)
436 arg_types
[i
] = param_type
->as_tree ();
441 build_varargs_function_type_array (return_type
->as_tree (),
442 param_types
->length (),
445 fn_type
= build_function_type_array (return_type
->as_tree (),
446 param_types
->length (),
450 return new type (fn_type
);
453 /* Construct a playback::param instance (wrapping a tree). */
457 new_param (location
*loc
,
463 tree inner
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
464 get_identifier (name
), type
->as_tree ());
466 set_tree_location (inner
, loc
);
468 return new param (this, inner
);
471 /* Construct a playback::function instance. */
475 new_function (location
*loc
,
476 enum gcc_jit_function_kind kind
,
479 const auto_vec
<param
*> *params
,
481 enum built_in_function builtin_id
)
486 //can return_type be NULL?
489 tree
*arg_types
= (tree
*)xcalloc(params
->length (), sizeof(tree
*));
490 FOR_EACH_VEC_ELT (*params
, i
, param
)
491 arg_types
[i
] = TREE_TYPE (param
->as_tree ());
495 fn_type
= build_varargs_function_type_array (return_type
->as_tree (),
496 params
->length (), arg_types
);
498 fn_type
= build_function_type_array (return_type
->as_tree (),
499 params
->length (), arg_types
);
502 /* FIXME: this uses input_location: */
503 tree fndecl
= build_fn_decl (name
, fn_type
);
506 set_tree_location (fndecl
, loc
);
508 tree resdecl
= build_decl (UNKNOWN_LOCATION
, RESULT_DECL
,
509 NULL_TREE
, return_type
->as_tree ());
510 DECL_ARTIFICIAL (resdecl
) = 1;
511 DECL_IGNORED_P (resdecl
) = 1;
512 DECL_RESULT (fndecl
) = resdecl
;
513 DECL_CONTEXT (resdecl
) = fndecl
;
517 gcc_assert (loc
== NULL
);
518 DECL_SOURCE_LOCATION (fndecl
) = BUILTINS_LOCATION
;
520 built_in_class fclass
= builtins_manager::get_class (builtin_id
);
521 set_decl_built_in_function (fndecl
, fclass
, builtin_id
);
522 set_builtin_decl (builtin_id
, fndecl
,
523 builtins_manager::implicit_p (builtin_id
));
525 builtins_manager
*bm
= get_builtins_manager ();
526 tree attrs
= bm
->get_attrs_tree (builtin_id
);
528 decl_attributes (&fndecl
, attrs
, ATTR_FLAG_BUILT_IN
);
530 decl_attributes (&fndecl
, NULL_TREE
, 0);
533 if (kind
!= GCC_JIT_FUNCTION_IMPORTED
)
535 tree param_decl_list
= NULL
;
536 FOR_EACH_VEC_ELT (*params
, i
, param
)
538 param_decl_list
= chainon (param
->as_tree (), param_decl_list
);
541 /* The param list was created in reverse order; fix it: */
542 param_decl_list
= nreverse (param_decl_list
);
545 for (t
= param_decl_list
; t
; t
= DECL_CHAIN (t
))
547 DECL_CONTEXT (t
) = fndecl
;
548 DECL_ARG_TYPE (t
) = TREE_TYPE (t
);
551 /* Set it up on DECL_ARGUMENTS */
552 DECL_ARGUMENTS(fndecl
) = param_decl_list
;
555 if (kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
557 DECL_DECLARED_INLINE_P (fndecl
) = 1;
559 /* Add attribute "always_inline": */
560 DECL_ATTRIBUTES (fndecl
) =
561 tree_cons (get_identifier ("always_inline"),
563 DECL_ATTRIBUTES (fndecl
));
566 function
*func
= new function (this, fndecl
, kind
);
567 m_functions
.safe_push (func
);
571 /* In use by new_global and new_global_initialized. */
575 global_new_decl (location
*loc
,
576 enum gcc_jit_global_kind kind
,
579 enum global_var_flags flags
)
584 tree type_tree
= type
->as_tree ();
586 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
587 get_identifier (name
),
590 TREE_PUBLIC (inner
) = (kind
!= GCC_JIT_GLOBAL_INTERNAL
);
593 int will_be_init
= flags
& (GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT
|
594 GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT
);
596 /* A VAR_DECL with DECL_INITIAL will not end up in .common section. */
598 DECL_COMMON (inner
) = 1;
605 case GCC_JIT_GLOBAL_EXPORTED
:
606 TREE_STATIC (inner
) = 1;
609 case GCC_JIT_GLOBAL_INTERNAL
:
610 TREE_STATIC (inner
) = 1;
613 case GCC_JIT_GLOBAL_IMPORTED
:
614 DECL_EXTERNAL (inner
) = 1;
618 if (TYPE_READONLY (type_tree
))
619 TREE_READONLY (inner
) = 1;
622 set_tree_location (inner
, loc
);
627 /* In use by new_global and new_global_initialized. */
631 global_finalize_lvalue (tree inner
)
633 m_globals
.safe_push (inner
);
635 return new lvalue (this, inner
);
638 /* Construct a playback::lvalue instance (wrapping a tree). */
642 new_global (location
*loc
,
643 enum gcc_jit_global_kind kind
,
646 enum global_var_flags flags
)
649 global_new_decl (loc
, kind
, type
, name
, flags
);
651 return global_finalize_lvalue (inner
);
656 global_set_init_rvalue (lvalue
* variable
,
659 tree inner
= variable
->as_tree ();
661 /* We need to fold all expressions as much as possible. The code
662 for a DECL_INITIAL only handles some operations,
663 etc addition, minus, 'address of'. See output_addressed_constants ()
665 tree init_tree
= init
->as_tree ();
666 tree folded
= fold_const_var (init_tree
);
668 if (!TREE_CONSTANT (folded
))
670 tree name
= DECL_NAME (inner
);
672 if (name
!= NULL_TREE
)
674 "unable to convert initial value for the global variable %s"
675 " to a compile-time constant",
676 IDENTIFIER_POINTER (name
));
679 "unable to convert initial value for global variable"
680 " to a compile-time constant");
684 DECL_INITIAL (inner
) = folded
;
689 new_ctor (location
*loc
,
691 const auto_vec
<field
*> *fields
,
692 const auto_vec
<rvalue
*> *rvalues
)
694 tree type_tree
= type
->as_tree ();
696 /* Handle empty ctors first. I.e. set everything to 0. */
697 if (rvalues
->length () == 0)
698 return new rvalue (this, build_constructor (type_tree
, NULL
));
700 /* Handle arrays (and return). */
701 if (TREE_CODE (type_tree
) == ARRAY_TYPE
)
703 int n
= rvalues
->length ();
704 /* The vec for the constructor node. */
705 vec
<constructor_elt
, va_gc
> *v
= NULL
;
708 for (int i
= 0; i
< n
; i
++)
710 rvalue
*rv
= (*rvalues
)[i
];
711 /* null rvalues indicate that the element should be zeroed. */
713 CONSTRUCTOR_APPEND_ELT (v
,
714 build_int_cst (size_type_node
, i
),
717 CONSTRUCTOR_APPEND_ELT (v
,
718 build_int_cst (size_type_node
, i
),
719 build_zero_cst (TREE_TYPE (type_tree
)));
722 tree ctor
= build_constructor (type_tree
, v
);
725 set_tree_location (ctor
, loc
);
727 return new rvalue (this, ctor
);
730 /* Handle structs and unions. */
731 int n
= fields
->length ();
733 /* The vec for the constructor node. */
734 vec
<constructor_elt
, va_gc
> *v
= NULL
;
737 /* Iterate over the fields, building initializations. */
738 for (int i
= 0;i
< n
; i
++)
740 tree field
= (*fields
)[i
]->as_tree ();
741 rvalue
*rv
= (*rvalues
)[i
];
742 /* If the value is NULL, it means we should zero the field. */
744 CONSTRUCTOR_APPEND_ELT (v
, field
, rv
->as_tree ());
747 tree zero_cst
= build_zero_cst (TREE_TYPE (field
));
748 CONSTRUCTOR_APPEND_ELT (v
, field
, zero_cst
);
752 tree ctor
= build_constructor (type_tree
, v
);
755 set_tree_location (ctor
, loc
);
757 return new rvalue (this, build_constructor (type_tree
, v
));
760 /* Fill 'constructor_elements' with the memory content of
761 'initializer'. Each element of the initializer is of the size of
762 type T. In use by new_global_initialized.*/
766 load_blob_in_ctor (vec
<constructor_elt
, va_gc
> *&constructor_elements
,
768 const void *initializer
)
770 /* Loosely based on 'output_init_element' c-typeck.cc:9691. */
771 const T
*p
= (const T
*)initializer
;
772 tree node
= make_unsigned_type (BITS_PER_UNIT
* sizeof (T
));
773 for (size_t i
= 0; i
< num_elem
; i
++)
775 constructor_elt celt
=
776 { build_int_cst (long_unsigned_type_node
, i
),
777 build_int_cst (node
, p
[i
]) };
778 vec_safe_push (constructor_elements
, celt
);
782 /* Construct an initialized playback::lvalue instance (wrapping a
787 new_global_initialized (location
*loc
,
788 enum gcc_jit_global_kind kind
,
791 size_t initializer_num_elem
,
792 const void *initializer
,
794 enum global_var_flags flags
)
796 tree inner
= global_new_decl (loc
, kind
, type
, name
, flags
);
798 vec
<constructor_elt
, va_gc
> *constructor_elements
= NULL
;
800 switch (element_size
)
803 load_blob_in_ctor
<uint8_t> (constructor_elements
, initializer_num_elem
,
807 load_blob_in_ctor
<uint16_t> (constructor_elements
, initializer_num_elem
,
811 load_blob_in_ctor
<uint32_t> (constructor_elements
, initializer_num_elem
,
815 load_blob_in_ctor
<uint64_t> (constructor_elements
, initializer_num_elem
,
819 /* This function is serving on sizes returned by 'get_size',
820 these are all covered by the previous cases. */
823 /* Compare with 'pop_init_level' c-typeck.cc:8780. */
824 tree ctor
= build_constructor (type
->as_tree (), constructor_elements
);
825 constructor_elements
= NULL
;
827 /* Compare with 'store_init_value' c-typeck.cc:7555. */
828 DECL_INITIAL (inner
) = ctor
;
830 return global_finalize_lvalue (inner
);
833 /* Implementation of the various
834 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
836 Each of these constructs a playback::rvalue instance (wrapping a tree).
838 These specializations are required to be in the same namespace
839 as the template, hence we now have to enter the gcc::jit::playback
845 /* Specialization of making an rvalue from a const, for host <int>. */
850 new_rvalue_from_const
<int> (type
*type
,
853 // FIXME: type-checking, or coercion?
854 tree inner_type
= type
->as_tree ();
855 if (INTEGRAL_TYPE_P (inner_type
))
857 tree inner
= build_int_cst (inner_type
, value
);
858 return new rvalue (this, inner
);
862 REAL_VALUE_TYPE real_value
;
863 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
864 tree inner
= build_real (inner_type
, real_value
);
865 return new rvalue (this, inner
);
869 /* Specialization of making an rvalue from a const, for host <long>. */
874 new_rvalue_from_const
<long> (type
*type
,
877 // FIXME: type-checking, or coercion?
878 tree inner_type
= type
->as_tree ();
879 if (INTEGRAL_TYPE_P (inner_type
))
881 tree inner
= build_int_cst (inner_type
, value
);
882 return new rvalue (this, inner
);
886 REAL_VALUE_TYPE real_value
;
887 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
888 tree inner
= build_real (inner_type
, real_value
);
889 return new rvalue (this, inner
);
893 /* Specialization of making an rvalue from a const, for host <double>. */
898 new_rvalue_from_const
<double> (type
*type
,
901 // FIXME: type-checking, or coercion?
902 tree inner_type
= type
->as_tree ();
904 /* We have a "double", we want a REAL_VALUE_TYPE.
906 real.cc:real_from_target appears to require the representation to be
907 split into 32-bit values, and then sent as an pair of host long
909 REAL_VALUE_TYPE real_value
;
913 uint32_t as_uint32s
[2];
916 long int as_long_ints
[2];
917 as_long_ints
[0] = u
.as_uint32s
[0];
918 as_long_ints
[1] = u
.as_uint32s
[1];
919 real_from_target (&real_value
, as_long_ints
, DFmode
);
920 tree inner
= build_real (inner_type
, real_value
);
921 return new rvalue (this, inner
);
924 /* Specialization of making an rvalue from a const, for host <void *>. */
929 new_rvalue_from_const
<void *> (type
*type
,
932 tree inner_type
= type
->as_tree ();
933 /* FIXME: how to ensure we have a wide enough type? */
934 tree inner
= build_int_cstu (inner_type
, (unsigned HOST_WIDE_INT
)value
);
935 return new rvalue (this, inner
);
938 /* We're done implementing the specializations of
939 gcc::jit::playback::context::new_rvalue_from_const <T>
940 so we can exit the gcc::jit::playback namespace. */
942 } // namespace playback
944 /* Construct a playback::rvalue instance (wrapping a tree). */
948 new_string_literal (const char *value
)
950 /* Compare with c-family/c-common.cc: fix_string_type. */
951 size_t len
= strlen (value
);
952 tree i_type
= build_index_type (size_int (len
));
953 tree a_type
= build_array_type (char_type_node
, i_type
);
954 /* build_string len parameter must include NUL terminator when
955 building C strings. */
956 tree t_str
= ::build_string (len
+ 1, value
);
957 TREE_TYPE (t_str
) = a_type
;
959 /* Convert to (const char*), loosely based on
960 c/c-typeck.cc: array_to_pointer_conversion,
961 by taking address of start of string. */
962 tree t_addr
= build1 (ADDR_EXPR
, m_const_char_ptr
, t_str
);
964 return new rvalue (this, t_addr
);
967 /* Construct a playback::rvalue instance (wrapping a tree) for a
971 playback::context::new_rvalue_from_vector (location
*,
973 const auto_vec
<rvalue
*> &elements
)
975 vec
<constructor_elt
, va_gc
> *v
;
976 vec_alloc (v
, elements
.length ());
977 for (unsigned i
= 0; i
< elements
.length (); ++i
)
978 CONSTRUCTOR_APPEND_ELT (v
, NULL_TREE
, elements
[i
]->as_tree ());
979 tree t_ctor
= build_constructor (type
->as_tree (), v
);
980 return new rvalue (this, t_ctor
);
983 /* Coerce a tree expression into a boolean tree expression. */
987 as_truth_value (tree expr
, location
*loc
)
989 /* Compare to c-typeck.cc:c_objc_common_truthvalue_conversion */
990 tree typed_zero
= fold_build1 (CONVERT_EXPR
,
994 set_tree_location (typed_zero
, loc
);
996 expr
= fold_build2_loc (UNKNOWN_LOCATION
,
997 NE_EXPR
, integer_type_node
, expr
, typed_zero
);
999 set_tree_location (expr
, loc
);
1004 /* Add a "top-level" basic asm statement (i.e. one outside of any functions)
1005 containing ASM_STMTS.
1007 Compare with c_parser_asm_definition. */
1010 playback::context::add_top_level_asm (const char *asm_stmts
)
1012 tree asm_str
= build_string (asm_stmts
);
1013 symtab
->finalize_toplevel_asm (asm_str
);
1016 /* Construct a playback::rvalue instance (wrapping a tree) for a
1021 new_unary_op (location
*loc
,
1022 enum gcc_jit_unary_op op
,
1026 // FIXME: type-checking, or coercion?
1027 enum tree_code inner_op
;
1029 gcc_assert (result_type
);
1032 tree node
= a
->as_tree ();
1033 node
= fold_const_var (node
);
1035 tree inner_result
= NULL
;
1040 add_error (loc
, "unrecognized (enum gcc_jit_unary_op) value: %i", op
);
1043 case GCC_JIT_UNARY_OP_MINUS
:
1044 inner_op
= NEGATE_EXPR
;
1047 case GCC_JIT_UNARY_OP_BITWISE_NEGATE
:
1048 inner_op
= BIT_NOT_EXPR
;
1051 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE
:
1052 node
= as_truth_value (node
, loc
);
1053 inner_result
= invert_truthvalue (node
);
1055 set_tree_location (inner_result
, loc
);
1056 return new rvalue (this, inner_result
);
1058 case GCC_JIT_UNARY_OP_ABS
:
1059 inner_op
= ABS_EXPR
;
1063 inner_result
= build1 (inner_op
,
1064 result_type
->as_tree (),
1068 inner_result
= fold (inner_result
);
1071 set_tree_location (inner_result
, loc
);
1073 return new rvalue (this, inner_result
);
1076 /* Construct a playback::rvalue instance (wrapping a tree) for a
1081 new_binary_op (location
*loc
,
1082 enum gcc_jit_binary_op op
,
1084 rvalue
*a
, rvalue
*b
)
1086 // FIXME: type-checking, or coercion?
1087 enum tree_code inner_op
;
1089 gcc_assert (result_type
);
1093 tree node_a
= a
->as_tree ();
1094 node_a
= fold_const_var (node_a
);
1096 tree node_b
= b
->as_tree ();
1097 node_b
= fold_const_var (node_b
);
1102 add_error (loc
, "unrecognized (enum gcc_jit_binary_op) value: %i", op
);
1105 case GCC_JIT_BINARY_OP_PLUS
:
1106 inner_op
= PLUS_EXPR
;
1109 case GCC_JIT_BINARY_OP_MINUS
:
1110 inner_op
= MINUS_EXPR
;
1113 case GCC_JIT_BINARY_OP_MULT
:
1114 inner_op
= MULT_EXPR
;
1117 case GCC_JIT_BINARY_OP_DIVIDE
:
1118 if (FLOAT_TYPE_P (result_type
->as_tree ()))
1119 /* Floating-point division: */
1120 inner_op
= RDIV_EXPR
;
1122 /* Truncating to zero: */
1123 inner_op
= TRUNC_DIV_EXPR
;
1126 case GCC_JIT_BINARY_OP_MODULO
:
1127 inner_op
= TRUNC_MOD_EXPR
;
1130 case GCC_JIT_BINARY_OP_BITWISE_AND
:
1131 inner_op
= BIT_AND_EXPR
;
1134 case GCC_JIT_BINARY_OP_BITWISE_XOR
:
1135 inner_op
= BIT_XOR_EXPR
;
1138 case GCC_JIT_BINARY_OP_BITWISE_OR
:
1139 inner_op
= BIT_IOR_EXPR
;
1142 case GCC_JIT_BINARY_OP_LOGICAL_AND
:
1143 node_a
= as_truth_value (node_a
, loc
);
1144 node_b
= as_truth_value (node_b
, loc
);
1145 inner_op
= TRUTH_ANDIF_EXPR
;
1148 case GCC_JIT_BINARY_OP_LOGICAL_OR
:
1149 node_a
= as_truth_value (node_a
, loc
);
1150 node_b
= as_truth_value (node_b
, loc
);
1151 inner_op
= TRUTH_ORIF_EXPR
;
1154 case GCC_JIT_BINARY_OP_LSHIFT
:
1155 inner_op
= LSHIFT_EXPR
;
1158 case GCC_JIT_BINARY_OP_RSHIFT
:
1159 inner_op
= RSHIFT_EXPR
;
1163 tree inner_expr
= build2 (inner_op
,
1164 result_type
->as_tree (),
1168 /* Try to fold the expression. */
1169 inner_expr
= fold (inner_expr
);
1172 set_tree_location (inner_expr
, loc
);
1174 return new rvalue (this, inner_expr
);
1177 /* Construct a playback::rvalue instance (wrapping a tree) for a
1182 new_comparison (location
*loc
,
1183 enum gcc_jit_comparison op
,
1184 rvalue
*a
, rvalue
*b
)
1186 // FIXME: type-checking, or coercion?
1187 enum tree_code inner_op
;
1195 add_error (loc
, "unrecognized (enum gcc_jit_comparison) value: %i", op
);
1198 case GCC_JIT_COMPARISON_EQ
:
1201 case GCC_JIT_COMPARISON_NE
:
1204 case GCC_JIT_COMPARISON_LT
:
1207 case GCC_JIT_COMPARISON_LE
:
1210 case GCC_JIT_COMPARISON_GT
:
1213 case GCC_JIT_COMPARISON_GE
:
1218 tree node_a
= a
->as_tree ();
1219 node_a
= fold_const_var (node_a
);
1220 tree node_b
= b
->as_tree ();
1221 node_b
= fold_const_var (node_b
);
1223 tree inner_expr
= build2 (inner_op
,
1229 inner_expr
= fold (inner_expr
);
1232 set_tree_location (inner_expr
, loc
);
1233 return new rvalue (this, inner_expr
);
1236 /* Construct a playback::rvalue instance (wrapping a tree) for a
1241 build_call (location
*loc
,
1243 const auto_vec
<rvalue
*> *args
,
1244 bool require_tail_call
)
1246 vec
<tree
, va_gc
> *tree_args
;
1247 vec_alloc (tree_args
, args
->length ());
1248 for (unsigned i
= 0; i
< args
->length (); i
++)
1249 tree_args
->quick_push ((*args
)[i
]->as_tree ());
1252 set_tree_location (fn_ptr
, loc
);
1254 tree fn
= TREE_TYPE (fn_ptr
);
1255 tree fn_type
= TREE_TYPE (fn
);
1256 tree return_type
= TREE_TYPE (fn_type
);
1258 tree call
= build_call_vec (return_type
,
1261 if (require_tail_call
)
1262 CALL_EXPR_MUST_TAIL_CALL (call
) = 1;
1264 return new rvalue (this, call
);
1266 /* see c-typeck.cc: build_function_call
1267 which calls build_function_call_vec
1269 which does lots of checking, then:
1270 result = build_call_array_loc (loc, TREE_TYPE (fntype),
1271 function, nargs, argarray);
1273 (see also build_call_vec)
1277 /* Construct a playback::rvalue instance (wrapping a tree) for a
1278 call to a specific function. */
1282 new_call (location
*loc
,
1284 const auto_vec
<rvalue
*> *args
,
1285 bool require_tail_call
)
1291 fndecl
= func
->as_fndecl ();
1293 tree fntype
= TREE_TYPE (fndecl
);
1295 tree fn
= build1 (ADDR_EXPR
, build_pointer_type (fntype
), fndecl
);
1297 return build_call (loc
, fn
, args
, require_tail_call
);
1300 /* Construct a playback::rvalue instance (wrapping a tree) for a
1301 call through a function pointer. */
1305 new_call_through_ptr (location
*loc
,
1307 const auto_vec
<rvalue
*> *args
,
1308 bool require_tail_call
)
1310 gcc_assert (fn_ptr
);
1311 tree t_fn_ptr
= fn_ptr
->as_tree ();
1313 return build_call (loc
, t_fn_ptr
, args
, require_tail_call
);
1316 /* Construct a tree for a cast. */
1319 playback::context::build_cast (playback::location
*loc
,
1320 playback::rvalue
*expr
,
1321 playback::type
*type_
)
1323 /* For comparison, see:
1324 - c/c-typeck.cc:build_c_cast
1325 - c/c-convert.cc: convert
1328 Only some kinds of cast are currently supported here. */
1329 tree t_expr
= expr
->as_tree ();
1330 t_expr
= fold_const_var (t_expr
);
1332 tree t_dst_type
= type_
->as_tree ();
1334 t_ret
= targetm
.convert_to_type (t_dst_type
, t_expr
);
1337 enum tree_code dst_code
= TREE_CODE (t_dst_type
);
1342 t_ret
= convert_to_integer (t_dst_type
, t_expr
);
1346 /* Compare with c_objc_common_truthvalue_conversion and
1347 c_common_truthvalue_conversion. */
1348 /* For now, convert to: (t_expr != 0) */
1349 t_ret
= build2 (NE_EXPR
, t_dst_type
,
1351 build_int_cst (TREE_TYPE (t_expr
), 0));
1355 t_ret
= convert_to_real (t_dst_type
, t_expr
);
1359 t_ret
= build1 (NOP_EXPR
, t_dst_type
, t_expr
);
1363 add_error (loc
, "couldn't handle cast during playback");
1364 fprintf (stderr
, "input expression:\n");
1365 debug_tree (t_expr
);
1366 fprintf (stderr
, "requested type:\n");
1367 debug_tree (t_dst_type
);
1368 return error_mark_node
;
1371 if (TREE_CODE (t_ret
) != C_MAYBE_CONST_EXPR
)
1372 t_ret
= fold (t_ret
);
1377 /* Construct a playback::rvalue instance (wrapping a tree) for a
1382 new_cast (playback::location
*loc
,
1383 playback::rvalue
*expr
,
1384 playback::type
*type_
)
1387 tree t_cast
= build_cast (loc
, expr
, type_
);
1389 set_tree_location (t_cast
, loc
);
1390 return new rvalue (this, t_cast
);
1393 /* Construct a playback::lvalue instance (wrapping a tree) for an
1398 new_array_access (location
*loc
,
1405 /* For comparison, see:
1406 c/c-typeck.cc: build_array_ref
1407 c-family/c-common.cc: pointer_int_sum
1409 tree t_ptr
= ptr
->as_tree ();
1410 t_ptr
= fold_const_var (t_ptr
);
1411 tree t_index
= index
->as_tree ();
1412 t_index
= fold_const_var (t_index
);
1414 tree t_type_ptr
= TREE_TYPE (t_ptr
);
1415 tree t_type_star_ptr
= TREE_TYPE (t_type_ptr
);
1417 if (TREE_CODE (t_type_ptr
) == ARRAY_TYPE
)
1419 tree t_result
= build4 (ARRAY_REF
, t_type_star_ptr
, t_ptr
, t_index
,
1420 NULL_TREE
, NULL_TREE
);
1421 t_result
= fold (t_result
);
1423 set_tree_location (t_result
, loc
);
1424 return new lvalue (this, t_result
);
1428 /* Convert index to an offset in bytes. */
1429 tree t_sizeof
= size_in_bytes (t_type_star_ptr
);
1430 t_index
= fold_build1 (CONVERT_EXPR
, sizetype
, t_index
);
1431 tree t_offset
= fold_build2_loc (UNKNOWN_LOCATION
,
1432 MULT_EXPR
, sizetype
, t_index
, t_sizeof
);
1434 /* Locate (ptr + offset). */
1435 tree t_address
= fold_build2_loc (UNKNOWN_LOCATION
,
1436 POINTER_PLUS_EXPR
, t_type_ptr
, t_ptr
, t_offset
);
1438 tree t_indirection
= fold_build1 (INDIRECT_REF
, t_type_star_ptr
, t_address
);
1441 set_tree_location (t_sizeof
, loc
);
1442 set_tree_location (t_offset
, loc
);
1443 set_tree_location (t_address
, loc
);
1444 set_tree_location (t_indirection
, loc
);
1447 return new lvalue (this, t_indirection
);
1451 /* Construct a tree for a field access. */
1455 new_field_access (location
*loc
,
1462 /* Compare with c/c-typeck.cc:lookup_field, build_indirect_ref, and
1463 build_component_ref. */
1464 tree type
= TREE_TYPE (datum
);
1466 gcc_assert (TREE_CODE (type
) != POINTER_TYPE
);
1468 tree t_field
= field
->as_tree ();
1469 tree ref
= build3 (COMPONENT_REF
, TREE_TYPE (t_field
), datum
,
1470 t_field
, NULL_TREE
);
1472 set_tree_location (ref
, loc
);
1476 /* Construct a tree for a dereference. */
1480 new_dereference (tree ptr
,
1485 tree type
= TREE_TYPE (TREE_TYPE(ptr
));
1486 tree datum
= fold_build1 (INDIRECT_REF
, type
, ptr
);
1488 set_tree_location (datum
, loc
);
1492 /* Construct a playback::type instance (wrapping a tree)
1493 with the given alignment. */
1497 get_aligned (size_t alignment_in_bytes
) const
1499 tree t_new_type
= build_variant_type_copy (m_inner
);
1501 SET_TYPE_ALIGN (t_new_type
, alignment_in_bytes
* BITS_PER_UNIT
);
1502 TYPE_USER_ALIGN (t_new_type
) = 1;
1504 return new type (t_new_type
);
1507 /* Construct a playback::type instance (wrapping a tree)
1508 for the given vector type. */
1512 get_vector (size_t num_units
) const
1514 tree t_new_type
= build_vector_type (m_inner
, num_units
);
1515 return new type (t_new_type
);
1518 /* Construct a playback::lvalue instance (wrapping a tree) for a
1523 access_field (location
*loc
,
1526 tree datum
= as_tree ();
1527 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1530 return new lvalue (get_context (), ref
);
1533 /* Construct a playback::rvalue instance (wrapping a tree) for a
1538 access_field (location
*loc
,
1541 tree datum
= as_tree ();
1542 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1545 return new rvalue (get_context (), ref
);
1548 /* Construct a playback::lvalue instance (wrapping a tree) for a
1549 dereferenced field access. */
1553 dereference_field (location
*loc
,
1556 tree ptr
= as_tree ();
1557 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1560 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1563 return new lvalue (get_context (), ref
);
1566 /* Construct a playback::lvalue instance (wrapping a tree) for a
1571 dereference (location
*loc
)
1573 tree ptr
= as_tree ();
1574 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1575 return new lvalue (get_context (), datum
);
1578 /* Mark the lvalue saying that we need to be able to take the
1579 address of it; it should not be allocated in a register.
1580 Compare with e.g. c/c-typeck.cc: c_mark_addressable really_atomic_lvalue.
1581 Returns false if a failure occurred (an error will already have been
1582 added to the active context for this case). */
1586 mark_addressable (location
*loc
)
1588 tree x
= as_tree ();;
1591 switch (TREE_CODE (x
))
1594 if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x
, 1)))
1596 gcc_assert (gcc::jit::active_playback_ctxt
);
1598 active_playback_ctxt
->add_error (loc
,
1599 "cannot take address of "
1608 x
= TREE_OPERAND (x
, 0);
1611 case COMPOUND_LITERAL_EXPR
:
1613 TREE_ADDRESSABLE (x
) = 1;
1620 /* (we don't have a concept of a "register" declaration) */
1623 TREE_ADDRESSABLE (x
) = 1;
1630 /* Construct a playback::rvalue instance (wrapping a tree) for an
1635 get_address (location
*loc
)
1637 tree t_lvalue
= as_tree ();
1638 tree t_thistype
= TREE_TYPE (t_lvalue
);
1639 tree t_ptrtype
= build_pointer_type (t_thistype
);
1640 tree ptr
= fold_build1 (ADDR_EXPR
, t_ptrtype
, t_lvalue
);
1642 get_context ()->set_tree_location (ptr
, loc
);
1643 if (mark_addressable (loc
))
1644 return new rvalue (get_context (), ptr
);
1649 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1650 Provide this finalization hook for calling then they are collected,
1651 which calls the finalizer vfunc. This allows them to call "release"
1652 on any vec<> within them. */
1655 wrapper_finalizer (void *ptr
)
1657 playback::wrapper
*wrapper
= reinterpret_cast <playback::wrapper
*> (ptr
);
1658 wrapper
->finalizer ();
1661 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1662 allocate them using ggc_internal_cleared_alloc. */
1666 operator new (size_t sz
)
1668 return ggc_internal_cleared_alloc (sz
, wrapper_finalizer
, 0, 1);
1672 /* Constructor for gcc:jit::playback::function. */
1674 playback::function::
1675 function (context
*ctxt
,
1677 enum gcc_jit_function_kind kind
)
1679 m_inner_fndecl (fndecl
),
1680 m_inner_bind_expr (NULL
),
1684 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1686 /* Create a BIND_EXPR, and within it, a statement list. */
1687 m_stmt_list
= alloc_stmt_list ();
1688 m_stmt_iter
= tsi_start (m_stmt_list
);
1689 m_inner_block
= make_node (BLOCK
);
1691 build3 (BIND_EXPR
, void_type_node
, NULL
, m_stmt_list
, m_inner_block
);
1695 m_inner_block
= NULL
;
1700 /* Hand-written GC-marking hook for playback functions. */
1703 playback::function::
1706 gt_ggc_m_9tree_node (m_inner_fndecl
);
1707 gt_ggc_m_9tree_node (m_inner_bind_expr
);
1708 gt_ggc_m_9tree_node (m_stmt_list
);
1709 gt_ggc_m_9tree_node (m_inner_block
);
1712 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1716 playback::function::finalizer ()
1718 m_blocks
.release ();
1721 /* Get the return type of a playback function, in tree form. */
1724 playback::function::
1725 get_return_type_as_tree () const
1727 return TREE_TYPE (TREE_TYPE(m_inner_fndecl
));
1730 /* Construct a new local within this playback::function. */
1733 playback::function::
1734 new_local (location
*loc
,
1740 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
1741 get_identifier (name
),
1743 DECL_CONTEXT (inner
) = this->m_inner_fndecl
;
1745 /* Prepend to BIND_EXPR_VARS: */
1746 DECL_CHAIN (inner
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1747 BIND_EXPR_VARS (m_inner_bind_expr
) = inner
;
1750 set_tree_location (inner
, loc
);
1751 return new lvalue (m_ctxt
, inner
);
1754 /* Construct a new block within this playback::function. */
1757 playback::function::
1758 new_block (const char *name
)
1760 gcc_assert (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
);
1762 block
*result
= new playback::block (this, name
);
1763 m_blocks
.safe_push (result
);
1767 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1768 this playback::function. */
1771 playback::function::get_address (location
*loc
)
1773 tree t_fndecl
= as_fndecl ();
1774 tree t_fntype
= TREE_TYPE (t_fndecl
);
1775 tree t_fnptr
= build1 (ADDR_EXPR
, build_pointer_type (t_fntype
), t_fndecl
);
1777 m_ctxt
->set_tree_location (t_fnptr
, loc
);
1778 return new rvalue (m_ctxt
, t_fnptr
);
1781 /* Build a statement list for the function as a whole out of the
1782 lists of statements for the individual blocks, building labels
1786 playback::function::
1792 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1794 FOR_EACH_VEC_ELT (m_blocks
, i
, b
)
1799 b
->m_label_expr
= build1 (LABEL_EXPR
,
1801 b
->as_label_decl ());
1802 tsi_link_after (&m_stmt_iter
, b
->m_label_expr
, TSI_CONTINUE_LINKING
);
1804 FOR_EACH_VEC_ELT (b
->m_stmts
, j
, stmt
)
1805 tsi_link_after (&m_stmt_iter
, stmt
, TSI_CONTINUE_LINKING
);
1809 /* Finish compiling the given function, potentially running the
1811 The function will have a statement list by now.
1812 Amongst other things, this gimplifies the statement list,
1813 and calls cgraph_node::finalize_function on the function. */
1816 playback::function::
1819 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1821 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
))
1822 debug_tree (m_stmt_list
);
1824 /* Do we need this to force cgraphunit.cc to output the function? */
1825 if (m_kind
== GCC_JIT_FUNCTION_EXPORTED
)
1827 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1828 DECL_PRESERVE_P (m_inner_fndecl
) = 1;
1831 if (m_kind
== GCC_JIT_FUNCTION_INTERNAL
1832 ||m_kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
1834 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1835 TREE_PUBLIC (m_inner_fndecl
) = 0;
1838 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1840 /* Seem to need this in gimple-low.cc: */
1841 gcc_assert (m_inner_block
);
1842 DECL_INITIAL (m_inner_fndecl
) = m_inner_block
;
1844 /* how to add to function? the following appears to be how to
1845 set the body of a m_inner_fndecl: */
1846 DECL_SAVED_TREE(m_inner_fndecl
) = m_inner_bind_expr
;
1848 /* Ensure that locals appear in the debuginfo. */
1849 BLOCK_VARS (m_inner_block
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1851 //debug_tree (m_inner_fndecl);
1853 /* Convert to gimple: */
1854 //printf("about to gimplify_function_tree\n");
1855 gimplify_function_tree (m_inner_fndecl
);
1856 //printf("finished gimplify_function_tree\n");
1858 current_function_decl
= m_inner_fndecl
;
1859 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
))
1860 dump_function_to_file (m_inner_fndecl
, stderr
, TDF_VOPS
|TDF_MEMSYMS
|TDF_LINENO
);
1861 //debug_tree (m_inner_fndecl);
1863 //printf("about to add to cgraph\n");
1864 /* Add to cgraph: */
1865 cgraph_node::finalize_function (m_inner_fndecl
, false);
1866 /* This can trigger a collection, so we need to have all of
1867 the funcs as roots. */
1869 current_function_decl
= NULL
;
1873 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1877 playback::block::finalizer ()
1882 /* Add an eval of the rvalue to the function's statement list. */
1886 add_eval (location
*loc
,
1889 gcc_assert (rvalue
);
1892 set_tree_location (rvalue
->as_tree (), loc
);
1894 add_stmt (rvalue
->as_tree ());
1897 /* Add an assignment to the function's statement list. */
1901 add_assignment (location
*loc
,
1905 gcc_assert (lvalue
);
1906 gcc_assert (rvalue
);
1908 tree t_lvalue
= lvalue
->as_tree ();
1909 tree t_rvalue
= rvalue
->as_tree ();
1910 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1912 t_rvalue
= build1 (CONVERT_EXPR
,
1913 TREE_TYPE (t_lvalue
),
1916 set_tree_location (t_rvalue
, loc
);
1920 build2 (MODIFY_EXPR
, TREE_TYPE (t_lvalue
),
1921 t_lvalue
, t_rvalue
);
1923 set_tree_location (stmt
, loc
);
1927 /* Add a comment to the function's statement list.
1928 For now this is done by adding a dummy label. */
1932 add_comment (location
*loc
,
1935 /* Wrap the text in C-style comment delimiters. */
1937 (3 /* opening delim */
1939 + 3 /* closing delim */
1940 + 1 /* terminator */);
1941 char *wrapped
= (char *)ggc_internal_alloc (sz
);
1942 snprintf (wrapped
, sz
, "/* %s */", text
);
1944 /* For now we simply implement this by adding a dummy label with a name
1945 containing the given text. */
1946 tree identifier
= get_identifier (wrapped
);
1947 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1948 identifier
, void_type_node
);
1949 DECL_CONTEXT (label_decl
) = m_func
->as_fndecl ();
1951 tree label_expr
= build1 (LABEL_EXPR
, void_type_node
, label_decl
);
1953 set_tree_location (label_expr
, loc
);
1954 add_stmt (label_expr
);
1957 /* Add a conditional jump statement to the function's statement list. */
1961 add_conditional (location
*loc
,
1966 gcc_assert (boolval
);
1967 gcc_assert (on_true
);
1968 gcc_assert (on_false
);
1970 /* COND_EXPR wants statement lists for the true/false operands, but we
1972 Shim it by creating jumps to the labels */
1973 tree true_jump
= build1 (GOTO_EXPR
, void_type_node
,
1974 on_true
->as_label_decl ());
1976 set_tree_location (true_jump
, loc
);
1978 tree false_jump
= build1 (GOTO_EXPR
, void_type_node
,
1979 on_false
->as_label_decl ());
1981 set_tree_location (false_jump
, loc
);
1984 build3 (COND_EXPR
, void_type_node
, boolval
->as_tree (),
1985 true_jump
, false_jump
);
1987 set_tree_location (stmt
, loc
);
1991 /* Add an unconditional jump statement to the function's statement list. */
1995 add_jump (location
*loc
,
1998 gcc_assert (target
);
2000 // see c_finish_loop
2001 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
2004 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
2005 TREE_USED (target
->as_label_decl ()) = 1;
2006 tree stmt
= build1 (GOTO_EXPR
, void_type_node
, target
->as_label_decl ());
2008 set_tree_location (stmt
, loc
);
2014 c_finish_goto_label (location_t loc, tree label)
2016 tree decl = lookup_label_for_goto (loc, label);
2019 TREE_USED (decl) = 1;
2021 tree t = build1 (GOTO_EXPR, void_type_node, decl);
2022 SET_EXPR_LOCATION (t, loc);
2023 return add_stmt (t);
2030 /* Add a return statement to the function's statement list. */
2034 add_return (location
*loc
,
2037 tree modify_retval
= NULL
;
2038 tree return_type
= m_func
->get_return_type_as_tree ();
2041 tree t_lvalue
= DECL_RESULT (m_func
->as_fndecl ());
2042 tree t_rvalue
= rvalue
->as_tree ();
2043 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
2044 t_rvalue
= build1 (CONVERT_EXPR
,
2045 TREE_TYPE (t_lvalue
),
2047 modify_retval
= build2 (MODIFY_EXPR
, return_type
,
2048 t_lvalue
, t_rvalue
);
2050 set_tree_location (modify_retval
, loc
);
2052 tree return_stmt
= build1 (RETURN_EXPR
, return_type
,
2055 set_tree_location (return_stmt
, loc
);
2057 add_stmt (return_stmt
);
2060 /* Helper function for playback::block::add_switch.
2061 Construct a case label for the given range, followed by a goto stmt
2062 to the given block, appending them to stmt list *ptr_t_switch_body. */
2065 add_case (tree
*ptr_t_switch_body
,
2068 playback::block
*dest_block
)
2070 tree t_label
= create_artificial_label (UNKNOWN_LOCATION
);
2071 DECL_CONTEXT (t_label
) = dest_block
->get_function ()->as_fndecl ();
2074 build_case_label (t_low_value
, t_high_value
, t_label
);
2075 append_to_statement_list (t_case_label
, ptr_t_switch_body
);
2078 build1 (GOTO_EXPR
, void_type_node
, dest_block
->as_label_decl ());
2079 append_to_statement_list (t_goto_stmt
, ptr_t_switch_body
);
2082 /* Add a switch statement to the function's statement list.
2084 We create a switch body, and populate it with case labels, each
2085 followed by a goto to the desired block. */
2089 add_switch (location
*loc
,
2091 block
*default_block
,
2092 const auto_vec
<case_
> *cases
)
2095 - c/c-typeck.cc: c_start_case
2096 - c-family/c-common.cc:c_add_case_label
2097 - java/expr.cc:expand_java_switch and expand_java_add_case
2098 We've already rejected overlaps and duplicates in
2099 libgccjit.cc:case_range_validator::validate. */
2101 tree t_expr
= expr
->as_tree ();
2102 tree t_type
= TREE_TYPE (t_expr
);
2104 tree t_switch_body
= alloc_stmt_list ();
2108 FOR_EACH_VEC_ELT (*cases
, i
, c
)
2110 tree t_low_value
= c
->m_min_value
->as_tree ();
2111 tree t_high_value
= c
->m_max_value
->as_tree ();
2112 add_case (&t_switch_body
, t_low_value
, t_high_value
, c
->m_dest_block
);
2114 /* Default label. */
2115 add_case (&t_switch_body
, NULL_TREE
, NULL_TREE
, default_block
);
2117 tree switch_stmt
= build2 (SWITCH_EXPR
, t_type
, t_expr
, t_switch_body
);
2119 set_tree_location (switch_stmt
, loc
);
2120 add_stmt (switch_stmt
);
2123 /* Convert OPERANDS to a tree-based chain suitable for creating an
2125 Compare with c_parser_asm_operands. */
2128 build_operand_chain (const auto_vec
<playback::asm_operand
> *operands
)
2130 tree result
= NULL_TREE
;
2132 playback::asm_operand
*asm_op
;
2133 FOR_EACH_VEC_ELT (*operands
, i
, asm_op
)
2135 tree name
= build_string (asm_op
->m_asm_symbolic_name
);
2136 tree str
= build_string (asm_op
->m_constraint
);
2137 tree value
= asm_op
->m_expr
;
2138 result
= chainon (result
,
2139 build_tree_list (build_tree_list (name
, str
),
2145 /* Convert CLOBBERS to a tree-based list suitable for creating an
2147 Compare with c_parser_asm_clobbers. */
2150 build_clobbers (const auto_vec
<const char *> *clobbers
)
2152 tree list
= NULL_TREE
;
2154 const char *clobber
;
2155 FOR_EACH_VEC_ELT (*clobbers
, i
, clobber
)
2157 tree str
= build_string (clobber
);
2158 list
= tree_cons (NULL_TREE
, str
, list
);
2163 /* Convert BLOCKS to a tree-based list suitable for creating an
2165 Compare with c_parser_asm_goto_operands. */
2168 build_goto_operands (const auto_vec
<playback::block
*> *blocks
)
2170 tree list
= NULL_TREE
;
2173 FOR_EACH_VEC_ELT (*blocks
, i
, b
)
2175 tree label
= b
->as_label_decl ();
2176 tree name
= build_string (IDENTIFIER_POINTER (DECL_NAME (label
)));
2177 TREE_USED (label
) = 1;
2178 list
= tree_cons (name
, label
, list
);
2180 return nreverse (list
);
2183 /* Add an extended asm statement to this block.
2185 Compare with c_parser_asm_statement (in c/c-parser.cc)
2186 and build_asm_expr (in c/c-typeck.cc). */
2189 playback::block::add_extended_asm (location
*loc
,
2190 const char *asm_template
,
2193 const auto_vec
<asm_operand
> *outputs
,
2194 const auto_vec
<asm_operand
> *inputs
,
2195 const auto_vec
<const char *> *clobbers
,
2196 const auto_vec
<block
*> *goto_blocks
)
2198 tree t_string
= build_string (asm_template
);
2199 tree t_outputs
= build_operand_chain (outputs
);
2200 tree t_inputs
= build_operand_chain (inputs
);
2201 tree t_clobbers
= build_clobbers (clobbers
);
2202 tree t_labels
= build_goto_operands (goto_blocks
);
2204 = resolve_asm_operand_names (t_string
, t_outputs
, t_inputs
, t_labels
);
2206 = build5 (ASM_EXPR
, void_type_node
,
2207 t_string
, t_outputs
, t_inputs
, t_clobbers
, t_labels
);
2209 /* asm statements without outputs, including simple ones, are treated
2211 ASM_VOLATILE_P (asm_stmt
) = (outputs
->length () == 0);
2212 ASM_INPUT_P (asm_stmt
) = 0; /* extended asm stmts are not "simple". */
2213 ASM_INLINE_P (asm_stmt
) = is_inline
;
2215 ASM_VOLATILE_P (asm_stmt
) = 1;
2217 set_tree_location (asm_stmt
, loc
);
2218 add_stmt (asm_stmt
);
2221 /* Constructor for gcc::jit::playback::block. */
2224 block (function
*func
,
2234 identifier
= get_identifier (name
);
2237 m_label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
2238 identifier
, void_type_node
);
2239 DECL_CONTEXT (m_label_decl
) = func
->as_fndecl ();
2240 m_label_expr
= NULL
;
2243 /* Compile a playback::context:
2245 - Use the context's options to cconstruct command-line options, and
2246 call into the rest of GCC (toplev::main).
2247 - Assuming it succeeds, we have a .s file.
2248 - We then run the "postprocess" vfunc:
2250 (A) In-memory compile ("gcc_jit_context_compile")
2252 For an in-memory compile we have the playback::compile_to_memory
2253 subclass; "postprocess" will convert the .s file to a .so DSO,
2254 and load it in memory (via dlopen), wrapping the result up as
2255 a jit::result and returning it.
2257 (B) Compile to file ("gcc_jit_context_compile_to_file")
2259 When compiling to a file, we have the playback::compile_to_file
2260 subclass; "postprocess" will either copy the .s file to the
2261 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
2262 the driver to convert it as necessary, copying the result. */
2268 JIT_LOG_SCOPE (get_logger ());
2270 const char *ctxt_progname
;
2272 int keep_intermediates
=
2273 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
);
2275 m_tempdir
= new tempdir (get_logger (), keep_intermediates
);
2276 if (!m_tempdir
->create ())
2279 /* Call into the rest of gcc.
2280 For now, we have to assemble command-line options to pass into
2281 toplev::main, so that they can be parsed. */
2283 /* Pass in user-provided program name as argv0, if any, so that it
2284 makes it into GCC's "progname" global, used in various diagnostics. */
2285 ctxt_progname
= get_str_option (GCC_JIT_STR_OPTION_PROGNAME
);
2288 ctxt_progname
= "libgccjit.so";
2290 auto_vec
<recording::requested_dump
> requested_dumps
;
2291 m_recording_ctxt
->get_all_requested_dumps (&requested_dumps
);
2293 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
2296 auto_string_vec fake_args
;
2297 make_fake_args (&fake_args
, ctxt_progname
, &requested_dumps
);
2298 if (errors_occurred ())
2304 /* This runs the compiler. */
2305 toplev
toplev (get_timer (), /* external_timer */
2306 false); /* init_signals */
2307 enter_scope ("toplev::main");
2309 for (unsigned i
= 0; i
< fake_args
.length (); i
++)
2310 get_logger ()->log ("argv[%i]: %s", i
, fake_args
[i
]);
2311 toplev
.main (fake_args
.length (),
2312 const_cast <char **> (fake_args
.address ()));
2313 exit_scope ("toplev::main");
2315 /* Extracting dumps makes use of the gcc::dump_manager, hence we
2316 need to do it between toplev::main (which creates the dump manager)
2317 and toplev::finalize (which deletes it). */
2318 extract_any_requested_dumps (&requested_dumps
);
2320 /* Clean up the compiler. */
2321 enter_scope ("toplev::finalize");
2323 exit_scope ("toplev::finalize");
2325 /* Ideally we would release the jit mutex here, but we can't yet since
2326 followup activities use timevars, which are global state. */
2328 if (errors_occurred ())
2334 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
))
2335 dump_generated_code ();
2337 /* We now have a .s file.
2339 Run any postprocessing steps. This will either convert the .s file to
2340 a .so DSO, and load it in memory (playback::compile_to_memory), or
2341 convert the .s file to the requested output format, and copy it to a
2342 given file (playback::compile_to_file). */
2343 postprocess (ctxt_progname
);
2348 /* Implementation of class gcc::jit::playback::compile_to_memory,
2349 a subclass of gcc::jit::playback::context. */
2351 /* playback::compile_to_memory's trivial constructor. */
2353 playback::compile_to_memory::compile_to_memory (recording::context
*ctxt
) :
2354 playback::context (ctxt
),
2357 JIT_LOG_SCOPE (get_logger ());
2360 /* Implementation of the playback::context::process vfunc for compiling
2363 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
2364 wrapping the result up as a jit::result and returning it. */
2367 playback::compile_to_memory::postprocess (const char *ctxt_progname
)
2369 JIT_LOG_SCOPE (get_logger ());
2370 convert_to_dso (ctxt_progname
);
2371 if (errors_occurred ())
2373 m_result
= dlopen_built_dso ();
2376 /* Implementation of class gcc::jit::playback::compile_to_file,
2377 a subclass of gcc::jit::playback::context. */
2379 /* playback::compile_to_file's trivial constructor. */
2381 playback::compile_to_file::compile_to_file (recording::context
*ctxt
,
2382 enum gcc_jit_output_kind output_kind
,
2383 const char *output_path
) :
2384 playback::context (ctxt
),
2385 m_output_kind (output_kind
),
2386 m_output_path (output_path
)
2388 JIT_LOG_SCOPE (get_logger ());
2391 /* Implementation of the playback::context::process vfunc for compiling
2394 Either copy the .s file to the given destination (for
2395 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
2396 as necessary, copying the result. */
2399 playback::compile_to_file::postprocess (const char *ctxt_progname
)
2401 JIT_LOG_SCOPE (get_logger ());
2403 /* The driver takes different actions based on the filename, so
2404 we provide a filename with an appropriate suffix for the
2405 output kind, and then copy it up to the user-provided path,
2406 rather than directly compiling it to the requested output path. */
2408 switch (m_output_kind
)
2413 case GCC_JIT_OUTPUT_KIND_ASSEMBLER
:
2414 copy_file (get_tempdir ()->get_path_s_file (),
2416 /* The .s file is automatically unlinked by tempdir::~tempdir. */
2419 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE
:
2421 char *tmp_o_path
= ::concat (get_tempdir ()->get_path (),
2424 invoke_driver (ctxt_progname
,
2425 get_tempdir ()->get_path_s_file (),
2428 false, /* bool shared, */
2429 false);/* bool run_linker */
2430 if (!errors_occurred ())
2432 copy_file (tmp_o_path
,
2434 get_tempdir ()->add_temp_file (tmp_o_path
);
2441 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY
:
2442 invoke_driver (ctxt_progname
,
2443 get_tempdir ()->get_path_s_file (),
2444 get_tempdir ()->get_path_so_file (),
2446 true, /* bool shared, */
2447 true);/* bool run_linker */
2448 if (!errors_occurred ())
2449 copy_file (get_tempdir ()->get_path_so_file (),
2451 /* The .so file is automatically unlinked by tempdir::~tempdir. */
2454 case GCC_JIT_OUTPUT_KIND_EXECUTABLE
:
2456 char *tmp_exe_path
= ::concat (get_tempdir ()->get_path (),
2459 invoke_driver (ctxt_progname
,
2460 get_tempdir ()->get_path_s_file (),
2463 false, /* bool shared, */
2464 true);/* bool run_linker */
2465 if (!errors_occurred ())
2467 copy_file (tmp_exe_path
,
2469 get_tempdir ()->add_temp_file (tmp_exe_path
);
2472 free (tmp_exe_path
);
2480 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2481 the "executable" bits).
2483 Any errors that occur are reported on the context and hence count as
2484 a failure of the compile.
2486 We can't in general hardlink or use "rename" from the tempdir since
2487 it might be on a different filesystem to the destination. For example,
2488 I get EXDEV: "Invalid cross-device link". */
2491 playback::compile_to_file::copy_file (const char *src_path
,
2492 const char *dst_path
)
2494 JIT_LOG_SCOPE (get_logger ());
2497 get_logger ()->log ("src_path: %s", src_path
);
2498 get_logger ()->log ("dst_path: %s", dst_path
);
2503 size_t total_sz_in
= 0;
2504 size_t total_sz_out
= 0;
2507 struct stat stat_buf
;
2509 f_in
= fopen (src_path
, "rb");
2513 "unable to open %s for reading: %s",
2519 /* Use stat on the filedescriptor to get the mode,
2520 so that we can copy it over (in particular, the
2521 "executable" bits). */
2522 if (fstat (fileno (f_in
), &stat_buf
) == -1)
2525 "unable to fstat %s: %s",
2532 f_out
= fopen (dst_path
, "wb");
2536 "unable to open %s for writing: %s",
2543 while ( (sz_in
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2545 total_sz_in
+= sz_in
;
2546 size_t sz_out_remaining
= sz_in
;
2547 size_t sz_out_so_far
= 0;
2548 while (sz_out_remaining
)
2550 size_t sz_out
= fwrite (buf
+ sz_out_so_far
,
2554 gcc_assert (sz_out
<= sz_out_remaining
);
2558 "error writing to %s: %s",
2565 total_sz_out
+= sz_out
;
2566 sz_out_so_far
+= sz_out
;
2567 sz_out_remaining
-= sz_out
;
2569 gcc_assert (sz_out_so_far
== sz_in
);
2574 "error reading from %s: %s",
2580 gcc_assert (total_sz_in
== total_sz_out
);
2582 get_logger ()->log ("total bytes copied: %zu", total_sz_out
);
2584 /* fchmod does not exist in Windows. */
2586 /* Set the permissions of the copy to those of the original file,
2587 in particular the "executable" bits. */
2588 if (fchmod (fileno (f_out
), stat_buf
.st_mode
) == -1)
2590 "error setting mode of %s: %s",
2598 /* Helper functions for gcc::jit::playback::context::compile. */
2600 /* This mutex guards gcc::jit::recording::context::compile, so that only
2601 one thread can be accessing the bulk of GCC's state at once. */
2603 static pthread_mutex_t jit_mutex
= PTHREAD_MUTEX_INITIALIZER
;
2605 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2608 playback::context::acquire_mutex ()
2610 auto_timevar
tv (get_timer (), TV_JIT_ACQUIRING_MUTEX
);
2612 /* Acquire the big GCC mutex. */
2613 JIT_LOG_SCOPE (get_logger ());
2614 pthread_mutex_lock (&jit_mutex
);
2615 gcc_assert (active_playback_ctxt
== NULL
);
2616 active_playback_ctxt
= this;
2619 /* Release jit_mutex and clear the active playback ctxt. */
2622 playback::context::release_mutex ()
2624 /* Release the big GCC mutex. */
2625 JIT_LOG_SCOPE (get_logger ());
2626 gcc_assert (active_playback_ctxt
== this);
2627 active_playback_ctxt
= NULL
;
2628 pthread_mutex_unlock (&jit_mutex
);
2631 /* Callback used by gcc::jit::playback::context::make_fake_args when
2632 invoking driver_get_configure_time_options.
2633 Populate a vec <char * > with the configure-time options. */
2636 append_arg_from_driver (const char *option
, void *user_data
)
2638 gcc_assert (option
);
2639 gcc_assert (user_data
);
2640 vec
<char *> *argvec
= static_cast <vec
<char *> *> (user_data
);
2641 argvec
->safe_push (concat ("-", option
, NULL
));
2644 /* Build a fake argv for toplev::main from the options set
2645 by the user on the context . */
2649 make_fake_args (vec
<char *> *argvec
,
2650 const char *ctxt_progname
,
2651 vec
<recording::requested_dump
> *requested_dumps
)
2653 JIT_LOG_SCOPE (get_logger ());
2655 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2656 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2658 ADD_ARG (ctxt_progname
);
2659 ADD_ARG (get_path_c_file ());
2662 /* Handle int options: */
2663 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
))
2667 "unrecognized optimization level: %i",
2668 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
));
2687 /* What about -Os? */
2689 /* Handle bool options: */
2690 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2693 /* Suppress timing (and other) info. */
2694 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
))
2700 /* Aggressively garbage-collect, to shake out bugs: */
2701 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC
))
2703 ADD_ARG ("--param=ggc-min-expand=0");
2704 ADD_ARG ("--param=ggc-min-heapsize=0");
2707 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
))
2709 ADD_ARG ("-fdump-tree-all");
2710 ADD_ARG ("-fdump-rtl-all");
2711 ADD_ARG ("-fdump-ipa-all");
2714 /* Add "-fdump-" options for any calls to
2715 gcc_jit_context_enable_dump. */
2718 recording::requested_dump
*d
;
2719 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2721 char *arg
= concat ("-fdump-", d
->m_dumpname
, NULL
);
2722 ADD_ARG_TAKE_OWNERSHIP (arg
);
2726 /* PR jit/64810: Add any target-specific default options
2727 from OPTION_DEFAULT_SPECS, normally provided by the driver
2728 in the non-jit case.
2730 The target-specific code can define OPTION_DEFAULT_SPECS:
2731 default command options in the form of spec macros for the
2732 driver to expand ().
2734 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2735 if not overriden, injects the defaults as extra arguments to
2737 For the jit case, we need to add these arguments here. The
2738 input format (using the specs language) means that we have to run
2739 part of the driver code here (driver_get_configure_time_options).
2741 To avoid running the spec-expansion code every time, we just do
2742 it the first time (via a function-static flag), saving the result
2743 into a function-static vec.
2744 This flag and vec are global state (i.e. per-process).
2745 They are guarded by the jit mutex. */
2747 static bool have_configure_time_options
= false;
2748 static vec
<char *> configure_time_options
;
2750 if (have_configure_time_options
)
2751 log ("reusing cached configure-time options");
2754 have_configure_time_options
= true;
2755 log ("getting configure-time options from driver");
2756 driver_get_configure_time_options (append_arg_from_driver
,
2757 &configure_time_options
);
2764 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2765 log ("configure_time_options[%i]: %s", i
, opt
);
2767 /* configure_time_options should now contain the expanded options
2768 from OPTION_DEFAULT_SPECS (if any). */
2769 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2772 gcc_assert (opt
[0] == '-');
2778 ADD_ARG ("-ftime-report");
2780 /* Add any user-provided extra options, starting with any from
2782 m_recording_ctxt
->append_command_line_options (argvec
);
2785 #undef ADD_ARG_TAKE_OWNERSHIP
2788 /* The second half of the implementation of gcc_jit_context_enable_dump.
2789 Iterate through the requested dumps, reading the underlying files
2790 into heap-allocated buffers, writing pointers to the buffers into
2791 the char ** pointers provided by client code.
2792 Client code is responsible for calling free on the results. */
2796 extract_any_requested_dumps (vec
<recording::requested_dump
> *requested_dumps
)
2798 JIT_LOG_SCOPE (get_logger ());
2801 recording::requested_dump
*d
;
2802 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2804 dump_file_info
*dfi
;
2808 dfi
= g
->get_dumps ()->get_dump_file_info_by_switch (d
->m_dumpname
);
2811 add_error (NULL
, "unrecognized dump: %s", d
->m_dumpname
);
2815 filename
= g
->get_dumps ()->get_dump_file_name (dfi
);
2816 content
= read_dump_file (filename
);
2817 *(d
->m_out_ptr
) = content
;
2818 m_tempdir
->add_temp_file (filename
);
2822 /* Helper function for playback::context::extract_any_requested_dumps
2823 (itself for use in implementation of gcc_jit_context_enable_dump).
2825 Attempt to read the complete file at the given path, returning the
2826 bytes found there as a buffer.
2827 The caller is responsible for calling free on the result.
2828 Errors will be reported on the context, and lead to NULL being
2829 returned; an out-of-memory error will terminate the process. */
2832 playback::context::read_dump_file (const char *path
)
2834 char *result
= NULL
;
2835 size_t total_sz
= 0;
2840 f_in
= fopen (path
, "r");
2843 add_error (NULL
, "unable to open %s for reading", path
);
2847 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2849 size_t old_total_sz
= total_sz
;
2851 result
= reinterpret_cast <char *> (xrealloc (result
, total_sz
+ 1));
2852 memcpy (result
+ old_total_sz
, buf
, sz
);
2857 add_error (NULL
, "error reading from %s", path
);
2867 result
[total_sz
] = '\0';
2871 return xstrdup ("");
2874 /* Part of playback::context::compile ().
2876 We have a .s file; we want a .so file.
2877 We could reuse parts of gcc/gcc.cc to do this.
2878 For now, just use the driver binary from the install, as
2879 named in gcc-driver-name.h
2880 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2884 convert_to_dso (const char *ctxt_progname
)
2886 JIT_LOG_SCOPE (get_logger ());
2888 invoke_driver (ctxt_progname
,
2889 m_tempdir
->get_path_s_file (),
2890 m_tempdir
->get_path_so_file (),
2892 true, /* bool shared, */
2893 true);/* bool run_linker */
2896 static const char * const gcc_driver_name
= GCC_DRIVER_NAME
;
2900 invoke_driver (const char *ctxt_progname
,
2901 const char *input_file
,
2902 const char *output_file
,
2907 JIT_LOG_SCOPE (get_logger ());
2909 bool embedded_driver
2910 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER
);
2912 /* Currently this lumps together both assembling and linking into
2914 auto_timevar
assemble_timevar (get_timer (), tv_id
);
2915 auto_string_vec argvec
;
2916 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2918 ADD_ARG (gcc_driver_name
);
2920 add_multilib_driver_arguments (&argvec
);
2923 ADD_ARG ("-shared");
2928 ADD_ARG (input_file
);
2930 ADD_ARG (output_file
);
2932 /* Don't use the linker plugin.
2933 If running with just a "make" and not a "make install", then we'd
2935 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2936 libto_plugin is a .la at build time, with it becoming installed with
2937 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2939 ADD_ARG ("-fno-use-linker-plugin");
2941 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2942 /* OS X's linker defaults to treating undefined symbols as errors.
2943 If the context has any imported functions or globals they will be
2944 undefined until the .so is dynamically-linked into the process.
2945 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2947 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2953 /* Add any user-provided driver extra options. */
2955 m_recording_ctxt
->append_driver_options (&argvec
);
2959 /* pex_one's error-handling requires pname to be non-NULL. */
2960 gcc_assert (ctxt_progname
);
2963 for (unsigned i
= 0; i
< argvec
.length (); i
++)
2964 get_logger ()->log ("argv[%i]: %s", i
, argvec
[i
]);
2966 if (embedded_driver
)
2967 invoke_embedded_driver (&argvec
);
2969 invoke_external_driver (ctxt_progname
, &argvec
);
2974 invoke_embedded_driver (const vec
<char *> *argvec
)
2976 JIT_LOG_SCOPE (get_logger ());
2977 driver
d (true, /* can_finalize */
2979 int result
= d
.main (argvec
->length (),
2980 const_cast <char **> (argvec
->address ()));
2983 add_error (NULL
, "error invoking gcc driver");
2988 invoke_external_driver (const char *ctxt_progname
,
2989 vec
<char *> *argvec
)
2991 JIT_LOG_SCOPE (get_logger ());
2993 int exit_status
= 0;
2996 /* pex argv arrays are NULL-terminated. */
2997 argvec
->safe_push (NULL
);
2999 errmsg
= pex_one (PEX_SEARCH
, /* int flags, */
3001 const_cast <char *const *> (argvec
->address ()),
3002 ctxt_progname
, /* const char *pname */
3003 NULL
, /* const char *outname */
3004 NULL
, /* const char *errname */
3005 &exit_status
, /* int *status */
3006 &err
); /* int *err*/
3009 add_error (NULL
, "error invoking gcc driver: %s", errmsg
);
3013 /* pex_one can return a NULL errmsg when the executable wasn't
3014 found (or doesn't exist), so trap these cases also. */
3015 if (exit_status
|| err
)
3018 "error invoking gcc driver: exit_status: %i err: %i",
3021 "whilst attempting to run a driver named: %s",
3030 /* Extract the target-specific MULTILIB_DEFAULTS to
3031 multilib_defaults_raw for use by
3032 playback::context::add_multilib_driver_arguments (). */
3034 #ifndef MULTILIB_DEFAULTS
3035 #define MULTILIB_DEFAULTS { "" }
3038 static const char *const multilib_defaults_raw
[] = MULTILIB_DEFAULTS
;
3040 /* Helper function for playback::context::invoke_driver ().
3042 32-bit and 64-bit multilib peer builds of libgccjit.so may share
3043 a driver binary. We need to pass in options to the shared driver
3044 to get the appropriate assembler/linker options for this multilib
3049 add_multilib_driver_arguments (vec
<char *> *argvec
)
3051 JIT_LOG_SCOPE (get_logger ());
3053 /* Add copies of the arguments in multilib_defaults_raw to argvec,
3054 prepending each with a "-". */
3055 for (size_t i
= 0; i
< ARRAY_SIZE (multilib_defaults_raw
); i
++)
3056 if (multilib_defaults_raw
[i
][0])
3057 argvec
->safe_push (concat ("-", multilib_defaults_raw
[i
], NULL
));
3060 /* Dynamically-link the built DSO file into this process, using dlopen.
3061 Wrap it up within a jit::result *, and return that.
3062 Return NULL if any errors occur, reporting them on this context. */
3068 JIT_LOG_SCOPE (get_logger ());
3069 auto_timevar
load_timevar (get_timer (), TV_LOAD
);
3070 result::handle handle
= NULL
;
3071 result
*result_obj
= NULL
;
3074 /* Clear any existing error. */
3077 handle
= LoadLibrary(m_tempdir
->get_path_so_file ());
3078 if (GetLastError() != 0) {
3082 const char *error
= NULL
;
3083 /* Clear any existing error. */
3086 handle
= dlopen (m_tempdir
->get_path_so_file (),
3087 RTLD_NOW
| RTLD_LOCAL
);
3088 if ((error
= dlerror()) != NULL
) {
3089 add_error (NULL
, "%s", error
);
3095 /* We've successfully dlopened the result; create a
3096 jit::result object to wrap it.
3098 We're done with the tempdir for now, but if the user
3099 has requested debugging, the user's debugger might not
3100 be capable of dealing with the .so file being unlinked
3101 immediately, so keep it around until after the result
3102 is released. We do this by handing over ownership of
3103 the jit::tempdir to the result. See PR jit/64206. */
3104 tempdir
*handover_tempdir
;
3105 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
3107 handover_tempdir
= m_tempdir
;
3109 /* The tempdir will eventually be cleaned up in the
3110 jit::result's dtor. */
3111 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
3112 " handing over tempdir to jit::result");
3116 handover_tempdir
= NULL
;
3117 /* ... and retain ownership of m_tempdir so we clean it
3118 up it the playback::context's dtor. */
3119 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
3120 " retaining ownership of tempdir");
3123 result_obj
= new result (get_logger (), handle
, handover_tempdir
);
3131 /* Top-level hook for playing back a recording context.
3133 This plays back m_recording_ctxt, and, if no errors
3134 occurred builds statement lists for and then postprocesses
3135 every function in the result. */
3141 JIT_LOG_SCOPE (get_logger ());
3145 /* Replay the recorded events: */
3146 timevar_push (TV_JIT_REPLAY
);
3148 /* Ensure that builtins that could be needed during optimization
3149 get created ahead of time. */
3150 builtins_manager
*bm
= m_recording_ctxt
->get_builtins_manager ();
3151 bm
->ensure_optimization_builtins_exist ();
3153 m_recording_ctxt
->replay_into (this);
3155 /* Clean away the temporary references from recording objects
3156 to playback objects. We have to do this now since the
3157 latter are GC-allocated, but the former don't mark these
3158 refs. Hence we must stop using them before the GC can run. */
3159 m_recording_ctxt
->disassociate_from_playback ();
3161 /* The builtins_manager is associated with the recording::context
3162 and might be reused for future compiles on other playback::contexts,
3163 but its m_attributes array is not GTY-labeled and hence will become
3164 nonsense if the GC runs. Purge this state. */
3165 bm
->finish_playback ();
3167 timevar_pop (TV_JIT_REPLAY
);
3169 if (!errors_occurred ())
3174 /* No GC can happen yet; process the cached source locations. */
3175 handle_locations ();
3177 /* Finalize globals. See how FORTRAN 95 does it in gfc_be_parse_file()
3178 for a simple reference. */
3179 FOR_EACH_VEC_ELT (m_globals
, i
, global
)
3180 rest_of_decl_compilation (global
, true, true);
3182 wrapup_global_declarations (m_globals
.address(), m_globals
.length());
3184 /* We've now created tree nodes for the stmts in the various blocks
3185 in each function, but we haven't built each function's single stmt
3186 list yet. Do so now. */
3187 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
3188 func
->build_stmt_list ();
3190 /* No GC can have happened yet. */
3192 /* Postprocess the functions. This could trigger GC. */
3193 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
3196 func
->postprocess ();
3201 /* Dump the generated .s file to stderr. */
3205 dump_generated_code ()
3207 JIT_LOG_SCOPE (get_logger ());
3210 FILE *f_in
= fopen (get_path_s_file (), "r");
3214 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
3215 fwrite (buf
, 1, sz
, stderr
);
3220 /* Get the supposed path of the notional "fake.c" file within the
3221 tempdir. This file doesn't exist, but the rest of the compiler
3226 get_path_c_file () const
3228 return m_tempdir
->get_path_c_file ();
3231 /* Get the path of the assembler output file "fake.s" file within the
3236 get_path_s_file () const
3238 return m_tempdir
->get_path_s_file ();
3241 /* Get the path of the DSO object file "fake.so" file within the
3246 get_path_so_file () const
3248 return m_tempdir
->get_path_so_file ();
3251 /* qsort comparator for comparing pairs of playback::source_line *,
3252 ordering them by line number. */
3255 line_comparator (const void *lhs
, const void *rhs
)
3257 const playback::source_line
*line_lhs
= \
3258 *static_cast<const playback::source_line
* const*> (lhs
);
3259 const playback::source_line
*line_rhs
= \
3260 *static_cast<const playback::source_line
* const*> (rhs
);
3261 return line_lhs
->get_line_num () - line_rhs
->get_line_num ();
3264 /* qsort comparator for comparing pairs of playback::location *,
3265 ordering them by column number. */
3268 location_comparator (const void *lhs
, const void *rhs
)
3270 const playback::location
*loc_lhs
= \
3271 *static_cast<const playback::location
* const *> (lhs
);
3272 const playback::location
*loc_rhs
= \
3273 *static_cast<const playback::location
* const *> (rhs
);
3274 return loc_lhs
->get_column_num () - loc_rhs
->get_column_num ();
3277 /* Initialize the NAME_TYPE of the primitive types as well as some
3283 /* See lto_init() in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc
3284 for reference. If TYPE_NAME is not set, debug info will not contain types */
3285 #define NAME_TYPE(t,n) \
3287 TYPE_NAME (t) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, \
3288 get_identifier (n), t)
3290 NAME_TYPE (integer_type_node
, "int");
3291 NAME_TYPE (char_type_node
, "char");
3292 NAME_TYPE (long_integer_type_node
, "long int");
3293 NAME_TYPE (unsigned_type_node
, "unsigned int");
3294 NAME_TYPE (long_unsigned_type_node
, "long unsigned int");
3295 NAME_TYPE (long_long_integer_type_node
, "long long int");
3296 NAME_TYPE (long_long_unsigned_type_node
, "long long unsigned int");
3297 NAME_TYPE (short_integer_type_node
, "short int");
3298 NAME_TYPE (short_unsigned_type_node
, "short unsigned int");
3299 if (signed_char_type_node
!= char_type_node
)
3300 NAME_TYPE (signed_char_type_node
, "signed char");
3301 if (unsigned_char_type_node
!= char_type_node
)
3302 NAME_TYPE (unsigned_char_type_node
, "unsigned char");
3303 NAME_TYPE (float_type_node
, "float");
3304 NAME_TYPE (double_type_node
, "double");
3305 NAME_TYPE (long_double_type_node
, "long double");
3306 NAME_TYPE (void_type_node
, "void");
3307 NAME_TYPE (boolean_type_node
, "bool");
3308 NAME_TYPE (complex_float_type_node
, "complex float");
3309 NAME_TYPE (complex_double_type_node
, "complex double");
3310 NAME_TYPE (complex_long_double_type_node
, "complex long double");
3312 m_const_char_ptr
= build_pointer_type(
3313 build_qualified_type (char_type_node
, TYPE_QUAL_CONST
));
3315 NAME_TYPE (m_const_char_ptr
, "char");
3316 NAME_TYPE (size_type_node
, "size_t");
3317 NAME_TYPE (fileptr_type_node
, "FILE");
3321 /* Our API allows locations to be created in arbitrary orders, but the
3322 linemap API requires locations to be created in ascending order
3323 as if we were tokenizing files.
3325 This hook sorts all of the locations that have been created, and
3326 calls into the linemap API, creating linemap entries in sorted order
3327 for our locations. */
3333 /* Create the source code locations, following the ordering rules
3334 imposed by the linemap API.
3336 line_table is a global. */
3337 JIT_LOG_SCOPE (get_logger ());
3341 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
3343 linemap_add (line_table
, LC_ENTER
, false, file
->get_filename (), 0);
3345 /* Sort lines by ascending line numbers. */
3346 file
->m_source_lines
.qsort (&line_comparator
);
3350 FOR_EACH_VEC_ELT (file
->m_source_lines
, j
, line
)
3355 /* Sort locations in line by ascending column numbers. */
3356 line
->m_locations
.qsort (&location_comparator
);
3358 /* Determine maximum column within this line. */
3359 gcc_assert (line
->m_locations
.length () > 0);
3360 location
*final_column
=
3361 line
->m_locations
[line
->m_locations
.length () - 1];
3362 int max_col
= final_column
->get_column_num ();
3364 linemap_line_start (line_table
, line
->get_line_num (), max_col
);
3365 FOR_EACH_VEC_ELT (line
->m_locations
, k
, loc
)
3368 linemap_position_for_column (line_table
, loc
->get_column_num ());
3372 linemap_add (line_table
, LC_LEAVE
, false, NULL
, 0);
3375 /* line_table should now be populated; every playback::location should
3376 now have an m_srcloc. */
3378 /* Now assign them to tree nodes as appropriate. */
3379 std::pair
<tree
, location
*> *cached_location
;
3381 FOR_EACH_VEC_ELT (m_cached_locations
, i
, cached_location
)
3383 tree t
= cached_location
->first
;
3384 location_t srcloc
= cached_location
->second
->m_srcloc
;
3386 /* This covers expressions: */
3387 if (CAN_HAVE_LOCATION_P (t
))
3388 SET_EXPR_LOCATION (t
, srcloc
);
3389 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t
), TS_DECL_MINIMAL
))
3390 DECL_SOURCE_LOCATION (t
) = srcloc
;
3393 /* Don't know how to set location on this node. */
3398 /* We handle errors on a playback::context by adding them to the
3399 corresponding recording::context. */
3403 add_error (location
*loc
, const char *fmt
, ...)
3407 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
3412 /* We handle errors on a playback::context by adding them to the
3413 corresponding recording::context. */
3417 add_error_va (location
*loc
, const char *fmt
, va_list ap
)
3419 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
3423 /* Report a diagnostic up to the jit context as an error,
3424 so that the compilation is treated as a failure.
3425 For now, any kind of diagnostic is treated as an error by the jit
3430 add_diagnostic (struct diagnostic_context
*diag_context
,
3431 struct diagnostic_info
*diagnostic
)
3433 /* At this point the text has been formatted into the pretty-printer's
3435 pretty_printer
*pp
= diag_context
->printer
;
3436 const char *text
= pp_formatted_text (pp
);
3438 /* Get location information (if any) from the diagnostic.
3439 The recording::context::add_error[_va] methods require a
3440 recording::location. We can't lookup the playback::location
3441 from the file/line/column since any playback location instances
3442 may have been garbage-collected away by now, so instead we create
3443 another recording::location directly. */
3444 location_t gcc_loc
= diagnostic_location (diagnostic
);
3445 recording::location
*rec_loc
= NULL
;
3448 expanded_location exploc
= expand_location (gcc_loc
);
3450 rec_loc
= m_recording_ctxt
->new_location (exploc
.file
,
3456 m_recording_ctxt
->add_error (rec_loc
, "%s", text
);
3457 pp_clear_output_area (pp
);
3460 /* Dealing with the linemap API. */
3462 /* Construct a playback::location for a recording::location, if it
3463 doesn't exist already. */
3465 playback::location
*
3467 new_location (recording::location
*rloc
,
3468 const char *filename
,
3472 /* Get the source_file for filename, creating if necessary. */
3473 source_file
*src_file
= get_source_file (filename
);
3474 /* Likewise for the line within the file. */
3475 source_line
*src_line
= src_file
->get_source_line (line
);
3476 /* Likewise for the column within the line. */
3477 location
*loc
= src_line
->get_location (rloc
, column
);
3481 /* Deferred setting of the location for a given tree, by adding the
3482 (tree, playback::location) pair to a list of deferred associations.
3483 We will actually set the location on the tree later on once
3484 the location_t for the playback::location exists. */
3488 set_tree_location (tree t
, location
*loc
)
3491 m_cached_locations
.safe_push (std::make_pair (t
, loc
));
3495 /* Construct a playback::source_file for the given source
3496 filename, if it doesn't exist already. */
3498 playback::source_file
*
3500 get_source_file (const char *filename
)
3503 For simplicitly, this is currently a linear search.
3504 Replace with a hash if this shows up in the profile. */
3507 tree ident_filename
= get_identifier (filename
);
3509 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
3510 if (file
->filename_as_tree () == ident_filename
)
3514 file
= new source_file (ident_filename
);
3515 m_source_files
.safe_push (file
);
3519 /* Constructor for gcc::jit::playback::source_file. */
3521 playback::source_file::source_file (tree filename
) :
3523 m_filename (filename
)
3527 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3531 playback::source_file::finalizer ()
3533 m_source_lines
.release ();
3536 /* Construct a playback::source_line for the given line
3537 within this source file, if one doesn't exist already. */
3539 playback::source_line
*
3540 playback::source_file::
3541 get_source_line (int line_num
)
3544 For simplicitly, this is currently a linear search.
3545 Replace with a hash if this shows up in the profile. */
3549 FOR_EACH_VEC_ELT (m_source_lines
, i
, line
)
3550 if (line
->get_line_num () == line_num
)
3554 line
= new source_line (this, line_num
);
3555 m_source_lines
.safe_push (line
);
3559 /* Constructor for gcc::jit::playback::source_line. */
3561 playback::source_line::source_line (source_file
*file
, int line_num
) :
3563 m_source_file (file
),
3564 m_line_num (line_num
)
3568 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3572 playback::source_line::finalizer ()
3574 m_locations
.release ();
3577 /* Construct a playback::location for the given column
3578 within this line of a specific source file, if one doesn't exist
3581 playback::location
*
3582 playback::source_line::
3583 get_location (recording::location
*rloc
, int column_num
)
3588 /* Another linear search that probably should be a hash table. */
3589 FOR_EACH_VEC_ELT (m_locations
, i
, loc
)
3590 if (loc
->get_column_num () == column_num
)
3594 loc
= new location (rloc
, this, column_num
);
3595 m_locations
.safe_push (loc
);
3599 /* Constructor for gcc::jit::playback::location. */
3601 playback::location::location (recording::location
*loc
,
3604 m_srcloc (UNKNOWN_LOCATION
),
3605 m_recording_loc (loc
),
3607 m_column_num(column_num
)
3611 /* The active gcc::jit::playback::context instance. This is a singleton,
3612 guarded by jit_mutex. */
3614 playback::context
*active_playback_ctxt
;
3616 } // namespace gcc::jit