1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2018 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"
40 #include "diagnostic.h"
44 #include "jit-playback.h"
45 #include "jit-result.h"
46 #include "jit-builtins.h"
47 #include "jit-tempdir.h"
50 /* gcc::jit::playback::context::build_cast uses the convert.h API,
51 which in turn requires the frontend to provide a "convert"
52 function, apparently as a fallback.
54 Hence we provide this dummy one, with the requirement that any casts
55 are handled before reaching this. */
56 extern tree
convert (tree type
, tree expr
);
59 convert (tree dst_type
, tree expr
)
61 gcc_assert (gcc::jit::active_playback_ctxt
);
62 gcc::jit::active_playback_ctxt
->add_error (NULL
, "unhandled conversion");
63 fprintf (stderr
, "input expression:\n");
65 fprintf (stderr
, "requested type:\n");
66 debug_tree (dst_type
);
67 return error_mark_node
;
73 /**********************************************************************
75 **********************************************************************/
77 /* The constructor for gcc::jit::playback::context. */
79 playback::context::context (recording::context
*ctxt
)
80 : log_user (ctxt
->get_logger ()),
81 m_recording_ctxt (ctxt
),
83 m_char_array_type_node (NULL
),
84 m_const_char_ptr (NULL
)
86 JIT_LOG_SCOPE (get_logger ());
87 m_functions
.create (0);
89 m_source_files
.create (0);
90 m_cached_locations
.create (0);
93 /* The destructor for gcc::jit::playback::context. */
95 playback::context::~context ()
97 JIT_LOG_SCOPE (get_logger ());
99 /* Normally the playback::context is responsible for cleaning up the
100 tempdir (including "fake.so" within the filesystem).
102 In the normal case, clean it up now.
104 However m_tempdir can be NULL if the context has handed over
105 responsibility for the tempdir cleanup to the jit::result object, so
106 that the cleanup can be delayed (see PR jit/64206). If that's the
107 case this "delete NULL;" is a no-op. */
110 m_functions
.release ();
113 /* A playback::context can reference GC-managed pointers. Mark them
114 ("by hand", rather than by gengtype).
116 This is called on the active playback context (if any) by the
117 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
125 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
127 if (ggc_test_and_set_mark (func
))
132 /* Given an enum gcc_jit_types value, get a "tree" type. */
135 get_tree_node_for_type (enum gcc_jit_types type_
)
139 case GCC_JIT_TYPE_VOID
:
140 return void_type_node
;
142 case GCC_JIT_TYPE_VOID_PTR
:
143 return ptr_type_node
;
145 case GCC_JIT_TYPE_BOOL
:
146 return boolean_type_node
;
148 case GCC_JIT_TYPE_CHAR
:
149 return char_type_node
;
150 case GCC_JIT_TYPE_SIGNED_CHAR
:
151 return signed_char_type_node
;
152 case GCC_JIT_TYPE_UNSIGNED_CHAR
:
153 return unsigned_char_type_node
;
155 case GCC_JIT_TYPE_SHORT
:
156 return short_integer_type_node
;
157 case GCC_JIT_TYPE_UNSIGNED_SHORT
:
158 return short_unsigned_type_node
;
160 case GCC_JIT_TYPE_CONST_CHAR_PTR
:
162 tree const_char
= build_qualified_type (char_type_node
,
164 return build_pointer_type (const_char
);
167 case GCC_JIT_TYPE_INT
:
168 return integer_type_node
;
169 case GCC_JIT_TYPE_UNSIGNED_INT
:
170 return unsigned_type_node
;
172 case GCC_JIT_TYPE_LONG
:
173 return long_integer_type_node
;
174 case GCC_JIT_TYPE_UNSIGNED_LONG
:
175 return long_unsigned_type_node
;
177 case GCC_JIT_TYPE_LONG_LONG
:
178 return long_long_integer_type_node
;
179 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG
:
180 return long_long_unsigned_type_node
;
182 case GCC_JIT_TYPE_FLOAT
:
183 return float_type_node
;
184 case GCC_JIT_TYPE_DOUBLE
:
185 return double_type_node
;
186 case GCC_JIT_TYPE_LONG_DOUBLE
:
187 return long_double_type_node
;
189 case GCC_JIT_TYPE_SIZE_T
:
190 return size_type_node
;
192 case GCC_JIT_TYPE_FILE_PTR
:
193 return fileptr_type_node
;
195 case GCC_JIT_TYPE_COMPLEX_FLOAT
:
196 return complex_float_type_node
;
197 case GCC_JIT_TYPE_COMPLEX_DOUBLE
:
198 return complex_double_type_node
;
199 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE
:
200 return complex_long_double_type_node
;
206 /* Construct a playback::type instance (wrapping a tree) for the given
211 get_type (enum gcc_jit_types type_
)
213 tree type_node
= get_tree_node_for_type (type_
);
214 if (type_node
== NULL
)
216 add_error (NULL
, "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 /* Construct a playback::rvalue instance (wrapping a tree) for a
635 playback::context::new_rvalue_from_vector (location
*,
637 const auto_vec
<rvalue
*> &elements
)
639 vec
<constructor_elt
, va_gc
> *v
;
640 vec_alloc (v
, elements
.length ());
641 for (unsigned i
= 0; i
< elements
.length (); ++i
)
642 CONSTRUCTOR_APPEND_ELT (v
, NULL_TREE
, elements
[i
]->as_tree ());
643 tree t_ctor
= build_constructor (type
->as_tree (), v
);
644 return new rvalue (this, t_ctor
);
647 /* Coerce a tree expression into a boolean tree expression. */
651 as_truth_value (tree expr
, location
*loc
)
653 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
654 tree typed_zero
= fold_build1 (CONVERT_EXPR
,
658 set_tree_location (typed_zero
, loc
);
660 expr
= build2 (NE_EXPR
, integer_type_node
, expr
, typed_zero
);
662 set_tree_location (expr
, loc
);
667 /* Construct a playback::rvalue instance (wrapping a tree) for a
672 new_unary_op (location
*loc
,
673 enum gcc_jit_unary_op op
,
677 // FIXME: type-checking, or coercion?
678 enum tree_code inner_op
;
680 gcc_assert (result_type
);
683 tree node
= a
->as_tree ();
684 tree inner_result
= NULL
;
689 add_error (loc
, "unrecognized (enum gcc_jit_unary_op) value: %i", op
);
692 case GCC_JIT_UNARY_OP_MINUS
:
693 inner_op
= NEGATE_EXPR
;
696 case GCC_JIT_UNARY_OP_BITWISE_NEGATE
:
697 inner_op
= BIT_NOT_EXPR
;
700 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE
:
701 node
= as_truth_value (node
, loc
);
702 inner_result
= invert_truthvalue (node
);
704 set_tree_location (inner_result
, loc
);
705 return new rvalue (this, inner_result
);
707 case GCC_JIT_UNARY_OP_ABS
:
712 inner_result
= build1 (inner_op
,
713 result_type
->as_tree (),
716 set_tree_location (inner_result
, loc
);
718 return new rvalue (this, inner_result
);
721 /* Construct a playback::rvalue instance (wrapping a tree) for a
726 new_binary_op (location
*loc
,
727 enum gcc_jit_binary_op op
,
729 rvalue
*a
, rvalue
*b
)
731 // FIXME: type-checking, or coercion?
732 enum tree_code inner_op
;
734 gcc_assert (result_type
);
738 tree node_a
= a
->as_tree ();
739 tree node_b
= b
->as_tree ();
744 add_error (loc
, "unrecognized (enum gcc_jit_binary_op) value: %i", op
);
747 case GCC_JIT_BINARY_OP_PLUS
:
748 inner_op
= PLUS_EXPR
;
751 case GCC_JIT_BINARY_OP_MINUS
:
752 inner_op
= MINUS_EXPR
;
755 case GCC_JIT_BINARY_OP_MULT
:
756 inner_op
= MULT_EXPR
;
759 case GCC_JIT_BINARY_OP_DIVIDE
:
760 if (FLOAT_TYPE_P (result_type
->as_tree ()))
761 /* Floating-point division: */
762 inner_op
= RDIV_EXPR
;
764 /* Truncating to zero: */
765 inner_op
= TRUNC_DIV_EXPR
;
768 case GCC_JIT_BINARY_OP_MODULO
:
769 inner_op
= TRUNC_MOD_EXPR
;
772 case GCC_JIT_BINARY_OP_BITWISE_AND
:
773 inner_op
= BIT_AND_EXPR
;
776 case GCC_JIT_BINARY_OP_BITWISE_XOR
:
777 inner_op
= BIT_XOR_EXPR
;
780 case GCC_JIT_BINARY_OP_BITWISE_OR
:
781 inner_op
= BIT_IOR_EXPR
;
784 case GCC_JIT_BINARY_OP_LOGICAL_AND
:
785 node_a
= as_truth_value (node_a
, loc
);
786 node_b
= as_truth_value (node_b
, loc
);
787 inner_op
= TRUTH_ANDIF_EXPR
;
790 case GCC_JIT_BINARY_OP_LOGICAL_OR
:
791 node_a
= as_truth_value (node_a
, loc
);
792 node_b
= as_truth_value (node_b
, loc
);
793 inner_op
= TRUTH_ORIF_EXPR
;
796 case GCC_JIT_BINARY_OP_LSHIFT
:
797 inner_op
= LSHIFT_EXPR
;
800 case GCC_JIT_BINARY_OP_RSHIFT
:
801 inner_op
= RSHIFT_EXPR
;
805 tree inner_expr
= build2 (inner_op
,
806 result_type
->as_tree (),
810 set_tree_location (inner_expr
, loc
);
812 return new rvalue (this, inner_expr
);
815 /* Construct a playback::rvalue instance (wrapping a tree) for a
820 new_comparison (location
*loc
,
821 enum gcc_jit_comparison op
,
822 rvalue
*a
, rvalue
*b
)
824 // FIXME: type-checking, or coercion?
825 enum tree_code inner_op
;
833 add_error (loc
, "unrecognized (enum gcc_jit_comparison) value: %i", op
);
836 case GCC_JIT_COMPARISON_EQ
:
839 case GCC_JIT_COMPARISON_NE
:
842 case GCC_JIT_COMPARISON_LT
:
845 case GCC_JIT_COMPARISON_LE
:
848 case GCC_JIT_COMPARISON_GT
:
851 case GCC_JIT_COMPARISON_GE
:
856 tree inner_expr
= build2 (inner_op
,
861 set_tree_location (inner_expr
, loc
);
862 return new rvalue (this, inner_expr
);
865 /* Construct a playback::rvalue instance (wrapping a tree) for a
870 build_call (location
*loc
,
872 const auto_vec
<rvalue
*> *args
,
873 bool require_tail_call
)
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 tree call
= build_call_vec (return_type
,
890 if (require_tail_call
)
891 CALL_EXPR_MUST_TAIL_CALL (call
) = 1;
893 return new rvalue (this, call
);
895 /* see c-typeck.c: build_function_call
896 which calls build_function_call_vec
898 which does lots of checking, then:
899 result = build_call_array_loc (loc, TREE_TYPE (fntype),
900 function, nargs, argarray);
902 (see also build_call_vec)
906 /* Construct a playback::rvalue instance (wrapping a tree) for a
907 call to a specific function. */
911 new_call (location
*loc
,
913 const auto_vec
<rvalue
*> *args
,
914 bool require_tail_call
)
920 fndecl
= func
->as_fndecl ();
922 tree fntype
= TREE_TYPE (fndecl
);
924 tree fn
= build1 (ADDR_EXPR
, build_pointer_type (fntype
), fndecl
);
926 return build_call (loc
, fn
, args
, require_tail_call
);
929 /* Construct a playback::rvalue instance (wrapping a tree) for a
930 call through a function pointer. */
934 new_call_through_ptr (location
*loc
,
936 const auto_vec
<rvalue
*> *args
,
937 bool require_tail_call
)
940 tree t_fn_ptr
= fn_ptr
->as_tree ();
942 return build_call (loc
, t_fn_ptr
, args
, require_tail_call
);
945 /* Construct a tree for a cast. */
948 playback::context::build_cast (playback::location
*loc
,
949 playback::rvalue
*expr
,
950 playback::type
*type_
)
952 /* For comparison, see:
953 - c/c-typeck.c:build_c_cast
954 - c/c-convert.c: convert
957 Only some kinds of cast are currently supported here. */
958 tree t_expr
= expr
->as_tree ();
959 tree t_dst_type
= type_
->as_tree ();
961 t_ret
= targetm
.convert_to_type (t_dst_type
, t_expr
);
964 enum tree_code dst_code
= TREE_CODE (t_dst_type
);
969 t_ret
= convert_to_integer (t_dst_type
, t_expr
);
973 /* Compare with c_objc_common_truthvalue_conversion and
974 c_common_truthvalue_conversion. */
975 /* For now, convert to: (t_expr != 0) */
976 t_ret
= build2 (NE_EXPR
, t_dst_type
,
978 build_int_cst (TREE_TYPE (t_expr
), 0));
982 t_ret
= convert_to_real (t_dst_type
, t_expr
);
986 t_ret
= build1 (NOP_EXPR
, t_dst_type
, t_expr
);
990 add_error (loc
, "couldn't handle cast during playback");
991 fprintf (stderr
, "input expression:\n");
993 fprintf (stderr
, "requested type:\n");
994 debug_tree (t_dst_type
);
995 return error_mark_node
;
998 if (TREE_CODE (t_ret
) != C_MAYBE_CONST_EXPR
)
999 t_ret
= fold (t_ret
);
1004 /* Construct a playback::rvalue instance (wrapping a tree) for a
1009 new_cast (playback::location
*loc
,
1010 playback::rvalue
*expr
,
1011 playback::type
*type_
)
1014 tree t_cast
= build_cast (loc
, expr
, type_
);
1016 set_tree_location (t_cast
, loc
);
1017 return new rvalue (this, t_cast
);
1020 /* Construct a playback::lvalue instance (wrapping a tree) for an
1025 new_array_access (location
*loc
,
1032 /* For comparison, see:
1033 c/c-typeck.c: build_array_ref
1034 c-family/c-common.c: pointer_int_sum
1036 tree t_ptr
= ptr
->as_tree ();
1037 tree t_index
= index
->as_tree ();
1038 tree t_type_ptr
= TREE_TYPE (t_ptr
);
1039 tree t_type_star_ptr
= TREE_TYPE (t_type_ptr
);
1041 if (TREE_CODE (t_type_ptr
) == ARRAY_TYPE
)
1043 tree t_result
= build4 (ARRAY_REF
, t_type_star_ptr
, t_ptr
, t_index
,
1044 NULL_TREE
, NULL_TREE
);
1046 set_tree_location (t_result
, loc
);
1047 return new lvalue (this, t_result
);
1051 /* Convert index to an offset in bytes. */
1052 tree t_sizeof
= size_in_bytes (t_type_star_ptr
);
1053 t_index
= fold_build1 (CONVERT_EXPR
, sizetype
, t_index
);
1054 tree t_offset
= build2 (MULT_EXPR
, sizetype
, t_index
, t_sizeof
);
1056 /* Locate (ptr + offset). */
1057 tree t_address
= build2 (POINTER_PLUS_EXPR
, t_type_ptr
, t_ptr
, t_offset
);
1059 tree t_indirection
= build1 (INDIRECT_REF
, t_type_star_ptr
, t_address
);
1062 set_tree_location (t_sizeof
, loc
);
1063 set_tree_location (t_offset
, loc
);
1064 set_tree_location (t_address
, loc
);
1065 set_tree_location (t_indirection
, loc
);
1068 return new lvalue (this, t_indirection
);
1072 /* Construct a tree for a field access. */
1076 new_field_access (location
*loc
,
1083 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1084 build_component_ref. */
1085 tree type
= TREE_TYPE (datum
);
1087 gcc_assert (TREE_CODE (type
) != POINTER_TYPE
);
1089 tree t_field
= field
->as_tree ();
1090 tree ref
= build3 (COMPONENT_REF
, TREE_TYPE (t_field
), datum
,
1091 t_field
, NULL_TREE
);
1093 set_tree_location (ref
, loc
);
1097 /* Construct a tree for a dereference. */
1101 new_dereference (tree ptr
,
1106 tree type
= TREE_TYPE (TREE_TYPE(ptr
));
1107 tree datum
= build1 (INDIRECT_REF
, type
, ptr
);
1109 set_tree_location (datum
, loc
);
1113 /* Construct a playback::type instance (wrapping a tree)
1114 with the given alignment. */
1118 get_aligned (size_t alignment_in_bytes
) const
1120 tree t_new_type
= build_variant_type_copy (m_inner
);
1122 SET_TYPE_ALIGN (t_new_type
, alignment_in_bytes
* BITS_PER_UNIT
);
1123 TYPE_USER_ALIGN (t_new_type
) = 1;
1125 return new type (t_new_type
);
1128 /* Construct a playback::type instance (wrapping a tree)
1129 for the given vector type. */
1133 get_vector (size_t num_units
) const
1135 tree t_new_type
= build_vector_type (m_inner
, num_units
);
1136 return new type (t_new_type
);
1139 /* Construct a playback::lvalue instance (wrapping a tree) for a
1144 access_field (location
*loc
,
1147 tree datum
= as_tree ();
1148 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1151 return new lvalue (get_context (), ref
);
1154 /* Construct a playback::rvalue instance (wrapping a tree) for a
1159 access_field (location
*loc
,
1162 tree datum
= as_tree ();
1163 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1166 return new rvalue (get_context (), ref
);
1169 /* Construct a playback::lvalue instance (wrapping a tree) for a
1170 dereferenced field access. */
1174 dereference_field (location
*loc
,
1177 tree ptr
= as_tree ();
1178 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1181 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1184 return new lvalue (get_context (), ref
);
1187 /* Construct a playback::lvalue instance (wrapping a tree) for a
1192 dereference (location
*loc
)
1194 tree ptr
= as_tree ();
1195 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1196 return new lvalue (get_context (), datum
);
1199 /* Mark EXP saying that we need to be able to take the
1200 address of it; it should not be allocated in a register.
1201 Compare with e.g. c/c-typeck.c: c_mark_addressable. */
1204 jit_mark_addressable (tree exp
)
1209 switch (TREE_CODE (x
))
1212 /* (we don't yet support bitfields) */
1218 x
= TREE_OPERAND (x
, 0);
1221 case COMPOUND_LITERAL_EXPR
:
1223 TREE_ADDRESSABLE (x
) = 1;
1230 /* (we don't have a concept of a "register" declaration) */
1233 TREE_ADDRESSABLE (x
) = 1;
1240 /* Construct a playback::rvalue instance (wrapping a tree) for an
1245 get_address (location
*loc
)
1247 tree t_lvalue
= as_tree ();
1248 tree t_thistype
= TREE_TYPE (t_lvalue
);
1249 tree t_ptrtype
= build_pointer_type (t_thistype
);
1250 tree ptr
= build1 (ADDR_EXPR
, t_ptrtype
, t_lvalue
);
1252 get_context ()->set_tree_location (ptr
, loc
);
1253 jit_mark_addressable (t_lvalue
);
1254 return new rvalue (get_context (), ptr
);
1257 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1258 Provide this finalization hook for calling then they are collected,
1259 which calls the finalizer vfunc. This allows them to call "release"
1260 on any vec<> within them. */
1263 wrapper_finalizer (void *ptr
)
1265 playback::wrapper
*wrapper
= reinterpret_cast <playback::wrapper
*> (ptr
);
1266 wrapper
->finalizer ();
1269 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1270 allocate them using ggc_internal_cleared_alloc. */
1274 operator new (size_t sz
)
1276 return ggc_internal_cleared_alloc (sz
, wrapper_finalizer
, 0, 1);
1280 /* Constructor for gcc:jit::playback::function. */
1282 playback::function::
1283 function (context
*ctxt
,
1285 enum gcc_jit_function_kind kind
)
1287 m_inner_fndecl (fndecl
),
1288 m_inner_bind_expr (NULL
),
1291 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1293 /* Create a BIND_EXPR, and within it, a statement list. */
1294 m_stmt_list
= alloc_stmt_list ();
1295 m_stmt_iter
= tsi_start (m_stmt_list
);
1296 m_inner_block
= make_node (BLOCK
);
1298 build3 (BIND_EXPR
, void_type_node
, NULL
, m_stmt_list
, m_inner_block
);
1302 m_inner_block
= NULL
;
1307 /* Hand-written GC-marking hook for playback functions. */
1310 playback::function::
1313 gt_ggc_m_9tree_node (m_inner_fndecl
);
1314 gt_ggc_m_9tree_node (m_inner_bind_expr
);
1315 gt_ggc_m_9tree_node (m_stmt_list
);
1316 gt_ggc_m_9tree_node (m_inner_block
);
1319 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1323 playback::function::finalizer ()
1325 m_blocks
.release ();
1328 /* Get the return type of a playback function, in tree form. */
1331 playback::function::
1332 get_return_type_as_tree () const
1334 return TREE_TYPE (TREE_TYPE(m_inner_fndecl
));
1337 /* Construct a new local within this playback::function. */
1340 playback::function::
1341 new_local (location
*loc
,
1347 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
1348 get_identifier (name
),
1350 DECL_CONTEXT (inner
) = this->m_inner_fndecl
;
1352 /* Prepend to BIND_EXPR_VARS: */
1353 DECL_CHAIN (inner
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1354 BIND_EXPR_VARS (m_inner_bind_expr
) = inner
;
1357 set_tree_location (inner
, loc
);
1358 return new lvalue (m_ctxt
, inner
);
1361 /* Construct a new block within this playback::function. */
1364 playback::function::
1365 new_block (const char *name
)
1367 gcc_assert (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
);
1369 block
*result
= new playback::block (this, name
);
1370 m_blocks
.safe_push (result
);
1374 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1375 this playback::function. */
1378 playback::function::get_address (location
*loc
)
1380 tree t_fndecl
= as_fndecl ();
1381 tree t_fntype
= TREE_TYPE (t_fndecl
);
1382 tree t_fnptr
= build1 (ADDR_EXPR
, build_pointer_type (t_fntype
), t_fndecl
);
1384 m_ctxt
->set_tree_location (t_fnptr
, loc
);
1385 return new rvalue (m_ctxt
, t_fnptr
);
1388 /* Build a statement list for the function as a whole out of the
1389 lists of statements for the individual blocks, building labels
1393 playback::function::
1399 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1401 FOR_EACH_VEC_ELT (m_blocks
, i
, b
)
1406 b
->m_label_expr
= build1 (LABEL_EXPR
,
1408 b
->as_label_decl ());
1409 tsi_link_after (&m_stmt_iter
, b
->m_label_expr
, TSI_CONTINUE_LINKING
);
1411 FOR_EACH_VEC_ELT (b
->m_stmts
, j
, stmt
)
1412 tsi_link_after (&m_stmt_iter
, stmt
, TSI_CONTINUE_LINKING
);
1416 /* Finish compiling the given function, potentially running the
1418 The function will have a statement list by now.
1419 Amongst other things, this gimplifies the statement list,
1420 and calls cgraph_node::finalize_function on the function. */
1423 playback::function::
1426 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1428 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
))
1429 debug_tree (m_stmt_list
);
1431 /* Do we need this to force cgraphunit.c to output the function? */
1432 if (m_kind
== GCC_JIT_FUNCTION_EXPORTED
)
1434 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1435 DECL_PRESERVE_P (m_inner_fndecl
) = 1;
1438 if (m_kind
== GCC_JIT_FUNCTION_INTERNAL
1439 ||m_kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
1441 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1442 TREE_PUBLIC (m_inner_fndecl
) = 0;
1445 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1447 /* Seem to need this in gimple-low.c: */
1448 gcc_assert (m_inner_block
);
1449 DECL_INITIAL (m_inner_fndecl
) = m_inner_block
;
1451 /* how to add to function? the following appears to be how to
1452 set the body of a m_inner_fndecl: */
1453 DECL_SAVED_TREE(m_inner_fndecl
) = m_inner_bind_expr
;
1455 /* Ensure that locals appear in the debuginfo. */
1456 BLOCK_VARS (m_inner_block
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1458 //debug_tree (m_inner_fndecl);
1460 /* Convert to gimple: */
1461 //printf("about to gimplify_function_tree\n");
1462 gimplify_function_tree (m_inner_fndecl
);
1463 //printf("finished gimplify_function_tree\n");
1465 current_function_decl
= m_inner_fndecl
;
1466 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
))
1467 dump_function_to_file (m_inner_fndecl
, stderr
, TDF_VOPS
|TDF_MEMSYMS
|TDF_LINENO
);
1468 //debug_tree (m_inner_fndecl);
1470 //printf("about to add to cgraph\n");
1471 /* Add to cgraph: */
1472 cgraph_node::finalize_function (m_inner_fndecl
, false);
1473 /* This can trigger a collection, so we need to have all of
1474 the funcs as roots. */
1476 current_function_decl
= NULL
;
1480 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1484 playback::block::finalizer ()
1489 /* Add an eval of the rvalue to the function's statement list. */
1493 add_eval (location
*loc
,
1496 gcc_assert (rvalue
);
1499 set_tree_location (rvalue
->as_tree (), loc
);
1501 add_stmt (rvalue
->as_tree ());
1504 /* Add an assignment to the function's statement list. */
1508 add_assignment (location
*loc
,
1512 gcc_assert (lvalue
);
1513 gcc_assert (rvalue
);
1515 tree t_lvalue
= lvalue
->as_tree ();
1516 tree t_rvalue
= rvalue
->as_tree ();
1517 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1519 t_rvalue
= build1 (CONVERT_EXPR
,
1520 TREE_TYPE (t_lvalue
),
1523 set_tree_location (t_rvalue
, loc
);
1527 build2 (MODIFY_EXPR
, TREE_TYPE (t_lvalue
),
1528 t_lvalue
, t_rvalue
);
1530 set_tree_location (stmt
, loc
);
1534 /* Add a comment to the function's statement list.
1535 For now this is done by adding a dummy label. */
1539 add_comment (location
*loc
,
1542 /* Wrap the text in C-style comment delimiters. */
1544 (3 /* opening delim */
1546 + 3 /* closing delim */
1547 + 1 /* terminator */);
1548 char *wrapped
= (char *)ggc_internal_alloc (sz
);
1549 snprintf (wrapped
, sz
, "/* %s */", text
);
1551 /* For now we simply implement this by adding a dummy label with a name
1552 containing the given text. */
1553 tree identifier
= get_identifier (wrapped
);
1554 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1555 identifier
, void_type_node
);
1556 DECL_CONTEXT (label_decl
) = m_func
->as_fndecl ();
1558 tree label_expr
= build1 (LABEL_EXPR
, void_type_node
, label_decl
);
1560 set_tree_location (label_expr
, loc
);
1561 add_stmt (label_expr
);
1564 /* Add a conditional jump statement to the function's statement list. */
1568 add_conditional (location
*loc
,
1573 gcc_assert (boolval
);
1574 gcc_assert (on_true
);
1575 gcc_assert (on_false
);
1577 /* COND_EXPR wants statement lists for the true/false operands, but we
1579 Shim it by creating jumps to the labels */
1580 tree true_jump
= build1 (GOTO_EXPR
, void_type_node
,
1581 on_true
->as_label_decl ());
1583 set_tree_location (true_jump
, loc
);
1585 tree false_jump
= build1 (GOTO_EXPR
, void_type_node
,
1586 on_false
->as_label_decl ());
1588 set_tree_location (false_jump
, loc
);
1591 build3 (COND_EXPR
, void_type_node
, boolval
->as_tree (),
1592 true_jump
, false_jump
);
1594 set_tree_location (stmt
, loc
);
1598 /* Add an unconditional jump statement to the function's statement list. */
1602 add_jump (location
*loc
,
1605 gcc_assert (target
);
1607 // see c_finish_loop
1608 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1611 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1612 TREE_USED (target
->as_label_decl ()) = 1;
1613 tree stmt
= build1 (GOTO_EXPR
, void_type_node
, target
->as_label_decl ());
1615 set_tree_location (stmt
, loc
);
1621 c_finish_goto_label (location_t loc, tree label)
1623 tree decl = lookup_label_for_goto (loc, label);
1626 TREE_USED (decl) = 1;
1628 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1629 SET_EXPR_LOCATION (t, loc);
1630 return add_stmt (t);
1637 /* Add a return statement to the function's statement list. */
1641 add_return (location
*loc
,
1644 tree modify_retval
= NULL
;
1645 tree return_type
= m_func
->get_return_type_as_tree ();
1648 tree t_lvalue
= DECL_RESULT (m_func
->as_fndecl ());
1649 tree t_rvalue
= rvalue
->as_tree ();
1650 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1651 t_rvalue
= build1 (CONVERT_EXPR
,
1652 TREE_TYPE (t_lvalue
),
1654 modify_retval
= build2 (MODIFY_EXPR
, return_type
,
1655 t_lvalue
, t_rvalue
);
1657 set_tree_location (modify_retval
, loc
);
1659 tree return_stmt
= build1 (RETURN_EXPR
, return_type
,
1662 set_tree_location (return_stmt
, loc
);
1664 add_stmt (return_stmt
);
1667 /* Helper function for playback::block::add_switch.
1668 Construct a case label for the given range, followed by a goto stmt
1669 to the given block, appending them to stmt list *ptr_t_switch_body. */
1672 add_case (tree
*ptr_t_switch_body
,
1675 playback::block
*dest_block
)
1677 tree t_label
= create_artificial_label (UNKNOWN_LOCATION
);
1678 DECL_CONTEXT (t_label
) = dest_block
->get_function ()->as_fndecl ();
1681 build_case_label (t_low_value
, t_high_value
, t_label
);
1682 append_to_statement_list (t_case_label
, ptr_t_switch_body
);
1685 build1 (GOTO_EXPR
, void_type_node
, dest_block
->as_label_decl ());
1686 append_to_statement_list (t_goto_stmt
, ptr_t_switch_body
);
1689 /* Add a switch statement to the function's statement list.
1691 We create a switch body, and populate it with case labels, each
1692 followed by a goto to the desired block. */
1696 add_switch (location
*loc
,
1698 block
*default_block
,
1699 const auto_vec
<case_
> *cases
)
1702 - c/c-typeck.c: c_start_case
1703 - c-family/c-common.c:c_add_case_label
1704 - java/expr.c:expand_java_switch and expand_java_add_case
1705 We've already rejected overlaps and duplicates in
1706 libgccjit.c:case_range_validator::validate. */
1708 tree t_expr
= expr
->as_tree ();
1709 tree t_type
= TREE_TYPE (t_expr
);
1711 tree t_switch_body
= alloc_stmt_list ();
1715 FOR_EACH_VEC_ELT (*cases
, i
, c
)
1717 tree t_low_value
= c
->m_min_value
->as_tree ();
1718 tree t_high_value
= c
->m_max_value
->as_tree ();
1719 add_case (&t_switch_body
, t_low_value
, t_high_value
, c
->m_dest_block
);
1721 /* Default label. */
1722 add_case (&t_switch_body
, NULL_TREE
, NULL_TREE
, default_block
);
1724 tree switch_stmt
= build2 (SWITCH_EXPR
, t_type
, t_expr
, t_switch_body
);
1726 set_tree_location (switch_stmt
, loc
);
1727 add_stmt (switch_stmt
);
1730 /* Constructor for gcc::jit::playback::block. */
1733 block (function
*func
,
1743 identifier
= get_identifier (name
);
1746 m_label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1747 identifier
, void_type_node
);
1748 DECL_CONTEXT (m_label_decl
) = func
->as_fndecl ();
1749 m_label_expr
= NULL
;
1752 /* A subclass of auto_vec <char *> that frees all of its elements on
1755 class auto_argvec
: public auto_vec
<char *>
1761 /* auto_argvec's dtor, freeing all contained strings, automatically
1762 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1764 auto_argvec::~auto_argvec ()
1768 FOR_EACH_VEC_ELT (*this, i
, str
)
1772 /* Compile a playback::context:
1774 - Use the context's options to cconstruct command-line options, and
1775 call into the rest of GCC (toplev::main).
1776 - Assuming it succeeds, we have a .s file.
1777 - We then run the "postprocess" vfunc:
1779 (A) In-memory compile ("gcc_jit_context_compile")
1781 For an in-memory compile we have the playback::compile_to_memory
1782 subclass; "postprocess" will convert the .s file to a .so DSO,
1783 and load it in memory (via dlopen), wrapping the result up as
1784 a jit::result and returning it.
1786 (B) Compile to file ("gcc_jit_context_compile_to_file")
1788 When compiling to a file, we have the playback::compile_to_file
1789 subclass; "postprocess" will either copy the .s file to the
1790 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1791 the driver to convert it as necessary, copying the result. */
1797 JIT_LOG_SCOPE (get_logger ());
1799 const char *ctxt_progname
;
1801 int keep_intermediates
=
1802 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
);
1804 m_tempdir
= new tempdir (get_logger (), keep_intermediates
);
1805 if (!m_tempdir
->create ())
1808 /* Call into the rest of gcc.
1809 For now, we have to assemble command-line options to pass into
1810 toplev::main, so that they can be parsed. */
1812 /* Pass in user-provided program name as argv0, if any, so that it
1813 makes it into GCC's "progname" global, used in various diagnostics. */
1814 ctxt_progname
= get_str_option (GCC_JIT_STR_OPTION_PROGNAME
);
1817 ctxt_progname
= "libgccjit.so";
1819 auto_vec
<recording::requested_dump
> requested_dumps
;
1820 m_recording_ctxt
->get_all_requested_dumps (&requested_dumps
);
1822 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1825 auto_argvec fake_args
;
1826 make_fake_args (&fake_args
, ctxt_progname
, &requested_dumps
);
1827 if (errors_occurred ())
1833 /* This runs the compiler. */
1834 toplev
toplev (get_timer (), /* external_timer */
1835 false); /* init_signals */
1836 enter_scope ("toplev::main");
1838 for (unsigned i
= 0; i
< fake_args
.length (); i
++)
1839 get_logger ()->log ("argv[%i]: %s", i
, fake_args
[i
]);
1840 toplev
.main (fake_args
.length (),
1841 const_cast <char **> (fake_args
.address ()));
1842 exit_scope ("toplev::main");
1844 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1845 need to do it between toplev::main (which creates the dump manager)
1846 and toplev::finalize (which deletes it). */
1847 extract_any_requested_dumps (&requested_dumps
);
1849 /* Clean up the compiler. */
1850 enter_scope ("toplev::finalize");
1852 exit_scope ("toplev::finalize");
1854 /* Ideally we would release the jit mutex here, but we can't yet since
1855 followup activities use timevars, which are global state. */
1857 if (errors_occurred ())
1863 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
))
1864 dump_generated_code ();
1866 /* We now have a .s file.
1868 Run any postprocessing steps. This will either convert the .s file to
1869 a .so DSO, and load it in memory (playback::compile_to_memory), or
1870 convert the .s file to the requested output format, and copy it to a
1871 given file (playback::compile_to_file). */
1872 postprocess (ctxt_progname
);
1877 /* Implementation of class gcc::jit::playback::compile_to_memory,
1878 a subclass of gcc::jit::playback::context. */
1880 /* playback::compile_to_memory's trivial constructor. */
1882 playback::compile_to_memory::compile_to_memory (recording::context
*ctxt
) :
1883 playback::context (ctxt
),
1886 JIT_LOG_SCOPE (get_logger ());
1889 /* Implementation of the playback::context::process vfunc for compiling
1892 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1893 wrapping the result up as a jit::result and returning it. */
1896 playback::compile_to_memory::postprocess (const char *ctxt_progname
)
1898 JIT_LOG_SCOPE (get_logger ());
1899 convert_to_dso (ctxt_progname
);
1900 if (errors_occurred ())
1902 m_result
= dlopen_built_dso ();
1905 /* Implementation of class gcc::jit::playback::compile_to_file,
1906 a subclass of gcc::jit::playback::context. */
1908 /* playback::compile_to_file's trivial constructor. */
1910 playback::compile_to_file::compile_to_file (recording::context
*ctxt
,
1911 enum gcc_jit_output_kind output_kind
,
1912 const char *output_path
) :
1913 playback::context (ctxt
),
1914 m_output_kind (output_kind
),
1915 m_output_path (output_path
)
1917 JIT_LOG_SCOPE (get_logger ());
1920 /* Implementation of the playback::context::process vfunc for compiling
1923 Either copy the .s file to the given destination (for
1924 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1925 as necessary, copying the result. */
1928 playback::compile_to_file::postprocess (const char *ctxt_progname
)
1930 JIT_LOG_SCOPE (get_logger ());
1932 /* The driver takes different actions based on the filename, so
1933 we provide a filename with an appropriate suffix for the
1934 output kind, and then copy it up to the user-provided path,
1935 rather than directly compiling it to the requested output path. */
1937 switch (m_output_kind
)
1942 case GCC_JIT_OUTPUT_KIND_ASSEMBLER
:
1943 copy_file (get_tempdir ()->get_path_s_file (),
1945 /* The .s file is automatically unlinked by tempdir::~tempdir. */
1948 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE
:
1950 char *tmp_o_path
= ::concat (get_tempdir ()->get_path (),
1953 invoke_driver (ctxt_progname
,
1954 get_tempdir ()->get_path_s_file (),
1957 false, /* bool shared, */
1958 false);/* bool run_linker */
1959 if (!errors_occurred ())
1961 copy_file (tmp_o_path
,
1963 get_tempdir ()->add_temp_file (tmp_o_path
);
1970 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY
:
1971 invoke_driver (ctxt_progname
,
1972 get_tempdir ()->get_path_s_file (),
1973 get_tempdir ()->get_path_so_file (),
1975 true, /* bool shared, */
1976 true);/* bool run_linker */
1977 if (!errors_occurred ())
1978 copy_file (get_tempdir ()->get_path_so_file (),
1980 /* The .so file is automatically unlinked by tempdir::~tempdir. */
1983 case GCC_JIT_OUTPUT_KIND_EXECUTABLE
:
1985 char *tmp_exe_path
= ::concat (get_tempdir ()->get_path (),
1988 invoke_driver (ctxt_progname
,
1989 get_tempdir ()->get_path_s_file (),
1992 false, /* bool shared, */
1993 true);/* bool run_linker */
1994 if (!errors_occurred ())
1996 copy_file (tmp_exe_path
,
1998 get_tempdir ()->add_temp_file (tmp_exe_path
);
2001 free (tmp_exe_path
);
2009 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2010 the "executable" bits).
2012 Any errors that occur are reported on the context and hence count as
2013 a failure of the compile.
2015 We can't in general hardlink or use "rename" from the tempdir since
2016 it might be on a different filesystem to the destination. For example,
2017 I get EXDEV: "Invalid cross-device link". */
2020 playback::compile_to_file::copy_file (const char *src_path
,
2021 const char *dst_path
)
2023 JIT_LOG_SCOPE (get_logger ());
2026 get_logger ()->log ("src_path: %s", src_path
);
2027 get_logger ()->log ("dst_path: %s", dst_path
);
2032 size_t total_sz_in
= 0;
2033 size_t total_sz_out
= 0;
2036 struct stat stat_buf
;
2038 f_in
= fopen (src_path
, "rb");
2042 "unable to open %s for reading: %s",
2048 /* Use stat on the filedescriptor to get the mode,
2049 so that we can copy it over (in particular, the
2050 "executable" bits). */
2051 if (fstat (fileno (f_in
), &stat_buf
) == -1)
2054 "unable to fstat %s: %s",
2061 f_out
= fopen (dst_path
, "wb");
2065 "unable to open %s for writing: %s",
2072 while ( (sz_in
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2074 total_sz_in
+= sz_in
;
2075 size_t sz_out_remaining
= sz_in
;
2076 size_t sz_out_so_far
= 0;
2077 while (sz_out_remaining
)
2079 size_t sz_out
= fwrite (buf
+ sz_out_so_far
,
2083 gcc_assert (sz_out
<= sz_out_remaining
);
2087 "error writing to %s: %s",
2094 total_sz_out
+= sz_out
;
2095 sz_out_so_far
+= sz_out
;
2096 sz_out_remaining
-= sz_out
;
2098 gcc_assert (sz_out_so_far
== sz_in
);
2103 "error reading from %s: %s",
2109 gcc_assert (total_sz_in
== total_sz_out
);
2111 get_logger ()->log ("total bytes copied: %ld", total_sz_out
);
2113 /* Set the permissions of the copy to those of the original file,
2114 in particular the "executable" bits. */
2115 if (fchmod (fileno (f_out
), stat_buf
.st_mode
) == -1)
2117 "error setting mode of %s: %s",
2124 /* Helper functions for gcc::jit::playback::context::compile. */
2126 /* This mutex guards gcc::jit::recording::context::compile, so that only
2127 one thread can be accessing the bulk of GCC's state at once. */
2129 static pthread_mutex_t jit_mutex
= PTHREAD_MUTEX_INITIALIZER
;
2131 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2134 playback::context::acquire_mutex ()
2136 auto_timevar
tv (get_timer (), TV_JIT_ACQUIRING_MUTEX
);
2138 /* Acquire the big GCC mutex. */
2139 JIT_LOG_SCOPE (get_logger ());
2140 pthread_mutex_lock (&jit_mutex
);
2141 gcc_assert (active_playback_ctxt
== NULL
);
2142 active_playback_ctxt
= this;
2145 /* Release jit_mutex and clear the active playback ctxt. */
2148 playback::context::release_mutex ()
2150 /* Release the big GCC mutex. */
2151 JIT_LOG_SCOPE (get_logger ());
2152 gcc_assert (active_playback_ctxt
== this);
2153 active_playback_ctxt
= NULL
;
2154 pthread_mutex_unlock (&jit_mutex
);
2157 /* Callback used by gcc::jit::playback::context::make_fake_args when
2158 invoking driver_get_configure_time_options.
2159 Populate a vec <char * > with the configure-time options. */
2162 append_arg_from_driver (const char *option
, void *user_data
)
2164 gcc_assert (option
);
2165 gcc_assert (user_data
);
2166 vec
<char *> *argvec
= static_cast <vec
<char *> *> (user_data
);
2167 argvec
->safe_push (concat ("-", option
, NULL
));
2170 /* Build a fake argv for toplev::main from the options set
2171 by the user on the context . */
2175 make_fake_args (vec
<char *> *argvec
,
2176 const char *ctxt_progname
,
2177 vec
<recording::requested_dump
> *requested_dumps
)
2179 JIT_LOG_SCOPE (get_logger ());
2181 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2182 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2184 ADD_ARG (ctxt_progname
);
2185 ADD_ARG (get_path_c_file ());
2188 /* Handle int options: */
2189 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
))
2193 "unrecognized optimization level: %i",
2194 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
));
2213 /* What about -Os? */
2215 /* Handle bool options: */
2216 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2219 /* Suppress timing (and other) info. */
2220 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
))
2226 /* Aggressively garbage-collect, to shake out bugs: */
2227 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC
))
2229 ADD_ARG ("--param");
2230 ADD_ARG ("ggc-min-expand=0");
2231 ADD_ARG ("--param");
2232 ADD_ARG ("ggc-min-heapsize=0");
2235 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
))
2237 ADD_ARG ("-fdump-tree-all");
2238 ADD_ARG ("-fdump-rtl-all");
2239 ADD_ARG ("-fdump-ipa-all");
2242 /* Add "-fdump-" options for any calls to
2243 gcc_jit_context_enable_dump. */
2246 recording::requested_dump
*d
;
2247 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2249 char *arg
= concat ("-fdump-", d
->m_dumpname
, NULL
);
2250 ADD_ARG_TAKE_OWNERSHIP (arg
);
2254 /* PR jit/64810: Add any target-specific default options
2255 from OPTION_DEFAULT_SPECS, normally provided by the driver
2256 in the non-jit case.
2258 The target-specific code can define OPTION_DEFAULT_SPECS:
2259 default command options in the form of spec macros for the
2260 driver to expand ().
2262 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2263 if not overriden, injects the defaults as extra arguments to
2265 For the jit case, we need to add these arguments here. The
2266 input format (using the specs language) means that we have to run
2267 part of the driver code here (driver_get_configure_time_options).
2269 To avoid running the spec-expansion code every time, we just do
2270 it the first time (via a function-static flag), saving the result
2271 into a function-static vec.
2272 This flag and vec are global state (i.e. per-process).
2273 They are guarded by the jit mutex. */
2275 static bool have_configure_time_options
= false;
2276 static vec
<char *> configure_time_options
;
2278 if (have_configure_time_options
)
2279 log ("reusing cached configure-time options");
2282 have_configure_time_options
= true;
2283 log ("getting configure-time options from driver");
2284 driver_get_configure_time_options (append_arg_from_driver
,
2285 &configure_time_options
);
2292 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2293 log ("configure_time_options[%i]: %s", i
, opt
);
2295 /* configure_time_options should now contain the expanded options
2296 from OPTION_DEFAULT_SPECS (if any). */
2297 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2300 gcc_assert (opt
[0] == '-');
2306 ADD_ARG ("-ftime-report");
2308 /* Add any user-provided extra options, starting with any from
2310 m_recording_ctxt
->append_command_line_options (argvec
);
2313 #undef ADD_ARG_TAKE_OWNERSHIP
2316 /* The second half of the implementation of gcc_jit_context_enable_dump.
2317 Iterate through the requested dumps, reading the underlying files
2318 into heap-allocated buffers, writing pointers to the buffers into
2319 the char ** pointers provided by client code.
2320 Client code is responsible for calling free on the results. */
2324 extract_any_requested_dumps (vec
<recording::requested_dump
> *requested_dumps
)
2326 JIT_LOG_SCOPE (get_logger ());
2329 recording::requested_dump
*d
;
2330 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2332 dump_file_info
*dfi
;
2336 dfi
= g
->get_dumps ()->get_dump_file_info_by_switch (d
->m_dumpname
);
2339 add_error (NULL
, "unrecognized dump: %s", d
->m_dumpname
);
2343 filename
= g
->get_dumps ()->get_dump_file_name (dfi
);
2344 content
= read_dump_file (filename
);
2345 *(d
->m_out_ptr
) = content
;
2346 m_tempdir
->add_temp_file (filename
);
2350 /* Helper function for playback::context::extract_any_requested_dumps
2351 (itself for use in implementation of gcc_jit_context_enable_dump).
2353 Attempt to read the complete file at the given path, returning the
2354 bytes found there as a buffer.
2355 The caller is responsible for calling free on the result.
2356 Errors will be reported on the context, and lead to NULL being
2357 returned; an out-of-memory error will terminate the process. */
2360 playback::context::read_dump_file (const char *path
)
2362 char *result
= NULL
;
2363 size_t total_sz
= 0;
2368 f_in
= fopen (path
, "r");
2371 add_error (NULL
, "unable to open %s for reading", path
);
2375 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2377 size_t old_total_sz
= total_sz
;
2379 result
= reinterpret_cast <char *> (xrealloc (result
, total_sz
+ 1));
2380 memcpy (result
+ old_total_sz
, buf
, sz
);
2385 add_error (NULL
, "error reading from %s", path
);
2395 result
[total_sz
] = '\0';
2399 return xstrdup ("");
2402 /* Part of playback::context::compile ().
2404 We have a .s file; we want a .so file.
2405 We could reuse parts of gcc/gcc.c to do this.
2406 For now, just use the driver binary from the install, as
2407 named in gcc-driver-name.h
2408 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2412 convert_to_dso (const char *ctxt_progname
)
2414 JIT_LOG_SCOPE (get_logger ());
2416 invoke_driver (ctxt_progname
,
2417 m_tempdir
->get_path_s_file (),
2418 m_tempdir
->get_path_so_file (),
2420 true, /* bool shared, */
2421 true);/* bool run_linker */
2424 static const char * const gcc_driver_name
= GCC_DRIVER_NAME
;
2428 invoke_driver (const char *ctxt_progname
,
2429 const char *input_file
,
2430 const char *output_file
,
2435 JIT_LOG_SCOPE (get_logger ());
2437 bool embedded_driver
2438 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER
);
2440 /* Currently this lumps together both assembling and linking into
2442 auto_timevar
assemble_timevar (get_timer (), tv_id
);
2444 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2446 ADD_ARG (gcc_driver_name
);
2448 add_multilib_driver_arguments (&argvec
);
2451 ADD_ARG ("-shared");
2456 ADD_ARG (input_file
);
2458 ADD_ARG (output_file
);
2460 /* Don't use the linker plugin.
2461 If running with just a "make" and not a "make install", then we'd
2463 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2464 libto_plugin is a .la at build time, with it becoming installed with
2465 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2467 ADD_ARG ("-fno-use-linker-plugin");
2469 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2470 /* OS X's linker defaults to treating undefined symbols as errors.
2471 If the context has any imported functions or globals they will be
2472 undefined until the .so is dynamically-linked into the process.
2473 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2475 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2483 /* pex_one's error-handling requires pname to be non-NULL. */
2484 gcc_assert (ctxt_progname
);
2487 for (unsigned i
= 0; i
< argvec
.length (); i
++)
2488 get_logger ()->log ("argv[%i]: %s", i
, argvec
[i
]);
2490 if (embedded_driver
)
2491 invoke_embedded_driver (&argvec
);
2493 invoke_external_driver (ctxt_progname
, &argvec
);
2498 invoke_embedded_driver (const vec
<char *> *argvec
)
2500 JIT_LOG_SCOPE (get_logger ());
2501 driver
d (true, /* can_finalize */
2503 int result
= d
.main (argvec
->length (),
2504 const_cast <char **> (argvec
->address ()));
2507 add_error (NULL
, "error invoking gcc driver");
2512 invoke_external_driver (const char *ctxt_progname
,
2513 vec
<char *> *argvec
)
2515 JIT_LOG_SCOPE (get_logger ());
2517 int exit_status
= 0;
2520 /* pex argv arrays are NULL-terminated. */
2521 argvec
->safe_push (NULL
);
2523 errmsg
= pex_one (PEX_SEARCH
, /* int flags, */
2525 const_cast <char *const *> (argvec
->address ()),
2526 ctxt_progname
, /* const char *pname */
2527 NULL
, /* const char *outname */
2528 NULL
, /* const char *errname */
2529 &exit_status
, /* int *status */
2530 &err
); /* int *err*/
2533 add_error (NULL
, "error invoking gcc driver: %s", errmsg
);
2537 /* pex_one can return a NULL errmsg when the executable wasn't
2538 found (or doesn't exist), so trap these cases also. */
2539 if (exit_status
|| err
)
2542 "error invoking gcc driver: exit_status: %i err: %i",
2545 "whilst attempting to run a driver named: %s",
2554 /* Extract the target-specific MULTILIB_DEFAULTS to
2555 multilib_defaults_raw for use by
2556 playback::context::add_multilib_driver_arguments (). */
2558 #ifndef MULTILIB_DEFAULTS
2559 #define MULTILIB_DEFAULTS { "" }
2562 static const char *const multilib_defaults_raw
[] = MULTILIB_DEFAULTS
;
2564 /* Helper function for playback::context::invoke_driver ().
2566 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2567 a driver binary. We need to pass in options to the shared driver
2568 to get the appropriate assembler/linker options for this multilib
2573 add_multilib_driver_arguments (vec
<char *> *argvec
)
2575 JIT_LOG_SCOPE (get_logger ());
2577 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2578 prepending each with a "-". */
2579 for (size_t i
= 0; i
< ARRAY_SIZE (multilib_defaults_raw
); i
++)
2580 if (multilib_defaults_raw
[i
][0])
2581 argvec
->safe_push (concat ("-", multilib_defaults_raw
[i
], NULL
));
2584 /* Dynamically-link the built DSO file into this process, using dlopen.
2585 Wrap it up within a jit::result *, and return that.
2586 Return NULL if any errors occur, reporting them on this context. */
2592 JIT_LOG_SCOPE (get_logger ());
2593 auto_timevar
load_timevar (get_timer (), TV_LOAD
);
2594 void *handle
= NULL
;
2595 const char *error
= NULL
;
2596 result
*result_obj
= NULL
;
2598 /* Clear any existing error. */
2601 handle
= dlopen (m_tempdir
->get_path_so_file (),
2602 RTLD_NOW
| RTLD_LOCAL
);
2603 if ((error
= dlerror()) != NULL
) {
2604 add_error (NULL
, "%s", error
);
2608 /* We've successfully dlopened the result; create a
2609 jit::result object to wrap it.
2611 We're done with the tempdir for now, but if the user
2612 has requested debugging, the user's debugger might not
2613 be capable of dealing with the .so file being unlinked
2614 immediately, so keep it around until after the result
2615 is released. We do this by handing over ownership of
2616 the jit::tempdir to the result. See PR jit/64206. */
2617 tempdir
*handover_tempdir
;
2618 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2620 handover_tempdir
= m_tempdir
;
2622 /* The tempdir will eventually be cleaned up in the
2623 jit::result's dtor. */
2624 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2625 " handing over tempdir to jit::result");
2629 handover_tempdir
= NULL
;
2630 /* ... and retain ownership of m_tempdir so we clean it
2631 up it the playback::context's dtor. */
2632 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2633 " retaining ownership of tempdir");
2636 result_obj
= new result (get_logger (), handle
, handover_tempdir
);
2644 /* Top-level hook for playing back a recording context.
2646 This plays back m_recording_ctxt, and, if no errors
2647 occurred builds statement lists for and then postprocesses
2648 every function in the result. */
2654 JIT_LOG_SCOPE (get_logger ());
2655 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2656 tree array_domain_type
= build_index_type (size_int (200));
2657 m_char_array_type_node
2658 = build_array_type (char_type_node
, array_domain_type
);
2661 = build_pointer_type (build_qualified_type (char_type_node
,
2664 /* Replay the recorded events: */
2665 timevar_push (TV_JIT_REPLAY
);
2667 m_recording_ctxt
->replay_into (this);
2669 /* Clean away the temporary references from recording objects
2670 to playback objects. We have to do this now since the
2671 latter are GC-allocated, but the former don't mark these
2672 refs. Hence we must stop using them before the GC can run. */
2673 m_recording_ctxt
->disassociate_from_playback ();
2675 /* The builtins_manager, if any, is associated with the recording::context
2676 and might be reused for future compiles on other playback::contexts,
2677 but its m_attributes array is not GTY-labeled and hence will become
2678 nonsense if the GC runs. Purge this state. */
2679 builtins_manager
*bm
= get_builtins_manager ();
2681 bm
->finish_playback ();
2683 timevar_pop (TV_JIT_REPLAY
);
2685 if (!errors_occurred ())
2690 /* No GC can happen yet; process the cached source locations. */
2691 handle_locations ();
2693 /* We've now created tree nodes for the stmts in the various blocks
2694 in each function, but we haven't built each function's single stmt
2695 list yet. Do so now. */
2696 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2697 func
->build_stmt_list ();
2699 /* No GC can have happened yet. */
2701 /* Postprocess the functions. This could trigger GC. */
2702 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2705 func
->postprocess ();
2710 /* Dump the generated .s file to stderr. */
2714 dump_generated_code ()
2716 JIT_LOG_SCOPE (get_logger ());
2719 FILE *f_in
= fopen (get_path_s_file (), "r");
2723 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2724 fwrite (buf
, 1, sz
, stderr
);
2729 /* Get the supposed path of the notional "fake.c" file within the
2730 tempdir. This file doesn't exist, but the rest of the compiler
2735 get_path_c_file () const
2737 return m_tempdir
->get_path_c_file ();
2740 /* Get the path of the assembler output file "fake.s" file within the
2745 get_path_s_file () const
2747 return m_tempdir
->get_path_s_file ();
2750 /* Get the path of the DSO object file "fake.so" file within the
2755 get_path_so_file () const
2757 return m_tempdir
->get_path_so_file ();
2760 /* qsort comparator for comparing pairs of playback::source_line *,
2761 ordering them by line number. */
2764 line_comparator (const void *lhs
, const void *rhs
)
2766 const playback::source_line
*line_lhs
= \
2767 *static_cast<const playback::source_line
* const*> (lhs
);
2768 const playback::source_line
*line_rhs
= \
2769 *static_cast<const playback::source_line
* const*> (rhs
);
2770 return line_lhs
->get_line_num () - line_rhs
->get_line_num ();
2773 /* qsort comparator for comparing pairs of playback::location *,
2774 ordering them by column number. */
2777 location_comparator (const void *lhs
, const void *rhs
)
2779 const playback::location
*loc_lhs
= \
2780 *static_cast<const playback::location
* const *> (lhs
);
2781 const playback::location
*loc_rhs
= \
2782 *static_cast<const playback::location
* const *> (rhs
);
2783 return loc_lhs
->get_column_num () - loc_rhs
->get_column_num ();
2786 /* Our API allows locations to be created in arbitrary orders, but the
2787 linemap API requires locations to be created in ascending order
2788 as if we were tokenizing files.
2790 This hook sorts all of the locations that have been created, and
2791 calls into the linemap API, creating linemap entries in sorted order
2792 for our locations. */
2798 /* Create the source code locations, following the ordering rules
2799 imposed by the linemap API.
2801 line_table is a global. */
2802 JIT_LOG_SCOPE (get_logger ());
2806 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2808 linemap_add (line_table
, LC_ENTER
, false, file
->get_filename (), 0);
2810 /* Sort lines by ascending line numbers. */
2811 file
->m_source_lines
.qsort (&line_comparator
);
2815 FOR_EACH_VEC_ELT (file
->m_source_lines
, j
, line
)
2820 /* Sort locations in line by ascending column numbers. */
2821 line
->m_locations
.qsort (&location_comparator
);
2823 /* Determine maximum column within this line. */
2824 gcc_assert (line
->m_locations
.length () > 0);
2825 location
*final_column
=
2826 line
->m_locations
[line
->m_locations
.length () - 1];
2827 int max_col
= final_column
->get_column_num ();
2829 linemap_line_start (line_table
, line
->get_line_num (), max_col
);
2830 FOR_EACH_VEC_ELT (line
->m_locations
, k
, loc
)
2833 linemap_position_for_column (line_table
, loc
->get_column_num ());
2837 linemap_add (line_table
, LC_LEAVE
, false, NULL
, 0);
2840 /* line_table should now be populated; every playback::location should
2841 now have an m_srcloc. */
2843 /* Now assign them to tree nodes as appropriate. */
2844 std::pair
<tree
, location
*> *cached_location
;
2846 FOR_EACH_VEC_ELT (m_cached_locations
, i
, cached_location
)
2848 tree t
= cached_location
->first
;
2849 source_location srcloc
= cached_location
->second
->m_srcloc
;
2851 /* This covers expressions: */
2852 if (CAN_HAVE_LOCATION_P (t
))
2853 SET_EXPR_LOCATION (t
, srcloc
);
2854 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t
), TS_DECL_MINIMAL
))
2855 DECL_SOURCE_LOCATION (t
) = srcloc
;
2858 /* Don't know how to set location on this node. */
2863 /* We handle errors on a playback::context by adding them to the
2864 corresponding recording::context. */
2868 add_error (location
*loc
, const char *fmt
, ...)
2872 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2877 /* We handle errors on a playback::context by adding them to the
2878 corresponding recording::context. */
2882 add_error_va (location
*loc
, const char *fmt
, va_list ap
)
2884 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2888 /* Report a diagnostic up to the jit context as an error,
2889 so that the compilation is treated as a failure.
2890 For now, any kind of diagnostic is treated as an error by the jit
2895 add_diagnostic (struct diagnostic_context
*diag_context
,
2896 struct diagnostic_info
*diagnostic
)
2898 /* At this point the text has been formatted into the pretty-printer's
2900 pretty_printer
*pp
= diag_context
->printer
;
2901 const char *text
= pp_formatted_text (pp
);
2903 /* Get location information (if any) from the diagnostic.
2904 The recording::context::add_error[_va] methods require a
2905 recording::location. We can't lookup the playback::location
2906 from the file/line/column since any playback location instances
2907 may have been garbage-collected away by now, so instead we create
2908 another recording::location directly. */
2909 location_t gcc_loc
= diagnostic_location (diagnostic
);
2910 recording::location
*rec_loc
= NULL
;
2913 expanded_location exploc
= expand_location (gcc_loc
);
2915 rec_loc
= m_recording_ctxt
->new_location (exploc
.file
,
2921 m_recording_ctxt
->add_error (rec_loc
, "%s", text
);
2922 pp_clear_output_area (pp
);
2925 /* Dealing with the linemap API. */
2927 /* Construct a playback::location for a recording::location, if it
2928 doesn't exist already. */
2930 playback::location
*
2932 new_location (recording::location
*rloc
,
2933 const char *filename
,
2937 /* Get the source_file for filename, creating if necessary. */
2938 source_file
*src_file
= get_source_file (filename
);
2939 /* Likewise for the line within the file. */
2940 source_line
*src_line
= src_file
->get_source_line (line
);
2941 /* Likewise for the column within the line. */
2942 location
*loc
= src_line
->get_location (rloc
, column
);
2946 /* Deferred setting of the location for a given tree, by adding the
2947 (tree, playback::location) pair to a list of deferred associations.
2948 We will actually set the location on the tree later on once
2949 the source_location for the playback::location exists. */
2953 set_tree_location (tree t
, location
*loc
)
2956 m_cached_locations
.safe_push (std::make_pair (t
, loc
));
2960 /* Construct a playback::source_file for the given source
2961 filename, if it doesn't exist already. */
2963 playback::source_file
*
2965 get_source_file (const char *filename
)
2968 For simplicitly, this is currently a linear search.
2969 Replace with a hash if this shows up in the profile. */
2972 tree ident_filename
= get_identifier (filename
);
2974 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2975 if (file
->filename_as_tree () == ident_filename
)
2979 file
= new source_file (ident_filename
);
2980 m_source_files
.safe_push (file
);
2984 /* Constructor for gcc::jit::playback::source_file. */
2986 playback::source_file::source_file (tree filename
) :
2988 m_filename (filename
)
2992 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2996 playback::source_file::finalizer ()
2998 m_source_lines
.release ();
3001 /* Construct a playback::source_line for the given line
3002 within this source file, if one doesn't exist already. */
3004 playback::source_line
*
3005 playback::source_file::
3006 get_source_line (int line_num
)
3009 For simplicitly, this is currently a linear search.
3010 Replace with a hash if this shows up in the profile. */
3014 FOR_EACH_VEC_ELT (m_source_lines
, i
, line
)
3015 if (line
->get_line_num () == line_num
)
3019 line
= new source_line (this, line_num
);
3020 m_source_lines
.safe_push (line
);
3024 /* Constructor for gcc::jit::playback::source_line. */
3026 playback::source_line::source_line (source_file
*file
, int line_num
) :
3028 m_source_file (file
),
3029 m_line_num (line_num
)
3033 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3037 playback::source_line::finalizer ()
3039 m_locations
.release ();
3042 /* Construct a playback::location for the given column
3043 within this line of a specific source file, if one doesn't exist
3046 playback::location
*
3047 playback::source_line::
3048 get_location (recording::location
*rloc
, int column_num
)
3053 /* Another linear search that probably should be a hash table. */
3054 FOR_EACH_VEC_ELT (m_locations
, i
, loc
)
3055 if (loc
->get_column_num () == column_num
)
3059 loc
= new location (rloc
, this, column_num
);
3060 m_locations
.safe_push (loc
);
3064 /* Constructor for gcc::jit::playback::location. */
3066 playback::location::location (recording::location
*loc
,
3069 m_srcloc (UNKNOWN_LOCATION
),
3070 m_recording_loc (loc
),
3072 m_column_num(column_num
)
3076 /* The active gcc::jit::playback::context instance. This is a singleton,
3077 guarded by jit_mutex. */
3079 playback::context
*active_playback_ctxt
;
3081 } // namespace gcc::jit