1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2015 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 "statistics.h"
31 #include "tree-core.h"
38 #include "hard-reg-set.h"
47 #include "stringpool.h"
48 #include "stor-layout.h"
49 #include "print-tree.h"
51 #include "gcc-driver-name.h"
54 #include "fold-const.h"
58 #include "jit-common.h"
59 #include "jit-logging.h"
60 #include "jit-playback.h"
61 #include "jit-result.h"
62 #include "jit-builtins.h"
63 #include "jit-tempdir.h"
66 /* gcc::jit::playback::context::build_cast uses the convert.h API,
67 which in turn requires the frontend to provide a "convert"
68 function, apparently as a fallback.
70 Hence we provide this dummy one, with the requirement that any casts
71 are handled before reaching this. */
72 extern tree
convert (tree type
, tree expr
);
75 convert (tree dst_type
, tree expr
)
77 gcc_assert (gcc::jit::active_playback_ctxt
);
78 gcc::jit::active_playback_ctxt
->add_error (NULL
, "unhandled conversion");
79 fprintf (stderr
, "input expression:\n");
81 fprintf (stderr
, "requested type:\n");
82 debug_tree (dst_type
);
83 return error_mark_node
;
89 /**********************************************************************
91 **********************************************************************/
93 /* The constructor for gcc::jit::playback::context. */
95 playback::context::context (recording::context
*ctxt
)
96 : log_user (ctxt
->get_logger ()),
97 m_recording_ctxt (ctxt
),
99 m_char_array_type_node (NULL
),
100 m_const_char_ptr (NULL
)
102 JIT_LOG_SCOPE (get_logger ());
103 m_functions
.create (0);
104 m_globals
.create (0);
105 m_source_files
.create (0);
106 m_cached_locations
.create (0);
109 /* The destructor for gcc::jit::playback::context. */
111 playback::context::~context ()
113 JIT_LOG_SCOPE (get_logger ());
115 /* Normally the playback::context is responsible for cleaning up the
116 tempdir (including "fake.so" within the filesystem).
118 In the normal case, clean it up now.
120 However m_tempdir can be NULL if the context has handed over
121 responsibility for the tempdir cleanup to the jit::result object, so
122 that the cleanup can be delayed (see PR jit/64206). If that's the
123 case this "delete NULL;" is a no-op. */
126 m_functions
.release ();
129 /* A playback::context can reference GC-managed pointers. Mark them
130 ("by hand", rather than by gengtype).
132 This is called on the active playback context (if any) by the
133 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
141 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
143 if (ggc_test_and_set_mark (func
))
148 /* Given an enum gcc_jit_types value, get a "tree" type. */
151 get_tree_node_for_type (enum gcc_jit_types type_
)
155 case GCC_JIT_TYPE_VOID
:
156 return void_type_node
;
158 case GCC_JIT_TYPE_VOID_PTR
:
159 return ptr_type_node
;
161 case GCC_JIT_TYPE_BOOL
:
162 return boolean_type_node
;
164 case GCC_JIT_TYPE_CHAR
:
165 return char_type_node
;
166 case GCC_JIT_TYPE_SIGNED_CHAR
:
167 return signed_char_type_node
;
168 case GCC_JIT_TYPE_UNSIGNED_CHAR
:
169 return unsigned_char_type_node
;
171 case GCC_JIT_TYPE_SHORT
:
172 return short_integer_type_node
;
173 case GCC_JIT_TYPE_UNSIGNED_SHORT
:
174 return short_unsigned_type_node
;
176 case GCC_JIT_TYPE_CONST_CHAR_PTR
:
178 tree const_char
= build_qualified_type (char_type_node
,
180 return build_pointer_type (const_char
);
183 case GCC_JIT_TYPE_INT
:
184 return integer_type_node
;
185 case GCC_JIT_TYPE_UNSIGNED_INT
:
186 return unsigned_type_node
;
188 case GCC_JIT_TYPE_LONG
:
189 return long_integer_type_node
;
190 case GCC_JIT_TYPE_UNSIGNED_LONG
:
191 return long_unsigned_type_node
;
193 case GCC_JIT_TYPE_LONG_LONG
:
194 return long_long_integer_type_node
;
195 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG
:
196 return long_long_unsigned_type_node
;
198 case GCC_JIT_TYPE_FLOAT
:
199 return float_type_node
;
200 case GCC_JIT_TYPE_DOUBLE
:
201 return double_type_node
;
202 case GCC_JIT_TYPE_LONG_DOUBLE
:
203 return long_double_type_node
;
205 case GCC_JIT_TYPE_SIZE_T
:
206 return size_type_node
;
208 case GCC_JIT_TYPE_FILE_PTR
:
209 return fileptr_type_node
;
211 case GCC_JIT_TYPE_COMPLEX_FLOAT
:
212 return complex_float_type_node
;
213 case GCC_JIT_TYPE_COMPLEX_DOUBLE
:
214 return complex_double_type_node
;
215 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE
:
216 return complex_long_double_type_node
;
222 /* Construct a playback::type instance (wrapping a tree) for the given
227 get_type (enum gcc_jit_types type_
)
229 tree type_node
= get_tree_node_for_type (type_
);
230 if (NULL
== type_node
)
233 "unrecognized (enum gcc_jit_types) value: %i", type_
);
237 return new type (type_node
);
240 /* Construct a playback::type instance (wrapping a tree) for the given
245 new_array_type (playback::location
*loc
,
246 playback::type
*element_type
,
249 gcc_assert (element_type
);
251 tree t
= build_array_type_nelts (element_type
->as_tree (),
256 set_tree_location (t
, loc
);
261 /* Construct a playback::field instance (wrapping a tree). */
265 new_field (location
*loc
,
272 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
273 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
274 get_identifier (name
), type
->as_tree ());
277 set_tree_location (decl
, loc
);
279 return new field (decl
);
282 /* Construct a playback::compound_type instance (wrapping a tree). */
284 playback::compound_type
*
286 new_compound_type (location
*loc
,
288 bool is_struct
) /* else is union */
292 /* Compare with c/c-decl.c: start_struct. */
294 tree t
= make_node (is_struct
? RECORD_TYPE
: UNION_TYPE
);
295 TYPE_NAME (t
) = get_identifier (name
);
299 set_tree_location (t
, loc
);
301 return new compound_type (t
);
305 playback::compound_type::set_fields (const auto_vec
<playback::field
*> *fields
)
307 /* Compare with c/c-decl.c: finish_struct. */
310 tree fieldlist
= NULL
;
311 for (unsigned i
= 0; i
< fields
->length (); i
++)
313 field
*f
= (*fields
)[i
];
314 DECL_CONTEXT (f
->as_tree ()) = t
;
315 fieldlist
= chainon (f
->as_tree (), fieldlist
);
317 fieldlist
= nreverse (fieldlist
);
318 TYPE_FIELDS (t
) = fieldlist
;
323 /* Construct a playback::type instance (wrapping a tree) for a function
328 new_function_type (type
*return_type
,
329 const auto_vec
<type
*> *param_types
,
335 tree
*arg_types
= (tree
*)xcalloc(param_types
->length (), sizeof(tree
*));
337 FOR_EACH_VEC_ELT (*param_types
, i
, param_type
)
338 arg_types
[i
] = param_type
->as_tree ();
343 build_varargs_function_type_array (return_type
->as_tree (),
344 param_types
->length (),
347 fn_type
= build_function_type_array (return_type
->as_tree (),
348 param_types
->length (),
352 return new type (fn_type
);
355 /* Construct a playback::param instance (wrapping a tree). */
359 new_param (location
*loc
,
365 tree inner
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
366 get_identifier (name
), type
->as_tree ());
368 set_tree_location (inner
, loc
);
370 return new param (this, inner
);
373 /* Construct a playback::function instance. */
377 new_function (location
*loc
,
378 enum gcc_jit_function_kind kind
,
381 const auto_vec
<param
*> *params
,
383 enum built_in_function builtin_id
)
388 //can return_type be NULL?
391 tree
*arg_types
= (tree
*)xcalloc(params
->length (), sizeof(tree
*));
392 FOR_EACH_VEC_ELT (*params
, i
, param
)
393 arg_types
[i
] = TREE_TYPE (param
->as_tree ());
397 fn_type
= build_varargs_function_type_array (return_type
->as_tree (),
398 params
->length (), arg_types
);
400 fn_type
= build_function_type_array (return_type
->as_tree (),
401 params
->length (), arg_types
);
404 /* FIXME: this uses input_location: */
405 tree fndecl
= build_fn_decl (name
, fn_type
);
408 set_tree_location (fndecl
, loc
);
410 tree resdecl
= build_decl (UNKNOWN_LOCATION
, RESULT_DECL
,
411 NULL_TREE
, return_type
->as_tree ());
412 DECL_ARTIFICIAL (resdecl
) = 1;
413 DECL_IGNORED_P (resdecl
) = 1;
414 DECL_RESULT (fndecl
) = resdecl
;
418 DECL_FUNCTION_CODE (fndecl
) = builtin_id
;
419 gcc_assert (loc
== NULL
);
420 DECL_SOURCE_LOCATION (fndecl
) = BUILTINS_LOCATION
;
422 DECL_BUILT_IN_CLASS (fndecl
) =
423 builtins_manager::get_class (builtin_id
);
424 set_builtin_decl (builtin_id
, fndecl
,
425 builtins_manager::implicit_p (builtin_id
));
427 builtins_manager
*bm
= get_builtins_manager ();
428 tree attrs
= bm
->get_attrs_tree (builtin_id
);
430 decl_attributes (&fndecl
, attrs
, ATTR_FLAG_BUILT_IN
);
432 decl_attributes (&fndecl
, NULL_TREE
, 0);
435 if (kind
!= GCC_JIT_FUNCTION_IMPORTED
)
437 tree param_decl_list
= NULL
;
438 FOR_EACH_VEC_ELT (*params
, i
, param
)
440 param_decl_list
= chainon (param
->as_tree (), param_decl_list
);
443 /* The param list was created in reverse order; fix it: */
444 param_decl_list
= nreverse (param_decl_list
);
447 for (t
= param_decl_list
; t
; t
= DECL_CHAIN (t
))
449 DECL_CONTEXT (t
) = fndecl
;
450 DECL_ARG_TYPE (t
) = TREE_TYPE (t
);
453 /* Set it up on DECL_ARGUMENTS */
454 DECL_ARGUMENTS(fndecl
) = param_decl_list
;
457 if (kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
459 DECL_DECLARED_INLINE_P (fndecl
) = 1;
461 /* Add attribute "always_inline": */
462 DECL_ATTRIBUTES (fndecl
) =
463 tree_cons (get_identifier ("always_inline"),
465 DECL_ATTRIBUTES (fndecl
));
468 function
*func
= new function (this, fndecl
, kind
);
469 m_functions
.safe_push (func
);
473 /* Construct a playback::lvalue instance (wrapping a tree). */
477 new_global (location
*loc
,
478 enum gcc_jit_global_kind kind
,
484 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
485 get_identifier (name
),
487 TREE_PUBLIC (inner
) = (kind
!= GCC_JIT_GLOBAL_INTERNAL
);
488 DECL_COMMON (inner
) = 1;
494 case GCC_JIT_GLOBAL_EXPORTED
:
495 TREE_STATIC (inner
) = 1;
498 case GCC_JIT_GLOBAL_INTERNAL
:
499 TREE_STATIC (inner
) = 1;
502 case GCC_JIT_GLOBAL_IMPORTED
:
503 DECL_EXTERNAL (inner
) = 1;
508 set_tree_location (inner
, loc
);
510 varpool_node::get_create (inner
);
512 varpool_node::finalize_decl (inner
);
514 m_globals
.safe_push (inner
);
516 return new lvalue (this, inner
);
519 /* Implementation of the various
520 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
522 Each of these constructs a playback::rvalue instance (wrapping a tree).
524 These specializations are required to be in the same namespace
525 as the template, hence we now have to enter the gcc::jit::playback
531 /* Specialization of making an rvalue from a const, for host <int>. */
536 new_rvalue_from_const
<int> (type
*type
,
539 // FIXME: type-checking, or coercion?
540 tree inner_type
= type
->as_tree ();
541 if (INTEGRAL_TYPE_P (inner_type
))
543 tree inner
= build_int_cst (inner_type
, value
);
544 return new rvalue (this, inner
);
548 REAL_VALUE_TYPE real_value
;
549 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
550 tree inner
= build_real (inner_type
, real_value
);
551 return new rvalue (this, inner
);
555 /* Specialization of making an rvalue from a const, for host <long>. */
560 new_rvalue_from_const
<long> (type
*type
,
563 // FIXME: type-checking, or coercion?
564 tree inner_type
= type
->as_tree ();
565 if (INTEGRAL_TYPE_P (inner_type
))
567 tree inner
= build_int_cst (inner_type
, value
);
568 return new rvalue (this, inner
);
572 REAL_VALUE_TYPE real_value
;
573 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
574 tree inner
= build_real (inner_type
, real_value
);
575 return new rvalue (this, inner
);
579 /* Specialization of making an rvalue from a const, for host <double>. */
584 new_rvalue_from_const
<double> (type
*type
,
587 // FIXME: type-checking, or coercion?
588 tree inner_type
= type
->as_tree ();
590 /* We have a "double", we want a REAL_VALUE_TYPE.
592 real.c:real_from_target appears to require the representation to be
593 split into 32-bit values, and then sent as an pair of host long
595 REAL_VALUE_TYPE real_value
;
599 uint32_t as_uint32s
[2];
602 long int as_long_ints
[2];
603 as_long_ints
[0] = u
.as_uint32s
[0];
604 as_long_ints
[1] = u
.as_uint32s
[1];
605 real_from_target (&real_value
, as_long_ints
, DFmode
);
606 tree inner
= build_real (inner_type
, real_value
);
607 return new rvalue (this, inner
);
610 /* Specialization of making an rvalue from a const, for host <void *>. */
615 new_rvalue_from_const
<void *> (type
*type
,
618 tree inner_type
= type
->as_tree ();
619 /* FIXME: how to ensure we have a wide enough type? */
620 tree inner
= build_int_cstu (inner_type
, (unsigned HOST_WIDE_INT
)value
);
621 return new rvalue (this, inner
);
624 /* We're done implementing the specializations of
625 gcc::jit::playback::context::new_rvalue_from_const <T>
626 so we can exit the gcc::jit::playback namespace. */
628 } // namespace playback
630 /* Construct a playback::rvalue instance (wrapping a tree). */
634 new_string_literal (const char *value
)
636 tree t_str
= build_string (strlen (value
), value
);
637 gcc_assert (m_char_array_type_node
);
638 TREE_TYPE (t_str
) = m_char_array_type_node
;
640 /* Convert to (const char*), loosely based on
641 c/c-typeck.c: array_to_pointer_conversion,
642 by taking address of start of string. */
643 tree t_addr
= build1 (ADDR_EXPR
, m_const_char_ptr
, t_str
);
645 return new rvalue (this, t_addr
);
648 /* Coerce a tree expression into a boolean tree expression. */
652 as_truth_value (tree expr
, location
*loc
)
654 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
655 tree typed_zero
= fold_build1 (CONVERT_EXPR
,
659 set_tree_location (typed_zero
, loc
);
661 expr
= build2 (NE_EXPR
, integer_type_node
, expr
, typed_zero
);
663 set_tree_location (expr
, loc
);
668 /* Construct a playback::rvalue instance (wrapping a tree) for a
673 new_unary_op (location
*loc
,
674 enum gcc_jit_unary_op op
,
678 // FIXME: type-checking, or coercion?
679 enum tree_code inner_op
;
681 gcc_assert (result_type
);
684 tree node
= a
->as_tree ();
685 tree inner_result
= NULL
;
690 add_error (loc
, "unrecognized (enum gcc_jit_unary_op) value: %i", op
);
693 case GCC_JIT_UNARY_OP_MINUS
:
694 inner_op
= NEGATE_EXPR
;
697 case GCC_JIT_UNARY_OP_BITWISE_NEGATE
:
698 inner_op
= BIT_NOT_EXPR
;
701 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE
:
702 node
= as_truth_value (node
, loc
);
703 inner_result
= invert_truthvalue (node
);
705 set_tree_location (inner_result
, loc
);
706 return new rvalue (this, inner_result
);
708 case GCC_JIT_UNARY_OP_ABS
:
713 inner_result
= build1 (inner_op
,
714 result_type
->as_tree (),
717 set_tree_location (inner_result
, loc
);
719 return new rvalue (this, inner_result
);
722 /* Construct a playback::rvalue instance (wrapping a tree) for a
727 new_binary_op (location
*loc
,
728 enum gcc_jit_binary_op op
,
730 rvalue
*a
, rvalue
*b
)
732 // FIXME: type-checking, or coercion?
733 enum tree_code inner_op
;
735 gcc_assert (result_type
);
739 tree node_a
= a
->as_tree ();
740 tree node_b
= b
->as_tree ();
745 add_error (loc
, "unrecognized (enum gcc_jit_binary_op) value: %i", op
);
748 case GCC_JIT_BINARY_OP_PLUS
:
749 inner_op
= PLUS_EXPR
;
752 case GCC_JIT_BINARY_OP_MINUS
:
753 inner_op
= MINUS_EXPR
;
756 case GCC_JIT_BINARY_OP_MULT
:
757 inner_op
= MULT_EXPR
;
760 case GCC_JIT_BINARY_OP_DIVIDE
:
761 if (FLOAT_TYPE_P (result_type
->as_tree ()))
762 /* Floating-point division: */
763 inner_op
= RDIV_EXPR
;
765 /* Truncating to zero: */
766 inner_op
= TRUNC_DIV_EXPR
;
769 case GCC_JIT_BINARY_OP_MODULO
:
770 inner_op
= TRUNC_MOD_EXPR
;
773 case GCC_JIT_BINARY_OP_BITWISE_AND
:
774 inner_op
= BIT_AND_EXPR
;
777 case GCC_JIT_BINARY_OP_BITWISE_XOR
:
778 inner_op
= BIT_XOR_EXPR
;
781 case GCC_JIT_BINARY_OP_BITWISE_OR
:
782 inner_op
= BIT_IOR_EXPR
;
785 case GCC_JIT_BINARY_OP_LOGICAL_AND
:
786 node_a
= as_truth_value (node_a
, loc
);
787 node_b
= as_truth_value (node_b
, loc
);
788 inner_op
= TRUTH_ANDIF_EXPR
;
791 case GCC_JIT_BINARY_OP_LOGICAL_OR
:
792 node_a
= as_truth_value (node_a
, loc
);
793 node_b
= as_truth_value (node_b
, loc
);
794 inner_op
= TRUTH_ORIF_EXPR
;
797 case GCC_JIT_BINARY_OP_LSHIFT
:
798 inner_op
= LSHIFT_EXPR
;
801 case GCC_JIT_BINARY_OP_RSHIFT
:
802 inner_op
= RSHIFT_EXPR
;
806 tree inner_expr
= build2 (inner_op
,
807 result_type
->as_tree (),
811 set_tree_location (inner_expr
, loc
);
813 return new rvalue (this, inner_expr
);
816 /* Construct a playback::rvalue instance (wrapping a tree) for a
821 new_comparison (location
*loc
,
822 enum gcc_jit_comparison op
,
823 rvalue
*a
, rvalue
*b
)
825 // FIXME: type-checking, or coercion?
826 enum tree_code inner_op
;
834 add_error (loc
, "unrecognized (enum gcc_jit_comparison) value: %i", op
);
837 case GCC_JIT_COMPARISON_EQ
:
840 case GCC_JIT_COMPARISON_NE
:
843 case GCC_JIT_COMPARISON_LT
:
846 case GCC_JIT_COMPARISON_LE
:
849 case GCC_JIT_COMPARISON_GT
:
852 case GCC_JIT_COMPARISON_GE
:
857 tree inner_expr
= build2 (inner_op
,
862 set_tree_location (inner_expr
, loc
);
863 return new rvalue (this, inner_expr
);
866 /* Construct a playback::rvalue instance (wrapping a tree) for a
871 build_call (location
*loc
,
873 const auto_vec
<rvalue
*> *args
)
875 vec
<tree
, va_gc
> *tree_args
;
876 vec_alloc (tree_args
, args
->length ());
877 for (unsigned i
= 0; i
< args
->length (); i
++)
878 tree_args
->quick_push ((*args
)[i
]->as_tree ());
881 set_tree_location (fn_ptr
, loc
);
883 tree fn
= TREE_TYPE (fn_ptr
);
884 tree fn_type
= TREE_TYPE (fn
);
885 tree return_type
= TREE_TYPE (fn_type
);
887 return new rvalue (this,
888 build_call_vec (return_type
,
891 /* see c-typeck.c: build_function_call
892 which calls build_function_call_vec
894 which does lots of checking, then:
895 result = build_call_array_loc (loc, TREE_TYPE (fntype),
896 function, nargs, argarray);
898 (see also build_call_vec)
902 /* Construct a playback::rvalue instance (wrapping a tree) for a
903 call to a specific function. */
907 new_call (location
*loc
,
909 const auto_vec
<rvalue
*> *args
)
915 fndecl
= func
->as_fndecl ();
917 tree fntype
= TREE_TYPE (fndecl
);
919 tree fn
= build1 (ADDR_EXPR
, build_pointer_type (fntype
), fndecl
);
921 return build_call (loc
, fn
, args
);
924 /* Construct a playback::rvalue instance (wrapping a tree) for a
925 call through a function pointer. */
929 new_call_through_ptr (location
*loc
,
931 const auto_vec
<rvalue
*> *args
)
934 tree t_fn_ptr
= fn_ptr
->as_tree ();
936 return build_call (loc
, t_fn_ptr
, args
);
939 /* Construct a tree for a cast. */
942 playback::context::build_cast (playback::location
*loc
,
943 playback::rvalue
*expr
,
944 playback::type
*type_
)
946 /* For comparison, see:
947 - c/c-typeck.c:build_c_cast
948 - c/c-convert.c: convert
951 Only some kinds of cast are currently supported here. */
952 tree t_expr
= expr
->as_tree ();
953 tree t_dst_type
= type_
->as_tree ();
955 t_ret
= targetm
.convert_to_type (t_dst_type
, t_expr
);
958 enum tree_code dst_code
= TREE_CODE (t_dst_type
);
963 t_ret
= convert_to_integer (t_dst_type
, t_expr
);
967 /* Compare with c_objc_common_truthvalue_conversion and
968 c_common_truthvalue_conversion. */
969 /* For now, convert to: (t_expr != 0) */
970 t_ret
= build2 (NE_EXPR
, t_dst_type
,
972 build_int_cst (TREE_TYPE (t_expr
), 0));
976 t_ret
= convert_to_real (t_dst_type
, t_expr
);
980 t_ret
= build1 (NOP_EXPR
, t_dst_type
, t_expr
);
984 add_error (loc
, "couldn't handle cast during playback");
985 fprintf (stderr
, "input expression:\n");
987 fprintf (stderr
, "requested type:\n");
988 debug_tree (t_dst_type
);
989 return error_mark_node
;
992 if (TREE_CODE (t_ret
) != C_MAYBE_CONST_EXPR
)
993 t_ret
= fold (t_ret
);
998 /* Construct a playback::rvalue instance (wrapping a tree) for a
1003 new_cast (playback::location
*loc
,
1004 playback::rvalue
*expr
,
1005 playback::type
*type_
)
1008 tree t_cast
= build_cast (loc
, expr
, type_
);
1010 set_tree_location (t_cast
, loc
);
1011 return new rvalue (this, t_cast
);
1014 /* Construct a playback::lvalue instance (wrapping a tree) for an
1019 new_array_access (location
*loc
,
1026 /* For comparison, see:
1027 c/c-typeck.c: build_array_ref
1028 c-family/c-common.c: pointer_int_sum
1030 tree t_ptr
= ptr
->as_tree ();
1031 tree t_index
= index
->as_tree ();
1032 tree t_type_ptr
= TREE_TYPE (t_ptr
);
1033 tree t_type_star_ptr
= TREE_TYPE (t_type_ptr
);
1035 if (TREE_CODE (t_type_ptr
) == ARRAY_TYPE
)
1037 tree t_result
= build4 (ARRAY_REF
, t_type_star_ptr
, t_ptr
, t_index
,
1038 NULL_TREE
, NULL_TREE
);
1040 set_tree_location (t_result
, loc
);
1041 return new lvalue (this, t_result
);
1045 /* Convert index to an offset in bytes. */
1046 tree t_sizeof
= size_in_bytes (t_type_star_ptr
);
1047 t_index
= fold_build1 (CONVERT_EXPR
, sizetype
, t_index
);
1048 tree t_offset
= build2 (MULT_EXPR
, sizetype
, t_index
, t_sizeof
);
1050 /* Locate (ptr + offset). */
1051 tree t_address
= build2 (POINTER_PLUS_EXPR
, t_type_ptr
, t_ptr
, t_offset
);
1053 tree t_indirection
= build1 (INDIRECT_REF
, t_type_star_ptr
, t_address
);
1056 set_tree_location (t_sizeof
, loc
);
1057 set_tree_location (t_offset
, loc
);
1058 set_tree_location (t_address
, loc
);
1059 set_tree_location (t_indirection
, loc
);
1062 return new lvalue (this, t_indirection
);
1066 /* Construct a tree for a field access. */
1070 new_field_access (location
*loc
,
1077 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1078 build_component_ref. */
1079 tree type
= TREE_TYPE (datum
);
1081 gcc_assert (TREE_CODE (type
) != POINTER_TYPE
);
1083 tree t_field
= field
->as_tree ();
1084 tree ref
= build3 (COMPONENT_REF
, TREE_TYPE (t_field
), datum
,
1085 t_field
, NULL_TREE
);
1087 set_tree_location (ref
, loc
);
1091 /* Construct a tree for a dereference. */
1095 new_dereference (tree ptr
,
1100 tree type
= TREE_TYPE (TREE_TYPE(ptr
));
1101 tree datum
= build1 (INDIRECT_REF
, type
, ptr
);
1103 set_tree_location (datum
, loc
);
1107 /* Construct a playback::lvalue instance (wrapping a tree) for a
1112 access_field (location
*loc
,
1115 tree datum
= as_tree ();
1116 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1119 return new lvalue (get_context (), ref
);
1122 /* Construct a playback::rvalue instance (wrapping a tree) for a
1127 access_field (location
*loc
,
1130 tree datum
= as_tree ();
1131 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1134 return new rvalue (get_context (), ref
);
1137 /* Construct a playback::lvalue instance (wrapping a tree) for a
1138 dereferenced field access. */
1142 dereference_field (location
*loc
,
1145 tree ptr
= as_tree ();
1146 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1149 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1152 return new lvalue (get_context (), ref
);
1155 /* Construct a playback::lvalue instance (wrapping a tree) for a
1160 dereference (location
*loc
)
1162 tree ptr
= as_tree ();
1163 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1164 return new lvalue (get_context (), datum
);
1167 /* Mark EXP saying that we need to be able to take the
1168 address of it; it should not be allocated in a register.
1169 Compare with e.g. c/c-typeck.c: c_mark_addressable. */
1172 jit_mark_addressable (tree exp
)
1177 switch (TREE_CODE (x
))
1180 /* (we don't yet support bitfields) */
1186 x
= TREE_OPERAND (x
, 0);
1189 case COMPOUND_LITERAL_EXPR
:
1191 TREE_ADDRESSABLE (x
) = 1;
1198 /* (we don't have a concept of a "register" declaration) */
1201 TREE_ADDRESSABLE (x
) = 1;
1208 /* Construct a playback::rvalue instance (wrapping a tree) for an
1213 get_address (location
*loc
)
1215 tree t_lvalue
= as_tree ();
1216 tree t_thistype
= TREE_TYPE (t_lvalue
);
1217 tree t_ptrtype
= build_pointer_type (t_thistype
);
1218 tree ptr
= build1 (ADDR_EXPR
, t_ptrtype
, t_lvalue
);
1220 get_context ()->set_tree_location (ptr
, loc
);
1221 jit_mark_addressable (t_lvalue
);
1222 return new rvalue (get_context (), ptr
);
1225 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1226 Provide this finalization hook for calling then they are collected,
1227 which calls the finalizer vfunc. This allows them to call "release"
1228 on any vec<> within them. */
1231 wrapper_finalizer (void *ptr
)
1233 playback::wrapper
*wrapper
= reinterpret_cast <playback::wrapper
*> (ptr
);
1234 wrapper
->finalizer ();
1237 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1238 allocate them using ggc_internal_cleared_alloc. */
1242 operator new (size_t sz
)
1244 return ggc_internal_cleared_alloc (sz
, wrapper_finalizer
, 0, 1);
1248 /* Constructor for gcc:jit::playback::function. */
1250 playback::function::
1251 function (context
*ctxt
,
1253 enum gcc_jit_function_kind kind
)
1255 m_inner_fndecl (fndecl
),
1256 m_inner_bind_expr (NULL
),
1259 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1261 /* Create a BIND_EXPR, and within it, a statement list. */
1262 m_stmt_list
= alloc_stmt_list ();
1263 m_stmt_iter
= tsi_start (m_stmt_list
);
1264 m_inner_block
= make_node (BLOCK
);
1266 build3 (BIND_EXPR
, void_type_node
, NULL
, m_stmt_list
, m_inner_block
);
1270 m_inner_block
= NULL
;
1275 /* Hand-written GC-marking hook for playback functions. */
1278 playback::function::
1281 gt_ggc_m_9tree_node (m_inner_fndecl
);
1282 gt_ggc_m_9tree_node (m_inner_bind_expr
);
1283 gt_ggc_m_9tree_node (m_stmt_list
);
1284 gt_ggc_m_9tree_node (m_inner_block
);
1287 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1291 playback::function::finalizer ()
1293 m_blocks
.release ();
1296 /* Get the return type of a playback function, in tree form. */
1299 playback::function::
1300 get_return_type_as_tree () const
1302 return TREE_TYPE (TREE_TYPE(m_inner_fndecl
));
1305 /* Construct a new local within this playback::function. */
1308 playback::function::
1309 new_local (location
*loc
,
1315 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
1316 get_identifier (name
),
1318 DECL_CONTEXT (inner
) = this->m_inner_fndecl
;
1320 /* Prepend to BIND_EXPR_VARS: */
1321 DECL_CHAIN (inner
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1322 BIND_EXPR_VARS (m_inner_bind_expr
) = inner
;
1325 set_tree_location (inner
, loc
);
1326 return new lvalue (m_ctxt
, inner
);
1329 /* Construct a new block within this playback::function. */
1332 playback::function::
1333 new_block (const char *name
)
1335 gcc_assert (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
);
1337 block
*result
= new playback::block (this, name
);
1338 m_blocks
.safe_push (result
);
1342 /* Build a statement list for the function as a whole out of the
1343 lists of statements for the individual blocks, building labels
1347 playback::function::
1353 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1355 FOR_EACH_VEC_ELT (m_blocks
, i
, b
)
1360 b
->m_label_expr
= build1 (LABEL_EXPR
,
1362 b
->as_label_decl ());
1363 tsi_link_after (&m_stmt_iter
, b
->m_label_expr
, TSI_CONTINUE_LINKING
);
1365 FOR_EACH_VEC_ELT (b
->m_stmts
, j
, stmt
)
1366 tsi_link_after (&m_stmt_iter
, stmt
, TSI_CONTINUE_LINKING
);
1370 /* Finish compiling the given function, potentially running the
1372 The function will have a statement list by now.
1373 Amongst other things, this gimplifies the statement list,
1374 and calls cgraph_node::finalize_function on the function. */
1377 playback::function::
1380 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1382 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
))
1383 debug_tree (m_stmt_list
);
1385 /* Do we need this to force cgraphunit.c to output the function? */
1386 if (m_kind
== GCC_JIT_FUNCTION_EXPORTED
)
1388 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1389 DECL_PRESERVE_P (m_inner_fndecl
) = 1;
1392 if (m_kind
== GCC_JIT_FUNCTION_INTERNAL
1393 ||m_kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
1395 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1396 TREE_PUBLIC (m_inner_fndecl
) = 0;
1399 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1401 /* Seem to need this in gimple-low.c: */
1402 gcc_assert (m_inner_block
);
1403 DECL_INITIAL (m_inner_fndecl
) = m_inner_block
;
1405 /* how to add to function? the following appears to be how to
1406 set the body of a m_inner_fndecl: */
1407 DECL_SAVED_TREE(m_inner_fndecl
) = m_inner_bind_expr
;
1409 /* Ensure that locals appear in the debuginfo. */
1410 BLOCK_VARS (m_inner_block
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1412 //debug_tree (m_inner_fndecl);
1414 /* Convert to gimple: */
1415 //printf("about to gimplify_function_tree\n");
1416 gimplify_function_tree (m_inner_fndecl
);
1417 //printf("finished gimplify_function_tree\n");
1419 current_function_decl
= m_inner_fndecl
;
1420 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
))
1421 dump_function_to_file (m_inner_fndecl
, stderr
, TDF_VOPS
|TDF_MEMSYMS
|TDF_LINENO
);
1422 //debug_tree (m_inner_fndecl);
1424 //printf("about to add to cgraph\n");
1425 /* Add to cgraph: */
1426 cgraph_node::finalize_function (m_inner_fndecl
, false);
1427 /* This can trigger a collection, so we need to have all of
1428 the funcs as roots. */
1430 current_function_decl
= NULL
;
1434 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1438 playback::block::finalizer ()
1443 /* Add an eval of the rvalue to the function's statement list. */
1447 add_eval (location
*loc
,
1450 gcc_assert (rvalue
);
1453 set_tree_location (rvalue
->as_tree (), loc
);
1455 add_stmt (rvalue
->as_tree ());
1458 /* Add an assignment to the function's statement list. */
1462 add_assignment (location
*loc
,
1466 gcc_assert (lvalue
);
1467 gcc_assert (rvalue
);
1469 tree t_lvalue
= lvalue
->as_tree ();
1470 tree t_rvalue
= rvalue
->as_tree ();
1471 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1473 t_rvalue
= build1 (CONVERT_EXPR
,
1474 TREE_TYPE (t_lvalue
),
1477 set_tree_location (t_rvalue
, loc
);
1481 build2 (MODIFY_EXPR
, TREE_TYPE (t_lvalue
),
1482 t_lvalue
, t_rvalue
);
1484 set_tree_location (stmt
, loc
);
1488 /* Add a comment to the function's statement list.
1489 For now this is done by adding a dummy label. */
1493 add_comment (location
*loc
,
1496 /* Wrap the text in C-style comment delimiters. */
1498 (3 /* opening delim */
1500 + 3 /* closing delim */
1501 + 1 /* terminator */);
1502 char *wrapped
= (char *)ggc_internal_alloc (sz
);
1503 snprintf (wrapped
, sz
, "/* %s */", text
);
1505 /* For now we simply implement this by adding a dummy label with a name
1506 containing the given text. */
1507 tree identifier
= get_identifier (wrapped
);
1508 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1509 identifier
, void_type_node
);
1510 DECL_CONTEXT (label_decl
) = m_func
->as_fndecl ();
1512 tree label_expr
= build1 (LABEL_EXPR
, void_type_node
, label_decl
);
1514 set_tree_location (label_expr
, loc
);
1515 add_stmt (label_expr
);
1518 /* Add a conditional jump statement to the function's statement list. */
1522 add_conditional (location
*loc
,
1527 gcc_assert (boolval
);
1528 gcc_assert (on_true
);
1529 gcc_assert (on_false
);
1531 /* COND_EXPR wants statement lists for the true/false operands, but we
1533 Shim it by creating jumps to the labels */
1534 tree true_jump
= build1 (GOTO_EXPR
, void_type_node
,
1535 on_true
->as_label_decl ());
1537 set_tree_location (true_jump
, loc
);
1539 tree false_jump
= build1 (GOTO_EXPR
, void_type_node
,
1540 on_false
->as_label_decl ());
1542 set_tree_location (false_jump
, loc
);
1545 build3 (COND_EXPR
, void_type_node
, boolval
->as_tree (),
1546 true_jump
, false_jump
);
1548 set_tree_location (stmt
, loc
);
1552 /* Add an unconditional jump statement to the function's statement list. */
1556 add_jump (location
*loc
,
1559 gcc_assert (target
);
1561 // see c_finish_loop
1562 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1565 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1566 TREE_USED (target
->as_label_decl ()) = 1;
1567 tree stmt
= build1 (GOTO_EXPR
, void_type_node
, target
->as_label_decl ());
1569 set_tree_location (stmt
, loc
);
1575 c_finish_goto_label (location_t loc, tree label)
1577 tree decl = lookup_label_for_goto (loc, label);
1580 TREE_USED (decl) = 1;
1582 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1583 SET_EXPR_LOCATION (t, loc);
1584 return add_stmt (t);
1591 /* Add a return statement to the function's statement list. */
1595 add_return (location
*loc
,
1598 tree modify_retval
= NULL
;
1599 tree return_type
= m_func
->get_return_type_as_tree ();
1602 tree t_lvalue
= DECL_RESULT (m_func
->as_fndecl ());
1603 tree t_rvalue
= rvalue
->as_tree ();
1604 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1605 t_rvalue
= build1 (CONVERT_EXPR
,
1606 TREE_TYPE (t_lvalue
),
1608 modify_retval
= build2 (MODIFY_EXPR
, return_type
,
1609 t_lvalue
, t_rvalue
);
1611 set_tree_location (modify_retval
, loc
);
1613 tree return_stmt
= build1 (RETURN_EXPR
, return_type
,
1616 set_tree_location (return_stmt
, loc
);
1618 add_stmt (return_stmt
);
1621 /* Helper function for playback::block::add_switch.
1622 Construct a case label for the given range, followed by a goto stmt
1623 to the given block, appending them to stmt list *ptr_t_switch_body. */
1626 add_case (tree
*ptr_t_switch_body
,
1629 playback::block
*dest_block
)
1631 tree t_label
= create_artificial_label (UNKNOWN_LOCATION
);
1632 DECL_CONTEXT (t_label
) = dest_block
->get_function ()->as_fndecl ();
1635 build_case_label (t_low_value
, t_high_value
, t_label
);
1636 append_to_statement_list (t_case_label
, ptr_t_switch_body
);
1639 build1 (GOTO_EXPR
, void_type_node
, dest_block
->as_label_decl ());
1640 append_to_statement_list (t_goto_stmt
, ptr_t_switch_body
);
1643 /* Add a switch statement to the function's statement list.
1645 My initial attempt at implementing this constructed a TREE_VEC
1646 of the cases and set it as SWITCH_LABELS (switch_expr). However,
1647 gimplify.c:gimplify_switch_expr is set up to deal with SWITCH_BODY, and
1648 doesn't have any logic for gimplifying SWITCH_LABELS.
1650 Hence we create a switch body, and populate it with case labels, each
1651 followed by a goto to the desired block. */
1655 add_switch (location
*loc
,
1657 block
*default_block
,
1658 const auto_vec
<case_
> *cases
)
1661 - c/c-typeck.c: c_start_case
1662 - c-family/c-common.c:c_add_case_label
1663 - java/expr.c:expand_java_switch and expand_java_add_case
1664 We've already rejected overlaps and duplicates in
1665 libgccjit.c:case_range_validator::validate. */
1667 tree t_expr
= expr
->as_tree ();
1668 tree t_type
= TREE_TYPE (t_expr
);
1670 tree t_switch_body
= alloc_stmt_list ();
1674 FOR_EACH_VEC_ELT (*cases
, i
, c
)
1676 tree t_low_value
= c
->m_min_value
->as_tree ();
1677 tree t_high_value
= c
->m_max_value
->as_tree ();
1678 add_case (&t_switch_body
,
1683 /* Default label. */
1684 add_case (&t_switch_body
,
1685 NULL_TREE
, NULL_TREE
,
1688 tree switch_stmt
= build3 (SWITCH_EXPR
, t_type
, t_expr
,
1689 t_switch_body
, NULL_TREE
);
1691 set_tree_location (switch_stmt
, loc
);
1692 add_stmt (switch_stmt
);
1695 /* Constructor for gcc::jit::playback::block. */
1698 block (function
*func
,
1708 identifier
= get_identifier (name
);
1711 m_label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1712 identifier
, void_type_node
);
1713 DECL_CONTEXT (m_label_decl
) = func
->as_fndecl ();
1714 m_label_expr
= NULL
;
1717 /* A subclass of auto_vec <char *> that frees all of its elements on
1720 class auto_argvec
: public auto_vec
<char *>
1726 /* auto_argvec's dtor, freeing all contained strings, automatically
1727 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1729 auto_argvec::~auto_argvec ()
1733 FOR_EACH_VEC_ELT (*this, i
, str
)
1737 /* Compile a playback::context:
1739 - Use the context's options to cconstruct command-line options, and
1740 call into the rest of GCC (toplev::main).
1741 - Assuming it succeeds, we have a .s file.
1742 - We then run the "postprocess" vfunc:
1744 (A) In-memory compile ("gcc_jit_context_compile")
1746 For an in-memory compile we have the playback::compile_to_memory
1747 subclass; "postprocess" will convert the .s file to a .so DSO,
1748 and load it in memory (via dlopen), wrapping the result up as
1749 a jit::result and returning it.
1751 (B) Compile to file ("gcc_jit_context_compile_to_file")
1753 When compiling to a file, we have the playback::compile_to_file
1754 subclass; "postprocess" will either copy the .s file to the
1755 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1756 the driver to convert it as necessary, copying the result. */
1762 JIT_LOG_SCOPE (get_logger ());
1764 const char *ctxt_progname
;
1766 int keep_intermediates
=
1767 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
);
1769 m_tempdir
= new tempdir (get_logger (), keep_intermediates
);
1770 if (!m_tempdir
->create ())
1773 /* Call into the rest of gcc.
1774 For now, we have to assemble command-line options to pass into
1775 toplev::main, so that they can be parsed. */
1777 /* Pass in user-provided program name as argv0, if any, so that it
1778 makes it into GCC's "progname" global, used in various diagnostics. */
1779 ctxt_progname
= get_str_option (GCC_JIT_STR_OPTION_PROGNAME
);
1782 ctxt_progname
= "libgccjit.so";
1784 auto_vec
<recording::requested_dump
> requested_dumps
;
1785 m_recording_ctxt
->get_all_requested_dumps (&requested_dumps
);
1787 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1790 auto_argvec fake_args
;
1791 make_fake_args (&fake_args
, ctxt_progname
, &requested_dumps
);
1792 if (errors_occurred ())
1798 /* This runs the compiler. */
1799 toplev
toplev (false, /* use_TV_TOTAL */
1800 false); /* init_signals */
1801 enter_scope ("toplev::main");
1803 for (unsigned i
= 0; i
< fake_args
.length (); i
++)
1804 get_logger ()->log ("argv[%i]: %s", i
, fake_args
[i
]);
1805 toplev
.main (fake_args
.length (),
1806 const_cast <char **> (fake_args
.address ()));
1807 exit_scope ("toplev::main");
1809 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1810 need to do it between toplev::main (which creates the dump manager)
1811 and toplev::finalize (which deletes it). */
1812 extract_any_requested_dumps (&requested_dumps
);
1814 /* Clean up the compiler. */
1815 enter_scope ("toplev::finalize");
1817 exit_scope ("toplev::finalize");
1819 /* Ideally we would release the jit mutex here, but we can't yet since
1820 followup activities use timevars, which are global state. */
1822 if (errors_occurred ())
1828 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
))
1829 dump_generated_code ();
1831 /* We now have a .s file.
1833 Run any postprocessing steps. This will either convert the .s file to
1834 a .so DSO, and load it in memory (playback::compile_to_memory), or
1835 convert the .s file to the requested output format, and copy it to a
1836 given file (playback::compile_to_file). */
1837 postprocess (ctxt_progname
);
1842 /* Implementation of class gcc::jit::playback::compile_to_memory,
1843 a subclass of gcc::jit::playback::context. */
1845 /* playback::compile_to_memory's trivial constructor. */
1847 playback::compile_to_memory::compile_to_memory (recording::context
*ctxt
) :
1848 playback::context (ctxt
),
1851 JIT_LOG_SCOPE (get_logger ());
1854 /* Implementation of the playback::context::process vfunc for compiling
1857 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1858 wrapping the result up as a jit::result and returning it. */
1861 playback::compile_to_memory::postprocess (const char *ctxt_progname
)
1863 JIT_LOG_SCOPE (get_logger ());
1864 convert_to_dso (ctxt_progname
);
1865 if (errors_occurred ())
1867 m_result
= dlopen_built_dso ();
1870 /* Implementation of class gcc::jit::playback::compile_to_file,
1871 a subclass of gcc::jit::playback::context. */
1873 /* playback::compile_to_file's trivial constructor. */
1875 playback::compile_to_file::compile_to_file (recording::context
*ctxt
,
1876 enum gcc_jit_output_kind output_kind
,
1877 const char *output_path
) :
1878 playback::context (ctxt
),
1879 m_output_kind (output_kind
),
1880 m_output_path (output_path
)
1882 JIT_LOG_SCOPE (get_logger ());
1885 /* Implementation of the playback::context::process vfunc for compiling
1888 Either copy the .s file to the given destination (for
1889 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1890 as necessary, copying the result. */
1893 playback::compile_to_file::postprocess (const char *ctxt_progname
)
1895 JIT_LOG_SCOPE (get_logger ());
1897 /* The driver takes different actions based on the filename, so
1898 we provide a filename with an appropriate suffix for the
1899 output kind, and then copy it up to the user-provided path,
1900 rather than directly compiling it to the requested output path. */
1902 switch (m_output_kind
)
1907 case GCC_JIT_OUTPUT_KIND_ASSEMBLER
:
1908 copy_file (get_tempdir ()->get_path_s_file (),
1912 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE
:
1914 char *tmp_o_path
= ::concat (get_tempdir ()->get_path (),
1917 invoke_driver (ctxt_progname
,
1918 get_tempdir ()->get_path_s_file (),
1921 false, /* bool shared, */
1922 false);/* bool run_linker */
1923 if (!errors_occurred ())
1924 copy_file (tmp_o_path
,
1930 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY
:
1931 invoke_driver (ctxt_progname
,
1932 get_tempdir ()->get_path_s_file (),
1933 get_tempdir ()->get_path_so_file (),
1935 true, /* bool shared, */
1936 true);/* bool run_linker */
1937 if (!errors_occurred ())
1938 copy_file (get_tempdir ()->get_path_so_file (),
1942 case GCC_JIT_OUTPUT_KIND_EXECUTABLE
:
1944 char *tmp_exe_path
= ::concat (get_tempdir ()->get_path (),
1947 invoke_driver (ctxt_progname
,
1948 get_tempdir ()->get_path_s_file (),
1951 false, /* bool shared, */
1952 true);/* bool run_linker */
1953 if (!errors_occurred ())
1954 copy_file (tmp_exe_path
,
1956 free (tmp_exe_path
);
1964 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
1965 the "executable" bits).
1967 Any errors that occur are reported on the context and hence count as
1968 a failure of the compile.
1970 We can't in general hardlink or use "rename" from the tempdir since
1971 it might be on a different filesystem to the destination. For example,
1972 I get EXDEV: "Invalid cross-device link". */
1975 playback::compile_to_file::copy_file (const char *src_path
,
1976 const char *dst_path
)
1978 JIT_LOG_SCOPE (get_logger ());
1981 get_logger ()->log ("src_path: %s", src_path
);
1982 get_logger ()->log ("dst_path: %s", dst_path
);
1987 size_t total_sz_in
= 0;
1988 size_t total_sz_out
= 0;
1991 struct stat stat_buf
;
1993 f_in
= fopen (src_path
, "rb");
1997 "unable to open %s for reading: %s",
2003 /* Use stat on the filedescriptor to get the mode,
2004 so that we can copy it over (in particular, the
2005 "executable" bits). */
2006 if (-1 == fstat (fileno (f_in
), &stat_buf
))
2009 "unable to fstat %s: %s",
2016 f_out
= fopen (dst_path
, "wb");
2020 "unable to open %s for writing: %s",
2027 while ( (sz_in
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2029 total_sz_in
+= sz_in
;
2030 size_t sz_out_remaining
= sz_in
;
2031 size_t sz_out_so_far
= 0;
2032 while (sz_out_remaining
)
2034 size_t sz_out
= fwrite (buf
+ sz_out_so_far
,
2038 gcc_assert (sz_out
<= sz_out_remaining
);
2042 "error writing to %s: %s",
2049 total_sz_out
+= sz_out
;
2050 sz_out_so_far
+= sz_out
;
2051 sz_out_remaining
-= sz_out
;
2053 gcc_assert (sz_out_so_far
== sz_in
);
2058 "error reading from %s: %s",
2064 gcc_assert (total_sz_in
== total_sz_out
);
2066 get_logger ()->log ("total bytes copied: %ld", total_sz_out
);
2068 /* Set the permissions of the copy to those of the original file,
2069 in particular the "executable" bits. */
2070 if (-1 == fchmod (fileno (f_out
), stat_buf
.st_mode
))
2072 "error setting mode of %s: %s",
2079 /* Helper functions for gcc::jit::playback::context::compile. */
2081 /* This mutex guards gcc::jit::recording::context::compile, so that only
2082 one thread can be accessing the bulk of GCC's state at once. */
2084 static pthread_mutex_t jit_mutex
= PTHREAD_MUTEX_INITIALIZER
;
2086 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2089 playback::context::acquire_mutex ()
2091 /* Acquire the big GCC mutex. */
2092 JIT_LOG_SCOPE (get_logger ());
2093 pthread_mutex_lock (&jit_mutex
);
2094 gcc_assert (NULL
== active_playback_ctxt
);
2095 active_playback_ctxt
= this;
2098 /* Release jit_mutex and clear the active playback ctxt. */
2101 playback::context::release_mutex ()
2103 /* Release the big GCC mutex. */
2104 JIT_LOG_SCOPE (get_logger ());
2105 gcc_assert (active_playback_ctxt
== this);
2106 active_playback_ctxt
= NULL
;
2107 pthread_mutex_unlock (&jit_mutex
);
2110 /* Callback used by gcc::jit::playback::context::make_fake_args when
2111 invoking driver_get_configure_time_options.
2112 Populate a vec <char * > with the configure-time options. */
2115 append_arg_from_driver (const char *option
, void *user_data
)
2117 gcc_assert (option
);
2118 gcc_assert (user_data
);
2119 vec
<char *> *argvec
= static_cast <vec
<char *> *> (user_data
);
2120 argvec
->safe_push (concat ("-", option
, NULL
));
2123 /* Build a fake argv for toplev::main from the options set
2124 by the user on the context . */
2128 make_fake_args (vec
<char *> *argvec
,
2129 const char *ctxt_progname
,
2130 vec
<recording::requested_dump
> *requested_dumps
)
2132 JIT_LOG_SCOPE (get_logger ());
2134 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2135 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2137 ADD_ARG (ctxt_progname
);
2138 ADD_ARG (get_path_c_file ());
2141 /* Handle int options: */
2142 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
))
2146 "unrecognized optimization level: %i",
2147 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
));
2166 /* What about -Os? */
2168 /* Handle bool options: */
2169 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2172 /* Suppress timing (and other) info. */
2173 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
))
2179 /* Aggressively garbage-collect, to shake out bugs: */
2180 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC
))
2182 ADD_ARG ("--param");
2183 ADD_ARG ("ggc-min-expand=0");
2184 ADD_ARG ("--param");
2185 ADD_ARG ("ggc-min-heapsize=0");
2188 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
))
2190 ADD_ARG ("-fdump-tree-all");
2191 ADD_ARG ("-fdump-rtl-all");
2192 ADD_ARG ("-fdump-ipa-all");
2195 /* Add "-fdump-" options for any calls to
2196 gcc_jit_context_enable_dump. */
2199 recording::requested_dump
*d
;
2200 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2202 char *arg
= concat ("-fdump-", d
->m_dumpname
, NULL
);
2203 ADD_ARG_TAKE_OWNERSHIP (arg
);
2207 /* PR jit/64810: Add any target-specific default options
2208 from OPTION_DEFAULT_SPECS, normally provided by the driver
2209 in the non-jit case.
2211 The target-specific code can define OPTION_DEFAULT_SPECS:
2212 default command options in the form of spec macros for the
2213 driver to expand ().
2215 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2216 if not overriden, injects the defaults as extra arguments to
2218 For the jit case, we need to add these arguments here. The
2219 input format (using the specs language) means that we have to run
2220 part of the driver code here (driver_get_configure_time_options).
2222 To avoid running the spec-expansion code every time, we just do
2223 it the first time (via a function-static flag), saving the result
2224 into a function-static vec.
2225 This flag and vec are global state (i.e. per-process).
2226 They are guarded by the jit mutex. */
2228 static bool have_configure_time_options
= false;
2229 static vec
<char *> configure_time_options
;
2231 if (have_configure_time_options
)
2232 log ("reusing cached configure-time options");
2235 have_configure_time_options
= true;
2236 log ("getting configure-time options from driver");
2237 driver_get_configure_time_options (append_arg_from_driver
,
2238 &configure_time_options
);
2245 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2246 log ("configure_time_options[%i]: %s", i
, opt
);
2248 /* configure_time_options should now contain the expanded options
2249 from OPTION_DEFAULT_SPECS (if any). */
2250 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2253 gcc_assert (opt
[0] == '-');
2258 /* Add any user-provided extra options, starting with any from
2260 m_recording_ctxt
->append_command_line_options (argvec
);
2263 #undef ADD_ARG_TAKE_OWNERSHIP
2266 /* The second half of the implementation of gcc_jit_context_enable_dump.
2267 Iterate through the requested dumps, reading the underlying files
2268 into heap-allocated buffers, writing pointers to the buffers into
2269 the char ** pointers provided by client code.
2270 Client code is responsible for calling free on the results. */
2274 extract_any_requested_dumps (vec
<recording::requested_dump
> *requested_dumps
)
2276 JIT_LOG_SCOPE (get_logger ());
2279 recording::requested_dump
*d
;
2280 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2282 dump_file_info
*dfi
;
2286 dfi
= g
->get_dumps ()->get_dump_file_info_by_switch (d
->m_dumpname
);
2289 add_error (NULL
, "unrecognized dump: %s", d
->m_dumpname
);
2293 filename
= g
->get_dumps ()->get_dump_file_name (dfi
);
2294 content
= read_dump_file (filename
);
2295 *(d
->m_out_ptr
) = content
;
2300 /* Helper function for playback::context::extract_any_requested_dumps
2301 (itself for use in implementation of gcc_jit_context_enable_dump).
2303 Attempt to read the complete file at the given path, returning the
2304 bytes found there as a buffer.
2305 The caller is responsible for calling free on the result.
2306 Errors will be reported on the context, and lead to NULL being
2307 returned; an out-of-memory error will terminate the process. */
2310 playback::context::read_dump_file (const char *path
)
2312 char *result
= NULL
;
2313 size_t total_sz
= 0;
2318 f_in
= fopen (path
, "r");
2321 add_error (NULL
, "unable to open %s for reading", path
);
2325 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2327 size_t old_total_sz
= total_sz
;
2329 result
= reinterpret_cast <char *> (xrealloc (result
, total_sz
+ 1));
2330 memcpy (result
+ old_total_sz
, buf
, sz
);
2335 add_error (NULL
, "error reading from %s", path
);
2345 result
[total_sz
] = '\0';
2349 return xstrdup ("");
2352 /* Part of playback::context::compile ().
2354 We have a .s file; we want a .so file.
2355 We could reuse parts of gcc/gcc.c to do this.
2356 For now, just use the driver binary from the install, as
2357 named in gcc-driver-name.h
2358 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2362 convert_to_dso (const char *ctxt_progname
)
2364 JIT_LOG_SCOPE (get_logger ());
2366 invoke_driver (ctxt_progname
,
2367 m_tempdir
->get_path_s_file (),
2368 m_tempdir
->get_path_so_file (),
2370 true, /* bool shared, */
2371 true);/* bool run_linker */
2376 invoke_driver (const char *ctxt_progname
,
2377 const char *input_file
,
2378 const char *output_file
,
2383 JIT_LOG_SCOPE (get_logger ());
2384 /* Currently this lumps together both assembling and linking into
2386 auto_timevar
assemble_timevar (tv_id
);
2388 auto_vec
<const char *> argvec
;
2389 #define ADD_ARG(arg) argvec.safe_push (arg)
2390 int exit_status
= 0;
2392 const char *gcc_driver_name
= GCC_DRIVER_NAME
;
2394 ADD_ARG (gcc_driver_name
);
2397 ADD_ARG ("-shared");
2402 ADD_ARG (input_file
);
2404 ADD_ARG (output_file
);
2406 /* Don't use the linker plugin.
2407 If running with just a "make" and not a "make install", then we'd
2409 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2410 libto_plugin is a .la at build time, with it becoming installed with
2411 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2413 ADD_ARG ("-fno-use-linker-plugin");
2415 /* pex argv arrays are NULL-terminated. */
2418 /* pex_one's error-handling requires pname to be non-NULL. */
2419 gcc_assert (ctxt_progname
);
2422 for (unsigned i
= 0; i
< argvec
.length (); i
++)
2423 get_logger ()->log ("argv[%i]: %s", i
, argvec
[i
]);
2425 errmsg
= pex_one (PEX_SEARCH
, /* int flags, */
2427 const_cast <char *const *> (argvec
.address ()),
2428 ctxt_progname
, /* const char *pname */
2429 NULL
, /* const char *outname */
2430 NULL
, /* const char *errname */
2431 &exit_status
, /* int *status */
2432 &err
); /* int *err*/
2435 add_error (NULL
, "error invoking gcc driver: %s", errmsg
);
2439 /* pex_one can return a NULL errmsg when the executable wasn't
2440 found (or doesn't exist), so trap these cases also. */
2441 if (exit_status
|| err
)
2444 "error invoking gcc driver: exit_status: %i err: %i",
2447 "whilst attempting to run a driver named: %s",
2457 /* Dynamically-link the built DSO file into this process, using dlopen.
2458 Wrap it up within a jit::result *, and return that.
2459 Return NULL if any errors occur, reporting them on this context. */
2465 JIT_LOG_SCOPE (get_logger ());
2466 auto_timevar
load_timevar (TV_LOAD
);
2467 void *handle
= NULL
;
2468 const char *error
= NULL
;
2469 result
*result_obj
= NULL
;
2471 /* Clear any existing error. */
2474 handle
= dlopen (m_tempdir
->get_path_so_file (),
2475 RTLD_NOW
| RTLD_LOCAL
);
2476 if ((error
= dlerror()) != NULL
) {
2477 add_error (NULL
, "%s", error
);
2481 /* We've successfully dlopened the result; create a
2482 jit::result object to wrap it.
2484 We're done with the tempdir for now, but if the user
2485 has requested debugging, the user's debugger might not
2486 be capable of dealing with the .so file being unlinked
2487 immediately, so keep it around until after the result
2488 is released. We do this by handing over ownership of
2489 the jit::tempdir to the result. See PR jit/64206. */
2490 tempdir
*handover_tempdir
;
2491 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2493 handover_tempdir
= m_tempdir
;
2495 /* The tempdir will eventually be cleaned up in the
2496 jit::result's dtor. */
2497 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2498 " handing over tempdir to jit::result");
2502 handover_tempdir
= NULL
;
2503 /* ... and retain ownership of m_tempdir so we clean it
2504 up it the playback::context's dtor. */
2505 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2506 " retaining ownership of tempdir");
2509 result_obj
= new result (get_logger (), handle
, handover_tempdir
);
2517 /* Top-level hook for playing back a recording context.
2519 This plays back m_recording_ctxt, and, if no errors
2520 occurred builds statement lists for and then postprocesses
2521 every function in the result. */
2527 JIT_LOG_SCOPE (get_logger ());
2528 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2529 tree array_domain_type
= build_index_type (size_int (200));
2530 m_char_array_type_node
2531 = build_array_type (char_type_node
, array_domain_type
);
2534 = build_pointer_type (build_qualified_type (char_type_node
,
2537 /* Replay the recorded events: */
2538 timevar_push (TV_JIT_REPLAY
);
2540 m_recording_ctxt
->replay_into (this);
2542 /* Clean away the temporary references from recording objects
2543 to playback objects. We have to do this now since the
2544 latter are GC-allocated, but the former don't mark these
2545 refs. Hence we must stop using them before the GC can run. */
2546 m_recording_ctxt
->disassociate_from_playback ();
2548 /* The builtins_manager, if any, is associated with the recording::context
2549 and might be reused for future compiles on other playback::contexts,
2550 but its m_attributes array is not GTY-labeled and hence will become
2551 nonsense if the GC runs. Purge this state. */
2552 builtins_manager
*bm
= get_builtins_manager ();
2554 bm
->finish_playback ();
2556 timevar_pop (TV_JIT_REPLAY
);
2558 if (!errors_occurred ())
2563 /* No GC can happen yet; process the cached source locations. */
2564 handle_locations ();
2566 /* We've now created tree nodes for the stmts in the various blocks
2567 in each function, but we haven't built each function's single stmt
2568 list yet. Do so now. */
2569 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2570 func
->build_stmt_list ();
2572 /* No GC can have happened yet. */
2574 /* Postprocess the functions. This could trigger GC. */
2575 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2578 func
->postprocess ();
2583 /* Dump the generated .s file to stderr. */
2587 dump_generated_code ()
2589 JIT_LOG_SCOPE (get_logger ());
2592 FILE *f_in
= fopen (get_path_s_file (), "r");
2596 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2597 fwrite (buf
, 1, sz
, stderr
);
2602 /* Get the supposed path of the notional "fake.c" file within the
2603 tempdir. This file doesn't exist, but the rest of the compiler
2608 get_path_c_file () const
2610 return m_tempdir
->get_path_c_file ();
2613 /* Get the path of the assembler output file "fake.s" file within the
2618 get_path_s_file () const
2620 return m_tempdir
->get_path_s_file ();
2623 /* Get the path of the DSO object file "fake.so" file within the
2628 get_path_so_file () const
2630 return m_tempdir
->get_path_so_file ();
2633 /* qsort comparator for comparing pairs of playback::source_line *,
2634 ordering them by line number. */
2637 line_comparator (const void *lhs
, const void *rhs
)
2639 const playback::source_line
*line_lhs
= \
2640 *static_cast<const playback::source_line
* const*> (lhs
);
2641 const playback::source_line
*line_rhs
= \
2642 *static_cast<const playback::source_line
* const*> (rhs
);
2643 return line_lhs
->get_line_num () - line_rhs
->get_line_num ();
2646 /* qsort comparator for comparing pairs of playback::location *,
2647 ordering them by column number. */
2650 location_comparator (const void *lhs
, const void *rhs
)
2652 const playback::location
*loc_lhs
= \
2653 *static_cast<const playback::location
* const *> (lhs
);
2654 const playback::location
*loc_rhs
= \
2655 *static_cast<const playback::location
* const *> (rhs
);
2656 return loc_lhs
->get_column_num () - loc_rhs
->get_column_num ();
2659 /* Our API allows locations to be created in arbitrary orders, but the
2660 linemap API requires locations to be created in ascending order
2661 as if we were tokenizing files.
2663 This hook sorts all of the the locations that have been created, and
2664 calls into the linemap API, creating linemap entries in sorted order
2665 for our locations. */
2671 /* Create the source code locations, following the ordering rules
2672 imposed by the linemap API.
2674 line_table is a global. */
2675 JIT_LOG_SCOPE (get_logger ());
2679 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2681 linemap_add (line_table
, LC_ENTER
, false, file
->get_filename (), 0);
2683 /* Sort lines by ascending line numbers. */
2684 file
->m_source_lines
.qsort (&line_comparator
);
2688 FOR_EACH_VEC_ELT (file
->m_source_lines
, j
, line
)
2693 /* Sort locations in line by ascending column numbers. */
2694 line
->m_locations
.qsort (&location_comparator
);
2696 /* Determine maximum column within this line. */
2697 gcc_assert (line
->m_locations
.length () > 0);
2698 location
*final_column
=
2699 line
->m_locations
[line
->m_locations
.length () - 1];
2700 int max_col
= final_column
->get_column_num ();
2702 linemap_line_start (line_table
, line
->get_line_num (), max_col
);
2703 FOR_EACH_VEC_ELT (line
->m_locations
, k
, loc
)
2706 linemap_position_for_column (line_table
, loc
->get_column_num ());
2710 linemap_add (line_table
, LC_LEAVE
, false, NULL
, 0);
2713 /* line_table should now be populated; every playback::location should
2714 now have an m_srcloc. */
2716 /* Now assign them to tree nodes as appropriate. */
2717 std::pair
<tree
, location
*> *cached_location
;
2719 FOR_EACH_VEC_ELT (m_cached_locations
, i
, cached_location
)
2721 tree t
= cached_location
->first
;
2722 source_location srcloc
= cached_location
->second
->m_srcloc
;
2724 /* This covers expressions: */
2725 if (CAN_HAVE_LOCATION_P (t
))
2726 SET_EXPR_LOCATION (t
, srcloc
);
2727 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t
), TS_DECL_MINIMAL
))
2728 DECL_SOURCE_LOCATION (t
) = srcloc
;
2731 /* Don't know how to set location on this node. */
2736 /* We handle errors on a playback::context by adding them to the
2737 corresponding recording::context. */
2741 add_error (location
*loc
, const char *fmt
, ...)
2745 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2750 /* We handle errors on a playback::context by adding them to the
2751 corresponding recording::context. */
2755 add_error_va (location
*loc
, const char *fmt
, va_list ap
)
2757 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2761 /* Dealing with the linemap API. */
2763 /* Construct a playback::location for a recording::location, if it
2764 doesn't exist already. */
2766 playback::location
*
2768 new_location (recording::location
*rloc
,
2769 const char *filename
,
2773 /* Get the source_file for filename, creating if necessary. */
2774 source_file
*src_file
= get_source_file (filename
);
2775 /* Likewise for the line within the file. */
2776 source_line
*src_line
= src_file
->get_source_line (line
);
2777 /* Likewise for the column within the line. */
2778 location
*loc
= src_line
->get_location (rloc
, column
);
2782 /* Deferred setting of the location for a given tree, by adding the
2783 (tree, playback::location) pair to a list of deferred associations.
2784 We will actually set the location on the tree later on once
2785 the source_location for the playback::location exists. */
2789 set_tree_location (tree t
, location
*loc
)
2792 m_cached_locations
.safe_push (std::make_pair (t
, loc
));
2796 /* Construct a playback::source_file for the given source
2797 filename, if it doesn't exist already. */
2799 playback::source_file
*
2801 get_source_file (const char *filename
)
2804 For simplicitly, this is currently a linear search.
2805 Replace with a hash if this shows up in the profile. */
2808 tree ident_filename
= get_identifier (filename
);
2810 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2811 if (file
->filename_as_tree () == ident_filename
)
2815 file
= new source_file (ident_filename
);
2816 m_source_files
.safe_push (file
);
2820 /* Constructor for gcc::jit::playback::source_file. */
2822 playback::source_file::source_file (tree filename
) :
2824 m_filename (filename
)
2828 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2832 playback::source_file::finalizer ()
2834 m_source_lines
.release ();
2837 /* Construct a playback::source_line for the given line
2838 within this source file, if one doesn't exist already. */
2840 playback::source_line
*
2841 playback::source_file::
2842 get_source_line (int line_num
)
2845 For simplicitly, this is currently a linear search.
2846 Replace with a hash if this shows up in the profile. */
2850 FOR_EACH_VEC_ELT (m_source_lines
, i
, line
)
2851 if (line
->get_line_num () == line_num
)
2855 line
= new source_line (this, line_num
);
2856 m_source_lines
.safe_push (line
);
2860 /* Constructor for gcc::jit::playback::source_line. */
2862 playback::source_line::source_line (source_file
*file
, int line_num
) :
2864 m_source_file (file
),
2865 m_line_num (line_num
)
2869 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2873 playback::source_line::finalizer ()
2875 m_locations
.release ();
2878 /* Construct a playback::location for the given column
2879 within this line of a specific source file, if one doesn't exist
2882 playback::location
*
2883 playback::source_line::
2884 get_location (recording::location
*rloc
, int column_num
)
2889 /* Another linear search that probably should be a hash table. */
2890 FOR_EACH_VEC_ELT (m_locations
, i
, loc
)
2891 if (loc
->get_column_num () == column_num
)
2895 loc
= new location (rloc
, this, column_num
);
2896 m_locations
.safe_push (loc
);
2900 /* Constructor for gcc::jit::playback::location. */
2902 playback::location::location (recording::location
*loc
,
2905 m_srcloc (UNKNOWN_LOCATION
),
2906 m_recording_loc (loc
),
2908 m_column_num(column_num
)
2912 /* The active gcc::jit::playback::context instance. This is a singleton,
2913 guarded by jit_mutex. */
2915 playback::context
*active_playback_ctxt
;
2917 } // namespace gcc::jit