1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2014 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"
28 #include "plugin-api.h"
34 #include "hard-reg-set.h"
44 #include "stringpool.h"
45 #include "stor-layout.h"
46 #include "print-tree.h"
48 #include "gcc-driver-name.h"
52 #include "jit-common.h"
53 #include "jit-playback.h"
54 #include "jit-result.h"
55 #include "jit-builtins.h"
56 #include "jit-tempdir.h"
59 /* gcc::jit::playback::context::build_cast uses the convert.h API,
60 which in turn requires the frontend to provide a "convert"
61 function, apparently as a fallback.
63 Hence we provide this dummy one, with the requirement that any casts
64 are handled before reaching this. */
65 extern tree
convert (tree type
, tree expr
);
68 convert (tree dst_type
, tree expr
)
70 gcc_assert (gcc::jit::active_playback_ctxt
);
71 gcc::jit::active_playback_ctxt
->add_error (NULL
, "unhandled conversion");
72 fprintf (stderr
, "input expression:\n");
74 fprintf (stderr
, "requested type:\n");
75 debug_tree (dst_type
);
76 return error_mark_node
;
82 /**********************************************************************
84 **********************************************************************/
86 /* The constructor for gcc::jit::playback::context. */
88 playback::context::context (recording::context
*ctxt
)
89 : m_recording_ctxt (ctxt
),
91 m_char_array_type_node (NULL
),
92 m_const_char_ptr (NULL
)
94 m_functions
.create (0);
95 m_source_files
.create (0);
96 m_cached_locations
.create (0);
99 /* The destructor for gcc::jit::playback::context. */
101 playback::context::~context ()
105 m_functions
.release ();
108 /* A playback::context can reference GC-managed pointers. Mark them
109 ("by hand", rather than by gengtype).
111 This is called on the active playback context (if any) by the
112 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
120 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
122 if (ggc_test_and_set_mark (func
))
127 /* Given an enum gcc_jit_types value, get a "tree" type. */
130 get_tree_node_for_type (enum gcc_jit_types type_
)
134 case GCC_JIT_TYPE_VOID
:
135 return void_type_node
;
137 case GCC_JIT_TYPE_VOID_PTR
:
138 return ptr_type_node
;
140 case GCC_JIT_TYPE_BOOL
:
141 return boolean_type_node
;
143 case GCC_JIT_TYPE_CHAR
:
144 return char_type_node
;
145 case GCC_JIT_TYPE_SIGNED_CHAR
:
146 return signed_char_type_node
;
147 case GCC_JIT_TYPE_UNSIGNED_CHAR
:
148 return unsigned_char_type_node
;
150 case GCC_JIT_TYPE_SHORT
:
151 return short_integer_type_node
;
152 case GCC_JIT_TYPE_UNSIGNED_SHORT
:
153 return short_unsigned_type_node
;
155 case GCC_JIT_TYPE_CONST_CHAR_PTR
:
157 tree const_char
= build_qualified_type (char_type_node
,
159 return build_pointer_type (const_char
);
162 case GCC_JIT_TYPE_INT
:
163 return integer_type_node
;
164 case GCC_JIT_TYPE_UNSIGNED_INT
:
165 return unsigned_type_node
;
167 case GCC_JIT_TYPE_LONG
:
168 return long_integer_type_node
;
169 case GCC_JIT_TYPE_UNSIGNED_LONG
:
170 return long_unsigned_type_node
;
172 case GCC_JIT_TYPE_LONG_LONG
:
173 return long_long_integer_type_node
;
174 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG
:
175 return long_long_unsigned_type_node
;
177 case GCC_JIT_TYPE_FLOAT
:
178 return float_type_node
;
179 case GCC_JIT_TYPE_DOUBLE
:
180 return double_type_node
;
181 case GCC_JIT_TYPE_LONG_DOUBLE
:
182 return long_double_type_node
;
184 case GCC_JIT_TYPE_SIZE_T
:
185 return size_type_node
;
187 case GCC_JIT_TYPE_FILE_PTR
:
188 return fileptr_type_node
;
190 case GCC_JIT_TYPE_COMPLEX_FLOAT
:
191 return complex_float_type_node
;
192 case GCC_JIT_TYPE_COMPLEX_DOUBLE
:
193 return complex_double_type_node
;
194 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE
:
195 return complex_long_double_type_node
;
201 /* Construct a playback::type instance (wrapping a tree) for the given
206 get_type (enum gcc_jit_types type_
)
208 tree type_node
= get_tree_node_for_type (type_
);
209 if (NULL
== type_node
)
212 "unrecognized (enum gcc_jit_types) value: %i", type_
);
216 return new type (type_node
);
219 /* Construct a playback::type instance (wrapping a tree) for the given
224 new_array_type (playback::location
*loc
,
225 playback::type
*element_type
,
228 gcc_assert (element_type
);
230 tree t
= build_array_type_nelts (element_type
->as_tree (),
235 set_tree_location (t
, loc
);
240 /* Construct a playback::field instance (wrapping a tree). */
244 new_field (location
*loc
,
251 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
252 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
253 get_identifier (name
), type
->as_tree ());
256 set_tree_location (decl
, loc
);
258 return new field (decl
);
261 /* Construct a playback::compound_type instance (wrapping a tree). */
263 playback::compound_type
*
265 new_compound_type (location
*loc
,
267 bool is_struct
) /* else is union */
271 /* Compare with c/c-decl.c: start_struct. */
273 tree t
= make_node (is_struct
? RECORD_TYPE
: UNION_TYPE
);
274 TYPE_NAME (t
) = get_identifier (name
);
278 set_tree_location (t
, loc
);
280 return new compound_type (t
);
284 playback::compound_type::set_fields (const auto_vec
<playback::field
*> *fields
)
286 /* Compare with c/c-decl.c: finish_struct. */
289 tree fieldlist
= NULL
;
290 for (unsigned i
= 0; i
< fields
->length (); i
++)
292 field
*f
= (*fields
)[i
];
293 DECL_CONTEXT (f
->as_tree ()) = t
;
294 fieldlist
= chainon (f
->as_tree (), fieldlist
);
296 fieldlist
= nreverse (fieldlist
);
297 TYPE_FIELDS (t
) = fieldlist
;
302 /* Construct a playback::type instance (wrapping a tree) for a function
307 new_function_type (type
*return_type
,
308 const auto_vec
<type
*> *param_types
,
314 tree
*arg_types
= (tree
*)xcalloc(param_types
->length (), sizeof(tree
*));
316 FOR_EACH_VEC_ELT (*param_types
, i
, param_type
)
317 arg_types
[i
] = param_type
->as_tree ();
322 build_varargs_function_type_array (return_type
->as_tree (),
323 param_types
->length (),
326 fn_type
= build_function_type_array (return_type
->as_tree (),
327 param_types
->length (),
331 return new type (fn_type
);
334 /* Construct a playback::param instance (wrapping a tree). */
338 new_param (location
*loc
,
344 tree inner
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
345 get_identifier (name
), type
->as_tree ());
347 set_tree_location (inner
, loc
);
349 return new param (this, inner
);
352 /* Construct a playback::function instance. */
356 new_function (location
*loc
,
357 enum gcc_jit_function_kind kind
,
360 const auto_vec
<param
*> *params
,
362 enum built_in_function builtin_id
)
367 //can return_type be NULL?
370 tree
*arg_types
= (tree
*)xcalloc(params
->length (), sizeof(tree
*));
371 FOR_EACH_VEC_ELT (*params
, i
, param
)
372 arg_types
[i
] = TREE_TYPE (param
->as_tree ());
376 fn_type
= build_varargs_function_type_array (return_type
->as_tree (),
377 params
->length (), arg_types
);
379 fn_type
= build_function_type_array (return_type
->as_tree (),
380 params
->length (), arg_types
);
383 /* FIXME: this uses input_location: */
384 tree fndecl
= build_fn_decl (name
, fn_type
);
387 set_tree_location (fndecl
, loc
);
389 tree resdecl
= build_decl (UNKNOWN_LOCATION
, RESULT_DECL
,
390 NULL_TREE
, return_type
->as_tree ());
391 DECL_ARTIFICIAL (resdecl
) = 1;
392 DECL_IGNORED_P (resdecl
) = 1;
393 DECL_RESULT (fndecl
) = resdecl
;
397 DECL_FUNCTION_CODE (fndecl
) = builtin_id
;
398 gcc_assert (loc
== NULL
);
399 DECL_SOURCE_LOCATION (fndecl
) = BUILTINS_LOCATION
;
401 DECL_BUILT_IN_CLASS (fndecl
) =
402 builtins_manager::get_class (builtin_id
);
403 set_builtin_decl (builtin_id
, fndecl
,
404 builtins_manager::implicit_p (builtin_id
));
406 builtins_manager
*bm
= get_builtins_manager ();
407 tree attrs
= bm
->get_attrs_tree (builtin_id
);
409 decl_attributes (&fndecl
, attrs
, ATTR_FLAG_BUILT_IN
);
411 decl_attributes (&fndecl
, NULL_TREE
, 0);
414 if (kind
!= GCC_JIT_FUNCTION_IMPORTED
)
416 tree param_decl_list
= NULL
;
417 FOR_EACH_VEC_ELT (*params
, i
, param
)
419 param_decl_list
= chainon (param
->as_tree (), param_decl_list
);
422 /* The param list was created in reverse order; fix it: */
423 param_decl_list
= nreverse (param_decl_list
);
426 for (t
= param_decl_list
; t
; t
= DECL_CHAIN (t
))
428 DECL_CONTEXT (t
) = fndecl
;
429 DECL_ARG_TYPE (t
) = TREE_TYPE (t
);
432 /* Set it up on DECL_ARGUMENTS */
433 DECL_ARGUMENTS(fndecl
) = param_decl_list
;
436 if (kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
438 DECL_DECLARED_INLINE_P (fndecl
) = 1;
440 /* Add attribute "always_inline": */
441 DECL_ATTRIBUTES (fndecl
) =
442 tree_cons (get_identifier ("always_inline"),
444 DECL_ATTRIBUTES (fndecl
));
447 function
*func
= new function (this, fndecl
, kind
);
448 m_functions
.safe_push (func
);
452 /* Construct a playback::lvalue instance (wrapping a tree). */
456 new_global (location
*loc
,
462 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
463 get_identifier (name
),
465 TREE_PUBLIC (inner
) = 1;
466 DECL_COMMON (inner
) = 1;
467 DECL_EXTERNAL (inner
) = 1;
470 set_tree_location (inner
, loc
);
472 return new lvalue (this, inner
);
475 /* Construct a playback::rvalue instance (wrapping a tree). */
479 new_rvalue_from_int (type
*type
,
482 // FIXME: type-checking, or coercion?
483 tree inner_type
= type
->as_tree ();
484 if (INTEGRAL_TYPE_P (inner_type
))
486 tree inner
= build_int_cst (inner_type
, value
);
487 return new rvalue (this, inner
);
491 REAL_VALUE_TYPE real_value
;
492 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
493 tree inner
= build_real (inner_type
, real_value
);
494 return new rvalue (this, inner
);
498 /* Construct a playback::rvalue instance (wrapping a tree). */
502 new_rvalue_from_double (type
*type
,
505 // FIXME: type-checking, or coercion?
506 tree inner_type
= type
->as_tree ();
508 /* We have a "double", we want a REAL_VALUE_TYPE.
510 real.c:real_from_target appears to require the representation to be
511 split into 32-bit values, and then sent as an pair of host long
513 REAL_VALUE_TYPE real_value
;
517 uint32_t as_uint32s
[2];
520 long int as_long_ints
[2];
521 as_long_ints
[0] = u
.as_uint32s
[0];
522 as_long_ints
[1] = u
.as_uint32s
[1];
523 real_from_target (&real_value
, as_long_ints
, DFmode
);
524 tree inner
= build_real (inner_type
, real_value
);
525 return new rvalue (this, inner
);
528 /* Construct a playback::rvalue instance (wrapping a tree). */
532 new_rvalue_from_ptr (type
*type
,
535 tree inner_type
= type
->as_tree ();
536 /* FIXME: how to ensure we have a wide enough type? */
537 tree inner
= build_int_cstu (inner_type
, (unsigned HOST_WIDE_INT
)value
);
538 return new rvalue (this, inner
);
541 /* Construct a playback::rvalue instance (wrapping a tree). */
545 new_string_literal (const char *value
)
547 tree t_str
= build_string (strlen (value
), value
);
548 gcc_assert (m_char_array_type_node
);
549 TREE_TYPE (t_str
) = m_char_array_type_node
;
551 /* Convert to (const char*), loosely based on
552 c/c-typeck.c: array_to_pointer_conversion,
553 by taking address of start of string. */
554 tree t_addr
= build1 (ADDR_EXPR
, m_const_char_ptr
, t_str
);
556 return new rvalue (this, t_addr
);
559 /* Coerce a tree expression into a boolean tree expression. */
563 as_truth_value (tree expr
, location
*loc
)
565 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
566 tree typed_zero
= fold_build1 (CONVERT_EXPR
,
570 set_tree_location (typed_zero
, loc
);
572 expr
= build2 (NE_EXPR
, integer_type_node
, expr
, typed_zero
);
574 set_tree_location (expr
, loc
);
579 /* Construct a playback::rvalue instance (wrapping a tree) for a
584 new_unary_op (location
*loc
,
585 enum gcc_jit_unary_op op
,
589 // FIXME: type-checking, or coercion?
590 enum tree_code inner_op
;
592 gcc_assert (result_type
);
595 tree node
= a
->as_tree ();
596 tree inner_result
= NULL
;
601 add_error (loc
, "unrecognized (enum gcc_jit_unary_op) value: %i", op
);
604 case GCC_JIT_UNARY_OP_MINUS
:
605 inner_op
= NEGATE_EXPR
;
608 case GCC_JIT_UNARY_OP_BITWISE_NEGATE
:
609 inner_op
= BIT_NOT_EXPR
;
612 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE
:
613 node
= as_truth_value (node
, loc
);
614 inner_result
= invert_truthvalue (node
);
616 set_tree_location (inner_result
, loc
);
617 return new rvalue (this, inner_result
);
620 inner_result
= build1 (inner_op
,
621 result_type
->as_tree (),
624 set_tree_location (inner_result
, loc
);
626 return new rvalue (this, inner_result
);
629 /* Construct a playback::rvalue instance (wrapping a tree) for a
634 new_binary_op (location
*loc
,
635 enum gcc_jit_binary_op op
,
637 rvalue
*a
, rvalue
*b
)
639 // FIXME: type-checking, or coercion?
640 enum tree_code inner_op
;
642 gcc_assert (result_type
);
646 tree node_a
= a
->as_tree ();
647 tree node_b
= b
->as_tree ();
652 add_error (loc
, "unrecognized (enum gcc_jit_binary_op) value: %i", op
);
655 case GCC_JIT_BINARY_OP_PLUS
:
656 inner_op
= PLUS_EXPR
;
659 case GCC_JIT_BINARY_OP_MINUS
:
660 inner_op
= MINUS_EXPR
;
663 case GCC_JIT_BINARY_OP_MULT
:
664 inner_op
= MULT_EXPR
;
667 case GCC_JIT_BINARY_OP_DIVIDE
:
668 if (FLOAT_TYPE_P (result_type
->as_tree ()))
669 /* Floating-point division: */
670 inner_op
= RDIV_EXPR
;
672 /* Truncating to zero: */
673 inner_op
= TRUNC_DIV_EXPR
;
676 case GCC_JIT_BINARY_OP_MODULO
:
677 inner_op
= TRUNC_MOD_EXPR
;
680 case GCC_JIT_BINARY_OP_BITWISE_AND
:
681 inner_op
= BIT_AND_EXPR
;
684 case GCC_JIT_BINARY_OP_BITWISE_XOR
:
685 inner_op
= BIT_XOR_EXPR
;
688 case GCC_JIT_BINARY_OP_BITWISE_OR
:
689 inner_op
= BIT_IOR_EXPR
;
692 case GCC_JIT_BINARY_OP_LOGICAL_AND
:
693 node_a
= as_truth_value (node_a
, loc
);
694 node_b
= as_truth_value (node_b
, loc
);
695 inner_op
= TRUTH_ANDIF_EXPR
;
698 case GCC_JIT_BINARY_OP_LOGICAL_OR
:
699 node_a
= as_truth_value (node_a
, loc
);
700 node_b
= as_truth_value (node_b
, loc
);
701 inner_op
= TRUTH_ORIF_EXPR
;
704 case GCC_JIT_BINARY_OP_LSHIFT
:
705 inner_op
= LSHIFT_EXPR
;
708 case GCC_JIT_BINARY_OP_RSHIFT
:
709 inner_op
= RSHIFT_EXPR
;
713 tree inner_expr
= build2 (inner_op
,
714 result_type
->as_tree (),
718 set_tree_location (inner_expr
, loc
);
720 return new rvalue (this, inner_expr
);
723 /* Construct a playback::rvalue instance (wrapping a tree) for a
728 new_comparison (location
*loc
,
729 enum gcc_jit_comparison op
,
730 rvalue
*a
, rvalue
*b
)
732 // FIXME: type-checking, or coercion?
733 enum tree_code inner_op
;
741 add_error (loc
, "unrecognized (enum gcc_jit_comparison) value: %i", op
);
744 case GCC_JIT_COMPARISON_EQ
:
747 case GCC_JIT_COMPARISON_NE
:
750 case GCC_JIT_COMPARISON_LT
:
753 case GCC_JIT_COMPARISON_LE
:
756 case GCC_JIT_COMPARISON_GT
:
759 case GCC_JIT_COMPARISON_GE
:
764 tree inner_expr
= build2 (inner_op
,
769 set_tree_location (inner_expr
, loc
);
770 return new rvalue (this, inner_expr
);
773 /* Construct a playback::rvalue instance (wrapping a tree) for a
778 build_call (location
*loc
,
780 const auto_vec
<rvalue
*> *args
)
782 vec
<tree
, va_gc
> *tree_args
;
783 vec_alloc (tree_args
, args
->length ());
784 for (unsigned i
= 0; i
< args
->length (); i
++)
785 tree_args
->quick_push ((*args
)[i
]->as_tree ());
788 set_tree_location (fn_ptr
, loc
);
790 tree fn
= TREE_TYPE (fn_ptr
);
791 tree fn_type
= TREE_TYPE (fn
);
792 tree return_type
= TREE_TYPE (fn_type
);
794 return new rvalue (this,
795 build_call_vec (return_type
,
798 /* see c-typeck.c: build_function_call
799 which calls build_function_call_vec
801 which does lots of checking, then:
802 result = build_call_array_loc (loc, TREE_TYPE (fntype),
803 function, nargs, argarray);
805 (see also build_call_vec)
809 /* Construct a playback::rvalue instance (wrapping a tree) for a
810 call to a specific function. */
814 new_call (location
*loc
,
816 const auto_vec
<rvalue
*> *args
)
822 fndecl
= func
->as_fndecl ();
824 tree fntype
= TREE_TYPE (fndecl
);
826 tree fn
= build1 (ADDR_EXPR
, build_pointer_type (fntype
), fndecl
);
828 return build_call (loc
, fn
, args
);
831 /* Construct a playback::rvalue instance (wrapping a tree) for a
832 call through a function pointer. */
836 new_call_through_ptr (location
*loc
,
838 const auto_vec
<rvalue
*> *args
)
841 tree t_fn_ptr
= fn_ptr
->as_tree ();
843 return build_call (loc
, t_fn_ptr
, args
);
846 /* Construct a tree for a cast. */
849 playback::context::build_cast (playback::location
*loc
,
850 playback::rvalue
*expr
,
851 playback::type
*type_
)
853 /* For comparison, see:
854 - c/c-typeck.c:build_c_cast
855 - c/c-convert.c: convert
858 Only some kinds of cast are currently supported here. */
859 tree t_expr
= expr
->as_tree ();
860 tree t_dst_type
= type_
->as_tree ();
862 t_ret
= targetm
.convert_to_type (t_dst_type
, t_expr
);
865 enum tree_code dst_code
= TREE_CODE (t_dst_type
);
870 t_ret
= convert_to_integer (t_dst_type
, t_expr
);
874 /* Compare with c_objc_common_truthvalue_conversion and
875 c_common_truthvalue_conversion. */
876 /* For now, convert to: (t_expr != 0) */
877 t_ret
= build2 (NE_EXPR
, t_dst_type
,
878 t_expr
, integer_zero_node
);
882 t_ret
= convert_to_real (t_dst_type
, t_expr
);
886 t_ret
= build1 (NOP_EXPR
, t_dst_type
, t_expr
);
890 add_error (loc
, "couldn't handle cast during playback");
891 fprintf (stderr
, "input expression:\n");
893 fprintf (stderr
, "requested type:\n");
894 debug_tree (t_dst_type
);
895 return error_mark_node
;
898 if (TREE_CODE (t_ret
) != C_MAYBE_CONST_EXPR
)
899 t_ret
= fold (t_ret
);
904 /* Construct a playback::rvalue instance (wrapping a tree) for a
909 new_cast (playback::location
*loc
,
910 playback::rvalue
*expr
,
911 playback::type
*type_
)
914 tree t_cast
= build_cast (loc
, expr
, type_
);
916 set_tree_location (t_cast
, loc
);
917 return new rvalue (this, t_cast
);
920 /* Construct a playback::lvalue instance (wrapping a tree) for an
925 new_array_access (location
*loc
,
932 /* For comparison, see:
933 c/c-typeck.c: build_array_ref
934 c-family/c-common.c: pointer_int_sum
936 tree t_ptr
= ptr
->as_tree ();
937 tree t_index
= index
->as_tree ();
938 tree t_type_ptr
= TREE_TYPE (t_ptr
);
939 tree t_type_star_ptr
= TREE_TYPE (t_type_ptr
);
941 if (TREE_CODE (t_type_ptr
) == ARRAY_TYPE
)
943 tree t_result
= build4 (ARRAY_REF
, t_type_star_ptr
, t_ptr
, t_index
,
944 NULL_TREE
, NULL_TREE
);
946 set_tree_location (t_result
, loc
);
947 return new lvalue (this, t_result
);
951 /* Convert index to an offset in bytes. */
952 tree t_sizeof
= size_in_bytes (t_type_star_ptr
);
953 t_index
= fold_build1 (CONVERT_EXPR
, sizetype
, t_index
);
954 tree t_offset
= build2 (MULT_EXPR
, sizetype
, t_index
, t_sizeof
);
956 /* Locate (ptr + offset). */
957 tree t_address
= build2 (POINTER_PLUS_EXPR
, t_type_ptr
, t_ptr
, t_offset
);
959 tree t_indirection
= build1 (INDIRECT_REF
, t_type_star_ptr
, t_address
);
962 set_tree_location (t_sizeof
, loc
);
963 set_tree_location (t_offset
, loc
);
964 set_tree_location (t_address
, loc
);
965 set_tree_location (t_indirection
, loc
);
968 return new lvalue (this, t_indirection
);
972 /* Construct a tree for a field access. */
976 new_field_access (location
*loc
,
983 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
984 build_component_ref. */
985 tree type
= TREE_TYPE (datum
);
987 gcc_assert (TREE_CODE (type
) != POINTER_TYPE
);
989 tree t_field
= field
->as_tree ();
990 tree ref
= build3 (COMPONENT_REF
, TREE_TYPE (t_field
), datum
,
993 set_tree_location (ref
, loc
);
997 /* Construct a tree for a dereference. */
1001 new_dereference (tree ptr
,
1006 tree type
= TREE_TYPE (TREE_TYPE(ptr
));
1007 tree datum
= build1 (INDIRECT_REF
, type
, ptr
);
1009 set_tree_location (datum
, loc
);
1013 /* Construct a playback::lvalue instance (wrapping a tree) for a
1018 access_field (location
*loc
,
1021 tree datum
= as_tree ();
1022 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1025 return new lvalue (get_context (), ref
);
1028 /* Construct a playback::rvalue instance (wrapping a tree) for a
1033 access_field (location
*loc
,
1036 tree datum
= as_tree ();
1037 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1040 return new rvalue (get_context (), ref
);
1043 /* Construct a playback::lvalue instance (wrapping a tree) for a
1044 dereferenced field access. */
1048 dereference_field (location
*loc
,
1051 tree ptr
= as_tree ();
1052 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1055 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1058 return new lvalue (get_context (), ref
);
1061 /* Construct a playback::lvalue instance (wrapping a tree) for a
1066 dereference (location
*loc
)
1068 tree ptr
= as_tree ();
1069 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1070 return new lvalue (get_context (), datum
);
1073 /* Construct a playback::rvalue instance (wrapping a tree) for an
1078 get_address (location
*loc
)
1080 tree t_lvalue
= as_tree ();
1081 tree t_thistype
= TREE_TYPE (t_lvalue
);
1082 tree t_ptrtype
= build_pointer_type (t_thistype
);
1083 tree ptr
= build1 (ADDR_EXPR
, t_ptrtype
, t_lvalue
);
1085 get_context ()->set_tree_location (ptr
, loc
);
1086 return new rvalue (get_context (), ptr
);
1089 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1090 Provide this finalization hook for calling then they are collected,
1091 which calls the finalizer vfunc. This allows them to call "release"
1092 on any vec<> within them. */
1095 wrapper_finalizer (void *ptr
)
1097 playback::wrapper
*wrapper
= reinterpret_cast <playback::wrapper
*> (ptr
);
1098 wrapper
->finalizer ();
1101 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1102 allocate them using ggc_internal_cleared_alloc. */
1106 operator new (size_t sz
)
1108 return ggc_internal_cleared_alloc (sz
, wrapper_finalizer
, 0, 1);
1112 /* Constructor for gcc:jit::playback::function. */
1114 playback::function::
1115 function (context
*ctxt
,
1117 enum gcc_jit_function_kind kind
)
1119 m_inner_fndecl (fndecl
),
1120 m_inner_bind_expr (NULL
),
1123 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1125 /* Create a BIND_EXPR, and within it, a statement list. */
1126 m_stmt_list
= alloc_stmt_list ();
1127 m_stmt_iter
= tsi_start (m_stmt_list
);
1128 m_inner_block
= make_node (BLOCK
);
1130 build3 (BIND_EXPR
, void_type_node
, NULL
, m_stmt_list
, m_inner_block
);
1134 m_inner_block
= NULL
;
1139 /* Hand-written GC-marking hook for playback functions. */
1142 playback::function::
1145 gt_ggc_m_9tree_node (m_inner_fndecl
);
1146 gt_ggc_m_9tree_node (m_inner_bind_expr
);
1147 gt_ggc_m_9tree_node (m_stmt_list
);
1148 gt_ggc_m_9tree_node (m_inner_block
);
1151 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1155 playback::function::finalizer ()
1157 m_blocks
.release ();
1160 /* Get the return type of a playback function, in tree form. */
1163 playback::function::
1164 get_return_type_as_tree () const
1166 return TREE_TYPE (TREE_TYPE(m_inner_fndecl
));
1169 /* Construct a new local within this playback::function. */
1172 playback::function::
1173 new_local (location
*loc
,
1179 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
1180 get_identifier (name
),
1182 DECL_CONTEXT (inner
) = this->m_inner_fndecl
;
1184 /* Prepend to BIND_EXPR_VARS: */
1185 DECL_CHAIN (inner
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1186 BIND_EXPR_VARS (m_inner_bind_expr
) = inner
;
1189 set_tree_location (inner
, loc
);
1190 return new lvalue (m_ctxt
, inner
);
1193 /* Construct a new block within this playback::function. */
1196 playback::function::
1197 new_block (const char *name
)
1199 gcc_assert (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
);
1201 block
*result
= new playback::block (this, name
);
1202 m_blocks
.safe_push (result
);
1206 /* Build a statement list for the function as a whole out of the
1207 lists of statements for the individual blocks, building labels
1211 playback::function::
1217 FOR_EACH_VEC_ELT (m_blocks
, i
, b
)
1222 b
->m_label_expr
= build1 (LABEL_EXPR
,
1224 b
->as_label_decl ());
1225 tsi_link_after (&m_stmt_iter
, b
->m_label_expr
, TSI_CONTINUE_LINKING
);
1227 FOR_EACH_VEC_ELT (b
->m_stmts
, j
, stmt
)
1228 tsi_link_after (&m_stmt_iter
, stmt
, TSI_CONTINUE_LINKING
);
1232 /* Finish compiling the given function, potentially running the
1234 The function will have a statement list by now.
1235 Amongst other things, this gimplifies the statement list,
1236 and calls cgraph_node::finalize_function on the function. */
1239 playback::function::
1242 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
))
1243 debug_tree (m_stmt_list
);
1245 /* Do we need this to force cgraphunit.c to output the function? */
1246 if (m_kind
== GCC_JIT_FUNCTION_EXPORTED
)
1248 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1249 DECL_PRESERVE_P (m_inner_fndecl
) = 1;
1252 if (m_kind
== GCC_JIT_FUNCTION_INTERNAL
1253 ||m_kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
1255 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1256 TREE_PUBLIC (m_inner_fndecl
) = 0;
1259 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1261 /* Seem to need this in gimple-low.c: */
1262 gcc_assert (m_inner_block
);
1263 DECL_INITIAL (m_inner_fndecl
) = m_inner_block
;
1265 /* how to add to function? the following appears to be how to
1266 set the body of a m_inner_fndecl: */
1267 DECL_SAVED_TREE(m_inner_fndecl
) = m_inner_bind_expr
;
1269 /* Ensure that locals appear in the debuginfo. */
1270 BLOCK_VARS (m_inner_block
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1272 //debug_tree (m_inner_fndecl);
1274 /* Convert to gimple: */
1275 //printf("about to gimplify_function_tree\n");
1276 gimplify_function_tree (m_inner_fndecl
);
1277 //printf("finished gimplify_function_tree\n");
1279 current_function_decl
= m_inner_fndecl
;
1280 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
))
1281 dump_function_to_file (m_inner_fndecl
, stderr
, TDF_VOPS
|TDF_MEMSYMS
|TDF_LINENO
);
1282 //debug_tree (m_inner_fndecl);
1284 //printf("about to add to cgraph\n");
1285 /* Add to cgraph: */
1286 cgraph_node::finalize_function (m_inner_fndecl
, false);
1287 /* This can trigger a collection, so we need to have all of
1288 the funcs as roots. */
1290 current_function_decl
= NULL
;
1294 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1298 playback::block::finalizer ()
1303 /* Add an eval of the rvalue to the function's statement list. */
1307 add_eval (location
*loc
,
1310 gcc_assert (rvalue
);
1313 set_tree_location (rvalue
->as_tree (), loc
);
1315 add_stmt (rvalue
->as_tree ());
1318 /* Add an assignment to the function's statement list. */
1322 add_assignment (location
*loc
,
1326 gcc_assert (lvalue
);
1327 gcc_assert (rvalue
);
1329 tree t_lvalue
= lvalue
->as_tree ();
1330 tree t_rvalue
= rvalue
->as_tree ();
1331 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1333 t_rvalue
= build1 (CONVERT_EXPR
,
1334 TREE_TYPE (t_lvalue
),
1337 set_tree_location (t_rvalue
, loc
);
1341 build2 (MODIFY_EXPR
, TREE_TYPE (t_lvalue
),
1342 t_lvalue
, t_rvalue
);
1344 set_tree_location (stmt
, loc
);
1348 /* Add a comment to the function's statement list.
1349 For now this is done by adding a dummy label. */
1353 add_comment (location
*loc
,
1356 /* Wrap the text in C-style comment delimiters. */
1358 (3 /* opening delim */
1360 + 3 /* closing delim */
1361 + 1 /* terminator */);
1362 char *wrapped
= (char *)ggc_internal_alloc (sz
);
1363 snprintf (wrapped
, sz
, "/* %s */", text
);
1365 /* For now we simply implement this by adding a dummy label with a name
1366 containing the given text. */
1367 tree identifier
= get_identifier (wrapped
);
1368 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1369 identifier
, void_type_node
);
1370 DECL_CONTEXT (label_decl
) = m_func
->as_fndecl ();
1372 tree label_expr
= build1 (LABEL_EXPR
, void_type_node
, label_decl
);
1374 set_tree_location (label_expr
, loc
);
1375 add_stmt (label_expr
);
1378 /* Add a conditional jump statement to the function's statement list. */
1382 add_conditional (location
*loc
,
1387 gcc_assert (boolval
);
1388 gcc_assert (on_true
);
1389 gcc_assert (on_false
);
1391 /* COND_EXPR wants statement lists for the true/false operands, but we
1393 Shim it by creating jumps to the labels */
1394 tree true_jump
= build1 (GOTO_EXPR
, void_type_node
,
1395 on_true
->as_label_decl ());
1397 set_tree_location (true_jump
, loc
);
1399 tree false_jump
= build1 (GOTO_EXPR
, void_type_node
,
1400 on_false
->as_label_decl ());
1402 set_tree_location (false_jump
, loc
);
1405 build3 (COND_EXPR
, void_type_node
, boolval
->as_tree (),
1406 true_jump
, false_jump
);
1408 set_tree_location (stmt
, loc
);
1412 /* Add an unconditional jump statement to the function's statement list. */
1416 add_jump (location
*loc
,
1419 gcc_assert (target
);
1421 // see c_finish_loop
1422 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1425 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1426 TREE_USED (target
->as_label_decl ()) = 1;
1427 tree stmt
= build1 (GOTO_EXPR
, void_type_node
, target
->as_label_decl ());
1429 set_tree_location (stmt
, loc
);
1435 c_finish_goto_label (location_t loc, tree label)
1437 tree decl = lookup_label_for_goto (loc, label);
1440 TREE_USED (decl) = 1;
1442 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1443 SET_EXPR_LOCATION (t, loc);
1444 return add_stmt (t);
1451 /* Add a return statement to the function's statement list. */
1455 add_return (location
*loc
,
1458 tree modify_retval
= NULL
;
1459 tree return_type
= m_func
->get_return_type_as_tree ();
1462 tree t_lvalue
= DECL_RESULT (m_func
->as_fndecl ());
1463 tree t_rvalue
= rvalue
->as_tree ();
1464 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1465 t_rvalue
= build1 (CONVERT_EXPR
,
1466 TREE_TYPE (t_lvalue
),
1468 modify_retval
= build2 (MODIFY_EXPR
, return_type
,
1469 t_lvalue
, t_rvalue
);
1471 set_tree_location (modify_retval
, loc
);
1473 tree return_stmt
= build1 (RETURN_EXPR
, return_type
,
1476 set_tree_location (return_stmt
, loc
);
1478 add_stmt (return_stmt
);
1481 /* Constructor for gcc::jit::playback::block. */
1484 block (function
*func
,
1494 identifier
= get_identifier (name
);
1497 m_label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1498 identifier
, void_type_node
);
1499 DECL_CONTEXT (m_label_decl
) = func
->as_fndecl ();
1500 m_label_expr
= NULL
;
1503 /* A subclass of auto_vec <char *> that frees all of its elements on
1506 class auto_argvec
: public auto_vec
<char *>
1512 /* auto_argvec's dtor, freeing all contained strings, automatically
1513 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1515 auto_argvec::~auto_argvec ()
1519 FOR_EACH_VEC_ELT (*this, i
, str
)
1523 /* Compile a playback::context:
1525 - Use the context's options to cconstruct command-line options, and
1526 call into the rest of GCC (toplev::main).
1527 - Assuming it succeeds, we have a .s file; we want a .so file.
1528 Invoke another gcc to convert the .s file to a .so file.
1529 - dlopen the .so file
1530 - Wrap the result up as a playback::result and return it. */
1536 const char *ctxt_progname
;
1537 result
*result_obj
= NULL
;
1539 int keep_intermediates
=
1540 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
);
1542 m_tempdir
= new tempdir (keep_intermediates
);
1543 if (!m_tempdir
->create ())
1546 /* Call into the rest of gcc.
1547 For now, we have to assemble command-line options to pass into
1548 toplev::main, so that they can be parsed. */
1550 /* Pass in user-provided program name as argv0, if any, so that it
1551 makes it into GCC's "progname" global, used in various diagnostics. */
1552 ctxt_progname
= get_str_option (GCC_JIT_STR_OPTION_PROGNAME
);
1555 ctxt_progname
= "libgccjit.so";
1557 auto_vec
<recording::requested_dump
> requested_dumps
;
1558 m_recording_ctxt
->get_all_requested_dumps (&requested_dumps
);
1560 auto_argvec fake_args
;
1561 make_fake_args (&fake_args
, ctxt_progname
, &requested_dumps
);
1562 if (errors_occurred ())
1565 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1568 /* This runs the compiler. */
1569 toplev
toplev (false);
1570 toplev
.main (fake_args
.length (),
1571 const_cast <char **> (fake_args
.address ()));
1573 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1574 need to do it between toplev::main (which creates the dump manager)
1575 and toplev::finalize (which deletes it). */
1576 extract_any_requested_dumps (&requested_dumps
);
1578 /* Clean up the compiler. */
1581 /* Ideally we would release the jit mutex here, but we can't yet since
1582 followup activities use timevars, which are global state. */
1584 if (errors_occurred ())
1590 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
))
1591 dump_generated_code ();
1593 convert_to_dso (ctxt_progname
);
1594 if (errors_occurred ())
1600 result_obj
= dlopen_built_dso ();
1607 /* Helper functions for gcc::jit::playback::context::compile. */
1609 /* This mutex guards gcc::jit::recording::context::compile, so that only
1610 one thread can be accessing the bulk of GCC's state at once. */
1612 static pthread_mutex_t jit_mutex
= PTHREAD_MUTEX_INITIALIZER
;
1614 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
1617 playback::context::acquire_mutex ()
1619 /* Acquire the big GCC mutex. */
1620 pthread_mutex_lock (&jit_mutex
);
1621 gcc_assert (NULL
== active_playback_ctxt
);
1622 active_playback_ctxt
= this;
1625 /* Release jit_mutex and clear the active playback ctxt. */
1628 playback::context::release_mutex ()
1630 /* Release the big GCC mutex. */
1631 gcc_assert (active_playback_ctxt
== this);
1632 active_playback_ctxt
= NULL
;
1633 pthread_mutex_unlock (&jit_mutex
);
1636 /* Build a fake argv for toplev::main from the options set
1637 by the user on the context . */
1641 make_fake_args (vec
<char *> *argvec
,
1642 const char *ctxt_progname
,
1643 vec
<recording::requested_dump
> *requested_dumps
)
1645 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
1646 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
1648 ADD_ARG (ctxt_progname
);
1649 ADD_ARG (get_path_c_file ());
1652 /* Handle int options: */
1653 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
))
1657 "unrecognized optimization level: %i",
1658 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
));
1677 /* What about -Os? */
1679 /* Handle bool options: */
1680 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
1683 /* Suppress timing (and other) info. */
1684 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
))
1690 /* Aggressively garbage-collect, to shake out bugs: */
1691 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC
))
1693 ADD_ARG ("--param");
1694 ADD_ARG ("ggc-min-expand=0");
1695 ADD_ARG ("--param");
1696 ADD_ARG ("ggc-min-heapsize=0");
1699 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
))
1701 ADD_ARG ("-fdump-tree-all");
1702 ADD_ARG ("-fdump-rtl-all");
1703 ADD_ARG ("-fdump-ipa-all");
1706 /* Add "-fdump-" options for any calls to
1707 gcc_jit_context_enable_dump. */
1710 recording::requested_dump
*d
;
1711 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
1713 char *arg
= concat ("-fdump-", d
->m_dumpname
, NULL
);
1714 ADD_ARG_TAKE_OWNERSHIP (arg
);
1719 #undef ADD_ARG_TAKE_OWNERSHIP
1722 /* The second half of the implementation of gcc_jit_context_enable_dump.
1723 Iterate through the requested dumps, reading the underlying files
1724 into heap-allocated buffers, writing pointers to the buffers into
1725 the char ** pointers provided by client code.
1726 Client code is responsible for calling free on the results. */
1730 extract_any_requested_dumps (vec
<recording::requested_dump
> *requested_dumps
)
1733 recording::requested_dump
*d
;
1734 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
1736 dump_file_info
*dfi
;
1740 dfi
= g
->get_dumps ()->get_dump_file_info_by_switch (d
->m_dumpname
);
1743 add_error (NULL
, "unrecognized dump: %s", d
->m_dumpname
);
1747 filename
= g
->get_dumps ()->get_dump_file_name (dfi
);
1748 content
= read_dump_file (filename
);
1749 *(d
->m_out_ptr
) = content
;
1754 /* Helper function for playback::context::extract_any_requested_dumps
1755 (itself for use in implementation of gcc_jit_context_enable_dump).
1757 Attempt to read the complete file at the given path, returning the
1758 bytes found there as a buffer.
1759 The caller is responsible for calling free on the result.
1760 Errors will be reported on the context, and lead to NULL being
1761 returned; an out-of-memory error will terminate the process. */
1764 playback::context::read_dump_file (const char *path
)
1766 char *result
= NULL
;
1767 size_t total_sz
= 0;
1772 f_in
= fopen (path
, "r");
1775 add_error (NULL
, "unable to open %s for reading", path
);
1779 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
1781 size_t old_total_sz
= total_sz
;
1783 result
= reinterpret_cast <char *> (xrealloc (result
, total_sz
+ 1));
1784 memcpy (result
+ old_total_sz
, buf
, sz
);
1789 add_error (NULL
, "error reading from %s", path
);
1798 result
[total_sz
] = '\0';
1802 return xstrdup ("");
1805 /* Part of playback::context::compile ().
1807 We have a .s file; we want a .so file.
1808 We could reuse parts of gcc/gcc.c to do this.
1809 For now, just use the driver binary from the install, as
1810 named in gcc-driver-name.h
1811 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
1815 convert_to_dso (const char *ctxt_progname
)
1817 /* Currently this lumps together both assembling and linking into
1819 auto_timevar
assemble_timevar (TV_ASSEMBLE
);
1821 const char *argv
[7];
1822 int exit_status
= 0;
1824 const char *gcc_driver_name
= GCC_DRIVER_NAME
;
1826 argv
[0] = gcc_driver_name
;
1827 argv
[1] = "-shared";
1828 /* The input: assembler. */
1829 argv
[2] = m_tempdir
->get_path_s_file ();
1830 /* The output: shared library. */
1832 argv
[4] = m_tempdir
->get_path_so_file ();
1834 /* Don't use the linker plugin.
1835 If running with just a "make" and not a "make install", then we'd
1837 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
1838 libto_plugin is a .la at build time, with it becoming installed with
1839 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
1841 argv
[5] = "-fno-use-linker-plugin";
1843 /* pex argv arrays are NULL-terminated. */
1846 /* pex_one's error-handling requires pname to be non-NULL. */
1847 gcc_assert (ctxt_progname
);
1849 errmsg
= pex_one (PEX_SEARCH
, /* int flags, */
1851 const_cast<char * const *> (argv
),
1852 ctxt_progname
, /* const char *pname */
1853 NULL
, /* const char *outname */
1854 NULL
, /* const char *errname */
1855 &exit_status
, /* int *status */
1856 &err
); /* int *err*/
1859 add_error (NULL
, "error invoking gcc driver: %s", errmsg
);
1863 /* pex_one can return a NULL errmsg when the executable wasn't
1864 found (or doesn't exist), so trap these cases also. */
1865 if (exit_status
|| err
)
1868 "error invoking gcc driver: exit_status: %i err: %i",
1871 "whilst attempting to run a driver named: %s",
1880 /* Dynamically-link the built DSO file into this process, using dlopen.
1881 Wrap it up within a jit::result *, and return that.
1882 Return NULL if any errors occur, reporting them on this context. */
1888 auto_timevar
load_timevar (TV_LOAD
);
1889 void *handle
= NULL
;
1890 const char *error
= NULL
;
1891 result
*result_obj
= NULL
;
1893 /* Clear any existing error. */
1896 handle
= dlopen (m_tempdir
->get_path_so_file (),
1897 RTLD_NOW
| RTLD_LOCAL
);
1898 if ((error
= dlerror()) != NULL
) {
1899 add_error (NULL
, "%s", error
);
1902 result_obj
= new result (handle
);
1909 /* Top-level hook for playing back a recording context.
1911 This plays back m_recording_ctxt, and, if no errors
1912 occurred builds statement lists for and then postprocesses
1913 every function in the result. */
1919 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
1920 tree array_domain_type
= build_index_type (size_int (200));
1921 m_char_array_type_node
1922 = build_array_type (char_type_node
, array_domain_type
);
1925 = build_pointer_type (build_qualified_type (char_type_node
,
1928 /* Replay the recorded events: */
1929 timevar_push (TV_JIT_REPLAY
);
1931 m_recording_ctxt
->replay_into (this);
1933 /* Clean away the temporary references from recording objects
1934 to playback objects. We have to do this now since the
1935 latter are GC-allocated, but the former don't mark these
1936 refs. Hence we must stop using them before the GC can run. */
1937 m_recording_ctxt
->disassociate_from_playback ();
1939 /* The builtins_manager, if any, is associated with the recording::context
1940 and might be reused for future compiles on other playback::contexts,
1941 but its m_attributes array is not GTY-labeled and hence will become
1942 nonsense if the GC runs. Purge this state. */
1943 builtins_manager
*bm
= get_builtins_manager ();
1945 bm
->finish_playback ();
1947 timevar_pop (TV_JIT_REPLAY
);
1949 if (!errors_occurred ())
1954 /* No GC can happen yet; process the cached source locations. */
1955 handle_locations ();
1957 /* We've now created tree nodes for the stmts in the various blocks
1958 in each function, but we haven't built each function's single stmt
1959 list yet. Do so now. */
1960 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
1961 func
->build_stmt_list ();
1963 /* No GC can have happened yet. */
1965 /* Postprocess the functions. This could trigger GC. */
1966 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
1969 func
->postprocess ();
1974 /* Dump the generated .s file to stderr. */
1978 dump_generated_code ()
1982 FILE *f_in
= fopen (get_path_s_file (), "r");
1986 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
1987 fwrite (buf
, 1, sz
, stderr
);
1992 /* Get the supposed path of the notional "fake.c" file within the
1993 tempdir. This file doesn't exist, but the rest of the compiler
1998 get_path_c_file () const
2000 return m_tempdir
->get_path_c_file ();
2003 /* Get the path of the assembler output file "fake.s" file within the
2008 get_path_s_file () const
2010 return m_tempdir
->get_path_s_file ();
2013 /* Get the path of the DSO object file "fake.so" file within the
2018 get_path_so_file () const
2020 return m_tempdir
->get_path_so_file ();
2023 /* qsort comparator for comparing pairs of playback::source_line *,
2024 ordering them by line number. */
2027 line_comparator (const void *lhs
, const void *rhs
)
2029 const playback::source_line
*line_lhs
= \
2030 *static_cast<const playback::source_line
* const*> (lhs
);
2031 const playback::source_line
*line_rhs
= \
2032 *static_cast<const playback::source_line
* const*> (rhs
);
2033 return line_lhs
->get_line_num () - line_rhs
->get_line_num ();
2036 /* qsort comparator for comparing pairs of playback::location *,
2037 ordering them by column number. */
2040 location_comparator (const void *lhs
, const void *rhs
)
2042 const playback::location
*loc_lhs
= \
2043 *static_cast<const playback::location
* const *> (lhs
);
2044 const playback::location
*loc_rhs
= \
2045 *static_cast<const playback::location
* const *> (rhs
);
2046 return loc_lhs
->get_column_num () - loc_rhs
->get_column_num ();
2049 /* Our API allows locations to be created in arbitrary orders, but the
2050 linemap API requires locations to be created in ascending order
2051 as if we were tokenizing files.
2053 This hook sorts all of the the locations that have been created, and
2054 calls into the linemap API, creating linemap entries in sorted order
2055 for our locations. */
2061 /* Create the source code locations, following the ordering rules
2062 imposed by the linemap API.
2064 line_table is a global. */
2068 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2070 linemap_add (line_table
, LC_ENTER
, false, file
->get_filename (), 0);
2072 /* Sort lines by ascending line numbers. */
2073 file
->m_source_lines
.qsort (&line_comparator
);
2077 FOR_EACH_VEC_ELT (file
->m_source_lines
, j
, line
)
2082 /* Sort locations in line by ascending column numbers. */
2083 line
->m_locations
.qsort (&location_comparator
);
2085 /* Determine maximum column within this line. */
2086 gcc_assert (line
->m_locations
.length () > 0);
2087 location
*final_column
=
2088 line
->m_locations
[line
->m_locations
.length () - 1];
2089 int max_col
= final_column
->get_column_num ();
2091 linemap_line_start (line_table
, line
->get_line_num (), max_col
);
2092 FOR_EACH_VEC_ELT (line
->m_locations
, k
, loc
)
2095 linemap_position_for_column (line_table
, loc
->get_column_num ());
2099 linemap_add (line_table
, LC_LEAVE
, false, NULL
, 0);
2102 /* line_table should now be populated; every playback::location should
2103 now have an m_srcloc. */
2105 /* Now assign them to tree nodes as appropriate. */
2106 std::pair
<tree
, location
*> *cached_location
;
2108 FOR_EACH_VEC_ELT (m_cached_locations
, i
, cached_location
)
2110 tree t
= cached_location
->first
;
2111 source_location srcloc
= cached_location
->second
->m_srcloc
;
2113 /* This covers expressions: */
2114 if (CAN_HAVE_LOCATION_P (t
))
2115 SET_EXPR_LOCATION (t
, srcloc
);
2116 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t
), TS_DECL_MINIMAL
))
2117 DECL_SOURCE_LOCATION (t
) = srcloc
;
2120 /* Don't know how to set location on this node. */
2125 /* We handle errors on a playback::context by adding them to the
2126 corresponding recording::context. */
2130 add_error (location
*loc
, const char *fmt
, ...)
2134 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2139 /* We handle errors on a playback::context by adding them to the
2140 corresponding recording::context. */
2144 add_error_va (location
*loc
, const char *fmt
, va_list ap
)
2146 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2150 /* Dealing with the linemap API. */
2152 /* Construct a playback::location for a recording::location, if it
2153 doesn't exist already. */
2155 playback::location
*
2157 new_location (recording::location
*rloc
,
2158 const char *filename
,
2162 /* Get the source_file for filename, creating if necessary. */
2163 source_file
*src_file
= get_source_file (filename
);
2164 /* Likewise for the line within the file. */
2165 source_line
*src_line
= src_file
->get_source_line (line
);
2166 /* Likewise for the column within the line. */
2167 location
*loc
= src_line
->get_location (rloc
, column
);
2171 /* Deferred setting of the location for a given tree, by adding the
2172 (tree, playback::location) pair to a list of deferred associations.
2173 We will actually set the location on the tree later on once
2174 the source_location for the playback::location exists. */
2178 set_tree_location (tree t
, location
*loc
)
2181 m_cached_locations
.safe_push (std::make_pair (t
, loc
));
2185 /* Construct a playback::source_file for the given source
2186 filename, if it doesn't exist already. */
2188 playback::source_file
*
2190 get_source_file (const char *filename
)
2193 For simplicitly, this is currently a linear search.
2194 Replace with a hash if this shows up in the profile. */
2197 tree ident_filename
= get_identifier (filename
);
2199 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2200 if (file
->filename_as_tree () == ident_filename
)
2204 file
= new source_file (ident_filename
);
2205 m_source_files
.safe_push (file
);
2209 /* Constructor for gcc::jit::playback::source_file. */
2211 playback::source_file::source_file (tree filename
) :
2213 m_filename (filename
)
2217 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2221 playback::source_file::finalizer ()
2223 m_source_lines
.release ();
2226 /* Construct a playback::source_line for the given line
2227 within this source file, if one doesn't exist already. */
2229 playback::source_line
*
2230 playback::source_file::
2231 get_source_line (int line_num
)
2234 For simplicitly, this is currently a linear search.
2235 Replace with a hash if this shows up in the profile. */
2239 FOR_EACH_VEC_ELT (m_source_lines
, i
, line
)
2240 if (line
->get_line_num () == line_num
)
2244 line
= new source_line (this, line_num
);
2245 m_source_lines
.safe_push (line
);
2249 /* Constructor for gcc::jit::playback::source_line. */
2251 playback::source_line::source_line (source_file
*file
, int line_num
) :
2253 m_source_file (file
),
2254 m_line_num (line_num
)
2258 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2262 playback::source_line::finalizer ()
2264 m_locations
.release ();
2267 /* Construct a playback::location for the given column
2268 within this line of a specific source file, if one doesn't exist
2271 playback::location
*
2272 playback::source_line::
2273 get_location (recording::location
*rloc
, int column_num
)
2278 /* Another linear search that probably should be a hash table. */
2279 FOR_EACH_VEC_ELT (m_locations
, i
, loc
)
2280 if (loc
->get_column_num () == column_num
)
2284 loc
= new location (rloc
, this, column_num
);
2285 m_locations
.safe_push (loc
);
2289 /* Constructor for gcc::jit::playback::location. */
2291 playback::location::location (recording::location
*loc
,
2294 m_srcloc (UNKNOWN_LOCATION
),
2295 m_recording_loc (loc
),
2297 m_column_num(column_num
)
2301 /* The active gcc::jit::playback::context instance. This is a singleton,
2302 guarded by jit_mutex. */
2304 playback::context
*active_playback_ctxt
;
2306 } // namespace gcc::jit