1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2024 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 "libgccjit.h"
25 #include "coretypes.h"
28 #include "stringpool.h"
34 #include "stor-layout.h"
35 #include "print-tree.h"
37 #include "gcc-driver-name.h"
40 #include "fold-const.h"
41 #include "opt-suggestions.h"
43 #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_UINT8_T
:
241 return unsigned_intQI_type_node
;
242 case GCC_JIT_TYPE_UINT16_T
:
243 return uint16_type_node
;
244 case GCC_JIT_TYPE_UINT32_T
:
245 return uint32_type_node
;
246 case GCC_JIT_TYPE_UINT64_T
:
247 return uint64_type_node
;
248 case GCC_JIT_TYPE_UINT128_T
:
249 if (targetm
.scalar_mode_supported_p (TImode
))
250 return uint128_type_node
;
252 add_error (NULL
, "gcc_jit_types value unsupported on this target: %i",
256 case GCC_JIT_TYPE_INT8_T
:
257 return intQI_type_node
;
258 case GCC_JIT_TYPE_INT16_T
:
259 return intHI_type_node
;
260 case GCC_JIT_TYPE_INT32_T
:
261 return intSI_type_node
;
262 case GCC_JIT_TYPE_INT64_T
:
263 return intDI_type_node
;
264 case GCC_JIT_TYPE_INT128_T
:
265 if (targetm
.scalar_mode_supported_p (TImode
))
266 return intTI_type_node
;
268 add_error (NULL
, "gcc_jit_types value unsupported on this target: %i",
272 case GCC_JIT_TYPE_LONG
:
273 return long_integer_type_node
;
274 case GCC_JIT_TYPE_UNSIGNED_LONG
:
275 return long_unsigned_type_node
;
277 case GCC_JIT_TYPE_LONG_LONG
:
278 return long_long_integer_type_node
;
279 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG
:
280 return long_long_unsigned_type_node
;
282 case GCC_JIT_TYPE_FLOAT
:
283 return float_type_node
;
284 case GCC_JIT_TYPE_DOUBLE
:
285 return double_type_node
;
286 case GCC_JIT_TYPE_LONG_DOUBLE
:
287 return long_double_type_node
;
289 case GCC_JIT_TYPE_SIZE_T
:
290 return size_type_node
;
292 case GCC_JIT_TYPE_FILE_PTR
:
293 return fileptr_type_node
;
295 case GCC_JIT_TYPE_COMPLEX_FLOAT
:
296 return complex_float_type_node
;
297 case GCC_JIT_TYPE_COMPLEX_DOUBLE
:
298 return complex_double_type_node
;
299 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE
:
300 return complex_long_double_type_node
;
303 add_error (NULL
, "unrecognized (enum gcc_jit_types) value: %i",
309 /* Construct a playback::type instance (wrapping a tree) for the given
314 get_type (enum gcc_jit_types type_
)
316 tree type_node
= get_tree_node_for_type (type_
);
317 if (type_node
== NULL
)
320 return new type (type_node
);
323 /* Construct a playback::type instance (wrapping a tree) for the given
328 new_array_type (playback::location
*loc
,
329 playback::type
*element_type
,
332 gcc_assert (element_type
);
334 tree t
= build_array_type_nelts (element_type
->as_tree (),
339 set_tree_location (t
, loc
);
344 /* Construct a playback::field instance (wrapping a tree). */
348 new_field (location
*loc
,
355 /* compare with c/c-decl.cc:grokfield and grokdeclarator. */
356 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
357 get_identifier (name
), type
->as_tree ());
360 set_tree_location (decl
, loc
);
362 return new field (decl
);
365 /* Construct a playback::bitfield instance (wrapping a tree). */
369 new_bitfield (location
*loc
,
378 /* compare with c/c-decl.cc:grokfield, grokdeclarator and
379 check_bitfield_type_and_width. */
381 tree tree_type
= type
->as_tree ();
382 gcc_assert (INTEGRAL_TYPE_P (tree_type
));
383 tree tree_width
= build_int_cst (integer_type_node
, width
);
384 if (compare_tree_int (tree_width
, TYPE_PRECISION (tree_type
)) > 0)
388 "width of bit-field %s (width: %i) is wider than its type (width: %i)",
389 name
, width
, TYPE_PRECISION (tree_type
));
393 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
394 get_identifier (name
), type
->as_tree ());
395 DECL_NONADDRESSABLE_P (decl
) = true;
396 DECL_INITIAL (decl
) = tree_width
;
397 SET_DECL_JIT_BIT_FIELD (decl
);
400 set_tree_location (decl
, loc
);
402 return new field (decl
);
405 /* Construct a playback::compound_type instance (wrapping a tree). */
407 playback::compound_type
*
409 new_compound_type (location
*loc
,
411 bool is_struct
) /* else is union */
415 /* Compare with c/c-decl.cc: start_struct. */
417 tree t
= make_node (is_struct
? RECORD_TYPE
: UNION_TYPE
);
418 TYPE_NAME (t
) = get_identifier (name
);
422 set_tree_location (t
, loc
);
424 return new compound_type (t
);
428 playback::compound_type::set_fields (const auto_vec
<playback::field
*> *fields
)
430 /* Compare with c/c-decl.cc: finish_struct. */
433 tree fieldlist
= NULL
;
434 for (unsigned i
= 0; i
< fields
->length (); i
++)
436 field
*f
= (*fields
)[i
];
437 tree x
= f
->as_tree ();
438 DECL_CONTEXT (x
) = t
;
439 if (DECL_JIT_BIT_FIELD (x
))
441 unsigned HOST_WIDE_INT width
= tree_to_uhwi (DECL_INITIAL (x
));
442 DECL_SIZE (x
) = bitsize_int (width
);
443 DECL_BIT_FIELD (x
) = 1;
445 fieldlist
= chainon (x
, fieldlist
);
447 fieldlist
= nreverse (fieldlist
);
448 TYPE_FIELDS (t
) = fieldlist
;
453 /* Construct a playback::type instance (wrapping a tree) for a function
458 new_function_type (type
*return_type
,
459 const auto_vec
<type
*> *param_types
,
465 tree
*arg_types
= (tree
*)xcalloc(param_types
->length (), sizeof(tree
*));
467 FOR_EACH_VEC_ELT (*param_types
, i
, param_type
)
468 arg_types
[i
] = param_type
->as_tree ();
473 build_varargs_function_type_array (return_type
->as_tree (),
474 param_types
->length (),
477 fn_type
= build_function_type_array (return_type
->as_tree (),
478 param_types
->length (),
482 return new type (fn_type
);
485 /* Construct a playback::param instance (wrapping a tree). */
489 new_param (location
*loc
,
495 tree inner
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
496 get_identifier (name
), type
->as_tree ());
498 set_tree_location (inner
, loc
);
500 return new param (this, inner
);
503 const char* fn_attribute_to_string (gcc_jit_fn_attribute attr
)
507 case GCC_JIT_FN_ATTRIBUTE_ALIAS
:
509 case GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE
:
510 return "always_inline";
511 case GCC_JIT_FN_ATTRIBUTE_INLINE
:
513 case GCC_JIT_FN_ATTRIBUTE_NOINLINE
:
515 case GCC_JIT_FN_ATTRIBUTE_TARGET
:
517 case GCC_JIT_FN_ATTRIBUTE_USED
:
519 case GCC_JIT_FN_ATTRIBUTE_VISIBILITY
:
521 case GCC_JIT_FN_ATTRIBUTE_COLD
:
523 case GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE
:
524 return "returns_twice";
525 case GCC_JIT_FN_ATTRIBUTE_PURE
:
527 case GCC_JIT_FN_ATTRIBUTE_CONST
:
529 case GCC_JIT_FN_ATTRIBUTE_WEAK
:
531 case GCC_JIT_FN_ATTRIBUTE_NONNULL
:
533 case GCC_JIT_FN_ATTRIBUTE_MAX
:
539 const char* variable_attribute_to_string (gcc_jit_variable_attribute attr
)
543 case GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY
:
545 case GCC_JIT_VARIABLE_ATTRIBUTE_MAX
:
551 /* Construct a playback::function instance. */
555 new_function (location
*loc
,
556 enum gcc_jit_function_kind kind
,
559 const auto_vec
<param
*> *params
,
561 enum built_in_function builtin_id
,
562 const std::vector
<gcc_jit_fn_attribute
> &attributes
,
563 const std::vector
<std::pair
<gcc_jit_fn_attribute
,
564 std::string
>> &string_attributes
,
565 const std::vector
<std::pair
<gcc_jit_fn_attribute
,
567 &int_array_attributes
)
572 //can return_type be NULL?
575 tree
*arg_types
= (tree
*)xcalloc(params
->length (), sizeof(tree
*));
576 FOR_EACH_VEC_ELT (*params
, i
, param
)
577 arg_types
[i
] = TREE_TYPE (param
->as_tree ());
581 fn_type
= build_varargs_function_type_array (return_type
->as_tree (),
582 params
->length (), arg_types
);
584 fn_type
= build_function_type_array (return_type
->as_tree (),
585 params
->length (), arg_types
);
588 /* FIXME: this uses input_location: */
589 tree fndecl
= build_fn_decl (name
, fn_type
);
592 set_tree_location (fndecl
, loc
);
594 tree resdecl
= build_decl (UNKNOWN_LOCATION
, RESULT_DECL
,
595 NULL_TREE
, return_type
->as_tree ());
596 DECL_ARTIFICIAL (resdecl
) = 1;
597 DECL_IGNORED_P (resdecl
) = 1;
598 DECL_RESULT (fndecl
) = resdecl
;
599 DECL_CONTEXT (resdecl
) = fndecl
;
601 tree fn_attributes
= NULL_TREE
;
605 gcc_assert (loc
== NULL
);
606 DECL_SOURCE_LOCATION (fndecl
) = BUILTINS_LOCATION
;
608 built_in_class fclass
= builtins_manager::get_class (builtin_id
);
609 set_decl_built_in_function (fndecl
, fclass
, builtin_id
);
610 set_builtin_decl (builtin_id
, fndecl
,
611 builtins_manager::implicit_p (builtin_id
));
613 builtins_manager
*bm
= get_builtins_manager ();
614 tree attrs
= bm
->get_attrs_tree (builtin_id
);
616 decl_attributes (&fndecl
, attrs
, ATTR_FLAG_BUILT_IN
);
618 decl_attributes (&fndecl
, NULL_TREE
, 0);
621 if (kind
!= GCC_JIT_FUNCTION_IMPORTED
)
623 tree param_decl_list
= NULL
;
624 FOR_EACH_VEC_ELT (*params
, i
, param
)
626 param_decl_list
= chainon (param
->as_tree (), param_decl_list
);
629 /* The param list was created in reverse order; fix it: */
630 param_decl_list
= nreverse (param_decl_list
);
633 for (t
= param_decl_list
; t
; t
= DECL_CHAIN (t
))
635 DECL_CONTEXT (t
) = fndecl
;
636 DECL_ARG_TYPE (t
) = TREE_TYPE (t
);
639 /* Set it up on DECL_ARGUMENTS */
640 DECL_ARGUMENTS(fndecl
) = param_decl_list
;
643 if (kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
645 DECL_DECLARED_INLINE_P (fndecl
) = 1;
647 /* Add attribute "always_inline": */
648 fn_attributes
= tree_cons (get_identifier ("always_inline"),
653 /* All attributes need to be declared in `dummy-frontend.cc` and more
654 specifically in `jit_attribute_table`. */
655 for (auto attr
: attributes
)
657 if (attr
== GCC_JIT_FN_ATTRIBUTE_INLINE
)
658 DECL_DECLARED_INLINE_P (fndecl
) = 1;
660 const char* attribute
= fn_attribute_to_string (attr
);
663 tree ident
= get_identifier (attribute
);
664 fn_attributes
= tree_cons (ident
, NULL_TREE
, fn_attributes
);
668 for (auto attr
: string_attributes
)
670 gcc_jit_fn_attribute
& name
= std::get
<0>(attr
);
671 std::string
& value
= std::get
<1>(attr
);
672 tree attribute_value
= build_tree_list (NULL_TREE
,
673 ::build_string (value
.length () + 1, value
.c_str ()));
674 const char* attribute
= fn_attribute_to_string (name
);
675 tree ident
= attribute
? get_identifier (attribute
) : NULL
;
678 fn_attributes
= tree_cons (ident
, attribute_value
, fn_attributes
);
681 for (auto attr
: int_array_attributes
)
683 gcc_jit_fn_attribute
& name
= std::get
<0>(attr
);
684 std::vector
<int>& values
= std::get
<1>(attr
);
686 const char* attribute
= fn_attribute_to_string (name
);
687 tree ident
= attribute
? get_identifier (attribute
) : NULL
;
692 tree tree_list
= NULL_TREE
;
693 tree
*p_tree_list
= &tree_list
;
694 for (auto value
: values
)
696 tree int_value
= build_int_cst (integer_type_node
, value
);
697 *p_tree_list
= build_tree_list (NULL
, int_value
);
698 p_tree_list
= &TREE_CHAIN (*p_tree_list
);
700 fn_attributes
= tree_cons (ident
, tree_list
, fn_attributes
);
703 decl_attributes (&fndecl
, fn_attributes
, 0);
704 function
*func
= new function (this, fndecl
, kind
);
705 m_functions
.safe_push (func
);
709 /* In use by new_global and new_global_initialized. */
713 global_new_decl (location
*loc
,
714 enum gcc_jit_global_kind kind
,
717 enum global_var_flags flags
,
718 const std::vector
<std::pair
<gcc_jit_variable_attribute
,
719 std::string
>> &attributes
)
724 tree type_tree
= type
->as_tree ();
726 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
727 get_identifier (name
),
730 TREE_PUBLIC (inner
) = (kind
!= GCC_JIT_GLOBAL_INTERNAL
);
733 int will_be_init
= flags
& (GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT
|
734 GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT
);
736 /* A VAR_DECL with DECL_INITIAL will not end up in .common section. */
738 DECL_COMMON (inner
) = 1;
745 case GCC_JIT_GLOBAL_EXPORTED
:
746 TREE_STATIC (inner
) = 1;
749 case GCC_JIT_GLOBAL_INTERNAL
:
750 TREE_STATIC (inner
) = 1;
753 case GCC_JIT_GLOBAL_IMPORTED
:
754 DECL_EXTERNAL (inner
) = 1;
758 if (TYPE_READONLY (type_tree
))
759 TREE_READONLY (inner
) = 1;
762 set_tree_location (inner
, loc
);
764 set_variable_string_attribute (attributes
, inner
);
771 set_variable_string_attribute (
772 const std::vector
<std::pair
<gcc_jit_variable_attribute
,
773 std::string
>> &string_attributes
,
776 tree var_attributes
= NULL_TREE
;
777 for (auto attr
: string_attributes
)
779 gcc_jit_variable_attribute
& name
= std::get
<0>(attr
);
780 std::string
& value
= std::get
<1>(attr
);
781 tree attribute_value
= build_tree_list (NULL_TREE
,
782 ::build_string (value
.length () + 1, value
.c_str ()));
783 tree ident
= get_identifier (variable_attribute_to_string (name
));
785 var_attributes
= tree_cons (ident
, attribute_value
, var_attributes
);
787 decl_attributes (&decl
, var_attributes
, 0);
790 /* In use by new_global and new_global_initialized. */
794 global_finalize_lvalue (tree inner
)
796 m_globals
.safe_push (inner
);
798 return new lvalue (this, inner
);
801 /* Construct a playback::lvalue instance (wrapping a tree). */
805 new_global (location
*loc
,
806 enum gcc_jit_global_kind kind
,
809 enum global_var_flags flags
,
810 const std::vector
<std::pair
<gcc_jit_variable_attribute
,
811 std::string
>> &attributes
)
814 global_new_decl (loc
, kind
, type
, name
, flags
, attributes
);
816 return global_finalize_lvalue (inner
);
821 global_set_init_rvalue (lvalue
* variable
,
824 tree inner
= variable
->as_tree ();
826 /* We need to fold all expressions as much as possible. The code
827 for a DECL_INITIAL only handles some operations,
828 etc addition, minus, 'address of'. See output_addressed_constants ()
830 tree init_tree
= init
->as_tree ();
831 tree folded
= fold_const_var (init_tree
);
833 if (!TREE_CONSTANT (folded
))
835 tree name
= DECL_NAME (inner
);
837 if (name
!= NULL_TREE
)
839 "unable to convert initial value for the global variable %s"
840 " to a compile-time constant",
841 IDENTIFIER_POINTER (name
));
844 "unable to convert initial value for global variable"
845 " to a compile-time constant");
849 DECL_INITIAL (inner
) = folded
;
854 new_ctor (location
*loc
,
856 const auto_vec
<field
*> *fields
,
857 const auto_vec
<rvalue
*> *rvalues
)
859 tree type_tree
= type
->as_tree ();
861 /* Handle empty ctors first. I.e. set everything to 0. */
862 if (rvalues
->length () == 0)
863 return new rvalue (this, build_constructor (type_tree
, NULL
));
865 /* Handle arrays (and return). */
866 if (TREE_CODE (type_tree
) == ARRAY_TYPE
)
868 int n
= rvalues
->length ();
869 /* The vec for the constructor node. */
870 vec
<constructor_elt
, va_gc
> *v
= NULL
;
873 for (int i
= 0; i
< n
; i
++)
875 rvalue
*rv
= (*rvalues
)[i
];
876 /* null rvalues indicate that the element should be zeroed. */
878 CONSTRUCTOR_APPEND_ELT (v
,
879 build_int_cst (size_type_node
, i
),
882 CONSTRUCTOR_APPEND_ELT (v
,
883 build_int_cst (size_type_node
, i
),
884 build_zero_cst (TREE_TYPE (type_tree
)));
887 tree ctor
= build_constructor (type_tree
, v
);
890 set_tree_location (ctor
, loc
);
892 return new rvalue (this, ctor
);
895 /* Handle structs and unions. */
896 int n
= fields
->length ();
898 /* The vec for the constructor node. */
899 vec
<constructor_elt
, va_gc
> *v
= NULL
;
902 /* Iterate over the fields, building initializations. */
903 for (int i
= 0;i
< n
; i
++)
905 tree field
= (*fields
)[i
]->as_tree ();
906 rvalue
*rv
= (*rvalues
)[i
];
907 /* If the value is NULL, it means we should zero the field. */
909 CONSTRUCTOR_APPEND_ELT (v
, field
, rv
->as_tree ());
912 tree zero_cst
= build_zero_cst (TREE_TYPE (field
));
913 CONSTRUCTOR_APPEND_ELT (v
, field
, zero_cst
);
917 tree ctor
= build_constructor (type_tree
, v
);
920 set_tree_location (ctor
, loc
);
922 return new rvalue (this, build_constructor (type_tree
, v
));
925 /* Fill 'constructor_elements' with the memory content of
926 'initializer'. Each element of the initializer is of the size of
927 type T. In use by new_global_initialized.*/
931 load_blob_in_ctor (vec
<constructor_elt
, va_gc
> *&constructor_elements
,
933 const void *initializer
)
935 /* Loosely based on 'output_init_element' c-typeck.cc:9691. */
936 const T
*p
= (const T
*)initializer
;
937 tree node
= make_unsigned_type (BITS_PER_UNIT
* sizeof (T
));
938 for (size_t i
= 0; i
< num_elem
; i
++)
940 constructor_elt celt
=
941 { build_int_cst (long_unsigned_type_node
, i
),
942 build_int_cst (node
, p
[i
]) };
943 vec_safe_push (constructor_elements
, celt
);
947 /* Construct an initialized playback::lvalue instance (wrapping a
952 new_global_initialized (location
*loc
,
953 enum gcc_jit_global_kind kind
,
956 size_t initializer_num_elem
,
957 const void *initializer
,
959 enum global_var_flags flags
,
960 const std::vector
<std::pair
<gcc_jit_variable_attribute
,
961 std::string
>> &attributes
)
963 tree inner
= global_new_decl (loc
, kind
, type
, name
, flags
, attributes
);
965 vec
<constructor_elt
, va_gc
> *constructor_elements
= NULL
;
967 switch (element_size
)
970 load_blob_in_ctor
<uint8_t> (constructor_elements
, initializer_num_elem
,
974 load_blob_in_ctor
<uint16_t> (constructor_elements
, initializer_num_elem
,
978 load_blob_in_ctor
<uint32_t> (constructor_elements
, initializer_num_elem
,
982 load_blob_in_ctor
<uint64_t> (constructor_elements
, initializer_num_elem
,
986 /* This function is serving on sizes returned by 'get_size',
987 these are all covered by the previous cases. */
990 /* Compare with 'pop_init_level' c-typeck.cc:8780. */
991 tree ctor
= build_constructor (type
->as_tree (), constructor_elements
);
992 constructor_elements
= NULL
;
994 /* Compare with 'store_init_value' c-typeck.cc:7555. */
995 DECL_INITIAL (inner
) = ctor
;
997 return global_finalize_lvalue (inner
);
1000 /* Implementation of the various
1001 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
1003 Each of these constructs a playback::rvalue instance (wrapping a tree).
1005 These specializations are required to be in the same namespace
1006 as the template, hence we now have to enter the gcc::jit::playback
1012 /* Specialization of making an rvalue from a const, for host <int>. */
1017 new_rvalue_from_const
<int> (type
*type
,
1020 // FIXME: type-checking, or coercion?
1021 tree inner_type
= type
->as_tree ();
1022 if (INTEGRAL_TYPE_P (inner_type
))
1024 tree inner
= build_int_cst (inner_type
, value
);
1025 return new rvalue (this, inner
);
1029 REAL_VALUE_TYPE real_value
;
1030 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
1031 tree inner
= build_real (inner_type
, real_value
);
1032 return new rvalue (this, inner
);
1036 /* Specialization of making an rvalue from a const, for host <long>. */
1041 new_rvalue_from_const
<long> (type
*type
,
1044 // FIXME: type-checking, or coercion?
1045 tree inner_type
= type
->as_tree ();
1046 if (INTEGRAL_TYPE_P (inner_type
))
1048 tree inner
= build_int_cst (inner_type
, value
);
1049 return new rvalue (this, inner
);
1053 REAL_VALUE_TYPE real_value
;
1054 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
1055 tree inner
= build_real (inner_type
, real_value
);
1056 return new rvalue (this, inner
);
1060 /* Specialization of making an rvalue from a const, for host <double>. */
1065 new_rvalue_from_const
<double> (type
*type
,
1068 // FIXME: type-checking, or coercion?
1069 tree inner_type
= type
->as_tree ();
1071 /* We have a "double", we want a REAL_VALUE_TYPE.
1073 real.cc:real_from_target appears to require the representation to be
1074 split into 32-bit values, and then sent as an pair of host long
1076 REAL_VALUE_TYPE real_value
;
1080 uint32_t as_uint32s
[2];
1082 u
.as_double
= value
;
1083 long int as_long_ints
[2];
1084 as_long_ints
[0] = u
.as_uint32s
[0];
1085 as_long_ints
[1] = u
.as_uint32s
[1];
1086 real_from_target (&real_value
, as_long_ints
, DFmode
);
1087 tree inner
= build_real (inner_type
, real_value
);
1088 return new rvalue (this, inner
);
1091 /* Specialization of making an rvalue from a const, for host <void *>. */
1096 new_rvalue_from_const
<void *> (type
*type
,
1099 tree inner_type
= type
->as_tree ();
1100 /* FIXME: how to ensure we have a wide enough type? */
1101 tree inner
= build_int_cstu (inner_type
, (unsigned HOST_WIDE_INT
)value
);
1102 return new rvalue (this, inner
);
1105 /* We're done implementing the specializations of
1106 gcc::jit::playback::context::new_rvalue_from_const <T>
1107 so we can exit the gcc::jit::playback namespace. */
1109 } // namespace playback
1111 /* Construct a playback::rvalue instance (wrapping a tree). */
1115 new_string_literal (const char *value
)
1117 /* Compare with c-family/c-common.cc: fix_string_type. */
1118 size_t len
= strlen (value
);
1119 tree i_type
= build_index_type (size_int (len
));
1120 tree a_type
= build_array_type (char_type_node
, i_type
);
1121 /* build_string len parameter must include NUL terminator when
1122 building C strings. */
1123 tree t_str
= ::build_string (len
+ 1, value
);
1124 TREE_TYPE (t_str
) = a_type
;
1126 /* Convert to (const char*), loosely based on
1127 c/c-typeck.cc: array_to_pointer_conversion,
1128 by taking address of start of string. */
1129 tree t_addr
= build1 (ADDR_EXPR
, m_const_char_ptr
, t_str
);
1131 return new rvalue (this, t_addr
);
1134 /* Construct a playback::rvalue instance (wrapping a tree) for a
1138 playback::context::new_rvalue_from_vector (location
*,
1140 const auto_vec
<rvalue
*> &elements
)
1142 vec
<constructor_elt
, va_gc
> *v
;
1143 vec_alloc (v
, elements
.length ());
1144 for (unsigned i
= 0; i
< elements
.length (); ++i
)
1145 CONSTRUCTOR_APPEND_ELT (v
, NULL_TREE
, elements
[i
]->as_tree ());
1146 tree t_ctor
= build_constructor (type
->as_tree (), v
);
1147 return new rvalue (this, t_ctor
);
1150 /* Coerce a tree expression into a boolean tree expression. */
1154 as_truth_value (tree expr
, location
*loc
)
1156 /* Compare to c-typeck.cc:c_objc_common_truthvalue_conversion */
1157 tree typed_zero
= fold_build1 (CONVERT_EXPR
,
1161 set_tree_location (typed_zero
, loc
);
1163 tree type
= TREE_TYPE (expr
);
1164 expr
= fold_build2_loc (UNKNOWN_LOCATION
,
1165 NE_EXPR
, type
, expr
, typed_zero
);
1167 set_tree_location (expr
, loc
);
1172 /* Add a "top-level" basic asm statement (i.e. one outside of any functions)
1173 containing ASM_STMTS.
1175 Compare with c_parser_asm_definition. */
1178 playback::context::add_top_level_asm (const char *asm_stmts
)
1180 tree asm_str
= build_string (asm_stmts
);
1181 symtab
->finalize_toplevel_asm (asm_str
);
1184 /* Construct a playback::rvalue instance (wrapping a tree) for a
1189 new_unary_op (location
*loc
,
1190 enum gcc_jit_unary_op op
,
1194 // FIXME: type-checking, or coercion?
1195 enum tree_code inner_op
;
1197 gcc_assert (result_type
);
1200 tree node
= a
->as_tree ();
1201 node
= fold_const_var (node
);
1203 tree inner_result
= NULL
;
1208 add_error (loc
, "unrecognized (enum gcc_jit_unary_op) value: %i", op
);
1211 case GCC_JIT_UNARY_OP_MINUS
:
1212 inner_op
= NEGATE_EXPR
;
1215 case GCC_JIT_UNARY_OP_BITWISE_NEGATE
:
1216 inner_op
= BIT_NOT_EXPR
;
1219 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE
:
1220 node
= as_truth_value (node
, loc
);
1221 inner_result
= invert_truthvalue (node
);
1223 set_tree_location (inner_result
, loc
);
1224 return new rvalue (this, inner_result
);
1226 case GCC_JIT_UNARY_OP_ABS
:
1227 inner_op
= ABS_EXPR
;
1231 inner_result
= build1 (inner_op
,
1232 result_type
->as_tree (),
1236 inner_result
= fold (inner_result
);
1239 set_tree_location (inner_result
, loc
);
1241 return new rvalue (this, inner_result
);
1244 /* Construct a playback::rvalue instance (wrapping a tree) for a
1249 new_binary_op (location
*loc
,
1250 enum gcc_jit_binary_op op
,
1252 rvalue
*a
, rvalue
*b
)
1254 // FIXME: type-checking, or coercion?
1255 enum tree_code inner_op
;
1257 gcc_assert (result_type
);
1261 tree node_a
= a
->as_tree ();
1262 node_a
= fold_const_var (node_a
);
1264 tree node_b
= b
->as_tree ();
1265 node_b
= fold_const_var (node_b
);
1270 add_error (loc
, "unrecognized (enum gcc_jit_binary_op) value: %i", op
);
1273 case GCC_JIT_BINARY_OP_PLUS
:
1274 inner_op
= PLUS_EXPR
;
1277 case GCC_JIT_BINARY_OP_MINUS
:
1278 inner_op
= MINUS_EXPR
;
1281 case GCC_JIT_BINARY_OP_MULT
:
1282 inner_op
= MULT_EXPR
;
1285 case GCC_JIT_BINARY_OP_DIVIDE
:
1286 if (FLOAT_TYPE_P (result_type
->as_tree ()))
1287 /* Floating-point division: */
1288 inner_op
= RDIV_EXPR
;
1290 /* Truncating to zero: */
1291 inner_op
= TRUNC_DIV_EXPR
;
1294 case GCC_JIT_BINARY_OP_MODULO
:
1295 inner_op
= TRUNC_MOD_EXPR
;
1298 case GCC_JIT_BINARY_OP_BITWISE_AND
:
1299 inner_op
= BIT_AND_EXPR
;
1302 case GCC_JIT_BINARY_OP_BITWISE_XOR
:
1303 inner_op
= BIT_XOR_EXPR
;
1306 case GCC_JIT_BINARY_OP_BITWISE_OR
:
1307 inner_op
= BIT_IOR_EXPR
;
1310 case GCC_JIT_BINARY_OP_LOGICAL_AND
:
1311 node_a
= as_truth_value (node_a
, loc
);
1312 node_b
= as_truth_value (node_b
, loc
);
1313 inner_op
= TRUTH_ANDIF_EXPR
;
1316 case GCC_JIT_BINARY_OP_LOGICAL_OR
:
1317 node_a
= as_truth_value (node_a
, loc
);
1318 node_b
= as_truth_value (node_b
, loc
);
1319 inner_op
= TRUTH_ORIF_EXPR
;
1322 case GCC_JIT_BINARY_OP_LSHIFT
:
1323 inner_op
= LSHIFT_EXPR
;
1326 case GCC_JIT_BINARY_OP_RSHIFT
:
1327 inner_op
= RSHIFT_EXPR
;
1331 tree inner_expr
= build2 (inner_op
,
1332 result_type
->as_tree (),
1336 /* Try to fold the expression. */
1337 inner_expr
= fold (inner_expr
);
1340 set_tree_location (inner_expr
, loc
);
1342 return new rvalue (this, inner_expr
);
1345 /* Construct a playback::rvalue instance (wrapping a tree) for a
1350 new_comparison (location
*loc
,
1351 enum gcc_jit_comparison op
,
1352 rvalue
*a
, rvalue
*b
, type
*vec_result_type
)
1354 // FIXME: type-checking, or coercion?
1355 enum tree_code inner_op
;
1363 add_error (loc
, "unrecognized (enum gcc_jit_comparison) value: %i", op
);
1366 case GCC_JIT_COMPARISON_EQ
:
1369 case GCC_JIT_COMPARISON_NE
:
1372 case GCC_JIT_COMPARISON_LT
:
1375 case GCC_JIT_COMPARISON_LE
:
1378 case GCC_JIT_COMPARISON_GT
:
1381 case GCC_JIT_COMPARISON_GE
:
1386 tree node_a
= a
->as_tree ();
1387 node_a
= fold_const_var (node_a
);
1388 tree node_b
= b
->as_tree ();
1389 node_b
= fold_const_var (node_b
);
1392 tree a_type
= TREE_TYPE (node_a
);
1393 if (VECTOR_TYPE_P (a_type
))
1395 /* Build a vector comparison. See build_vec_cmp in c-typeck.cc for
1397 tree t_vec_result_type
= vec_result_type
->as_tree ();
1398 tree zero_vec
= build_zero_cst (t_vec_result_type
);
1399 tree minus_one_vec
= build_minus_one_cst (t_vec_result_type
);
1400 tree cmp_type
= truth_type_for (a_type
);
1401 tree cmp
= build2 (inner_op
, cmp_type
, node_a
, node_b
);
1402 inner_expr
= build3 (VEC_COND_EXPR
, t_vec_result_type
, cmp
, minus_one_vec
,
1407 inner_expr
= build2 (inner_op
,
1414 inner_expr
= fold (inner_expr
);
1417 set_tree_location (inner_expr
, loc
);
1418 return new rvalue (this, inner_expr
);
1421 /* Construct a playback::rvalue instance (wrapping a tree) for a
1426 build_call (location
*loc
,
1428 const auto_vec
<rvalue
*> *args
,
1429 bool require_tail_call
)
1431 vec
<tree
, va_gc
> *tree_args
;
1432 vec_alloc (tree_args
, args
->length ());
1433 for (unsigned i
= 0; i
< args
->length (); i
++)
1434 tree_args
->quick_push ((*args
)[i
]->as_tree ());
1437 set_tree_location (fn_ptr
, loc
);
1439 tree fn
= TREE_TYPE (fn_ptr
);
1440 tree fn_type
= TREE_TYPE (fn
);
1441 tree return_type
= TREE_TYPE (fn_type
);
1443 tree call
= build_call_vec (return_type
,
1446 if (require_tail_call
)
1447 CALL_EXPR_MUST_TAIL_CALL (call
) = 1;
1449 return new rvalue (this, call
);
1451 /* see c-typeck.cc: build_function_call
1452 which calls build_function_call_vec
1454 which does lots of checking, then:
1455 result = build_call_array_loc (loc, TREE_TYPE (fntype),
1456 function, nargs, argarray);
1458 (see also build_call_vec)
1462 /* Construct a playback::rvalue instance (wrapping a tree) for a
1463 call to a specific function. */
1467 new_call (location
*loc
,
1469 const auto_vec
<rvalue
*> *args
,
1470 bool require_tail_call
)
1476 fndecl
= func
->as_fndecl ();
1478 tree fntype
= TREE_TYPE (fndecl
);
1480 tree fn
= build1 (ADDR_EXPR
, build_pointer_type (fntype
), fndecl
);
1482 return build_call (loc
, fn
, args
, require_tail_call
);
1485 /* Construct a playback::rvalue instance (wrapping a tree) for a
1486 call through a function pointer. */
1490 new_call_through_ptr (location
*loc
,
1492 const auto_vec
<rvalue
*> *args
,
1493 bool require_tail_call
)
1495 gcc_assert (fn_ptr
);
1496 tree t_fn_ptr
= fn_ptr
->as_tree ();
1498 return build_call (loc
, t_fn_ptr
, args
, require_tail_call
);
1501 /* Construct a tree for a cast. */
1504 playback::context::build_cast (playback::location
*loc
,
1505 playback::rvalue
*expr
,
1506 playback::type
*type_
)
1508 /* For comparison, see:
1509 - c/c-typeck.cc:build_c_cast
1510 - c/c-convert.cc: convert
1513 Only some kinds of cast are currently supported here. */
1514 tree t_expr
= expr
->as_tree ();
1515 t_expr
= fold_const_var (t_expr
);
1517 tree t_dst_type
= type_
->as_tree ();
1519 t_ret
= targetm
.convert_to_type (t_dst_type
, t_expr
);
1522 enum tree_code dst_code
= TREE_CODE (t_dst_type
);
1527 t_ret
= convert_to_integer (t_dst_type
, t_expr
);
1531 /* Compare with c_objc_common_truthvalue_conversion and
1532 c_common_truthvalue_conversion. */
1533 /* For now, convert to: (t_expr != 0) */
1534 t_ret
= build2 (NE_EXPR
, t_dst_type
,
1536 build_int_cst (TREE_TYPE (t_expr
), 0));
1540 t_ret
= convert_to_real (t_dst_type
, t_expr
);
1544 t_ret
= build1 (NOP_EXPR
, t_dst_type
, t_expr
);
1548 add_error (loc
, "couldn't handle cast during playback");
1549 fprintf (stderr
, "input expression:\n");
1550 debug_tree (t_expr
);
1551 fprintf (stderr
, "requested type:\n");
1552 debug_tree (t_dst_type
);
1553 return error_mark_node
;
1556 if (TREE_CODE (t_ret
) != C_MAYBE_CONST_EXPR
)
1557 t_ret
= fold (t_ret
);
1562 /* Construct a playback::rvalue instance (wrapping a tree) for a
1567 new_cast (playback::location
*loc
,
1568 playback::rvalue
*expr
,
1569 playback::type
*type_
)
1572 tree t_cast
= build_cast (loc
, expr
, type_
);
1574 set_tree_location (t_cast
, loc
);
1575 return new rvalue (this, t_cast
);
1578 /* Construct a playback::rvalue instance (wrapping a tree) for a
1583 new_bitcast (location
*loc
,
1587 tree expr_size
= TYPE_SIZE (expr
->get_type ()->as_tree ());
1588 tree type_size
= TYPE_SIZE (type_
->as_tree ());
1589 tree t_expr
= expr
->as_tree ();
1590 tree t_dst_type
= type_
->as_tree ();
1591 if (expr_size
!= type_size
)
1593 active_playback_ctxt
->add_error (loc
,
1594 "bitcast with types of different sizes");
1595 fprintf (stderr
, "input expression (size: %ld):\n",
1596 (long) tree_to_uhwi (expr_size
));
1597 debug_tree (t_expr
);
1598 fprintf (stderr
, "requested type (size: %ld):\n",
1599 (long) tree_to_uhwi (type_size
));
1600 debug_tree (t_dst_type
);
1602 tree t_bitcast
= build1 (VIEW_CONVERT_EXPR
, t_dst_type
, t_expr
);
1604 set_tree_location (t_bitcast
, loc
);
1605 return new rvalue (this, t_bitcast
);
1608 /* Construct a playback::lvalue instance (wrapping a tree) for an
1613 new_array_access (location
*loc
,
1620 /* For comparison, see:
1621 c/c-typeck.cc: build_array_ref
1622 c-family/c-common.cc: pointer_int_sum
1624 tree t_ptr
= ptr
->as_tree ();
1625 t_ptr
= fold_const_var (t_ptr
);
1626 tree t_index
= index
->as_tree ();
1627 t_index
= fold_const_var (t_index
);
1629 tree t_type_ptr
= TREE_TYPE (t_ptr
);
1630 tree t_type_star_ptr
= TREE_TYPE (t_type_ptr
);
1632 if (TREE_CODE (t_type_ptr
) == ARRAY_TYPE
)
1634 tree t_result
= build4 (ARRAY_REF
, t_type_star_ptr
, t_ptr
, t_index
,
1635 NULL_TREE
, NULL_TREE
);
1636 t_result
= fold (t_result
);
1638 set_tree_location (t_result
, loc
);
1639 return new lvalue (this, t_result
);
1643 /* Convert index to an offset in bytes. */
1644 tree t_sizeof
= size_in_bytes (t_type_star_ptr
);
1645 t_index
= fold_build1 (CONVERT_EXPR
, sizetype
, t_index
);
1646 tree t_offset
= fold_build2_loc (UNKNOWN_LOCATION
,
1647 MULT_EXPR
, sizetype
, t_index
, t_sizeof
);
1649 /* Locate (ptr + offset). */
1650 tree t_address
= fold_build2_loc (UNKNOWN_LOCATION
,
1651 POINTER_PLUS_EXPR
, t_type_ptr
, t_ptr
, t_offset
);
1653 tree t_indirection
= fold_build1 (INDIRECT_REF
, t_type_star_ptr
, t_address
);
1656 set_tree_location (t_sizeof
, loc
);
1657 set_tree_location (t_offset
, loc
);
1658 set_tree_location (t_address
, loc
);
1659 set_tree_location (t_indirection
, loc
);
1662 return new lvalue (this, t_indirection
);
1666 /* Construct a tree for a field access. */
1670 new_field_access (location
*loc
,
1677 /* Compare with c/c-typeck.cc:lookup_field, build_indirect_ref, and
1678 build_component_ref. */
1679 tree type
= TREE_TYPE (datum
);
1681 gcc_assert (TREE_CODE (type
) != POINTER_TYPE
);
1683 tree t_field
= field
->as_tree ();
1684 tree ref
= build3 (COMPONENT_REF
, TREE_TYPE (t_field
), datum
,
1685 t_field
, NULL_TREE
);
1687 set_tree_location (ref
, loc
);
1691 /* Construct a tree for a dereference. */
1695 new_dereference (tree ptr
,
1700 tree type
= TREE_TYPE (TREE_TYPE(ptr
));
1701 tree datum
= fold_build1 (INDIRECT_REF
, type
, ptr
);
1703 set_tree_location (datum
, loc
);
1707 /* Construct a playback::type instance (wrapping a tree)
1708 with the given alignment. */
1712 get_aligned (size_t alignment_in_bytes
) const
1714 tree t_new_type
= build_variant_type_copy (m_inner
);
1716 SET_TYPE_ALIGN (t_new_type
, alignment_in_bytes
* BITS_PER_UNIT
);
1717 TYPE_USER_ALIGN (t_new_type
) = 1;
1719 return new type (t_new_type
);
1722 /* Construct a playback::type instance (wrapping a tree)
1723 for the given vector type. */
1727 get_vector (size_t num_units
) const
1729 tree t_new_type
= build_vector_type (m_inner
, num_units
);
1730 return new type (t_new_type
);
1733 /* Construct a playback::lvalue instance (wrapping a tree) for a
1738 access_field (location
*loc
,
1741 tree datum
= as_tree ();
1742 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1745 return new lvalue (get_context (), ref
);
1748 /* Construct a playback::rvalue instance (wrapping a tree) for a
1753 access_field (location
*loc
,
1756 tree datum
= as_tree ();
1757 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1760 return new rvalue (get_context (), ref
);
1763 /* Construct a playback::lvalue instance (wrapping a tree) for a
1764 dereferenced field access. */
1768 dereference_field (location
*loc
,
1771 tree ptr
= as_tree ();
1772 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1775 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1778 return new lvalue (get_context (), ref
);
1781 /* Construct a playback::lvalue instance (wrapping a tree) for a
1786 dereference (location
*loc
)
1788 tree ptr
= as_tree ();
1789 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1790 return new lvalue (get_context (), datum
);
1793 /* Mark the lvalue saying that we need to be able to take the
1794 address of it; it should not be allocated in a register.
1795 Compare with e.g. c/c-typeck.cc: c_mark_addressable really_atomic_lvalue.
1796 Returns false if a failure occurred (an error will already have been
1797 added to the active context for this case). */
1801 mark_addressable (location
*loc
)
1803 tree x
= as_tree ();
1806 switch (TREE_CODE (x
))
1809 if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x
, 1)))
1811 gcc_assert (gcc::jit::active_playback_ctxt
);
1813 active_playback_ctxt
->add_error (loc
,
1814 "cannot take address of "
1823 x
= TREE_OPERAND (x
, 0);
1826 case COMPOUND_LITERAL_EXPR
:
1828 TREE_ADDRESSABLE (x
) = 1;
1835 /* (we don't have a concept of a "register" declaration) */
1838 TREE_ADDRESSABLE (x
) = 1;
1845 /* Construct a playback::rvalue instance (wrapping a tree) for an
1850 get_address (location
*loc
)
1852 tree t_lvalue
= as_tree ();
1853 tree t_thistype
= TREE_TYPE (t_lvalue
);
1854 tree t_ptrtype
= build_pointer_type (t_thistype
);
1855 tree ptr
= fold_build1 (ADDR_EXPR
, t_ptrtype
, t_lvalue
);
1857 get_context ()->set_tree_location (ptr
, loc
);
1858 if (mark_addressable (loc
))
1859 return new rvalue (get_context (), ptr
);
1864 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1865 Provide this finalization hook for calling then they are collected,
1866 which calls the finalizer vfunc. This allows them to call "release"
1867 on any vec<> within them. */
1870 wrapper_finalizer (void *ptr
)
1872 playback::wrapper
*wrapper
= reinterpret_cast <playback::wrapper
*> (ptr
);
1873 wrapper
->finalizer ();
1876 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1877 allocate them using ggc_internal_cleared_alloc. */
1881 operator new (size_t sz
)
1883 return ggc_internal_cleared_alloc (sz
, wrapper_finalizer
, 0, 1);
1887 /* Constructor for gcc:jit::playback::function. */
1889 playback::function::
1890 function (context
*ctxt
,
1892 enum gcc_jit_function_kind kind
)
1894 m_inner_fndecl (fndecl
),
1895 m_inner_bind_expr (NULL
),
1899 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1901 /* Create a BIND_EXPR, and within it, a statement list. */
1902 m_stmt_list
= alloc_stmt_list ();
1903 m_stmt_iter
= tsi_start (m_stmt_list
);
1904 m_inner_block
= make_node (BLOCK
);
1906 build3 (BIND_EXPR
, void_type_node
, NULL
, m_stmt_list
, m_inner_block
);
1910 m_inner_block
= NULL
;
1915 /* Hand-written GC-marking hook for playback functions. */
1918 playback::function::
1921 gt_ggc_m_9tree_node (m_inner_fndecl
);
1922 gt_ggc_m_9tree_node (m_inner_bind_expr
);
1923 gt_ggc_m_9tree_node (m_stmt_list
);
1924 gt_ggc_m_9tree_node (m_inner_block
);
1927 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1931 playback::function::finalizer ()
1933 m_blocks
.release ();
1936 /* Get the return type of a playback function, in tree form. */
1939 playback::function::
1940 get_return_type_as_tree () const
1942 return TREE_TYPE (TREE_TYPE(m_inner_fndecl
));
1945 /* Construct a new local within this playback::function. */
1948 playback::function::
1949 new_local (location
*loc
,
1952 const std::vector
<std::pair
<gcc_jit_variable_attribute
,
1953 std::string
>> &attributes
)
1957 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
1958 get_identifier (name
),
1960 DECL_CONTEXT (inner
) = this->m_inner_fndecl
;
1962 /* Prepend to BIND_EXPR_VARS: */
1963 DECL_CHAIN (inner
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1964 BIND_EXPR_VARS (m_inner_bind_expr
) = inner
;
1966 set_variable_string_attribute (attributes
, inner
);
1969 set_tree_location (inner
, loc
);
1970 return new lvalue (m_ctxt
, inner
);
1973 /* Construct a new block within this playback::function. */
1976 playback::function::
1977 new_block (const char *name
)
1979 gcc_assert (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
);
1981 block
*result
= new playback::block (this, name
);
1982 m_blocks
.safe_push (result
);
1986 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1987 this playback::function. */
1990 playback::function::get_address (location
*loc
)
1992 tree t_fndecl
= as_fndecl ();
1993 tree t_fntype
= TREE_TYPE (t_fndecl
);
1994 tree t_fnptr
= build1 (ADDR_EXPR
, build_pointer_type (t_fntype
), t_fndecl
);
1996 m_ctxt
->set_tree_location (t_fnptr
, loc
);
1997 return new rvalue (m_ctxt
, t_fnptr
);
2000 /* Build a statement list for the function as a whole out of the
2001 lists of statements for the individual blocks, building labels
2005 playback::function::
2011 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
2013 FOR_EACH_VEC_ELT (m_blocks
, i
, b
)
2018 b
->m_label_expr
= build1 (LABEL_EXPR
,
2020 b
->as_label_decl ());
2021 tsi_link_after (&m_stmt_iter
, b
->m_label_expr
, TSI_CONTINUE_LINKING
);
2023 FOR_EACH_VEC_ELT (b
->m_stmts
, j
, stmt
)
2024 tsi_link_after (&m_stmt_iter
, stmt
, TSI_CONTINUE_LINKING
);
2028 /* Finish compiling the given function, potentially running the
2030 The function will have a statement list by now.
2031 Amongst other things, this gimplifies the statement list,
2032 and calls cgraph_node::finalize_function on the function. */
2035 playback::function::
2038 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
2040 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
))
2041 debug_tree (m_stmt_list
);
2043 /* Do we need this to force cgraphunit.cc to output the function? */
2044 if (m_kind
== GCC_JIT_FUNCTION_EXPORTED
)
2046 DECL_EXTERNAL (m_inner_fndecl
) = 0;
2047 DECL_PRESERVE_P (m_inner_fndecl
) = 1;
2050 if (m_kind
== GCC_JIT_FUNCTION_INTERNAL
2051 ||m_kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
2053 DECL_EXTERNAL (m_inner_fndecl
) = 0;
2054 TREE_PUBLIC (m_inner_fndecl
) = 0;
2057 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
2059 /* Seem to need this in gimple-low.cc: */
2060 gcc_assert (m_inner_block
);
2061 DECL_INITIAL (m_inner_fndecl
) = m_inner_block
;
2063 /* how to add to function? the following appears to be how to
2064 set the body of a m_inner_fndecl: */
2065 DECL_SAVED_TREE(m_inner_fndecl
) = m_inner_bind_expr
;
2067 /* Ensure that locals appear in the debuginfo. */
2068 BLOCK_VARS (m_inner_block
) = BIND_EXPR_VARS (m_inner_bind_expr
);
2070 //debug_tree (m_inner_fndecl);
2072 /* Convert to gimple: */
2073 //printf("about to gimplify_function_tree\n");
2074 gimplify_function_tree (m_inner_fndecl
);
2075 //printf("finished gimplify_function_tree\n");
2077 current_function_decl
= m_inner_fndecl
;
2078 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
))
2079 dump_function_to_file (m_inner_fndecl
, stderr
, TDF_VOPS
|TDF_MEMSYMS
|TDF_LINENO
);
2080 //debug_tree (m_inner_fndecl);
2082 //printf("about to add to cgraph\n");
2083 /* Add to cgraph: */
2084 cgraph_node::finalize_function (m_inner_fndecl
, false);
2085 /* This can trigger a collection, so we need to have all of
2086 the funcs as roots. */
2088 current_function_decl
= NULL
;
2091 /* Add to cgraph to output aliases: */
2092 rest_of_decl_compilation (m_inner_fndecl
, true, 0);
2095 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2099 playback::block::finalizer ()
2104 /* Add an eval of the rvalue to the function's statement list. */
2108 add_eval (location
*loc
,
2111 gcc_assert (rvalue
);
2114 set_tree_location (rvalue
->as_tree (), loc
);
2116 add_stmt (rvalue
->as_tree ());
2119 /* Add an assignment to the function's statement list. */
2123 add_assignment (location
*loc
,
2127 gcc_assert (lvalue
);
2128 gcc_assert (rvalue
);
2130 tree t_lvalue
= lvalue
->as_tree ();
2131 tree t_rvalue
= rvalue
->as_tree ();
2132 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
2134 t_rvalue
= build1 (CONVERT_EXPR
,
2135 TREE_TYPE (t_lvalue
),
2138 set_tree_location (t_rvalue
, loc
);
2142 build2 (MODIFY_EXPR
, TREE_TYPE (t_lvalue
),
2143 t_lvalue
, t_rvalue
);
2145 set_tree_location (stmt
, loc
);
2149 /* Add a comment to the function's statement list.
2150 For now this is done by adding a dummy label. */
2154 add_comment (location
*loc
,
2157 /* Wrap the text in C-style comment delimiters. */
2159 (3 /* opening delim */
2161 + 3 /* closing delim */
2162 + 1 /* terminator */);
2163 char *wrapped
= (char *)ggc_internal_alloc (sz
);
2164 snprintf (wrapped
, sz
, "/* %s */", text
);
2166 /* For now we simply implement this by adding a dummy label with a name
2167 containing the given text. */
2168 tree identifier
= get_identifier (wrapped
);
2169 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
2170 identifier
, void_type_node
);
2171 DECL_CONTEXT (label_decl
) = m_func
->as_fndecl ();
2173 tree label_expr
= build1 (LABEL_EXPR
, void_type_node
, label_decl
);
2175 set_tree_location (label_expr
, loc
);
2176 add_stmt (label_expr
);
2179 /* Add a conditional jump statement to the function's statement list. */
2183 add_conditional (location
*loc
,
2188 gcc_assert (boolval
);
2189 gcc_assert (on_true
);
2190 gcc_assert (on_false
);
2192 /* COND_EXPR wants statement lists for the true/false operands, but we
2194 Shim it by creating jumps to the labels */
2195 tree true_jump
= build1 (GOTO_EXPR
, void_type_node
,
2196 on_true
->as_label_decl ());
2198 set_tree_location (true_jump
, loc
);
2200 tree false_jump
= build1 (GOTO_EXPR
, void_type_node
,
2201 on_false
->as_label_decl ());
2203 set_tree_location (false_jump
, loc
);
2206 build3 (COND_EXPR
, void_type_node
, boolval
->as_tree (),
2207 true_jump
, false_jump
);
2209 set_tree_location (stmt
, loc
);
2213 /* Add an unconditional jump statement to the function's statement list. */
2217 add_jump (location
*loc
,
2220 gcc_assert (target
);
2222 // see c_finish_loop
2223 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
2226 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
2227 TREE_USED (target
->as_label_decl ()) = 1;
2228 tree stmt
= build1 (GOTO_EXPR
, void_type_node
, target
->as_label_decl ());
2230 set_tree_location (stmt
, loc
);
2236 c_finish_goto_label (location_t loc, tree label)
2238 tree decl = lookup_label_for_goto (loc, label);
2241 TREE_USED (decl) = 1;
2243 tree t = build1 (GOTO_EXPR, void_type_node, decl);
2244 SET_EXPR_LOCATION (t, loc);
2245 return add_stmt (t);
2252 /* Add a return statement to the function's statement list. */
2256 add_return (location
*loc
,
2259 tree modify_retval
= NULL
;
2260 tree return_type
= m_func
->get_return_type_as_tree ();
2263 tree t_lvalue
= DECL_RESULT (m_func
->as_fndecl ());
2264 tree t_rvalue
= rvalue
->as_tree ();
2265 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
2266 t_rvalue
= build1 (CONVERT_EXPR
,
2267 TREE_TYPE (t_lvalue
),
2269 modify_retval
= build2 (MODIFY_EXPR
, return_type
,
2270 t_lvalue
, t_rvalue
);
2272 set_tree_location (modify_retval
, loc
);
2274 tree return_stmt
= build1 (RETURN_EXPR
, return_type
,
2277 set_tree_location (return_stmt
, loc
);
2279 add_stmt (return_stmt
);
2282 /* Helper function for playback::block::add_switch.
2283 Construct a case label for the given range, followed by a goto stmt
2284 to the given block, appending them to stmt list *ptr_t_switch_body. */
2287 add_case (tree
*ptr_t_switch_body
,
2290 playback::block
*dest_block
)
2292 tree t_label
= create_artificial_label (UNKNOWN_LOCATION
);
2293 DECL_CONTEXT (t_label
) = dest_block
->get_function ()->as_fndecl ();
2296 build_case_label (t_low_value
, t_high_value
, t_label
);
2297 append_to_statement_list (t_case_label
, ptr_t_switch_body
);
2300 build1 (GOTO_EXPR
, void_type_node
, dest_block
->as_label_decl ());
2301 append_to_statement_list (t_goto_stmt
, ptr_t_switch_body
);
2304 /* Add a switch statement to the function's statement list.
2306 We create a switch body, and populate it with case labels, each
2307 followed by a goto to the desired block. */
2311 add_switch (location
*loc
,
2313 block
*default_block
,
2314 const auto_vec
<case_
> *cases
)
2317 - c/c-typeck.cc: c_start_case
2318 - c-family/c-common.cc:c_add_case_label
2319 - java/expr.cc:expand_java_switch and expand_java_add_case
2320 We've already rejected overlaps and duplicates in
2321 libgccjit.cc:case_range_validator::validate. */
2323 tree t_expr
= expr
->as_tree ();
2324 tree t_type
= TREE_TYPE (t_expr
);
2326 tree t_switch_body
= alloc_stmt_list ();
2330 FOR_EACH_VEC_ELT (*cases
, i
, c
)
2332 tree t_low_value
= c
->m_min_value
->as_tree ();
2333 tree t_high_value
= c
->m_max_value
->as_tree ();
2334 add_case (&t_switch_body
, t_low_value
, t_high_value
, c
->m_dest_block
);
2336 /* Default label. */
2337 add_case (&t_switch_body
, NULL_TREE
, NULL_TREE
, default_block
);
2339 tree switch_stmt
= build2 (SWITCH_EXPR
, t_type
, t_expr
, t_switch_body
);
2341 set_tree_location (switch_stmt
, loc
);
2342 add_stmt (switch_stmt
);
2345 /* Convert OPERANDS to a tree-based chain suitable for creating an
2347 Compare with c_parser_asm_operands. */
2350 build_operand_chain (const auto_vec
<playback::asm_operand
> *operands
)
2352 tree result
= NULL_TREE
;
2354 playback::asm_operand
*asm_op
;
2355 FOR_EACH_VEC_ELT (*operands
, i
, asm_op
)
2357 tree name
= build_string (asm_op
->m_asm_symbolic_name
);
2358 tree str
= build_string (asm_op
->m_constraint
);
2359 tree value
= asm_op
->m_expr
;
2360 result
= chainon (result
,
2361 build_tree_list (build_tree_list (name
, str
),
2367 /* Convert CLOBBERS to a tree-based list suitable for creating an
2369 Compare with c_parser_asm_clobbers. */
2372 build_clobbers (const auto_vec
<const char *> *clobbers
)
2374 tree list
= NULL_TREE
;
2376 const char *clobber
;
2377 FOR_EACH_VEC_ELT (*clobbers
, i
, clobber
)
2379 tree str
= build_string (clobber
);
2380 list
= tree_cons (NULL_TREE
, str
, list
);
2385 /* Convert BLOCKS to a tree-based list suitable for creating an
2387 Compare with c_parser_asm_goto_operands. */
2390 build_goto_operands (const auto_vec
<playback::block
*> *blocks
)
2392 tree list
= NULL_TREE
;
2395 FOR_EACH_VEC_ELT (*blocks
, i
, b
)
2397 tree label
= b
->as_label_decl ();
2398 tree name
= build_string (IDENTIFIER_POINTER (DECL_NAME (label
)));
2399 TREE_USED (label
) = 1;
2400 list
= tree_cons (name
, label
, list
);
2402 return nreverse (list
);
2405 /* Add an extended asm statement to this block.
2407 Compare with c_parser_asm_statement (in c/c-parser.cc)
2408 and build_asm_expr (in c/c-typeck.cc). */
2411 playback::block::add_extended_asm (location
*loc
,
2412 const char *asm_template
,
2415 const auto_vec
<asm_operand
> *outputs
,
2416 const auto_vec
<asm_operand
> *inputs
,
2417 const auto_vec
<const char *> *clobbers
,
2418 const auto_vec
<block
*> *goto_blocks
)
2420 tree t_string
= build_string (asm_template
);
2421 tree t_outputs
= build_operand_chain (outputs
);
2422 tree t_inputs
= build_operand_chain (inputs
);
2423 tree t_clobbers
= build_clobbers (clobbers
);
2424 tree t_labels
= build_goto_operands (goto_blocks
);
2426 = resolve_asm_operand_names (t_string
, t_outputs
, t_inputs
, t_labels
);
2428 = build5 (ASM_EXPR
, void_type_node
,
2429 t_string
, t_outputs
, t_inputs
, t_clobbers
, t_labels
);
2431 /* asm statements without outputs, including simple ones, are treated
2433 ASM_VOLATILE_P (asm_stmt
) = (outputs
->length () == 0);
2434 ASM_INPUT_P (asm_stmt
) = 0; /* extended asm stmts are not "simple". */
2435 ASM_INLINE_P (asm_stmt
) = is_inline
;
2437 ASM_VOLATILE_P (asm_stmt
) = 1;
2439 set_tree_location (asm_stmt
, loc
);
2440 add_stmt (asm_stmt
);
2443 /* Constructor for gcc::jit::playback::block. */
2446 block (function
*func
,
2456 identifier
= get_identifier (name
);
2459 m_label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
2460 identifier
, void_type_node
);
2461 DECL_CONTEXT (m_label_decl
) = func
->as_fndecl ();
2462 m_label_expr
= NULL
;
2465 // This is basically std::lock_guard but it can call the private lock/unlock
2466 // members of playback::context.
2467 struct playback::context::scoped_lock
2469 scoped_lock (context
&ctx
) : m_ctx (&ctx
) { m_ctx
->lock (); }
2470 ~scoped_lock () { m_ctx
->unlock (); }
2474 // Not movable or copyable.
2475 scoped_lock (scoped_lock
&&) = delete;
2476 scoped_lock
&operator= (scoped_lock
&&) = delete;
2479 /* Compile a playback::context:
2481 - Use the context's options to cconstruct command-line options, and
2482 call into the rest of GCC (toplev::main).
2483 - Assuming it succeeds, we have a .s file.
2484 - We then run the "postprocess" vfunc:
2486 (A) In-memory compile ("gcc_jit_context_compile")
2488 For an in-memory compile we have the playback::compile_to_memory
2489 subclass; "postprocess" will convert the .s file to a .so DSO,
2490 and load it in memory (via dlopen), wrapping the result up as
2491 a jit::result and returning it.
2493 (B) Compile to file ("gcc_jit_context_compile_to_file")
2495 When compiling to a file, we have the playback::compile_to_file
2496 subclass; "postprocess" will either copy the .s file to the
2497 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
2498 the driver to convert it as necessary, copying the result. */
2504 JIT_LOG_SCOPE (get_logger ());
2506 const char *ctxt_progname
;
2508 int keep_intermediates
=
2509 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
);
2511 m_tempdir
= new tempdir (get_logger (), keep_intermediates
);
2512 if (!m_tempdir
->create ())
2515 /* Call into the rest of gcc.
2516 For now, we have to assemble command-line options to pass into
2517 toplev::main, so that they can be parsed. */
2519 /* Pass in user-provided program name as argv0, if any, so that it
2520 makes it into GCC's "progname" global, used in various diagnostics. */
2521 ctxt_progname
= get_str_option (GCC_JIT_STR_OPTION_PROGNAME
);
2524 ctxt_progname
= "libgccjit.so";
2526 auto_vec
<recording::requested_dump
> requested_dumps
;
2527 m_recording_ctxt
->get_all_requested_dumps (&requested_dumps
);
2529 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
2530 scoped_lock
lock(*this);
2532 auto_string_vec fake_args
;
2533 make_fake_args (&fake_args
, ctxt_progname
, &requested_dumps
);
2534 if (errors_occurred ())
2537 /* This runs the compiler. */
2538 toplev
toplev (get_timer (), /* external_timer */
2539 false); /* init_signals */
2540 enter_scope ("toplev::main");
2542 for (unsigned i
= 0; i
< fake_args
.length (); i
++)
2543 get_logger ()->log ("argv[%i]: %s", i
, fake_args
[i
]);
2544 toplev
.main (fake_args
.length (),
2545 const_cast <char **> (fake_args
.address ()));
2546 exit_scope ("toplev::main");
2548 /* Extracting dumps makes use of the gcc::dump_manager, hence we
2549 need to do it between toplev::main (which creates the dump manager)
2550 and toplev::finalize (which deletes it). */
2551 extract_any_requested_dumps (&requested_dumps
);
2553 /* Clean up the compiler. */
2554 enter_scope ("toplev::finalize");
2556 exit_scope ("toplev::finalize");
2558 /* Ideally we would release the jit mutex here, but we can't yet since
2559 followup activities use timevars, which are global state. */
2561 if (errors_occurred ())
2564 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
))
2565 dump_generated_code ();
2567 /* We now have a .s file.
2569 Run any postprocessing steps. This will either convert the .s file to
2570 a .so DSO, and load it in memory (playback::compile_to_memory), or
2571 convert the .s file to the requested output format, and copy it to a
2572 given file (playback::compile_to_file). */
2573 postprocess (ctxt_progname
);
2576 /* Implementation of class gcc::jit::playback::compile_to_memory,
2577 a subclass of gcc::jit::playback::context. */
2579 /* playback::compile_to_memory's trivial constructor. */
2581 playback::compile_to_memory::compile_to_memory (recording::context
*ctxt
) :
2582 playback::context (ctxt
),
2585 JIT_LOG_SCOPE (get_logger ());
2588 /* Implementation of the playback::context::process vfunc for compiling
2591 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
2592 wrapping the result up as a jit::result and returning it. */
2595 playback::compile_to_memory::postprocess (const char *ctxt_progname
)
2597 JIT_LOG_SCOPE (get_logger ());
2598 convert_to_dso (ctxt_progname
);
2599 if (errors_occurred ())
2601 m_result
= dlopen_built_dso ();
2604 /* Implementation of class gcc::jit::playback::compile_to_file,
2605 a subclass of gcc::jit::playback::context. */
2607 /* playback::compile_to_file's trivial constructor. */
2609 playback::compile_to_file::compile_to_file (recording::context
*ctxt
,
2610 enum gcc_jit_output_kind output_kind
,
2611 const char *output_path
) :
2612 playback::context (ctxt
),
2613 m_output_kind (output_kind
),
2614 m_output_path (output_path
)
2616 JIT_LOG_SCOPE (get_logger ());
2619 /* Implementation of the playback::context::process vfunc for compiling
2622 Either copy the .s file to the given destination (for
2623 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
2624 as necessary, copying the result. */
2627 playback::compile_to_file::postprocess (const char *ctxt_progname
)
2629 JIT_LOG_SCOPE (get_logger ());
2631 /* The driver takes different actions based on the filename, so
2632 we provide a filename with an appropriate suffix for the
2633 output kind, and then copy it up to the user-provided path,
2634 rather than directly compiling it to the requested output path. */
2636 switch (m_output_kind
)
2641 case GCC_JIT_OUTPUT_KIND_ASSEMBLER
:
2642 copy_file (get_tempdir ()->get_path_s_file (),
2644 /* The .s file is automatically unlinked by tempdir::~tempdir. */
2647 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE
:
2649 char *tmp_o_path
= ::concat (get_tempdir ()->get_path (),
2652 invoke_driver (ctxt_progname
,
2653 get_tempdir ()->get_path_s_file (),
2656 false, /* bool shared, */
2657 false);/* bool run_linker */
2658 if (!errors_occurred ())
2660 copy_file (tmp_o_path
,
2662 get_tempdir ()->add_temp_file (tmp_o_path
);
2669 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY
:
2670 invoke_driver (ctxt_progname
,
2671 get_tempdir ()->get_path_s_file (),
2672 get_tempdir ()->get_path_so_file (),
2674 true, /* bool shared, */
2675 true);/* bool run_linker */
2676 if (!errors_occurred ())
2677 copy_file (get_tempdir ()->get_path_so_file (),
2679 /* The .so file is automatically unlinked by tempdir::~tempdir. */
2682 case GCC_JIT_OUTPUT_KIND_EXECUTABLE
:
2684 char *tmp_exe_path
= ::concat (get_tempdir ()->get_path (),
2687 invoke_driver (ctxt_progname
,
2688 get_tempdir ()->get_path_s_file (),
2691 false, /* bool shared, */
2692 true);/* bool run_linker */
2693 if (!errors_occurred ())
2695 copy_file (tmp_exe_path
,
2697 get_tempdir ()->add_temp_file (tmp_exe_path
);
2700 free (tmp_exe_path
);
2708 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2709 the "executable" bits).
2711 Any errors that occur are reported on the context and hence count as
2712 a failure of the compile.
2714 We can't in general hardlink or use "rename" from the tempdir since
2715 it might be on a different filesystem to the destination. For example,
2716 I get EXDEV: "Invalid cross-device link". */
2719 playback::compile_to_file::copy_file (const char *src_path
,
2720 const char *dst_path
)
2722 JIT_LOG_SCOPE (get_logger ());
2725 get_logger ()->log ("src_path: %s", src_path
);
2726 get_logger ()->log ("dst_path: %s", dst_path
);
2731 size_t total_sz_in
= 0;
2732 size_t total_sz_out
= 0;
2735 struct stat stat_buf
;
2737 f_in
= fopen (src_path
, "rb");
2741 "unable to open %s for reading: %s",
2747 /* Use stat on the filedescriptor to get the mode,
2748 so that we can copy it over (in particular, the
2749 "executable" bits). */
2750 if (fstat (fileno (f_in
), &stat_buf
) == -1)
2753 "unable to fstat %s: %s",
2760 f_out
= fopen (dst_path
, "wb");
2764 "unable to open %s for writing: %s",
2771 while ( (sz_in
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2773 total_sz_in
+= sz_in
;
2774 size_t sz_out_remaining
= sz_in
;
2775 size_t sz_out_so_far
= 0;
2776 while (sz_out_remaining
)
2778 size_t sz_out
= fwrite (buf
+ sz_out_so_far
,
2782 gcc_assert (sz_out
<= sz_out_remaining
);
2786 "error writing to %s: %s",
2793 total_sz_out
+= sz_out
;
2794 sz_out_so_far
+= sz_out
;
2795 sz_out_remaining
-= sz_out
;
2797 gcc_assert (sz_out_so_far
== sz_in
);
2802 "error reading from %s: %s",
2808 gcc_assert (total_sz_in
== total_sz_out
);
2810 get_logger ()->log ("total bytes copied: %zu", total_sz_out
);
2812 /* fchmod does not exist in Windows. */
2814 /* Set the permissions of the copy to those of the original file,
2815 in particular the "executable" bits. */
2816 if (fchmod (fileno (f_out
), stat_buf
.st_mode
) == -1)
2818 "error setting mode of %s: %s",
2826 /* Helper functions for gcc::jit::playback::context::compile. */
2828 /* This mutex guards gcc::jit::recording::context::compile, so that only
2829 one thread can be accessing the bulk of GCC's state at once. */
2831 static std::mutex jit_mutex
;
2833 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2836 playback::context::lock ()
2838 auto_timevar
tv (get_timer (), TV_JIT_ACQUIRING_MUTEX
);
2840 /* Acquire the big GCC mutex. */
2841 JIT_LOG_SCOPE (get_logger ());
2843 gcc_assert (active_playback_ctxt
== NULL
);
2844 active_playback_ctxt
= this;
2847 /* Release jit_mutex and clear the active playback ctxt. */
2850 playback::context::unlock ()
2852 /* Release the big GCC mutex. */
2853 JIT_LOG_SCOPE (get_logger ());
2854 gcc_assert (active_playback_ctxt
== this);
2855 active_playback_ctxt
= NULL
;
2856 jit_mutex
.unlock ();
2859 /* Callback used by gcc::jit::playback::context::make_fake_args when
2860 invoking driver_get_configure_time_options.
2861 Populate a vec <char * > with the configure-time options. */
2864 append_arg_from_driver (const char *option
, void *user_data
)
2866 gcc_assert (option
);
2867 gcc_assert (user_data
);
2868 vec
<char *> *argvec
= static_cast <vec
<char *> *> (user_data
);
2869 argvec
->safe_push (concat ("-", option
, NULL
));
2872 /* Build a fake argv for toplev::main from the options set
2873 by the user on the context . */
2877 make_fake_args (vec
<char *> *argvec
,
2878 const char *ctxt_progname
,
2879 vec
<recording::requested_dump
> *requested_dumps
)
2881 JIT_LOG_SCOPE (get_logger ());
2883 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2884 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2886 ADD_ARG (ctxt_progname
);
2887 ADD_ARG (get_path_c_file ());
2890 /* Handle int options: */
2891 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
))
2895 "unrecognized optimization level: %i",
2896 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
));
2915 /* What about -Os? */
2917 /* Handle bool options: */
2918 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2921 /* Suppress timing (and other) info. */
2922 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
))
2928 /* Aggressively garbage-collect, to shake out bugs: */
2929 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC
))
2931 ADD_ARG ("--param=ggc-min-expand=0");
2932 ADD_ARG ("--param=ggc-min-heapsize=0");
2935 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
))
2937 ADD_ARG ("-fdump-tree-all");
2938 ADD_ARG ("-fdump-rtl-all");
2939 ADD_ARG ("-fdump-ipa-all");
2942 /* Add "-fdump-" options for any calls to
2943 gcc_jit_context_enable_dump. */
2946 recording::requested_dump
*d
;
2947 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2949 char *arg
= concat ("-fdump-", d
->m_dumpname
, NULL
);
2950 ADD_ARG_TAKE_OWNERSHIP (arg
);
2954 /* PR jit/64810: Add any target-specific default options
2955 from OPTION_DEFAULT_SPECS, normally provided by the driver
2956 in the non-jit case.
2958 The target-specific code can define OPTION_DEFAULT_SPECS:
2959 default command options in the form of spec macros for the
2960 driver to expand ().
2962 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2963 if not overriden, injects the defaults as extra arguments to
2965 For the jit case, we need to add these arguments here. The
2966 input format (using the specs language) means that we have to run
2967 part of the driver code here (driver_get_configure_time_options).
2969 To avoid running the spec-expansion code every time, we just do
2970 it the first time (via a function-static flag), saving the result
2971 into a function-static vec.
2972 This flag and vec are global state (i.e. per-process).
2973 They are guarded by the jit mutex. */
2975 static bool have_configure_time_options
= false;
2976 static vec
<char *> configure_time_options
;
2978 if (have_configure_time_options
)
2979 log ("reusing cached configure-time options");
2982 have_configure_time_options
= true;
2983 log ("getting configure-time options from driver");
2984 driver_get_configure_time_options (append_arg_from_driver
,
2985 &configure_time_options
);
2992 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2993 log ("configure_time_options[%i]: %s", i
, opt
);
2995 /* configure_time_options should now contain the expanded options
2996 from OPTION_DEFAULT_SPECS (if any). */
2997 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
3000 gcc_assert (opt
[0] == '-');
3006 ADD_ARG ("-ftime-report");
3008 /* Add any user-provided extra options, starting with any from
3010 m_recording_ctxt
->append_command_line_options (argvec
);
3013 #undef ADD_ARG_TAKE_OWNERSHIP
3016 /* The second half of the implementation of gcc_jit_context_enable_dump.
3017 Iterate through the requested dumps, reading the underlying files
3018 into heap-allocated buffers, writing pointers to the buffers into
3019 the char ** pointers provided by client code.
3020 Client code is responsible for calling free on the results. */
3024 extract_any_requested_dumps (vec
<recording::requested_dump
> *requested_dumps
)
3026 JIT_LOG_SCOPE (get_logger ());
3029 recording::requested_dump
*d
;
3030 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
3032 dump_file_info
*dfi
;
3036 dfi
= g
->get_dumps ()->get_dump_file_info_by_switch (d
->m_dumpname
);
3039 add_error (NULL
, "unrecognized dump: %s", d
->m_dumpname
);
3043 filename
= g
->get_dumps ()->get_dump_file_name (dfi
);
3044 content
= read_dump_file (filename
);
3045 *(d
->m_out_ptr
) = content
;
3046 m_tempdir
->add_temp_file (filename
);
3050 /* Helper function for playback::context::extract_any_requested_dumps
3051 (itself for use in implementation of gcc_jit_context_enable_dump).
3053 Attempt to read the complete file at the given path, returning the
3054 bytes found there as a buffer.
3055 The caller is responsible for calling free on the result.
3056 Errors will be reported on the context, and lead to NULL being
3057 returned; an out-of-memory error will terminate the process. */
3060 playback::context::read_dump_file (const char *path
)
3062 char *result
= NULL
;
3063 size_t total_sz
= 0;
3068 f_in
= fopen (path
, "r");
3071 add_error (NULL
, "unable to open %s for reading", path
);
3075 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
3077 size_t old_total_sz
= total_sz
;
3079 result
= reinterpret_cast <char *> (xrealloc (result
, total_sz
+ 1));
3080 memcpy (result
+ old_total_sz
, buf
, sz
);
3085 add_error (NULL
, "error reading from %s", path
);
3095 result
[total_sz
] = '\0';
3099 return xstrdup ("");
3102 /* Part of playback::context::compile ().
3104 We have a .s file; we want a .so file.
3105 We could reuse parts of gcc/gcc.cc to do this.
3106 For now, just use the driver binary from the install, as
3107 named in gcc-driver-name.h
3108 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
3112 convert_to_dso (const char *ctxt_progname
)
3114 JIT_LOG_SCOPE (get_logger ());
3116 invoke_driver (ctxt_progname
,
3117 m_tempdir
->get_path_s_file (),
3118 m_tempdir
->get_path_so_file (),
3120 true, /* bool shared, */
3121 true);/* bool run_linker */
3124 static const char * const gcc_driver_name
= GCC_DRIVER_NAME
;
3128 invoke_driver (const char *ctxt_progname
,
3129 const char *input_file
,
3130 const char *output_file
,
3135 JIT_LOG_SCOPE (get_logger ());
3137 bool embedded_driver
3138 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER
);
3140 /* Currently this lumps together both assembling and linking into
3142 auto_timevar
assemble_timevar (get_timer (), tv_id
);
3143 auto_string_vec argvec
;
3144 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
3146 ADD_ARG (gcc_driver_name
);
3148 add_multilib_driver_arguments (&argvec
);
3151 ADD_ARG ("-shared");
3156 ADD_ARG (input_file
);
3158 ADD_ARG (output_file
);
3160 /* Don't use the linker plugin.
3161 If running with just a "make" and not a "make install", then we'd
3163 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
3164 libto_plugin is a .la at build time, with it becoming installed with
3165 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
3167 ADD_ARG ("-fno-use-linker-plugin");
3169 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
3170 /* macOS's linker defaults to treating undefined symbols as errors.
3171 If the context has any imported functions or globals they will be
3172 undefined until the .so is dynamically-linked into the process.
3173 Ensure that the driver passes in "-undefined dynamic_lookup" to the
3175 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
3181 /* Add any user-provided driver extra options. */
3183 m_recording_ctxt
->append_driver_options (&argvec
);
3187 /* pex_one's error-handling requires pname to be non-NULL. */
3188 gcc_assert (ctxt_progname
);
3191 for (unsigned i
= 0; i
< argvec
.length (); i
++)
3192 get_logger ()->log ("argv[%i]: %s", i
, argvec
[i
]);
3194 if (embedded_driver
)
3195 invoke_embedded_driver (&argvec
);
3197 invoke_external_driver (ctxt_progname
, &argvec
);
3202 invoke_embedded_driver (const vec
<char *> *argvec
)
3204 JIT_LOG_SCOPE (get_logger ());
3205 driver
d (true, /* can_finalize */
3207 int result
= d
.main (argvec
->length (),
3208 const_cast <char **> (argvec
->address ()));
3211 add_error (NULL
, "error invoking gcc driver");
3216 invoke_external_driver (const char *ctxt_progname
,
3217 vec
<char *> *argvec
)
3219 JIT_LOG_SCOPE (get_logger ());
3221 int exit_status
= 0;
3224 /* pex argv arrays are NULL-terminated. */
3225 argvec
->safe_push (NULL
);
3227 errmsg
= pex_one (PEX_SEARCH
, /* int flags, */
3229 const_cast <char *const *> (argvec
->address ()),
3230 ctxt_progname
, /* const char *pname */
3231 NULL
, /* const char *outname */
3232 NULL
, /* const char *errname */
3233 &exit_status
, /* int *status */
3234 &err
); /* int *err*/
3237 add_error (NULL
, "error invoking gcc driver: %s", errmsg
);
3241 /* pex_one can return a NULL errmsg when the executable wasn't
3242 found (or doesn't exist), so trap these cases also. */
3243 if (exit_status
|| err
)
3246 "error invoking gcc driver: exit_status: %i err: %i",
3249 "whilst attempting to run a driver named: %s",
3258 /* Extract the target-specific MULTILIB_DEFAULTS to
3259 multilib_defaults_raw for use by
3260 playback::context::add_multilib_driver_arguments (). */
3262 #ifndef MULTILIB_DEFAULTS
3263 #define MULTILIB_DEFAULTS { "" }
3266 static const char *const multilib_defaults_raw
[] = MULTILIB_DEFAULTS
;
3268 /* Helper function for playback::context::invoke_driver ().
3270 32-bit and 64-bit multilib peer builds of libgccjit.so may share
3271 a driver binary. We need to pass in options to the shared driver
3272 to get the appropriate assembler/linker options for this multilib
3277 add_multilib_driver_arguments (vec
<char *> *argvec
)
3279 JIT_LOG_SCOPE (get_logger ());
3281 /* Add copies of the arguments in multilib_defaults_raw to argvec,
3282 prepending each with a "-". */
3283 for (size_t i
= 0; i
< ARRAY_SIZE (multilib_defaults_raw
); i
++)
3284 if (multilib_defaults_raw
[i
][0])
3285 argvec
->safe_push (concat ("-", multilib_defaults_raw
[i
], NULL
));
3288 /* Dynamically-link the built DSO file into this process, using dlopen.
3289 Wrap it up within a jit::result *, and return that.
3290 Return NULL if any errors occur, reporting them on this context. */
3296 JIT_LOG_SCOPE (get_logger ());
3297 auto_timevar
load_timevar (get_timer (), TV_LOAD
);
3298 result::handle handle
= NULL
;
3299 result
*result_obj
= NULL
;
3302 /* Clear any existing error. */
3305 handle
= LoadLibrary(m_tempdir
->get_path_so_file ());
3306 if (GetLastError() != 0) {
3310 const char *error
= NULL
;
3311 /* Clear any existing error. */
3314 handle
= dlopen (m_tempdir
->get_path_so_file (),
3315 RTLD_NOW
| RTLD_LOCAL
);
3316 if ((error
= dlerror()) != NULL
) {
3317 add_error (NULL
, "%s", error
);
3323 /* We've successfully dlopened the result; create a
3324 jit::result object to wrap it.
3326 We're done with the tempdir for now, but if the user
3327 has requested debugging, the user's debugger might not
3328 be capable of dealing with the .so file being unlinked
3329 immediately, so keep it around until after the result
3330 is released. We do this by handing over ownership of
3331 the jit::tempdir to the result. See PR jit/64206. */
3332 tempdir
*handover_tempdir
;
3333 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
3335 handover_tempdir
= m_tempdir
;
3337 /* The tempdir will eventually be cleaned up in the
3338 jit::result's dtor. */
3339 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
3340 " handing over tempdir to jit::result");
3344 handover_tempdir
= NULL
;
3345 /* ... and retain ownership of m_tempdir so we clean it
3346 up it the playback::context's dtor. */
3347 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
3348 " retaining ownership of tempdir");
3351 result_obj
= new result (get_logger (), handle
, handover_tempdir
);
3359 /* Top-level hook for playing back a recording context.
3361 This plays back m_recording_ctxt, and, if no errors
3362 occurred builds statement lists for and then postprocesses
3363 every function in the result. */
3369 JIT_LOG_SCOPE (get_logger ());
3373 /* Replay the recorded events: */
3374 timevar_push (TV_JIT_REPLAY
);
3376 /* Ensure that builtins that could be needed during optimization
3377 get created ahead of time. */
3378 builtins_manager
*bm
= m_recording_ctxt
->get_builtins_manager ();
3379 bm
->ensure_optimization_builtins_exist ();
3381 m_recording_ctxt
->replay_into (this);
3383 /* Clean away the temporary references from recording objects
3384 to playback objects. We have to do this now since the
3385 latter are GC-allocated, but the former don't mark these
3386 refs. Hence we must stop using them before the GC can run. */
3387 m_recording_ctxt
->disassociate_from_playback ();
3389 /* The builtins_manager is associated with the recording::context
3390 and might be reused for future compiles on other playback::contexts,
3391 but its m_attributes array is not GTY-labeled and hence will become
3392 nonsense if the GC runs. Purge this state. */
3393 bm
->finish_playback ();
3395 timevar_pop (TV_JIT_REPLAY
);
3397 if (!errors_occurred ())
3402 /* No GC can happen yet; process the cached source locations. */
3403 handle_locations ();
3405 /* Finalize globals. See how FORTRAN 95 does it in gfc_be_parse_file()
3406 for a simple reference. */
3407 FOR_EACH_VEC_ELT (m_globals
, i
, global
)
3408 rest_of_decl_compilation (global
, true, true);
3410 wrapup_global_declarations (m_globals
.address(), m_globals
.length());
3412 /* We've now created tree nodes for the stmts in the various blocks
3413 in each function, but we haven't built each function's single stmt
3414 list yet. Do so now. */
3415 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
3416 func
->build_stmt_list ();
3418 /* No GC can have happened yet. */
3420 /* Postprocess the functions. This could trigger GC. */
3421 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
3424 func
->postprocess ();
3429 /* Dump the generated .s file to stderr. */
3433 dump_generated_code ()
3435 JIT_LOG_SCOPE (get_logger ());
3438 FILE *f_in
= fopen (get_path_s_file (), "r");
3442 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
3443 fwrite (buf
, 1, sz
, stderr
);
3448 /* Get the supposed path of the notional "fake.c" file within the
3449 tempdir. This file doesn't exist, but the rest of the compiler
3454 get_path_c_file () const
3456 return m_tempdir
->get_path_c_file ();
3459 /* Get the path of the assembler output file "fake.s" file within the
3464 get_path_s_file () const
3466 return m_tempdir
->get_path_s_file ();
3469 /* Get the path of the DSO object file "fake.so" file within the
3474 get_path_so_file () const
3476 return m_tempdir
->get_path_so_file ();
3479 /* qsort comparator for comparing pairs of playback::source_line *,
3480 ordering them by line number. */
3483 line_comparator (const void *lhs
, const void *rhs
)
3485 const playback::source_line
*line_lhs
= \
3486 *static_cast<const playback::source_line
* const*> (lhs
);
3487 const playback::source_line
*line_rhs
= \
3488 *static_cast<const playback::source_line
* const*> (rhs
);
3489 return line_lhs
->get_line_num () - line_rhs
->get_line_num ();
3492 /* qsort comparator for comparing pairs of playback::location *,
3493 ordering them by column number. */
3496 location_comparator (const void *lhs
, const void *rhs
)
3498 const playback::location
*loc_lhs
= \
3499 *static_cast<const playback::location
* const *> (lhs
);
3500 const playback::location
*loc_rhs
= \
3501 *static_cast<const playback::location
* const *> (rhs
);
3502 return loc_lhs
->get_column_num () - loc_rhs
->get_column_num ();
3505 /* Initialize the NAME_TYPE of the primitive types as well as some
3511 /* See lto_init () in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc
3512 for reference. If TYPE_NAME is not set, debug info will not contain types */
3513 #define NAME_TYPE(t,n) \
3515 TYPE_NAME (t) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, \
3516 get_identifier (n), t)
3518 NAME_TYPE (integer_type_node
, "int");
3519 NAME_TYPE (char_type_node
, "char");
3520 NAME_TYPE (long_integer_type_node
, "long int");
3521 NAME_TYPE (unsigned_type_node
, "unsigned int");
3522 NAME_TYPE (long_unsigned_type_node
, "long unsigned int");
3523 NAME_TYPE (long_long_integer_type_node
, "long long int");
3524 NAME_TYPE (long_long_unsigned_type_node
, "long long unsigned int");
3525 NAME_TYPE (short_integer_type_node
, "short int");
3526 NAME_TYPE (short_unsigned_type_node
, "short unsigned int");
3527 if (signed_char_type_node
!= char_type_node
)
3528 NAME_TYPE (signed_char_type_node
, "signed char");
3529 if (unsigned_char_type_node
!= char_type_node
)
3530 NAME_TYPE (unsigned_char_type_node
, "unsigned char");
3531 NAME_TYPE (float_type_node
, "float");
3532 NAME_TYPE (double_type_node
, "double");
3533 NAME_TYPE (long_double_type_node
, "long double");
3534 NAME_TYPE (void_type_node
, "void");
3535 NAME_TYPE (boolean_type_node
, "bool");
3536 NAME_TYPE (complex_float_type_node
, "complex float");
3537 NAME_TYPE (complex_double_type_node
, "complex double");
3538 NAME_TYPE (complex_long_double_type_node
, "complex long double");
3540 m_const_char_ptr
= build_pointer_type(
3541 build_qualified_type (char_type_node
, TYPE_QUAL_CONST
));
3543 NAME_TYPE (m_const_char_ptr
, "char");
3544 NAME_TYPE (size_type_node
, "size_t");
3545 NAME_TYPE (fileptr_type_node
, "FILE");
3549 /* Our API allows locations to be created in arbitrary orders, but the
3550 linemap API requires locations to be created in ascending order
3551 as if we were tokenizing files.
3553 This hook sorts all of the locations that have been created, and
3554 calls into the linemap API, creating linemap entries in sorted order
3555 for our locations. */
3561 /* Create the source code locations, following the ordering rules
3562 imposed by the linemap API.
3564 line_table is a global. */
3565 JIT_LOG_SCOPE (get_logger ());
3569 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
3571 linemap_add (line_table
, LC_ENTER
, false, file
->get_filename (), 0);
3573 /* Sort lines by ascending line numbers. */
3574 file
->m_source_lines
.qsort (&line_comparator
);
3578 FOR_EACH_VEC_ELT (file
->m_source_lines
, j
, line
)
3583 /* Sort locations in line by ascending column numbers. */
3584 line
->m_locations
.qsort (&location_comparator
);
3586 /* Determine maximum column within this line. */
3587 gcc_assert (line
->m_locations
.length () > 0);
3588 location
*final_column
=
3589 line
->m_locations
[line
->m_locations
.length () - 1];
3590 int max_col
= final_column
->get_column_num ();
3592 linemap_line_start (line_table
, line
->get_line_num (), max_col
);
3593 FOR_EACH_VEC_ELT (line
->m_locations
, k
, loc
)
3596 linemap_position_for_column (line_table
, loc
->get_column_num ());
3600 linemap_add (line_table
, LC_LEAVE
, false, NULL
, 0);
3603 /* line_table should now be populated; every playback::location should
3604 now have an m_srcloc. */
3606 /* Now assign them to tree nodes as appropriate. */
3607 std::pair
<tree
, location
*> *cached_location
;
3609 FOR_EACH_VEC_ELT (m_cached_locations
, i
, cached_location
)
3611 tree t
= cached_location
->first
;
3612 location_t srcloc
= cached_location
->second
->m_srcloc
;
3614 /* This covers expressions: */
3615 if (CAN_HAVE_LOCATION_P (t
))
3616 SET_EXPR_LOCATION (t
, srcloc
);
3617 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t
), TS_DECL_MINIMAL
))
3618 DECL_SOURCE_LOCATION (t
) = srcloc
;
3621 /* Don't know how to set location on this node. */
3626 /* We handle errors on a playback::context by adding them to the
3627 corresponding recording::context. */
3631 add_error (location
*loc
, const char *fmt
, ...)
3635 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
3640 /* We handle errors on a playback::context by adding them to the
3641 corresponding recording::context. */
3645 add_error_va (location
*loc
, const char *fmt
, va_list ap
)
3647 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
3651 /* Report a diagnostic up to the jit context as an error,
3652 so that the compilation is treated as a failure.
3653 For now, any kind of diagnostic is treated as an error by the jit
3658 add_diagnostic (diagnostic_context
*diag_context
,
3659 const diagnostic_info
&diagnostic
)
3661 /* At this point the text has been formatted into the pretty-printer's
3663 pretty_printer
*pp
= diag_context
->printer
;
3664 const char *text
= pp_formatted_text (pp
);
3666 /* Get location information (if any) from the diagnostic.
3667 The recording::context::add_error[_va] methods require a
3668 recording::location. We can't lookup the playback::location
3669 from the file/line/column since any playback location instances
3670 may have been garbage-collected away by now, so instead we create
3671 another recording::location directly. */
3672 location_t gcc_loc
= diagnostic_location (&diagnostic
);
3673 recording::location
*rec_loc
= NULL
;
3676 expanded_location exploc
= expand_location (gcc_loc
);
3678 rec_loc
= m_recording_ctxt
->new_location (exploc
.file
,
3684 m_recording_ctxt
->add_error (rec_loc
, "%s", text
);
3685 pp_clear_output_area (pp
);
3688 /* Dealing with the linemap API. */
3690 /* Construct a playback::location for a recording::location, if it
3691 doesn't exist already. */
3693 playback::location
*
3695 new_location (recording::location
*rloc
,
3696 const char *filename
,
3700 /* Get the source_file for filename, creating if necessary. */
3701 source_file
*src_file
= get_source_file (filename
);
3702 /* Likewise for the line within the file. */
3703 source_line
*src_line
= src_file
->get_source_line (line
);
3704 /* Likewise for the column within the line. */
3705 location
*loc
= src_line
->get_location (rloc
, column
);
3709 /* Deferred setting of the location for a given tree, by adding the
3710 (tree, playback::location) pair to a list of deferred associations.
3711 We will actually set the location on the tree later on once
3712 the location_t for the playback::location exists. */
3716 set_tree_location (tree t
, location
*loc
)
3719 m_cached_locations
.safe_push (std::make_pair (t
, loc
));
3723 /* Construct a playback::source_file for the given source
3724 filename, if it doesn't exist already. */
3726 playback::source_file
*
3728 get_source_file (const char *filename
)
3731 For simplicitly, this is currently a linear search.
3732 Replace with a hash if this shows up in the profile. */
3735 tree ident_filename
= get_identifier (filename
);
3737 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
3738 if (file
->filename_as_tree () == ident_filename
)
3742 file
= new source_file (ident_filename
);
3743 m_source_files
.safe_push (file
);
3747 /* Constructor for gcc::jit::playback::source_file. */
3749 playback::source_file::source_file (tree filename
) :
3751 m_filename (filename
)
3755 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3759 playback::source_file::finalizer ()
3761 m_source_lines
.release ();
3764 /* Construct a playback::source_line for the given line
3765 within this source file, if one doesn't exist already. */
3767 playback::source_line
*
3768 playback::source_file::
3769 get_source_line (int line_num
)
3772 For simplicitly, this is currently a linear search.
3773 Replace with a hash if this shows up in the profile. */
3777 FOR_EACH_VEC_ELT (m_source_lines
, i
, line
)
3778 if (line
->get_line_num () == line_num
)
3782 line
= new source_line (this, line_num
);
3783 m_source_lines
.safe_push (line
);
3787 /* Constructor for gcc::jit::playback::source_line. */
3789 playback::source_line::source_line (source_file
*file
, int line_num
) :
3791 m_source_file (file
),
3792 m_line_num (line_num
)
3796 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3800 playback::source_line::finalizer ()
3802 m_locations
.release ();
3805 /* Construct a playback::location for the given column
3806 within this line of a specific source file, if one doesn't exist
3809 playback::location
*
3810 playback::source_line::
3811 get_location (recording::location
*rloc
, int column_num
)
3816 /* Another linear search that probably should be a hash table. */
3817 FOR_EACH_VEC_ELT (m_locations
, i
, loc
)
3818 if (loc
->get_column_num () == column_num
)
3822 loc
= new location (rloc
, this, column_num
);
3823 m_locations
.safe_push (loc
);
3827 /* Constructor for gcc::jit::playback::location. */
3829 playback::location::location (recording::location
*loc
,
3832 m_srcloc (UNKNOWN_LOCATION
),
3833 m_recording_loc (loc
),
3835 m_column_num(column_num
)
3839 /* The active gcc::jit::playback::context instance. This is a singleton,
3840 guarded by jit_mutex. */
3842 playback::context
*active_playback_ctxt
;
3844 } // namespace gcc::jit