1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2016 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"
43 #include "jit-playback.h"
44 #include "jit-result.h"
45 #include "jit-builtins.h"
46 #include "jit-tempdir.h"
49 /* gcc::jit::playback::context::build_cast uses the convert.h API,
50 which in turn requires the frontend to provide a "convert"
51 function, apparently as a fallback.
53 Hence we provide this dummy one, with the requirement that any casts
54 are handled before reaching this. */
55 extern tree
convert (tree type
, tree expr
);
58 convert (tree dst_type
, tree expr
)
60 gcc_assert (gcc::jit::active_playback_ctxt
);
61 gcc::jit::active_playback_ctxt
->add_error (NULL
, "unhandled conversion");
62 fprintf (stderr
, "input expression:\n");
64 fprintf (stderr
, "requested type:\n");
65 debug_tree (dst_type
);
66 return error_mark_node
;
72 /**********************************************************************
74 **********************************************************************/
76 /* The constructor for gcc::jit::playback::context. */
78 playback::context::context (recording::context
*ctxt
)
79 : log_user (ctxt
->get_logger ()),
80 m_recording_ctxt (ctxt
),
82 m_char_array_type_node (NULL
),
83 m_const_char_ptr (NULL
)
85 JIT_LOG_SCOPE (get_logger ());
86 m_functions
.create (0);
88 m_source_files
.create (0);
89 m_cached_locations
.create (0);
92 /* The destructor for gcc::jit::playback::context. */
94 playback::context::~context ()
96 JIT_LOG_SCOPE (get_logger ());
98 /* Normally the playback::context is responsible for cleaning up the
99 tempdir (including "fake.so" within the filesystem).
101 In the normal case, clean it up now.
103 However m_tempdir can be NULL if the context has handed over
104 responsibility for the tempdir cleanup to the jit::result object, so
105 that the cleanup can be delayed (see PR jit/64206). If that's the
106 case this "delete NULL;" is a no-op. */
109 m_functions
.release ();
112 /* A playback::context can reference GC-managed pointers. Mark them
113 ("by hand", rather than by gengtype).
115 This is called on the active playback context (if any) by the
116 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
124 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
126 if (ggc_test_and_set_mark (func
))
131 /* Given an enum gcc_jit_types value, get a "tree" type. */
134 get_tree_node_for_type (enum gcc_jit_types type_
)
138 case GCC_JIT_TYPE_VOID
:
139 return void_type_node
;
141 case GCC_JIT_TYPE_VOID_PTR
:
142 return ptr_type_node
;
144 case GCC_JIT_TYPE_BOOL
:
145 return boolean_type_node
;
147 case GCC_JIT_TYPE_CHAR
:
148 return char_type_node
;
149 case GCC_JIT_TYPE_SIGNED_CHAR
:
150 return signed_char_type_node
;
151 case GCC_JIT_TYPE_UNSIGNED_CHAR
:
152 return unsigned_char_type_node
;
154 case GCC_JIT_TYPE_SHORT
:
155 return short_integer_type_node
;
156 case GCC_JIT_TYPE_UNSIGNED_SHORT
:
157 return short_unsigned_type_node
;
159 case GCC_JIT_TYPE_CONST_CHAR_PTR
:
161 tree const_char
= build_qualified_type (char_type_node
,
163 return build_pointer_type (const_char
);
166 case GCC_JIT_TYPE_INT
:
167 return integer_type_node
;
168 case GCC_JIT_TYPE_UNSIGNED_INT
:
169 return unsigned_type_node
;
171 case GCC_JIT_TYPE_LONG
:
172 return long_integer_type_node
;
173 case GCC_JIT_TYPE_UNSIGNED_LONG
:
174 return long_unsigned_type_node
;
176 case GCC_JIT_TYPE_LONG_LONG
:
177 return long_long_integer_type_node
;
178 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG
:
179 return long_long_unsigned_type_node
;
181 case GCC_JIT_TYPE_FLOAT
:
182 return float_type_node
;
183 case GCC_JIT_TYPE_DOUBLE
:
184 return double_type_node
;
185 case GCC_JIT_TYPE_LONG_DOUBLE
:
186 return long_double_type_node
;
188 case GCC_JIT_TYPE_SIZE_T
:
189 return size_type_node
;
191 case GCC_JIT_TYPE_FILE_PTR
:
192 return fileptr_type_node
;
194 case GCC_JIT_TYPE_COMPLEX_FLOAT
:
195 return complex_float_type_node
;
196 case GCC_JIT_TYPE_COMPLEX_DOUBLE
:
197 return complex_double_type_node
;
198 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE
:
199 return complex_long_double_type_node
;
205 /* Construct a playback::type instance (wrapping a tree) for the given
210 get_type (enum gcc_jit_types type_
)
212 tree type_node
= get_tree_node_for_type (type_
);
213 if (NULL
== type_node
)
216 "unrecognized (enum gcc_jit_types) value: %i", type_
);
220 return new type (type_node
);
223 /* Construct a playback::type instance (wrapping a tree) for the given
228 new_array_type (playback::location
*loc
,
229 playback::type
*element_type
,
232 gcc_assert (element_type
);
234 tree t
= build_array_type_nelts (element_type
->as_tree (),
239 set_tree_location (t
, loc
);
244 /* Construct a playback::field instance (wrapping a tree). */
248 new_field (location
*loc
,
255 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
256 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
257 get_identifier (name
), type
->as_tree ());
260 set_tree_location (decl
, loc
);
262 return new field (decl
);
265 /* Construct a playback::compound_type instance (wrapping a tree). */
267 playback::compound_type
*
269 new_compound_type (location
*loc
,
271 bool is_struct
) /* else is union */
275 /* Compare with c/c-decl.c: start_struct. */
277 tree t
= make_node (is_struct
? RECORD_TYPE
: UNION_TYPE
);
278 TYPE_NAME (t
) = get_identifier (name
);
282 set_tree_location (t
, loc
);
284 return new compound_type (t
);
288 playback::compound_type::set_fields (const auto_vec
<playback::field
*> *fields
)
290 /* Compare with c/c-decl.c: finish_struct. */
293 tree fieldlist
= NULL
;
294 for (unsigned i
= 0; i
< fields
->length (); i
++)
296 field
*f
= (*fields
)[i
];
297 DECL_CONTEXT (f
->as_tree ()) = t
;
298 fieldlist
= chainon (f
->as_tree (), fieldlist
);
300 fieldlist
= nreverse (fieldlist
);
301 TYPE_FIELDS (t
) = fieldlist
;
306 /* Construct a playback::type instance (wrapping a tree) for a function
311 new_function_type (type
*return_type
,
312 const auto_vec
<type
*> *param_types
,
318 tree
*arg_types
= (tree
*)xcalloc(param_types
->length (), sizeof(tree
*));
320 FOR_EACH_VEC_ELT (*param_types
, i
, param_type
)
321 arg_types
[i
] = param_type
->as_tree ();
326 build_varargs_function_type_array (return_type
->as_tree (),
327 param_types
->length (),
330 fn_type
= build_function_type_array (return_type
->as_tree (),
331 param_types
->length (),
335 return new type (fn_type
);
338 /* Construct a playback::param instance (wrapping a tree). */
342 new_param (location
*loc
,
348 tree inner
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
349 get_identifier (name
), type
->as_tree ());
351 set_tree_location (inner
, loc
);
353 return new param (this, inner
);
356 /* Construct a playback::function instance. */
360 new_function (location
*loc
,
361 enum gcc_jit_function_kind kind
,
364 const auto_vec
<param
*> *params
,
366 enum built_in_function builtin_id
)
371 //can return_type be NULL?
374 tree
*arg_types
= (tree
*)xcalloc(params
->length (), sizeof(tree
*));
375 FOR_EACH_VEC_ELT (*params
, i
, param
)
376 arg_types
[i
] = TREE_TYPE (param
->as_tree ());
380 fn_type
= build_varargs_function_type_array (return_type
->as_tree (),
381 params
->length (), arg_types
);
383 fn_type
= build_function_type_array (return_type
->as_tree (),
384 params
->length (), arg_types
);
387 /* FIXME: this uses input_location: */
388 tree fndecl
= build_fn_decl (name
, fn_type
);
391 set_tree_location (fndecl
, loc
);
393 tree resdecl
= build_decl (UNKNOWN_LOCATION
, RESULT_DECL
,
394 NULL_TREE
, return_type
->as_tree ());
395 DECL_ARTIFICIAL (resdecl
) = 1;
396 DECL_IGNORED_P (resdecl
) = 1;
397 DECL_RESULT (fndecl
) = resdecl
;
401 DECL_FUNCTION_CODE (fndecl
) = builtin_id
;
402 gcc_assert (loc
== NULL
);
403 DECL_SOURCE_LOCATION (fndecl
) = BUILTINS_LOCATION
;
405 DECL_BUILT_IN_CLASS (fndecl
) =
406 builtins_manager::get_class (builtin_id
);
407 set_builtin_decl (builtin_id
, fndecl
,
408 builtins_manager::implicit_p (builtin_id
));
410 builtins_manager
*bm
= get_builtins_manager ();
411 tree attrs
= bm
->get_attrs_tree (builtin_id
);
413 decl_attributes (&fndecl
, attrs
, ATTR_FLAG_BUILT_IN
);
415 decl_attributes (&fndecl
, NULL_TREE
, 0);
418 if (kind
!= GCC_JIT_FUNCTION_IMPORTED
)
420 tree param_decl_list
= NULL
;
421 FOR_EACH_VEC_ELT (*params
, i
, param
)
423 param_decl_list
= chainon (param
->as_tree (), param_decl_list
);
426 /* The param list was created in reverse order; fix it: */
427 param_decl_list
= nreverse (param_decl_list
);
430 for (t
= param_decl_list
; t
; t
= DECL_CHAIN (t
))
432 DECL_CONTEXT (t
) = fndecl
;
433 DECL_ARG_TYPE (t
) = TREE_TYPE (t
);
436 /* Set it up on DECL_ARGUMENTS */
437 DECL_ARGUMENTS(fndecl
) = param_decl_list
;
440 if (kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
442 DECL_DECLARED_INLINE_P (fndecl
) = 1;
444 /* Add attribute "always_inline": */
445 DECL_ATTRIBUTES (fndecl
) =
446 tree_cons (get_identifier ("always_inline"),
448 DECL_ATTRIBUTES (fndecl
));
451 function
*func
= new function (this, fndecl
, kind
);
452 m_functions
.safe_push (func
);
456 /* Construct a playback::lvalue instance (wrapping a tree). */
460 new_global (location
*loc
,
461 enum gcc_jit_global_kind kind
,
467 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
468 get_identifier (name
),
470 TREE_PUBLIC (inner
) = (kind
!= GCC_JIT_GLOBAL_INTERNAL
);
471 DECL_COMMON (inner
) = 1;
477 case GCC_JIT_GLOBAL_EXPORTED
:
478 TREE_STATIC (inner
) = 1;
481 case GCC_JIT_GLOBAL_INTERNAL
:
482 TREE_STATIC (inner
) = 1;
485 case GCC_JIT_GLOBAL_IMPORTED
:
486 DECL_EXTERNAL (inner
) = 1;
491 set_tree_location (inner
, loc
);
493 varpool_node::get_create (inner
);
495 varpool_node::finalize_decl (inner
);
497 m_globals
.safe_push (inner
);
499 return new lvalue (this, inner
);
502 /* Implementation of the various
503 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
505 Each of these constructs a playback::rvalue instance (wrapping a tree).
507 These specializations are required to be in the same namespace
508 as the template, hence we now have to enter the gcc::jit::playback
514 /* Specialization of making an rvalue from a const, for host <int>. */
519 new_rvalue_from_const
<int> (type
*type
,
522 // FIXME: type-checking, or coercion?
523 tree inner_type
= type
->as_tree ();
524 if (INTEGRAL_TYPE_P (inner_type
))
526 tree inner
= build_int_cst (inner_type
, value
);
527 return new rvalue (this, inner
);
531 REAL_VALUE_TYPE real_value
;
532 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
533 tree inner
= build_real (inner_type
, real_value
);
534 return new rvalue (this, inner
);
538 /* Specialization of making an rvalue from a const, for host <long>. */
543 new_rvalue_from_const
<long> (type
*type
,
546 // FIXME: type-checking, or coercion?
547 tree inner_type
= type
->as_tree ();
548 if (INTEGRAL_TYPE_P (inner_type
))
550 tree inner
= build_int_cst (inner_type
, value
);
551 return new rvalue (this, inner
);
555 REAL_VALUE_TYPE real_value
;
556 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
557 tree inner
= build_real (inner_type
, real_value
);
558 return new rvalue (this, inner
);
562 /* Specialization of making an rvalue from a const, for host <double>. */
567 new_rvalue_from_const
<double> (type
*type
,
570 // FIXME: type-checking, or coercion?
571 tree inner_type
= type
->as_tree ();
573 /* We have a "double", we want a REAL_VALUE_TYPE.
575 real.c:real_from_target appears to require the representation to be
576 split into 32-bit values, and then sent as an pair of host long
578 REAL_VALUE_TYPE real_value
;
582 uint32_t as_uint32s
[2];
585 long int as_long_ints
[2];
586 as_long_ints
[0] = u
.as_uint32s
[0];
587 as_long_ints
[1] = u
.as_uint32s
[1];
588 real_from_target (&real_value
, as_long_ints
, DFmode
);
589 tree inner
= build_real (inner_type
, real_value
);
590 return new rvalue (this, inner
);
593 /* Specialization of making an rvalue from a const, for host <void *>. */
598 new_rvalue_from_const
<void *> (type
*type
,
601 tree inner_type
= type
->as_tree ();
602 /* FIXME: how to ensure we have a wide enough type? */
603 tree inner
= build_int_cstu (inner_type
, (unsigned HOST_WIDE_INT
)value
);
604 return new rvalue (this, inner
);
607 /* We're done implementing the specializations of
608 gcc::jit::playback::context::new_rvalue_from_const <T>
609 so we can exit the gcc::jit::playback namespace. */
611 } // namespace playback
613 /* Construct a playback::rvalue instance (wrapping a tree). */
617 new_string_literal (const char *value
)
619 tree t_str
= build_string (strlen (value
), value
);
620 gcc_assert (m_char_array_type_node
);
621 TREE_TYPE (t_str
) = m_char_array_type_node
;
623 /* Convert to (const char*), loosely based on
624 c/c-typeck.c: array_to_pointer_conversion,
625 by taking address of start of string. */
626 tree t_addr
= build1 (ADDR_EXPR
, m_const_char_ptr
, t_str
);
628 return new rvalue (this, t_addr
);
631 /* Coerce a tree expression into a boolean tree expression. */
635 as_truth_value (tree expr
, location
*loc
)
637 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
638 tree typed_zero
= fold_build1 (CONVERT_EXPR
,
642 set_tree_location (typed_zero
, loc
);
644 expr
= build2 (NE_EXPR
, integer_type_node
, expr
, typed_zero
);
646 set_tree_location (expr
, loc
);
651 /* Construct a playback::rvalue instance (wrapping a tree) for a
656 new_unary_op (location
*loc
,
657 enum gcc_jit_unary_op op
,
661 // FIXME: type-checking, or coercion?
662 enum tree_code inner_op
;
664 gcc_assert (result_type
);
667 tree node
= a
->as_tree ();
668 tree inner_result
= NULL
;
673 add_error (loc
, "unrecognized (enum gcc_jit_unary_op) value: %i", op
);
676 case GCC_JIT_UNARY_OP_MINUS
:
677 inner_op
= NEGATE_EXPR
;
680 case GCC_JIT_UNARY_OP_BITWISE_NEGATE
:
681 inner_op
= BIT_NOT_EXPR
;
684 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE
:
685 node
= as_truth_value (node
, loc
);
686 inner_result
= invert_truthvalue (node
);
688 set_tree_location (inner_result
, loc
);
689 return new rvalue (this, inner_result
);
691 case GCC_JIT_UNARY_OP_ABS
:
696 inner_result
= build1 (inner_op
,
697 result_type
->as_tree (),
700 set_tree_location (inner_result
, loc
);
702 return new rvalue (this, inner_result
);
705 /* Construct a playback::rvalue instance (wrapping a tree) for a
710 new_binary_op (location
*loc
,
711 enum gcc_jit_binary_op op
,
713 rvalue
*a
, rvalue
*b
)
715 // FIXME: type-checking, or coercion?
716 enum tree_code inner_op
;
718 gcc_assert (result_type
);
722 tree node_a
= a
->as_tree ();
723 tree node_b
= b
->as_tree ();
728 add_error (loc
, "unrecognized (enum gcc_jit_binary_op) value: %i", op
);
731 case GCC_JIT_BINARY_OP_PLUS
:
732 inner_op
= PLUS_EXPR
;
735 case GCC_JIT_BINARY_OP_MINUS
:
736 inner_op
= MINUS_EXPR
;
739 case GCC_JIT_BINARY_OP_MULT
:
740 inner_op
= MULT_EXPR
;
743 case GCC_JIT_BINARY_OP_DIVIDE
:
744 if (FLOAT_TYPE_P (result_type
->as_tree ()))
745 /* Floating-point division: */
746 inner_op
= RDIV_EXPR
;
748 /* Truncating to zero: */
749 inner_op
= TRUNC_DIV_EXPR
;
752 case GCC_JIT_BINARY_OP_MODULO
:
753 inner_op
= TRUNC_MOD_EXPR
;
756 case GCC_JIT_BINARY_OP_BITWISE_AND
:
757 inner_op
= BIT_AND_EXPR
;
760 case GCC_JIT_BINARY_OP_BITWISE_XOR
:
761 inner_op
= BIT_XOR_EXPR
;
764 case GCC_JIT_BINARY_OP_BITWISE_OR
:
765 inner_op
= BIT_IOR_EXPR
;
768 case GCC_JIT_BINARY_OP_LOGICAL_AND
:
769 node_a
= as_truth_value (node_a
, loc
);
770 node_b
= as_truth_value (node_b
, loc
);
771 inner_op
= TRUTH_ANDIF_EXPR
;
774 case GCC_JIT_BINARY_OP_LOGICAL_OR
:
775 node_a
= as_truth_value (node_a
, loc
);
776 node_b
= as_truth_value (node_b
, loc
);
777 inner_op
= TRUTH_ORIF_EXPR
;
780 case GCC_JIT_BINARY_OP_LSHIFT
:
781 inner_op
= LSHIFT_EXPR
;
784 case GCC_JIT_BINARY_OP_RSHIFT
:
785 inner_op
= RSHIFT_EXPR
;
789 tree inner_expr
= build2 (inner_op
,
790 result_type
->as_tree (),
794 set_tree_location (inner_expr
, loc
);
796 return new rvalue (this, inner_expr
);
799 /* Construct a playback::rvalue instance (wrapping a tree) for a
804 new_comparison (location
*loc
,
805 enum gcc_jit_comparison op
,
806 rvalue
*a
, rvalue
*b
)
808 // FIXME: type-checking, or coercion?
809 enum tree_code inner_op
;
817 add_error (loc
, "unrecognized (enum gcc_jit_comparison) value: %i", op
);
820 case GCC_JIT_COMPARISON_EQ
:
823 case GCC_JIT_COMPARISON_NE
:
826 case GCC_JIT_COMPARISON_LT
:
829 case GCC_JIT_COMPARISON_LE
:
832 case GCC_JIT_COMPARISON_GT
:
835 case GCC_JIT_COMPARISON_GE
:
840 tree inner_expr
= build2 (inner_op
,
845 set_tree_location (inner_expr
, loc
);
846 return new rvalue (this, inner_expr
);
849 /* Construct a playback::rvalue instance (wrapping a tree) for a
854 build_call (location
*loc
,
856 const auto_vec
<rvalue
*> *args
)
858 vec
<tree
, va_gc
> *tree_args
;
859 vec_alloc (tree_args
, args
->length ());
860 for (unsigned i
= 0; i
< args
->length (); i
++)
861 tree_args
->quick_push ((*args
)[i
]->as_tree ());
864 set_tree_location (fn_ptr
, loc
);
866 tree fn
= TREE_TYPE (fn_ptr
);
867 tree fn_type
= TREE_TYPE (fn
);
868 tree return_type
= TREE_TYPE (fn_type
);
870 return new rvalue (this,
871 build_call_vec (return_type
,
874 /* see c-typeck.c: build_function_call
875 which calls build_function_call_vec
877 which does lots of checking, then:
878 result = build_call_array_loc (loc, TREE_TYPE (fntype),
879 function, nargs, argarray);
881 (see also build_call_vec)
885 /* Construct a playback::rvalue instance (wrapping a tree) for a
886 call to a specific function. */
890 new_call (location
*loc
,
892 const auto_vec
<rvalue
*> *args
)
898 fndecl
= func
->as_fndecl ();
900 tree fntype
= TREE_TYPE (fndecl
);
902 tree fn
= build1 (ADDR_EXPR
, build_pointer_type (fntype
), fndecl
);
904 return build_call (loc
, fn
, args
);
907 /* Construct a playback::rvalue instance (wrapping a tree) for a
908 call through a function pointer. */
912 new_call_through_ptr (location
*loc
,
914 const auto_vec
<rvalue
*> *args
)
917 tree t_fn_ptr
= fn_ptr
->as_tree ();
919 return build_call (loc
, t_fn_ptr
, args
);
922 /* Construct a tree for a cast. */
925 playback::context::build_cast (playback::location
*loc
,
926 playback::rvalue
*expr
,
927 playback::type
*type_
)
929 /* For comparison, see:
930 - c/c-typeck.c:build_c_cast
931 - c/c-convert.c: convert
934 Only some kinds of cast are currently supported here. */
935 tree t_expr
= expr
->as_tree ();
936 tree t_dst_type
= type_
->as_tree ();
938 t_ret
= targetm
.convert_to_type (t_dst_type
, t_expr
);
941 enum tree_code dst_code
= TREE_CODE (t_dst_type
);
946 t_ret
= convert_to_integer (t_dst_type
, t_expr
);
950 /* Compare with c_objc_common_truthvalue_conversion and
951 c_common_truthvalue_conversion. */
952 /* For now, convert to: (t_expr != 0) */
953 t_ret
= build2 (NE_EXPR
, t_dst_type
,
955 build_int_cst (TREE_TYPE (t_expr
), 0));
959 t_ret
= convert_to_real (t_dst_type
, t_expr
);
963 t_ret
= build1 (NOP_EXPR
, t_dst_type
, t_expr
);
967 add_error (loc
, "couldn't handle cast during playback");
968 fprintf (stderr
, "input expression:\n");
970 fprintf (stderr
, "requested type:\n");
971 debug_tree (t_dst_type
);
972 return error_mark_node
;
975 if (TREE_CODE (t_ret
) != C_MAYBE_CONST_EXPR
)
976 t_ret
= fold (t_ret
);
981 /* Construct a playback::rvalue instance (wrapping a tree) for a
986 new_cast (playback::location
*loc
,
987 playback::rvalue
*expr
,
988 playback::type
*type_
)
991 tree t_cast
= build_cast (loc
, expr
, type_
);
993 set_tree_location (t_cast
, loc
);
994 return new rvalue (this, t_cast
);
997 /* Construct a playback::lvalue instance (wrapping a tree) for an
1002 new_array_access (location
*loc
,
1009 /* For comparison, see:
1010 c/c-typeck.c: build_array_ref
1011 c-family/c-common.c: pointer_int_sum
1013 tree t_ptr
= ptr
->as_tree ();
1014 tree t_index
= index
->as_tree ();
1015 tree t_type_ptr
= TREE_TYPE (t_ptr
);
1016 tree t_type_star_ptr
= TREE_TYPE (t_type_ptr
);
1018 if (TREE_CODE (t_type_ptr
) == ARRAY_TYPE
)
1020 tree t_result
= build4 (ARRAY_REF
, t_type_star_ptr
, t_ptr
, t_index
,
1021 NULL_TREE
, NULL_TREE
);
1023 set_tree_location (t_result
, loc
);
1024 return new lvalue (this, t_result
);
1028 /* Convert index to an offset in bytes. */
1029 tree t_sizeof
= size_in_bytes (t_type_star_ptr
);
1030 t_index
= fold_build1 (CONVERT_EXPR
, sizetype
, t_index
);
1031 tree t_offset
= build2 (MULT_EXPR
, sizetype
, t_index
, t_sizeof
);
1033 /* Locate (ptr + offset). */
1034 tree t_address
= build2 (POINTER_PLUS_EXPR
, t_type_ptr
, t_ptr
, t_offset
);
1036 tree t_indirection
= build1 (INDIRECT_REF
, t_type_star_ptr
, t_address
);
1039 set_tree_location (t_sizeof
, loc
);
1040 set_tree_location (t_offset
, loc
);
1041 set_tree_location (t_address
, loc
);
1042 set_tree_location (t_indirection
, loc
);
1045 return new lvalue (this, t_indirection
);
1049 /* Construct a tree for a field access. */
1053 new_field_access (location
*loc
,
1060 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1061 build_component_ref. */
1062 tree type
= TREE_TYPE (datum
);
1064 gcc_assert (TREE_CODE (type
) != POINTER_TYPE
);
1066 tree t_field
= field
->as_tree ();
1067 tree ref
= build3 (COMPONENT_REF
, TREE_TYPE (t_field
), datum
,
1068 t_field
, NULL_TREE
);
1070 set_tree_location (ref
, loc
);
1074 /* Construct a tree for a dereference. */
1078 new_dereference (tree ptr
,
1083 tree type
= TREE_TYPE (TREE_TYPE(ptr
));
1084 tree datum
= build1 (INDIRECT_REF
, type
, ptr
);
1086 set_tree_location (datum
, loc
);
1090 /* Construct a playback::lvalue instance (wrapping a tree) for a
1095 access_field (location
*loc
,
1098 tree datum
= as_tree ();
1099 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1102 return new lvalue (get_context (), ref
);
1105 /* Construct a playback::rvalue instance (wrapping a tree) for a
1110 access_field (location
*loc
,
1113 tree datum
= as_tree ();
1114 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1117 return new rvalue (get_context (), ref
);
1120 /* Construct a playback::lvalue instance (wrapping a tree) for a
1121 dereferenced field access. */
1125 dereference_field (location
*loc
,
1128 tree ptr
= as_tree ();
1129 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1132 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1135 return new lvalue (get_context (), ref
);
1138 /* Construct a playback::lvalue instance (wrapping a tree) for a
1143 dereference (location
*loc
)
1145 tree ptr
= as_tree ();
1146 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1147 return new lvalue (get_context (), datum
);
1150 /* Mark EXP saying that we need to be able to take the
1151 address of it; it should not be allocated in a register.
1152 Compare with e.g. c/c-typeck.c: c_mark_addressable. */
1155 jit_mark_addressable (tree exp
)
1160 switch (TREE_CODE (x
))
1163 /* (we don't yet support bitfields) */
1169 x
= TREE_OPERAND (x
, 0);
1172 case COMPOUND_LITERAL_EXPR
:
1174 TREE_ADDRESSABLE (x
) = 1;
1181 /* (we don't have a concept of a "register" declaration) */
1184 TREE_ADDRESSABLE (x
) = 1;
1191 /* Construct a playback::rvalue instance (wrapping a tree) for an
1196 get_address (location
*loc
)
1198 tree t_lvalue
= as_tree ();
1199 tree t_thistype
= TREE_TYPE (t_lvalue
);
1200 tree t_ptrtype
= build_pointer_type (t_thistype
);
1201 tree ptr
= build1 (ADDR_EXPR
, t_ptrtype
, t_lvalue
);
1203 get_context ()->set_tree_location (ptr
, loc
);
1204 jit_mark_addressable (t_lvalue
);
1205 return new rvalue (get_context (), ptr
);
1208 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1209 Provide this finalization hook for calling then they are collected,
1210 which calls the finalizer vfunc. This allows them to call "release"
1211 on any vec<> within them. */
1214 wrapper_finalizer (void *ptr
)
1216 playback::wrapper
*wrapper
= reinterpret_cast <playback::wrapper
*> (ptr
);
1217 wrapper
->finalizer ();
1220 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1221 allocate them using ggc_internal_cleared_alloc. */
1225 operator new (size_t sz
)
1227 return ggc_internal_cleared_alloc (sz
, wrapper_finalizer
, 0, 1);
1231 /* Constructor for gcc:jit::playback::function. */
1233 playback::function::
1234 function (context
*ctxt
,
1236 enum gcc_jit_function_kind kind
)
1238 m_inner_fndecl (fndecl
),
1239 m_inner_bind_expr (NULL
),
1242 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1244 /* Create a BIND_EXPR, and within it, a statement list. */
1245 m_stmt_list
= alloc_stmt_list ();
1246 m_stmt_iter
= tsi_start (m_stmt_list
);
1247 m_inner_block
= make_node (BLOCK
);
1249 build3 (BIND_EXPR
, void_type_node
, NULL
, m_stmt_list
, m_inner_block
);
1253 m_inner_block
= NULL
;
1258 /* Hand-written GC-marking hook for playback functions. */
1261 playback::function::
1264 gt_ggc_m_9tree_node (m_inner_fndecl
);
1265 gt_ggc_m_9tree_node (m_inner_bind_expr
);
1266 gt_ggc_m_9tree_node (m_stmt_list
);
1267 gt_ggc_m_9tree_node (m_inner_block
);
1270 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1274 playback::function::finalizer ()
1276 m_blocks
.release ();
1279 /* Get the return type of a playback function, in tree form. */
1282 playback::function::
1283 get_return_type_as_tree () const
1285 return TREE_TYPE (TREE_TYPE(m_inner_fndecl
));
1288 /* Construct a new local within this playback::function. */
1291 playback::function::
1292 new_local (location
*loc
,
1298 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
1299 get_identifier (name
),
1301 DECL_CONTEXT (inner
) = this->m_inner_fndecl
;
1303 /* Prepend to BIND_EXPR_VARS: */
1304 DECL_CHAIN (inner
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1305 BIND_EXPR_VARS (m_inner_bind_expr
) = inner
;
1308 set_tree_location (inner
, loc
);
1309 return new lvalue (m_ctxt
, inner
);
1312 /* Construct a new block within this playback::function. */
1315 playback::function::
1316 new_block (const char *name
)
1318 gcc_assert (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
);
1320 block
*result
= new playback::block (this, name
);
1321 m_blocks
.safe_push (result
);
1325 /* Build a statement list for the function as a whole out of the
1326 lists of statements for the individual blocks, building labels
1330 playback::function::
1336 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1338 FOR_EACH_VEC_ELT (m_blocks
, i
, b
)
1343 b
->m_label_expr
= build1 (LABEL_EXPR
,
1345 b
->as_label_decl ());
1346 tsi_link_after (&m_stmt_iter
, b
->m_label_expr
, TSI_CONTINUE_LINKING
);
1348 FOR_EACH_VEC_ELT (b
->m_stmts
, j
, stmt
)
1349 tsi_link_after (&m_stmt_iter
, stmt
, TSI_CONTINUE_LINKING
);
1353 /* Finish compiling the given function, potentially running the
1355 The function will have a statement list by now.
1356 Amongst other things, this gimplifies the statement list,
1357 and calls cgraph_node::finalize_function on the function. */
1360 playback::function::
1363 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1365 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
))
1366 debug_tree (m_stmt_list
);
1368 /* Do we need this to force cgraphunit.c to output the function? */
1369 if (m_kind
== GCC_JIT_FUNCTION_EXPORTED
)
1371 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1372 DECL_PRESERVE_P (m_inner_fndecl
) = 1;
1375 if (m_kind
== GCC_JIT_FUNCTION_INTERNAL
1376 ||m_kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
1378 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1379 TREE_PUBLIC (m_inner_fndecl
) = 0;
1382 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1384 /* Seem to need this in gimple-low.c: */
1385 gcc_assert (m_inner_block
);
1386 DECL_INITIAL (m_inner_fndecl
) = m_inner_block
;
1388 /* how to add to function? the following appears to be how to
1389 set the body of a m_inner_fndecl: */
1390 DECL_SAVED_TREE(m_inner_fndecl
) = m_inner_bind_expr
;
1392 /* Ensure that locals appear in the debuginfo. */
1393 BLOCK_VARS (m_inner_block
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1395 //debug_tree (m_inner_fndecl);
1397 /* Convert to gimple: */
1398 //printf("about to gimplify_function_tree\n");
1399 gimplify_function_tree (m_inner_fndecl
);
1400 //printf("finished gimplify_function_tree\n");
1402 current_function_decl
= m_inner_fndecl
;
1403 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
))
1404 dump_function_to_file (m_inner_fndecl
, stderr
, TDF_VOPS
|TDF_MEMSYMS
|TDF_LINENO
);
1405 //debug_tree (m_inner_fndecl);
1407 //printf("about to add to cgraph\n");
1408 /* Add to cgraph: */
1409 cgraph_node::finalize_function (m_inner_fndecl
, false);
1410 /* This can trigger a collection, so we need to have all of
1411 the funcs as roots. */
1413 current_function_decl
= NULL
;
1417 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1421 playback::block::finalizer ()
1426 /* Add an eval of the rvalue to the function's statement list. */
1430 add_eval (location
*loc
,
1433 gcc_assert (rvalue
);
1436 set_tree_location (rvalue
->as_tree (), loc
);
1438 add_stmt (rvalue
->as_tree ());
1441 /* Add an assignment to the function's statement list. */
1445 add_assignment (location
*loc
,
1449 gcc_assert (lvalue
);
1450 gcc_assert (rvalue
);
1452 tree t_lvalue
= lvalue
->as_tree ();
1453 tree t_rvalue
= rvalue
->as_tree ();
1454 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1456 t_rvalue
= build1 (CONVERT_EXPR
,
1457 TREE_TYPE (t_lvalue
),
1460 set_tree_location (t_rvalue
, loc
);
1464 build2 (MODIFY_EXPR
, TREE_TYPE (t_lvalue
),
1465 t_lvalue
, t_rvalue
);
1467 set_tree_location (stmt
, loc
);
1471 /* Add a comment to the function's statement list.
1472 For now this is done by adding a dummy label. */
1476 add_comment (location
*loc
,
1479 /* Wrap the text in C-style comment delimiters. */
1481 (3 /* opening delim */
1483 + 3 /* closing delim */
1484 + 1 /* terminator */);
1485 char *wrapped
= (char *)ggc_internal_alloc (sz
);
1486 snprintf (wrapped
, sz
, "/* %s */", text
);
1488 /* For now we simply implement this by adding a dummy label with a name
1489 containing the given text. */
1490 tree identifier
= get_identifier (wrapped
);
1491 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1492 identifier
, void_type_node
);
1493 DECL_CONTEXT (label_decl
) = m_func
->as_fndecl ();
1495 tree label_expr
= build1 (LABEL_EXPR
, void_type_node
, label_decl
);
1497 set_tree_location (label_expr
, loc
);
1498 add_stmt (label_expr
);
1501 /* Add a conditional jump statement to the function's statement list. */
1505 add_conditional (location
*loc
,
1510 gcc_assert (boolval
);
1511 gcc_assert (on_true
);
1512 gcc_assert (on_false
);
1514 /* COND_EXPR wants statement lists for the true/false operands, but we
1516 Shim it by creating jumps to the labels */
1517 tree true_jump
= build1 (GOTO_EXPR
, void_type_node
,
1518 on_true
->as_label_decl ());
1520 set_tree_location (true_jump
, loc
);
1522 tree false_jump
= build1 (GOTO_EXPR
, void_type_node
,
1523 on_false
->as_label_decl ());
1525 set_tree_location (false_jump
, loc
);
1528 build3 (COND_EXPR
, void_type_node
, boolval
->as_tree (),
1529 true_jump
, false_jump
);
1531 set_tree_location (stmt
, loc
);
1535 /* Add an unconditional jump statement to the function's statement list. */
1539 add_jump (location
*loc
,
1542 gcc_assert (target
);
1544 // see c_finish_loop
1545 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1548 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1549 TREE_USED (target
->as_label_decl ()) = 1;
1550 tree stmt
= build1 (GOTO_EXPR
, void_type_node
, target
->as_label_decl ());
1552 set_tree_location (stmt
, loc
);
1558 c_finish_goto_label (location_t loc, tree label)
1560 tree decl = lookup_label_for_goto (loc, label);
1563 TREE_USED (decl) = 1;
1565 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1566 SET_EXPR_LOCATION (t, loc);
1567 return add_stmt (t);
1574 /* Add a return statement to the function's statement list. */
1578 add_return (location
*loc
,
1581 tree modify_retval
= NULL
;
1582 tree return_type
= m_func
->get_return_type_as_tree ();
1585 tree t_lvalue
= DECL_RESULT (m_func
->as_fndecl ());
1586 tree t_rvalue
= rvalue
->as_tree ();
1587 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1588 t_rvalue
= build1 (CONVERT_EXPR
,
1589 TREE_TYPE (t_lvalue
),
1591 modify_retval
= build2 (MODIFY_EXPR
, return_type
,
1592 t_lvalue
, t_rvalue
);
1594 set_tree_location (modify_retval
, loc
);
1596 tree return_stmt
= build1 (RETURN_EXPR
, return_type
,
1599 set_tree_location (return_stmt
, loc
);
1601 add_stmt (return_stmt
);
1604 /* Helper function for playback::block::add_switch.
1605 Construct a case label for the given range, followed by a goto stmt
1606 to the given block, appending them to stmt list *ptr_t_switch_body. */
1609 add_case (tree
*ptr_t_switch_body
,
1612 playback::block
*dest_block
)
1614 tree t_label
= create_artificial_label (UNKNOWN_LOCATION
);
1615 DECL_CONTEXT (t_label
) = dest_block
->get_function ()->as_fndecl ();
1618 build_case_label (t_low_value
, t_high_value
, t_label
);
1619 append_to_statement_list (t_case_label
, ptr_t_switch_body
);
1622 build1 (GOTO_EXPR
, void_type_node
, dest_block
->as_label_decl ());
1623 append_to_statement_list (t_goto_stmt
, ptr_t_switch_body
);
1626 /* Add a switch statement to the function's statement list.
1628 My initial attempt at implementing this constructed a TREE_VEC
1629 of the cases and set it as SWITCH_LABELS (switch_expr). However,
1630 gimplify.c:gimplify_switch_expr is set up to deal with SWITCH_BODY, and
1631 doesn't have any logic for gimplifying SWITCH_LABELS.
1633 Hence we create a switch body, and populate it with case labels, each
1634 followed by a goto to the desired block. */
1638 add_switch (location
*loc
,
1640 block
*default_block
,
1641 const auto_vec
<case_
> *cases
)
1644 - c/c-typeck.c: c_start_case
1645 - c-family/c-common.c:c_add_case_label
1646 - java/expr.c:expand_java_switch and expand_java_add_case
1647 We've already rejected overlaps and duplicates in
1648 libgccjit.c:case_range_validator::validate. */
1650 tree t_expr
= expr
->as_tree ();
1651 tree t_type
= TREE_TYPE (t_expr
);
1653 tree t_switch_body
= alloc_stmt_list ();
1657 FOR_EACH_VEC_ELT (*cases
, i
, c
)
1659 tree t_low_value
= c
->m_min_value
->as_tree ();
1660 tree t_high_value
= c
->m_max_value
->as_tree ();
1661 add_case (&t_switch_body
,
1666 /* Default label. */
1667 add_case (&t_switch_body
,
1668 NULL_TREE
, NULL_TREE
,
1671 tree switch_stmt
= build3 (SWITCH_EXPR
, t_type
, t_expr
,
1672 t_switch_body
, NULL_TREE
);
1674 set_tree_location (switch_stmt
, loc
);
1675 add_stmt (switch_stmt
);
1678 /* Constructor for gcc::jit::playback::block. */
1681 block (function
*func
,
1691 identifier
= get_identifier (name
);
1694 m_label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1695 identifier
, void_type_node
);
1696 DECL_CONTEXT (m_label_decl
) = func
->as_fndecl ();
1697 m_label_expr
= NULL
;
1700 /* A subclass of auto_vec <char *> that frees all of its elements on
1703 class auto_argvec
: public auto_vec
<char *>
1709 /* auto_argvec's dtor, freeing all contained strings, automatically
1710 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1712 auto_argvec::~auto_argvec ()
1716 FOR_EACH_VEC_ELT (*this, i
, str
)
1720 /* Compile a playback::context:
1722 - Use the context's options to cconstruct command-line options, and
1723 call into the rest of GCC (toplev::main).
1724 - Assuming it succeeds, we have a .s file.
1725 - We then run the "postprocess" vfunc:
1727 (A) In-memory compile ("gcc_jit_context_compile")
1729 For an in-memory compile we have the playback::compile_to_memory
1730 subclass; "postprocess" will convert the .s file to a .so DSO,
1731 and load it in memory (via dlopen), wrapping the result up as
1732 a jit::result and returning it.
1734 (B) Compile to file ("gcc_jit_context_compile_to_file")
1736 When compiling to a file, we have the playback::compile_to_file
1737 subclass; "postprocess" will either copy the .s file to the
1738 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1739 the driver to convert it as necessary, copying the result. */
1745 JIT_LOG_SCOPE (get_logger ());
1747 const char *ctxt_progname
;
1749 int keep_intermediates
=
1750 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
);
1752 m_tempdir
= new tempdir (get_logger (), keep_intermediates
);
1753 if (!m_tempdir
->create ())
1756 /* Call into the rest of gcc.
1757 For now, we have to assemble command-line options to pass into
1758 toplev::main, so that they can be parsed. */
1760 /* Pass in user-provided program name as argv0, if any, so that it
1761 makes it into GCC's "progname" global, used in various diagnostics. */
1762 ctxt_progname
= get_str_option (GCC_JIT_STR_OPTION_PROGNAME
);
1765 ctxt_progname
= "libgccjit.so";
1767 auto_vec
<recording::requested_dump
> requested_dumps
;
1768 m_recording_ctxt
->get_all_requested_dumps (&requested_dumps
);
1770 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1773 auto_argvec fake_args
;
1774 make_fake_args (&fake_args
, ctxt_progname
, &requested_dumps
);
1775 if (errors_occurred ())
1781 /* This runs the compiler. */
1782 toplev
toplev (get_timer (), /* external_timer */
1783 false); /* init_signals */
1784 enter_scope ("toplev::main");
1786 for (unsigned i
= 0; i
< fake_args
.length (); i
++)
1787 get_logger ()->log ("argv[%i]: %s", i
, fake_args
[i
]);
1788 toplev
.main (fake_args
.length (),
1789 const_cast <char **> (fake_args
.address ()));
1790 exit_scope ("toplev::main");
1792 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1793 need to do it between toplev::main (which creates the dump manager)
1794 and toplev::finalize (which deletes it). */
1795 extract_any_requested_dumps (&requested_dumps
);
1797 /* Clean up the compiler. */
1798 enter_scope ("toplev::finalize");
1800 exit_scope ("toplev::finalize");
1802 /* Ideally we would release the jit mutex here, but we can't yet since
1803 followup activities use timevars, which are global state. */
1805 if (errors_occurred ())
1811 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
))
1812 dump_generated_code ();
1814 /* We now have a .s file.
1816 Run any postprocessing steps. This will either convert the .s file to
1817 a .so DSO, and load it in memory (playback::compile_to_memory), or
1818 convert the .s file to the requested output format, and copy it to a
1819 given file (playback::compile_to_file). */
1820 postprocess (ctxt_progname
);
1825 /* Implementation of class gcc::jit::playback::compile_to_memory,
1826 a subclass of gcc::jit::playback::context. */
1828 /* playback::compile_to_memory's trivial constructor. */
1830 playback::compile_to_memory::compile_to_memory (recording::context
*ctxt
) :
1831 playback::context (ctxt
),
1834 JIT_LOG_SCOPE (get_logger ());
1837 /* Implementation of the playback::context::process vfunc for compiling
1840 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1841 wrapping the result up as a jit::result and returning it. */
1844 playback::compile_to_memory::postprocess (const char *ctxt_progname
)
1846 JIT_LOG_SCOPE (get_logger ());
1847 convert_to_dso (ctxt_progname
);
1848 if (errors_occurred ())
1850 m_result
= dlopen_built_dso ();
1853 /* Implementation of class gcc::jit::playback::compile_to_file,
1854 a subclass of gcc::jit::playback::context. */
1856 /* playback::compile_to_file's trivial constructor. */
1858 playback::compile_to_file::compile_to_file (recording::context
*ctxt
,
1859 enum gcc_jit_output_kind output_kind
,
1860 const char *output_path
) :
1861 playback::context (ctxt
),
1862 m_output_kind (output_kind
),
1863 m_output_path (output_path
)
1865 JIT_LOG_SCOPE (get_logger ());
1868 /* Implementation of the playback::context::process vfunc for compiling
1871 Either copy the .s file to the given destination (for
1872 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1873 as necessary, copying the result. */
1876 playback::compile_to_file::postprocess (const char *ctxt_progname
)
1878 JIT_LOG_SCOPE (get_logger ());
1880 /* The driver takes different actions based on the filename, so
1881 we provide a filename with an appropriate suffix for the
1882 output kind, and then copy it up to the user-provided path,
1883 rather than directly compiling it to the requested output path. */
1885 switch (m_output_kind
)
1890 case GCC_JIT_OUTPUT_KIND_ASSEMBLER
:
1891 copy_file (get_tempdir ()->get_path_s_file (),
1893 /* The .s file is automatically unlinked by tempdir::~tempdir. */
1896 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE
:
1898 char *tmp_o_path
= ::concat (get_tempdir ()->get_path (),
1901 invoke_driver (ctxt_progname
,
1902 get_tempdir ()->get_path_s_file (),
1905 false, /* bool shared, */
1906 false);/* bool run_linker */
1907 if (!errors_occurred ())
1909 copy_file (tmp_o_path
,
1911 get_tempdir ()->add_temp_file (tmp_o_path
);
1918 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY
:
1919 invoke_driver (ctxt_progname
,
1920 get_tempdir ()->get_path_s_file (),
1921 get_tempdir ()->get_path_so_file (),
1923 true, /* bool shared, */
1924 true);/* bool run_linker */
1925 if (!errors_occurred ())
1926 copy_file (get_tempdir ()->get_path_so_file (),
1928 /* The .so file is automatically unlinked by tempdir::~tempdir. */
1931 case GCC_JIT_OUTPUT_KIND_EXECUTABLE
:
1933 char *tmp_exe_path
= ::concat (get_tempdir ()->get_path (),
1936 invoke_driver (ctxt_progname
,
1937 get_tempdir ()->get_path_s_file (),
1940 false, /* bool shared, */
1941 true);/* bool run_linker */
1942 if (!errors_occurred ())
1944 copy_file (tmp_exe_path
,
1946 get_tempdir ()->add_temp_file (tmp_exe_path
);
1949 free (tmp_exe_path
);
1957 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
1958 the "executable" bits).
1960 Any errors that occur are reported on the context and hence count as
1961 a failure of the compile.
1963 We can't in general hardlink or use "rename" from the tempdir since
1964 it might be on a different filesystem to the destination. For example,
1965 I get EXDEV: "Invalid cross-device link". */
1968 playback::compile_to_file::copy_file (const char *src_path
,
1969 const char *dst_path
)
1971 JIT_LOG_SCOPE (get_logger ());
1974 get_logger ()->log ("src_path: %s", src_path
);
1975 get_logger ()->log ("dst_path: %s", dst_path
);
1980 size_t total_sz_in
= 0;
1981 size_t total_sz_out
= 0;
1984 struct stat stat_buf
;
1986 f_in
= fopen (src_path
, "rb");
1990 "unable to open %s for reading: %s",
1996 /* Use stat on the filedescriptor to get the mode,
1997 so that we can copy it over (in particular, the
1998 "executable" bits). */
1999 if (-1 == fstat (fileno (f_in
), &stat_buf
))
2002 "unable to fstat %s: %s",
2009 f_out
= fopen (dst_path
, "wb");
2013 "unable to open %s for writing: %s",
2020 while ( (sz_in
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2022 total_sz_in
+= sz_in
;
2023 size_t sz_out_remaining
= sz_in
;
2024 size_t sz_out_so_far
= 0;
2025 while (sz_out_remaining
)
2027 size_t sz_out
= fwrite (buf
+ sz_out_so_far
,
2031 gcc_assert (sz_out
<= sz_out_remaining
);
2035 "error writing to %s: %s",
2042 total_sz_out
+= sz_out
;
2043 sz_out_so_far
+= sz_out
;
2044 sz_out_remaining
-= sz_out
;
2046 gcc_assert (sz_out_so_far
== sz_in
);
2051 "error reading from %s: %s",
2057 gcc_assert (total_sz_in
== total_sz_out
);
2059 get_logger ()->log ("total bytes copied: %ld", total_sz_out
);
2061 /* Set the permissions of the copy to those of the original file,
2062 in particular the "executable" bits. */
2063 if (-1 == fchmod (fileno (f_out
), stat_buf
.st_mode
))
2065 "error setting mode of %s: %s",
2072 /* Helper functions for gcc::jit::playback::context::compile. */
2074 /* This mutex guards gcc::jit::recording::context::compile, so that only
2075 one thread can be accessing the bulk of GCC's state at once. */
2077 static pthread_mutex_t jit_mutex
= PTHREAD_MUTEX_INITIALIZER
;
2079 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2082 playback::context::acquire_mutex ()
2084 auto_timevar
tv (get_timer (), TV_JIT_ACQUIRING_MUTEX
);
2086 /* Acquire the big GCC mutex. */
2087 JIT_LOG_SCOPE (get_logger ());
2088 pthread_mutex_lock (&jit_mutex
);
2089 gcc_assert (NULL
== active_playback_ctxt
);
2090 active_playback_ctxt
= this;
2093 /* Release jit_mutex and clear the active playback ctxt. */
2096 playback::context::release_mutex ()
2098 /* Release the big GCC mutex. */
2099 JIT_LOG_SCOPE (get_logger ());
2100 gcc_assert (active_playback_ctxt
== this);
2101 active_playback_ctxt
= NULL
;
2102 pthread_mutex_unlock (&jit_mutex
);
2105 /* Callback used by gcc::jit::playback::context::make_fake_args when
2106 invoking driver_get_configure_time_options.
2107 Populate a vec <char * > with the configure-time options. */
2110 append_arg_from_driver (const char *option
, void *user_data
)
2112 gcc_assert (option
);
2113 gcc_assert (user_data
);
2114 vec
<char *> *argvec
= static_cast <vec
<char *> *> (user_data
);
2115 argvec
->safe_push (concat ("-", option
, NULL
));
2118 /* Build a fake argv for toplev::main from the options set
2119 by the user on the context . */
2123 make_fake_args (vec
<char *> *argvec
,
2124 const char *ctxt_progname
,
2125 vec
<recording::requested_dump
> *requested_dumps
)
2127 JIT_LOG_SCOPE (get_logger ());
2129 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2130 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2132 ADD_ARG (ctxt_progname
);
2133 ADD_ARG (get_path_c_file ());
2136 /* Handle int options: */
2137 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
))
2141 "unrecognized optimization level: %i",
2142 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
));
2161 /* What about -Os? */
2163 /* Handle bool options: */
2164 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2167 /* Suppress timing (and other) info. */
2168 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
))
2174 /* Aggressively garbage-collect, to shake out bugs: */
2175 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC
))
2177 ADD_ARG ("--param");
2178 ADD_ARG ("ggc-min-expand=0");
2179 ADD_ARG ("--param");
2180 ADD_ARG ("ggc-min-heapsize=0");
2183 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
))
2185 ADD_ARG ("-fdump-tree-all");
2186 ADD_ARG ("-fdump-rtl-all");
2187 ADD_ARG ("-fdump-ipa-all");
2190 /* Add "-fdump-" options for any calls to
2191 gcc_jit_context_enable_dump. */
2194 recording::requested_dump
*d
;
2195 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2197 char *arg
= concat ("-fdump-", d
->m_dumpname
, NULL
);
2198 ADD_ARG_TAKE_OWNERSHIP (arg
);
2202 /* PR jit/64810: Add any target-specific default options
2203 from OPTION_DEFAULT_SPECS, normally provided by the driver
2204 in the non-jit case.
2206 The target-specific code can define OPTION_DEFAULT_SPECS:
2207 default command options in the form of spec macros for the
2208 driver to expand ().
2210 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2211 if not overriden, injects the defaults as extra arguments to
2213 For the jit case, we need to add these arguments here. The
2214 input format (using the specs language) means that we have to run
2215 part of the driver code here (driver_get_configure_time_options).
2217 To avoid running the spec-expansion code every time, we just do
2218 it the first time (via a function-static flag), saving the result
2219 into a function-static vec.
2220 This flag and vec are global state (i.e. per-process).
2221 They are guarded by the jit mutex. */
2223 static bool have_configure_time_options
= false;
2224 static vec
<char *> configure_time_options
;
2226 if (have_configure_time_options
)
2227 log ("reusing cached configure-time options");
2230 have_configure_time_options
= true;
2231 log ("getting configure-time options from driver");
2232 driver_get_configure_time_options (append_arg_from_driver
,
2233 &configure_time_options
);
2240 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2241 log ("configure_time_options[%i]: %s", i
, opt
);
2243 /* configure_time_options should now contain the expanded options
2244 from OPTION_DEFAULT_SPECS (if any). */
2245 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2248 gcc_assert (opt
[0] == '-');
2254 ADD_ARG ("-ftime-report");
2256 /* Add any user-provided extra options, starting with any from
2258 m_recording_ctxt
->append_command_line_options (argvec
);
2261 #undef ADD_ARG_TAKE_OWNERSHIP
2264 /* The second half of the implementation of gcc_jit_context_enable_dump.
2265 Iterate through the requested dumps, reading the underlying files
2266 into heap-allocated buffers, writing pointers to the buffers into
2267 the char ** pointers provided by client code.
2268 Client code is responsible for calling free on the results. */
2272 extract_any_requested_dumps (vec
<recording::requested_dump
> *requested_dumps
)
2274 JIT_LOG_SCOPE (get_logger ());
2277 recording::requested_dump
*d
;
2278 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2280 dump_file_info
*dfi
;
2284 dfi
= g
->get_dumps ()->get_dump_file_info_by_switch (d
->m_dumpname
);
2287 add_error (NULL
, "unrecognized dump: %s", d
->m_dumpname
);
2291 filename
= g
->get_dumps ()->get_dump_file_name (dfi
);
2292 content
= read_dump_file (filename
);
2293 *(d
->m_out_ptr
) = content
;
2294 m_tempdir
->add_temp_file (filename
);
2298 /* Helper function for playback::context::extract_any_requested_dumps
2299 (itself for use in implementation of gcc_jit_context_enable_dump).
2301 Attempt to read the complete file at the given path, returning the
2302 bytes found there as a buffer.
2303 The caller is responsible for calling free on the result.
2304 Errors will be reported on the context, and lead to NULL being
2305 returned; an out-of-memory error will terminate the process. */
2308 playback::context::read_dump_file (const char *path
)
2310 char *result
= NULL
;
2311 size_t total_sz
= 0;
2316 f_in
= fopen (path
, "r");
2319 add_error (NULL
, "unable to open %s for reading", path
);
2323 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2325 size_t old_total_sz
= total_sz
;
2327 result
= reinterpret_cast <char *> (xrealloc (result
, total_sz
+ 1));
2328 memcpy (result
+ old_total_sz
, buf
, sz
);
2333 add_error (NULL
, "error reading from %s", path
);
2343 result
[total_sz
] = '\0';
2347 return xstrdup ("");
2350 /* Part of playback::context::compile ().
2352 We have a .s file; we want a .so file.
2353 We could reuse parts of gcc/gcc.c to do this.
2354 For now, just use the driver binary from the install, as
2355 named in gcc-driver-name.h
2356 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2360 convert_to_dso (const char *ctxt_progname
)
2362 JIT_LOG_SCOPE (get_logger ());
2364 invoke_driver (ctxt_progname
,
2365 m_tempdir
->get_path_s_file (),
2366 m_tempdir
->get_path_so_file (),
2368 true, /* bool shared, */
2369 true);/* bool run_linker */
2372 static const char * const gcc_driver_name
= GCC_DRIVER_NAME
;
2376 invoke_driver (const char *ctxt_progname
,
2377 const char *input_file
,
2378 const char *output_file
,
2383 JIT_LOG_SCOPE (get_logger ());
2385 bool embedded_driver
2386 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER
);
2388 /* Currently this lumps together both assembling and linking into
2390 auto_timevar
assemble_timevar (get_timer (), tv_id
);
2392 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2394 ADD_ARG (gcc_driver_name
);
2396 add_multilib_driver_arguments (&argvec
);
2399 ADD_ARG ("-shared");
2404 ADD_ARG (input_file
);
2406 ADD_ARG (output_file
);
2408 /* Don't use the linker plugin.
2409 If running with just a "make" and not a "make install", then we'd
2411 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2412 libto_plugin is a .la at build time, with it becoming installed with
2413 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2415 ADD_ARG ("-fno-use-linker-plugin");
2417 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2418 /* OS X's linker defaults to treating undefined symbols as errors.
2419 If the context has any imported functions or globals they will be
2420 undefined until the .so is dynamically-linked into the process.
2421 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2423 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2431 /* pex_one's error-handling requires pname to be non-NULL. */
2432 gcc_assert (ctxt_progname
);
2435 for (unsigned i
= 0; i
< argvec
.length (); i
++)
2436 get_logger ()->log ("argv[%i]: %s", i
, argvec
[i
]);
2438 if (embedded_driver
)
2439 invoke_embedded_driver (&argvec
);
2441 invoke_external_driver (ctxt_progname
, &argvec
);
2446 invoke_embedded_driver (const vec
<char *> *argvec
)
2448 JIT_LOG_SCOPE (get_logger ());
2449 driver
d (true, /* can_finalize */
2451 int result
= d
.main (argvec
->length (),
2452 const_cast <char **> (argvec
->address ()));
2455 add_error (NULL
, "error invoking gcc driver");
2460 invoke_external_driver (const char *ctxt_progname
,
2461 vec
<char *> *argvec
)
2463 JIT_LOG_SCOPE (get_logger ());
2465 int exit_status
= 0;
2468 /* pex argv arrays are NULL-terminated. */
2469 argvec
->safe_push (NULL
);
2471 errmsg
= pex_one (PEX_SEARCH
, /* int flags, */
2473 const_cast <char *const *> (argvec
->address ()),
2474 ctxt_progname
, /* const char *pname */
2475 NULL
, /* const char *outname */
2476 NULL
, /* const char *errname */
2477 &exit_status
, /* int *status */
2478 &err
); /* int *err*/
2481 add_error (NULL
, "error invoking gcc driver: %s", errmsg
);
2485 /* pex_one can return a NULL errmsg when the executable wasn't
2486 found (or doesn't exist), so trap these cases also. */
2487 if (exit_status
|| err
)
2490 "error invoking gcc driver: exit_status: %i err: %i",
2493 "whilst attempting to run a driver named: %s",
2502 /* Extract the target-specific MULTILIB_DEFAULTS to
2503 multilib_defaults_raw for use by
2504 playback::context::add_multilib_driver_arguments (). */
2506 #ifndef MULTILIB_DEFAULTS
2507 #define MULTILIB_DEFAULTS { "" }
2510 static const char *const multilib_defaults_raw
[] = MULTILIB_DEFAULTS
;
2512 /* Helper function for playback::context::invoke_driver ().
2514 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2515 a driver binary. We need to pass in options to the shared driver
2516 to get the appropriate assembler/linker options for this multilib
2521 add_multilib_driver_arguments (vec
<char *> *argvec
)
2523 JIT_LOG_SCOPE (get_logger ());
2525 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2526 prepending each with a "-". */
2527 for (size_t i
= 0; i
< ARRAY_SIZE (multilib_defaults_raw
); i
++)
2528 if (multilib_defaults_raw
[i
][0])
2529 argvec
->safe_push (concat ("-", multilib_defaults_raw
[i
], NULL
));
2532 /* Dynamically-link the built DSO file into this process, using dlopen.
2533 Wrap it up within a jit::result *, and return that.
2534 Return NULL if any errors occur, reporting them on this context. */
2540 JIT_LOG_SCOPE (get_logger ());
2541 auto_timevar
load_timevar (get_timer (), TV_LOAD
);
2542 void *handle
= NULL
;
2543 const char *error
= NULL
;
2544 result
*result_obj
= NULL
;
2546 /* Clear any existing error. */
2549 handle
= dlopen (m_tempdir
->get_path_so_file (),
2550 RTLD_NOW
| RTLD_LOCAL
);
2551 if ((error
= dlerror()) != NULL
) {
2552 add_error (NULL
, "%s", error
);
2556 /* We've successfully dlopened the result; create a
2557 jit::result object to wrap it.
2559 We're done with the tempdir for now, but if the user
2560 has requested debugging, the user's debugger might not
2561 be capable of dealing with the .so file being unlinked
2562 immediately, so keep it around until after the result
2563 is released. We do this by handing over ownership of
2564 the jit::tempdir to the result. See PR jit/64206. */
2565 tempdir
*handover_tempdir
;
2566 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2568 handover_tempdir
= m_tempdir
;
2570 /* The tempdir will eventually be cleaned up in the
2571 jit::result's dtor. */
2572 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2573 " handing over tempdir to jit::result");
2577 handover_tempdir
= NULL
;
2578 /* ... and retain ownership of m_tempdir so we clean it
2579 up it the playback::context's dtor. */
2580 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2581 " retaining ownership of tempdir");
2584 result_obj
= new result (get_logger (), handle
, handover_tempdir
);
2592 /* Top-level hook for playing back a recording context.
2594 This plays back m_recording_ctxt, and, if no errors
2595 occurred builds statement lists for and then postprocesses
2596 every function in the result. */
2602 JIT_LOG_SCOPE (get_logger ());
2603 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2604 tree array_domain_type
= build_index_type (size_int (200));
2605 m_char_array_type_node
2606 = build_array_type (char_type_node
, array_domain_type
);
2609 = build_pointer_type (build_qualified_type (char_type_node
,
2612 /* Replay the recorded events: */
2613 timevar_push (TV_JIT_REPLAY
);
2615 m_recording_ctxt
->replay_into (this);
2617 /* Clean away the temporary references from recording objects
2618 to playback objects. We have to do this now since the
2619 latter are GC-allocated, but the former don't mark these
2620 refs. Hence we must stop using them before the GC can run. */
2621 m_recording_ctxt
->disassociate_from_playback ();
2623 /* The builtins_manager, if any, is associated with the recording::context
2624 and might be reused for future compiles on other playback::contexts,
2625 but its m_attributes array is not GTY-labeled and hence will become
2626 nonsense if the GC runs. Purge this state. */
2627 builtins_manager
*bm
= get_builtins_manager ();
2629 bm
->finish_playback ();
2631 timevar_pop (TV_JIT_REPLAY
);
2633 if (!errors_occurred ())
2638 /* No GC can happen yet; process the cached source locations. */
2639 handle_locations ();
2641 /* We've now created tree nodes for the stmts in the various blocks
2642 in each function, but we haven't built each function's single stmt
2643 list yet. Do so now. */
2644 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2645 func
->build_stmt_list ();
2647 /* No GC can have happened yet. */
2649 /* Postprocess the functions. This could trigger GC. */
2650 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2653 func
->postprocess ();
2658 /* Dump the generated .s file to stderr. */
2662 dump_generated_code ()
2664 JIT_LOG_SCOPE (get_logger ());
2667 FILE *f_in
= fopen (get_path_s_file (), "r");
2671 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2672 fwrite (buf
, 1, sz
, stderr
);
2677 /* Get the supposed path of the notional "fake.c" file within the
2678 tempdir. This file doesn't exist, but the rest of the compiler
2683 get_path_c_file () const
2685 return m_tempdir
->get_path_c_file ();
2688 /* Get the path of the assembler output file "fake.s" file within the
2693 get_path_s_file () const
2695 return m_tempdir
->get_path_s_file ();
2698 /* Get the path of the DSO object file "fake.so" file within the
2703 get_path_so_file () const
2705 return m_tempdir
->get_path_so_file ();
2708 /* qsort comparator for comparing pairs of playback::source_line *,
2709 ordering them by line number. */
2712 line_comparator (const void *lhs
, const void *rhs
)
2714 const playback::source_line
*line_lhs
= \
2715 *static_cast<const playback::source_line
* const*> (lhs
);
2716 const playback::source_line
*line_rhs
= \
2717 *static_cast<const playback::source_line
* const*> (rhs
);
2718 return line_lhs
->get_line_num () - line_rhs
->get_line_num ();
2721 /* qsort comparator for comparing pairs of playback::location *,
2722 ordering them by column number. */
2725 location_comparator (const void *lhs
, const void *rhs
)
2727 const playback::location
*loc_lhs
= \
2728 *static_cast<const playback::location
* const *> (lhs
);
2729 const playback::location
*loc_rhs
= \
2730 *static_cast<const playback::location
* const *> (rhs
);
2731 return loc_lhs
->get_column_num () - loc_rhs
->get_column_num ();
2734 /* Our API allows locations to be created in arbitrary orders, but the
2735 linemap API requires locations to be created in ascending order
2736 as if we were tokenizing files.
2738 This hook sorts all of the locations that have been created, and
2739 calls into the linemap API, creating linemap entries in sorted order
2740 for our locations. */
2746 /* Create the source code locations, following the ordering rules
2747 imposed by the linemap API.
2749 line_table is a global. */
2750 JIT_LOG_SCOPE (get_logger ());
2754 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2756 linemap_add (line_table
, LC_ENTER
, false, file
->get_filename (), 0);
2758 /* Sort lines by ascending line numbers. */
2759 file
->m_source_lines
.qsort (&line_comparator
);
2763 FOR_EACH_VEC_ELT (file
->m_source_lines
, j
, line
)
2768 /* Sort locations in line by ascending column numbers. */
2769 line
->m_locations
.qsort (&location_comparator
);
2771 /* Determine maximum column within this line. */
2772 gcc_assert (line
->m_locations
.length () > 0);
2773 location
*final_column
=
2774 line
->m_locations
[line
->m_locations
.length () - 1];
2775 int max_col
= final_column
->get_column_num ();
2777 linemap_line_start (line_table
, line
->get_line_num (), max_col
);
2778 FOR_EACH_VEC_ELT (line
->m_locations
, k
, loc
)
2781 linemap_position_for_column (line_table
, loc
->get_column_num ());
2785 linemap_add (line_table
, LC_LEAVE
, false, NULL
, 0);
2788 /* line_table should now be populated; every playback::location should
2789 now have an m_srcloc. */
2791 /* Now assign them to tree nodes as appropriate. */
2792 std::pair
<tree
, location
*> *cached_location
;
2794 FOR_EACH_VEC_ELT (m_cached_locations
, i
, cached_location
)
2796 tree t
= cached_location
->first
;
2797 source_location srcloc
= cached_location
->second
->m_srcloc
;
2799 /* This covers expressions: */
2800 if (CAN_HAVE_LOCATION_P (t
))
2801 SET_EXPR_LOCATION (t
, srcloc
);
2802 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t
), TS_DECL_MINIMAL
))
2803 DECL_SOURCE_LOCATION (t
) = srcloc
;
2806 /* Don't know how to set location on this node. */
2811 /* We handle errors on a playback::context by adding them to the
2812 corresponding recording::context. */
2816 add_error (location
*loc
, const char *fmt
, ...)
2820 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2825 /* We handle errors on a playback::context by adding them to the
2826 corresponding recording::context. */
2830 add_error_va (location
*loc
, const char *fmt
, va_list ap
)
2832 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2836 /* Dealing with the linemap API. */
2838 /* Construct a playback::location for a recording::location, if it
2839 doesn't exist already. */
2841 playback::location
*
2843 new_location (recording::location
*rloc
,
2844 const char *filename
,
2848 /* Get the source_file for filename, creating if necessary. */
2849 source_file
*src_file
= get_source_file (filename
);
2850 /* Likewise for the line within the file. */
2851 source_line
*src_line
= src_file
->get_source_line (line
);
2852 /* Likewise for the column within the line. */
2853 location
*loc
= src_line
->get_location (rloc
, column
);
2857 /* Deferred setting of the location for a given tree, by adding the
2858 (tree, playback::location) pair to a list of deferred associations.
2859 We will actually set the location on the tree later on once
2860 the source_location for the playback::location exists. */
2864 set_tree_location (tree t
, location
*loc
)
2867 m_cached_locations
.safe_push (std::make_pair (t
, loc
));
2871 /* Construct a playback::source_file for the given source
2872 filename, if it doesn't exist already. */
2874 playback::source_file
*
2876 get_source_file (const char *filename
)
2879 For simplicitly, this is currently a linear search.
2880 Replace with a hash if this shows up in the profile. */
2883 tree ident_filename
= get_identifier (filename
);
2885 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2886 if (file
->filename_as_tree () == ident_filename
)
2890 file
= new source_file (ident_filename
);
2891 m_source_files
.safe_push (file
);
2895 /* Constructor for gcc::jit::playback::source_file. */
2897 playback::source_file::source_file (tree filename
) :
2899 m_filename (filename
)
2903 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2907 playback::source_file::finalizer ()
2909 m_source_lines
.release ();
2912 /* Construct a playback::source_line for the given line
2913 within this source file, if one doesn't exist already. */
2915 playback::source_line
*
2916 playback::source_file::
2917 get_source_line (int line_num
)
2920 For simplicitly, this is currently a linear search.
2921 Replace with a hash if this shows up in the profile. */
2925 FOR_EACH_VEC_ELT (m_source_lines
, i
, line
)
2926 if (line
->get_line_num () == line_num
)
2930 line
= new source_line (this, line_num
);
2931 m_source_lines
.safe_push (line
);
2935 /* Constructor for gcc::jit::playback::source_line. */
2937 playback::source_line::source_line (source_file
*file
, int line_num
) :
2939 m_source_file (file
),
2940 m_line_num (line_num
)
2944 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2948 playback::source_line::finalizer ()
2950 m_locations
.release ();
2953 /* Construct a playback::location for the given column
2954 within this line of a specific source file, if one doesn't exist
2957 playback::location
*
2958 playback::source_line::
2959 get_location (recording::location
*rloc
, int column_num
)
2964 /* Another linear search that probably should be a hash table. */
2965 FOR_EACH_VEC_ELT (m_locations
, i
, loc
)
2966 if (loc
->get_column_num () == column_num
)
2970 loc
= new location (rloc
, this, column_num
);
2971 m_locations
.safe_push (loc
);
2975 /* Constructor for gcc::jit::playback::location. */
2977 playback::location::location (recording::location
*loc
,
2980 m_srcloc (UNKNOWN_LOCATION
),
2981 m_recording_loc (loc
),
2983 m_column_num(column_num
)
2987 /* The active gcc::jit::playback::context instance. This is a singleton,
2988 guarded by jit_mutex. */
2990 playback::context
*active_playback_ctxt
;
2992 } // namespace gcc::jit