1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2015 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
29 #include "statistics.h"
31 #include "double-int.h"
33 #include "fixed-value.h"
37 #include "tree-core.h"
42 #include "plugin-api.h"
47 #include "hard-reg-set.h"
57 #include "stringpool.h"
58 #include "stor-layout.h"
59 #include "print-tree.h"
61 #include "gcc-driver-name.h"
64 #include "fold-const.h"
67 #include "jit-common.h"
68 #include "jit-logging.h"
69 #include "jit-playback.h"
70 #include "jit-result.h"
71 #include "jit-builtins.h"
72 #include "jit-tempdir.h"
75 /* gcc::jit::playback::context::build_cast uses the convert.h API,
76 which in turn requires the frontend to provide a "convert"
77 function, apparently as a fallback.
79 Hence we provide this dummy one, with the requirement that any casts
80 are handled before reaching this. */
81 extern tree
convert (tree type
, tree expr
);
84 convert (tree dst_type
, tree expr
)
86 gcc_assert (gcc::jit::active_playback_ctxt
);
87 gcc::jit::active_playback_ctxt
->add_error (NULL
, "unhandled conversion");
88 fprintf (stderr
, "input expression:\n");
90 fprintf (stderr
, "requested type:\n");
91 debug_tree (dst_type
);
92 return error_mark_node
;
98 /**********************************************************************
100 **********************************************************************/
102 /* The constructor for gcc::jit::playback::context. */
104 playback::context::context (recording::context
*ctxt
)
105 : log_user (ctxt
->get_logger ()),
106 m_recording_ctxt (ctxt
),
108 m_char_array_type_node (NULL
),
109 m_const_char_ptr (NULL
)
111 JIT_LOG_SCOPE (get_logger ());
112 m_functions
.create (0);
113 m_globals
.create (0);
114 m_source_files
.create (0);
115 m_cached_locations
.create (0);
118 /* The destructor for gcc::jit::playback::context. */
120 playback::context::~context ()
122 JIT_LOG_SCOPE (get_logger ());
124 /* Normally the playback::context is responsible for cleaning up the
125 tempdir (including "fake.so" within the filesystem).
127 In the normal case, clean it up now.
129 However m_tempdir can be NULL if the context has handed over
130 responsibility for the tempdir cleanup to the jit::result object, so
131 that the cleanup can be delayed (see PR jit/64206). If that's the
132 case this "delete NULL;" is a no-op. */
135 m_functions
.release ();
138 /* A playback::context can reference GC-managed pointers. Mark them
139 ("by hand", rather than by gengtype).
141 This is called on the active playback context (if any) by the
142 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
150 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
152 if (ggc_test_and_set_mark (func
))
157 /* Given an enum gcc_jit_types value, get a "tree" type. */
160 get_tree_node_for_type (enum gcc_jit_types type_
)
164 case GCC_JIT_TYPE_VOID
:
165 return void_type_node
;
167 case GCC_JIT_TYPE_VOID_PTR
:
168 return ptr_type_node
;
170 case GCC_JIT_TYPE_BOOL
:
171 return boolean_type_node
;
173 case GCC_JIT_TYPE_CHAR
:
174 return char_type_node
;
175 case GCC_JIT_TYPE_SIGNED_CHAR
:
176 return signed_char_type_node
;
177 case GCC_JIT_TYPE_UNSIGNED_CHAR
:
178 return unsigned_char_type_node
;
180 case GCC_JIT_TYPE_SHORT
:
181 return short_integer_type_node
;
182 case GCC_JIT_TYPE_UNSIGNED_SHORT
:
183 return short_unsigned_type_node
;
185 case GCC_JIT_TYPE_CONST_CHAR_PTR
:
187 tree const_char
= build_qualified_type (char_type_node
,
189 return build_pointer_type (const_char
);
192 case GCC_JIT_TYPE_INT
:
193 return integer_type_node
;
194 case GCC_JIT_TYPE_UNSIGNED_INT
:
195 return unsigned_type_node
;
197 case GCC_JIT_TYPE_LONG
:
198 return long_integer_type_node
;
199 case GCC_JIT_TYPE_UNSIGNED_LONG
:
200 return long_unsigned_type_node
;
202 case GCC_JIT_TYPE_LONG_LONG
:
203 return long_long_integer_type_node
;
204 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG
:
205 return long_long_unsigned_type_node
;
207 case GCC_JIT_TYPE_FLOAT
:
208 return float_type_node
;
209 case GCC_JIT_TYPE_DOUBLE
:
210 return double_type_node
;
211 case GCC_JIT_TYPE_LONG_DOUBLE
:
212 return long_double_type_node
;
214 case GCC_JIT_TYPE_SIZE_T
:
215 return size_type_node
;
217 case GCC_JIT_TYPE_FILE_PTR
:
218 return fileptr_type_node
;
220 case GCC_JIT_TYPE_COMPLEX_FLOAT
:
221 return complex_float_type_node
;
222 case GCC_JIT_TYPE_COMPLEX_DOUBLE
:
223 return complex_double_type_node
;
224 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE
:
225 return complex_long_double_type_node
;
231 /* Construct a playback::type instance (wrapping a tree) for the given
236 get_type (enum gcc_jit_types type_
)
238 tree type_node
= get_tree_node_for_type (type_
);
239 if (NULL
== type_node
)
242 "unrecognized (enum gcc_jit_types) value: %i", type_
);
246 return new type (type_node
);
249 /* Construct a playback::type instance (wrapping a tree) for the given
254 new_array_type (playback::location
*loc
,
255 playback::type
*element_type
,
258 gcc_assert (element_type
);
260 tree t
= build_array_type_nelts (element_type
->as_tree (),
265 set_tree_location (t
, loc
);
270 /* Construct a playback::field instance (wrapping a tree). */
274 new_field (location
*loc
,
281 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
282 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
283 get_identifier (name
), type
->as_tree ());
286 set_tree_location (decl
, loc
);
288 return new field (decl
);
291 /* Construct a playback::compound_type instance (wrapping a tree). */
293 playback::compound_type
*
295 new_compound_type (location
*loc
,
297 bool is_struct
) /* else is union */
301 /* Compare with c/c-decl.c: start_struct. */
303 tree t
= make_node (is_struct
? RECORD_TYPE
: UNION_TYPE
);
304 TYPE_NAME (t
) = get_identifier (name
);
308 set_tree_location (t
, loc
);
310 return new compound_type (t
);
314 playback::compound_type::set_fields (const auto_vec
<playback::field
*> *fields
)
316 /* Compare with c/c-decl.c: finish_struct. */
319 tree fieldlist
= NULL
;
320 for (unsigned i
= 0; i
< fields
->length (); i
++)
322 field
*f
= (*fields
)[i
];
323 DECL_CONTEXT (f
->as_tree ()) = t
;
324 fieldlist
= chainon (f
->as_tree (), fieldlist
);
326 fieldlist
= nreverse (fieldlist
);
327 TYPE_FIELDS (t
) = fieldlist
;
332 /* Construct a playback::type instance (wrapping a tree) for a function
337 new_function_type (type
*return_type
,
338 const auto_vec
<type
*> *param_types
,
344 tree
*arg_types
= (tree
*)xcalloc(param_types
->length (), sizeof(tree
*));
346 FOR_EACH_VEC_ELT (*param_types
, i
, param_type
)
347 arg_types
[i
] = param_type
->as_tree ();
352 build_varargs_function_type_array (return_type
->as_tree (),
353 param_types
->length (),
356 fn_type
= build_function_type_array (return_type
->as_tree (),
357 param_types
->length (),
361 return new type (fn_type
);
364 /* Construct a playback::param instance (wrapping a tree). */
368 new_param (location
*loc
,
374 tree inner
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
375 get_identifier (name
), type
->as_tree ());
377 set_tree_location (inner
, loc
);
379 return new param (this, inner
);
382 /* Construct a playback::function instance. */
386 new_function (location
*loc
,
387 enum gcc_jit_function_kind kind
,
390 const auto_vec
<param
*> *params
,
392 enum built_in_function builtin_id
)
397 //can return_type be NULL?
400 tree
*arg_types
= (tree
*)xcalloc(params
->length (), sizeof(tree
*));
401 FOR_EACH_VEC_ELT (*params
, i
, param
)
402 arg_types
[i
] = TREE_TYPE (param
->as_tree ());
406 fn_type
= build_varargs_function_type_array (return_type
->as_tree (),
407 params
->length (), arg_types
);
409 fn_type
= build_function_type_array (return_type
->as_tree (),
410 params
->length (), arg_types
);
413 /* FIXME: this uses input_location: */
414 tree fndecl
= build_fn_decl (name
, fn_type
);
417 set_tree_location (fndecl
, loc
);
419 tree resdecl
= build_decl (UNKNOWN_LOCATION
, RESULT_DECL
,
420 NULL_TREE
, return_type
->as_tree ());
421 DECL_ARTIFICIAL (resdecl
) = 1;
422 DECL_IGNORED_P (resdecl
) = 1;
423 DECL_RESULT (fndecl
) = resdecl
;
427 DECL_FUNCTION_CODE (fndecl
) = builtin_id
;
428 gcc_assert (loc
== NULL
);
429 DECL_SOURCE_LOCATION (fndecl
) = BUILTINS_LOCATION
;
431 DECL_BUILT_IN_CLASS (fndecl
) =
432 builtins_manager::get_class (builtin_id
);
433 set_builtin_decl (builtin_id
, fndecl
,
434 builtins_manager::implicit_p (builtin_id
));
436 builtins_manager
*bm
= get_builtins_manager ();
437 tree attrs
= bm
->get_attrs_tree (builtin_id
);
439 decl_attributes (&fndecl
, attrs
, ATTR_FLAG_BUILT_IN
);
441 decl_attributes (&fndecl
, NULL_TREE
, 0);
444 if (kind
!= GCC_JIT_FUNCTION_IMPORTED
)
446 tree param_decl_list
= NULL
;
447 FOR_EACH_VEC_ELT (*params
, i
, param
)
449 param_decl_list
= chainon (param
->as_tree (), param_decl_list
);
452 /* The param list was created in reverse order; fix it: */
453 param_decl_list
= nreverse (param_decl_list
);
456 for (t
= param_decl_list
; t
; t
= DECL_CHAIN (t
))
458 DECL_CONTEXT (t
) = fndecl
;
459 DECL_ARG_TYPE (t
) = TREE_TYPE (t
);
462 /* Set it up on DECL_ARGUMENTS */
463 DECL_ARGUMENTS(fndecl
) = param_decl_list
;
466 if (kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
468 DECL_DECLARED_INLINE_P (fndecl
) = 1;
470 /* Add attribute "always_inline": */
471 DECL_ATTRIBUTES (fndecl
) =
472 tree_cons (get_identifier ("always_inline"),
474 DECL_ATTRIBUTES (fndecl
));
477 function
*func
= new function (this, fndecl
, kind
);
478 m_functions
.safe_push (func
);
482 /* Construct a playback::lvalue instance (wrapping a tree). */
486 new_global (location
*loc
,
487 enum gcc_jit_global_kind kind
,
493 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
494 get_identifier (name
),
496 TREE_PUBLIC (inner
) = (kind
!= GCC_JIT_GLOBAL_INTERNAL
);
497 DECL_COMMON (inner
) = 1;
503 case GCC_JIT_GLOBAL_EXPORTED
:
504 TREE_STATIC (inner
) = 1;
507 case GCC_JIT_GLOBAL_INTERNAL
:
508 TREE_STATIC (inner
) = 1;
511 case GCC_JIT_GLOBAL_IMPORTED
:
512 DECL_EXTERNAL (inner
) = 1;
517 set_tree_location (inner
, loc
);
519 varpool_node::get_create (inner
);
521 m_globals
.safe_push (inner
);
523 return new lvalue (this, inner
);
526 /* Implementation of the various
527 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
529 Each of these constructs a playback::rvalue instance (wrapping a tree).
531 These specializations are required to be in the same namespace
532 as the template, hence we now have to enter the gcc::jit::playback
538 /* Specialization of making an rvalue from a const, for host <int>. */
543 new_rvalue_from_const
<int> (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 <long>. */
567 new_rvalue_from_const
<long> (type
*type
,
570 // FIXME: type-checking, or coercion?
571 tree inner_type
= type
->as_tree ();
572 if (INTEGRAL_TYPE_P (inner_type
))
574 tree inner
= build_int_cst (inner_type
, value
);
575 return new rvalue (this, inner
);
579 REAL_VALUE_TYPE real_value
;
580 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
581 tree inner
= build_real (inner_type
, real_value
);
582 return new rvalue (this, inner
);
586 /* Specialization of making an rvalue from a const, for host <double>. */
591 new_rvalue_from_const
<double> (type
*type
,
594 // FIXME: type-checking, or coercion?
595 tree inner_type
= type
->as_tree ();
597 /* We have a "double", we want a REAL_VALUE_TYPE.
599 real.c:real_from_target appears to require the representation to be
600 split into 32-bit values, and then sent as an pair of host long
602 REAL_VALUE_TYPE real_value
;
606 uint32_t as_uint32s
[2];
609 long int as_long_ints
[2];
610 as_long_ints
[0] = u
.as_uint32s
[0];
611 as_long_ints
[1] = u
.as_uint32s
[1];
612 real_from_target (&real_value
, as_long_ints
, DFmode
);
613 tree inner
= build_real (inner_type
, real_value
);
614 return new rvalue (this, inner
);
617 /* Specialization of making an rvalue from a const, for host <void *>. */
622 new_rvalue_from_const
<void *> (type
*type
,
625 tree inner_type
= type
->as_tree ();
626 /* FIXME: how to ensure we have a wide enough type? */
627 tree inner
= build_int_cstu (inner_type
, (unsigned HOST_WIDE_INT
)value
);
628 return new rvalue (this, inner
);
631 /* We're done implementing the specializations of
632 gcc::jit::playback::context::new_rvalue_from_const <T>
633 so we can exit the gcc::jit::playback namespace. */
635 } // namespace playback
637 /* Construct a playback::rvalue instance (wrapping a tree). */
641 new_string_literal (const char *value
)
643 tree t_str
= build_string (strlen (value
), value
);
644 gcc_assert (m_char_array_type_node
);
645 TREE_TYPE (t_str
) = m_char_array_type_node
;
647 /* Convert to (const char*), loosely based on
648 c/c-typeck.c: array_to_pointer_conversion,
649 by taking address of start of string. */
650 tree t_addr
= build1 (ADDR_EXPR
, m_const_char_ptr
, t_str
);
652 return new rvalue (this, t_addr
);
655 /* Coerce a tree expression into a boolean tree expression. */
659 as_truth_value (tree expr
, location
*loc
)
661 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
662 tree typed_zero
= fold_build1 (CONVERT_EXPR
,
666 set_tree_location (typed_zero
, loc
);
668 expr
= build2 (NE_EXPR
, integer_type_node
, expr
, typed_zero
);
670 set_tree_location (expr
, loc
);
675 /* For use by jit_langhook_write_globals.
676 Calls varpool_node::finalize_decl on each global. */
680 write_global_decls_1 ()
682 /* Compare with e.g. the C frontend's c_write_global_declarations. */
683 JIT_LOG_SCOPE (get_logger ());
687 FOR_EACH_VEC_ELT (m_globals
, i
, decl
)
689 gcc_assert (TREE_CODE (decl
) == VAR_DECL
);
690 varpool_node::finalize_decl (decl
);
694 /* For use by jit_langhook_write_globals.
695 Calls debug_hooks->global_decl on each global. */
699 write_global_decls_2 ()
701 /* Compare with e.g. the C frontend's c_write_global_declarations_2. */
702 JIT_LOG_SCOPE (get_logger ());
706 FOR_EACH_VEC_ELT (m_globals
, i
, decl
)
708 gcc_assert (TREE_CODE (decl
) == VAR_DECL
);
709 debug_hooks
->global_decl (decl
);
714 /* Construct a playback::rvalue instance (wrapping a tree) for a
719 new_unary_op (location
*loc
,
720 enum gcc_jit_unary_op op
,
724 // FIXME: type-checking, or coercion?
725 enum tree_code inner_op
;
727 gcc_assert (result_type
);
730 tree node
= a
->as_tree ();
731 tree inner_result
= NULL
;
736 add_error (loc
, "unrecognized (enum gcc_jit_unary_op) value: %i", op
);
739 case GCC_JIT_UNARY_OP_MINUS
:
740 inner_op
= NEGATE_EXPR
;
743 case GCC_JIT_UNARY_OP_BITWISE_NEGATE
:
744 inner_op
= BIT_NOT_EXPR
;
747 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE
:
748 node
= as_truth_value (node
, loc
);
749 inner_result
= invert_truthvalue (node
);
751 set_tree_location (inner_result
, loc
);
752 return new rvalue (this, inner_result
);
754 case GCC_JIT_UNARY_OP_ABS
:
759 inner_result
= build1 (inner_op
,
760 result_type
->as_tree (),
763 set_tree_location (inner_result
, loc
);
765 return new rvalue (this, inner_result
);
768 /* Construct a playback::rvalue instance (wrapping a tree) for a
773 new_binary_op (location
*loc
,
774 enum gcc_jit_binary_op op
,
776 rvalue
*a
, rvalue
*b
)
778 // FIXME: type-checking, or coercion?
779 enum tree_code inner_op
;
781 gcc_assert (result_type
);
785 tree node_a
= a
->as_tree ();
786 tree node_b
= b
->as_tree ();
791 add_error (loc
, "unrecognized (enum gcc_jit_binary_op) value: %i", op
);
794 case GCC_JIT_BINARY_OP_PLUS
:
795 inner_op
= PLUS_EXPR
;
798 case GCC_JIT_BINARY_OP_MINUS
:
799 inner_op
= MINUS_EXPR
;
802 case GCC_JIT_BINARY_OP_MULT
:
803 inner_op
= MULT_EXPR
;
806 case GCC_JIT_BINARY_OP_DIVIDE
:
807 if (FLOAT_TYPE_P (result_type
->as_tree ()))
808 /* Floating-point division: */
809 inner_op
= RDIV_EXPR
;
811 /* Truncating to zero: */
812 inner_op
= TRUNC_DIV_EXPR
;
815 case GCC_JIT_BINARY_OP_MODULO
:
816 inner_op
= TRUNC_MOD_EXPR
;
819 case GCC_JIT_BINARY_OP_BITWISE_AND
:
820 inner_op
= BIT_AND_EXPR
;
823 case GCC_JIT_BINARY_OP_BITWISE_XOR
:
824 inner_op
= BIT_XOR_EXPR
;
827 case GCC_JIT_BINARY_OP_BITWISE_OR
:
828 inner_op
= BIT_IOR_EXPR
;
831 case GCC_JIT_BINARY_OP_LOGICAL_AND
:
832 node_a
= as_truth_value (node_a
, loc
);
833 node_b
= as_truth_value (node_b
, loc
);
834 inner_op
= TRUTH_ANDIF_EXPR
;
837 case GCC_JIT_BINARY_OP_LOGICAL_OR
:
838 node_a
= as_truth_value (node_a
, loc
);
839 node_b
= as_truth_value (node_b
, loc
);
840 inner_op
= TRUTH_ORIF_EXPR
;
843 case GCC_JIT_BINARY_OP_LSHIFT
:
844 inner_op
= LSHIFT_EXPR
;
847 case GCC_JIT_BINARY_OP_RSHIFT
:
848 inner_op
= RSHIFT_EXPR
;
852 tree inner_expr
= build2 (inner_op
,
853 result_type
->as_tree (),
857 set_tree_location (inner_expr
, loc
);
859 return new rvalue (this, inner_expr
);
862 /* Construct a playback::rvalue instance (wrapping a tree) for a
867 new_comparison (location
*loc
,
868 enum gcc_jit_comparison op
,
869 rvalue
*a
, rvalue
*b
)
871 // FIXME: type-checking, or coercion?
872 enum tree_code inner_op
;
880 add_error (loc
, "unrecognized (enum gcc_jit_comparison) value: %i", op
);
883 case GCC_JIT_COMPARISON_EQ
:
886 case GCC_JIT_COMPARISON_NE
:
889 case GCC_JIT_COMPARISON_LT
:
892 case GCC_JIT_COMPARISON_LE
:
895 case GCC_JIT_COMPARISON_GT
:
898 case GCC_JIT_COMPARISON_GE
:
903 tree inner_expr
= build2 (inner_op
,
908 set_tree_location (inner_expr
, loc
);
909 return new rvalue (this, inner_expr
);
912 /* Construct a playback::rvalue instance (wrapping a tree) for a
917 build_call (location
*loc
,
919 const auto_vec
<rvalue
*> *args
)
921 vec
<tree
, va_gc
> *tree_args
;
922 vec_alloc (tree_args
, args
->length ());
923 for (unsigned i
= 0; i
< args
->length (); i
++)
924 tree_args
->quick_push ((*args
)[i
]->as_tree ());
927 set_tree_location (fn_ptr
, loc
);
929 tree fn
= TREE_TYPE (fn_ptr
);
930 tree fn_type
= TREE_TYPE (fn
);
931 tree return_type
= TREE_TYPE (fn_type
);
933 return new rvalue (this,
934 build_call_vec (return_type
,
937 /* see c-typeck.c: build_function_call
938 which calls build_function_call_vec
940 which does lots of checking, then:
941 result = build_call_array_loc (loc, TREE_TYPE (fntype),
942 function, nargs, argarray);
944 (see also build_call_vec)
948 /* Construct a playback::rvalue instance (wrapping a tree) for a
949 call to a specific function. */
953 new_call (location
*loc
,
955 const auto_vec
<rvalue
*> *args
)
961 fndecl
= func
->as_fndecl ();
963 tree fntype
= TREE_TYPE (fndecl
);
965 tree fn
= build1 (ADDR_EXPR
, build_pointer_type (fntype
), fndecl
);
967 return build_call (loc
, fn
, args
);
970 /* Construct a playback::rvalue instance (wrapping a tree) for a
971 call through a function pointer. */
975 new_call_through_ptr (location
*loc
,
977 const auto_vec
<rvalue
*> *args
)
980 tree t_fn_ptr
= fn_ptr
->as_tree ();
982 return build_call (loc
, t_fn_ptr
, args
);
985 /* Construct a tree for a cast. */
988 playback::context::build_cast (playback::location
*loc
,
989 playback::rvalue
*expr
,
990 playback::type
*type_
)
992 /* For comparison, see:
993 - c/c-typeck.c:build_c_cast
994 - c/c-convert.c: convert
997 Only some kinds of cast are currently supported here. */
998 tree t_expr
= expr
->as_tree ();
999 tree t_dst_type
= type_
->as_tree ();
1001 t_ret
= targetm
.convert_to_type (t_dst_type
, t_expr
);
1004 enum tree_code dst_code
= TREE_CODE (t_dst_type
);
1009 t_ret
= convert_to_integer (t_dst_type
, t_expr
);
1013 /* Compare with c_objc_common_truthvalue_conversion and
1014 c_common_truthvalue_conversion. */
1015 /* For now, convert to: (t_expr != 0) */
1016 t_ret
= build2 (NE_EXPR
, t_dst_type
,
1018 build_int_cst (TREE_TYPE (t_expr
), 0));
1022 t_ret
= convert_to_real (t_dst_type
, t_expr
);
1026 t_ret
= build1 (NOP_EXPR
, t_dst_type
, t_expr
);
1030 add_error (loc
, "couldn't handle cast during playback");
1031 fprintf (stderr
, "input expression:\n");
1032 debug_tree (t_expr
);
1033 fprintf (stderr
, "requested type:\n");
1034 debug_tree (t_dst_type
);
1035 return error_mark_node
;
1038 if (TREE_CODE (t_ret
) != C_MAYBE_CONST_EXPR
)
1039 t_ret
= fold (t_ret
);
1044 /* Construct a playback::rvalue instance (wrapping a tree) for a
1049 new_cast (playback::location
*loc
,
1050 playback::rvalue
*expr
,
1051 playback::type
*type_
)
1054 tree t_cast
= build_cast (loc
, expr
, type_
);
1056 set_tree_location (t_cast
, loc
);
1057 return new rvalue (this, t_cast
);
1060 /* Construct a playback::lvalue instance (wrapping a tree) for an
1065 new_array_access (location
*loc
,
1072 /* For comparison, see:
1073 c/c-typeck.c: build_array_ref
1074 c-family/c-common.c: pointer_int_sum
1076 tree t_ptr
= ptr
->as_tree ();
1077 tree t_index
= index
->as_tree ();
1078 tree t_type_ptr
= TREE_TYPE (t_ptr
);
1079 tree t_type_star_ptr
= TREE_TYPE (t_type_ptr
);
1081 if (TREE_CODE (t_type_ptr
) == ARRAY_TYPE
)
1083 tree t_result
= build4 (ARRAY_REF
, t_type_star_ptr
, t_ptr
, t_index
,
1084 NULL_TREE
, NULL_TREE
);
1086 set_tree_location (t_result
, loc
);
1087 return new lvalue (this, t_result
);
1091 /* Convert index to an offset in bytes. */
1092 tree t_sizeof
= size_in_bytes (t_type_star_ptr
);
1093 t_index
= fold_build1 (CONVERT_EXPR
, sizetype
, t_index
);
1094 tree t_offset
= build2 (MULT_EXPR
, sizetype
, t_index
, t_sizeof
);
1096 /* Locate (ptr + offset). */
1097 tree t_address
= build2 (POINTER_PLUS_EXPR
, t_type_ptr
, t_ptr
, t_offset
);
1099 tree t_indirection
= build1 (INDIRECT_REF
, t_type_star_ptr
, t_address
);
1102 set_tree_location (t_sizeof
, loc
);
1103 set_tree_location (t_offset
, loc
);
1104 set_tree_location (t_address
, loc
);
1105 set_tree_location (t_indirection
, loc
);
1108 return new lvalue (this, t_indirection
);
1112 /* Construct a tree for a field access. */
1116 new_field_access (location
*loc
,
1123 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1124 build_component_ref. */
1125 tree type
= TREE_TYPE (datum
);
1127 gcc_assert (TREE_CODE (type
) != POINTER_TYPE
);
1129 tree t_field
= field
->as_tree ();
1130 tree ref
= build3 (COMPONENT_REF
, TREE_TYPE (t_field
), datum
,
1131 t_field
, NULL_TREE
);
1133 set_tree_location (ref
, loc
);
1137 /* Construct a tree for a dereference. */
1141 new_dereference (tree ptr
,
1146 tree type
= TREE_TYPE (TREE_TYPE(ptr
));
1147 tree datum
= build1 (INDIRECT_REF
, type
, ptr
);
1149 set_tree_location (datum
, loc
);
1153 /* Construct a playback::lvalue instance (wrapping a tree) for a
1158 access_field (location
*loc
,
1161 tree datum
= as_tree ();
1162 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1165 return new lvalue (get_context (), ref
);
1168 /* Construct a playback::rvalue instance (wrapping a tree) for a
1173 access_field (location
*loc
,
1176 tree datum
= as_tree ();
1177 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1180 return new rvalue (get_context (), ref
);
1183 /* Construct a playback::lvalue instance (wrapping a tree) for a
1184 dereferenced field access. */
1188 dereference_field (location
*loc
,
1191 tree ptr
= as_tree ();
1192 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1195 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1198 return new lvalue (get_context (), ref
);
1201 /* Construct a playback::lvalue instance (wrapping a tree) for a
1206 dereference (location
*loc
)
1208 tree ptr
= as_tree ();
1209 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1210 return new lvalue (get_context (), datum
);
1213 /* Construct a playback::rvalue instance (wrapping a tree) for an
1218 get_address (location
*loc
)
1220 tree t_lvalue
= as_tree ();
1221 tree t_thistype
= TREE_TYPE (t_lvalue
);
1222 tree t_ptrtype
= build_pointer_type (t_thistype
);
1223 tree ptr
= build1 (ADDR_EXPR
, t_ptrtype
, t_lvalue
);
1225 get_context ()->set_tree_location (ptr
, loc
);
1226 return new rvalue (get_context (), ptr
);
1229 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1230 Provide this finalization hook for calling then they are collected,
1231 which calls the finalizer vfunc. This allows them to call "release"
1232 on any vec<> within them. */
1235 wrapper_finalizer (void *ptr
)
1237 playback::wrapper
*wrapper
= reinterpret_cast <playback::wrapper
*> (ptr
);
1238 wrapper
->finalizer ();
1241 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1242 allocate them using ggc_internal_cleared_alloc. */
1246 operator new (size_t sz
)
1248 return ggc_internal_cleared_alloc (sz
, wrapper_finalizer
, 0, 1);
1252 /* Constructor for gcc:jit::playback::function. */
1254 playback::function::
1255 function (context
*ctxt
,
1257 enum gcc_jit_function_kind kind
)
1259 m_inner_fndecl (fndecl
),
1260 m_inner_bind_expr (NULL
),
1263 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1265 /* Create a BIND_EXPR, and within it, a statement list. */
1266 m_stmt_list
= alloc_stmt_list ();
1267 m_stmt_iter
= tsi_start (m_stmt_list
);
1268 m_inner_block
= make_node (BLOCK
);
1270 build3 (BIND_EXPR
, void_type_node
, NULL
, m_stmt_list
, m_inner_block
);
1274 m_inner_block
= NULL
;
1279 /* Hand-written GC-marking hook for playback functions. */
1282 playback::function::
1285 gt_ggc_m_9tree_node (m_inner_fndecl
);
1286 gt_ggc_m_9tree_node (m_inner_bind_expr
);
1287 gt_ggc_m_9tree_node (m_stmt_list
);
1288 gt_ggc_m_9tree_node (m_inner_block
);
1291 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1295 playback::function::finalizer ()
1297 m_blocks
.release ();
1300 /* Get the return type of a playback function, in tree form. */
1303 playback::function::
1304 get_return_type_as_tree () const
1306 return TREE_TYPE (TREE_TYPE(m_inner_fndecl
));
1309 /* Construct a new local within this playback::function. */
1312 playback::function::
1313 new_local (location
*loc
,
1319 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
1320 get_identifier (name
),
1322 DECL_CONTEXT (inner
) = this->m_inner_fndecl
;
1324 /* Prepend to BIND_EXPR_VARS: */
1325 DECL_CHAIN (inner
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1326 BIND_EXPR_VARS (m_inner_bind_expr
) = inner
;
1329 set_tree_location (inner
, loc
);
1330 return new lvalue (m_ctxt
, inner
);
1333 /* Construct a new block within this playback::function. */
1336 playback::function::
1337 new_block (const char *name
)
1339 gcc_assert (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
);
1341 block
*result
= new playback::block (this, name
);
1342 m_blocks
.safe_push (result
);
1346 /* Build a statement list for the function as a whole out of the
1347 lists of statements for the individual blocks, building labels
1351 playback::function::
1357 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1359 FOR_EACH_VEC_ELT (m_blocks
, i
, b
)
1364 b
->m_label_expr
= build1 (LABEL_EXPR
,
1366 b
->as_label_decl ());
1367 tsi_link_after (&m_stmt_iter
, b
->m_label_expr
, TSI_CONTINUE_LINKING
);
1369 FOR_EACH_VEC_ELT (b
->m_stmts
, j
, stmt
)
1370 tsi_link_after (&m_stmt_iter
, stmt
, TSI_CONTINUE_LINKING
);
1374 /* Finish compiling the given function, potentially running the
1376 The function will have a statement list by now.
1377 Amongst other things, this gimplifies the statement list,
1378 and calls cgraph_node::finalize_function on the function. */
1381 playback::function::
1384 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1386 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
))
1387 debug_tree (m_stmt_list
);
1389 /* Do we need this to force cgraphunit.c to output the function? */
1390 if (m_kind
== GCC_JIT_FUNCTION_EXPORTED
)
1392 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1393 DECL_PRESERVE_P (m_inner_fndecl
) = 1;
1396 if (m_kind
== GCC_JIT_FUNCTION_INTERNAL
1397 ||m_kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
1399 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1400 TREE_PUBLIC (m_inner_fndecl
) = 0;
1403 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1405 /* Seem to need this in gimple-low.c: */
1406 gcc_assert (m_inner_block
);
1407 DECL_INITIAL (m_inner_fndecl
) = m_inner_block
;
1409 /* how to add to function? the following appears to be how to
1410 set the body of a m_inner_fndecl: */
1411 DECL_SAVED_TREE(m_inner_fndecl
) = m_inner_bind_expr
;
1413 /* Ensure that locals appear in the debuginfo. */
1414 BLOCK_VARS (m_inner_block
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1416 //debug_tree (m_inner_fndecl);
1418 /* Convert to gimple: */
1419 //printf("about to gimplify_function_tree\n");
1420 gimplify_function_tree (m_inner_fndecl
);
1421 //printf("finished gimplify_function_tree\n");
1423 current_function_decl
= m_inner_fndecl
;
1424 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
))
1425 dump_function_to_file (m_inner_fndecl
, stderr
, TDF_VOPS
|TDF_MEMSYMS
|TDF_LINENO
);
1426 //debug_tree (m_inner_fndecl);
1428 //printf("about to add to cgraph\n");
1429 /* Add to cgraph: */
1430 cgraph_node::finalize_function (m_inner_fndecl
, false);
1431 /* This can trigger a collection, so we need to have all of
1432 the funcs as roots. */
1434 current_function_decl
= NULL
;
1438 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1442 playback::block::finalizer ()
1447 /* Add an eval of the rvalue to the function's statement list. */
1451 add_eval (location
*loc
,
1454 gcc_assert (rvalue
);
1457 set_tree_location (rvalue
->as_tree (), loc
);
1459 add_stmt (rvalue
->as_tree ());
1462 /* Add an assignment to the function's statement list. */
1466 add_assignment (location
*loc
,
1470 gcc_assert (lvalue
);
1471 gcc_assert (rvalue
);
1473 tree t_lvalue
= lvalue
->as_tree ();
1474 tree t_rvalue
= rvalue
->as_tree ();
1475 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1477 t_rvalue
= build1 (CONVERT_EXPR
,
1478 TREE_TYPE (t_lvalue
),
1481 set_tree_location (t_rvalue
, loc
);
1485 build2 (MODIFY_EXPR
, TREE_TYPE (t_lvalue
),
1486 t_lvalue
, t_rvalue
);
1488 set_tree_location (stmt
, loc
);
1492 /* Add a comment to the function's statement list.
1493 For now this is done by adding a dummy label. */
1497 add_comment (location
*loc
,
1500 /* Wrap the text in C-style comment delimiters. */
1502 (3 /* opening delim */
1504 + 3 /* closing delim */
1505 + 1 /* terminator */);
1506 char *wrapped
= (char *)ggc_internal_alloc (sz
);
1507 snprintf (wrapped
, sz
, "/* %s */", text
);
1509 /* For now we simply implement this by adding a dummy label with a name
1510 containing the given text. */
1511 tree identifier
= get_identifier (wrapped
);
1512 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1513 identifier
, void_type_node
);
1514 DECL_CONTEXT (label_decl
) = m_func
->as_fndecl ();
1516 tree label_expr
= build1 (LABEL_EXPR
, void_type_node
, label_decl
);
1518 set_tree_location (label_expr
, loc
);
1519 add_stmt (label_expr
);
1522 /* Add a conditional jump statement to the function's statement list. */
1526 add_conditional (location
*loc
,
1531 gcc_assert (boolval
);
1532 gcc_assert (on_true
);
1533 gcc_assert (on_false
);
1535 /* COND_EXPR wants statement lists for the true/false operands, but we
1537 Shim it by creating jumps to the labels */
1538 tree true_jump
= build1 (GOTO_EXPR
, void_type_node
,
1539 on_true
->as_label_decl ());
1541 set_tree_location (true_jump
, loc
);
1543 tree false_jump
= build1 (GOTO_EXPR
, void_type_node
,
1544 on_false
->as_label_decl ());
1546 set_tree_location (false_jump
, loc
);
1549 build3 (COND_EXPR
, void_type_node
, boolval
->as_tree (),
1550 true_jump
, false_jump
);
1552 set_tree_location (stmt
, loc
);
1556 /* Add an unconditional jump statement to the function's statement list. */
1560 add_jump (location
*loc
,
1563 gcc_assert (target
);
1565 // see c_finish_loop
1566 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1569 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1570 TREE_USED (target
->as_label_decl ()) = 1;
1571 tree stmt
= build1 (GOTO_EXPR
, void_type_node
, target
->as_label_decl ());
1573 set_tree_location (stmt
, loc
);
1579 c_finish_goto_label (location_t loc, tree label)
1581 tree decl = lookup_label_for_goto (loc, label);
1584 TREE_USED (decl) = 1;
1586 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1587 SET_EXPR_LOCATION (t, loc);
1588 return add_stmt (t);
1595 /* Add a return statement to the function's statement list. */
1599 add_return (location
*loc
,
1602 tree modify_retval
= NULL
;
1603 tree return_type
= m_func
->get_return_type_as_tree ();
1606 tree t_lvalue
= DECL_RESULT (m_func
->as_fndecl ());
1607 tree t_rvalue
= rvalue
->as_tree ();
1608 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1609 t_rvalue
= build1 (CONVERT_EXPR
,
1610 TREE_TYPE (t_lvalue
),
1612 modify_retval
= build2 (MODIFY_EXPR
, return_type
,
1613 t_lvalue
, t_rvalue
);
1615 set_tree_location (modify_retval
, loc
);
1617 tree return_stmt
= build1 (RETURN_EXPR
, return_type
,
1620 set_tree_location (return_stmt
, loc
);
1622 add_stmt (return_stmt
);
1625 /* Constructor for gcc::jit::playback::block. */
1628 block (function
*func
,
1638 identifier
= get_identifier (name
);
1641 m_label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1642 identifier
, void_type_node
);
1643 DECL_CONTEXT (m_label_decl
) = func
->as_fndecl ();
1644 m_label_expr
= NULL
;
1647 /* A subclass of auto_vec <char *> that frees all of its elements on
1650 class auto_argvec
: public auto_vec
<char *>
1656 /* auto_argvec's dtor, freeing all contained strings, automatically
1657 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1659 auto_argvec::~auto_argvec ()
1663 FOR_EACH_VEC_ELT (*this, i
, str
)
1667 /* Compile a playback::context:
1669 - Use the context's options to cconstruct command-line options, and
1670 call into the rest of GCC (toplev::main).
1671 - Assuming it succeeds, we have a .s file; we want a .so file.
1672 Invoke another gcc to convert the .s file to a .so file.
1673 - dlopen the .so file
1674 - Wrap the result up as a playback::result and return it. */
1680 JIT_LOG_SCOPE (get_logger ());
1682 const char *ctxt_progname
;
1683 result
*result_obj
= NULL
;
1685 int keep_intermediates
=
1686 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
);
1688 m_tempdir
= new tempdir (get_logger (), keep_intermediates
);
1689 if (!m_tempdir
->create ())
1692 /* Call into the rest of gcc.
1693 For now, we have to assemble command-line options to pass into
1694 toplev::main, so that they can be parsed. */
1696 /* Pass in user-provided program name as argv0, if any, so that it
1697 makes it into GCC's "progname" global, used in various diagnostics. */
1698 ctxt_progname
= get_str_option (GCC_JIT_STR_OPTION_PROGNAME
);
1701 ctxt_progname
= "libgccjit.so";
1703 auto_vec
<recording::requested_dump
> requested_dumps
;
1704 m_recording_ctxt
->get_all_requested_dumps (&requested_dumps
);
1706 auto_argvec fake_args
;
1707 make_fake_args (&fake_args
, ctxt_progname
, &requested_dumps
);
1708 if (errors_occurred ())
1711 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1714 /* This runs the compiler. */
1715 toplev
toplev (false);
1716 enter_scope ("toplev::main");
1718 for (unsigned i
= 0; i
< fake_args
.length (); i
++)
1719 get_logger ()->log ("argv[%i]: %s", i
, fake_args
[i
]);
1720 toplev
.main (fake_args
.length (),
1721 const_cast <char **> (fake_args
.address ()));
1722 exit_scope ("toplev::main");
1724 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1725 need to do it between toplev::main (which creates the dump manager)
1726 and toplev::finalize (which deletes it). */
1727 extract_any_requested_dumps (&requested_dumps
);
1729 /* Clean up the compiler. */
1730 enter_scope ("toplev::finalize");
1732 exit_scope ("toplev::finalize");
1734 /* Ideally we would release the jit mutex here, but we can't yet since
1735 followup activities use timevars, which are global state. */
1737 if (errors_occurred ())
1743 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
))
1744 dump_generated_code ();
1746 convert_to_dso (ctxt_progname
);
1747 if (errors_occurred ())
1753 result_obj
= dlopen_built_dso ();
1760 /* Helper functions for gcc::jit::playback::context::compile. */
1762 /* This mutex guards gcc::jit::recording::context::compile, so that only
1763 one thread can be accessing the bulk of GCC's state at once. */
1765 static pthread_mutex_t jit_mutex
= PTHREAD_MUTEX_INITIALIZER
;
1767 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
1770 playback::context::acquire_mutex ()
1772 /* Acquire the big GCC mutex. */
1773 JIT_LOG_SCOPE (get_logger ());
1774 pthread_mutex_lock (&jit_mutex
);
1775 gcc_assert (NULL
== active_playback_ctxt
);
1776 active_playback_ctxt
= this;
1779 /* Release jit_mutex and clear the active playback ctxt. */
1782 playback::context::release_mutex ()
1784 /* Release the big GCC mutex. */
1785 JIT_LOG_SCOPE (get_logger ());
1786 gcc_assert (active_playback_ctxt
== this);
1787 active_playback_ctxt
= NULL
;
1788 pthread_mutex_unlock (&jit_mutex
);
1791 /* Build a fake argv for toplev::main from the options set
1792 by the user on the context . */
1796 make_fake_args (vec
<char *> *argvec
,
1797 const char *ctxt_progname
,
1798 vec
<recording::requested_dump
> *requested_dumps
)
1800 JIT_LOG_SCOPE (get_logger ());
1802 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
1803 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
1805 ADD_ARG (ctxt_progname
);
1806 ADD_ARG (get_path_c_file ());
1809 /* Handle int options: */
1810 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
))
1814 "unrecognized optimization level: %i",
1815 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
));
1834 /* What about -Os? */
1836 /* Handle bool options: */
1837 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
1840 /* Suppress timing (and other) info. */
1841 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
))
1847 /* Aggressively garbage-collect, to shake out bugs: */
1848 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC
))
1850 ADD_ARG ("--param");
1851 ADD_ARG ("ggc-min-expand=0");
1852 ADD_ARG ("--param");
1853 ADD_ARG ("ggc-min-heapsize=0");
1856 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
))
1858 ADD_ARG ("-fdump-tree-all");
1859 ADD_ARG ("-fdump-rtl-all");
1860 ADD_ARG ("-fdump-ipa-all");
1863 /* Add "-fdump-" options for any calls to
1864 gcc_jit_context_enable_dump. */
1867 recording::requested_dump
*d
;
1868 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
1870 char *arg
= concat ("-fdump-", d
->m_dumpname
, NULL
);
1871 ADD_ARG_TAKE_OWNERSHIP (arg
);
1876 #undef ADD_ARG_TAKE_OWNERSHIP
1879 /* The second half of the implementation of gcc_jit_context_enable_dump.
1880 Iterate through the requested dumps, reading the underlying files
1881 into heap-allocated buffers, writing pointers to the buffers into
1882 the char ** pointers provided by client code.
1883 Client code is responsible for calling free on the results. */
1887 extract_any_requested_dumps (vec
<recording::requested_dump
> *requested_dumps
)
1889 JIT_LOG_SCOPE (get_logger ());
1892 recording::requested_dump
*d
;
1893 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
1895 dump_file_info
*dfi
;
1899 dfi
= g
->get_dumps ()->get_dump_file_info_by_switch (d
->m_dumpname
);
1902 add_error (NULL
, "unrecognized dump: %s", d
->m_dumpname
);
1906 filename
= g
->get_dumps ()->get_dump_file_name (dfi
);
1907 content
= read_dump_file (filename
);
1908 *(d
->m_out_ptr
) = content
;
1913 /* Helper function for playback::context::extract_any_requested_dumps
1914 (itself for use in implementation of gcc_jit_context_enable_dump).
1916 Attempt to read the complete file at the given path, returning the
1917 bytes found there as a buffer.
1918 The caller is responsible for calling free on the result.
1919 Errors will be reported on the context, and lead to NULL being
1920 returned; an out-of-memory error will terminate the process. */
1923 playback::context::read_dump_file (const char *path
)
1925 char *result
= NULL
;
1926 size_t total_sz
= 0;
1931 f_in
= fopen (path
, "r");
1934 add_error (NULL
, "unable to open %s for reading", path
);
1938 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
1940 size_t old_total_sz
= total_sz
;
1942 result
= reinterpret_cast <char *> (xrealloc (result
, total_sz
+ 1));
1943 memcpy (result
+ old_total_sz
, buf
, sz
);
1948 add_error (NULL
, "error reading from %s", path
);
1957 result
[total_sz
] = '\0';
1961 return xstrdup ("");
1964 /* Part of playback::context::compile ().
1966 We have a .s file; we want a .so file.
1967 We could reuse parts of gcc/gcc.c to do this.
1968 For now, just use the driver binary from the install, as
1969 named in gcc-driver-name.h
1970 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
1974 convert_to_dso (const char *ctxt_progname
)
1976 JIT_LOG_SCOPE (get_logger ());
1977 /* Currently this lumps together both assembling and linking into
1979 auto_timevar
assemble_timevar (TV_ASSEMBLE
);
1981 auto_vec
<const char *> argvec
;
1982 #define ADD_ARG(arg) argvec.safe_push (arg)
1983 int exit_status
= 0;
1985 const char *gcc_driver_name
= GCC_DRIVER_NAME
;
1987 ADD_ARG (gcc_driver_name
);
1988 ADD_ARG ("-shared");
1989 /* The input: assembler. */
1990 ADD_ARG (m_tempdir
->get_path_s_file ());
1991 /* The output: shared library. */
1993 ADD_ARG (m_tempdir
->get_path_so_file ());
1995 /* Don't use the linker plugin.
1996 If running with just a "make" and not a "make install", then we'd
1998 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
1999 libto_plugin is a .la at build time, with it becoming installed with
2000 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2002 ADD_ARG ("-fno-use-linker-plugin");
2004 /* pex argv arrays are NULL-terminated. */
2007 /* pex_one's error-handling requires pname to be non-NULL. */
2008 gcc_assert (ctxt_progname
);
2011 for (unsigned i
= 0; i
< argvec
.length (); i
++)
2012 get_logger ()->log ("argv[%i]: %s", i
, argvec
[i
]);
2014 errmsg
= pex_one (PEX_SEARCH
, /* int flags, */
2016 const_cast <char *const *> (argvec
.address ()),
2017 ctxt_progname
, /* const char *pname */
2018 NULL
, /* const char *outname */
2019 NULL
, /* const char *errname */
2020 &exit_status
, /* int *status */
2021 &err
); /* int *err*/
2024 add_error (NULL
, "error invoking gcc driver: %s", errmsg
);
2028 /* pex_one can return a NULL errmsg when the executable wasn't
2029 found (or doesn't exist), so trap these cases also. */
2030 if (exit_status
|| err
)
2033 "error invoking gcc driver: exit_status: %i err: %i",
2036 "whilst attempting to run a driver named: %s",
2046 /* Dynamically-link the built DSO file into this process, using dlopen.
2047 Wrap it up within a jit::result *, and return that.
2048 Return NULL if any errors occur, reporting them on this context. */
2054 JIT_LOG_SCOPE (get_logger ());
2055 auto_timevar
load_timevar (TV_LOAD
);
2056 void *handle
= NULL
;
2057 const char *error
= NULL
;
2058 result
*result_obj
= NULL
;
2060 /* Clear any existing error. */
2063 handle
= dlopen (m_tempdir
->get_path_so_file (),
2064 RTLD_NOW
| RTLD_LOCAL
);
2065 if ((error
= dlerror()) != NULL
) {
2066 add_error (NULL
, "%s", error
);
2070 /* We've successfully dlopened the result; create a
2071 jit::result object to wrap it.
2073 We're done with the tempdir for now, but if the user
2074 has requested debugging, the user's debugger might not
2075 be capable of dealing with the .so file being unlinked
2076 immediately, so keep it around until after the result
2077 is released. We do this by handing over ownership of
2078 the jit::tempdir to the result. See PR jit/64206. */
2079 tempdir
*handover_tempdir
;
2080 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2082 handover_tempdir
= m_tempdir
;
2084 /* The tempdir will eventually be cleaned up in the
2085 jit::result's dtor. */
2086 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2087 " handing over tempdir to jit::result");
2091 handover_tempdir
= NULL
;
2092 /* ... and retain ownership of m_tempdir so we clean it
2093 up it the playback::context's dtor. */
2094 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2095 " retaining ownership of tempdir");
2098 result_obj
= new result (get_logger (), handle
, handover_tempdir
);
2106 /* Top-level hook for playing back a recording context.
2108 This plays back m_recording_ctxt, and, if no errors
2109 occurred builds statement lists for and then postprocesses
2110 every function in the result. */
2116 JIT_LOG_SCOPE (get_logger ());
2117 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2118 tree array_domain_type
= build_index_type (size_int (200));
2119 m_char_array_type_node
2120 = build_array_type (char_type_node
, array_domain_type
);
2123 = build_pointer_type (build_qualified_type (char_type_node
,
2126 /* Replay the recorded events: */
2127 timevar_push (TV_JIT_REPLAY
);
2129 m_recording_ctxt
->replay_into (this);
2131 /* Clean away the temporary references from recording objects
2132 to playback objects. We have to do this now since the
2133 latter are GC-allocated, but the former don't mark these
2134 refs. Hence we must stop using them before the GC can run. */
2135 m_recording_ctxt
->disassociate_from_playback ();
2137 /* The builtins_manager, if any, is associated with the recording::context
2138 and might be reused for future compiles on other playback::contexts,
2139 but its m_attributes array is not GTY-labeled and hence will become
2140 nonsense if the GC runs. Purge this state. */
2141 builtins_manager
*bm
= get_builtins_manager ();
2143 bm
->finish_playback ();
2145 timevar_pop (TV_JIT_REPLAY
);
2147 if (!errors_occurred ())
2152 /* No GC can happen yet; process the cached source locations. */
2153 handle_locations ();
2155 /* We've now created tree nodes for the stmts in the various blocks
2156 in each function, but we haven't built each function's single stmt
2157 list yet. Do so now. */
2158 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2159 func
->build_stmt_list ();
2161 /* No GC can have happened yet. */
2163 /* Postprocess the functions. This could trigger GC. */
2164 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2167 func
->postprocess ();
2172 /* Dump the generated .s file to stderr. */
2176 dump_generated_code ()
2178 JIT_LOG_SCOPE (get_logger ());
2181 FILE *f_in
= fopen (get_path_s_file (), "r");
2185 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2186 fwrite (buf
, 1, sz
, stderr
);
2191 /* Get the supposed path of the notional "fake.c" file within the
2192 tempdir. This file doesn't exist, but the rest of the compiler
2197 get_path_c_file () const
2199 return m_tempdir
->get_path_c_file ();
2202 /* Get the path of the assembler output file "fake.s" file within the
2207 get_path_s_file () const
2209 return m_tempdir
->get_path_s_file ();
2212 /* Get the path of the DSO object file "fake.so" file within the
2217 get_path_so_file () const
2219 return m_tempdir
->get_path_so_file ();
2222 /* qsort comparator for comparing pairs of playback::source_line *,
2223 ordering them by line number. */
2226 line_comparator (const void *lhs
, const void *rhs
)
2228 const playback::source_line
*line_lhs
= \
2229 *static_cast<const playback::source_line
* const*> (lhs
);
2230 const playback::source_line
*line_rhs
= \
2231 *static_cast<const playback::source_line
* const*> (rhs
);
2232 return line_lhs
->get_line_num () - line_rhs
->get_line_num ();
2235 /* qsort comparator for comparing pairs of playback::location *,
2236 ordering them by column number. */
2239 location_comparator (const void *lhs
, const void *rhs
)
2241 const playback::location
*loc_lhs
= \
2242 *static_cast<const playback::location
* const *> (lhs
);
2243 const playback::location
*loc_rhs
= \
2244 *static_cast<const playback::location
* const *> (rhs
);
2245 return loc_lhs
->get_column_num () - loc_rhs
->get_column_num ();
2248 /* Our API allows locations to be created in arbitrary orders, but the
2249 linemap API requires locations to be created in ascending order
2250 as if we were tokenizing files.
2252 This hook sorts all of the the locations that have been created, and
2253 calls into the linemap API, creating linemap entries in sorted order
2254 for our locations. */
2260 /* Create the source code locations, following the ordering rules
2261 imposed by the linemap API.
2263 line_table is a global. */
2264 JIT_LOG_SCOPE (get_logger ());
2268 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2270 linemap_add (line_table
, LC_ENTER
, false, file
->get_filename (), 0);
2272 /* Sort lines by ascending line numbers. */
2273 file
->m_source_lines
.qsort (&line_comparator
);
2277 FOR_EACH_VEC_ELT (file
->m_source_lines
, j
, line
)
2282 /* Sort locations in line by ascending column numbers. */
2283 line
->m_locations
.qsort (&location_comparator
);
2285 /* Determine maximum column within this line. */
2286 gcc_assert (line
->m_locations
.length () > 0);
2287 location
*final_column
=
2288 line
->m_locations
[line
->m_locations
.length () - 1];
2289 int max_col
= final_column
->get_column_num ();
2291 linemap_line_start (line_table
, line
->get_line_num (), max_col
);
2292 FOR_EACH_VEC_ELT (line
->m_locations
, k
, loc
)
2295 linemap_position_for_column (line_table
, loc
->get_column_num ());
2299 linemap_add (line_table
, LC_LEAVE
, false, NULL
, 0);
2302 /* line_table should now be populated; every playback::location should
2303 now have an m_srcloc. */
2305 /* Now assign them to tree nodes as appropriate. */
2306 std::pair
<tree
, location
*> *cached_location
;
2308 FOR_EACH_VEC_ELT (m_cached_locations
, i
, cached_location
)
2310 tree t
= cached_location
->first
;
2311 source_location srcloc
= cached_location
->second
->m_srcloc
;
2313 /* This covers expressions: */
2314 if (CAN_HAVE_LOCATION_P (t
))
2315 SET_EXPR_LOCATION (t
, srcloc
);
2316 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t
), TS_DECL_MINIMAL
))
2317 DECL_SOURCE_LOCATION (t
) = srcloc
;
2320 /* Don't know how to set location on this node. */
2325 /* We handle errors on a playback::context by adding them to the
2326 corresponding recording::context. */
2330 add_error (location
*loc
, const char *fmt
, ...)
2334 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2339 /* We handle errors on a playback::context by adding them to the
2340 corresponding recording::context. */
2344 add_error_va (location
*loc
, const char *fmt
, va_list ap
)
2346 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2350 /* Dealing with the linemap API. */
2352 /* Construct a playback::location for a recording::location, if it
2353 doesn't exist already. */
2355 playback::location
*
2357 new_location (recording::location
*rloc
,
2358 const char *filename
,
2362 /* Get the source_file for filename, creating if necessary. */
2363 source_file
*src_file
= get_source_file (filename
);
2364 /* Likewise for the line within the file. */
2365 source_line
*src_line
= src_file
->get_source_line (line
);
2366 /* Likewise for the column within the line. */
2367 location
*loc
= src_line
->get_location (rloc
, column
);
2371 /* Deferred setting of the location for a given tree, by adding the
2372 (tree, playback::location) pair to a list of deferred associations.
2373 We will actually set the location on the tree later on once
2374 the source_location for the playback::location exists. */
2378 set_tree_location (tree t
, location
*loc
)
2381 m_cached_locations
.safe_push (std::make_pair (t
, loc
));
2385 /* Construct a playback::source_file for the given source
2386 filename, if it doesn't exist already. */
2388 playback::source_file
*
2390 get_source_file (const char *filename
)
2393 For simplicitly, this is currently a linear search.
2394 Replace with a hash if this shows up in the profile. */
2397 tree ident_filename
= get_identifier (filename
);
2399 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2400 if (file
->filename_as_tree () == ident_filename
)
2404 file
= new source_file (ident_filename
);
2405 m_source_files
.safe_push (file
);
2409 /* Constructor for gcc::jit::playback::source_file. */
2411 playback::source_file::source_file (tree filename
) :
2413 m_filename (filename
)
2417 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2421 playback::source_file::finalizer ()
2423 m_source_lines
.release ();
2426 /* Construct a playback::source_line for the given line
2427 within this source file, if one doesn't exist already. */
2429 playback::source_line
*
2430 playback::source_file::
2431 get_source_line (int line_num
)
2434 For simplicitly, this is currently a linear search.
2435 Replace with a hash if this shows up in the profile. */
2439 FOR_EACH_VEC_ELT (m_source_lines
, i
, line
)
2440 if (line
->get_line_num () == line_num
)
2444 line
= new source_line (this, line_num
);
2445 m_source_lines
.safe_push (line
);
2449 /* Constructor for gcc::jit::playback::source_line. */
2451 playback::source_line::source_line (source_file
*file
, int line_num
) :
2453 m_source_file (file
),
2454 m_line_num (line_num
)
2458 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2462 playback::source_line::finalizer ()
2464 m_locations
.release ();
2467 /* Construct a playback::location for the given column
2468 within this line of a specific source file, if one doesn't exist
2471 playback::location
*
2472 playback::source_line::
2473 get_location (recording::location
*rloc
, int column_num
)
2478 /* Another linear search that probably should be a hash table. */
2479 FOR_EACH_VEC_ELT (m_locations
, i
, loc
)
2480 if (loc
->get_column_num () == column_num
)
2484 loc
= new location (rloc
, this, column_num
);
2485 m_locations
.safe_push (loc
);
2489 /* Constructor for gcc::jit::playback::location. */
2491 playback::location::location (recording::location
*loc
,
2494 m_srcloc (UNKNOWN_LOCATION
),
2495 m_recording_loc (loc
),
2497 m_column_num(column_num
)
2501 /* The active gcc::jit::playback::context instance. This is a singleton,
2502 guarded by jit_mutex. */
2504 playback::context
*active_playback_ctxt
;
2506 } // namespace gcc::jit