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 /* Construct a playback::lvalue instance (wrapping a tree). */
517 new_global (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
);
550 varpool_node::get_create (inner
);
552 varpool_node::finalize_decl (inner
);
554 m_globals
.safe_push (inner
);
556 return new lvalue (this, inner
);
559 /* Implementation of the various
560 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
562 Each of these constructs a playback::rvalue instance (wrapping a tree).
564 These specializations are required to be in the same namespace
565 as the template, hence we now have to enter the gcc::jit::playback
571 /* Specialization of making an rvalue from a const, for host <int>. */
576 new_rvalue_from_const
<int> (type
*type
,
579 // FIXME: type-checking, or coercion?
580 tree inner_type
= type
->as_tree ();
581 if (INTEGRAL_TYPE_P (inner_type
))
583 tree inner
= build_int_cst (inner_type
, value
);
584 return new rvalue (this, inner
);
588 REAL_VALUE_TYPE real_value
;
589 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
590 tree inner
= build_real (inner_type
, real_value
);
591 return new rvalue (this, inner
);
595 /* Specialization of making an rvalue from a const, for host <long>. */
600 new_rvalue_from_const
<long> (type
*type
,
603 // FIXME: type-checking, or coercion?
604 tree inner_type
= type
->as_tree ();
605 if (INTEGRAL_TYPE_P (inner_type
))
607 tree inner
= build_int_cst (inner_type
, value
);
608 return new rvalue (this, inner
);
612 REAL_VALUE_TYPE real_value
;
613 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
614 tree inner
= build_real (inner_type
, real_value
);
615 return new rvalue (this, inner
);
619 /* Specialization of making an rvalue from a const, for host <double>. */
624 new_rvalue_from_const
<double> (type
*type
,
627 // FIXME: type-checking, or coercion?
628 tree inner_type
= type
->as_tree ();
630 /* We have a "double", we want a REAL_VALUE_TYPE.
632 real.c:real_from_target appears to require the representation to be
633 split into 32-bit values, and then sent as an pair of host long
635 REAL_VALUE_TYPE real_value
;
639 uint32_t as_uint32s
[2];
642 long int as_long_ints
[2];
643 as_long_ints
[0] = u
.as_uint32s
[0];
644 as_long_ints
[1] = u
.as_uint32s
[1];
645 real_from_target (&real_value
, as_long_ints
, DFmode
);
646 tree inner
= build_real (inner_type
, real_value
);
647 return new rvalue (this, inner
);
650 /* Specialization of making an rvalue from a const, for host <void *>. */
655 new_rvalue_from_const
<void *> (type
*type
,
658 tree inner_type
= type
->as_tree ();
659 /* FIXME: how to ensure we have a wide enough type? */
660 tree inner
= build_int_cstu (inner_type
, (unsigned HOST_WIDE_INT
)value
);
661 return new rvalue (this, inner
);
664 /* We're done implementing the specializations of
665 gcc::jit::playback::context::new_rvalue_from_const <T>
666 so we can exit the gcc::jit::playback namespace. */
668 } // namespace playback
670 /* Construct a playback::rvalue instance (wrapping a tree). */
674 new_string_literal (const char *value
)
676 /* Compare with c-family/c-common.c: fix_string_type. */
677 size_t len
= strlen (value
);
678 tree i_type
= build_index_type (size_int (len
));
679 tree a_type
= build_array_type (char_type_node
, i_type
);
680 /* build_string len parameter must include NUL terminator when
681 building C strings. */
682 tree t_str
= build_string (len
+ 1, value
);
683 TREE_TYPE (t_str
) = a_type
;
685 /* Convert to (const char*), loosely based on
686 c/c-typeck.c: array_to_pointer_conversion,
687 by taking address of start of string. */
688 tree t_addr
= build1 (ADDR_EXPR
, m_const_char_ptr
, t_str
);
690 return new rvalue (this, t_addr
);
693 /* Construct a playback::rvalue instance (wrapping a tree) for a
697 playback::context::new_rvalue_from_vector (location
*,
699 const auto_vec
<rvalue
*> &elements
)
701 vec
<constructor_elt
, va_gc
> *v
;
702 vec_alloc (v
, elements
.length ());
703 for (unsigned i
= 0; i
< elements
.length (); ++i
)
704 CONSTRUCTOR_APPEND_ELT (v
, NULL_TREE
, elements
[i
]->as_tree ());
705 tree t_ctor
= build_constructor (type
->as_tree (), v
);
706 return new rvalue (this, t_ctor
);
709 /* Coerce a tree expression into a boolean tree expression. */
713 as_truth_value (tree expr
, location
*loc
)
715 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
716 tree typed_zero
= fold_build1 (CONVERT_EXPR
,
720 set_tree_location (typed_zero
, loc
);
722 expr
= build2 (NE_EXPR
, integer_type_node
, expr
, typed_zero
);
724 set_tree_location (expr
, loc
);
729 /* Construct a playback::rvalue instance (wrapping a tree) for a
734 new_unary_op (location
*loc
,
735 enum gcc_jit_unary_op op
,
739 // FIXME: type-checking, or coercion?
740 enum tree_code inner_op
;
742 gcc_assert (result_type
);
745 tree node
= a
->as_tree ();
746 tree inner_result
= NULL
;
751 add_error (loc
, "unrecognized (enum gcc_jit_unary_op) value: %i", op
);
754 case GCC_JIT_UNARY_OP_MINUS
:
755 inner_op
= NEGATE_EXPR
;
758 case GCC_JIT_UNARY_OP_BITWISE_NEGATE
:
759 inner_op
= BIT_NOT_EXPR
;
762 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE
:
763 node
= as_truth_value (node
, loc
);
764 inner_result
= invert_truthvalue (node
);
766 set_tree_location (inner_result
, loc
);
767 return new rvalue (this, inner_result
);
769 case GCC_JIT_UNARY_OP_ABS
:
774 inner_result
= build1 (inner_op
,
775 result_type
->as_tree (),
778 set_tree_location (inner_result
, loc
);
780 return new rvalue (this, inner_result
);
783 /* Construct a playback::rvalue instance (wrapping a tree) for a
788 new_binary_op (location
*loc
,
789 enum gcc_jit_binary_op op
,
791 rvalue
*a
, rvalue
*b
)
793 // FIXME: type-checking, or coercion?
794 enum tree_code inner_op
;
796 gcc_assert (result_type
);
800 tree node_a
= a
->as_tree ();
801 tree node_b
= b
->as_tree ();
806 add_error (loc
, "unrecognized (enum gcc_jit_binary_op) value: %i", op
);
809 case GCC_JIT_BINARY_OP_PLUS
:
810 inner_op
= PLUS_EXPR
;
813 case GCC_JIT_BINARY_OP_MINUS
:
814 inner_op
= MINUS_EXPR
;
817 case GCC_JIT_BINARY_OP_MULT
:
818 inner_op
= MULT_EXPR
;
821 case GCC_JIT_BINARY_OP_DIVIDE
:
822 if (FLOAT_TYPE_P (result_type
->as_tree ()))
823 /* Floating-point division: */
824 inner_op
= RDIV_EXPR
;
826 /* Truncating to zero: */
827 inner_op
= TRUNC_DIV_EXPR
;
830 case GCC_JIT_BINARY_OP_MODULO
:
831 inner_op
= TRUNC_MOD_EXPR
;
834 case GCC_JIT_BINARY_OP_BITWISE_AND
:
835 inner_op
= BIT_AND_EXPR
;
838 case GCC_JIT_BINARY_OP_BITWISE_XOR
:
839 inner_op
= BIT_XOR_EXPR
;
842 case GCC_JIT_BINARY_OP_BITWISE_OR
:
843 inner_op
= BIT_IOR_EXPR
;
846 case GCC_JIT_BINARY_OP_LOGICAL_AND
:
847 node_a
= as_truth_value (node_a
, loc
);
848 node_b
= as_truth_value (node_b
, loc
);
849 inner_op
= TRUTH_ANDIF_EXPR
;
852 case GCC_JIT_BINARY_OP_LOGICAL_OR
:
853 node_a
= as_truth_value (node_a
, loc
);
854 node_b
= as_truth_value (node_b
, loc
);
855 inner_op
= TRUTH_ORIF_EXPR
;
858 case GCC_JIT_BINARY_OP_LSHIFT
:
859 inner_op
= LSHIFT_EXPR
;
862 case GCC_JIT_BINARY_OP_RSHIFT
:
863 inner_op
= RSHIFT_EXPR
;
867 tree inner_expr
= build2 (inner_op
,
868 result_type
->as_tree (),
872 set_tree_location (inner_expr
, loc
);
874 return new rvalue (this, inner_expr
);
877 /* Construct a playback::rvalue instance (wrapping a tree) for a
882 new_comparison (location
*loc
,
883 enum gcc_jit_comparison op
,
884 rvalue
*a
, rvalue
*b
)
886 // FIXME: type-checking, or coercion?
887 enum tree_code inner_op
;
895 add_error (loc
, "unrecognized (enum gcc_jit_comparison) value: %i", op
);
898 case GCC_JIT_COMPARISON_EQ
:
901 case GCC_JIT_COMPARISON_NE
:
904 case GCC_JIT_COMPARISON_LT
:
907 case GCC_JIT_COMPARISON_LE
:
910 case GCC_JIT_COMPARISON_GT
:
913 case GCC_JIT_COMPARISON_GE
:
918 tree inner_expr
= build2 (inner_op
,
923 set_tree_location (inner_expr
, loc
);
924 return new rvalue (this, inner_expr
);
927 /* Construct a playback::rvalue instance (wrapping a tree) for a
932 build_call (location
*loc
,
934 const auto_vec
<rvalue
*> *args
,
935 bool require_tail_call
)
937 vec
<tree
, va_gc
> *tree_args
;
938 vec_alloc (tree_args
, args
->length ());
939 for (unsigned i
= 0; i
< args
->length (); i
++)
940 tree_args
->quick_push ((*args
)[i
]->as_tree ());
943 set_tree_location (fn_ptr
, loc
);
945 tree fn
= TREE_TYPE (fn_ptr
);
946 tree fn_type
= TREE_TYPE (fn
);
947 tree return_type
= TREE_TYPE (fn_type
);
949 tree call
= build_call_vec (return_type
,
952 if (require_tail_call
)
953 CALL_EXPR_MUST_TAIL_CALL (call
) = 1;
955 return new rvalue (this, call
);
957 /* see c-typeck.c: build_function_call
958 which calls build_function_call_vec
960 which does lots of checking, then:
961 result = build_call_array_loc (loc, TREE_TYPE (fntype),
962 function, nargs, argarray);
964 (see also build_call_vec)
968 /* Construct a playback::rvalue instance (wrapping a tree) for a
969 call to a specific function. */
973 new_call (location
*loc
,
975 const auto_vec
<rvalue
*> *args
,
976 bool require_tail_call
)
982 fndecl
= func
->as_fndecl ();
984 tree fntype
= TREE_TYPE (fndecl
);
986 tree fn
= build1 (ADDR_EXPR
, build_pointer_type (fntype
), fndecl
);
988 return build_call (loc
, fn
, args
, require_tail_call
);
991 /* Construct a playback::rvalue instance (wrapping a tree) for a
992 call through a function pointer. */
996 new_call_through_ptr (location
*loc
,
998 const auto_vec
<rvalue
*> *args
,
999 bool require_tail_call
)
1001 gcc_assert (fn_ptr
);
1002 tree t_fn_ptr
= fn_ptr
->as_tree ();
1004 return build_call (loc
, t_fn_ptr
, args
, require_tail_call
);
1007 /* Construct a tree for a cast. */
1010 playback::context::build_cast (playback::location
*loc
,
1011 playback::rvalue
*expr
,
1012 playback::type
*type_
)
1014 /* For comparison, see:
1015 - c/c-typeck.c:build_c_cast
1016 - c/c-convert.c: convert
1019 Only some kinds of cast are currently supported here. */
1020 tree t_expr
= expr
->as_tree ();
1021 tree t_dst_type
= type_
->as_tree ();
1023 t_ret
= targetm
.convert_to_type (t_dst_type
, t_expr
);
1026 enum tree_code dst_code
= TREE_CODE (t_dst_type
);
1031 t_ret
= convert_to_integer (t_dst_type
, t_expr
);
1035 /* Compare with c_objc_common_truthvalue_conversion and
1036 c_common_truthvalue_conversion. */
1037 /* For now, convert to: (t_expr != 0) */
1038 t_ret
= build2 (NE_EXPR
, t_dst_type
,
1040 build_int_cst (TREE_TYPE (t_expr
), 0));
1044 t_ret
= convert_to_real (t_dst_type
, t_expr
);
1048 t_ret
= build1 (NOP_EXPR
, t_dst_type
, t_expr
);
1052 add_error (loc
, "couldn't handle cast during playback");
1053 fprintf (stderr
, "input expression:\n");
1054 debug_tree (t_expr
);
1055 fprintf (stderr
, "requested type:\n");
1056 debug_tree (t_dst_type
);
1057 return error_mark_node
;
1060 if (TREE_CODE (t_ret
) != C_MAYBE_CONST_EXPR
)
1061 t_ret
= fold (t_ret
);
1066 /* Construct a playback::rvalue instance (wrapping a tree) for a
1071 new_cast (playback::location
*loc
,
1072 playback::rvalue
*expr
,
1073 playback::type
*type_
)
1076 tree t_cast
= build_cast (loc
, expr
, type_
);
1078 set_tree_location (t_cast
, loc
);
1079 return new rvalue (this, t_cast
);
1082 /* Construct a playback::lvalue instance (wrapping a tree) for an
1087 new_array_access (location
*loc
,
1094 /* For comparison, see:
1095 c/c-typeck.c: build_array_ref
1096 c-family/c-common.c: pointer_int_sum
1098 tree t_ptr
= ptr
->as_tree ();
1099 tree t_index
= index
->as_tree ();
1100 tree t_type_ptr
= TREE_TYPE (t_ptr
);
1101 tree t_type_star_ptr
= TREE_TYPE (t_type_ptr
);
1103 if (TREE_CODE (t_type_ptr
) == ARRAY_TYPE
)
1105 tree t_result
= build4 (ARRAY_REF
, t_type_star_ptr
, t_ptr
, t_index
,
1106 NULL_TREE
, NULL_TREE
);
1108 set_tree_location (t_result
, loc
);
1109 return new lvalue (this, t_result
);
1113 /* Convert index to an offset in bytes. */
1114 tree t_sizeof
= size_in_bytes (t_type_star_ptr
);
1115 t_index
= fold_build1 (CONVERT_EXPR
, sizetype
, t_index
);
1116 tree t_offset
= build2 (MULT_EXPR
, sizetype
, t_index
, t_sizeof
);
1118 /* Locate (ptr + offset). */
1119 tree t_address
= build2 (POINTER_PLUS_EXPR
, t_type_ptr
, t_ptr
, t_offset
);
1121 tree t_indirection
= build1 (INDIRECT_REF
, t_type_star_ptr
, t_address
);
1124 set_tree_location (t_sizeof
, loc
);
1125 set_tree_location (t_offset
, loc
);
1126 set_tree_location (t_address
, loc
);
1127 set_tree_location (t_indirection
, loc
);
1130 return new lvalue (this, t_indirection
);
1134 /* Construct a tree for a field access. */
1138 new_field_access (location
*loc
,
1145 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1146 build_component_ref. */
1147 tree type
= TREE_TYPE (datum
);
1149 gcc_assert (TREE_CODE (type
) != POINTER_TYPE
);
1151 tree t_field
= field
->as_tree ();
1152 tree ref
= build3 (COMPONENT_REF
, TREE_TYPE (t_field
), datum
,
1153 t_field
, NULL_TREE
);
1155 set_tree_location (ref
, loc
);
1159 /* Construct a tree for a dereference. */
1163 new_dereference (tree ptr
,
1168 tree type
= TREE_TYPE (TREE_TYPE(ptr
));
1169 tree datum
= build1 (INDIRECT_REF
, type
, ptr
);
1171 set_tree_location (datum
, loc
);
1175 /* Construct a playback::type instance (wrapping a tree)
1176 with the given alignment. */
1180 get_aligned (size_t alignment_in_bytes
) const
1182 tree t_new_type
= build_variant_type_copy (m_inner
);
1184 SET_TYPE_ALIGN (t_new_type
, alignment_in_bytes
* BITS_PER_UNIT
);
1185 TYPE_USER_ALIGN (t_new_type
) = 1;
1187 return new type (t_new_type
);
1190 /* Construct a playback::type instance (wrapping a tree)
1191 for the given vector type. */
1195 get_vector (size_t num_units
) const
1197 tree t_new_type
= build_vector_type (m_inner
, num_units
);
1198 return new type (t_new_type
);
1201 /* Construct a playback::lvalue instance (wrapping a tree) for a
1206 access_field (location
*loc
,
1209 tree datum
= as_tree ();
1210 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1213 return new lvalue (get_context (), ref
);
1216 /* Construct a playback::rvalue instance (wrapping a tree) for a
1221 access_field (location
*loc
,
1224 tree datum
= as_tree ();
1225 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1228 return new rvalue (get_context (), ref
);
1231 /* Construct a playback::lvalue instance (wrapping a tree) for a
1232 dereferenced field access. */
1236 dereference_field (location
*loc
,
1239 tree ptr
= as_tree ();
1240 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1243 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1246 return new lvalue (get_context (), ref
);
1249 /* Construct a playback::lvalue instance (wrapping a tree) for a
1254 dereference (location
*loc
)
1256 tree ptr
= as_tree ();
1257 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1258 return new lvalue (get_context (), datum
);
1261 /* Mark the lvalue saying that we need to be able to take the
1262 address of it; it should not be allocated in a register.
1263 Compare with e.g. c/c-typeck.c: c_mark_addressable really_atomic_lvalue.
1264 Returns false if a failure occurred (an error will already have been
1265 added to the active context for this case). */
1269 mark_addressable (location
*loc
)
1271 tree x
= as_tree ();;
1274 switch (TREE_CODE (x
))
1277 if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x
, 1)))
1279 gcc_assert (gcc::jit::active_playback_ctxt
);
1281 active_playback_ctxt
->add_error (loc
,
1282 "cannot take address of "
1291 x
= TREE_OPERAND (x
, 0);
1294 case COMPOUND_LITERAL_EXPR
:
1296 TREE_ADDRESSABLE (x
) = 1;
1303 /* (we don't have a concept of a "register" declaration) */
1306 TREE_ADDRESSABLE (x
) = 1;
1313 /* Construct a playback::rvalue instance (wrapping a tree) for an
1318 get_address (location
*loc
)
1320 tree t_lvalue
= as_tree ();
1321 tree t_thistype
= TREE_TYPE (t_lvalue
);
1322 tree t_ptrtype
= build_pointer_type (t_thistype
);
1323 tree ptr
= build1 (ADDR_EXPR
, t_ptrtype
, t_lvalue
);
1325 get_context ()->set_tree_location (ptr
, loc
);
1326 if (mark_addressable (loc
))
1327 return new rvalue (get_context (), ptr
);
1332 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1333 Provide this finalization hook for calling then they are collected,
1334 which calls the finalizer vfunc. This allows them to call "release"
1335 on any vec<> within them. */
1338 wrapper_finalizer (void *ptr
)
1340 playback::wrapper
*wrapper
= reinterpret_cast <playback::wrapper
*> (ptr
);
1341 wrapper
->finalizer ();
1344 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1345 allocate them using ggc_internal_cleared_alloc. */
1349 operator new (size_t sz
)
1351 return ggc_internal_cleared_alloc (sz
, wrapper_finalizer
, 0, 1);
1355 /* Constructor for gcc:jit::playback::function. */
1357 playback::function::
1358 function (context
*ctxt
,
1360 enum gcc_jit_function_kind kind
)
1362 m_inner_fndecl (fndecl
),
1363 m_inner_bind_expr (NULL
),
1366 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1368 /* Create a BIND_EXPR, and within it, a statement list. */
1369 m_stmt_list
= alloc_stmt_list ();
1370 m_stmt_iter
= tsi_start (m_stmt_list
);
1371 m_inner_block
= make_node (BLOCK
);
1373 build3 (BIND_EXPR
, void_type_node
, NULL
, m_stmt_list
, m_inner_block
);
1377 m_inner_block
= NULL
;
1382 /* Hand-written GC-marking hook for playback functions. */
1385 playback::function::
1388 gt_ggc_m_9tree_node (m_inner_fndecl
);
1389 gt_ggc_m_9tree_node (m_inner_bind_expr
);
1390 gt_ggc_m_9tree_node (m_stmt_list
);
1391 gt_ggc_m_9tree_node (m_inner_block
);
1394 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1398 playback::function::finalizer ()
1400 m_blocks
.release ();
1403 /* Get the return type of a playback function, in tree form. */
1406 playback::function::
1407 get_return_type_as_tree () const
1409 return TREE_TYPE (TREE_TYPE(m_inner_fndecl
));
1412 /* Construct a new local within this playback::function. */
1415 playback::function::
1416 new_local (location
*loc
,
1422 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
1423 get_identifier (name
),
1425 DECL_CONTEXT (inner
) = this->m_inner_fndecl
;
1427 /* Prepend to BIND_EXPR_VARS: */
1428 DECL_CHAIN (inner
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1429 BIND_EXPR_VARS (m_inner_bind_expr
) = inner
;
1432 set_tree_location (inner
, loc
);
1433 return new lvalue (m_ctxt
, inner
);
1436 /* Construct a new block within this playback::function. */
1439 playback::function::
1440 new_block (const char *name
)
1442 gcc_assert (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
);
1444 block
*result
= new playback::block (this, name
);
1445 m_blocks
.safe_push (result
);
1449 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1450 this playback::function. */
1453 playback::function::get_address (location
*loc
)
1455 tree t_fndecl
= as_fndecl ();
1456 tree t_fntype
= TREE_TYPE (t_fndecl
);
1457 tree t_fnptr
= build1 (ADDR_EXPR
, build_pointer_type (t_fntype
), t_fndecl
);
1459 m_ctxt
->set_tree_location (t_fnptr
, loc
);
1460 return new rvalue (m_ctxt
, t_fnptr
);
1463 /* Build a statement list for the function as a whole out of the
1464 lists of statements for the individual blocks, building labels
1468 playback::function::
1474 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1476 FOR_EACH_VEC_ELT (m_blocks
, i
, b
)
1481 b
->m_label_expr
= build1 (LABEL_EXPR
,
1483 b
->as_label_decl ());
1484 tsi_link_after (&m_stmt_iter
, b
->m_label_expr
, TSI_CONTINUE_LINKING
);
1486 FOR_EACH_VEC_ELT (b
->m_stmts
, j
, stmt
)
1487 tsi_link_after (&m_stmt_iter
, stmt
, TSI_CONTINUE_LINKING
);
1491 /* Finish compiling the given function, potentially running the
1493 The function will have a statement list by now.
1494 Amongst other things, this gimplifies the statement list,
1495 and calls cgraph_node::finalize_function on the function. */
1498 playback::function::
1501 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1503 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
))
1504 debug_tree (m_stmt_list
);
1506 /* Do we need this to force cgraphunit.c to output the function? */
1507 if (m_kind
== GCC_JIT_FUNCTION_EXPORTED
)
1509 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1510 DECL_PRESERVE_P (m_inner_fndecl
) = 1;
1513 if (m_kind
== GCC_JIT_FUNCTION_INTERNAL
1514 ||m_kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
1516 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1517 TREE_PUBLIC (m_inner_fndecl
) = 0;
1520 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1522 /* Seem to need this in gimple-low.c: */
1523 gcc_assert (m_inner_block
);
1524 DECL_INITIAL (m_inner_fndecl
) = m_inner_block
;
1526 /* how to add to function? the following appears to be how to
1527 set the body of a m_inner_fndecl: */
1528 DECL_SAVED_TREE(m_inner_fndecl
) = m_inner_bind_expr
;
1530 /* Ensure that locals appear in the debuginfo. */
1531 BLOCK_VARS (m_inner_block
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1533 //debug_tree (m_inner_fndecl);
1535 /* Convert to gimple: */
1536 //printf("about to gimplify_function_tree\n");
1537 gimplify_function_tree (m_inner_fndecl
);
1538 //printf("finished gimplify_function_tree\n");
1540 current_function_decl
= m_inner_fndecl
;
1541 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
))
1542 dump_function_to_file (m_inner_fndecl
, stderr
, TDF_VOPS
|TDF_MEMSYMS
|TDF_LINENO
);
1543 //debug_tree (m_inner_fndecl);
1545 //printf("about to add to cgraph\n");
1546 /* Add to cgraph: */
1547 cgraph_node::finalize_function (m_inner_fndecl
, false);
1548 /* This can trigger a collection, so we need to have all of
1549 the funcs as roots. */
1551 current_function_decl
= NULL
;
1555 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1559 playback::block::finalizer ()
1564 /* Add an eval of the rvalue to the function's statement list. */
1568 add_eval (location
*loc
,
1571 gcc_assert (rvalue
);
1574 set_tree_location (rvalue
->as_tree (), loc
);
1576 add_stmt (rvalue
->as_tree ());
1579 /* Add an assignment to the function's statement list. */
1583 add_assignment (location
*loc
,
1587 gcc_assert (lvalue
);
1588 gcc_assert (rvalue
);
1590 tree t_lvalue
= lvalue
->as_tree ();
1591 tree t_rvalue
= rvalue
->as_tree ();
1592 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1594 t_rvalue
= build1 (CONVERT_EXPR
,
1595 TREE_TYPE (t_lvalue
),
1598 set_tree_location (t_rvalue
, loc
);
1602 build2 (MODIFY_EXPR
, TREE_TYPE (t_lvalue
),
1603 t_lvalue
, t_rvalue
);
1605 set_tree_location (stmt
, loc
);
1609 /* Add a comment to the function's statement list.
1610 For now this is done by adding a dummy label. */
1614 add_comment (location
*loc
,
1617 /* Wrap the text in C-style comment delimiters. */
1619 (3 /* opening delim */
1621 + 3 /* closing delim */
1622 + 1 /* terminator */);
1623 char *wrapped
= (char *)ggc_internal_alloc (sz
);
1624 snprintf (wrapped
, sz
, "/* %s */", text
);
1626 /* For now we simply implement this by adding a dummy label with a name
1627 containing the given text. */
1628 tree identifier
= get_identifier (wrapped
);
1629 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1630 identifier
, void_type_node
);
1631 DECL_CONTEXT (label_decl
) = m_func
->as_fndecl ();
1633 tree label_expr
= build1 (LABEL_EXPR
, void_type_node
, label_decl
);
1635 set_tree_location (label_expr
, loc
);
1636 add_stmt (label_expr
);
1639 /* Add a conditional jump statement to the function's statement list. */
1643 add_conditional (location
*loc
,
1648 gcc_assert (boolval
);
1649 gcc_assert (on_true
);
1650 gcc_assert (on_false
);
1652 /* COND_EXPR wants statement lists for the true/false operands, but we
1654 Shim it by creating jumps to the labels */
1655 tree true_jump
= build1 (GOTO_EXPR
, void_type_node
,
1656 on_true
->as_label_decl ());
1658 set_tree_location (true_jump
, loc
);
1660 tree false_jump
= build1 (GOTO_EXPR
, void_type_node
,
1661 on_false
->as_label_decl ());
1663 set_tree_location (false_jump
, loc
);
1666 build3 (COND_EXPR
, void_type_node
, boolval
->as_tree (),
1667 true_jump
, false_jump
);
1669 set_tree_location (stmt
, loc
);
1673 /* Add an unconditional jump statement to the function's statement list. */
1677 add_jump (location
*loc
,
1680 gcc_assert (target
);
1682 // see c_finish_loop
1683 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1686 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1687 TREE_USED (target
->as_label_decl ()) = 1;
1688 tree stmt
= build1 (GOTO_EXPR
, void_type_node
, target
->as_label_decl ());
1690 set_tree_location (stmt
, loc
);
1696 c_finish_goto_label (location_t loc, tree label)
1698 tree decl = lookup_label_for_goto (loc, label);
1701 TREE_USED (decl) = 1;
1703 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1704 SET_EXPR_LOCATION (t, loc);
1705 return add_stmt (t);
1712 /* Add a return statement to the function's statement list. */
1716 add_return (location
*loc
,
1719 tree modify_retval
= NULL
;
1720 tree return_type
= m_func
->get_return_type_as_tree ();
1723 tree t_lvalue
= DECL_RESULT (m_func
->as_fndecl ());
1724 tree t_rvalue
= rvalue
->as_tree ();
1725 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1726 t_rvalue
= build1 (CONVERT_EXPR
,
1727 TREE_TYPE (t_lvalue
),
1729 modify_retval
= build2 (MODIFY_EXPR
, return_type
,
1730 t_lvalue
, t_rvalue
);
1732 set_tree_location (modify_retval
, loc
);
1734 tree return_stmt
= build1 (RETURN_EXPR
, return_type
,
1737 set_tree_location (return_stmt
, loc
);
1739 add_stmt (return_stmt
);
1742 /* Helper function for playback::block::add_switch.
1743 Construct a case label for the given range, followed by a goto stmt
1744 to the given block, appending them to stmt list *ptr_t_switch_body. */
1747 add_case (tree
*ptr_t_switch_body
,
1750 playback::block
*dest_block
)
1752 tree t_label
= create_artificial_label (UNKNOWN_LOCATION
);
1753 DECL_CONTEXT (t_label
) = dest_block
->get_function ()->as_fndecl ();
1756 build_case_label (t_low_value
, t_high_value
, t_label
);
1757 append_to_statement_list (t_case_label
, ptr_t_switch_body
);
1760 build1 (GOTO_EXPR
, void_type_node
, dest_block
->as_label_decl ());
1761 append_to_statement_list (t_goto_stmt
, ptr_t_switch_body
);
1764 /* Add a switch statement to the function's statement list.
1766 We create a switch body, and populate it with case labels, each
1767 followed by a goto to the desired block. */
1771 add_switch (location
*loc
,
1773 block
*default_block
,
1774 const auto_vec
<case_
> *cases
)
1777 - c/c-typeck.c: c_start_case
1778 - c-family/c-common.c:c_add_case_label
1779 - java/expr.c:expand_java_switch and expand_java_add_case
1780 We've already rejected overlaps and duplicates in
1781 libgccjit.c:case_range_validator::validate. */
1783 tree t_expr
= expr
->as_tree ();
1784 tree t_type
= TREE_TYPE (t_expr
);
1786 tree t_switch_body
= alloc_stmt_list ();
1790 FOR_EACH_VEC_ELT (*cases
, i
, c
)
1792 tree t_low_value
= c
->m_min_value
->as_tree ();
1793 tree t_high_value
= c
->m_max_value
->as_tree ();
1794 add_case (&t_switch_body
, t_low_value
, t_high_value
, c
->m_dest_block
);
1796 /* Default label. */
1797 add_case (&t_switch_body
, NULL_TREE
, NULL_TREE
, default_block
);
1799 tree switch_stmt
= build2 (SWITCH_EXPR
, t_type
, t_expr
, t_switch_body
);
1801 set_tree_location (switch_stmt
, loc
);
1802 add_stmt (switch_stmt
);
1805 /* Constructor for gcc::jit::playback::block. */
1808 block (function
*func
,
1818 identifier
= get_identifier (name
);
1821 m_label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1822 identifier
, void_type_node
);
1823 DECL_CONTEXT (m_label_decl
) = func
->as_fndecl ();
1824 m_label_expr
= NULL
;
1827 /* Compile a playback::context:
1829 - Use the context's options to cconstruct command-line options, and
1830 call into the rest of GCC (toplev::main).
1831 - Assuming it succeeds, we have a .s file.
1832 - We then run the "postprocess" vfunc:
1834 (A) In-memory compile ("gcc_jit_context_compile")
1836 For an in-memory compile we have the playback::compile_to_memory
1837 subclass; "postprocess" will convert the .s file to a .so DSO,
1838 and load it in memory (via dlopen), wrapping the result up as
1839 a jit::result and returning it.
1841 (B) Compile to file ("gcc_jit_context_compile_to_file")
1843 When compiling to a file, we have the playback::compile_to_file
1844 subclass; "postprocess" will either copy the .s file to the
1845 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1846 the driver to convert it as necessary, copying the result. */
1852 JIT_LOG_SCOPE (get_logger ());
1854 const char *ctxt_progname
;
1856 int keep_intermediates
=
1857 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
);
1859 m_tempdir
= new tempdir (get_logger (), keep_intermediates
);
1860 if (!m_tempdir
->create ())
1863 /* Call into the rest of gcc.
1864 For now, we have to assemble command-line options to pass into
1865 toplev::main, so that they can be parsed. */
1867 /* Pass in user-provided program name as argv0, if any, so that it
1868 makes it into GCC's "progname" global, used in various diagnostics. */
1869 ctxt_progname
= get_str_option (GCC_JIT_STR_OPTION_PROGNAME
);
1872 ctxt_progname
= "libgccjit.so";
1874 auto_vec
<recording::requested_dump
> requested_dumps
;
1875 m_recording_ctxt
->get_all_requested_dumps (&requested_dumps
);
1877 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1880 auto_string_vec fake_args
;
1881 make_fake_args (&fake_args
, ctxt_progname
, &requested_dumps
);
1882 if (errors_occurred ())
1888 /* This runs the compiler. */
1889 toplev
toplev (get_timer (), /* external_timer */
1890 false); /* init_signals */
1891 enter_scope ("toplev::main");
1893 for (unsigned i
= 0; i
< fake_args
.length (); i
++)
1894 get_logger ()->log ("argv[%i]: %s", i
, fake_args
[i
]);
1895 toplev
.main (fake_args
.length (),
1896 const_cast <char **> (fake_args
.address ()));
1897 exit_scope ("toplev::main");
1899 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1900 need to do it between toplev::main (which creates the dump manager)
1901 and toplev::finalize (which deletes it). */
1902 extract_any_requested_dumps (&requested_dumps
);
1904 /* Clean up the compiler. */
1905 enter_scope ("toplev::finalize");
1907 exit_scope ("toplev::finalize");
1909 /* Ideally we would release the jit mutex here, but we can't yet since
1910 followup activities use timevars, which are global state. */
1912 if (errors_occurred ())
1918 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
))
1919 dump_generated_code ();
1921 /* We now have a .s file.
1923 Run any postprocessing steps. This will either convert the .s file to
1924 a .so DSO, and load it in memory (playback::compile_to_memory), or
1925 convert the .s file to the requested output format, and copy it to a
1926 given file (playback::compile_to_file). */
1927 postprocess (ctxt_progname
);
1932 /* Implementation of class gcc::jit::playback::compile_to_memory,
1933 a subclass of gcc::jit::playback::context. */
1935 /* playback::compile_to_memory's trivial constructor. */
1937 playback::compile_to_memory::compile_to_memory (recording::context
*ctxt
) :
1938 playback::context (ctxt
),
1941 JIT_LOG_SCOPE (get_logger ());
1944 /* Implementation of the playback::context::process vfunc for compiling
1947 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1948 wrapping the result up as a jit::result and returning it. */
1951 playback::compile_to_memory::postprocess (const char *ctxt_progname
)
1953 JIT_LOG_SCOPE (get_logger ());
1954 convert_to_dso (ctxt_progname
);
1955 if (errors_occurred ())
1957 m_result
= dlopen_built_dso ();
1960 /* Implementation of class gcc::jit::playback::compile_to_file,
1961 a subclass of gcc::jit::playback::context. */
1963 /* playback::compile_to_file's trivial constructor. */
1965 playback::compile_to_file::compile_to_file (recording::context
*ctxt
,
1966 enum gcc_jit_output_kind output_kind
,
1967 const char *output_path
) :
1968 playback::context (ctxt
),
1969 m_output_kind (output_kind
),
1970 m_output_path (output_path
)
1972 JIT_LOG_SCOPE (get_logger ());
1975 /* Implementation of the playback::context::process vfunc for compiling
1978 Either copy the .s file to the given destination (for
1979 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1980 as necessary, copying the result. */
1983 playback::compile_to_file::postprocess (const char *ctxt_progname
)
1985 JIT_LOG_SCOPE (get_logger ());
1987 /* The driver takes different actions based on the filename, so
1988 we provide a filename with an appropriate suffix for the
1989 output kind, and then copy it up to the user-provided path,
1990 rather than directly compiling it to the requested output path. */
1992 switch (m_output_kind
)
1997 case GCC_JIT_OUTPUT_KIND_ASSEMBLER
:
1998 copy_file (get_tempdir ()->get_path_s_file (),
2000 /* The .s file is automatically unlinked by tempdir::~tempdir. */
2003 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE
:
2005 char *tmp_o_path
= ::concat (get_tempdir ()->get_path (),
2008 invoke_driver (ctxt_progname
,
2009 get_tempdir ()->get_path_s_file (),
2012 false, /* bool shared, */
2013 false);/* bool run_linker */
2014 if (!errors_occurred ())
2016 copy_file (tmp_o_path
,
2018 get_tempdir ()->add_temp_file (tmp_o_path
);
2025 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY
:
2026 invoke_driver (ctxt_progname
,
2027 get_tempdir ()->get_path_s_file (),
2028 get_tempdir ()->get_path_so_file (),
2030 true, /* bool shared, */
2031 true);/* bool run_linker */
2032 if (!errors_occurred ())
2033 copy_file (get_tempdir ()->get_path_so_file (),
2035 /* The .so file is automatically unlinked by tempdir::~tempdir. */
2038 case GCC_JIT_OUTPUT_KIND_EXECUTABLE
:
2040 char *tmp_exe_path
= ::concat (get_tempdir ()->get_path (),
2043 invoke_driver (ctxt_progname
,
2044 get_tempdir ()->get_path_s_file (),
2047 false, /* bool shared, */
2048 true);/* bool run_linker */
2049 if (!errors_occurred ())
2051 copy_file (tmp_exe_path
,
2053 get_tempdir ()->add_temp_file (tmp_exe_path
);
2056 free (tmp_exe_path
);
2064 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2065 the "executable" bits).
2067 Any errors that occur are reported on the context and hence count as
2068 a failure of the compile.
2070 We can't in general hardlink or use "rename" from the tempdir since
2071 it might be on a different filesystem to the destination. For example,
2072 I get EXDEV: "Invalid cross-device link". */
2075 playback::compile_to_file::copy_file (const char *src_path
,
2076 const char *dst_path
)
2078 JIT_LOG_SCOPE (get_logger ());
2081 get_logger ()->log ("src_path: %s", src_path
);
2082 get_logger ()->log ("dst_path: %s", dst_path
);
2087 size_t total_sz_in
= 0;
2088 size_t total_sz_out
= 0;
2091 struct stat stat_buf
;
2093 f_in
= fopen (src_path
, "rb");
2097 "unable to open %s for reading: %s",
2103 /* Use stat on the filedescriptor to get the mode,
2104 so that we can copy it over (in particular, the
2105 "executable" bits). */
2106 if (fstat (fileno (f_in
), &stat_buf
) == -1)
2109 "unable to fstat %s: %s",
2116 f_out
= fopen (dst_path
, "wb");
2120 "unable to open %s for writing: %s",
2127 while ( (sz_in
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2129 total_sz_in
+= sz_in
;
2130 size_t sz_out_remaining
= sz_in
;
2131 size_t sz_out_so_far
= 0;
2132 while (sz_out_remaining
)
2134 size_t sz_out
= fwrite (buf
+ sz_out_so_far
,
2138 gcc_assert (sz_out
<= sz_out_remaining
);
2142 "error writing to %s: %s",
2149 total_sz_out
+= sz_out
;
2150 sz_out_so_far
+= sz_out
;
2151 sz_out_remaining
-= sz_out
;
2153 gcc_assert (sz_out_so_far
== sz_in
);
2158 "error reading from %s: %s",
2164 gcc_assert (total_sz_in
== total_sz_out
);
2166 get_logger ()->log ("total bytes copied: %zu", total_sz_out
);
2168 /* fchmod does not exist in Windows. */
2170 /* Set the permissions of the copy to those of the original file,
2171 in particular the "executable" bits. */
2172 if (fchmod (fileno (f_out
), stat_buf
.st_mode
) == -1)
2174 "error setting mode of %s: %s",
2182 /* Helper functions for gcc::jit::playback::context::compile. */
2184 /* This mutex guards gcc::jit::recording::context::compile, so that only
2185 one thread can be accessing the bulk of GCC's state at once. */
2187 static pthread_mutex_t jit_mutex
= PTHREAD_MUTEX_INITIALIZER
;
2189 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2192 playback::context::acquire_mutex ()
2194 auto_timevar
tv (get_timer (), TV_JIT_ACQUIRING_MUTEX
);
2196 /* Acquire the big GCC mutex. */
2197 JIT_LOG_SCOPE (get_logger ());
2198 pthread_mutex_lock (&jit_mutex
);
2199 gcc_assert (active_playback_ctxt
== NULL
);
2200 active_playback_ctxt
= this;
2203 /* Release jit_mutex and clear the active playback ctxt. */
2206 playback::context::release_mutex ()
2208 /* Release the big GCC mutex. */
2209 JIT_LOG_SCOPE (get_logger ());
2210 gcc_assert (active_playback_ctxt
== this);
2211 active_playback_ctxt
= NULL
;
2212 pthread_mutex_unlock (&jit_mutex
);
2215 /* Callback used by gcc::jit::playback::context::make_fake_args when
2216 invoking driver_get_configure_time_options.
2217 Populate a vec <char * > with the configure-time options. */
2220 append_arg_from_driver (const char *option
, void *user_data
)
2222 gcc_assert (option
);
2223 gcc_assert (user_data
);
2224 vec
<char *> *argvec
= static_cast <vec
<char *> *> (user_data
);
2225 argvec
->safe_push (concat ("-", option
, NULL
));
2228 /* Build a fake argv for toplev::main from the options set
2229 by the user on the context . */
2233 make_fake_args (vec
<char *> *argvec
,
2234 const char *ctxt_progname
,
2235 vec
<recording::requested_dump
> *requested_dumps
)
2237 JIT_LOG_SCOPE (get_logger ());
2239 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2240 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2242 ADD_ARG (ctxt_progname
);
2243 ADD_ARG (get_path_c_file ());
2246 /* Handle int options: */
2247 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
))
2251 "unrecognized optimization level: %i",
2252 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
));
2271 /* What about -Os? */
2273 /* Handle bool options: */
2274 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2277 /* Suppress timing (and other) info. */
2278 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
))
2284 /* Aggressively garbage-collect, to shake out bugs: */
2285 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC
))
2287 ADD_ARG ("--param=ggc-min-expand=0");
2288 ADD_ARG ("--param=ggc-min-heapsize=0");
2291 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
))
2293 ADD_ARG ("-fdump-tree-all");
2294 ADD_ARG ("-fdump-rtl-all");
2295 ADD_ARG ("-fdump-ipa-all");
2298 /* Add "-fdump-" options for any calls to
2299 gcc_jit_context_enable_dump. */
2302 recording::requested_dump
*d
;
2303 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2305 char *arg
= concat ("-fdump-", d
->m_dumpname
, NULL
);
2306 ADD_ARG_TAKE_OWNERSHIP (arg
);
2310 /* PR jit/64810: Add any target-specific default options
2311 from OPTION_DEFAULT_SPECS, normally provided by the driver
2312 in the non-jit case.
2314 The target-specific code can define OPTION_DEFAULT_SPECS:
2315 default command options in the form of spec macros for the
2316 driver to expand ().
2318 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2319 if not overriden, injects the defaults as extra arguments to
2321 For the jit case, we need to add these arguments here. The
2322 input format (using the specs language) means that we have to run
2323 part of the driver code here (driver_get_configure_time_options).
2325 To avoid running the spec-expansion code every time, we just do
2326 it the first time (via a function-static flag), saving the result
2327 into a function-static vec.
2328 This flag and vec are global state (i.e. per-process).
2329 They are guarded by the jit mutex. */
2331 static bool have_configure_time_options
= false;
2332 static vec
<char *> configure_time_options
;
2334 if (have_configure_time_options
)
2335 log ("reusing cached configure-time options");
2338 have_configure_time_options
= true;
2339 log ("getting configure-time options from driver");
2340 driver_get_configure_time_options (append_arg_from_driver
,
2341 &configure_time_options
);
2348 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2349 log ("configure_time_options[%i]: %s", i
, opt
);
2351 /* configure_time_options should now contain the expanded options
2352 from OPTION_DEFAULT_SPECS (if any). */
2353 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2356 gcc_assert (opt
[0] == '-');
2362 ADD_ARG ("-ftime-report");
2364 /* Add any user-provided extra options, starting with any from
2366 m_recording_ctxt
->append_command_line_options (argvec
);
2369 #undef ADD_ARG_TAKE_OWNERSHIP
2372 /* The second half of the implementation of gcc_jit_context_enable_dump.
2373 Iterate through the requested dumps, reading the underlying files
2374 into heap-allocated buffers, writing pointers to the buffers into
2375 the char ** pointers provided by client code.
2376 Client code is responsible for calling free on the results. */
2380 extract_any_requested_dumps (vec
<recording::requested_dump
> *requested_dumps
)
2382 JIT_LOG_SCOPE (get_logger ());
2385 recording::requested_dump
*d
;
2386 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2388 dump_file_info
*dfi
;
2392 dfi
= g
->get_dumps ()->get_dump_file_info_by_switch (d
->m_dumpname
);
2395 add_error (NULL
, "unrecognized dump: %s", d
->m_dumpname
);
2399 filename
= g
->get_dumps ()->get_dump_file_name (dfi
);
2400 content
= read_dump_file (filename
);
2401 *(d
->m_out_ptr
) = content
;
2402 m_tempdir
->add_temp_file (filename
);
2406 /* Helper function for playback::context::extract_any_requested_dumps
2407 (itself for use in implementation of gcc_jit_context_enable_dump).
2409 Attempt to read the complete file at the given path, returning the
2410 bytes found there as a buffer.
2411 The caller is responsible for calling free on the result.
2412 Errors will be reported on the context, and lead to NULL being
2413 returned; an out-of-memory error will terminate the process. */
2416 playback::context::read_dump_file (const char *path
)
2418 char *result
= NULL
;
2419 size_t total_sz
= 0;
2424 f_in
= fopen (path
, "r");
2427 add_error (NULL
, "unable to open %s for reading", path
);
2431 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2433 size_t old_total_sz
= total_sz
;
2435 result
= reinterpret_cast <char *> (xrealloc (result
, total_sz
+ 1));
2436 memcpy (result
+ old_total_sz
, buf
, sz
);
2441 add_error (NULL
, "error reading from %s", path
);
2451 result
[total_sz
] = '\0';
2455 return xstrdup ("");
2458 /* Part of playback::context::compile ().
2460 We have a .s file; we want a .so file.
2461 We could reuse parts of gcc/gcc.c to do this.
2462 For now, just use the driver binary from the install, as
2463 named in gcc-driver-name.h
2464 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2468 convert_to_dso (const char *ctxt_progname
)
2470 JIT_LOG_SCOPE (get_logger ());
2472 invoke_driver (ctxt_progname
,
2473 m_tempdir
->get_path_s_file (),
2474 m_tempdir
->get_path_so_file (),
2476 true, /* bool shared, */
2477 true);/* bool run_linker */
2480 static const char * const gcc_driver_name
= GCC_DRIVER_NAME
;
2484 invoke_driver (const char *ctxt_progname
,
2485 const char *input_file
,
2486 const char *output_file
,
2491 JIT_LOG_SCOPE (get_logger ());
2493 bool embedded_driver
2494 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER
);
2496 /* Currently this lumps together both assembling and linking into
2498 auto_timevar
assemble_timevar (get_timer (), tv_id
);
2499 auto_string_vec argvec
;
2500 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2502 ADD_ARG (gcc_driver_name
);
2504 add_multilib_driver_arguments (&argvec
);
2507 ADD_ARG ("-shared");
2512 ADD_ARG (input_file
);
2514 ADD_ARG (output_file
);
2516 /* Don't use the linker plugin.
2517 If running with just a "make" and not a "make install", then we'd
2519 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2520 libto_plugin is a .la at build time, with it becoming installed with
2521 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2523 ADD_ARG ("-fno-use-linker-plugin");
2525 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2526 /* OS X's linker defaults to treating undefined symbols as errors.
2527 If the context has any imported functions or globals they will be
2528 undefined until the .so is dynamically-linked into the process.
2529 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2531 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2537 /* Add any user-provided driver extra options. */
2539 m_recording_ctxt
->append_driver_options (&argvec
);
2543 /* pex_one's error-handling requires pname to be non-NULL. */
2544 gcc_assert (ctxt_progname
);
2547 for (unsigned i
= 0; i
< argvec
.length (); i
++)
2548 get_logger ()->log ("argv[%i]: %s", i
, argvec
[i
]);
2550 if (embedded_driver
)
2551 invoke_embedded_driver (&argvec
);
2553 invoke_external_driver (ctxt_progname
, &argvec
);
2558 invoke_embedded_driver (const vec
<char *> *argvec
)
2560 JIT_LOG_SCOPE (get_logger ());
2561 driver
d (true, /* can_finalize */
2563 int result
= d
.main (argvec
->length (),
2564 const_cast <char **> (argvec
->address ()));
2567 add_error (NULL
, "error invoking gcc driver");
2572 invoke_external_driver (const char *ctxt_progname
,
2573 vec
<char *> *argvec
)
2575 JIT_LOG_SCOPE (get_logger ());
2577 int exit_status
= 0;
2580 /* pex argv arrays are NULL-terminated. */
2581 argvec
->safe_push (NULL
);
2583 errmsg
= pex_one (PEX_SEARCH
, /* int flags, */
2585 const_cast <char *const *> (argvec
->address ()),
2586 ctxt_progname
, /* const char *pname */
2587 NULL
, /* const char *outname */
2588 NULL
, /* const char *errname */
2589 &exit_status
, /* int *status */
2590 &err
); /* int *err*/
2593 add_error (NULL
, "error invoking gcc driver: %s", errmsg
);
2597 /* pex_one can return a NULL errmsg when the executable wasn't
2598 found (or doesn't exist), so trap these cases also. */
2599 if (exit_status
|| err
)
2602 "error invoking gcc driver: exit_status: %i err: %i",
2605 "whilst attempting to run a driver named: %s",
2614 /* Extract the target-specific MULTILIB_DEFAULTS to
2615 multilib_defaults_raw for use by
2616 playback::context::add_multilib_driver_arguments (). */
2618 #ifndef MULTILIB_DEFAULTS
2619 #define MULTILIB_DEFAULTS { "" }
2622 static const char *const multilib_defaults_raw
[] = MULTILIB_DEFAULTS
;
2624 /* Helper function for playback::context::invoke_driver ().
2626 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2627 a driver binary. We need to pass in options to the shared driver
2628 to get the appropriate assembler/linker options for this multilib
2633 add_multilib_driver_arguments (vec
<char *> *argvec
)
2635 JIT_LOG_SCOPE (get_logger ());
2637 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2638 prepending each with a "-". */
2639 for (size_t i
= 0; i
< ARRAY_SIZE (multilib_defaults_raw
); i
++)
2640 if (multilib_defaults_raw
[i
][0])
2641 argvec
->safe_push (concat ("-", multilib_defaults_raw
[i
], NULL
));
2644 /* Dynamically-link the built DSO file into this process, using dlopen.
2645 Wrap it up within a jit::result *, and return that.
2646 Return NULL if any errors occur, reporting them on this context. */
2652 JIT_LOG_SCOPE (get_logger ());
2653 auto_timevar
load_timevar (get_timer (), TV_LOAD
);
2654 result::handle handle
= NULL
;
2655 result
*result_obj
= NULL
;
2658 /* Clear any existing error. */
2661 handle
= LoadLibrary(m_tempdir
->get_path_so_file ());
2662 if (GetLastError() != 0) {
2666 const char *error
= NULL
;
2667 /* Clear any existing error. */
2670 handle
= dlopen (m_tempdir
->get_path_so_file (),
2671 RTLD_NOW
| RTLD_LOCAL
);
2672 if ((error
= dlerror()) != NULL
) {
2673 add_error (NULL
, "%s", error
);
2679 /* We've successfully dlopened the result; create a
2680 jit::result object to wrap it.
2682 We're done with the tempdir for now, but if the user
2683 has requested debugging, the user's debugger might not
2684 be capable of dealing with the .so file being unlinked
2685 immediately, so keep it around until after the result
2686 is released. We do this by handing over ownership of
2687 the jit::tempdir to the result. See PR jit/64206. */
2688 tempdir
*handover_tempdir
;
2689 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2691 handover_tempdir
= m_tempdir
;
2693 /* The tempdir will eventually be cleaned up in the
2694 jit::result's dtor. */
2695 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2696 " handing over tempdir to jit::result");
2700 handover_tempdir
= NULL
;
2701 /* ... and retain ownership of m_tempdir so we clean it
2702 up it the playback::context's dtor. */
2703 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2704 " retaining ownership of tempdir");
2707 result_obj
= new result (get_logger (), handle
, handover_tempdir
);
2715 /* Top-level hook for playing back a recording context.
2717 This plays back m_recording_ctxt, and, if no errors
2718 occurred builds statement lists for and then postprocesses
2719 every function in the result. */
2725 JIT_LOG_SCOPE (get_logger ());
2728 = build_pointer_type (build_qualified_type (char_type_node
,
2731 /* Replay the recorded events: */
2732 timevar_push (TV_JIT_REPLAY
);
2734 m_recording_ctxt
->replay_into (this);
2736 /* Clean away the temporary references from recording objects
2737 to playback objects. We have to do this now since the
2738 latter are GC-allocated, but the former don't mark these
2739 refs. Hence we must stop using them before the GC can run. */
2740 m_recording_ctxt
->disassociate_from_playback ();
2742 /* The builtins_manager, if any, is associated with the recording::context
2743 and might be reused for future compiles on other playback::contexts,
2744 but its m_attributes array is not GTY-labeled and hence will become
2745 nonsense if the GC runs. Purge this state. */
2746 builtins_manager
*bm
= get_builtins_manager ();
2748 bm
->finish_playback ();
2750 timevar_pop (TV_JIT_REPLAY
);
2752 if (!errors_occurred ())
2757 /* No GC can happen yet; process the cached source locations. */
2758 handle_locations ();
2760 /* We've now created tree nodes for the stmts in the various blocks
2761 in each function, but we haven't built each function's single stmt
2762 list yet. Do so now. */
2763 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2764 func
->build_stmt_list ();
2766 /* No GC can have happened yet. */
2768 /* Postprocess the functions. This could trigger GC. */
2769 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2772 func
->postprocess ();
2777 /* Dump the generated .s file to stderr. */
2781 dump_generated_code ()
2783 JIT_LOG_SCOPE (get_logger ());
2786 FILE *f_in
= fopen (get_path_s_file (), "r");
2790 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2791 fwrite (buf
, 1, sz
, stderr
);
2796 /* Get the supposed path of the notional "fake.c" file within the
2797 tempdir. This file doesn't exist, but the rest of the compiler
2802 get_path_c_file () const
2804 return m_tempdir
->get_path_c_file ();
2807 /* Get the path of the assembler output file "fake.s" file within the
2812 get_path_s_file () const
2814 return m_tempdir
->get_path_s_file ();
2817 /* Get the path of the DSO object file "fake.so" file within the
2822 get_path_so_file () const
2824 return m_tempdir
->get_path_so_file ();
2827 /* qsort comparator for comparing pairs of playback::source_line *,
2828 ordering them by line number. */
2831 line_comparator (const void *lhs
, const void *rhs
)
2833 const playback::source_line
*line_lhs
= \
2834 *static_cast<const playback::source_line
* const*> (lhs
);
2835 const playback::source_line
*line_rhs
= \
2836 *static_cast<const playback::source_line
* const*> (rhs
);
2837 return line_lhs
->get_line_num () - line_rhs
->get_line_num ();
2840 /* qsort comparator for comparing pairs of playback::location *,
2841 ordering them by column number. */
2844 location_comparator (const void *lhs
, const void *rhs
)
2846 const playback::location
*loc_lhs
= \
2847 *static_cast<const playback::location
* const *> (lhs
);
2848 const playback::location
*loc_rhs
= \
2849 *static_cast<const playback::location
* const *> (rhs
);
2850 return loc_lhs
->get_column_num () - loc_rhs
->get_column_num ();
2853 /* Our API allows locations to be created in arbitrary orders, but the
2854 linemap API requires locations to be created in ascending order
2855 as if we were tokenizing files.
2857 This hook sorts all of the locations that have been created, and
2858 calls into the linemap API, creating linemap entries in sorted order
2859 for our locations. */
2865 /* Create the source code locations, following the ordering rules
2866 imposed by the linemap API.
2868 line_table is a global. */
2869 JIT_LOG_SCOPE (get_logger ());
2873 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2875 linemap_add (line_table
, LC_ENTER
, false, file
->get_filename (), 0);
2877 /* Sort lines by ascending line numbers. */
2878 file
->m_source_lines
.qsort (&line_comparator
);
2882 FOR_EACH_VEC_ELT (file
->m_source_lines
, j
, line
)
2887 /* Sort locations in line by ascending column numbers. */
2888 line
->m_locations
.qsort (&location_comparator
);
2890 /* Determine maximum column within this line. */
2891 gcc_assert (line
->m_locations
.length () > 0);
2892 location
*final_column
=
2893 line
->m_locations
[line
->m_locations
.length () - 1];
2894 int max_col
= final_column
->get_column_num ();
2896 linemap_line_start (line_table
, line
->get_line_num (), max_col
);
2897 FOR_EACH_VEC_ELT (line
->m_locations
, k
, loc
)
2900 linemap_position_for_column (line_table
, loc
->get_column_num ());
2904 linemap_add (line_table
, LC_LEAVE
, false, NULL
, 0);
2907 /* line_table should now be populated; every playback::location should
2908 now have an m_srcloc. */
2910 /* Now assign them to tree nodes as appropriate. */
2911 std::pair
<tree
, location
*> *cached_location
;
2913 FOR_EACH_VEC_ELT (m_cached_locations
, i
, cached_location
)
2915 tree t
= cached_location
->first
;
2916 location_t srcloc
= cached_location
->second
->m_srcloc
;
2918 /* This covers expressions: */
2919 if (CAN_HAVE_LOCATION_P (t
))
2920 SET_EXPR_LOCATION (t
, srcloc
);
2921 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t
), TS_DECL_MINIMAL
))
2922 DECL_SOURCE_LOCATION (t
) = srcloc
;
2925 /* Don't know how to set location on this node. */
2930 /* We handle errors on a playback::context by adding them to the
2931 corresponding recording::context. */
2935 add_error (location
*loc
, const char *fmt
, ...)
2939 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2944 /* We handle errors on a playback::context by adding them to the
2945 corresponding recording::context. */
2949 add_error_va (location
*loc
, const char *fmt
, va_list ap
)
2951 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2955 /* Report a diagnostic up to the jit context as an error,
2956 so that the compilation is treated as a failure.
2957 For now, any kind of diagnostic is treated as an error by the jit
2962 add_diagnostic (struct diagnostic_context
*diag_context
,
2963 struct diagnostic_info
*diagnostic
)
2965 /* At this point the text has been formatted into the pretty-printer's
2967 pretty_printer
*pp
= diag_context
->printer
;
2968 const char *text
= pp_formatted_text (pp
);
2970 /* Get location information (if any) from the diagnostic.
2971 The recording::context::add_error[_va] methods require a
2972 recording::location. We can't lookup the playback::location
2973 from the file/line/column since any playback location instances
2974 may have been garbage-collected away by now, so instead we create
2975 another recording::location directly. */
2976 location_t gcc_loc
= diagnostic_location (diagnostic
);
2977 recording::location
*rec_loc
= NULL
;
2980 expanded_location exploc
= expand_location (gcc_loc
);
2982 rec_loc
= m_recording_ctxt
->new_location (exploc
.file
,
2988 m_recording_ctxt
->add_error (rec_loc
, "%s", text
);
2989 pp_clear_output_area (pp
);
2992 /* Dealing with the linemap API. */
2994 /* Construct a playback::location for a recording::location, if it
2995 doesn't exist already. */
2997 playback::location
*
2999 new_location (recording::location
*rloc
,
3000 const char *filename
,
3004 /* Get the source_file for filename, creating if necessary. */
3005 source_file
*src_file
= get_source_file (filename
);
3006 /* Likewise for the line within the file. */
3007 source_line
*src_line
= src_file
->get_source_line (line
);
3008 /* Likewise for the column within the line. */
3009 location
*loc
= src_line
->get_location (rloc
, column
);
3013 /* Deferred setting of the location for a given tree, by adding the
3014 (tree, playback::location) pair to a list of deferred associations.
3015 We will actually set the location on the tree later on once
3016 the location_t for the playback::location exists. */
3020 set_tree_location (tree t
, location
*loc
)
3023 m_cached_locations
.safe_push (std::make_pair (t
, loc
));
3027 /* Construct a playback::source_file for the given source
3028 filename, if it doesn't exist already. */
3030 playback::source_file
*
3032 get_source_file (const char *filename
)
3035 For simplicitly, this is currently a linear search.
3036 Replace with a hash if this shows up in the profile. */
3039 tree ident_filename
= get_identifier (filename
);
3041 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
3042 if (file
->filename_as_tree () == ident_filename
)
3046 file
= new source_file (ident_filename
);
3047 m_source_files
.safe_push (file
);
3051 /* Constructor for gcc::jit::playback::source_file. */
3053 playback::source_file::source_file (tree filename
) :
3055 m_filename (filename
)
3059 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3063 playback::source_file::finalizer ()
3065 m_source_lines
.release ();
3068 /* Construct a playback::source_line for the given line
3069 within this source file, if one doesn't exist already. */
3071 playback::source_line
*
3072 playback::source_file::
3073 get_source_line (int line_num
)
3076 For simplicitly, this is currently a linear search.
3077 Replace with a hash if this shows up in the profile. */
3081 FOR_EACH_VEC_ELT (m_source_lines
, i
, line
)
3082 if (line
->get_line_num () == line_num
)
3086 line
= new source_line (this, line_num
);
3087 m_source_lines
.safe_push (line
);
3091 /* Constructor for gcc::jit::playback::source_line. */
3093 playback::source_line::source_line (source_file
*file
, int line_num
) :
3095 m_source_file (file
),
3096 m_line_num (line_num
)
3100 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3104 playback::source_line::finalizer ()
3106 m_locations
.release ();
3109 /* Construct a playback::location for the given column
3110 within this line of a specific source file, if one doesn't exist
3113 playback::location
*
3114 playback::source_line::
3115 get_location (recording::location
*rloc
, int column_num
)
3120 /* Another linear search that probably should be a hash table. */
3121 FOR_EACH_VEC_ELT (m_locations
, i
, loc
)
3122 if (loc
->get_column_num () == column_num
)
3126 loc
= new location (rloc
, this, column_num
);
3127 m_locations
.safe_push (loc
);
3131 /* Constructor for gcc::jit::playback::location. */
3133 playback::location::location (recording::location
*loc
,
3136 m_srcloc (UNKNOWN_LOCATION
),
3137 m_recording_loc (loc
),
3139 m_column_num(column_num
)
3143 /* The active gcc::jit::playback::context instance. This is a singleton,
3144 guarded by jit_mutex. */
3146 playback::context
*active_playback_ctxt
;
3148 } // namespace gcc::jit