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"
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-logging.h"
54 #include "jit-playback.h"
55 #include "jit-result.h"
56 #include "jit-builtins.h"
57 #include "jit-tempdir.h"
60 /* gcc::jit::playback::context::build_cast uses the convert.h API,
61 which in turn requires the frontend to provide a "convert"
62 function, apparently as a fallback.
64 Hence we provide this dummy one, with the requirement that any casts
65 are handled before reaching this. */
66 extern tree
convert (tree type
, tree expr
);
69 convert (tree dst_type
, tree expr
)
71 gcc_assert (gcc::jit::active_playback_ctxt
);
72 gcc::jit::active_playback_ctxt
->add_error (NULL
, "unhandled conversion");
73 fprintf (stderr
, "input expression:\n");
75 fprintf (stderr
, "requested type:\n");
76 debug_tree (dst_type
);
77 return error_mark_node
;
83 /**********************************************************************
85 **********************************************************************/
87 /* The constructor for gcc::jit::playback::context. */
89 playback::context::context (recording::context
*ctxt
)
90 : log_user (ctxt
->get_logger ()),
91 m_recording_ctxt (ctxt
),
93 m_char_array_type_node (NULL
),
94 m_const_char_ptr (NULL
)
96 JIT_LOG_SCOPE (get_logger ());
97 m_functions
.create (0);
98 m_source_files
.create (0);
99 m_cached_locations
.create (0);
102 /* The destructor for gcc::jit::playback::context. */
104 playback::context::~context ()
106 JIT_LOG_SCOPE (get_logger ());
109 m_functions
.release ();
112 /* A playback::context can reference GC-managed pointers. Mark them
113 ("by hand", rather than by gengtype).
115 This is called on the active playback context (if any) by the
116 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
124 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
126 if (ggc_test_and_set_mark (func
))
131 /* Given an enum gcc_jit_types value, get a "tree" type. */
134 get_tree_node_for_type (enum gcc_jit_types type_
)
138 case GCC_JIT_TYPE_VOID
:
139 return void_type_node
;
141 case GCC_JIT_TYPE_VOID_PTR
:
142 return ptr_type_node
;
144 case GCC_JIT_TYPE_BOOL
:
145 return boolean_type_node
;
147 case GCC_JIT_TYPE_CHAR
:
148 return char_type_node
;
149 case GCC_JIT_TYPE_SIGNED_CHAR
:
150 return signed_char_type_node
;
151 case GCC_JIT_TYPE_UNSIGNED_CHAR
:
152 return unsigned_char_type_node
;
154 case GCC_JIT_TYPE_SHORT
:
155 return short_integer_type_node
;
156 case GCC_JIT_TYPE_UNSIGNED_SHORT
:
157 return short_unsigned_type_node
;
159 case GCC_JIT_TYPE_CONST_CHAR_PTR
:
161 tree const_char
= build_qualified_type (char_type_node
,
163 return build_pointer_type (const_char
);
166 case GCC_JIT_TYPE_INT
:
167 return integer_type_node
;
168 case GCC_JIT_TYPE_UNSIGNED_INT
:
169 return unsigned_type_node
;
171 case GCC_JIT_TYPE_LONG
:
172 return long_integer_type_node
;
173 case GCC_JIT_TYPE_UNSIGNED_LONG
:
174 return long_unsigned_type_node
;
176 case GCC_JIT_TYPE_LONG_LONG
:
177 return long_long_integer_type_node
;
178 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG
:
179 return long_long_unsigned_type_node
;
181 case GCC_JIT_TYPE_FLOAT
:
182 return float_type_node
;
183 case GCC_JIT_TYPE_DOUBLE
:
184 return double_type_node
;
185 case GCC_JIT_TYPE_LONG_DOUBLE
:
186 return long_double_type_node
;
188 case GCC_JIT_TYPE_SIZE_T
:
189 return size_type_node
;
191 case GCC_JIT_TYPE_FILE_PTR
:
192 return fileptr_type_node
;
194 case GCC_JIT_TYPE_COMPLEX_FLOAT
:
195 return complex_float_type_node
;
196 case GCC_JIT_TYPE_COMPLEX_DOUBLE
:
197 return complex_double_type_node
;
198 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE
:
199 return complex_long_double_type_node
;
205 /* Construct a playback::type instance (wrapping a tree) for the given
210 get_type (enum gcc_jit_types type_
)
212 tree type_node
= get_tree_node_for_type (type_
);
213 if (NULL
== type_node
)
216 "unrecognized (enum gcc_jit_types) value: %i", type_
);
220 return new type (type_node
);
223 /* Construct a playback::type instance (wrapping a tree) for the given
228 new_array_type (playback::location
*loc
,
229 playback::type
*element_type
,
232 gcc_assert (element_type
);
234 tree t
= build_array_type_nelts (element_type
->as_tree (),
239 set_tree_location (t
, loc
);
244 /* Construct a playback::field instance (wrapping a tree). */
248 new_field (location
*loc
,
255 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
256 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
257 get_identifier (name
), type
->as_tree ());
260 set_tree_location (decl
, loc
);
262 return new field (decl
);
265 /* Construct a playback::compound_type instance (wrapping a tree). */
267 playback::compound_type
*
269 new_compound_type (location
*loc
,
271 bool is_struct
) /* else is union */
275 /* Compare with c/c-decl.c: start_struct. */
277 tree t
= make_node (is_struct
? RECORD_TYPE
: UNION_TYPE
);
278 TYPE_NAME (t
) = get_identifier (name
);
282 set_tree_location (t
, loc
);
284 return new compound_type (t
);
288 playback::compound_type::set_fields (const auto_vec
<playback::field
*> *fields
)
290 /* Compare with c/c-decl.c: finish_struct. */
293 tree fieldlist
= NULL
;
294 for (unsigned i
= 0; i
< fields
->length (); i
++)
296 field
*f
= (*fields
)[i
];
297 DECL_CONTEXT (f
->as_tree ()) = t
;
298 fieldlist
= chainon (f
->as_tree (), fieldlist
);
300 fieldlist
= nreverse (fieldlist
);
301 TYPE_FIELDS (t
) = fieldlist
;
306 /* Construct a playback::type instance (wrapping a tree) for a function
311 new_function_type (type
*return_type
,
312 const auto_vec
<type
*> *param_types
,
318 tree
*arg_types
= (tree
*)xcalloc(param_types
->length (), sizeof(tree
*));
320 FOR_EACH_VEC_ELT (*param_types
, i
, param_type
)
321 arg_types
[i
] = param_type
->as_tree ();
326 build_varargs_function_type_array (return_type
->as_tree (),
327 param_types
->length (),
330 fn_type
= build_function_type_array (return_type
->as_tree (),
331 param_types
->length (),
335 return new type (fn_type
);
338 /* Construct a playback::param instance (wrapping a tree). */
342 new_param (location
*loc
,
348 tree inner
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
349 get_identifier (name
), type
->as_tree ());
351 set_tree_location (inner
, loc
);
353 return new param (this, inner
);
356 /* Construct a playback::function instance. */
360 new_function (location
*loc
,
361 enum gcc_jit_function_kind kind
,
364 const auto_vec
<param
*> *params
,
366 enum built_in_function builtin_id
)
371 //can return_type be NULL?
374 tree
*arg_types
= (tree
*)xcalloc(params
->length (), sizeof(tree
*));
375 FOR_EACH_VEC_ELT (*params
, i
, param
)
376 arg_types
[i
] = TREE_TYPE (param
->as_tree ());
380 fn_type
= build_varargs_function_type_array (return_type
->as_tree (),
381 params
->length (), arg_types
);
383 fn_type
= build_function_type_array (return_type
->as_tree (),
384 params
->length (), arg_types
);
387 /* FIXME: this uses input_location: */
388 tree fndecl
= build_fn_decl (name
, fn_type
);
391 set_tree_location (fndecl
, loc
);
393 tree resdecl
= build_decl (UNKNOWN_LOCATION
, RESULT_DECL
,
394 NULL_TREE
, return_type
->as_tree ());
395 DECL_ARTIFICIAL (resdecl
) = 1;
396 DECL_IGNORED_P (resdecl
) = 1;
397 DECL_RESULT (fndecl
) = resdecl
;
401 DECL_FUNCTION_CODE (fndecl
) = builtin_id
;
402 gcc_assert (loc
== NULL
);
403 DECL_SOURCE_LOCATION (fndecl
) = BUILTINS_LOCATION
;
405 DECL_BUILT_IN_CLASS (fndecl
) =
406 builtins_manager::get_class (builtin_id
);
407 set_builtin_decl (builtin_id
, fndecl
,
408 builtins_manager::implicit_p (builtin_id
));
410 builtins_manager
*bm
= get_builtins_manager ();
411 tree attrs
= bm
->get_attrs_tree (builtin_id
);
413 decl_attributes (&fndecl
, attrs
, ATTR_FLAG_BUILT_IN
);
415 decl_attributes (&fndecl
, NULL_TREE
, 0);
418 if (kind
!= GCC_JIT_FUNCTION_IMPORTED
)
420 tree param_decl_list
= NULL
;
421 FOR_EACH_VEC_ELT (*params
, i
, param
)
423 param_decl_list
= chainon (param
->as_tree (), param_decl_list
);
426 /* The param list was created in reverse order; fix it: */
427 param_decl_list
= nreverse (param_decl_list
);
430 for (t
= param_decl_list
; t
; t
= DECL_CHAIN (t
))
432 DECL_CONTEXT (t
) = fndecl
;
433 DECL_ARG_TYPE (t
) = TREE_TYPE (t
);
436 /* Set it up on DECL_ARGUMENTS */
437 DECL_ARGUMENTS(fndecl
) = param_decl_list
;
440 if (kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
442 DECL_DECLARED_INLINE_P (fndecl
) = 1;
444 /* Add attribute "always_inline": */
445 DECL_ATTRIBUTES (fndecl
) =
446 tree_cons (get_identifier ("always_inline"),
448 DECL_ATTRIBUTES (fndecl
));
451 function
*func
= new function (this, fndecl
, kind
);
452 m_functions
.safe_push (func
);
456 /* Construct a playback::lvalue instance (wrapping a tree). */
460 new_global (location
*loc
,
466 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
467 get_identifier (name
),
469 TREE_PUBLIC (inner
) = 1;
470 DECL_COMMON (inner
) = 1;
471 DECL_EXTERNAL (inner
) = 1;
474 set_tree_location (inner
, loc
);
476 return new lvalue (this, inner
);
479 /* Construct a playback::rvalue instance (wrapping a tree). */
483 new_rvalue_from_int (type
*type
,
486 // FIXME: type-checking, or coercion?
487 tree inner_type
= type
->as_tree ();
488 if (INTEGRAL_TYPE_P (inner_type
))
490 tree inner
= build_int_cst (inner_type
, value
);
491 return new rvalue (this, inner
);
495 REAL_VALUE_TYPE real_value
;
496 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
497 tree inner
= build_real (inner_type
, real_value
);
498 return new rvalue (this, inner
);
502 /* Construct a playback::rvalue instance (wrapping a tree). */
506 new_rvalue_from_double (type
*type
,
509 // FIXME: type-checking, or coercion?
510 tree inner_type
= type
->as_tree ();
512 /* We have a "double", we want a REAL_VALUE_TYPE.
514 real.c:real_from_target appears to require the representation to be
515 split into 32-bit values, and then sent as an pair of host long
517 REAL_VALUE_TYPE real_value
;
521 uint32_t as_uint32s
[2];
524 long int as_long_ints
[2];
525 as_long_ints
[0] = u
.as_uint32s
[0];
526 as_long_ints
[1] = u
.as_uint32s
[1];
527 real_from_target (&real_value
, as_long_ints
, DFmode
);
528 tree inner
= build_real (inner_type
, real_value
);
529 return new rvalue (this, inner
);
532 /* Construct a playback::rvalue instance (wrapping a tree). */
536 new_rvalue_from_ptr (type
*type
,
539 tree inner_type
= type
->as_tree ();
540 /* FIXME: how to ensure we have a wide enough type? */
541 tree inner
= build_int_cstu (inner_type
, (unsigned HOST_WIDE_INT
)value
);
542 return new rvalue (this, inner
);
545 /* Construct a playback::rvalue instance (wrapping a tree). */
549 new_string_literal (const char *value
)
551 tree t_str
= build_string (strlen (value
), value
);
552 gcc_assert (m_char_array_type_node
);
553 TREE_TYPE (t_str
) = m_char_array_type_node
;
555 /* Convert to (const char*), loosely based on
556 c/c-typeck.c: array_to_pointer_conversion,
557 by taking address of start of string. */
558 tree t_addr
= build1 (ADDR_EXPR
, m_const_char_ptr
, t_str
);
560 return new rvalue (this, t_addr
);
563 /* Coerce a tree expression into a boolean tree expression. */
567 as_truth_value (tree expr
, location
*loc
)
569 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
570 tree typed_zero
= fold_build1 (CONVERT_EXPR
,
574 set_tree_location (typed_zero
, loc
);
576 expr
= build2 (NE_EXPR
, integer_type_node
, expr
, typed_zero
);
578 set_tree_location (expr
, loc
);
583 /* Construct a playback::rvalue instance (wrapping a tree) for a
588 new_unary_op (location
*loc
,
589 enum gcc_jit_unary_op op
,
593 // FIXME: type-checking, or coercion?
594 enum tree_code inner_op
;
596 gcc_assert (result_type
);
599 tree node
= a
->as_tree ();
600 tree inner_result
= NULL
;
605 add_error (loc
, "unrecognized (enum gcc_jit_unary_op) value: %i", op
);
608 case GCC_JIT_UNARY_OP_MINUS
:
609 inner_op
= NEGATE_EXPR
;
612 case GCC_JIT_UNARY_OP_BITWISE_NEGATE
:
613 inner_op
= BIT_NOT_EXPR
;
616 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE
:
617 node
= as_truth_value (node
, loc
);
618 inner_result
= invert_truthvalue (node
);
620 set_tree_location (inner_result
, loc
);
621 return new rvalue (this, inner_result
);
623 case GCC_JIT_UNARY_OP_ABS
:
628 inner_result
= build1 (inner_op
,
629 result_type
->as_tree (),
632 set_tree_location (inner_result
, loc
);
634 return new rvalue (this, inner_result
);
637 /* Construct a playback::rvalue instance (wrapping a tree) for a
642 new_binary_op (location
*loc
,
643 enum gcc_jit_binary_op op
,
645 rvalue
*a
, rvalue
*b
)
647 // FIXME: type-checking, or coercion?
648 enum tree_code inner_op
;
650 gcc_assert (result_type
);
654 tree node_a
= a
->as_tree ();
655 tree node_b
= b
->as_tree ();
660 add_error (loc
, "unrecognized (enum gcc_jit_binary_op) value: %i", op
);
663 case GCC_JIT_BINARY_OP_PLUS
:
664 inner_op
= PLUS_EXPR
;
667 case GCC_JIT_BINARY_OP_MINUS
:
668 inner_op
= MINUS_EXPR
;
671 case GCC_JIT_BINARY_OP_MULT
:
672 inner_op
= MULT_EXPR
;
675 case GCC_JIT_BINARY_OP_DIVIDE
:
676 if (FLOAT_TYPE_P (result_type
->as_tree ()))
677 /* Floating-point division: */
678 inner_op
= RDIV_EXPR
;
680 /* Truncating to zero: */
681 inner_op
= TRUNC_DIV_EXPR
;
684 case GCC_JIT_BINARY_OP_MODULO
:
685 inner_op
= TRUNC_MOD_EXPR
;
688 case GCC_JIT_BINARY_OP_BITWISE_AND
:
689 inner_op
= BIT_AND_EXPR
;
692 case GCC_JIT_BINARY_OP_BITWISE_XOR
:
693 inner_op
= BIT_XOR_EXPR
;
696 case GCC_JIT_BINARY_OP_BITWISE_OR
:
697 inner_op
= BIT_IOR_EXPR
;
700 case GCC_JIT_BINARY_OP_LOGICAL_AND
:
701 node_a
= as_truth_value (node_a
, loc
);
702 node_b
= as_truth_value (node_b
, loc
);
703 inner_op
= TRUTH_ANDIF_EXPR
;
706 case GCC_JIT_BINARY_OP_LOGICAL_OR
:
707 node_a
= as_truth_value (node_a
, loc
);
708 node_b
= as_truth_value (node_b
, loc
);
709 inner_op
= TRUTH_ORIF_EXPR
;
712 case GCC_JIT_BINARY_OP_LSHIFT
:
713 inner_op
= LSHIFT_EXPR
;
716 case GCC_JIT_BINARY_OP_RSHIFT
:
717 inner_op
= RSHIFT_EXPR
;
721 tree inner_expr
= build2 (inner_op
,
722 result_type
->as_tree (),
726 set_tree_location (inner_expr
, loc
);
728 return new rvalue (this, inner_expr
);
731 /* Construct a playback::rvalue instance (wrapping a tree) for a
736 new_comparison (location
*loc
,
737 enum gcc_jit_comparison op
,
738 rvalue
*a
, rvalue
*b
)
740 // FIXME: type-checking, or coercion?
741 enum tree_code inner_op
;
749 add_error (loc
, "unrecognized (enum gcc_jit_comparison) value: %i", op
);
752 case GCC_JIT_COMPARISON_EQ
:
755 case GCC_JIT_COMPARISON_NE
:
758 case GCC_JIT_COMPARISON_LT
:
761 case GCC_JIT_COMPARISON_LE
:
764 case GCC_JIT_COMPARISON_GT
:
767 case GCC_JIT_COMPARISON_GE
:
772 tree inner_expr
= build2 (inner_op
,
777 set_tree_location (inner_expr
, loc
);
778 return new rvalue (this, inner_expr
);
781 /* Construct a playback::rvalue instance (wrapping a tree) for a
786 build_call (location
*loc
,
788 const auto_vec
<rvalue
*> *args
)
790 vec
<tree
, va_gc
> *tree_args
;
791 vec_alloc (tree_args
, args
->length ());
792 for (unsigned i
= 0; i
< args
->length (); i
++)
793 tree_args
->quick_push ((*args
)[i
]->as_tree ());
796 set_tree_location (fn_ptr
, loc
);
798 tree fn
= TREE_TYPE (fn_ptr
);
799 tree fn_type
= TREE_TYPE (fn
);
800 tree return_type
= TREE_TYPE (fn_type
);
802 return new rvalue (this,
803 build_call_vec (return_type
,
806 /* see c-typeck.c: build_function_call
807 which calls build_function_call_vec
809 which does lots of checking, then:
810 result = build_call_array_loc (loc, TREE_TYPE (fntype),
811 function, nargs, argarray);
813 (see also build_call_vec)
817 /* Construct a playback::rvalue instance (wrapping a tree) for a
818 call to a specific function. */
822 new_call (location
*loc
,
824 const auto_vec
<rvalue
*> *args
)
830 fndecl
= func
->as_fndecl ();
832 tree fntype
= TREE_TYPE (fndecl
);
834 tree fn
= build1 (ADDR_EXPR
, build_pointer_type (fntype
), fndecl
);
836 return build_call (loc
, fn
, args
);
839 /* Construct a playback::rvalue instance (wrapping a tree) for a
840 call through a function pointer. */
844 new_call_through_ptr (location
*loc
,
846 const auto_vec
<rvalue
*> *args
)
849 tree t_fn_ptr
= fn_ptr
->as_tree ();
851 return build_call (loc
, t_fn_ptr
, args
);
854 /* Construct a tree for a cast. */
857 playback::context::build_cast (playback::location
*loc
,
858 playback::rvalue
*expr
,
859 playback::type
*type_
)
861 /* For comparison, see:
862 - c/c-typeck.c:build_c_cast
863 - c/c-convert.c: convert
866 Only some kinds of cast are currently supported here. */
867 tree t_expr
= expr
->as_tree ();
868 tree t_dst_type
= type_
->as_tree ();
870 t_ret
= targetm
.convert_to_type (t_dst_type
, t_expr
);
873 enum tree_code dst_code
= TREE_CODE (t_dst_type
);
878 t_ret
= convert_to_integer (t_dst_type
, t_expr
);
882 /* Compare with c_objc_common_truthvalue_conversion and
883 c_common_truthvalue_conversion. */
884 /* For now, convert to: (t_expr != 0) */
885 t_ret
= build2 (NE_EXPR
, t_dst_type
,
887 build_int_cst (TREE_TYPE (t_expr
), 0));
891 t_ret
= convert_to_real (t_dst_type
, t_expr
);
895 t_ret
= build1 (NOP_EXPR
, t_dst_type
, t_expr
);
899 add_error (loc
, "couldn't handle cast during playback");
900 fprintf (stderr
, "input expression:\n");
902 fprintf (stderr
, "requested type:\n");
903 debug_tree (t_dst_type
);
904 return error_mark_node
;
907 if (TREE_CODE (t_ret
) != C_MAYBE_CONST_EXPR
)
908 t_ret
= fold (t_ret
);
913 /* Construct a playback::rvalue instance (wrapping a tree) for a
918 new_cast (playback::location
*loc
,
919 playback::rvalue
*expr
,
920 playback::type
*type_
)
923 tree t_cast
= build_cast (loc
, expr
, type_
);
925 set_tree_location (t_cast
, loc
);
926 return new rvalue (this, t_cast
);
929 /* Construct a playback::lvalue instance (wrapping a tree) for an
934 new_array_access (location
*loc
,
941 /* For comparison, see:
942 c/c-typeck.c: build_array_ref
943 c-family/c-common.c: pointer_int_sum
945 tree t_ptr
= ptr
->as_tree ();
946 tree t_index
= index
->as_tree ();
947 tree t_type_ptr
= TREE_TYPE (t_ptr
);
948 tree t_type_star_ptr
= TREE_TYPE (t_type_ptr
);
950 if (TREE_CODE (t_type_ptr
) == ARRAY_TYPE
)
952 tree t_result
= build4 (ARRAY_REF
, t_type_star_ptr
, t_ptr
, t_index
,
953 NULL_TREE
, NULL_TREE
);
955 set_tree_location (t_result
, loc
);
956 return new lvalue (this, t_result
);
960 /* Convert index to an offset in bytes. */
961 tree t_sizeof
= size_in_bytes (t_type_star_ptr
);
962 t_index
= fold_build1 (CONVERT_EXPR
, sizetype
, t_index
);
963 tree t_offset
= build2 (MULT_EXPR
, sizetype
, t_index
, t_sizeof
);
965 /* Locate (ptr + offset). */
966 tree t_address
= build2 (POINTER_PLUS_EXPR
, t_type_ptr
, t_ptr
, t_offset
);
968 tree t_indirection
= build1 (INDIRECT_REF
, t_type_star_ptr
, t_address
);
971 set_tree_location (t_sizeof
, loc
);
972 set_tree_location (t_offset
, loc
);
973 set_tree_location (t_address
, loc
);
974 set_tree_location (t_indirection
, loc
);
977 return new lvalue (this, t_indirection
);
981 /* Construct a tree for a field access. */
985 new_field_access (location
*loc
,
992 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
993 build_component_ref. */
994 tree type
= TREE_TYPE (datum
);
996 gcc_assert (TREE_CODE (type
) != POINTER_TYPE
);
998 tree t_field
= field
->as_tree ();
999 tree ref
= build3 (COMPONENT_REF
, TREE_TYPE (t_field
), datum
,
1000 t_field
, NULL_TREE
);
1002 set_tree_location (ref
, loc
);
1006 /* Construct a tree for a dereference. */
1010 new_dereference (tree ptr
,
1015 tree type
= TREE_TYPE (TREE_TYPE(ptr
));
1016 tree datum
= build1 (INDIRECT_REF
, type
, ptr
);
1018 set_tree_location (datum
, loc
);
1022 /* Construct a playback::lvalue instance (wrapping a tree) for a
1027 access_field (location
*loc
,
1030 tree datum
= as_tree ();
1031 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1034 return new lvalue (get_context (), ref
);
1037 /* Construct a playback::rvalue instance (wrapping a tree) for a
1042 access_field (location
*loc
,
1045 tree datum
= as_tree ();
1046 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1049 return new rvalue (get_context (), ref
);
1052 /* Construct a playback::lvalue instance (wrapping a tree) for a
1053 dereferenced field access. */
1057 dereference_field (location
*loc
,
1060 tree ptr
= as_tree ();
1061 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1064 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1067 return new lvalue (get_context (), ref
);
1070 /* Construct a playback::lvalue instance (wrapping a tree) for a
1075 dereference (location
*loc
)
1077 tree ptr
= as_tree ();
1078 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1079 return new lvalue (get_context (), datum
);
1082 /* Construct a playback::rvalue instance (wrapping a tree) for an
1087 get_address (location
*loc
)
1089 tree t_lvalue
= as_tree ();
1090 tree t_thistype
= TREE_TYPE (t_lvalue
);
1091 tree t_ptrtype
= build_pointer_type (t_thistype
);
1092 tree ptr
= build1 (ADDR_EXPR
, t_ptrtype
, t_lvalue
);
1094 get_context ()->set_tree_location (ptr
, loc
);
1095 return new rvalue (get_context (), ptr
);
1098 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1099 Provide this finalization hook for calling then they are collected,
1100 which calls the finalizer vfunc. This allows them to call "release"
1101 on any vec<> within them. */
1104 wrapper_finalizer (void *ptr
)
1106 playback::wrapper
*wrapper
= reinterpret_cast <playback::wrapper
*> (ptr
);
1107 wrapper
->finalizer ();
1110 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1111 allocate them using ggc_internal_cleared_alloc. */
1115 operator new (size_t sz
)
1117 return ggc_internal_cleared_alloc (sz
, wrapper_finalizer
, 0, 1);
1121 /* Constructor for gcc:jit::playback::function. */
1123 playback::function::
1124 function (context
*ctxt
,
1126 enum gcc_jit_function_kind kind
)
1128 m_inner_fndecl (fndecl
),
1129 m_inner_bind_expr (NULL
),
1132 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1134 /* Create a BIND_EXPR, and within it, a statement list. */
1135 m_stmt_list
= alloc_stmt_list ();
1136 m_stmt_iter
= tsi_start (m_stmt_list
);
1137 m_inner_block
= make_node (BLOCK
);
1139 build3 (BIND_EXPR
, void_type_node
, NULL
, m_stmt_list
, m_inner_block
);
1143 m_inner_block
= NULL
;
1148 /* Hand-written GC-marking hook for playback functions. */
1151 playback::function::
1154 gt_ggc_m_9tree_node (m_inner_fndecl
);
1155 gt_ggc_m_9tree_node (m_inner_bind_expr
);
1156 gt_ggc_m_9tree_node (m_stmt_list
);
1157 gt_ggc_m_9tree_node (m_inner_block
);
1160 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1164 playback::function::finalizer ()
1166 m_blocks
.release ();
1169 /* Get the return type of a playback function, in tree form. */
1172 playback::function::
1173 get_return_type_as_tree () const
1175 return TREE_TYPE (TREE_TYPE(m_inner_fndecl
));
1178 /* Construct a new local within this playback::function. */
1181 playback::function::
1182 new_local (location
*loc
,
1188 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
1189 get_identifier (name
),
1191 DECL_CONTEXT (inner
) = this->m_inner_fndecl
;
1193 /* Prepend to BIND_EXPR_VARS: */
1194 DECL_CHAIN (inner
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1195 BIND_EXPR_VARS (m_inner_bind_expr
) = inner
;
1198 set_tree_location (inner
, loc
);
1199 return new lvalue (m_ctxt
, inner
);
1202 /* Construct a new block within this playback::function. */
1205 playback::function::
1206 new_block (const char *name
)
1208 gcc_assert (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
);
1210 block
*result
= new playback::block (this, name
);
1211 m_blocks
.safe_push (result
);
1215 /* Build a statement list for the function as a whole out of the
1216 lists of statements for the individual blocks, building labels
1220 playback::function::
1226 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1228 FOR_EACH_VEC_ELT (m_blocks
, i
, b
)
1233 b
->m_label_expr
= build1 (LABEL_EXPR
,
1235 b
->as_label_decl ());
1236 tsi_link_after (&m_stmt_iter
, b
->m_label_expr
, TSI_CONTINUE_LINKING
);
1238 FOR_EACH_VEC_ELT (b
->m_stmts
, j
, stmt
)
1239 tsi_link_after (&m_stmt_iter
, stmt
, TSI_CONTINUE_LINKING
);
1243 /* Finish compiling the given function, potentially running the
1245 The function will have a statement list by now.
1246 Amongst other things, this gimplifies the statement list,
1247 and calls cgraph_node::finalize_function on the function. */
1250 playback::function::
1253 JIT_LOG_SCOPE (m_ctxt
->get_logger ());
1255 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
))
1256 debug_tree (m_stmt_list
);
1258 /* Do we need this to force cgraphunit.c to output the function? */
1259 if (m_kind
== GCC_JIT_FUNCTION_EXPORTED
)
1261 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1262 DECL_PRESERVE_P (m_inner_fndecl
) = 1;
1265 if (m_kind
== GCC_JIT_FUNCTION_INTERNAL
1266 ||m_kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
1268 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1269 TREE_PUBLIC (m_inner_fndecl
) = 0;
1272 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1274 /* Seem to need this in gimple-low.c: */
1275 gcc_assert (m_inner_block
);
1276 DECL_INITIAL (m_inner_fndecl
) = m_inner_block
;
1278 /* how to add to function? the following appears to be how to
1279 set the body of a m_inner_fndecl: */
1280 DECL_SAVED_TREE(m_inner_fndecl
) = m_inner_bind_expr
;
1282 /* Ensure that locals appear in the debuginfo. */
1283 BLOCK_VARS (m_inner_block
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1285 //debug_tree (m_inner_fndecl);
1287 /* Convert to gimple: */
1288 //printf("about to gimplify_function_tree\n");
1289 gimplify_function_tree (m_inner_fndecl
);
1290 //printf("finished gimplify_function_tree\n");
1292 current_function_decl
= m_inner_fndecl
;
1293 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
))
1294 dump_function_to_file (m_inner_fndecl
, stderr
, TDF_VOPS
|TDF_MEMSYMS
|TDF_LINENO
);
1295 //debug_tree (m_inner_fndecl);
1297 //printf("about to add to cgraph\n");
1298 /* Add to cgraph: */
1299 cgraph_node::finalize_function (m_inner_fndecl
, false);
1300 /* This can trigger a collection, so we need to have all of
1301 the funcs as roots. */
1303 current_function_decl
= NULL
;
1307 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1311 playback::block::finalizer ()
1316 /* Add an eval of the rvalue to the function's statement list. */
1320 add_eval (location
*loc
,
1323 gcc_assert (rvalue
);
1326 set_tree_location (rvalue
->as_tree (), loc
);
1328 add_stmt (rvalue
->as_tree ());
1331 /* Add an assignment to the function's statement list. */
1335 add_assignment (location
*loc
,
1339 gcc_assert (lvalue
);
1340 gcc_assert (rvalue
);
1342 tree t_lvalue
= lvalue
->as_tree ();
1343 tree t_rvalue
= rvalue
->as_tree ();
1344 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1346 t_rvalue
= build1 (CONVERT_EXPR
,
1347 TREE_TYPE (t_lvalue
),
1350 set_tree_location (t_rvalue
, loc
);
1354 build2 (MODIFY_EXPR
, TREE_TYPE (t_lvalue
),
1355 t_lvalue
, t_rvalue
);
1357 set_tree_location (stmt
, loc
);
1361 /* Add a comment to the function's statement list.
1362 For now this is done by adding a dummy label. */
1366 add_comment (location
*loc
,
1369 /* Wrap the text in C-style comment delimiters. */
1371 (3 /* opening delim */
1373 + 3 /* closing delim */
1374 + 1 /* terminator */);
1375 char *wrapped
= (char *)ggc_internal_alloc (sz
);
1376 snprintf (wrapped
, sz
, "/* %s */", text
);
1378 /* For now we simply implement this by adding a dummy label with a name
1379 containing the given text. */
1380 tree identifier
= get_identifier (wrapped
);
1381 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1382 identifier
, void_type_node
);
1383 DECL_CONTEXT (label_decl
) = m_func
->as_fndecl ();
1385 tree label_expr
= build1 (LABEL_EXPR
, void_type_node
, label_decl
);
1387 set_tree_location (label_expr
, loc
);
1388 add_stmt (label_expr
);
1391 /* Add a conditional jump statement to the function's statement list. */
1395 add_conditional (location
*loc
,
1400 gcc_assert (boolval
);
1401 gcc_assert (on_true
);
1402 gcc_assert (on_false
);
1404 /* COND_EXPR wants statement lists for the true/false operands, but we
1406 Shim it by creating jumps to the labels */
1407 tree true_jump
= build1 (GOTO_EXPR
, void_type_node
,
1408 on_true
->as_label_decl ());
1410 set_tree_location (true_jump
, loc
);
1412 tree false_jump
= build1 (GOTO_EXPR
, void_type_node
,
1413 on_false
->as_label_decl ());
1415 set_tree_location (false_jump
, loc
);
1418 build3 (COND_EXPR
, void_type_node
, boolval
->as_tree (),
1419 true_jump
, false_jump
);
1421 set_tree_location (stmt
, loc
);
1425 /* Add an unconditional jump statement to the function's statement list. */
1429 add_jump (location
*loc
,
1432 gcc_assert (target
);
1434 // see c_finish_loop
1435 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1438 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1439 TREE_USED (target
->as_label_decl ()) = 1;
1440 tree stmt
= build1 (GOTO_EXPR
, void_type_node
, target
->as_label_decl ());
1442 set_tree_location (stmt
, loc
);
1448 c_finish_goto_label (location_t loc, tree label)
1450 tree decl = lookup_label_for_goto (loc, label);
1453 TREE_USED (decl) = 1;
1455 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1456 SET_EXPR_LOCATION (t, loc);
1457 return add_stmt (t);
1464 /* Add a return statement to the function's statement list. */
1468 add_return (location
*loc
,
1471 tree modify_retval
= NULL
;
1472 tree return_type
= m_func
->get_return_type_as_tree ();
1475 tree t_lvalue
= DECL_RESULT (m_func
->as_fndecl ());
1476 tree t_rvalue
= rvalue
->as_tree ();
1477 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1478 t_rvalue
= build1 (CONVERT_EXPR
,
1479 TREE_TYPE (t_lvalue
),
1481 modify_retval
= build2 (MODIFY_EXPR
, return_type
,
1482 t_lvalue
, t_rvalue
);
1484 set_tree_location (modify_retval
, loc
);
1486 tree return_stmt
= build1 (RETURN_EXPR
, return_type
,
1489 set_tree_location (return_stmt
, loc
);
1491 add_stmt (return_stmt
);
1494 /* Constructor for gcc::jit::playback::block. */
1497 block (function
*func
,
1507 identifier
= get_identifier (name
);
1510 m_label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1511 identifier
, void_type_node
);
1512 DECL_CONTEXT (m_label_decl
) = func
->as_fndecl ();
1513 m_label_expr
= NULL
;
1516 /* A subclass of auto_vec <char *> that frees all of its elements on
1519 class auto_argvec
: public auto_vec
<char *>
1525 /* auto_argvec's dtor, freeing all contained strings, automatically
1526 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1528 auto_argvec::~auto_argvec ()
1532 FOR_EACH_VEC_ELT (*this, i
, str
)
1536 /* Compile a playback::context:
1538 - Use the context's options to cconstruct command-line options, and
1539 call into the rest of GCC (toplev::main).
1540 - Assuming it succeeds, we have a .s file; we want a .so file.
1541 Invoke another gcc to convert the .s file to a .so file.
1542 - dlopen the .so file
1543 - Wrap the result up as a playback::result and return it. */
1549 JIT_LOG_SCOPE (get_logger ());
1551 const char *ctxt_progname
;
1552 result
*result_obj
= NULL
;
1554 int keep_intermediates
=
1555 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
);
1557 m_tempdir
= new tempdir (keep_intermediates
);
1558 if (!m_tempdir
->create ())
1561 /* Call into the rest of gcc.
1562 For now, we have to assemble command-line options to pass into
1563 toplev::main, so that they can be parsed. */
1565 /* Pass in user-provided program name as argv0, if any, so that it
1566 makes it into GCC's "progname" global, used in various diagnostics. */
1567 ctxt_progname
= get_str_option (GCC_JIT_STR_OPTION_PROGNAME
);
1570 ctxt_progname
= "libgccjit.so";
1572 auto_vec
<recording::requested_dump
> requested_dumps
;
1573 m_recording_ctxt
->get_all_requested_dumps (&requested_dumps
);
1575 auto_argvec fake_args
;
1576 make_fake_args (&fake_args
, ctxt_progname
, &requested_dumps
);
1577 if (errors_occurred ())
1580 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1583 /* This runs the compiler. */
1584 toplev
toplev (false);
1585 enter_scope ("toplev::main");
1587 for (unsigned i
= 0; i
< fake_args
.length (); i
++)
1588 get_logger ()->log ("argv[%i]: %s", i
, fake_args
[i
]);
1589 toplev
.main (fake_args
.length (),
1590 const_cast <char **> (fake_args
.address ()));
1591 exit_scope ("toplev::main");
1593 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1594 need to do it between toplev::main (which creates the dump manager)
1595 and toplev::finalize (which deletes it). */
1596 extract_any_requested_dumps (&requested_dumps
);
1598 /* Clean up the compiler. */
1599 enter_scope ("toplev::finalize");
1601 exit_scope ("toplev::finalize");
1603 /* Ideally we would release the jit mutex here, but we can't yet since
1604 followup activities use timevars, which are global state. */
1606 if (errors_occurred ())
1612 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
))
1613 dump_generated_code ();
1615 convert_to_dso (ctxt_progname
);
1616 if (errors_occurred ())
1622 result_obj
= dlopen_built_dso ();
1629 /* Helper functions for gcc::jit::playback::context::compile. */
1631 /* This mutex guards gcc::jit::recording::context::compile, so that only
1632 one thread can be accessing the bulk of GCC's state at once. */
1634 static pthread_mutex_t jit_mutex
= PTHREAD_MUTEX_INITIALIZER
;
1636 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
1639 playback::context::acquire_mutex ()
1641 /* Acquire the big GCC mutex. */
1642 JIT_LOG_SCOPE (get_logger ());
1643 pthread_mutex_lock (&jit_mutex
);
1644 gcc_assert (NULL
== active_playback_ctxt
);
1645 active_playback_ctxt
= this;
1648 /* Release jit_mutex and clear the active playback ctxt. */
1651 playback::context::release_mutex ()
1653 /* Release the big GCC mutex. */
1654 JIT_LOG_SCOPE (get_logger ());
1655 gcc_assert (active_playback_ctxt
== this);
1656 active_playback_ctxt
= NULL
;
1657 pthread_mutex_unlock (&jit_mutex
);
1660 /* Build a fake argv for toplev::main from the options set
1661 by the user on the context . */
1665 make_fake_args (vec
<char *> *argvec
,
1666 const char *ctxt_progname
,
1667 vec
<recording::requested_dump
> *requested_dumps
)
1669 JIT_LOG_SCOPE (get_logger ());
1671 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
1672 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
1674 ADD_ARG (ctxt_progname
);
1675 ADD_ARG (get_path_c_file ());
1678 /* Handle int options: */
1679 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
))
1683 "unrecognized optimization level: %i",
1684 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
));
1703 /* What about -Os? */
1705 /* Handle bool options: */
1706 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
1709 /* Suppress timing (and other) info. */
1710 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
))
1716 /* Aggressively garbage-collect, to shake out bugs: */
1717 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC
))
1719 ADD_ARG ("--param");
1720 ADD_ARG ("ggc-min-expand=0");
1721 ADD_ARG ("--param");
1722 ADD_ARG ("ggc-min-heapsize=0");
1725 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
))
1727 ADD_ARG ("-fdump-tree-all");
1728 ADD_ARG ("-fdump-rtl-all");
1729 ADD_ARG ("-fdump-ipa-all");
1732 /* Add "-fdump-" options for any calls to
1733 gcc_jit_context_enable_dump. */
1736 recording::requested_dump
*d
;
1737 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
1739 char *arg
= concat ("-fdump-", d
->m_dumpname
, NULL
);
1740 ADD_ARG_TAKE_OWNERSHIP (arg
);
1745 #undef ADD_ARG_TAKE_OWNERSHIP
1748 /* The second half of the implementation of gcc_jit_context_enable_dump.
1749 Iterate through the requested dumps, reading the underlying files
1750 into heap-allocated buffers, writing pointers to the buffers into
1751 the char ** pointers provided by client code.
1752 Client code is responsible for calling free on the results. */
1756 extract_any_requested_dumps (vec
<recording::requested_dump
> *requested_dumps
)
1758 JIT_LOG_SCOPE (get_logger ());
1761 recording::requested_dump
*d
;
1762 FOR_EACH_VEC_ELT (*requested_dumps
, i
, d
)
1764 dump_file_info
*dfi
;
1768 dfi
= g
->get_dumps ()->get_dump_file_info_by_switch (d
->m_dumpname
);
1771 add_error (NULL
, "unrecognized dump: %s", d
->m_dumpname
);
1775 filename
= g
->get_dumps ()->get_dump_file_name (dfi
);
1776 content
= read_dump_file (filename
);
1777 *(d
->m_out_ptr
) = content
;
1782 /* Helper function for playback::context::extract_any_requested_dumps
1783 (itself for use in implementation of gcc_jit_context_enable_dump).
1785 Attempt to read the complete file at the given path, returning the
1786 bytes found there as a buffer.
1787 The caller is responsible for calling free on the result.
1788 Errors will be reported on the context, and lead to NULL being
1789 returned; an out-of-memory error will terminate the process. */
1792 playback::context::read_dump_file (const char *path
)
1794 char *result
= NULL
;
1795 size_t total_sz
= 0;
1800 f_in
= fopen (path
, "r");
1803 add_error (NULL
, "unable to open %s for reading", path
);
1807 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
1809 size_t old_total_sz
= total_sz
;
1811 result
= reinterpret_cast <char *> (xrealloc (result
, total_sz
+ 1));
1812 memcpy (result
+ old_total_sz
, buf
, sz
);
1817 add_error (NULL
, "error reading from %s", path
);
1826 result
[total_sz
] = '\0';
1830 return xstrdup ("");
1833 /* Part of playback::context::compile ().
1835 We have a .s file; we want a .so file.
1836 We could reuse parts of gcc/gcc.c to do this.
1837 For now, just use the driver binary from the install, as
1838 named in gcc-driver-name.h
1839 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
1843 convert_to_dso (const char *ctxt_progname
)
1845 JIT_LOG_SCOPE (get_logger ());
1846 /* Currently this lumps together both assembling and linking into
1848 auto_timevar
assemble_timevar (TV_ASSEMBLE
);
1850 auto_vec
<const char *> argvec
;
1851 #define ADD_ARG(arg) argvec.safe_push (arg)
1852 int exit_status
= 0;
1854 const char *gcc_driver_name
= GCC_DRIVER_NAME
;
1856 ADD_ARG (gcc_driver_name
);
1857 ADD_ARG ("-shared");
1858 /* The input: assembler. */
1859 ADD_ARG (m_tempdir
->get_path_s_file ());
1860 /* The output: shared library. */
1862 ADD_ARG (m_tempdir
->get_path_so_file ());
1864 /* Don't use the linker plugin.
1865 If running with just a "make" and not a "make install", then we'd
1867 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
1868 libto_plugin is a .la at build time, with it becoming installed with
1869 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
1871 ADD_ARG ("-fno-use-linker-plugin");
1873 /* pex argv arrays are NULL-terminated. */
1876 /* pex_one's error-handling requires pname to be non-NULL. */
1877 gcc_assert (ctxt_progname
);
1880 for (unsigned i
= 0; i
< argvec
.length (); i
++)
1881 get_logger ()->log ("argv[%i]: %s", i
, argvec
[i
]);
1883 errmsg
= pex_one (PEX_SEARCH
, /* int flags, */
1885 const_cast <char *const *> (argvec
.address ()),
1886 ctxt_progname
, /* const char *pname */
1887 NULL
, /* const char *outname */
1888 NULL
, /* const char *errname */
1889 &exit_status
, /* int *status */
1890 &err
); /* int *err*/
1893 add_error (NULL
, "error invoking gcc driver: %s", errmsg
);
1897 /* pex_one can return a NULL errmsg when the executable wasn't
1898 found (or doesn't exist), so trap these cases also. */
1899 if (exit_status
|| err
)
1902 "error invoking gcc driver: exit_status: %i err: %i",
1905 "whilst attempting to run a driver named: %s",
1915 /* Dynamically-link the built DSO file into this process, using dlopen.
1916 Wrap it up within a jit::result *, and return that.
1917 Return NULL if any errors occur, reporting them on this context. */
1923 JIT_LOG_SCOPE (get_logger ());
1924 auto_timevar
load_timevar (TV_LOAD
);
1925 void *handle
= NULL
;
1926 const char *error
= NULL
;
1927 result
*result_obj
= NULL
;
1929 /* Clear any existing error. */
1932 handle
= dlopen (m_tempdir
->get_path_so_file (),
1933 RTLD_NOW
| RTLD_LOCAL
);
1934 if ((error
= dlerror()) != NULL
) {
1935 add_error (NULL
, "%s", error
);
1938 result_obj
= new result (get_logger (), handle
);
1945 /* Top-level hook for playing back a recording context.
1947 This plays back m_recording_ctxt, and, if no errors
1948 occurred builds statement lists for and then postprocesses
1949 every function in the result. */
1955 JIT_LOG_SCOPE (get_logger ());
1956 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
1957 tree array_domain_type
= build_index_type (size_int (200));
1958 m_char_array_type_node
1959 = build_array_type (char_type_node
, array_domain_type
);
1962 = build_pointer_type (build_qualified_type (char_type_node
,
1965 /* Replay the recorded events: */
1966 timevar_push (TV_JIT_REPLAY
);
1968 m_recording_ctxt
->replay_into (this);
1970 /* Clean away the temporary references from recording objects
1971 to playback objects. We have to do this now since the
1972 latter are GC-allocated, but the former don't mark these
1973 refs. Hence we must stop using them before the GC can run. */
1974 m_recording_ctxt
->disassociate_from_playback ();
1976 /* The builtins_manager, if any, is associated with the recording::context
1977 and might be reused for future compiles on other playback::contexts,
1978 but its m_attributes array is not GTY-labeled and hence will become
1979 nonsense if the GC runs. Purge this state. */
1980 builtins_manager
*bm
= get_builtins_manager ();
1982 bm
->finish_playback ();
1984 timevar_pop (TV_JIT_REPLAY
);
1986 if (!errors_occurred ())
1991 /* No GC can happen yet; process the cached source locations. */
1992 handle_locations ();
1994 /* We've now created tree nodes for the stmts in the various blocks
1995 in each function, but we haven't built each function's single stmt
1996 list yet. Do so now. */
1997 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
1998 func
->build_stmt_list ();
2000 /* No GC can have happened yet. */
2002 /* Postprocess the functions. This could trigger GC. */
2003 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
2006 func
->postprocess ();
2011 /* Dump the generated .s file to stderr. */
2015 dump_generated_code ()
2017 JIT_LOG_SCOPE (get_logger ());
2020 FILE *f_in
= fopen (get_path_s_file (), "r");
2024 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
2025 fwrite (buf
, 1, sz
, stderr
);
2030 /* Get the supposed path of the notional "fake.c" file within the
2031 tempdir. This file doesn't exist, but the rest of the compiler
2036 get_path_c_file () const
2038 return m_tempdir
->get_path_c_file ();
2041 /* Get the path of the assembler output file "fake.s" file within the
2046 get_path_s_file () const
2048 return m_tempdir
->get_path_s_file ();
2051 /* Get the path of the DSO object file "fake.so" file within the
2056 get_path_so_file () const
2058 return m_tempdir
->get_path_so_file ();
2061 /* qsort comparator for comparing pairs of playback::source_line *,
2062 ordering them by line number. */
2065 line_comparator (const void *lhs
, const void *rhs
)
2067 const playback::source_line
*line_lhs
= \
2068 *static_cast<const playback::source_line
* const*> (lhs
);
2069 const playback::source_line
*line_rhs
= \
2070 *static_cast<const playback::source_line
* const*> (rhs
);
2071 return line_lhs
->get_line_num () - line_rhs
->get_line_num ();
2074 /* qsort comparator for comparing pairs of playback::location *,
2075 ordering them by column number. */
2078 location_comparator (const void *lhs
, const void *rhs
)
2080 const playback::location
*loc_lhs
= \
2081 *static_cast<const playback::location
* const *> (lhs
);
2082 const playback::location
*loc_rhs
= \
2083 *static_cast<const playback::location
* const *> (rhs
);
2084 return loc_lhs
->get_column_num () - loc_rhs
->get_column_num ();
2087 /* Our API allows locations to be created in arbitrary orders, but the
2088 linemap API requires locations to be created in ascending order
2089 as if we were tokenizing files.
2091 This hook sorts all of the the locations that have been created, and
2092 calls into the linemap API, creating linemap entries in sorted order
2093 for our locations. */
2099 /* Create the source code locations, following the ordering rules
2100 imposed by the linemap API.
2102 line_table is a global. */
2103 JIT_LOG_SCOPE (get_logger ());
2107 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2109 linemap_add (line_table
, LC_ENTER
, false, file
->get_filename (), 0);
2111 /* Sort lines by ascending line numbers. */
2112 file
->m_source_lines
.qsort (&line_comparator
);
2116 FOR_EACH_VEC_ELT (file
->m_source_lines
, j
, line
)
2121 /* Sort locations in line by ascending column numbers. */
2122 line
->m_locations
.qsort (&location_comparator
);
2124 /* Determine maximum column within this line. */
2125 gcc_assert (line
->m_locations
.length () > 0);
2126 location
*final_column
=
2127 line
->m_locations
[line
->m_locations
.length () - 1];
2128 int max_col
= final_column
->get_column_num ();
2130 linemap_line_start (line_table
, line
->get_line_num (), max_col
);
2131 FOR_EACH_VEC_ELT (line
->m_locations
, k
, loc
)
2134 linemap_position_for_column (line_table
, loc
->get_column_num ());
2138 linemap_add (line_table
, LC_LEAVE
, false, NULL
, 0);
2141 /* line_table should now be populated; every playback::location should
2142 now have an m_srcloc. */
2144 /* Now assign them to tree nodes as appropriate. */
2145 std::pair
<tree
, location
*> *cached_location
;
2147 FOR_EACH_VEC_ELT (m_cached_locations
, i
, cached_location
)
2149 tree t
= cached_location
->first
;
2150 source_location srcloc
= cached_location
->second
->m_srcloc
;
2152 /* This covers expressions: */
2153 if (CAN_HAVE_LOCATION_P (t
))
2154 SET_EXPR_LOCATION (t
, srcloc
);
2155 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t
), TS_DECL_MINIMAL
))
2156 DECL_SOURCE_LOCATION (t
) = srcloc
;
2159 /* Don't know how to set location on this node. */
2164 /* We handle errors on a playback::context by adding them to the
2165 corresponding recording::context. */
2169 add_error (location
*loc
, const char *fmt
, ...)
2173 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2178 /* We handle errors on a playback::context by adding them to the
2179 corresponding recording::context. */
2183 add_error_va (location
*loc
, const char *fmt
, va_list ap
)
2185 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
2189 /* Dealing with the linemap API. */
2191 /* Construct a playback::location for a recording::location, if it
2192 doesn't exist already. */
2194 playback::location
*
2196 new_location (recording::location
*rloc
,
2197 const char *filename
,
2201 /* Get the source_file for filename, creating if necessary. */
2202 source_file
*src_file
= get_source_file (filename
);
2203 /* Likewise for the line within the file. */
2204 source_line
*src_line
= src_file
->get_source_line (line
);
2205 /* Likewise for the column within the line. */
2206 location
*loc
= src_line
->get_location (rloc
, column
);
2210 /* Deferred setting of the location for a given tree, by adding the
2211 (tree, playback::location) pair to a list of deferred associations.
2212 We will actually set the location on the tree later on once
2213 the source_location for the playback::location exists. */
2217 set_tree_location (tree t
, location
*loc
)
2220 m_cached_locations
.safe_push (std::make_pair (t
, loc
));
2224 /* Construct a playback::source_file for the given source
2225 filename, if it doesn't exist already. */
2227 playback::source_file
*
2229 get_source_file (const char *filename
)
2232 For simplicitly, this is currently a linear search.
2233 Replace with a hash if this shows up in the profile. */
2236 tree ident_filename
= get_identifier (filename
);
2238 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2239 if (file
->filename_as_tree () == ident_filename
)
2243 file
= new source_file (ident_filename
);
2244 m_source_files
.safe_push (file
);
2248 /* Constructor for gcc::jit::playback::source_file. */
2250 playback::source_file::source_file (tree filename
) :
2252 m_filename (filename
)
2256 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2260 playback::source_file::finalizer ()
2262 m_source_lines
.release ();
2265 /* Construct a playback::source_line for the given line
2266 within this source file, if one doesn't exist already. */
2268 playback::source_line
*
2269 playback::source_file::
2270 get_source_line (int line_num
)
2273 For simplicitly, this is currently a linear search.
2274 Replace with a hash if this shows up in the profile. */
2278 FOR_EACH_VEC_ELT (m_source_lines
, i
, line
)
2279 if (line
->get_line_num () == line_num
)
2283 line
= new source_line (this, line_num
);
2284 m_source_lines
.safe_push (line
);
2288 /* Constructor for gcc::jit::playback::source_line. */
2290 playback::source_line::source_line (source_file
*file
, int line_num
) :
2292 m_source_file (file
),
2293 m_line_num (line_num
)
2297 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2301 playback::source_line::finalizer ()
2303 m_locations
.release ();
2306 /* Construct a playback::location for the given column
2307 within this line of a specific source file, if one doesn't exist
2310 playback::location
*
2311 playback::source_line::
2312 get_location (recording::location
*rloc
, int column_num
)
2317 /* Another linear search that probably should be a hash table. */
2318 FOR_EACH_VEC_ELT (m_locations
, i
, loc
)
2319 if (loc
->get_column_num () == column_num
)
2323 loc
= new location (rloc
, this, column_num
);
2324 m_locations
.safe_push (loc
);
2328 /* Constructor for gcc::jit::playback::location. */
2330 playback::location::location (recording::location
*loc
,
2333 m_srcloc (UNKNOWN_LOCATION
),
2334 m_recording_loc (loc
),
2336 m_column_num(column_num
)
2340 /* The active gcc::jit::playback::context instance. This is a singleton,
2341 guarded by jit_mutex. */
2343 playback::context
*active_playback_ctxt
;
2345 } // namespace gcc::jit