1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2015 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
26 #include "statistics.h"
31 #include "tree-core.h"
38 #include "hard-reg-set.h"
47 #include "stringpool.h"
48 #include "stor-layout.h"
49 #include "print-tree.h"
51 #include "gcc-driver-name.h"
54 #include "fold-const.h"
58 #include "jit-common.h"
59 #include "jit-logging.h"
60 #include "jit-playback.h"
61 #include "jit-result.h"
62 #include "jit-builtins.h"
63 #include "jit-tempdir.h"
66 /* gcc::jit::playback::context::build_cast uses the convert.h API,
67 which in turn requires the frontend to provide a "convert"
68 function, apparently as a fallback.
70 Hence we provide this dummy one, with the requirement that any casts
71 are handled before reaching this. */
72 extern tree
convert (tree type
, tree expr
);
75 convert (tree dst_type
, tree expr
)
77 gcc_assert (gcc::jit::active_playback_ctxt
);
78 gcc::jit::active_playback_ctxt
->add_error (NULL
, "unhandled conversion");
79 fprintf (stderr
, "input expression:\n");
81 fprintf (stderr
, "requested type:\n");
82 debug_tree (dst_type
);
83 return error_mark_node
;
89 /**********************************************************************
91 **********************************************************************/
93 /* The constructor for gcc::jit::playback::context. */
95 playback::context::context (recording::context
*ctxt
)
96 : log_user (ctxt
->get_logger ()),
97 m_recording_ctxt (ctxt
),
99 m_char_array_type_node (NULL
),
100 m_const_char_ptr (NULL
)
102 JIT_LOG_SCOPE (get_logger ());
103 m_functions
.create (0);
104 m_globals
.create (0);
105 m_source_files
.create (0);
106 m_cached_locations
.create (0);
109 /* The destructor for gcc::jit::playback::context. */
111 playback::context::~context ()
113 JIT_LOG_SCOPE (get_logger ());
115 /* Normally the playback::context is responsible for cleaning up the
116 tempdir (including "fake.so" within the filesystem).
118 In the normal case, clean it up now.
120 However m_tempdir can be NULL if the context has handed over
121 responsibility for the tempdir cleanup to the jit::result object, so
122 that the cleanup can be delayed (see PR jit/64206). If that's the
123 case this "delete NULL;" is a no-op. */
126 m_functions
.release ();
129 /* A playback::context can reference GC-managed pointers. Mark them
130 ("by hand", rather than by gengtype).
132 This is called on the active playback context (if any) by the
133 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
141 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
143 if (ggc_test_and_set_mark (func
))
148 /* Given an enum gcc_jit_types value, get a "tree" type. */
151 get_tree_node_for_type (enum gcc_jit_types type_
)
155 case GCC_JIT_TYPE_VOID
:
156 return void_type_node
;
158 case GCC_JIT_TYPE_VOID_PTR
:
159 return ptr_type_node
;
161 case GCC_JIT_TYPE_BOOL
:
162 return boolean_type_node
;
164 case GCC_JIT_TYPE_CHAR
:
165 return char_type_node
;
166 case GCC_JIT_TYPE_SIGNED_CHAR
:
167 return signed_char_type_node
;
168 case GCC_JIT_TYPE_UNSIGNED_CHAR
:
169 return unsigned_char_type_node
;
171 case GCC_JIT_TYPE_SHORT
:
172 return short_integer_type_node
;
173 case GCC_JIT_TYPE_UNSIGNED_SHORT
:
174 return short_unsigned_type_node
;
176 case GCC_JIT_TYPE_CONST_CHAR_PTR
:
178 tree const_char
= build_qualified_type (char_type_node
,
180 return build_pointer_type (const_char
);
183 case GCC_JIT_TYPE_INT
:
184 return integer_type_node
;
185 case GCC_JIT_TYPE_UNSIGNED_INT
:
186 return unsigned_type_node
;
188 case GCC_JIT_TYPE_LONG
:
189 return long_integer_type_node
;
190 case GCC_JIT_TYPE_UNSIGNED_LONG
:
191 return long_unsigned_type_node
;
193 case GCC_JIT_TYPE_LONG_LONG
:
194 return long_long_integer_type_node
;
195 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG
:
196 return long_long_unsigned_type_node
;
198 case GCC_JIT_TYPE_FLOAT
:
199 return float_type_node
;
200 case GCC_JIT_TYPE_DOUBLE
:
201 return double_type_node
;
202 case GCC_JIT_TYPE_LONG_DOUBLE
:
203 return long_double_type_node
;
205 case GCC_JIT_TYPE_SIZE_T
:
206 return size_type_node
;
208 case GCC_JIT_TYPE_FILE_PTR
:
209 return fileptr_type_node
;
211 case GCC_JIT_TYPE_COMPLEX_FLOAT
:
212 return complex_float_type_node
;
213 case GCC_JIT_TYPE_COMPLEX_DOUBLE
:
214 return complex_double_type_node
;
215 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE
:
216 return complex_long_double_type_node
;
222 /* Construct a playback::type instance (wrapping a tree) for the given
227 get_type (enum gcc_jit_types type_
)
229 tree type_node
= get_tree_node_for_type (type_
);
230 if (NULL
== type_node
)
233 "unrecognized (enum gcc_jit_types) value: %i", type_
);
237 return new type (type_node
);
240 /* Construct a playback::type instance (wrapping a tree) for the given
245 new_array_type (playback::location
*loc
,
246 playback::type
*element_type
,
249 gcc_assert (element_type
);
251 tree t
= build_array_type_nelts (element_type
->as_tree (),
256 set_tree_location (t
, loc
);
261 /* Construct a playback::field instance (wrapping a tree). */
265 new_field (location
*loc
,
272 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
273 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
274 get_identifier (name
), type
->as_tree ());
277 set_tree_location (decl
, loc
);
279 return new field (decl
);
282 /* Construct a playback::compound_type instance (wrapping a tree). */
284 playback::compound_type
*
286 new_compound_type (location
*loc
,
288 bool is_struct
) /* else is union */
292 /* Compare with c/c-decl.c: start_struct. */
294 tree t
= make_node (is_struct
? RECORD_TYPE
: UNION_TYPE
);
295 TYPE_NAME (t
) = get_identifier (name
);
299 set_tree_location (t
, loc
);
301 return new compound_type (t
);
305 playback::compound_type::set_fields (const auto_vec
<playback::field
*> *fields
)
307 /* Compare with c/c-decl.c: finish_struct. */
310 tree fieldlist
= NULL
;
311 for (unsigned i
= 0; i
< fields
->length (); i
++)
313 field
*f
= (*fields
)[i
];
314 DECL_CONTEXT (f
->as_tree ()) = t
;
315 fieldlist
= chainon (f
->as_tree (), fieldlist
);
317 fieldlist
= nreverse (fieldlist
);
318 TYPE_FIELDS (t
) = fieldlist
;
323 /* Construct a playback::type instance (wrapping a tree) for a function
328 new_function_type (type
*return_type
,
329 const auto_vec
<type
*> *param_types
,
335 tree
*arg_types
= (tree
*)xcalloc(param_types
->length (), sizeof(tree
*));
337 FOR_EACH_VEC_ELT (*param_types
, i
, param_type
)
338 arg_types
[i
] = param_type
->as_tree ();
343 build_varargs_function_type_array (return_type
->as_tree (),
344 param_types
->length (),
347 fn_type
= build_function_type_array (return_type
->as_tree (),
348 param_types
->length (),
352 return new type (fn_type
);
355 /* Construct a playback::param instance (wrapping a tree). */
359 new_param (location
*loc
,
365 tree inner
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
366 get_identifier (name
), type
->as_tree ());
368 set_tree_location (inner
, loc
);
370 return new param (this, inner
);
373 /* Construct a playback::function instance. */
377 new_function (location
*loc
,
378 enum gcc_jit_function_kind kind
,
381 const auto_vec
<param
*> *params
,
383 enum built_in_function builtin_id
)
388 //can return_type be NULL?
391 tree
*arg_types
= (tree
*)xcalloc(params
->length (), sizeof(tree
*));
392 FOR_EACH_VEC_ELT (*params
, i
, param
)
393 arg_types
[i
] = TREE_TYPE (param
->as_tree ());
397 fn_type
= build_varargs_function_type_array (return_type
->as_tree (),
398 params
->length (), arg_types
);
400 fn_type
= build_function_type_array (return_type
->as_tree (),
401 params
->length (), arg_types
);
404 /* FIXME: this uses input_location: */
405 tree fndecl
= build_fn_decl (name
, fn_type
);
408 set_tree_location (fndecl
, loc
);
410 tree resdecl
= build_decl (UNKNOWN_LOCATION
, RESULT_DECL
,
411 NULL_TREE
, return_type
->as_tree ());
412 DECL_ARTIFICIAL (resdecl
) = 1;
413 DECL_IGNORED_P (resdecl
) = 1;
414 DECL_RESULT (fndecl
) = resdecl
;
418 DECL_FUNCTION_CODE (fndecl
) = builtin_id
;
419 gcc_assert (loc
== NULL
);
420 DECL_SOURCE_LOCATION (fndecl
) = BUILTINS_LOCATION
;
422 DECL_BUILT_IN_CLASS (fndecl
) =
423 builtins_manager::get_class (builtin_id
);
424 set_builtin_decl (builtin_id
, fndecl
,
425 builtins_manager::implicit_p (builtin_id
));
427 builtins_manager
*bm
= get_builtins_manager ();
428 tree attrs
= bm
->get_attrs_tree (builtin_id
);
430 decl_attributes (&fndecl
, attrs
, ATTR_FLAG_BUILT_IN
);
432 decl_attributes (&fndecl
, NULL_TREE
, 0);
435 if (kind
!= GCC_JIT_FUNCTION_IMPORTED
)
437 tree param_decl_list
= NULL
;
438 FOR_EACH_VEC_ELT (*params
, i
, param
)
440 param_decl_list
= chainon (param
->as_tree (), param_decl_list
);
443 /* The param list was created in reverse order; fix it: */
444 param_decl_list
= nreverse (param_decl_list
);
447 for (t
= param_decl_list
; t
; t
= DECL_CHAIN (t
))
449 DECL_CONTEXT (t
) = fndecl
;
450 DECL_ARG_TYPE (t
) = TREE_TYPE (t
);
453 /* Set it up on DECL_ARGUMENTS */
454 DECL_ARGUMENTS(fndecl
) = param_decl_list
;
457 if (kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
459 DECL_DECLARED_INLINE_P (fndecl
) = 1;
461 /* Add attribute "always_inline": */
462 DECL_ATTRIBUTES (fndecl
) =
463 tree_cons (get_identifier ("always_inline"),
465 DECL_ATTRIBUTES (fndecl
));
468 function
*func
= new function (this, fndecl
, kind
);
469 m_functions
.safe_push (func
);
473 /* Construct a playback::lvalue instance (wrapping a tree). */
477 new_global (location
*loc
,
478 enum gcc_jit_global_kind kind
,
484 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
485 get_identifier (name
),
487 TREE_PUBLIC (inner
) = (kind
!= GCC_JIT_GLOBAL_INTERNAL
);
488 DECL_COMMON (inner
) = 1;
494 case GCC_JIT_GLOBAL_EXPORTED
:
495 TREE_STATIC (inner
) = 1;
498 case GCC_JIT_GLOBAL_INTERNAL
:
499 TREE_STATIC (inner
) = 1;
502 case GCC_JIT_GLOBAL_IMPORTED
:
503 DECL_EXTERNAL (inner
) = 1;
508 set_tree_location (inner
, loc
);
510 varpool_node::get_create (inner
);
512 varpool_node::finalize_decl (inner
);
514 m_globals
.safe_push (inner
);
516 return new lvalue (this, inner
);
519 /* Implementation of the various
520 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
522 Each of these constructs a playback::rvalue instance (wrapping a tree).
524 These specializations are required to be in the same namespace
525 as the template, hence we now have to enter the gcc::jit::playback
531 /* Specialization of making an rvalue from a const, for host <int>. */
536 new_rvalue_from_const
<int> (type
*type
,
539 // FIXME: type-checking, or coercion?
540 tree inner_type
= type
->as_tree ();
541 if (INTEGRAL_TYPE_P (inner_type
))
543 tree inner
= build_int_cst (inner_type
, value
);
544 return new rvalue (this, inner
);
548 REAL_VALUE_TYPE real_value
;
549 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
550 tree inner
= build_real (inner_type
, real_value
);
551 return new rvalue (this, inner
);
555 /* Specialization of making an rvalue from a const, for host <long>. */
560 new_rvalue_from_const
<long> (type
*type
,
563 // FIXME: type-checking, or coercion?
564 tree inner_type
= type
->as_tree ();
565 if (INTEGRAL_TYPE_P (inner_type
))
567 tree inner
= build_int_cst (inner_type
, value
);
568 return new rvalue (this, inner
);
572 REAL_VALUE_TYPE real_value
;
573 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
574 tree inner
= build_real (inner_type
, real_value
);
575 return new rvalue (this, inner
);
579 /* Specialization of making an rvalue from a const, for host <double>. */
584 new_rvalue_from_const
<double> (type
*type
,
587 // FIXME: type-checking, or coercion?
588 tree inner_type
= type
->as_tree ();
590 /* We have a "double", we want a REAL_VALUE_TYPE.
592 real.c:real_from_target appears to require the representation to be
593 split into 32-bit values, and then sent as an pair of host long
595 REAL_VALUE_TYPE real_value
;
599 uint32_t as_uint32s
[2];
602 long int as_long_ints
[2];
603 as_long_ints
[0] = u
.as_uint32s
[0];
604 as_long_ints
[1] = u
.as_uint32s
[1];
605 real_from_target (&real_value
, as_long_ints
, DFmode
);
606 tree inner
= build_real (inner_type
, real_value
);
607 return new rvalue (this, inner
);
610 /* Specialization of making an rvalue from a const, for host <void *>. */
615 new_rvalue_from_const
<void *> (type
*type
,
618 tree inner_type
= type
->as_tree ();
619 /* FIXME: how to ensure we have a wide enough type? */
620 tree inner
= build_int_cstu (inner_type
, (unsigned HOST_WIDE_INT
)value
);
621 return new rvalue (this, inner
);
624 /* We're done implementing the specializations of
625 gcc::jit::playback::context::new_rvalue_from_const <T>
626 so we can exit the gcc::jit::playback namespace. */
628 } // namespace playback
630 /* Construct a playback::rvalue instance (wrapping a tree). */
634 new_string_literal (const char *value
)
636 tree t_str
= build_string (strlen (value
), value
);
637 gcc_assert (m_char_array_type_node
);
638 TREE_TYPE (t_str
) = m_char_array_type_node
;
640 /* Convert to (const char*), loosely based on
641 c/c-typeck.c: array_to_pointer_conversion,
642 by taking address of start of string. */
643 tree t_addr
= build1 (ADDR_EXPR
, m_const_char_ptr
, t_str
);
645 return new rvalue (this, t_addr
);
648 /* Coerce a tree expression into a boolean tree expression. */
652 as_truth_value (tree expr
, location
*loc
)
654 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
655 tree typed_zero
= fold_build1 (CONVERT_EXPR
,
659 set_tree_location (typed_zero
, loc
);
661 expr
= build2 (NE_EXPR
, integer_type_node
, expr
, typed_zero
);
663 set_tree_location (expr
, loc
);
668 /* Construct a playback::rvalue instance (wrapping a tree) for a
673 new_unary_op (location
*loc
,
674 enum gcc_jit_unary_op op
,
678 // FIXME: type-checking, or coercion?
679 enum tree_code inner_op
;
681 gcc_assert (result_type
);
684 tree node
= a
->as_tree ();
685 tree inner_result
= NULL
;
690 add_error (loc
, "unrecognized (enum gcc_jit_unary_op) value: %i", op
);
693 case GCC_JIT_UNARY_OP_MINUS
:
694 inner_op
= NEGATE_EXPR
;
697 case GCC_JIT_UNARY_OP_BITWISE_NEGATE
:
698 inner_op
= BIT_NOT_EXPR
;
701 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE
:
702 node
= as_truth_value (node
, loc
);
703 inner_result
= invert_truthvalue (node
);
705 set_tree_location (inner_result
, loc
);
706 return new rvalue (this, inner_result
);
708 case GCC_JIT_UNARY_OP_ABS
:
713 inner_result
= build1 (inner_op
,
714 result_type
->as_tree (),
717 set_tree_location (inner_result
, loc
);
719 return new rvalue (this, inner_result
);
722 /* Construct a playback::rvalue instance (wrapping a tree) for a
727 new_binary_op (location
*loc
,
728 enum gcc_jit_binary_op op
,
730 rvalue
*a
, rvalue
*b
)
732 // FIXME: type-checking, or coercion?
733 enum tree_code inner_op
;
735 gcc_assert (result_type
);
739 tree node_a
= a
->as_tree ();
740 tree node_b
= b
->as_tree ();
745 add_error (loc
, "unrecognized (enum gcc_jit_binary_op) value: %i", op
);
748 case GCC_JIT_BINARY_OP_PLUS
:
749 inner_op
= PLUS_EXPR
;
752 case GCC_JIT_BINARY_OP_MINUS
:
753 inner_op
= MINUS_EXPR
;
756 case GCC_JIT_BINARY_OP_MULT
:
757 inner_op
= MULT_EXPR
;
760 case GCC_JIT_BINARY_OP_DIVIDE
:
761 if (FLOAT_TYPE_P (result_type
->as_tree ()))
762 /* Floating-point division: */
763 inner_op
= RDIV_EXPR
;
765 /* Truncating to zero: */
766 inner_op
= TRUNC_DIV_EXPR
;
769 case GCC_JIT_BINARY_OP_MODULO
:
770 inner_op
= TRUNC_MOD_EXPR
;
773 case GCC_JIT_BINARY_OP_BITWISE_AND
:
774 inner_op
= BIT_AND_EXPR
;
777 case GCC_JIT_BINARY_OP_BITWISE_XOR
:
778 inner_op
= BIT_XOR_EXPR
;
781 case GCC_JIT_BINARY_OP_BITWISE_OR
:
782 inner_op
= BIT_IOR_EXPR
;
785 case GCC_JIT_BINARY_OP_LOGICAL_AND
:
786 node_a
= as_truth_value (node_a
, loc
);
787 node_b
= as_truth_value (node_b
, loc
);
788 inner_op
= TRUTH_ANDIF_EXPR
;
791 case GCC_JIT_BINARY_OP_LOGICAL_OR
:
792 node_a
= as_truth_value (node_a
, loc
);
793 node_b
= as_truth_value (node_b
, loc
);
794 inner_op
= TRUTH_ORIF_EXPR
;
797 case GCC_JIT_BINARY_OP_LSHIFT
:
798 inner_op
= LSHIFT_EXPR
;
801 case GCC_JIT_BINARY_OP_RSHIFT
:
802 inner_op
= RSHIFT_EXPR
;
806 tree inner_expr
= build2 (inner_op
,
807 result_type
->as_tree (),
811 set_tree_location (inner_expr
, loc
);
813 return new rvalue (this, inner_expr
);
816 /* Construct a playback::rvalue instance (wrapping a tree) for a
821 new_comparison (location
*loc
,
822 enum gcc_jit_comparison op
,
823 rvalue
*a
, rvalue
*b
)
825 // FIXME: type-checking, or coercion?
826 enum tree_code inner_op
;
834 add_error (loc
, "unrecognized (enum gcc_jit_comparison) value: %i", op
);
837 case GCC_JIT_COMPARISON_EQ
:
840 case GCC_JIT_COMPARISON_NE
:
843 case GCC_JIT_COMPARISON_LT
:
846 case GCC_JIT_COMPARISON_LE
:
849 case GCC_JIT_COMPARISON_GT
:
852 case GCC_JIT_COMPARISON_GE
:
857 tree inner_expr
= build2 (inner_op
,
862 set_tree_location (inner_expr
, loc
);
863 return new rvalue (this, inner_expr
);
866 /* Construct a playback::rvalue instance (wrapping a tree) for a
871 build_call (location
*loc
,
873 const auto_vec
<rvalue
*> *args
)
875 vec
<tree
, va_gc
> *tree_args
;
876 vec_alloc (tree_args
, args
->length ());
877 for (unsigned i
= 0; i
< args
->length (); i
++)
878 tree_args
->quick_push ((*args
)[i
]->as_tree ());
881 set_tree_location (fn_ptr
, loc
);
883 tree fn
= TREE_TYPE (fn_ptr
);
884 tree fn_type
= TREE_TYPE (fn
);
885 tree return_type
= TREE_TYPE (fn_type
);
887 return new rvalue (this,
888 build_call_vec (return_type
,
891 /* see c-typeck.c: build_function_call
892 which calls build_function_call_vec
894 which does lots of checking, then:
895 result = build_call_array_loc (loc, TREE_TYPE (fntype),
896 function, nargs, argarray);
898 (see also build_call_vec)
902 /* Construct a playback::rvalue instance (wrapping a tree) for a
903 call to a specific function. */
907 new_call (location
*loc
,
909 const auto_vec
<rvalue
*> *args
)
915 fndecl
= func
->as_fndecl ();
917 tree fntype
= TREE_TYPE (fndecl
);
919 tree fn
= build1 (ADDR_EXPR
, build_pointer_type (fntype
), fndecl
);
921 return build_call (loc
, fn
, args
);
924 /* Construct a playback::rvalue instance (wrapping a tree) for a
925 call through a function pointer. */
929 new_call_through_ptr (location
*loc
,
931 const auto_vec
<rvalue
*> *args
)
934 tree t_fn_ptr
= fn_ptr
->as_tree ();
936 return build_call (loc
, t_fn_ptr
, args
);
939 /* Construct a tree for a cast. */
942 playback::context::build_cast (playback::location
*loc
,
943 playback::rvalue
*expr
,
944 playback::type
*type_
)
946 /* For comparison, see:
947 - c/c-typeck.c:build_c_cast
948 - c/c-convert.c: convert
951 Only some kinds of cast are currently supported here. */
952 tree t_expr
= expr
->as_tree ();
953 tree t_dst_type
= type_
->as_tree ();
955 t_ret
= targetm
.convert_to_type (t_dst_type
, t_expr
);
958 enum tree_code dst_code
= TREE_CODE (t_dst_type
);
963 t_ret
= convert_to_integer (t_dst_type
, t_expr
);
967 /* Compare with c_objc_common_truthvalue_conversion and
968 c_common_truthvalue_conversion. */
969 /* For now, convert to: (t_expr != 0) */
970 t_ret
= build2 (NE_EXPR
, t_dst_type
,
972 build_int_cst (TREE_TYPE (t_expr
), 0));
976 t_ret
= convert_to_real (t_dst_type
, t_expr
);
980 t_ret
= build1 (NOP_EXPR
, t_dst_type
, t_expr
);
984 add_error (loc
, "couldn't handle cast during playback");
985 fprintf (stderr
, "input expression:\n");
987 fprintf (stderr
, "requested type:\n");
988 debug_tree (t_dst_type
);
989 return error_mark_node
;
992 if (TREE_CODE (t_ret
) != C_MAYBE_CONST_EXPR
)
993 t_ret
= fold (t_ret
);
998 /* Construct a playback::rvalue instance (wrapping a tree) for a
1003 new_cast (playback::location
*loc
,
1004 playback::rvalue
*expr
,
1005 playback::type
*type_
)
1008 tree t_cast
= build_cast (loc
, expr
, type_
);
1010 set_tree_location (t_cast
, loc
);
1011 return new rvalue (this, t_cast
);
1014 /* Construct a playback::lvalue instance (wrapping a tree) for an
1019 new_array_access (location
*loc
,
1026 /* For comparison, see:
1027 c/c-typeck.c: build_array_ref
1028 c-family/c-common.c: pointer_int_sum
1030 tree t_ptr
= ptr
->as_tree ();
1031 tree t_index
= index
->as_tree ();
1032 tree t_type_ptr
= TREE_TYPE (t_ptr
);
1033 tree t_type_star_ptr
= TREE_TYPE (t_type_ptr
);
1035 if (TREE_CODE (t_type_ptr
) == ARRAY_TYPE
)
1037 tree t_result
= build4 (ARRAY_REF
, t_type_star_ptr
, t_ptr
, t_index
,
1038 NULL_TREE
, NULL_TREE
);
1040 set_tree_location (t_result
, loc
);
1041 return new lvalue (this, t_result
);
1045 /* Convert index to an offset in bytes. */
1046 tree t_sizeof
= size_in_bytes (t_type_star_ptr
);
1047 t_index
= fold_build1 (CONVERT_EXPR
, sizetype
, t_index
);
1048 tree t_offset
= build2 (MULT_EXPR
, sizetype
, t_index
, t_sizeof
);
1050 /* Locate (ptr + offset). */
1051 tree t_address
= build2 (POINTER_PLUS_EXPR
, t_type_ptr
, t_ptr
, t_offset
);
1053 tree t_indirection
= build1 (INDIRECT_REF
, t_type_star_ptr
, t_address
);
1056 set_tree_location (t_sizeof
, loc
);
1057 set_tree_location (t_offset
, loc
);
1058 set_tree_location (t_address
, loc
);
1059 set_tree_location (t_indirection
, loc
);
1062 return new lvalue (this, t_indirection
);
1066 /* Construct a tree for a field access. */
1070 new_field_access (location
*loc
,
1077 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1078 build_component_ref. */
1079 tree type
= TREE_TYPE (datum
);
1081 gcc_assert (TREE_CODE (type
) != POINTER_TYPE
);
1083 tree t_field
= field
->as_tree ();
1084 tree ref
= build3 (COMPONENT_REF
, TREE_TYPE (t_field
), datum
,
1085 t_field
, NULL_TREE
);
1087 set_tree_location (ref
, loc
);
1091 /* Construct a tree for a dereference. */
1095 new_dereference (tree ptr
,
1100 tree type
= TREE_TYPE (TREE_TYPE(ptr
));
1101 tree datum
= build1 (INDIRECT_REF
, type
, ptr
);
1103 set_tree_location (datum
, loc
);
1107 /* Construct a playback::lvalue instance (wrapping a tree) for a
1112 access_field (location
*loc
,
1115 tree datum
= as_tree ();
1116 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1119 return new lvalue (get_context (), ref
);
1122 /* Construct a playback::rvalue instance (wrapping a tree) for a
1127 access_field (location
*loc
,
1130 tree datum
= as_tree ();
1131 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1134 return new rvalue (get_context (), ref
);
1137 /* Construct a playback::lvalue instance (wrapping a tree) for a
1138 dereferenced field access. */
1142 dereference_field (location
*loc
,
1145 tree ptr
= as_tree ();
1146 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1149 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1152 return new lvalue (get_context (), ref
);
1155 /* Construct a playback::lvalue instance (wrapping a tree) for a
1160 dereference (location
*loc
)
1162 tree ptr
= as_tree ();
1163 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1164 return new lvalue (get_context (), datum
);
1167 /* Construct a playback::rvalue instance (wrapping a tree) for an
1172 get_address (location
*loc
)
1174 tree t_lvalue
= as_tree ();
1175 tree t_thistype
= TREE_TYPE (t_lvalue
);
1176 tree t_ptrtype
= build_pointer_type (t_thistype
);
1177 tree ptr
= build1 (ADDR_EXPR
, t_ptrtype
, t_lvalue
);
1179 get_context ()->set_tree_location (ptr
, loc
);
1180 return new rvalue (get_context (), ptr
);
1183 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1184 Provide this finalization hook for calling then they are collected,
1185 which calls the finalizer vfunc. This allows them to call "release"
1186 on any vec<> within them. */
1189 wrapper_finalizer (void *ptr
)
1191 playback::wrapper
*wrapper
= reinterpret_cast <playback::wrapper
*> (ptr
);
1192 wrapper
->finalizer ();
1195 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1196 allocate them using ggc_internal_cleared_alloc. */
1200 operator new (size_t sz
)
1202 return ggc_internal_cleared_alloc (sz
, wrapper_finalizer
, 0, 1);
1206 /* Constructor for gcc:jit::playback::function. */
1208 playback::function::
1209 function (context
*ctxt
,
1211 enum gcc_jit_function_kind kind
)
1213 m_inner_fndecl (fndecl
),
1214 m_inner_bind_expr (NULL
),
1217 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1219 /* Create a BIND_EXPR, and within it, a statement list. */
1220 m_stmt_list
= alloc_stmt_list ();
1221 m_stmt_iter
= tsi_start (m_stmt_list
);
1222 m_inner_block
= make_node (BLOCK
);
1224 build3 (BIND_EXPR
, void_type_node
, NULL
, m_stmt_list
, m_inner_block
);
1228 m_inner_block
= NULL
;
1233 /* Hand-written GC-marking hook for playback functions. */
1236 playback::function::
1239 gt_ggc_m_9tree_node (m_inner_fndecl
);
1240 gt_ggc_m_9tree_node (m_inner_bind_expr
);
1241 gt_ggc_m_9tree_node (m_stmt_list
);
1242 gt_ggc_m_9tree_node (m_inner_block
);
1245 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1249 playback::function::finalizer ()
1251 m_blocks
.release ();
1254 /* Get the return type of a playback function, in tree form. */
1257 playback::function::
1258 get_return_type_as_tree () const
1260 return TREE_TYPE (TREE_TYPE(m_inner_fndecl
));
1263 /* Construct a new local within this playback::function. */
1266 playback::function::
1267 new_local (location
*loc
,
1273 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
1274 get_identifier (name
),
1276 DECL_CONTEXT (inner
) = this->m_inner_fndecl
;
1278 /* Prepend to BIND_EXPR_VARS: */
1279 DECL_CHAIN (inner
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1280 BIND_EXPR_VARS (m_inner_bind_expr
) = inner
;
1283 set_tree_location (inner
, loc
);
1284 return new lvalue (m_ctxt
, inner
);
1287 /* Construct a new block within this playback::function. */
1290 playback::function::
1291 new_block (const char *name
)
1293 gcc_assert (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
);
1295 block
*result
= new playback::block (this, name
);
1296 m_blocks
.safe_push (result
);
1300 /* Build a statement list for the function as a whole out of the
1301 lists of statements for the individual blocks, building labels
1305 playback::function::
1311 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1313 FOR_EACH_VEC_ELT (m_blocks
, i
, b
)
1318 b
->m_label_expr
= build1 (LABEL_EXPR
,
1320 b
->as_label_decl ());
1321 tsi_link_after (&m_stmt_iter
, b
->m_label_expr
, TSI_CONTINUE_LINKING
);
1323 FOR_EACH_VEC_ELT (b
->m_stmts
, j
, stmt
)
1324 tsi_link_after (&m_stmt_iter
, stmt
, TSI_CONTINUE_LINKING
);
1328 /* Finish compiling the given function, potentially running the
1330 The function will have a statement list by now.
1331 Amongst other things, this gimplifies the statement list,
1332 and calls cgraph_node::finalize_function on the function. */
1335 playback::function::
1338 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1340 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
))
1341 debug_tree (m_stmt_list
);
1343 /* Do we need this to force cgraphunit.c to output the function? */
1344 if (m_kind
== GCC_JIT_FUNCTION_EXPORTED
)
1346 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1347 DECL_PRESERVE_P (m_inner_fndecl
) = 1;
1350 if (m_kind
== GCC_JIT_FUNCTION_INTERNAL
1351 ||m_kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
1353 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1354 TREE_PUBLIC (m_inner_fndecl
) = 0;
1357 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1359 /* Seem to need this in gimple-low.c: */
1360 gcc_assert (m_inner_block
);
1361 DECL_INITIAL (m_inner_fndecl
) = m_inner_block
;
1363 /* how to add to function? the following appears to be how to
1364 set the body of a m_inner_fndecl: */
1365 DECL_SAVED_TREE(m_inner_fndecl
) = m_inner_bind_expr
;
1367 /* Ensure that locals appear in the debuginfo. */
1368 BLOCK_VARS (m_inner_block
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1370 //debug_tree (m_inner_fndecl);
1372 /* Convert to gimple: */
1373 //printf("about to gimplify_function_tree\n");
1374 gimplify_function_tree (m_inner_fndecl
);
1375 //printf("finished gimplify_function_tree\n");
1377 current_function_decl
= m_inner_fndecl
;
1378 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
))
1379 dump_function_to_file (m_inner_fndecl
, stderr
, TDF_VOPS
|TDF_MEMSYMS
|TDF_LINENO
);
1380 //debug_tree (m_inner_fndecl);
1382 //printf("about to add to cgraph\n");
1383 /* Add to cgraph: */
1384 cgraph_node::finalize_function (m_inner_fndecl
, false);
1385 /* This can trigger a collection, so we need to have all of
1386 the funcs as roots. */
1388 current_function_decl
= NULL
;
1392 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1396 playback::block::finalizer ()
1401 /* Add an eval of the rvalue to the function's statement list. */
1405 add_eval (location
*loc
,
1408 gcc_assert (rvalue
);
1411 set_tree_location (rvalue
->as_tree (), loc
);
1413 add_stmt (rvalue
->as_tree ());
1416 /* Add an assignment to the function's statement list. */
1420 add_assignment (location
*loc
,
1424 gcc_assert (lvalue
);
1425 gcc_assert (rvalue
);
1427 tree t_lvalue
= lvalue
->as_tree ();
1428 tree t_rvalue
= rvalue
->as_tree ();
1429 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1431 t_rvalue
= build1 (CONVERT_EXPR
,
1432 TREE_TYPE (t_lvalue
),
1435 set_tree_location (t_rvalue
, loc
);
1439 build2 (MODIFY_EXPR
, TREE_TYPE (t_lvalue
),
1440 t_lvalue
, t_rvalue
);
1442 set_tree_location (stmt
, loc
);
1446 /* Add a comment to the function's statement list.
1447 For now this is done by adding a dummy label. */
1451 add_comment (location
*loc
,
1454 /* Wrap the text in C-style comment delimiters. */
1456 (3 /* opening delim */
1458 + 3 /* closing delim */
1459 + 1 /* terminator */);
1460 char *wrapped
= (char *)ggc_internal_alloc (sz
);
1461 snprintf (wrapped
, sz
, "/* %s */", text
);
1463 /* For now we simply implement this by adding a dummy label with a name
1464 containing the given text. */
1465 tree identifier
= get_identifier (wrapped
);
1466 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1467 identifier
, void_type_node
);
1468 DECL_CONTEXT (label_decl
) = m_func
->as_fndecl ();
1470 tree label_expr
= build1 (LABEL_EXPR
, void_type_node
, label_decl
);
1472 set_tree_location (label_expr
, loc
);
1473 add_stmt (label_expr
);
1476 /* Add a conditional jump statement to the function's statement list. */
1480 add_conditional (location
*loc
,
1485 gcc_assert (boolval
);
1486 gcc_assert (on_true
);
1487 gcc_assert (on_false
);
1489 /* COND_EXPR wants statement lists for the true/false operands, but we
1491 Shim it by creating jumps to the labels */
1492 tree true_jump
= build1 (GOTO_EXPR
, void_type_node
,
1493 on_true
->as_label_decl ());
1495 set_tree_location (true_jump
, loc
);
1497 tree false_jump
= build1 (GOTO_EXPR
, void_type_node
,
1498 on_false
->as_label_decl ());
1500 set_tree_location (false_jump
, loc
);
1503 build3 (COND_EXPR
, void_type_node
, boolval
->as_tree (),
1504 true_jump
, false_jump
);
1506 set_tree_location (stmt
, loc
);
1510 /* Add an unconditional jump statement to the function's statement list. */
1514 add_jump (location
*loc
,
1517 gcc_assert (target
);
1519 // see c_finish_loop
1520 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1523 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1524 TREE_USED (target
->as_label_decl ()) = 1;
1525 tree stmt
= build1 (GOTO_EXPR
, void_type_node
, target
->as_label_decl ());
1527 set_tree_location (stmt
, loc
);
1533 c_finish_goto_label (location_t loc, tree label)
1535 tree decl = lookup_label_for_goto (loc, label);
1538 TREE_USED (decl) = 1;
1540 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1541 SET_EXPR_LOCATION (t, loc);
1542 return add_stmt (t);
1549 /* Add a return statement to the function's statement list. */
1553 add_return (location
*loc
,
1556 tree modify_retval
= NULL
;
1557 tree return_type
= m_func
->get_return_type_as_tree ();
1560 tree t_lvalue
= DECL_RESULT (m_func
->as_fndecl ());
1561 tree t_rvalue
= rvalue
->as_tree ();
1562 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1563 t_rvalue
= build1 (CONVERT_EXPR
,
1564 TREE_TYPE (t_lvalue
),
1566 modify_retval
= build2 (MODIFY_EXPR
, return_type
,
1567 t_lvalue
, t_rvalue
);
1569 set_tree_location (modify_retval
, loc
);
1571 tree return_stmt
= build1 (RETURN_EXPR
, return_type
,
1574 set_tree_location (return_stmt
, loc
);
1576 add_stmt (return_stmt
);
1579 /* Constructor for gcc::jit::playback::block. */
1582 block (function
*func
,
1592 identifier
= get_identifier (name
);
1595 m_label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1596 identifier
, void_type_node
);
1597 DECL_CONTEXT (m_label_decl
) = func
->as_fndecl ();
1598 m_label_expr
= NULL
;
1601 /* A subclass of auto_vec <char *> that frees all of its elements on
1604 class auto_argvec
: public auto_vec
<char *>
1610 /* auto_argvec's dtor, freeing all contained strings, automatically
1611 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1613 auto_argvec::~auto_argvec ()
1617 FOR_EACH_VEC_ELT (*this, i
, str
)
1621 /* Compile a playback::context:
1623 - Use the context's options to cconstruct command-line options, and
1624 call into the rest of GCC (toplev::main).
1625 - Assuming it succeeds, we have a .s file.
1626 - We then run the "postprocess" vfunc:
1628 (A) In-memory compile ("gcc_jit_context_compile")
1630 For an in-memory compile we have the playback::compile_to_memory
1631 subclass; "postprocess" will convert the .s file to a .so DSO,
1632 and load it in memory (via dlopen), wrapping the result up as
1633 a jit::result and returning it.
1635 (B) Compile to file ("gcc_jit_context_compile_to_file")
1637 When compiling to a file, we have the playback::compile_to_file
1638 subclass; "postprocess" will either copy the .s file to the
1639 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1640 the driver to convert it as necessary, copying the result. */
1646 JIT_LOG_SCOPE (get_logger ());
1648 const char *ctxt_progname
;
1650 int keep_intermediates
=
1651 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
);
1653 m_tempdir
= new tempdir (get_logger (), keep_intermediates
);
1654 if (!m_tempdir
->create ())
1657 /* Call into the rest of gcc.
1658 For now, we have to assemble command-line options to pass into
1659 toplev::main, so that they can be parsed. */
1661 /* Pass in user-provided program name as argv0, if any, so that it
1662 makes it into GCC's "progname" global, used in various diagnostics. */
1663 ctxt_progname
= get_str_option (GCC_JIT_STR_OPTION_PROGNAME
);
1666 ctxt_progname
= "libgccjit.so";
1668 auto_vec
<recording::requested_dump
> requested_dumps
;
1669 m_recording_ctxt
->get_all_requested_dumps (&requested_dumps
);
1671 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1674 auto_argvec fake_args
;
1675 make_fake_args (&fake_args
, ctxt_progname
, &requested_dumps
);
1676 if (errors_occurred ())
1682 /* This runs the compiler. */
1683 toplev
toplev (false, /* use_TV_TOTAL */
1684 false); /* init_signals */
1685 enter_scope ("toplev::main");
1687 for (unsigned i
= 0; i
< fake_args
.length (); i
++)
1688 get_logger ()->log ("argv[%i]: %s", i
, fake_args
[i
]);
1689 toplev
.main (fake_args
.length (),
1690 const_cast <char **> (fake_args
.address ()));
1691 exit_scope ("toplev::main");
1693 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1694 need to do it between toplev::main (which creates the dump manager)
1695 and toplev::finalize (which deletes it). */
1696 extract_any_requested_dumps (&requested_dumps
);
1698 /* Clean up the compiler. */
1699 enter_scope ("toplev::finalize");
1701 exit_scope ("toplev::finalize");
1703 /* Ideally we would release the jit mutex here, but we can't yet since
1704 followup activities use timevars, which are global state. */
1706 if (errors_occurred ())
1712 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
))
1713 dump_generated_code ();
1715 /* We now have a .s file.
1717 Run any postprocessing steps. This will either convert the .s file to
1718 a .so DSO, and load it in memory (playback::compile_to_memory), or
1719 convert the .s file to the requested output format, and copy it to a
1720 given file (playback::compile_to_file). */
1721 postprocess (ctxt_progname
);
1726 /* Implementation of class gcc::jit::playback::compile_to_memory,
1727 a subclass of gcc::jit::playback::context. */
1729 /* playback::compile_to_memory's trivial constructor. */
1731 playback::compile_to_memory::compile_to_memory (recording::context
*ctxt
) :
1732 playback::context (ctxt
),
1735 JIT_LOG_SCOPE (get_logger ());
1738 /* Implementation of the playback::context::process vfunc for compiling
1741 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1742 wrapping the result up as a jit::result and returning it. */
1745 playback::compile_to_memory::postprocess (const char *ctxt_progname
)
1747 JIT_LOG_SCOPE (get_logger ());
1748 convert_to_dso (ctxt_progname
);
1749 if (errors_occurred ())
1751 m_result
= dlopen_built_dso ();
1754 /* Implementation of class gcc::jit::playback::compile_to_file,
1755 a subclass of gcc::jit::playback::context. */
1757 /* playback::compile_to_file's trivial constructor. */
1759 playback::compile_to_file::compile_to_file (recording::context
*ctxt
,
1760 enum gcc_jit_output_kind output_kind
,
1761 const char *output_path
) :
1762 playback::context (ctxt
),
1763 m_output_kind (output_kind
),
1764 m_output_path (output_path
)
1766 JIT_LOG_SCOPE (get_logger ());
1769 /* Implementation of the playback::context::process vfunc for compiling
1772 Either copy the .s file to the given destination (for
1773 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1774 as necessary, copying the result. */
1777 playback::compile_to_file::postprocess (const char *ctxt_progname
)
1779 JIT_LOG_SCOPE (get_logger ());
1781 /* The driver takes different actions based on the filename, so
1782 we provide a filename with an appropriate suffix for the
1783 output kind, and then copy it up to the user-provided path,
1784 rather than directly compiling it to the requested output path. */
1786 switch (m_output_kind
)
1791 case GCC_JIT_OUTPUT_KIND_ASSEMBLER
:
1792 copy_file (get_tempdir ()->get_path_s_file (),
1796 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE
:
1798 char *tmp_o_path
= ::concat (get_tempdir ()->get_path (),
1801 invoke_driver (ctxt_progname
,
1802 get_tempdir ()->get_path_s_file (),
1805 false, /* bool shared, */
1806 false);/* bool run_linker */
1807 if (!errors_occurred ())
1808 copy_file (tmp_o_path
,
1814 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY
:
1815 invoke_driver (ctxt_progname
,
1816 get_tempdir ()->get_path_s_file (),
1817 get_tempdir ()->get_path_so_file (),
1819 true, /* bool shared, */
1820 true);/* bool run_linker */
1821 if (!errors_occurred ())
1822 copy_file (get_tempdir ()->get_path_so_file (),
1826 case GCC_JIT_OUTPUT_KIND_EXECUTABLE
:
1828 char *tmp_exe_path
= ::concat (get_tempdir ()->get_path (),
1831 invoke_driver (ctxt_progname
,
1832 get_tempdir ()->get_path_s_file (),
1835 false, /* bool shared, */
1836 true);/* bool run_linker */
1837 if (!errors_occurred ())
1838 copy_file (tmp_exe_path
,
1840 free (tmp_exe_path
);
1848 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
1849 the "executable" bits).
1851 Any errors that occur are reported on the context and hence count as
1852 a failure of the compile.
1854 We can't in general hardlink or use "rename" from the tempdir since
1855 it might be on a different filesystem to the destination. For example,
1856 I get EXDEV: "Invalid cross-device link". */
1859 playback::compile_to_file::copy_file (const char *src_path
,
1860 const char *dst_path
)
1862 JIT_LOG_SCOPE (get_logger ());
1865 get_logger ()->log ("src_path: %s", src_path
);
1866 get_logger ()->log ("dst_path: %s", dst_path
);
1871 size_t total_sz_in
= 0;
1872 size_t total_sz_out
= 0;
1875 struct stat stat_buf
;
1877 f_in
= fopen (src_path
, "rb");
1881 "unable to open %s for reading: %s",
1887 /* Use stat on the filedescriptor to get the mode,
1888 so that we can copy it over (in particular, the
1889 "executable" bits). */
1890 if (-1 == fstat (fileno (f_in
), &stat_buf
))
1893 "unable to fstat %s: %s",
1900 f_out
= fopen (dst_path
, "wb");
1904 "unable to open %s for writing: %s",
1911 while ( (sz_in
= fread (buf
, 1, sizeof (buf
), f_in
)) )
1913 total_sz_in
+= sz_in
;
1914 size_t sz_out_remaining
= sz_in
;
1915 size_t sz_out_so_far
= 0;
1916 while (sz_out_remaining
)
1918 size_t sz_out
= fwrite (buf
+ sz_out_so_far
,
1922 gcc_assert (sz_out
<= sz_out_remaining
);
1926 "error writing to %s: %s",
1933 total_sz_out
+= sz_out
;
1934 sz_out_so_far
+= sz_out
;
1935 sz_out_remaining
-= sz_out
;
1937 gcc_assert (sz_out_so_far
== sz_in
);
1942 "error reading from %s: %s",
1948 gcc_assert (total_sz_in
== total_sz_out
);
1950 get_logger ()->log ("total bytes copied: %ld", total_sz_out
);
1952 /* Set the permissions of the copy to those of the original file,
1953 in particular the "executable" bits. */
1954 if (-1 == fchmod (fileno (f_out
), stat_buf
.st_mode
))
1956 "error setting mode of %s: %s",
1963 /* Helper functions for gcc::jit::playback::context::compile. */
1965 /* This mutex guards gcc::jit::recording::context::compile, so that only
1966 one thread can be accessing the bulk of GCC's state at once. */
1968 static pthread_mutex_t jit_mutex
= PTHREAD_MUTEX_INITIALIZER
;
1970 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
1973 playback::context::acquire_mutex ()
1975 /* Acquire the big GCC mutex. */
1976 JIT_LOG_SCOPE (get_logger ());
1977 pthread_mutex_lock (&jit_mutex
);
1978 gcc_assert (NULL
== active_playback_ctxt
);
1979 active_playback_ctxt
= this;
1982 /* Release jit_mutex and clear the active playback ctxt. */
1985 playback::context::release_mutex ()
1987 /* Release the big GCC mutex. */
1988 JIT_LOG_SCOPE (get_logger ());
1989 gcc_assert (active_playback_ctxt
== this);
1990 active_playback_ctxt
= NULL
;
1991 pthread_mutex_unlock (&jit_mutex
);
1994 /* Callback used by gcc::jit::playback::context::make_fake_args when
1995 invoking driver_get_configure_time_options.
1996 Populate a vec <char * > with the configure-time options. */
1999 append_arg_from_driver (const char *option
, void *user_data
)
2001 gcc_assert (option
);
2002 gcc_assert (user_data
);
2003 vec
<char *> *argvec
= static_cast <vec
<char *> *> (user_data
);
2004 argvec
->safe_push (concat ("-", option
, NULL
));
2007 /* Build a fake argv for toplev::main from the options set
2008 by the user on the context . */
2012 make_fake_args (vec
<char *> *argvec
,
2013 const char *ctxt_progname
,
2014 vec
<recording::requested_dump
> *requested_dumps
)
2016 JIT_LOG_SCOPE (get_logger ());
2018 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2019 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2021 ADD_ARG (ctxt_progname
);
2022 ADD_ARG (get_path_c_file ());
2025 /* Handle int options: */
2026 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
))
2030 "unrecognized optimization level: %i",
2031 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
));
2050 /* What about -Os? */
2052 /* Handle bool options: */
2053 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2056 /* Suppress timing (and other) info. */
2057 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
))
2063 /* Aggressively garbage-collect, to shake out bugs: */
2064 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC
))
2066 ADD_ARG ("--param");
2067 ADD_ARG ("ggc-min-expand=0");
2068 ADD_ARG ("--param");
2069 ADD_ARG ("ggc-min-heapsize=0");
2072 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
))
2074 ADD_ARG ("-fdump-tree-all");
2075 ADD_ARG ("-fdump-rtl-all");
2076 ADD_ARG ("-fdump-ipa-all");
2079 /* Add "-fdump-" options for any calls to
2080 gcc_jit_context_enable_dump. */
2083 recording::requested_dump
*d
;
2084 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2086 char *arg
= concat ("-fdump-", d
->m_dumpname
, NULL
);
2087 ADD_ARG_TAKE_OWNERSHIP (arg
);
2091 /* PR jit/64810: Add any target-specific default options
2092 from OPTION_DEFAULT_SPECS, normally provided by the driver
2093 in the non-jit case.
2095 The target-specific code can define OPTION_DEFAULT_SPECS:
2096 default command options in the form of spec macros for the
2097 driver to expand ().
2099 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2100 if not overriden, injects the defaults as extra arguments to
2102 For the jit case, we need to add these arguments here. The
2103 input format (using the specs language) means that we have to run
2104 part of the driver code here (driver_get_configure_time_options).
2106 To avoid running the spec-expansion code every time, we just do
2107 it the first time (via a function-static flag), saving the result
2108 into a function-static vec.
2109 This flag and vec are global state (i.e. per-process).
2110 They are guarded by the jit mutex. */
2112 static bool have_configure_time_options
= false;
2113 static vec
<char *> configure_time_options
;
2115 if (have_configure_time_options
)
2116 log ("reusing cached configure-time options");
2119 have_configure_time_options
= true;
2120 log ("getting configure-time options from driver");
2121 driver_get_configure_time_options (append_arg_from_driver
,
2122 &configure_time_options
);
2129 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2130 log ("configure_time_options[%i]: %s", i
, opt
);
2132 /* configure_time_options should now contain the expanded options
2133 from OPTION_DEFAULT_SPECS (if any). */
2134 FOR_EACH_VEC_ELT (configure_time_options
, i
, opt
)
2137 gcc_assert (opt
[0] == '-');
2143 #undef ADD_ARG_TAKE_OWNERSHIP
2146 /* The second half of the implementation of gcc_jit_context_enable_dump.
2147 Iterate through the requested dumps, reading the underlying files
2148 into heap-allocated buffers, writing pointers to the buffers into
2149 the char ** pointers provided by client code.
2150 Client code is responsible for calling free on the results. */
2154 extract_any_requested_dumps (vec
<recording::requested_dump
> *requested_dumps
)
2156 JIT_LOG_SCOPE (get_logger ());
2159 recording::requested_dump
*d
;
2160 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
2162 dump_file_info
*dfi
;
2166 dfi
= g
->get_dumps ()->get_dump_file_info_by_switch (d
->m_dumpname
);
2169 add_error (NULL
, "unrecognized dump: %s", d
->m_dumpname
);
2173 filename
= g
->get_dumps ()->get_dump_file_name (dfi
);
2174 content
= read_dump_file (filename
);
2175 *(d
->m_out_ptr
) = content
;
2180 /* Helper function for playback::context::extract_any_requested_dumps
2181 (itself for use in implementation of gcc_jit_context_enable_dump).
2183 Attempt to read the complete file at the given path, returning the
2184 bytes found there as a buffer.
2185 The caller is responsible for calling free on the result.
2186 Errors will be reported on the context, and lead to NULL being
2187 returned; an out-of-memory error will terminate the process. */
2190 playback::context::read_dump_file (const char *path
)
2192 char *result
= NULL
;
2193 size_t total_sz
= 0;
2198 f_in
= fopen (path
, "r");
2201 add_error (NULL
, "unable to open %s for reading", path
);
2205 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2207 size_t old_total_sz
= total_sz
;
2209 result
= reinterpret_cast <char *> (xrealloc (result
, total_sz
+ 1));
2210 memcpy (result
+ old_total_sz
, buf
, sz
);
2215 add_error (NULL
, "error reading from %s", path
);
2225 result
[total_sz
] = '\0';
2229 return xstrdup ("");
2232 /* Part of playback::context::compile ().
2234 We have a .s file; we want a .so file.
2235 We could reuse parts of gcc/gcc.c to do this.
2236 For now, just use the driver binary from the install, as
2237 named in gcc-driver-name.h
2238 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2242 convert_to_dso (const char *ctxt_progname
)
2244 JIT_LOG_SCOPE (get_logger ());
2246 invoke_driver (ctxt_progname
,
2247 m_tempdir
->get_path_s_file (),
2248 m_tempdir
->get_path_so_file (),
2250 true, /* bool shared, */
2251 true);/* bool run_linker */
2256 invoke_driver (const char *ctxt_progname
,
2257 const char *input_file
,
2258 const char *output_file
,
2263 JIT_LOG_SCOPE (get_logger ());
2264 /* Currently this lumps together both assembling and linking into
2266 auto_timevar
assemble_timevar (tv_id
);
2268 auto_vec
<const char *> argvec
;
2269 #define ADD_ARG(arg) argvec.safe_push (arg)
2270 int exit_status
= 0;
2272 const char *gcc_driver_name
= GCC_DRIVER_NAME
;
2274 ADD_ARG (gcc_driver_name
);
2277 ADD_ARG ("-shared");
2282 ADD_ARG (input_file
);
2284 ADD_ARG (output_file
);
2286 /* Don't use the linker plugin.
2287 If running with just a "make" and not a "make install", then we'd
2289 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2290 libto_plugin is a .la at build time, with it becoming installed with
2291 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2293 ADD_ARG ("-fno-use-linker-plugin");
2295 /* pex argv arrays are NULL-terminated. */
2298 /* pex_one's error-handling requires pname to be non-NULL. */
2299 gcc_assert (ctxt_progname
);
2302 for (unsigned i
= 0; i
< argvec
.length (); i
++)
2303 get_logger ()->log ("argv[%i]: %s", i
, argvec
[i
]);
2305 errmsg
= pex_one (PEX_SEARCH
, /* int flags, */
2307 const_cast <char *const *> (argvec
.address ()),
2308 ctxt_progname
, /* const char *pname */
2309 NULL
, /* const char *outname */
2310 NULL
, /* const char *errname */
2311 &exit_status
, /* int *status */
2312 &err
); /* int *err*/
2315 add_error (NULL
, "error invoking gcc driver: %s", errmsg
);
2319 /* pex_one can return a NULL errmsg when the executable wasn't
2320 found (or doesn't exist), so trap these cases also. */
2321 if (exit_status
|| err
)
2324 "error invoking gcc driver: exit_status: %i err: %i",
2327 "whilst attempting to run a driver named: %s",
2337 /* Dynamically-link the built DSO file into this process, using dlopen.
2338 Wrap it up within a jit::result *, and return that.
2339 Return NULL if any errors occur, reporting them on this context. */
2345 JIT_LOG_SCOPE (get_logger ());
2346 auto_timevar
load_timevar (TV_LOAD
);
2347 void *handle
= NULL
;
2348 const char *error
= NULL
;
2349 result
*result_obj
= NULL
;
2351 /* Clear any existing error. */
2354 handle
= dlopen (m_tempdir
->get_path_so_file (),
2355 RTLD_NOW
| RTLD_LOCAL
);
2356 if ((error
= dlerror()) != NULL
) {
2357 add_error (NULL
, "%s", error
);
2361 /* We've successfully dlopened the result; create a
2362 jit::result object to wrap it.
2364 We're done with the tempdir for now, but if the user
2365 has requested debugging, the user's debugger might not
2366 be capable of dealing with the .so file being unlinked
2367 immediately, so keep it around until after the result
2368 is released. We do this by handing over ownership of
2369 the jit::tempdir to the result. See PR jit/64206. */
2370 tempdir
*handover_tempdir
;
2371 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
2373 handover_tempdir
= m_tempdir
;
2375 /* The tempdir will eventually be cleaned up in the
2376 jit::result's dtor. */
2377 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2378 " handing over tempdir to jit::result");
2382 handover_tempdir
= NULL
;
2383 /* ... and retain ownership of m_tempdir so we clean it
2384 up it the playback::context's dtor. */
2385 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2386 " retaining ownership of tempdir");
2389 result_obj
= new result (get_logger (), handle
, handover_tempdir
);
2397 /* Top-level hook for playing back a recording context.
2399 This plays back m_recording_ctxt, and, if no errors
2400 occurred builds statement lists for and then postprocesses
2401 every function in the result. */
2407 JIT_LOG_SCOPE (get_logger ());
2408 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2409 tree array_domain_type
= build_index_type (size_int (200));
2410 m_char_array_type_node
2411 = build_array_type (char_type_node
, array_domain_type
);
2414 = build_pointer_type (build_qualified_type (char_type_node
,
2417 /* Replay the recorded events: */
2418 timevar_push (TV_JIT_REPLAY
);
2420 m_recording_ctxt
->replay_into (this);
2422 /* Clean away the temporary references from recording objects
2423 to playback objects. We have to do this now since the
2424 latter are GC-allocated, but the former don't mark these
2425 refs. Hence we must stop using them before the GC can run. */
2426 m_recording_ctxt
->disassociate_from_playback ();
2428 /* The builtins_manager, if any, is associated with the recording::context
2429 and might be reused for future compiles on other playback::contexts,
2430 but its m_attributes array is not GTY-labeled and hence will become
2431 nonsense if the GC runs. Purge this state. */
2432 builtins_manager
*bm
= get_builtins_manager ();
2434 bm
->finish_playback ();
2436 timevar_pop (TV_JIT_REPLAY
);
2438 if (!errors_occurred ())
2443 /* No GC can happen yet; process the cached source locations. */
2444 handle_locations ();
2446 /* We've now created tree nodes for the stmts in the various blocks
2447 in each function, but we haven't built each function's single stmt
2448 list yet. Do so now. */
2449 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2450 func
->build_stmt_list ();
2452 /* No GC can have happened yet. */
2454 /* Postprocess the functions. This could trigger GC. */
2455 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2458 func
->postprocess ();
2463 /* Dump the generated .s file to stderr. */
2467 dump_generated_code ()
2469 JIT_LOG_SCOPE (get_logger ());
2472 FILE *f_in
= fopen (get_path_s_file (), "r");
2476 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2477 fwrite (buf
, 1, sz
, stderr
);
2482 /* Get the supposed path of the notional "fake.c" file within the
2483 tempdir. This file doesn't exist, but the rest of the compiler
2488 get_path_c_file () const
2490 return m_tempdir
->get_path_c_file ();
2493 /* Get the path of the assembler output file "fake.s" file within the
2498 get_path_s_file () const
2500 return m_tempdir
->get_path_s_file ();
2503 /* Get the path of the DSO object file "fake.so" file within the
2508 get_path_so_file () const
2510 return m_tempdir
->get_path_so_file ();
2513 /* qsort comparator for comparing pairs of playback::source_line *,
2514 ordering them by line number. */
2517 line_comparator (const void *lhs
, const void *rhs
)
2519 const playback::source_line
*line_lhs
= \
2520 *static_cast<const playback::source_line
* const*> (lhs
);
2521 const playback::source_line
*line_rhs
= \
2522 *static_cast<const playback::source_line
* const*> (rhs
);
2523 return line_lhs
->get_line_num () - line_rhs
->get_line_num ();
2526 /* qsort comparator for comparing pairs of playback::location *,
2527 ordering them by column number. */
2530 location_comparator (const void *lhs
, const void *rhs
)
2532 const playback::location
*loc_lhs
= \
2533 *static_cast<const playback::location
* const *> (lhs
);
2534 const playback::location
*loc_rhs
= \
2535 *static_cast<const playback::location
* const *> (rhs
);
2536 return loc_lhs
->get_column_num () - loc_rhs
->get_column_num ();
2539 /* Our API allows locations to be created in arbitrary orders, but the
2540 linemap API requires locations to be created in ascending order
2541 as if we were tokenizing files.
2543 This hook sorts all of the the locations that have been created, and
2544 calls into the linemap API, creating linemap entries in sorted order
2545 for our locations. */
2551 /* Create the source code locations, following the ordering rules
2552 imposed by the linemap API.
2554 line_table is a global. */
2555 JIT_LOG_SCOPE (get_logger ());
2559 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2561 linemap_add (line_table
, LC_ENTER
, false, file
->get_filename (), 0);
2563 /* Sort lines by ascending line numbers. */
2564 file
->m_source_lines
.qsort (&line_comparator
);
2568 FOR_EACH_VEC_ELT (file
->m_source_lines
, j
, line
)
2573 /* Sort locations in line by ascending column numbers. */
2574 line
->m_locations
.qsort (&location_comparator
);
2576 /* Determine maximum column within this line. */
2577 gcc_assert (line
->m_locations
.length () > 0);
2578 location
*final_column
=
2579 line
->m_locations
[line
->m_locations
.length () - 1];
2580 int max_col
= final_column
->get_column_num ();
2582 linemap_line_start (line_table
, line
->get_line_num (), max_col
);
2583 FOR_EACH_VEC_ELT (line
->m_locations
, k
, loc
)
2586 linemap_position_for_column (line_table
, loc
->get_column_num ());
2590 linemap_add (line_table
, LC_LEAVE
, false, NULL
, 0);
2593 /* line_table should now be populated; every playback::location should
2594 now have an m_srcloc. */
2596 /* Now assign them to tree nodes as appropriate. */
2597 std::pair
<tree
, location
*> *cached_location
;
2599 FOR_EACH_VEC_ELT (m_cached_locations
, i
, cached_location
)
2601 tree t
= cached_location
->first
;
2602 source_location srcloc
= cached_location
->second
->m_srcloc
;
2604 /* This covers expressions: */
2605 if (CAN_HAVE_LOCATION_P (t
))
2606 SET_EXPR_LOCATION (t
, srcloc
);
2607 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t
), TS_DECL_MINIMAL
))
2608 DECL_SOURCE_LOCATION (t
) = srcloc
;
2611 /* Don't know how to set location on this node. */
2616 /* We handle errors on a playback::context by adding them to the
2617 corresponding recording::context. */
2621 add_error (location
*loc
, const char *fmt
, ...)
2625 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2630 /* We handle errors on a playback::context by adding them to the
2631 corresponding recording::context. */
2635 add_error_va (location
*loc
, const char *fmt
, va_list ap
)
2637 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2641 /* Dealing with the linemap API. */
2643 /* Construct a playback::location for a recording::location, if it
2644 doesn't exist already. */
2646 playback::location
*
2648 new_location (recording::location
*rloc
,
2649 const char *filename
,
2653 /* Get the source_file for filename, creating if necessary. */
2654 source_file
*src_file
= get_source_file (filename
);
2655 /* Likewise for the line within the file. */
2656 source_line
*src_line
= src_file
->get_source_line (line
);
2657 /* Likewise for the column within the line. */
2658 location
*loc
= src_line
->get_location (rloc
, column
);
2662 /* Deferred setting of the location for a given tree, by adding the
2663 (tree, playback::location) pair to a list of deferred associations.
2664 We will actually set the location on the tree later on once
2665 the source_location for the playback::location exists. */
2669 set_tree_location (tree t
, location
*loc
)
2672 m_cached_locations
.safe_push (std::make_pair (t
, loc
));
2676 /* Construct a playback::source_file for the given source
2677 filename, if it doesn't exist already. */
2679 playback::source_file
*
2681 get_source_file (const char *filename
)
2684 For simplicitly, this is currently a linear search.
2685 Replace with a hash if this shows up in the profile. */
2688 tree ident_filename
= get_identifier (filename
);
2690 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2691 if (file
->filename_as_tree () == ident_filename
)
2695 file
= new source_file (ident_filename
);
2696 m_source_files
.safe_push (file
);
2700 /* Constructor for gcc::jit::playback::source_file. */
2702 playback::source_file::source_file (tree filename
) :
2704 m_filename (filename
)
2708 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2712 playback::source_file::finalizer ()
2714 m_source_lines
.release ();
2717 /* Construct a playback::source_line for the given line
2718 within this source file, if one doesn't exist already. */
2720 playback::source_line
*
2721 playback::source_file::
2722 get_source_line (int line_num
)
2725 For simplicitly, this is currently a linear search.
2726 Replace with a hash if this shows up in the profile. */
2730 FOR_EACH_VEC_ELT (m_source_lines
, i
, line
)
2731 if (line
->get_line_num () == line_num
)
2735 line
= new source_line (this, line_num
);
2736 m_source_lines
.safe_push (line
);
2740 /* Constructor for gcc::jit::playback::source_line. */
2742 playback::source_line::source_line (source_file
*file
, int line_num
) :
2744 m_source_file (file
),
2745 m_line_num (line_num
)
2749 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2753 playback::source_line::finalizer ()
2755 m_locations
.release ();
2758 /* Construct a playback::location for the given column
2759 within this line of a specific source file, if one doesn't exist
2762 playback::location
*
2763 playback::source_line::
2764 get_location (recording::location
*rloc
, int column_num
)
2769 /* Another linear search that probably should be a hash table. */
2770 FOR_EACH_VEC_ELT (m_locations
, i
, loc
)
2771 if (loc
->get_column_num () == column_num
)
2775 loc
= new location (rloc
, this, column_num
);
2776 m_locations
.safe_push (loc
);
2780 /* Constructor for gcc::jit::playback::location. */
2782 playback::location::location (recording::location
*loc
,
2785 m_srcloc (UNKNOWN_LOCATION
),
2786 m_recording_loc (loc
),
2788 m_column_num(column_num
)
2792 /* The active gcc::jit::playback::context instance. This is a singleton,
2793 guarded by jit_mutex. */
2795 playback::context
*active_playback_ctxt
;
2797 } // namespace gcc::jit