1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2020 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
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"
45 #include "jit-playback.h"
46 #include "jit-result.h"
47 #include "jit-builtins.h"
48 #include "jit-tempdir.h"
54 /* Compare with gcc/c-family/c-common.h: DECL_C_BIT_FIELD,
56 These are redefined here to avoid depending from the C frontend. */
57 #define DECL_JIT_BIT_FIELD(NODE) \
58 (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1)
59 #define SET_DECL_JIT_BIT_FIELD(NODE) \
60 (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1)
62 /* gcc::jit::playback::context::build_cast uses the convert.h API,
63 which in turn requires the frontend to provide a "convert"
64 function, apparently as a fallback.
66 Hence we provide this dummy one, with the requirement that any casts
67 are handled before reaching this. */
68 extern tree
convert (tree type
, tree expr
);
71 convert (tree dst_type
, tree expr
)
73 gcc_assert (gcc::jit::active_playback_ctxt
);
74 gcc::jit::active_playback_ctxt
->add_error (NULL
, "unhandled conversion");
75 fprintf (stderr
, "input expression:\n");
77 fprintf (stderr
, "requested type:\n");
78 debug_tree (dst_type
);
79 return error_mark_node
;
85 /**********************************************************************
87 **********************************************************************/
89 /* The constructor for gcc::jit::playback::context. */
91 playback::context::context (recording::context
*ctxt
)
92 : log_user (ctxt
->get_logger ()),
93 m_recording_ctxt (ctxt
),
95 m_const_char_ptr (NULL
)
97 JIT_LOG_SCOPE (get_logger ());
98 m_functions
.create (0);
100 m_source_files
.create (0);
101 m_cached_locations
.create (0);
104 /* The destructor for gcc::jit::playback::context. */
106 playback::context::~context ()
108 JIT_LOG_SCOPE (get_logger ());
110 /* Normally the playback::context is responsible for cleaning up the
111 tempdir (including "fake.so" within the filesystem).
113 In the normal case, clean it up now.
115 However m_tempdir can be NULL if the context has handed over
116 responsibility for the tempdir cleanup to the jit::result object, so
117 that the cleanup can be delayed (see PR jit/64206). If that's the
118 case this "delete NULL;" is a no-op. */
121 m_functions
.release ();
124 /* A playback::context can reference GC-managed pointers. Mark them
125 ("by hand", rather than by gengtype).
127 This is called on the active playback context (if any) by the
128 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
136 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
138 if (ggc_test_and_set_mark (func
))
143 /* Given an enum gcc_jit_types value, get a "tree" type. */
146 get_tree_node_for_type (enum gcc_jit_types type_
)
150 case GCC_JIT_TYPE_VOID
:
151 return void_type_node
;
153 case GCC_JIT_TYPE_VOID_PTR
:
154 return ptr_type_node
;
156 case GCC_JIT_TYPE_BOOL
:
157 return boolean_type_node
;
159 case GCC_JIT_TYPE_CHAR
:
160 return char_type_node
;
161 case GCC_JIT_TYPE_SIGNED_CHAR
:
162 return signed_char_type_node
;
163 case GCC_JIT_TYPE_UNSIGNED_CHAR
:
164 return unsigned_char_type_node
;
166 case GCC_JIT_TYPE_SHORT
:
167 return short_integer_type_node
;
168 case GCC_JIT_TYPE_UNSIGNED_SHORT
:
169 return short_unsigned_type_node
;
171 case GCC_JIT_TYPE_CONST_CHAR_PTR
:
173 tree const_char
= build_qualified_type (char_type_node
,
175 return build_pointer_type (const_char
);
178 case GCC_JIT_TYPE_INT
:
179 return integer_type_node
;
180 case GCC_JIT_TYPE_UNSIGNED_INT
:
181 return unsigned_type_node
;
183 case GCC_JIT_TYPE_LONG
:
184 return long_integer_type_node
;
185 case GCC_JIT_TYPE_UNSIGNED_LONG
:
186 return long_unsigned_type_node
;
188 case GCC_JIT_TYPE_LONG_LONG
:
189 return long_long_integer_type_node
;
190 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG
:
191 return long_long_unsigned_type_node
;
193 case GCC_JIT_TYPE_FLOAT
:
194 return float_type_node
;
195 case GCC_JIT_TYPE_DOUBLE
:
196 return double_type_node
;
197 case GCC_JIT_TYPE_LONG_DOUBLE
:
198 return long_double_type_node
;
200 case GCC_JIT_TYPE_SIZE_T
:
201 return size_type_node
;
203 case GCC_JIT_TYPE_FILE_PTR
:
204 return fileptr_type_node
;
206 case GCC_JIT_TYPE_COMPLEX_FLOAT
:
207 return complex_float_type_node
;
208 case GCC_JIT_TYPE_COMPLEX_DOUBLE
:
209 return complex_double_type_node
;
210 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE
:
211 return complex_long_double_type_node
;
217 /* Construct a playback::type instance (wrapping a tree) for the given
222 get_type (enum gcc_jit_types type_
)
224 tree type_node
= get_tree_node_for_type (type_
);
225 if (type_node
== NULL
)
227 add_error (NULL
, "unrecognized (enum gcc_jit_types) value: %i", type_
);
231 return new type (type_node
);
234 /* Construct a playback::type instance (wrapping a tree) for the given
239 new_array_type (playback::location
*loc
,
240 playback::type
*element_type
,
243 gcc_assert (element_type
);
245 tree t
= build_array_type_nelts (element_type
->as_tree (),
250 set_tree_location (t
, loc
);
255 /* Construct a playback::field instance (wrapping a tree). */
259 new_field (location
*loc
,
266 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
267 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
268 get_identifier (name
), type
->as_tree ());
271 set_tree_location (decl
, loc
);
273 return new field (decl
);
276 /* Construct a playback::bitfield instance (wrapping a tree). */
280 new_bitfield (location
*loc
,
289 /* compare with c/c-decl.c:grokfield, grokdeclarator and
290 check_bitfield_type_and_width. */
292 tree tree_type
= type
->as_tree ();
293 gcc_assert (INTEGRAL_TYPE_P (tree_type
));
294 tree tree_width
= build_int_cst (integer_type_node
, width
);
295 if (compare_tree_int (tree_width
, TYPE_PRECISION (tree_type
)) > 0)
299 "width of bit-field %s (width: %i) is wider than its type (width: %i)",
300 name
, width
, TYPE_PRECISION (tree_type
));
304 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
305 get_identifier (name
), type
->as_tree ());
306 DECL_NONADDRESSABLE_P (decl
) = true;
307 DECL_INITIAL (decl
) = tree_width
;
308 SET_DECL_JIT_BIT_FIELD (decl
);
311 set_tree_location (decl
, loc
);
313 return new field (decl
);
316 /* Construct a playback::compound_type instance (wrapping a tree). */
318 playback::compound_type
*
320 new_compound_type (location
*loc
,
322 bool is_struct
) /* else is union */
326 /* Compare with c/c-decl.c: start_struct. */
328 tree t
= make_node (is_struct
? RECORD_TYPE
: UNION_TYPE
);
329 TYPE_NAME (t
) = get_identifier (name
);
333 set_tree_location (t
, loc
);
335 return new compound_type (t
);
339 playback::compound_type::set_fields (const auto_vec
<playback::field
*> *fields
)
341 /* Compare with c/c-decl.c: finish_struct. */
344 tree fieldlist
= NULL
;
345 for (unsigned i
= 0; i
< fields
->length (); i
++)
347 field
*f
= (*fields
)[i
];
348 tree x
= f
->as_tree ();
349 DECL_CONTEXT (x
) = t
;
350 if (DECL_JIT_BIT_FIELD (x
))
352 unsigned HOST_WIDE_INT width
= tree_to_uhwi (DECL_INITIAL (x
));
353 DECL_SIZE (x
) = bitsize_int (width
);
354 DECL_BIT_FIELD (x
) = 1;
356 fieldlist
= chainon (x
, fieldlist
);
358 fieldlist
= nreverse (fieldlist
);
359 TYPE_FIELDS (t
) = fieldlist
;
364 /* Construct a playback::type instance (wrapping a tree) for a function
369 new_function_type (type
*return_type
,
370 const auto_vec
<type
*> *param_types
,
376 tree
*arg_types
= (tree
*)xcalloc(param_types
->length (), sizeof(tree
*));
378 FOR_EACH_VEC_ELT (*param_types
, i
, param_type
)
379 arg_types
[i
] = param_type
->as_tree ();
384 build_varargs_function_type_array (return_type
->as_tree (),
385 param_types
->length (),
388 fn_type
= build_function_type_array (return_type
->as_tree (),
389 param_types
->length (),
393 return new type (fn_type
);
396 /* Construct a playback::param instance (wrapping a tree). */
400 new_param (location
*loc
,
406 tree inner
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
407 get_identifier (name
), type
->as_tree ());
409 set_tree_location (inner
, loc
);
411 return new param (this, inner
);
414 /* Construct a playback::function instance. */
418 new_function (location
*loc
,
419 enum gcc_jit_function_kind kind
,
422 const auto_vec
<param
*> *params
,
424 enum built_in_function builtin_id
)
429 //can return_type be NULL?
432 tree
*arg_types
= (tree
*)xcalloc(params
->length (), sizeof(tree
*));
433 FOR_EACH_VEC_ELT (*params
, i
, param
)
434 arg_types
[i
] = TREE_TYPE (param
->as_tree ());
438 fn_type
= build_varargs_function_type_array (return_type
->as_tree (),
439 params
->length (), arg_types
);
441 fn_type
= build_function_type_array (return_type
->as_tree (),
442 params
->length (), arg_types
);
445 /* FIXME: this uses input_location: */
446 tree fndecl
= build_fn_decl (name
, fn_type
);
449 set_tree_location (fndecl
, loc
);
451 tree resdecl
= build_decl (UNKNOWN_LOCATION
, RESULT_DECL
,
452 NULL_TREE
, return_type
->as_tree ());
453 DECL_ARTIFICIAL (resdecl
) = 1;
454 DECL_IGNORED_P (resdecl
) = 1;
455 DECL_RESULT (fndecl
) = resdecl
;
459 gcc_assert (loc
== NULL
);
460 DECL_SOURCE_LOCATION (fndecl
) = BUILTINS_LOCATION
;
462 built_in_class fclass
= builtins_manager::get_class (builtin_id
);
463 set_decl_built_in_function (fndecl
, fclass
, builtin_id
);
464 set_builtin_decl (builtin_id
, fndecl
,
465 builtins_manager::implicit_p (builtin_id
));
467 builtins_manager
*bm
= get_builtins_manager ();
468 tree attrs
= bm
->get_attrs_tree (builtin_id
);
470 decl_attributes (&fndecl
, attrs
, ATTR_FLAG_BUILT_IN
);
472 decl_attributes (&fndecl
, NULL_TREE
, 0);
475 if (kind
!= GCC_JIT_FUNCTION_IMPORTED
)
477 tree param_decl_list
= NULL
;
478 FOR_EACH_VEC_ELT (*params
, i
, param
)
480 param_decl_list
= chainon (param
->as_tree (), param_decl_list
);
483 /* The param list was created in reverse order; fix it: */
484 param_decl_list
= nreverse (param_decl_list
);
487 for (t
= param_decl_list
; t
; t
= DECL_CHAIN (t
))
489 DECL_CONTEXT (t
) = fndecl
;
490 DECL_ARG_TYPE (t
) = TREE_TYPE (t
);
493 /* Set it up on DECL_ARGUMENTS */
494 DECL_ARGUMENTS(fndecl
) = param_decl_list
;
497 if (kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
499 DECL_DECLARED_INLINE_P (fndecl
) = 1;
501 /* Add attribute "always_inline": */
502 DECL_ATTRIBUTES (fndecl
) =
503 tree_cons (get_identifier ("always_inline"),
505 DECL_ATTRIBUTES (fndecl
));
508 function
*func
= new function (this, fndecl
, kind
);
509 m_functions
.safe_push (func
);
513 /* In use by new_global and new_global_initialized. */
517 global_new_decl (location
*loc
,
518 enum gcc_jit_global_kind kind
,
524 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
525 get_identifier (name
),
527 TREE_PUBLIC (inner
) = (kind
!= GCC_JIT_GLOBAL_INTERNAL
);
528 DECL_COMMON (inner
) = 1;
534 case GCC_JIT_GLOBAL_EXPORTED
:
535 TREE_STATIC (inner
) = 1;
538 case GCC_JIT_GLOBAL_INTERNAL
:
539 TREE_STATIC (inner
) = 1;
542 case GCC_JIT_GLOBAL_IMPORTED
:
543 DECL_EXTERNAL (inner
) = 1;
548 set_tree_location (inner
, loc
);
553 /* In use by new_global and new_global_initialized. */
557 global_finalize_lvalue (tree inner
)
559 varpool_node::get_create (inner
);
561 varpool_node::finalize_decl (inner
);
563 m_globals
.safe_push (inner
);
565 return new lvalue (this, inner
);
568 /* Construct a playback::lvalue instance (wrapping a tree). */
572 new_global (location
*loc
,
573 enum gcc_jit_global_kind kind
,
577 tree inner
= global_new_decl (loc
, kind
, type
, name
);
579 return global_finalize_lvalue (inner
);
582 /* Fill 'constructor_elements' with the memory content of
583 'initializer'. Each element of the initializer is of the size of
584 type T. In use by new_global_initialized.*/
588 load_blob_in_ctor (vec
<constructor_elt
, va_gc
> *&constructor_elements
,
590 const void *initializer
)
592 /* Loosely based on 'output_init_element' c-typeck.c:9691. */
593 const T
*p
= (const T
*)initializer
;
594 tree node
= make_unsigned_type (BITS_PER_UNIT
* sizeof (T
));
595 for (size_t i
= 0; i
< num_elem
; i
++)
597 constructor_elt celt
=
598 { build_int_cst (long_unsigned_type_node
, i
),
599 build_int_cst (node
, p
[i
]) };
600 vec_safe_push (constructor_elements
, celt
);
604 /* Construct an initialized playback::lvalue instance (wrapping a
609 new_global_initialized (location
*loc
,
610 enum gcc_jit_global_kind kind
,
613 size_t initializer_num_elem
,
614 const void *initializer
,
617 tree inner
= global_new_decl (loc
, kind
, type
, name
);
619 vec
<constructor_elt
, va_gc
> *constructor_elements
= NULL
;
621 switch (element_size
)
624 load_blob_in_ctor
<uint8_t> (constructor_elements
, initializer_num_elem
,
628 load_blob_in_ctor
<uint16_t> (constructor_elements
, initializer_num_elem
,
632 load_blob_in_ctor
<uint32_t> (constructor_elements
, initializer_num_elem
,
636 load_blob_in_ctor
<uint64_t> (constructor_elements
, initializer_num_elem
,
640 /* This function is serving on sizes returned by 'get_size',
641 these are all covered by the previous cases. */
644 /* Compare with 'pop_init_level' c-typeck.c:8780. */
645 tree ctor
= build_constructor (type
->as_tree (), constructor_elements
);
646 constructor_elements
= NULL
;
648 /* Compare with 'store_init_value' c-typeck.c:7555. */
649 DECL_INITIAL (inner
) = ctor
;
651 return global_finalize_lvalue (inner
);
654 /* Implementation of the various
655 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
657 Each of these constructs a playback::rvalue instance (wrapping a tree).
659 These specializations are required to be in the same namespace
660 as the template, hence we now have to enter the gcc::jit::playback
666 /* Specialization of making an rvalue from a const, for host <int>. */
671 new_rvalue_from_const
<int> (type
*type
,
674 // FIXME: type-checking, or coercion?
675 tree inner_type
= type
->as_tree ();
676 if (INTEGRAL_TYPE_P (inner_type
))
678 tree inner
= build_int_cst (inner_type
, value
);
679 return new rvalue (this, inner
);
683 REAL_VALUE_TYPE real_value
;
684 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
685 tree inner
= build_real (inner_type
, real_value
);
686 return new rvalue (this, inner
);
690 /* Specialization of making an rvalue from a const, for host <long>. */
695 new_rvalue_from_const
<long> (type
*type
,
698 // FIXME: type-checking, or coercion?
699 tree inner_type
= type
->as_tree ();
700 if (INTEGRAL_TYPE_P (inner_type
))
702 tree inner
= build_int_cst (inner_type
, value
);
703 return new rvalue (this, inner
);
707 REAL_VALUE_TYPE real_value
;
708 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
709 tree inner
= build_real (inner_type
, real_value
);
710 return new rvalue (this, inner
);
714 /* Specialization of making an rvalue from a const, for host <double>. */
719 new_rvalue_from_const
<double> (type
*type
,
722 // FIXME: type-checking, or coercion?
723 tree inner_type
= type
->as_tree ();
725 /* We have a "double", we want a REAL_VALUE_TYPE.
727 real.c:real_from_target appears to require the representation to be
728 split into 32-bit values, and then sent as an pair of host long
730 REAL_VALUE_TYPE real_value
;
734 uint32_t as_uint32s
[2];
737 long int as_long_ints
[2];
738 as_long_ints
[0] = u
.as_uint32s
[0];
739 as_long_ints
[1] = u
.as_uint32s
[1];
740 real_from_target (&real_value
, as_long_ints
, DFmode
);
741 tree inner
= build_real (inner_type
, real_value
);
742 return new rvalue (this, inner
);
745 /* Specialization of making an rvalue from a const, for host <void *>. */
750 new_rvalue_from_const
<void *> (type
*type
,
753 tree inner_type
= type
->as_tree ();
754 /* FIXME: how to ensure we have a wide enough type? */
755 tree inner
= build_int_cstu (inner_type
, (unsigned HOST_WIDE_INT
)value
);
756 return new rvalue (this, inner
);
759 /* We're done implementing the specializations of
760 gcc::jit::playback::context::new_rvalue_from_const <T>
761 so we can exit the gcc::jit::playback namespace. */
763 } // namespace playback
765 /* Construct a playback::rvalue instance (wrapping a tree). */
769 new_string_literal (const char *value
)
771 /* Compare with c-family/c-common.c: fix_string_type. */
772 size_t len
= strlen (value
);
773 tree i_type
= build_index_type (size_int (len
));
774 tree a_type
= build_array_type (char_type_node
, i_type
);
775 /* build_string len parameter must include NUL terminator when
776 building C strings. */
777 tree t_str
= build_string (len
+ 1, value
);
778 TREE_TYPE (t_str
) = a_type
;
780 /* Convert to (const char*), loosely based on
781 c/c-typeck.c: array_to_pointer_conversion,
782 by taking address of start of string. */
783 tree t_addr
= build1 (ADDR_EXPR
, m_const_char_ptr
, t_str
);
785 return new rvalue (this, t_addr
);
788 /* Construct a playback::rvalue instance (wrapping a tree) for a
792 playback::context::new_rvalue_from_vector (location
*,
794 const auto_vec
<rvalue
*> &elements
)
796 vec
<constructor_elt
, va_gc
> *v
;
797 vec_alloc (v
, elements
.length ());
798 for (unsigned i
= 0; i
< elements
.length (); ++i
)
799 CONSTRUCTOR_APPEND_ELT (v
, NULL_TREE
, elements
[i
]->as_tree ());
800 tree t_ctor
= build_constructor (type
->as_tree (), v
);
801 return new rvalue (this, t_ctor
);
804 /* Coerce a tree expression into a boolean tree expression. */
808 as_truth_value (tree expr
, location
*loc
)
810 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
811 tree typed_zero
= fold_build1 (CONVERT_EXPR
,
815 set_tree_location (typed_zero
, loc
);
817 expr
= build2 (NE_EXPR
, integer_type_node
, expr
, typed_zero
);
819 set_tree_location (expr
, loc
);
824 /* Construct a playback::rvalue instance (wrapping a tree) for a
829 new_unary_op (location
*loc
,
830 enum gcc_jit_unary_op op
,
834 // FIXME: type-checking, or coercion?
835 enum tree_code inner_op
;
837 gcc_assert (result_type
);
840 tree node
= a
->as_tree ();
841 tree inner_result
= NULL
;
846 add_error (loc
, "unrecognized (enum gcc_jit_unary_op) value: %i", op
);
849 case GCC_JIT_UNARY_OP_MINUS
:
850 inner_op
= NEGATE_EXPR
;
853 case GCC_JIT_UNARY_OP_BITWISE_NEGATE
:
854 inner_op
= BIT_NOT_EXPR
;
857 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE
:
858 node
= as_truth_value (node
, loc
);
859 inner_result
= invert_truthvalue (node
);
861 set_tree_location (inner_result
, loc
);
862 return new rvalue (this, inner_result
);
864 case GCC_JIT_UNARY_OP_ABS
:
869 inner_result
= build1 (inner_op
,
870 result_type
->as_tree (),
873 set_tree_location (inner_result
, loc
);
875 return new rvalue (this, inner_result
);
878 /* Construct a playback::rvalue instance (wrapping a tree) for a
883 new_binary_op (location
*loc
,
884 enum gcc_jit_binary_op op
,
886 rvalue
*a
, rvalue
*b
)
888 // FIXME: type-checking, or coercion?
889 enum tree_code inner_op
;
891 gcc_assert (result_type
);
895 tree node_a
= a
->as_tree ();
896 tree node_b
= b
->as_tree ();
901 add_error (loc
, "unrecognized (enum gcc_jit_binary_op) value: %i", op
);
904 case GCC_JIT_BINARY_OP_PLUS
:
905 inner_op
= PLUS_EXPR
;
908 case GCC_JIT_BINARY_OP_MINUS
:
909 inner_op
= MINUS_EXPR
;
912 case GCC_JIT_BINARY_OP_MULT
:
913 inner_op
= MULT_EXPR
;
916 case GCC_JIT_BINARY_OP_DIVIDE
:
917 if (FLOAT_TYPE_P (result_type
->as_tree ()))
918 /* Floating-point division: */
919 inner_op
= RDIV_EXPR
;
921 /* Truncating to zero: */
922 inner_op
= TRUNC_DIV_EXPR
;
925 case GCC_JIT_BINARY_OP_MODULO
:
926 inner_op
= TRUNC_MOD_EXPR
;
929 case GCC_JIT_BINARY_OP_BITWISE_AND
:
930 inner_op
= BIT_AND_EXPR
;
933 case GCC_JIT_BINARY_OP_BITWISE_XOR
:
934 inner_op
= BIT_XOR_EXPR
;
937 case GCC_JIT_BINARY_OP_BITWISE_OR
:
938 inner_op
= BIT_IOR_EXPR
;
941 case GCC_JIT_BINARY_OP_LOGICAL_AND
:
942 node_a
= as_truth_value (node_a
, loc
);
943 node_b
= as_truth_value (node_b
, loc
);
944 inner_op
= TRUTH_ANDIF_EXPR
;
947 case GCC_JIT_BINARY_OP_LOGICAL_OR
:
948 node_a
= as_truth_value (node_a
, loc
);
949 node_b
= as_truth_value (node_b
, loc
);
950 inner_op
= TRUTH_ORIF_EXPR
;
953 case GCC_JIT_BINARY_OP_LSHIFT
:
954 inner_op
= LSHIFT_EXPR
;
957 case GCC_JIT_BINARY_OP_RSHIFT
:
958 inner_op
= RSHIFT_EXPR
;
962 tree inner_expr
= build2 (inner_op
,
963 result_type
->as_tree (),
967 set_tree_location (inner_expr
, loc
);
969 return new rvalue (this, inner_expr
);
972 /* Construct a playback::rvalue instance (wrapping a tree) for a
977 new_comparison (location
*loc
,
978 enum gcc_jit_comparison op
,
979 rvalue
*a
, rvalue
*b
)
981 // FIXME: type-checking, or coercion?
982 enum tree_code inner_op
;
990 add_error (loc
, "unrecognized (enum gcc_jit_comparison) value: %i", op
);
993 case GCC_JIT_COMPARISON_EQ
:
996 case GCC_JIT_COMPARISON_NE
:
999 case GCC_JIT_COMPARISON_LT
:
1002 case GCC_JIT_COMPARISON_LE
:
1005 case GCC_JIT_COMPARISON_GT
:
1008 case GCC_JIT_COMPARISON_GE
:
1013 tree inner_expr
= build2 (inner_op
,
1018 set_tree_location (inner_expr
, loc
);
1019 return new rvalue (this, inner_expr
);
1022 /* Construct a playback::rvalue instance (wrapping a tree) for a
1027 build_call (location
*loc
,
1029 const auto_vec
<rvalue
*> *args
,
1030 bool require_tail_call
)
1032 vec
<tree
, va_gc
> *tree_args
;
1033 vec_alloc (tree_args
, args
->length ());
1034 for (unsigned i
= 0; i
< args
->length (); i
++)
1035 tree_args
->quick_push ((*args
)[i
]->as_tree ());
1038 set_tree_location (fn_ptr
, loc
);
1040 tree fn
= TREE_TYPE (fn_ptr
);
1041 tree fn_type
= TREE_TYPE (fn
);
1042 tree return_type
= TREE_TYPE (fn_type
);
1044 tree call
= build_call_vec (return_type
,
1047 if (require_tail_call
)
1048 CALL_EXPR_MUST_TAIL_CALL (call
) = 1;
1050 return new rvalue (this, call
);
1052 /* see c-typeck.c: build_function_call
1053 which calls build_function_call_vec
1055 which does lots of checking, then:
1056 result = build_call_array_loc (loc, TREE_TYPE (fntype),
1057 function, nargs, argarray);
1059 (see also build_call_vec)
1063 /* Construct a playback::rvalue instance (wrapping a tree) for a
1064 call to a specific function. */
1068 new_call (location
*loc
,
1070 const auto_vec
<rvalue
*> *args
,
1071 bool require_tail_call
)
1077 fndecl
= func
->as_fndecl ();
1079 tree fntype
= TREE_TYPE (fndecl
);
1081 tree fn
= build1 (ADDR_EXPR
, build_pointer_type (fntype
), fndecl
);
1083 return build_call (loc
, fn
, args
, require_tail_call
);
1086 /* Construct a playback::rvalue instance (wrapping a tree) for a
1087 call through a function pointer. */
1091 new_call_through_ptr (location
*loc
,
1093 const auto_vec
<rvalue
*> *args
,
1094 bool require_tail_call
)
1096 gcc_assert (fn_ptr
);
1097 tree t_fn_ptr
= fn_ptr
->as_tree ();
1099 return build_call (loc
, t_fn_ptr
, args
, require_tail_call
);
1102 /* Construct a tree for a cast. */
1105 playback::context::build_cast (playback::location
*loc
,
1106 playback::rvalue
*expr
,
1107 playback::type
*type_
)
1109 /* For comparison, see:
1110 - c/c-typeck.c:build_c_cast
1111 - c/c-convert.c: convert
1114 Only some kinds of cast are currently supported here. */
1115 tree t_expr
= expr
->as_tree ();
1116 tree t_dst_type
= type_
->as_tree ();
1118 t_ret
= targetm
.convert_to_type (t_dst_type
, t_expr
);
1121 enum tree_code dst_code
= TREE_CODE (t_dst_type
);
1126 t_ret
= convert_to_integer (t_dst_type
, t_expr
);
1130 /* Compare with c_objc_common_truthvalue_conversion and
1131 c_common_truthvalue_conversion. */
1132 /* For now, convert to: (t_expr != 0) */
1133 t_ret
= build2 (NE_EXPR
, t_dst_type
,
1135 build_int_cst (TREE_TYPE (t_expr
), 0));
1139 t_ret
= convert_to_real (t_dst_type
, t_expr
);
1143 t_ret
= build1 (NOP_EXPR
, t_dst_type
, t_expr
);
1147 add_error (loc
, "couldn't handle cast during playback");
1148 fprintf (stderr
, "input expression:\n");
1149 debug_tree (t_expr
);
1150 fprintf (stderr
, "requested type:\n");
1151 debug_tree (t_dst_type
);
1152 return error_mark_node
;
1155 if (TREE_CODE (t_ret
) != C_MAYBE_CONST_EXPR
)
1156 t_ret
= fold (t_ret
);
1161 /* Construct a playback::rvalue instance (wrapping a tree) for a
1166 new_cast (playback::location
*loc
,
1167 playback::rvalue
*expr
,
1168 playback::type
*type_
)
1171 tree t_cast
= build_cast (loc
, expr
, type_
);
1173 set_tree_location (t_cast
, loc
);
1174 return new rvalue (this, t_cast
);
1177 /* Construct a playback::lvalue instance (wrapping a tree) for an
1182 new_array_access (location
*loc
,
1189 /* For comparison, see:
1190 c/c-typeck.c: build_array_ref
1191 c-family/c-common.c: pointer_int_sum
1193 tree t_ptr
= ptr
->as_tree ();
1194 tree t_index
= index
->as_tree ();
1195 tree t_type_ptr
= TREE_TYPE (t_ptr
);
1196 tree t_type_star_ptr
= TREE_TYPE (t_type_ptr
);
1198 if (TREE_CODE (t_type_ptr
) == ARRAY_TYPE
)
1200 tree t_result
= build4 (ARRAY_REF
, t_type_star_ptr
, t_ptr
, t_index
,
1201 NULL_TREE
, NULL_TREE
);
1203 set_tree_location (t_result
, loc
);
1204 return new lvalue (this, t_result
);
1208 /* Convert index to an offset in bytes. */
1209 tree t_sizeof
= size_in_bytes (t_type_star_ptr
);
1210 t_index
= fold_build1 (CONVERT_EXPR
, sizetype
, t_index
);
1211 tree t_offset
= build2 (MULT_EXPR
, sizetype
, t_index
, t_sizeof
);
1213 /* Locate (ptr + offset). */
1214 tree t_address
= build2 (POINTER_PLUS_EXPR
, t_type_ptr
, t_ptr
, t_offset
);
1216 tree t_indirection
= build1 (INDIRECT_REF
, t_type_star_ptr
, t_address
);
1219 set_tree_location (t_sizeof
, loc
);
1220 set_tree_location (t_offset
, loc
);
1221 set_tree_location (t_address
, loc
);
1222 set_tree_location (t_indirection
, loc
);
1225 return new lvalue (this, t_indirection
);
1229 /* Construct a tree for a field access. */
1233 new_field_access (location
*loc
,
1240 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1241 build_component_ref. */
1242 tree type
= TREE_TYPE (datum
);
1244 gcc_assert (TREE_CODE (type
) != POINTER_TYPE
);
1246 tree t_field
= field
->as_tree ();
1247 tree ref
= build3 (COMPONENT_REF
, TREE_TYPE (t_field
), datum
,
1248 t_field
, NULL_TREE
);
1250 set_tree_location (ref
, loc
);
1254 /* Construct a tree for a dereference. */
1258 new_dereference (tree ptr
,
1263 tree type
= TREE_TYPE (TREE_TYPE(ptr
));
1264 tree datum
= build1 (INDIRECT_REF
, type
, ptr
);
1266 set_tree_location (datum
, loc
);
1270 /* Construct a playback::type instance (wrapping a tree)
1271 with the given alignment. */
1275 get_aligned (size_t alignment_in_bytes
) const
1277 tree t_new_type
= build_variant_type_copy (m_inner
);
1279 SET_TYPE_ALIGN (t_new_type
, alignment_in_bytes
* BITS_PER_UNIT
);
1280 TYPE_USER_ALIGN (t_new_type
) = 1;
1282 return new type (t_new_type
);
1285 /* Construct a playback::type instance (wrapping a tree)
1286 for the given vector type. */
1290 get_vector (size_t num_units
) const
1292 tree t_new_type
= build_vector_type (m_inner
, num_units
);
1293 return new type (t_new_type
);
1296 /* Construct a playback::lvalue instance (wrapping a tree) for a
1301 access_field (location
*loc
,
1304 tree datum
= as_tree ();
1305 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1308 return new lvalue (get_context (), ref
);
1311 /* Construct a playback::rvalue instance (wrapping a tree) for a
1316 access_field (location
*loc
,
1319 tree datum
= as_tree ();
1320 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1323 return new rvalue (get_context (), ref
);
1326 /* Construct a playback::lvalue instance (wrapping a tree) for a
1327 dereferenced field access. */
1331 dereference_field (location
*loc
,
1334 tree ptr
= as_tree ();
1335 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1338 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1341 return new lvalue (get_context (), ref
);
1344 /* Construct a playback::lvalue instance (wrapping a tree) for a
1349 dereference (location
*loc
)
1351 tree ptr
= as_tree ();
1352 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1353 return new lvalue (get_context (), datum
);
1356 /* Mark the lvalue saying that we need to be able to take the
1357 address of it; it should not be allocated in a register.
1358 Compare with e.g. c/c-typeck.c: c_mark_addressable really_atomic_lvalue.
1359 Returns false if a failure occurred (an error will already have been
1360 added to the active context for this case). */
1364 mark_addressable (location
*loc
)
1366 tree x
= as_tree ();;
1369 switch (TREE_CODE (x
))
1372 if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x
, 1)))
1374 gcc_assert (gcc::jit::active_playback_ctxt
);
1376 active_playback_ctxt
->add_error (loc
,
1377 "cannot take address of "
1386 x
= TREE_OPERAND (x
, 0);
1389 case COMPOUND_LITERAL_EXPR
:
1391 TREE_ADDRESSABLE (x
) = 1;
1398 /* (we don't have a concept of a "register" declaration) */
1401 TREE_ADDRESSABLE (x
) = 1;
1408 /* Construct a playback::rvalue instance (wrapping a tree) for an
1413 get_address (location
*loc
)
1415 tree t_lvalue
= as_tree ();
1416 tree t_thistype
= TREE_TYPE (t_lvalue
);
1417 tree t_ptrtype
= build_pointer_type (t_thistype
);
1418 tree ptr
= build1 (ADDR_EXPR
, t_ptrtype
, t_lvalue
);
1420 get_context ()->set_tree_location (ptr
, loc
);
1421 if (mark_addressable (loc
))
1422 return new rvalue (get_context (), ptr
);
1427 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1428 Provide this finalization hook for calling then they are collected,
1429 which calls the finalizer vfunc. This allows them to call "release"
1430 on any vec<> within them. */
1433 wrapper_finalizer (void *ptr
)
1435 playback::wrapper
*wrapper
= reinterpret_cast <playback::wrapper
*> (ptr
);
1436 wrapper
->finalizer ();
1439 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1440 allocate them using ggc_internal_cleared_alloc. */
1444 operator new (size_t sz
)
1446 return ggc_internal_cleared_alloc (sz
, wrapper_finalizer
, 0, 1);
1450 /* Constructor for gcc:jit::playback::function. */
1452 playback::function::
1453 function (context
*ctxt
,
1455 enum gcc_jit_function_kind kind
)
1457 m_inner_fndecl (fndecl
),
1458 m_inner_bind_expr (NULL
),
1461 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1463 /* Create a BIND_EXPR, and within it, a statement list. */
1464 m_stmt_list
= alloc_stmt_list ();
1465 m_stmt_iter
= tsi_start (m_stmt_list
);
1466 m_inner_block
= make_node (BLOCK
);
1468 build3 (BIND_EXPR
, void_type_node
, NULL
, m_stmt_list
, m_inner_block
);
1472 m_inner_block
= NULL
;
1477 /* Hand-written GC-marking hook for playback functions. */
1480 playback::function::
1483 gt_ggc_m_9tree_node (m_inner_fndecl
);
1484 gt_ggc_m_9tree_node (m_inner_bind_expr
);
1485 gt_ggc_m_9tree_node (m_stmt_list
);
1486 gt_ggc_m_9tree_node (m_inner_block
);
1489 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1493 playback::function::finalizer ()
1495 m_blocks
.release ();
1498 /* Get the return type of a playback function, in tree form. */
1501 playback::function::
1502 get_return_type_as_tree () const
1504 return TREE_TYPE (TREE_TYPE(m_inner_fndecl
));
1507 /* Construct a new local within this playback::function. */
1510 playback::function::
1511 new_local (location
*loc
,
1517 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
1518 get_identifier (name
),
1520 DECL_CONTEXT (inner
) = this->m_inner_fndecl
;
1522 /* Prepend to BIND_EXPR_VARS: */
1523 DECL_CHAIN (inner
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1524 BIND_EXPR_VARS (m_inner_bind_expr
) = inner
;
1527 set_tree_location (inner
, loc
);
1528 return new lvalue (m_ctxt
, inner
);
1531 /* Construct a new block within this playback::function. */
1534 playback::function::
1535 new_block (const char *name
)
1537 gcc_assert (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
);
1539 block
*result
= new playback::block (this, name
);
1540 m_blocks
.safe_push (result
);
1544 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1545 this playback::function. */
1548 playback::function::get_address (location
*loc
)
1550 tree t_fndecl
= as_fndecl ();
1551 tree t_fntype
= TREE_TYPE (t_fndecl
);
1552 tree t_fnptr
= build1 (ADDR_EXPR
, build_pointer_type (t_fntype
), t_fndecl
);
1554 m_ctxt
->set_tree_location (t_fnptr
, loc
);
1555 return new rvalue (m_ctxt
, t_fnptr
);
1558 /* Build a statement list for the function as a whole out of the
1559 lists of statements for the individual blocks, building labels
1563 playback::function::
1569 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1571 FOR_EACH_VEC_ELT (m_blocks
, i
, b
)
1576 b
->m_label_expr
= build1 (LABEL_EXPR
,
1578 b
->as_label_decl ());
1579 tsi_link_after (&m_stmt_iter
, b
->m_label_expr
, TSI_CONTINUE_LINKING
);
1581 FOR_EACH_VEC_ELT (b
->m_stmts
, j
, stmt
)
1582 tsi_link_after (&m_stmt_iter
, stmt
, TSI_CONTINUE_LINKING
);
1586 /* Finish compiling the given function, potentially running the
1588 The function will have a statement list by now.
1589 Amongst other things, this gimplifies the statement list,
1590 and calls cgraph_node::finalize_function on the function. */
1593 playback::function::
1596 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1598 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
))
1599 debug_tree (m_stmt_list
);
1601 /* Do we need this to force cgraphunit.c to output the function? */
1602 if (m_kind
== GCC_JIT_FUNCTION_EXPORTED
)
1604 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1605 DECL_PRESERVE_P (m_inner_fndecl
) = 1;
1608 if (m_kind
== GCC_JIT_FUNCTION_INTERNAL
1609 ||m_kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
1611 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1612 TREE_PUBLIC (m_inner_fndecl
) = 0;
1615 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1617 /* Seem to need this in gimple-low.c: */
1618 gcc_assert (m_inner_block
);
1619 DECL_INITIAL (m_inner_fndecl
) = m_inner_block
;
1621 /* how to add to function? the following appears to be how to
1622 set the body of a m_inner_fndecl: */
1623 DECL_SAVED_TREE(m_inner_fndecl
) = m_inner_bind_expr
;
1625 /* Ensure that locals appear in the debuginfo. */
1626 BLOCK_VARS (m_inner_block
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1628 //debug_tree (m_inner_fndecl);
1630 /* Convert to gimple: */
1631 //printf("about to gimplify_function_tree\n");
1632 gimplify_function_tree (m_inner_fndecl
);
1633 //printf("finished gimplify_function_tree\n");
1635 current_function_decl
= m_inner_fndecl
;
1636 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
))
1637 dump_function_to_file (m_inner_fndecl
, stderr
, TDF_VOPS
|TDF_MEMSYMS
|TDF_LINENO
);
1638 //debug_tree (m_inner_fndecl);
1640 //printf("about to add to cgraph\n");
1641 /* Add to cgraph: */
1642 cgraph_node::finalize_function (m_inner_fndecl
, false);
1643 /* This can trigger a collection, so we need to have all of
1644 the funcs as roots. */
1646 current_function_decl
= NULL
;
1650 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1654 playback::block::finalizer ()
1659 /* Add an eval of the rvalue to the function's statement list. */
1663 add_eval (location
*loc
,
1666 gcc_assert (rvalue
);
1669 set_tree_location (rvalue
->as_tree (), loc
);
1671 add_stmt (rvalue
->as_tree ());
1674 /* Add an assignment to the function's statement list. */
1678 add_assignment (location
*loc
,
1682 gcc_assert (lvalue
);
1683 gcc_assert (rvalue
);
1685 tree t_lvalue
= lvalue
->as_tree ();
1686 tree t_rvalue
= rvalue
->as_tree ();
1687 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1689 t_rvalue
= build1 (CONVERT_EXPR
,
1690 TREE_TYPE (t_lvalue
),
1693 set_tree_location (t_rvalue
, loc
);
1697 build2 (MODIFY_EXPR
, TREE_TYPE (t_lvalue
),
1698 t_lvalue
, t_rvalue
);
1700 set_tree_location (stmt
, loc
);
1704 /* Add a comment to the function's statement list.
1705 For now this is done by adding a dummy label. */
1709 add_comment (location
*loc
,
1712 /* Wrap the text in C-style comment delimiters. */
1714 (3 /* opening delim */
1716 + 3 /* closing delim */
1717 + 1 /* terminator */);
1718 char *wrapped
= (char *)ggc_internal_alloc (sz
);
1719 snprintf (wrapped
, sz
, "/* %s */", text
);
1721 /* For now we simply implement this by adding a dummy label with a name
1722 containing the given text. */
1723 tree identifier
= get_identifier (wrapped
);
1724 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1725 identifier
, void_type_node
);
1726 DECL_CONTEXT (label_decl
) = m_func
->as_fndecl ();
1728 tree label_expr
= build1 (LABEL_EXPR
, void_type_node
, label_decl
);
1730 set_tree_location (label_expr
, loc
);
1731 add_stmt (label_expr
);
1734 /* Add a conditional jump statement to the function's statement list. */
1738 add_conditional (location
*loc
,
1743 gcc_assert (boolval
);
1744 gcc_assert (on_true
);
1745 gcc_assert (on_false
);
1747 /* COND_EXPR wants statement lists for the true/false operands, but we
1749 Shim it by creating jumps to the labels */
1750 tree true_jump
= build1 (GOTO_EXPR
, void_type_node
,
1751 on_true
->as_label_decl ());
1753 set_tree_location (true_jump
, loc
);
1755 tree false_jump
= build1 (GOTO_EXPR
, void_type_node
,
1756 on_false
->as_label_decl ());
1758 set_tree_location (false_jump
, loc
);
1761 build3 (COND_EXPR
, void_type_node
, boolval
->as_tree (),
1762 true_jump
, false_jump
);
1764 set_tree_location (stmt
, loc
);
1768 /* Add an unconditional jump statement to the function's statement list. */
1772 add_jump (location
*loc
,
1775 gcc_assert (target
);
1777 // see c_finish_loop
1778 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1781 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1782 TREE_USED (target
->as_label_decl ()) = 1;
1783 tree stmt
= build1 (GOTO_EXPR
, void_type_node
, target
->as_label_decl ());
1785 set_tree_location (stmt
, loc
);
1791 c_finish_goto_label (location_t loc, tree label)
1793 tree decl = lookup_label_for_goto (loc, label);
1796 TREE_USED (decl) = 1;
1798 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1799 SET_EXPR_LOCATION (t, loc);
1800 return add_stmt (t);
1807 /* Add a return statement to the function's statement list. */
1811 add_return (location
*loc
,
1814 tree modify_retval
= NULL
;
1815 tree return_type
= m_func
->get_return_type_as_tree ();
1818 tree t_lvalue
= DECL_RESULT (m_func
->as_fndecl ());
1819 tree t_rvalue
= rvalue
->as_tree ();
1820 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1821 t_rvalue
= build1 (CONVERT_EXPR
,
1822 TREE_TYPE (t_lvalue
),
1824 modify_retval
= build2 (MODIFY_EXPR
, return_type
,
1825 t_lvalue
, t_rvalue
);
1827 set_tree_location (modify_retval
, loc
);
1829 tree return_stmt
= build1 (RETURN_EXPR
, return_type
,
1832 set_tree_location (return_stmt
, loc
);
1834 add_stmt (return_stmt
);
1837 /* Helper function for playback::block::add_switch.
1838 Construct a case label for the given range, followed by a goto stmt
1839 to the given block, appending them to stmt list *ptr_t_switch_body. */
1842 add_case (tree
*ptr_t_switch_body
,
1845 playback::block
*dest_block
)
1847 tree t_label
= create_artificial_label (UNKNOWN_LOCATION
);
1848 DECL_CONTEXT (t_label
) = dest_block
->get_function ()->as_fndecl ();
1851 build_case_label (t_low_value
, t_high_value
, t_label
);
1852 append_to_statement_list (t_case_label
, ptr_t_switch_body
);
1855 build1 (GOTO_EXPR
, void_type_node
, dest_block
->as_label_decl ());
1856 append_to_statement_list (t_goto_stmt
, ptr_t_switch_body
);
1859 /* Add a switch statement to the function's statement list.
1861 We create a switch body, and populate it with case labels, each
1862 followed by a goto to the desired block. */
1866 add_switch (location
*loc
,
1868 block
*default_block
,
1869 const auto_vec
<case_
> *cases
)
1872 - c/c-typeck.c: c_start_case
1873 - c-family/c-common.c:c_add_case_label
1874 - java/expr.c:expand_java_switch and expand_java_add_case
1875 We've already rejected overlaps and duplicates in
1876 libgccjit.c:case_range_validator::validate. */
1878 tree t_expr
= expr
->as_tree ();
1879 tree t_type
= TREE_TYPE (t_expr
);
1881 tree t_switch_body
= alloc_stmt_list ();
1885 FOR_EACH_VEC_ELT (*cases
, i
, c
)
1887 tree t_low_value
= c
->m_min_value
->as_tree ();
1888 tree t_high_value
= c
->m_max_value
->as_tree ();
1889 add_case (&t_switch_body
, t_low_value
, t_high_value
, c
->m_dest_block
);
1891 /* Default label. */
1892 add_case (&t_switch_body
, NULL_TREE
, NULL_TREE
, default_block
);
1894 tree switch_stmt
= build2 (SWITCH_EXPR
, t_type
, t_expr
, t_switch_body
);
1896 set_tree_location (switch_stmt
, loc
);
1897 add_stmt (switch_stmt
);
1900 /* Constructor for gcc::jit::playback::block. */
1903 block (function
*func
,
1913 identifier
= get_identifier (name
);
1916 m_label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1917 identifier
, void_type_node
);
1918 DECL_CONTEXT (m_label_decl
) = func
->as_fndecl ();
1919 m_label_expr
= NULL
;
1922 /* Compile a playback::context:
1924 - Use the context's options to cconstruct command-line options, and
1925 call into the rest of GCC (toplev::main).
1926 - Assuming it succeeds, we have a .s file.
1927 - We then run the "postprocess" vfunc:
1929 (A) In-memory compile ("gcc_jit_context_compile")
1931 For an in-memory compile we have the playback::compile_to_memory
1932 subclass; "postprocess" will convert the .s file to a .so DSO,
1933 and load it in memory (via dlopen), wrapping the result up as
1934 a jit::result and returning it.
1936 (B) Compile to file ("gcc_jit_context_compile_to_file")
1938 When compiling to a file, we have the playback::compile_to_file
1939 subclass; "postprocess" will either copy the .s file to the
1940 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1941 the driver to convert it as necessary, copying the result. */
1947 JIT_LOG_SCOPE (get_logger ());
1949 const char *ctxt_progname
;
1951 int keep_intermediates
=
1952 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
);
1954 m_tempdir
= new tempdir (get_logger (), keep_intermediates
);
1955 if (!m_tempdir
->create ())
1958 /* Call into the rest of gcc.
1959 For now, we have to assemble command-line options to pass into
1960 toplev::main, so that they can be parsed. */
1962 /* Pass in user-provided program name as argv0, if any, so that it
1963 makes it into GCC's "progname" global, used in various diagnostics. */
1964 ctxt_progname
= get_str_option (GCC_JIT_STR_OPTION_PROGNAME
);
1967 ctxt_progname
= "libgccjit.so";
1969 auto_vec
<recording::requested_dump
> requested_dumps
;
1970 m_recording_ctxt
->get_all_requested_dumps (&requested_dumps
);
1972 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1975 auto_string_vec fake_args
;
1976 make_fake_args (&fake_args
, ctxt_progname
, &requested_dumps
);
1977 if (errors_occurred ())
1983 /* This runs the compiler. */
1984 toplev
toplev (get_timer (), /* external_timer */
1985 false); /* init_signals */
1986 enter_scope ("toplev::main");
1988 for (unsigned i
= 0; i
< fake_args
.length (); i
++)
1989 get_logger ()->log ("argv[%i]: %s", i
, fake_args
[i
]);
1990 toplev
.main (fake_args
.length (),
1991 const_cast <char **> (fake_args
.address ()));
1992 exit_scope ("toplev::main");
1994 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1995 need to do it between toplev::main (which creates the dump manager)
1996 and toplev::finalize (which deletes it). */
1997 extract_any_requested_dumps (&requested_dumps
);
1999 /* Clean up the compiler. */
2000 enter_scope ("toplev::finalize");
2002 exit_scope ("toplev::finalize");
2004 /* Ideally we would release the jit mutex here, but we can't yet since
2005 followup activities use timevars, which are global state. */
2007 if (errors_occurred ())
2013 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
))
2014 dump_generated_code ();
2016 /* We now have a .s file.
2018 Run any postprocessing steps. This will either convert the .s file to
2019 a .so DSO, and load it in memory (playback::compile_to_memory), or
2020 convert the .s file to the requested output format, and copy it to a
2021 given file (playback::compile_to_file). */
2022 postprocess (ctxt_progname
);
2027 /* Implementation of class gcc::jit::playback::compile_to_memory,
2028 a subclass of gcc::jit::playback::context. */
2030 /* playback::compile_to_memory's trivial constructor. */
2032 playback::compile_to_memory::compile_to_memory (recording::context
*ctxt
) :
2033 playback::context (ctxt
),
2036 JIT_LOG_SCOPE (get_logger ());
2039 /* Implementation of the playback::context::process vfunc for compiling
2042 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
2043 wrapping the result up as a jit::result and returning it. */
2046 playback::compile_to_memory::postprocess (const char *ctxt_progname
)
2048 JIT_LOG_SCOPE (get_logger ());
2049 convert_to_dso (ctxt_progname
);
2050 if (errors_occurred ())
2052 m_result
= dlopen_built_dso ();
2055 /* Implementation of class gcc::jit::playback::compile_to_file,
2056 a subclass of gcc::jit::playback::context. */
2058 /* playback::compile_to_file's trivial constructor. */
2060 playback::compile_to_file::compile_to_file (recording::context
*ctxt
,
2061 enum gcc_jit_output_kind output_kind
,
2062 const char *output_path
) :
2063 playback::context (ctxt
),
2064 m_output_kind (output_kind
),
2065 m_output_path (output_path
)
2067 JIT_LOG_SCOPE (get_logger ());
2070 /* Implementation of the playback::context::process vfunc for compiling
2073 Either copy the .s file to the given destination (for
2074 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
2075 as necessary, copying the result. */
2078 playback::compile_to_file::postprocess (const char *ctxt_progname
)
2080 JIT_LOG_SCOPE (get_logger ());
2082 /* The driver takes different actions based on the filename, so
2083 we provide a filename with an appropriate suffix for the
2084 output kind, and then copy it up to the user-provided path,
2085 rather than directly compiling it to the requested output path. */
2087 switch (m_output_kind
)
2092 case GCC_JIT_OUTPUT_KIND_ASSEMBLER
:
2093 copy_file (get_tempdir ()->get_path_s_file (),
2095 /* The .s file is automatically unlinked by tempdir::~tempdir. */
2098 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE
:
2100 char *tmp_o_path
= ::concat (get_tempdir ()->get_path (),
2103 invoke_driver (ctxt_progname
,
2104 get_tempdir ()->get_path_s_file (),
2107 false, /* bool shared, */
2108 false);/* bool run_linker */
2109 if (!errors_occurred ())
2111 copy_file (tmp_o_path
,
2113 get_tempdir ()->add_temp_file (tmp_o_path
);
2120 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY
:
2121 invoke_driver (ctxt_progname
,
2122 get_tempdir ()->get_path_s_file (),
2123 get_tempdir ()->get_path_so_file (),
2125 true, /* bool shared, */
2126 true);/* bool run_linker */
2127 if (!errors_occurred ())
2128 copy_file (get_tempdir ()->get_path_so_file (),
2130 /* The .so file is automatically unlinked by tempdir::~tempdir. */
2133 case GCC_JIT_OUTPUT_KIND_EXECUTABLE
:
2135 char *tmp_exe_path
= ::concat (get_tempdir ()->get_path (),
2138 invoke_driver (ctxt_progname
,
2139 get_tempdir ()->get_path_s_file (),
2142 false, /* bool shared, */
2143 true);/* bool run_linker */
2144 if (!errors_occurred ())
2146 copy_file (tmp_exe_path
,
2148 get_tempdir ()->add_temp_file (tmp_exe_path
);
2151 free (tmp_exe_path
);
2159 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2160 the "executable" bits).
2162 Any errors that occur are reported on the context and hence count as
2163 a failure of the compile.
2165 We can't in general hardlink or use "rename" from the tempdir since
2166 it might be on a different filesystem to the destination. For example,
2167 I get EXDEV: "Invalid cross-device link". */
2170 playback::compile_to_file::copy_file (const char *src_path
,
2171 const char *dst_path
)
2173 JIT_LOG_SCOPE (get_logger ());
2176 get_logger ()->log ("src_path: %s", src_path
);
2177 get_logger ()->log ("dst_path: %s", dst_path
);
2182 size_t total_sz_in
= 0;
2183 size_t total_sz_out
= 0;
2186 struct stat stat_buf
;
2188 f_in
= fopen (src_path
, "rb");
2192 "unable to open %s for reading: %s",
2198 /* Use stat on the filedescriptor to get the mode,
2199 so that we can copy it over (in particular, the
2200 "executable" bits). */
2201 if (fstat (fileno (f_in
), &stat_buf
) == -1)
2204 "unable to fstat %s: %s",
2211 f_out
= fopen (dst_path
, "wb");
2215 "unable to open %s for writing: %s",
2222 while ( (sz_in
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2224 total_sz_in
+= sz_in
;
2225 size_t sz_out_remaining
= sz_in
;
2226 size_t sz_out_so_far
= 0;
2227 while (sz_out_remaining
)
2229 size_t sz_out
= fwrite (buf
+ sz_out_so_far
,
2233 gcc_assert (sz_out
<= sz_out_remaining
);
2237 "error writing to %s: %s",
2244 total_sz_out
+= sz_out
;
2245 sz_out_so_far
+= sz_out
;
2246 sz_out_remaining
-= sz_out
;
2248 gcc_assert (sz_out_so_far
== sz_in
);
2253 "error reading from %s: %s",
2259 gcc_assert (total_sz_in
== total_sz_out
);
2261 get_logger ()->log ("total bytes copied: %zu", total_sz_out
);
2263 /* fchmod does not exist in Windows. */
2265 /* Set the permissions of the copy to those of the original file,
2266 in particular the "executable" bits. */
2267 if (fchmod (fileno (f_out
), stat_buf
.st_mode
) == -1)
2269 "error setting mode of %s: %s",
2277 /* Helper functions for gcc::jit::playback::context::compile. */
2279 /* This mutex guards gcc::jit::recording::context::compile, so that only
2280 one thread can be accessing the bulk of GCC's state at once. */
2282 static pthread_mutex_t jit_mutex
= PTHREAD_MUTEX_INITIALIZER
;
2284 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2287 playback::context::acquire_mutex ()
2289 auto_timevar
tv (get_timer (), TV_JIT_ACQUIRING_MUTEX
);
2291 /* Acquire the big GCC mutex. */
2292 JIT_LOG_SCOPE (get_logger ());
2293 pthread_mutex_lock (&jit_mutex
);
2294 gcc_assert (active_playback_ctxt
== NULL
);
2295 active_playback_ctxt
= this;
2298 /* Release jit_mutex and clear the active playback ctxt. */
2301 playback::context::release_mutex ()
2303 /* Release the big GCC mutex. */
2304 JIT_LOG_SCOPE (get_logger ());
2305 gcc_assert (active_playback_ctxt
== this);
2306 active_playback_ctxt
= NULL
;
2307 pthread_mutex_unlock (&jit_mutex
);
2310 /* Callback used by gcc::jit::playback::context::make_fake_args when
2311 invoking driver_get_configure_time_options.
2312 Populate a vec <char * > with the configure-time options. */
2315 append_arg_from_driver (const char *option
, void *user_data
)
2317 gcc_assert (option
);
2318 gcc_assert (user_data
);
2319 vec
<char *> *argvec
= static_cast <vec
<char *> *> (user_data
);
2320 argvec
->safe_push (concat ("-", option
, NULL
));
2323 /* Build a fake argv for toplev::main from the options set
2324 by the user on the context . */
2328 make_fake_args (vec
<char *> *argvec
,
2329 const char *ctxt_progname
,
2330 vec
<recording::requested_dump
> *requested_dumps
)
2332 JIT_LOG_SCOPE (get_logger ());
2334 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2335 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2337 ADD_ARG (ctxt_progname
);
2338 ADD_ARG (get_path_c_file ());
2341 /* Handle int options: */
2342 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
))
2346 "unrecognized optimization level: %i",
2347 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
));
2366 /* What about -Os? */
2368 /* Handle bool options: */
2369 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2372 /* Suppress timing (and other) info. */
2373 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
))
2379 /* Aggressively garbage-collect, to shake out bugs: */
2380 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC
))
2382 ADD_ARG ("--param=ggc-min-expand=0");
2383 ADD_ARG ("--param=ggc-min-heapsize=0");
2386 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
))
2388 ADD_ARG ("-fdump-tree-all");
2389 ADD_ARG ("-fdump-rtl-all");
2390 ADD_ARG ("-fdump-ipa-all");
2393 /* Add "-fdump-" options for any calls to
2394 gcc_jit_context_enable_dump. */
2397 recording::requested_dump
*d
;
2398 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2400 char *arg
= concat ("-fdump-", d
->m_dumpname
, NULL
);
2401 ADD_ARG_TAKE_OWNERSHIP (arg
);
2405 /* PR jit/64810: Add any target-specific default options
2406 from OPTION_DEFAULT_SPECS, normally provided by the driver
2407 in the non-jit case.
2409 The target-specific code can define OPTION_DEFAULT_SPECS:
2410 default command options in the form of spec macros for the
2411 driver to expand ().
2413 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2414 if not overriden, injects the defaults as extra arguments to
2416 For the jit case, we need to add these arguments here. The
2417 input format (using the specs language) means that we have to run
2418 part of the driver code here (driver_get_configure_time_options).
2420 To avoid running the spec-expansion code every time, we just do
2421 it the first time (via a function-static flag), saving the result
2422 into a function-static vec.
2423 This flag and vec are global state (i.e. per-process).
2424 They are guarded by the jit mutex. */
2426 static bool have_configure_time_options
= false;
2427 static vec
<char *> configure_time_options
;
2429 if (have_configure_time_options
)
2430 log ("reusing cached configure-time options");
2433 have_configure_time_options
= true;
2434 log ("getting configure-time options from driver");
2435 driver_get_configure_time_options (append_arg_from_driver
,
2436 &configure_time_options
);
2443 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2444 log ("configure_time_options[%i]: %s", i
, opt
);
2446 /* configure_time_options should now contain the expanded options
2447 from OPTION_DEFAULT_SPECS (if any). */
2448 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2451 gcc_assert (opt
[0] == '-');
2457 ADD_ARG ("-ftime-report");
2459 /* Add any user-provided extra options, starting with any from
2461 m_recording_ctxt
->append_command_line_options (argvec
);
2464 #undef ADD_ARG_TAKE_OWNERSHIP
2467 /* The second half of the implementation of gcc_jit_context_enable_dump.
2468 Iterate through the requested dumps, reading the underlying files
2469 into heap-allocated buffers, writing pointers to the buffers into
2470 the char ** pointers provided by client code.
2471 Client code is responsible for calling free on the results. */
2475 extract_any_requested_dumps (vec
<recording::requested_dump
> *requested_dumps
)
2477 JIT_LOG_SCOPE (get_logger ());
2480 recording::requested_dump
*d
;
2481 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2483 dump_file_info
*dfi
;
2487 dfi
= g
->get_dumps ()->get_dump_file_info_by_switch (d
->m_dumpname
);
2490 add_error (NULL
, "unrecognized dump: %s", d
->m_dumpname
);
2494 filename
= g
->get_dumps ()->get_dump_file_name (dfi
);
2495 content
= read_dump_file (filename
);
2496 *(d
->m_out_ptr
) = content
;
2497 m_tempdir
->add_temp_file (filename
);
2501 /* Helper function for playback::context::extract_any_requested_dumps
2502 (itself for use in implementation of gcc_jit_context_enable_dump).
2504 Attempt to read the complete file at the given path, returning the
2505 bytes found there as a buffer.
2506 The caller is responsible for calling free on the result.
2507 Errors will be reported on the context, and lead to NULL being
2508 returned; an out-of-memory error will terminate the process. */
2511 playback::context::read_dump_file (const char *path
)
2513 char *result
= NULL
;
2514 size_t total_sz
= 0;
2519 f_in
= fopen (path
, "r");
2522 add_error (NULL
, "unable to open %s for reading", path
);
2526 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2528 size_t old_total_sz
= total_sz
;
2530 result
= reinterpret_cast <char *> (xrealloc (result
, total_sz
+ 1));
2531 memcpy (result
+ old_total_sz
, buf
, sz
);
2536 add_error (NULL
, "error reading from %s", path
);
2546 result
[total_sz
] = '\0';
2550 return xstrdup ("");
2553 /* Part of playback::context::compile ().
2555 We have a .s file; we want a .so file.
2556 We could reuse parts of gcc/gcc.c to do this.
2557 For now, just use the driver binary from the install, as
2558 named in gcc-driver-name.h
2559 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2563 convert_to_dso (const char *ctxt_progname
)
2565 JIT_LOG_SCOPE (get_logger ());
2567 invoke_driver (ctxt_progname
,
2568 m_tempdir
->get_path_s_file (),
2569 m_tempdir
->get_path_so_file (),
2571 true, /* bool shared, */
2572 true);/* bool run_linker */
2575 static const char * const gcc_driver_name
= GCC_DRIVER_NAME
;
2579 invoke_driver (const char *ctxt_progname
,
2580 const char *input_file
,
2581 const char *output_file
,
2586 JIT_LOG_SCOPE (get_logger ());
2588 bool embedded_driver
2589 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER
);
2591 /* Currently this lumps together both assembling and linking into
2593 auto_timevar
assemble_timevar (get_timer (), tv_id
);
2594 auto_string_vec argvec
;
2595 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2597 ADD_ARG (gcc_driver_name
);
2599 add_multilib_driver_arguments (&argvec
);
2602 ADD_ARG ("-shared");
2607 ADD_ARG (input_file
);
2609 ADD_ARG (output_file
);
2611 /* Don't use the linker plugin.
2612 If running with just a "make" and not a "make install", then we'd
2614 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2615 libto_plugin is a .la at build time, with it becoming installed with
2616 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2618 ADD_ARG ("-fno-use-linker-plugin");
2620 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2621 /* OS X's linker defaults to treating undefined symbols as errors.
2622 If the context has any imported functions or globals they will be
2623 undefined until the .so is dynamically-linked into the process.
2624 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2626 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2632 /* Add any user-provided driver extra options. */
2634 m_recording_ctxt
->append_driver_options (&argvec
);
2638 /* pex_one's error-handling requires pname to be non-NULL. */
2639 gcc_assert (ctxt_progname
);
2642 for (unsigned i
= 0; i
< argvec
.length (); i
++)
2643 get_logger ()->log ("argv[%i]: %s", i
, argvec
[i
]);
2645 if (embedded_driver
)
2646 invoke_embedded_driver (&argvec
);
2648 invoke_external_driver (ctxt_progname
, &argvec
);
2653 invoke_embedded_driver (const vec
<char *> *argvec
)
2655 JIT_LOG_SCOPE (get_logger ());
2656 driver
d (true, /* can_finalize */
2658 int result
= d
.main (argvec
->length (),
2659 const_cast <char **> (argvec
->address ()));
2662 add_error (NULL
, "error invoking gcc driver");
2667 invoke_external_driver (const char *ctxt_progname
,
2668 vec
<char *> *argvec
)
2670 JIT_LOG_SCOPE (get_logger ());
2672 int exit_status
= 0;
2675 /* pex argv arrays are NULL-terminated. */
2676 argvec
->safe_push (NULL
);
2678 errmsg
= pex_one (PEX_SEARCH
, /* int flags, */
2680 const_cast <char *const *> (argvec
->address ()),
2681 ctxt_progname
, /* const char *pname */
2682 NULL
, /* const char *outname */
2683 NULL
, /* const char *errname */
2684 &exit_status
, /* int *status */
2685 &err
); /* int *err*/
2688 add_error (NULL
, "error invoking gcc driver: %s", errmsg
);
2692 /* pex_one can return a NULL errmsg when the executable wasn't
2693 found (or doesn't exist), so trap these cases also. */
2694 if (exit_status
|| err
)
2697 "error invoking gcc driver: exit_status: %i err: %i",
2700 "whilst attempting to run a driver named: %s",
2709 /* Extract the target-specific MULTILIB_DEFAULTS to
2710 multilib_defaults_raw for use by
2711 playback::context::add_multilib_driver_arguments (). */
2713 #ifndef MULTILIB_DEFAULTS
2714 #define MULTILIB_DEFAULTS { "" }
2717 static const char *const multilib_defaults_raw
[] = MULTILIB_DEFAULTS
;
2719 /* Helper function for playback::context::invoke_driver ().
2721 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2722 a driver binary. We need to pass in options to the shared driver
2723 to get the appropriate assembler/linker options for this multilib
2728 add_multilib_driver_arguments (vec
<char *> *argvec
)
2730 JIT_LOG_SCOPE (get_logger ());
2732 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2733 prepending each with a "-". */
2734 for (size_t i
= 0; i
< ARRAY_SIZE (multilib_defaults_raw
); i
++)
2735 if (multilib_defaults_raw
[i
][0])
2736 argvec
->safe_push (concat ("-", multilib_defaults_raw
[i
], NULL
));
2739 /* Dynamically-link the built DSO file into this process, using dlopen.
2740 Wrap it up within a jit::result *, and return that.
2741 Return NULL if any errors occur, reporting them on this context. */
2747 JIT_LOG_SCOPE (get_logger ());
2748 auto_timevar
load_timevar (get_timer (), TV_LOAD
);
2749 result::handle handle
= NULL
;
2750 result
*result_obj
= NULL
;
2753 /* Clear any existing error. */
2756 handle
= LoadLibrary(m_tempdir
->get_path_so_file ());
2757 if (GetLastError() != 0) {
2761 const char *error
= NULL
;
2762 /* Clear any existing error. */
2765 handle
= dlopen (m_tempdir
->get_path_so_file (),
2766 RTLD_NOW
| RTLD_LOCAL
);
2767 if ((error
= dlerror()) != NULL
) {
2768 add_error (NULL
, "%s", error
);
2774 /* We've successfully dlopened the result; create a
2775 jit::result object to wrap it.
2777 We're done with the tempdir for now, but if the user
2778 has requested debugging, the user's debugger might not
2779 be capable of dealing with the .so file being unlinked
2780 immediately, so keep it around until after the result
2781 is released. We do this by handing over ownership of
2782 the jit::tempdir to the result. See PR jit/64206. */
2783 tempdir
*handover_tempdir
;
2784 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2786 handover_tempdir
= m_tempdir
;
2788 /* The tempdir will eventually be cleaned up in the
2789 jit::result's dtor. */
2790 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2791 " handing over tempdir to jit::result");
2795 handover_tempdir
= NULL
;
2796 /* ... and retain ownership of m_tempdir so we clean it
2797 up it the playback::context's dtor. */
2798 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2799 " retaining ownership of tempdir");
2802 result_obj
= new result (get_logger (), handle
, handover_tempdir
);
2810 /* Top-level hook for playing back a recording context.
2812 This plays back m_recording_ctxt, and, if no errors
2813 occurred builds statement lists for and then postprocesses
2814 every function in the result. */
2820 JIT_LOG_SCOPE (get_logger ());
2823 = build_pointer_type (build_qualified_type (char_type_node
,
2826 /* Replay the recorded events: */
2827 timevar_push (TV_JIT_REPLAY
);
2829 m_recording_ctxt
->replay_into (this);
2831 /* Clean away the temporary references from recording objects
2832 to playback objects. We have to do this now since the
2833 latter are GC-allocated, but the former don't mark these
2834 refs. Hence we must stop using them before the GC can run. */
2835 m_recording_ctxt
->disassociate_from_playback ();
2837 /* The builtins_manager, if any, is associated with the recording::context
2838 and might be reused for future compiles on other playback::contexts,
2839 but its m_attributes array is not GTY-labeled and hence will become
2840 nonsense if the GC runs. Purge this state. */
2841 builtins_manager
*bm
= get_builtins_manager ();
2843 bm
->finish_playback ();
2845 timevar_pop (TV_JIT_REPLAY
);
2847 if (!errors_occurred ())
2852 /* No GC can happen yet; process the cached source locations. */
2853 handle_locations ();
2855 /* We've now created tree nodes for the stmts in the various blocks
2856 in each function, but we haven't built each function's single stmt
2857 list yet. Do so now. */
2858 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2859 func
->build_stmt_list ();
2861 /* No GC can have happened yet. */
2863 /* Postprocess the functions. This could trigger GC. */
2864 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2867 func
->postprocess ();
2872 /* Dump the generated .s file to stderr. */
2876 dump_generated_code ()
2878 JIT_LOG_SCOPE (get_logger ());
2881 FILE *f_in
= fopen (get_path_s_file (), "r");
2885 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2886 fwrite (buf
, 1, sz
, stderr
);
2891 /* Get the supposed path of the notional "fake.c" file within the
2892 tempdir. This file doesn't exist, but the rest of the compiler
2897 get_path_c_file () const
2899 return m_tempdir
->get_path_c_file ();
2902 /* Get the path of the assembler output file "fake.s" file within the
2907 get_path_s_file () const
2909 return m_tempdir
->get_path_s_file ();
2912 /* Get the path of the DSO object file "fake.so" file within the
2917 get_path_so_file () const
2919 return m_tempdir
->get_path_so_file ();
2922 /* qsort comparator for comparing pairs of playback::source_line *,
2923 ordering them by line number. */
2926 line_comparator (const void *lhs
, const void *rhs
)
2928 const playback::source_line
*line_lhs
= \
2929 *static_cast<const playback::source_line
* const*> (lhs
);
2930 const playback::source_line
*line_rhs
= \
2931 *static_cast<const playback::source_line
* const*> (rhs
);
2932 return line_lhs
->get_line_num () - line_rhs
->get_line_num ();
2935 /* qsort comparator for comparing pairs of playback::location *,
2936 ordering them by column number. */
2939 location_comparator (const void *lhs
, const void *rhs
)
2941 const playback::location
*loc_lhs
= \
2942 *static_cast<const playback::location
* const *> (lhs
);
2943 const playback::location
*loc_rhs
= \
2944 *static_cast<const playback::location
* const *> (rhs
);
2945 return loc_lhs
->get_column_num () - loc_rhs
->get_column_num ();
2948 /* Our API allows locations to be created in arbitrary orders, but the
2949 linemap API requires locations to be created in ascending order
2950 as if we were tokenizing files.
2952 This hook sorts all of the locations that have been created, and
2953 calls into the linemap API, creating linemap entries in sorted order
2954 for our locations. */
2960 /* Create the source code locations, following the ordering rules
2961 imposed by the linemap API.
2963 line_table is a global. */
2964 JIT_LOG_SCOPE (get_logger ());
2968 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2970 linemap_add (line_table
, LC_ENTER
, false, file
->get_filename (), 0);
2972 /* Sort lines by ascending line numbers. */
2973 file
->m_source_lines
.qsort (&line_comparator
);
2977 FOR_EACH_VEC_ELT (file
->m_source_lines
, j
, line
)
2982 /* Sort locations in line by ascending column numbers. */
2983 line
->m_locations
.qsort (&location_comparator
);
2985 /* Determine maximum column within this line. */
2986 gcc_assert (line
->m_locations
.length () > 0);
2987 location
*final_column
=
2988 line
->m_locations
[line
->m_locations
.length () - 1];
2989 int max_col
= final_column
->get_column_num ();
2991 linemap_line_start (line_table
, line
->get_line_num (), max_col
);
2992 FOR_EACH_VEC_ELT (line
->m_locations
, k
, loc
)
2995 linemap_position_for_column (line_table
, loc
->get_column_num ());
2999 linemap_add (line_table
, LC_LEAVE
, false, NULL
, 0);
3002 /* line_table should now be populated; every playback::location should
3003 now have an m_srcloc. */
3005 /* Now assign them to tree nodes as appropriate. */
3006 std::pair
<tree
, location
*> *cached_location
;
3008 FOR_EACH_VEC_ELT (m_cached_locations
, i
, cached_location
)
3010 tree t
= cached_location
->first
;
3011 location_t srcloc
= cached_location
->second
->m_srcloc
;
3013 /* This covers expressions: */
3014 if (CAN_HAVE_LOCATION_P (t
))
3015 SET_EXPR_LOCATION (t
, srcloc
);
3016 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t
), TS_DECL_MINIMAL
))
3017 DECL_SOURCE_LOCATION (t
) = srcloc
;
3020 /* Don't know how to set location on this node. */
3025 /* We handle errors on a playback::context by adding them to the
3026 corresponding recording::context. */
3030 add_error (location
*loc
, const char *fmt
, ...)
3034 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
3039 /* We handle errors on a playback::context by adding them to the
3040 corresponding recording::context. */
3044 add_error_va (location
*loc
, const char *fmt
, va_list ap
)
3046 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
3050 /* Report a diagnostic up to the jit context as an error,
3051 so that the compilation is treated as a failure.
3052 For now, any kind of diagnostic is treated as an error by the jit
3057 add_diagnostic (struct diagnostic_context
*diag_context
,
3058 struct diagnostic_info
*diagnostic
)
3060 /* At this point the text has been formatted into the pretty-printer's
3062 pretty_printer
*pp
= diag_context
->printer
;
3063 const char *text
= pp_formatted_text (pp
);
3065 /* Get location information (if any) from the diagnostic.
3066 The recording::context::add_error[_va] methods require a
3067 recording::location. We can't lookup the playback::location
3068 from the file/line/column since any playback location instances
3069 may have been garbage-collected away by now, so instead we create
3070 another recording::location directly. */
3071 location_t gcc_loc
= diagnostic_location (diagnostic
);
3072 recording::location
*rec_loc
= NULL
;
3075 expanded_location exploc
= expand_location (gcc_loc
);
3077 rec_loc
= m_recording_ctxt
->new_location (exploc
.file
,
3083 m_recording_ctxt
->add_error (rec_loc
, "%s", text
);
3084 pp_clear_output_area (pp
);
3087 /* Dealing with the linemap API. */
3089 /* Construct a playback::location for a recording::location, if it
3090 doesn't exist already. */
3092 playback::location
*
3094 new_location (recording::location
*rloc
,
3095 const char *filename
,
3099 /* Get the source_file for filename, creating if necessary. */
3100 source_file
*src_file
= get_source_file (filename
);
3101 /* Likewise for the line within the file. */
3102 source_line
*src_line
= src_file
->get_source_line (line
);
3103 /* Likewise for the column within the line. */
3104 location
*loc
= src_line
->get_location (rloc
, column
);
3108 /* Deferred setting of the location for a given tree, by adding the
3109 (tree, playback::location) pair to a list of deferred associations.
3110 We will actually set the location on the tree later on once
3111 the location_t for the playback::location exists. */
3115 set_tree_location (tree t
, location
*loc
)
3118 m_cached_locations
.safe_push (std::make_pair (t
, loc
));
3122 /* Construct a playback::source_file for the given source
3123 filename, if it doesn't exist already. */
3125 playback::source_file
*
3127 get_source_file (const char *filename
)
3130 For simplicitly, this is currently a linear search.
3131 Replace with a hash if this shows up in the profile. */
3134 tree ident_filename
= get_identifier (filename
);
3136 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
3137 if (file
->filename_as_tree () == ident_filename
)
3141 file
= new source_file (ident_filename
);
3142 m_source_files
.safe_push (file
);
3146 /* Constructor for gcc::jit::playback::source_file. */
3148 playback::source_file::source_file (tree filename
) :
3150 m_filename (filename
)
3154 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3158 playback::source_file::finalizer ()
3160 m_source_lines
.release ();
3163 /* Construct a playback::source_line for the given line
3164 within this source file, if one doesn't exist already. */
3166 playback::source_line
*
3167 playback::source_file::
3168 get_source_line (int line_num
)
3171 For simplicitly, this is currently a linear search.
3172 Replace with a hash if this shows up in the profile. */
3176 FOR_EACH_VEC_ELT (m_source_lines
, i
, line
)
3177 if (line
->get_line_num () == line_num
)
3181 line
= new source_line (this, line_num
);
3182 m_source_lines
.safe_push (line
);
3186 /* Constructor for gcc::jit::playback::source_line. */
3188 playback::source_line::source_line (source_file
*file
, int line_num
) :
3190 m_source_file (file
),
3191 m_line_num (line_num
)
3195 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3199 playback::source_line::finalizer ()
3201 m_locations
.release ();
3204 /* Construct a playback::location for the given column
3205 within this line of a specific source file, if one doesn't exist
3208 playback::location
*
3209 playback::source_line::
3210 get_location (recording::location
*rloc
, int column_num
)
3215 /* Another linear search that probably should be a hash table. */
3216 FOR_EACH_VEC_ELT (m_locations
, i
, loc
)
3217 if (loc
->get_column_num () == column_num
)
3221 loc
= new location (rloc
, this, column_num
);
3222 m_locations
.safe_push (loc
);
3226 /* Constructor for gcc::jit::playback::location. */
3228 playback::location::location (recording::location
*loc
,
3231 m_srcloc (UNKNOWN_LOCATION
),
3232 m_recording_loc (loc
),
3234 m_column_num(column_num
)
3238 /* The active gcc::jit::playback::context instance. This is a singleton,
3239 guarded by jit_mutex. */
3241 playback::context
*active_playback_ctxt
;
3243 } // namespace gcc::jit