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"
51 #include "jit-common.h"
52 #include "jit-playback.h"
53 #include "jit-result.h"
54 #include "jit-builtins.h"
57 /* gcc::jit::playback::context::build_cast uses the convert.h API,
58 which in turn requires the frontend to provide a "convert"
59 function, apparently as a fallback.
61 Hence we provide this dummy one, with the requirement that any casts
62 are handled before reaching this. */
63 extern tree
convert (tree type
, tree expr
);
66 convert (tree dst_type
, tree expr
)
68 gcc_assert (gcc::jit::active_playback_ctxt
);
69 gcc::jit::active_playback_ctxt
->add_error (NULL
, "unhandled conversion");
70 fprintf (stderr
, "input expression:\n");
72 fprintf (stderr
, "requested type:\n");
73 debug_tree (dst_type
);
74 return error_mark_node
;
80 /**********************************************************************
82 **********************************************************************/
84 /* The constructor for gcc::jit::playback::context. */
86 playback::context::context (recording::context
*ctxt
)
87 : m_recording_ctxt (ctxt
),
88 m_char_array_type_node (NULL
),
89 m_const_char_ptr (NULL
)
91 m_functions
.create (0);
92 m_source_files
.create (0);
93 m_cached_locations
.create (0);
96 /* The destructor for gcc::jit::playback::context. */
98 playback::context::~context ()
100 if (get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
))
101 fprintf (stderr
, "intermediate files written to %s\n", m_path_tempdir
);
104 /* Clean up .s/.so and tempdir. */
106 unlink (m_path_s_file
);
108 unlink (m_path_so_file
);
110 rmdir (m_path_tempdir
);
113 free (m_path_template
);
114 /* m_path_tempdir aliases m_path_template, or is NULL, so don't
115 attempt to free it . */
116 free (m_path_c_file
);
117 free (m_path_s_file
);
118 free (m_path_so_file
);
119 m_functions
.release ();
122 /* A playback::context can reference GC-managed pointers. Mark them
123 ("by hand", rather than by gengtype).
125 This is called on the active playback context (if any) by the
126 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
134 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
136 if (ggc_test_and_set_mark (func
))
141 /* Given an enum gcc_jit_types value, get a "tree" type. */
144 get_tree_node_for_type (enum gcc_jit_types type_
)
148 case GCC_JIT_TYPE_VOID
:
149 return void_type_node
;
151 case GCC_JIT_TYPE_VOID_PTR
:
152 return ptr_type_node
;
154 case GCC_JIT_TYPE_BOOL
:
155 return boolean_type_node
;
157 case GCC_JIT_TYPE_CHAR
:
158 return char_type_node
;
159 case GCC_JIT_TYPE_SIGNED_CHAR
:
160 return signed_char_type_node
;
161 case GCC_JIT_TYPE_UNSIGNED_CHAR
:
162 return unsigned_char_type_node
;
164 case GCC_JIT_TYPE_SHORT
:
165 return short_integer_type_node
;
166 case GCC_JIT_TYPE_UNSIGNED_SHORT
:
167 return short_unsigned_type_node
;
169 case GCC_JIT_TYPE_CONST_CHAR_PTR
:
171 tree const_char
= build_qualified_type (char_type_node
,
173 return build_pointer_type (const_char
);
176 case GCC_JIT_TYPE_INT
:
177 return integer_type_node
;
178 case GCC_JIT_TYPE_UNSIGNED_INT
:
179 return unsigned_type_node
;
181 case GCC_JIT_TYPE_LONG
:
182 return long_integer_type_node
;
183 case GCC_JIT_TYPE_UNSIGNED_LONG
:
184 return long_unsigned_type_node
;
186 case GCC_JIT_TYPE_LONG_LONG
:
187 return long_long_integer_type_node
;
188 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG
:
189 return long_long_unsigned_type_node
;
191 case GCC_JIT_TYPE_FLOAT
:
192 return float_type_node
;
193 case GCC_JIT_TYPE_DOUBLE
:
194 return double_type_node
;
195 case GCC_JIT_TYPE_LONG_DOUBLE
:
196 return long_double_type_node
;
198 case GCC_JIT_TYPE_SIZE_T
:
199 return size_type_node
;
201 case GCC_JIT_TYPE_FILE_PTR
:
202 return fileptr_type_node
;
204 case GCC_JIT_TYPE_COMPLEX_FLOAT
:
205 return complex_float_type_node
;
206 case GCC_JIT_TYPE_COMPLEX_DOUBLE
:
207 return complex_double_type_node
;
208 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE
:
209 return complex_long_double_type_node
;
215 /* Construct a playback::type instance (wrapping a tree) for the given
220 get_type (enum gcc_jit_types type_
)
222 tree type_node
= get_tree_node_for_type (type_
);
223 if (NULL
== type_node
)
226 "unrecognized (enum gcc_jit_types) value: %i", type_
);
230 return new type (type_node
);
233 /* Construct a playback::type instance (wrapping a tree) for the given
238 new_array_type (playback::location
*loc
,
239 playback::type
*element_type
,
242 gcc_assert (element_type
);
244 tree t
= build_array_type_nelts (element_type
->as_tree (),
249 set_tree_location (t
, loc
);
254 /* Construct a playback::field instance (wrapping a tree). */
258 new_field (location
*loc
,
265 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
266 tree decl
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
267 get_identifier (name
), type
->as_tree ());
270 set_tree_location (decl
, loc
);
272 return new field (decl
);
275 /* Construct a playback::compound_type instance (wrapping a tree). */
277 playback::compound_type
*
279 new_compound_type (location
*loc
,
281 bool is_struct
) /* else is union */
285 /* Compare with c/c-decl.c: start_struct. */
287 tree t
= make_node (is_struct
? RECORD_TYPE
: UNION_TYPE
);
288 TYPE_NAME (t
) = get_identifier (name
);
292 set_tree_location (t
, loc
);
294 return new compound_type (t
);
298 playback::compound_type::set_fields (const auto_vec
<playback::field
*> *fields
)
300 /* Compare with c/c-decl.c: finish_struct. */
303 tree fieldlist
= NULL
;
304 for (unsigned i
= 0; i
< fields
->length (); i
++)
306 field
*f
= (*fields
)[i
];
307 DECL_CONTEXT (f
->as_tree ()) = t
;
308 fieldlist
= chainon (f
->as_tree (), fieldlist
);
310 fieldlist
= nreverse (fieldlist
);
311 TYPE_FIELDS (t
) = fieldlist
;
316 /* Construct a playback::type instance (wrapping a tree) for a function
321 new_function_type (type
*return_type
,
322 const auto_vec
<type
*> *param_types
,
328 tree
*arg_types
= (tree
*)xcalloc(param_types
->length (), sizeof(tree
*));
330 FOR_EACH_VEC_ELT (*param_types
, i
, param_type
)
331 arg_types
[i
] = param_type
->as_tree ();
336 build_varargs_function_type_array (return_type
->as_tree (),
337 param_types
->length (),
340 fn_type
= build_function_type_array (return_type
->as_tree (),
341 param_types
->length (),
345 return new type (fn_type
);
348 /* Construct a playback::param instance (wrapping a tree). */
352 new_param (location
*loc
,
358 tree inner
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
359 get_identifier (name
), type
->as_tree ());
361 set_tree_location (inner
, loc
);
363 return new param (this, inner
);
366 /* Construct a playback::function instance. */
370 new_function (location
*loc
,
371 enum gcc_jit_function_kind kind
,
374 const auto_vec
<param
*> *params
,
376 enum built_in_function builtin_id
)
381 //can return_type be NULL?
384 tree
*arg_types
= (tree
*)xcalloc(params
->length (), sizeof(tree
*));
385 FOR_EACH_VEC_ELT (*params
, i
, param
)
386 arg_types
[i
] = TREE_TYPE (param
->as_tree ());
390 fn_type
= build_varargs_function_type_array (return_type
->as_tree (),
391 params
->length (), arg_types
);
393 fn_type
= build_function_type_array (return_type
->as_tree (),
394 params
->length (), arg_types
);
397 /* FIXME: this uses input_location: */
398 tree fndecl
= build_fn_decl (name
, fn_type
);
401 set_tree_location (fndecl
, loc
);
403 tree resdecl
= build_decl (UNKNOWN_LOCATION
, RESULT_DECL
,
404 NULL_TREE
, return_type
->as_tree ());
405 DECL_ARTIFICIAL (resdecl
) = 1;
406 DECL_IGNORED_P (resdecl
) = 1;
407 DECL_RESULT (fndecl
) = resdecl
;
411 DECL_FUNCTION_CODE (fndecl
) = builtin_id
;
412 gcc_assert (loc
== NULL
);
413 DECL_SOURCE_LOCATION (fndecl
) = BUILTINS_LOCATION
;
415 DECL_BUILT_IN_CLASS (fndecl
) =
416 builtins_manager::get_class (builtin_id
);
417 set_builtin_decl (builtin_id
, fndecl
,
418 builtins_manager::implicit_p (builtin_id
));
420 builtins_manager
*bm
= get_builtins_manager ();
421 tree attrs
= bm
->get_attrs_tree (builtin_id
);
423 decl_attributes (&fndecl
, attrs
, ATTR_FLAG_BUILT_IN
);
425 decl_attributes (&fndecl
, NULL_TREE
, 0);
428 if (kind
!= GCC_JIT_FUNCTION_IMPORTED
)
430 tree param_decl_list
= NULL
;
431 FOR_EACH_VEC_ELT (*params
, i
, param
)
433 param_decl_list
= chainon (param
->as_tree (), param_decl_list
);
436 /* The param list was created in reverse order; fix it: */
437 param_decl_list
= nreverse (param_decl_list
);
440 for (t
= param_decl_list
; t
; t
= DECL_CHAIN (t
))
442 DECL_CONTEXT (t
) = fndecl
;
443 DECL_ARG_TYPE (t
) = TREE_TYPE (t
);
446 /* Set it up on DECL_ARGUMENTS */
447 DECL_ARGUMENTS(fndecl
) = param_decl_list
;
450 if (kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
452 DECL_DECLARED_INLINE_P (fndecl
) = 1;
454 /* Add attribute "always_inline": */
455 DECL_ATTRIBUTES (fndecl
) =
456 tree_cons (get_identifier ("always_inline"),
458 DECL_ATTRIBUTES (fndecl
));
461 function
*func
= new function (this, fndecl
, kind
);
462 m_functions
.safe_push (func
);
466 /* Construct a playback::lvalue instance (wrapping a tree). */
470 new_global (location
*loc
,
476 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
477 get_identifier (name
),
479 TREE_PUBLIC (inner
) = 1;
480 DECL_COMMON (inner
) = 1;
481 DECL_EXTERNAL (inner
) = 1;
484 set_tree_location (inner
, loc
);
486 return new lvalue (this, inner
);
489 /* Construct a playback::rvalue instance (wrapping a tree). */
493 new_rvalue_from_int (type
*type
,
496 // FIXME: type-checking, or coercion?
497 tree inner_type
= type
->as_tree ();
498 if (INTEGRAL_TYPE_P (inner_type
))
500 tree inner
= build_int_cst (inner_type
, value
);
501 return new rvalue (this, inner
);
505 REAL_VALUE_TYPE real_value
;
506 real_from_integer (&real_value
, VOIDmode
, value
, SIGNED
);
507 tree inner
= build_real (inner_type
, real_value
);
508 return new rvalue (this, inner
);
512 /* Construct a playback::rvalue instance (wrapping a tree). */
516 new_rvalue_from_double (type
*type
,
519 // FIXME: type-checking, or coercion?
520 tree inner_type
= type
->as_tree ();
522 /* We have a "double", we want a REAL_VALUE_TYPE.
524 real.c:real_from_target appears to require the representation to be
525 split into 32-bit values, and then sent as an pair of host long
527 REAL_VALUE_TYPE real_value
;
531 uint32_t as_uint32s
[2];
534 long int as_long_ints
[2];
535 as_long_ints
[0] = u
.as_uint32s
[0];
536 as_long_ints
[1] = u
.as_uint32s
[1];
537 real_from_target (&real_value
, as_long_ints
, DFmode
);
538 tree inner
= build_real (inner_type
, real_value
);
539 return new rvalue (this, inner
);
542 /* Construct a playback::rvalue instance (wrapping a tree). */
546 new_rvalue_from_ptr (type
*type
,
549 tree inner_type
= type
->as_tree ();
550 /* FIXME: how to ensure we have a wide enough type? */
551 tree inner
= build_int_cstu (inner_type
, (unsigned HOST_WIDE_INT
)value
);
552 return new rvalue (this, inner
);
555 /* Construct a playback::rvalue instance (wrapping a tree). */
559 new_string_literal (const char *value
)
561 tree t_str
= build_string (strlen (value
), value
);
562 gcc_assert (m_char_array_type_node
);
563 TREE_TYPE (t_str
) = m_char_array_type_node
;
565 /* Convert to (const char*), loosely based on
566 c/c-typeck.c: array_to_pointer_conversion,
567 by taking address of start of string. */
568 tree t_addr
= build1 (ADDR_EXPR
, m_const_char_ptr
, t_str
);
570 return new rvalue (this, t_addr
);
573 /* Coerce a tree expression into a boolean tree expression. */
577 as_truth_value (tree expr
, location
*loc
)
579 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
580 tree typed_zero
= fold_build1 (CONVERT_EXPR
,
584 set_tree_location (typed_zero
, loc
);
586 expr
= build2 (NE_EXPR
, integer_type_node
, expr
, typed_zero
);
588 set_tree_location (expr
, loc
);
593 /* Construct a playback::rvalue instance (wrapping a tree) for a
598 new_unary_op (location
*loc
,
599 enum gcc_jit_unary_op op
,
603 // FIXME: type-checking, or coercion?
604 enum tree_code inner_op
;
606 gcc_assert (result_type
);
609 tree node
= a
->as_tree ();
610 tree inner_result
= NULL
;
615 add_error (loc
, "unrecognized (enum gcc_jit_unary_op) value: %i", op
);
618 case GCC_JIT_UNARY_OP_MINUS
:
619 inner_op
= NEGATE_EXPR
;
622 case GCC_JIT_UNARY_OP_BITWISE_NEGATE
:
623 inner_op
= BIT_NOT_EXPR
;
626 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE
:
627 node
= as_truth_value (node
, loc
);
628 inner_result
= invert_truthvalue (node
);
630 set_tree_location (inner_result
, loc
);
631 return new rvalue (this, inner_result
);
634 inner_result
= build1 (inner_op
,
635 result_type
->as_tree (),
638 set_tree_location (inner_result
, loc
);
640 return new rvalue (this, inner_result
);
643 /* Construct a playback::rvalue instance (wrapping a tree) for a
648 new_binary_op (location
*loc
,
649 enum gcc_jit_binary_op op
,
651 rvalue
*a
, rvalue
*b
)
653 // FIXME: type-checking, or coercion?
654 enum tree_code inner_op
;
656 gcc_assert (result_type
);
660 tree node_a
= a
->as_tree ();
661 tree node_b
= b
->as_tree ();
666 add_error (loc
, "unrecognized (enum gcc_jit_binary_op) value: %i", op
);
669 case GCC_JIT_BINARY_OP_PLUS
:
670 inner_op
= PLUS_EXPR
;
673 case GCC_JIT_BINARY_OP_MINUS
:
674 inner_op
= MINUS_EXPR
;
677 case GCC_JIT_BINARY_OP_MULT
:
678 inner_op
= MULT_EXPR
;
681 case GCC_JIT_BINARY_OP_DIVIDE
:
682 if (FLOAT_TYPE_P (result_type
->as_tree ()))
683 /* Floating-point division: */
684 inner_op
= RDIV_EXPR
;
686 /* Truncating to zero: */
687 inner_op
= TRUNC_DIV_EXPR
;
690 case GCC_JIT_BINARY_OP_MODULO
:
691 inner_op
= TRUNC_MOD_EXPR
;
694 case GCC_JIT_BINARY_OP_BITWISE_AND
:
695 inner_op
= BIT_AND_EXPR
;
698 case GCC_JIT_BINARY_OP_BITWISE_XOR
:
699 inner_op
= BIT_XOR_EXPR
;
702 case GCC_JIT_BINARY_OP_BITWISE_OR
:
703 inner_op
= BIT_IOR_EXPR
;
706 case GCC_JIT_BINARY_OP_LOGICAL_AND
:
707 node_a
= as_truth_value (node_a
, loc
);
708 node_b
= as_truth_value (node_b
, loc
);
709 inner_op
= TRUTH_ANDIF_EXPR
;
712 case GCC_JIT_BINARY_OP_LOGICAL_OR
:
713 node_a
= as_truth_value (node_a
, loc
);
714 node_b
= as_truth_value (node_b
, loc
);
715 inner_op
= TRUTH_ORIF_EXPR
;
718 case GCC_JIT_BINARY_OP_LSHIFT
:
719 inner_op
= LSHIFT_EXPR
;
722 case GCC_JIT_BINARY_OP_RSHIFT
:
723 inner_op
= RSHIFT_EXPR
;
727 tree inner_expr
= build2 (inner_op
,
728 result_type
->as_tree (),
732 set_tree_location (inner_expr
, loc
);
734 return new rvalue (this, inner_expr
);
737 /* Construct a playback::rvalue instance (wrapping a tree) for a
742 new_comparison (location
*loc
,
743 enum gcc_jit_comparison op
,
744 rvalue
*a
, rvalue
*b
)
746 // FIXME: type-checking, or coercion?
747 enum tree_code inner_op
;
755 add_error (loc
, "unrecognized (enum gcc_jit_comparison) value: %i", op
);
758 case GCC_JIT_COMPARISON_EQ
:
761 case GCC_JIT_COMPARISON_NE
:
764 case GCC_JIT_COMPARISON_LT
:
767 case GCC_JIT_COMPARISON_LE
:
770 case GCC_JIT_COMPARISON_GT
:
773 case GCC_JIT_COMPARISON_GE
:
778 tree inner_expr
= build2 (inner_op
,
783 set_tree_location (inner_expr
, loc
);
784 return new rvalue (this, inner_expr
);
787 /* Construct a playback::rvalue instance (wrapping a tree) for a
792 build_call (location
*loc
,
794 const auto_vec
<rvalue
*> *args
)
796 vec
<tree
, va_gc
> *tree_args
;
797 vec_alloc (tree_args
, args
->length ());
798 for (unsigned i
= 0; i
< args
->length (); i
++)
799 tree_args
->quick_push ((*args
)[i
]->as_tree ());
802 set_tree_location (fn_ptr
, loc
);
804 tree fn
= TREE_TYPE (fn_ptr
);
805 tree fn_type
= TREE_TYPE (fn
);
806 tree return_type
= TREE_TYPE (fn_type
);
808 return new rvalue (this,
809 build_call_vec (return_type
,
812 /* see c-typeck.c: build_function_call
813 which calls build_function_call_vec
815 which does lots of checking, then:
816 result = build_call_array_loc (loc, TREE_TYPE (fntype),
817 function, nargs, argarray);
819 (see also build_call_vec)
823 /* Construct a playback::rvalue instance (wrapping a tree) for a
824 call to a specific function. */
828 new_call (location
*loc
,
830 const auto_vec
<rvalue
*> *args
)
836 fndecl
= func
->as_fndecl ();
838 tree fntype
= TREE_TYPE (fndecl
);
840 tree fn
= build1 (ADDR_EXPR
, build_pointer_type (fntype
), fndecl
);
842 return build_call (loc
, fn
, args
);
845 /* Construct a playback::rvalue instance (wrapping a tree) for a
846 call through a function pointer. */
850 new_call_through_ptr (location
*loc
,
852 const auto_vec
<rvalue
*> *args
)
855 tree t_fn_ptr
= fn_ptr
->as_tree ();
857 return build_call (loc
, t_fn_ptr
, args
);
860 /* Construct a tree for a cast. */
863 playback::context::build_cast (playback::location
*loc
,
864 playback::rvalue
*expr
,
865 playback::type
*type_
)
867 /* For comparison, see:
868 - c/c-typeck.c:build_c_cast
869 - c/c-convert.c: convert
872 Only some kinds of cast are currently supported here. */
873 tree t_expr
= expr
->as_tree ();
874 tree t_dst_type
= type_
->as_tree ();
876 t_ret
= targetm
.convert_to_type (t_dst_type
, t_expr
);
879 enum tree_code dst_code
= TREE_CODE (t_dst_type
);
884 t_ret
= convert_to_integer (t_dst_type
, t_expr
);
888 /* Compare with c_objc_common_truthvalue_conversion and
889 c_common_truthvalue_conversion. */
890 /* For now, convert to: (t_expr != 0) */
891 t_ret
= build2 (NE_EXPR
, t_dst_type
,
892 t_expr
, integer_zero_node
);
896 t_ret
= convert_to_real (t_dst_type
, t_expr
);
900 t_ret
= build1 (NOP_EXPR
, t_dst_type
, t_expr
);
904 add_error (loc
, "couldn't handle cast during playback");
905 fprintf (stderr
, "input expression:\n");
907 fprintf (stderr
, "requested type:\n");
908 debug_tree (t_dst_type
);
909 return error_mark_node
;
912 if (TREE_CODE (t_ret
) != C_MAYBE_CONST_EXPR
)
913 t_ret
= fold (t_ret
);
918 /* Construct a playback::rvalue instance (wrapping a tree) for a
923 new_cast (playback::location
*loc
,
924 playback::rvalue
*expr
,
925 playback::type
*type_
)
928 tree t_cast
= build_cast (loc
, expr
, type_
);
930 set_tree_location (t_cast
, loc
);
931 return new rvalue (this, t_cast
);
934 /* Construct a playback::lvalue instance (wrapping a tree) for an
939 new_array_access (location
*loc
,
946 /* For comparison, see:
947 c/c-typeck.c: build_array_ref
948 c-family/c-common.c: pointer_int_sum
950 tree t_ptr
= ptr
->as_tree ();
951 tree t_index
= index
->as_tree ();
952 tree t_type_ptr
= TREE_TYPE (t_ptr
);
953 tree t_type_star_ptr
= TREE_TYPE (t_type_ptr
);
955 if (TREE_CODE (t_type_ptr
) == ARRAY_TYPE
)
957 tree t_result
= build4 (ARRAY_REF
, t_type_star_ptr
, t_ptr
, t_index
,
958 NULL_TREE
, NULL_TREE
);
960 set_tree_location (t_result
, loc
);
961 return new lvalue (this, t_result
);
965 /* Convert index to an offset in bytes. */
966 tree t_sizeof
= size_in_bytes (t_type_star_ptr
);
967 t_index
= fold_build1 (CONVERT_EXPR
, sizetype
, t_index
);
968 tree t_offset
= build2 (MULT_EXPR
, sizetype
, t_index
, t_sizeof
);
970 /* Locate (ptr + offset). */
971 tree t_address
= build2 (POINTER_PLUS_EXPR
, t_type_ptr
, t_ptr
, t_offset
);
973 tree t_indirection
= build1 (INDIRECT_REF
, t_type_star_ptr
, t_address
);
976 set_tree_location (t_sizeof
, loc
);
977 set_tree_location (t_offset
, loc
);
978 set_tree_location (t_address
, loc
);
979 set_tree_location (t_indirection
, loc
);
982 return new lvalue (this, t_indirection
);
986 /* Construct a tree for a field access. */
990 new_field_access (location
*loc
,
997 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
998 build_component_ref. */
999 tree type
= TREE_TYPE (datum
);
1001 gcc_assert (TREE_CODE (type
) != POINTER_TYPE
);
1003 tree t_field
= field
->as_tree ();
1004 tree ref
= build3 (COMPONENT_REF
, TREE_TYPE (t_field
), datum
,
1005 t_field
, NULL_TREE
);
1007 set_tree_location (ref
, loc
);
1011 /* Construct a tree for a dereference. */
1015 new_dereference (tree ptr
,
1020 tree type
= TREE_TYPE (TREE_TYPE(ptr
));
1021 tree datum
= build1 (INDIRECT_REF
, type
, ptr
);
1023 set_tree_location (datum
, loc
);
1027 /* Construct a playback::lvalue instance (wrapping a tree) for a
1032 access_field (location
*loc
,
1035 tree datum
= as_tree ();
1036 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1039 return new lvalue (get_context (), ref
);
1042 /* Construct a playback::rvalue instance (wrapping a tree) for a
1047 access_field (location
*loc
,
1050 tree datum
= as_tree ();
1051 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1054 return new rvalue (get_context (), ref
);
1057 /* Construct a playback::lvalue instance (wrapping a tree) for a
1058 dereferenced field access. */
1062 dereference_field (location
*loc
,
1065 tree ptr
= as_tree ();
1066 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1069 tree ref
= get_context ()->new_field_access (loc
, datum
, field
);
1072 return new lvalue (get_context (), ref
);
1075 /* Construct a playback::lvalue instance (wrapping a tree) for a
1080 dereference (location
*loc
)
1082 tree ptr
= as_tree ();
1083 tree datum
= get_context ()->new_dereference (ptr
, loc
);
1084 return new lvalue (get_context (), datum
);
1087 /* Construct a playback::rvalue instance (wrapping a tree) for an
1092 get_address (location
*loc
)
1094 tree t_lvalue
= as_tree ();
1095 tree t_thistype
= TREE_TYPE (t_lvalue
);
1096 tree t_ptrtype
= build_pointer_type (t_thistype
);
1097 tree ptr
= build1 (ADDR_EXPR
, t_ptrtype
, t_lvalue
);
1099 get_context ()->set_tree_location (ptr
, loc
);
1100 return new rvalue (get_context (), ptr
);
1103 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1104 Provide this finalization hook for calling then they are collected,
1105 which calls the finalizer vfunc. This allows them to call "release"
1106 on any vec<> within them. */
1109 wrapper_finalizer (void *ptr
)
1111 playback::wrapper
*wrapper
= reinterpret_cast <playback::wrapper
*> (ptr
);
1112 wrapper
->finalizer ();
1115 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1116 allocate them using ggc_internal_cleared_alloc. */
1120 operator new (size_t sz
)
1122 return ggc_internal_cleared_alloc (sz
, wrapper_finalizer
, 0, 1);
1126 /* Constructor for gcc:jit::playback::function. */
1128 playback::function::
1129 function (context
*ctxt
,
1131 enum gcc_jit_function_kind kind
)
1133 m_inner_fndecl (fndecl
),
1134 m_inner_bind_expr (NULL
),
1137 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1139 /* Create a BIND_EXPR, and within it, a statement list. */
1140 m_stmt_list
= alloc_stmt_list ();
1141 m_stmt_iter
= tsi_start (m_stmt_list
);
1142 m_inner_block
= make_node (BLOCK
);
1144 build3 (BIND_EXPR
, void_type_node
, NULL
, m_stmt_list
, m_inner_block
);
1148 m_inner_block
= NULL
;
1153 /* Hand-written GC-marking hook for playback functions. */
1156 playback::function::
1159 gt_ggc_m_9tree_node (m_inner_fndecl
);
1160 gt_ggc_m_9tree_node (m_inner_bind_expr
);
1161 gt_ggc_m_9tree_node (m_stmt_list
);
1162 gt_ggc_m_9tree_node (m_inner_block
);
1165 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1169 playback::function::finalizer ()
1171 m_blocks
.release ();
1174 /* Get the return type of a playback function, in tree form. */
1177 playback::function::
1178 get_return_type_as_tree () const
1180 return TREE_TYPE (TREE_TYPE(m_inner_fndecl
));
1183 /* Construct a new local within this playback::function. */
1186 playback::function::
1187 new_local (location
*loc
,
1193 tree inner
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
1194 get_identifier (name
),
1196 DECL_CONTEXT (inner
) = this->m_inner_fndecl
;
1198 /* Prepend to BIND_EXPR_VARS: */
1199 DECL_CHAIN (inner
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1200 BIND_EXPR_VARS (m_inner_bind_expr
) = inner
;
1203 set_tree_location (inner
, loc
);
1204 return new lvalue (m_ctxt
, inner
);
1207 /* Construct a new block within this playback::function. */
1210 playback::function::
1211 new_block (const char *name
)
1213 gcc_assert (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
);
1215 block
*result
= new playback::block (this, name
);
1216 m_blocks
.safe_push (result
);
1220 /* Build a statement list for the function as a whole out of the
1221 lists of statements for the individual blocks, building labels
1225 playback::function::
1231 FOR_EACH_VEC_ELT (m_blocks
, i
, b
)
1236 b
->m_label_expr
= build1 (LABEL_EXPR
,
1238 b
->as_label_decl ());
1239 tsi_link_after (&m_stmt_iter
, b
->m_label_expr
, TSI_CONTINUE_LINKING
);
1241 FOR_EACH_VEC_ELT (b
->m_stmts
, j
, stmt
)
1242 tsi_link_after (&m_stmt_iter
, stmt
, TSI_CONTINUE_LINKING
);
1246 /* Finish compiling the given function, potentially running the
1248 The function will have a statement list by now.
1249 Amongst other things, this gimplifies the statement list,
1250 and calls cgraph_node::finalize_function on the function. */
1253 playback::function::
1256 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
))
1257 debug_tree (m_stmt_list
);
1259 /* Do we need this to force cgraphunit.c to output the function? */
1260 if (m_kind
== GCC_JIT_FUNCTION_EXPORTED
)
1262 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1263 DECL_PRESERVE_P (m_inner_fndecl
) = 1;
1266 if (m_kind
== GCC_JIT_FUNCTION_INTERNAL
1267 ||m_kind
== GCC_JIT_FUNCTION_ALWAYS_INLINE
)
1269 DECL_EXTERNAL (m_inner_fndecl
) = 0;
1270 TREE_PUBLIC (m_inner_fndecl
) = 0;
1273 if (m_kind
!= GCC_JIT_FUNCTION_IMPORTED
)
1275 /* Seem to need this in gimple-low.c: */
1276 gcc_assert (m_inner_block
);
1277 DECL_INITIAL (m_inner_fndecl
) = m_inner_block
;
1279 /* how to add to function? the following appears to be how to
1280 set the body of a m_inner_fndecl: */
1281 DECL_SAVED_TREE(m_inner_fndecl
) = m_inner_bind_expr
;
1283 /* Ensure that locals appear in the debuginfo. */
1284 BLOCK_VARS (m_inner_block
) = BIND_EXPR_VARS (m_inner_bind_expr
);
1286 //debug_tree (m_inner_fndecl);
1288 /* Convert to gimple: */
1289 //printf("about to gimplify_function_tree\n");
1290 gimplify_function_tree (m_inner_fndecl
);
1291 //printf("finished gimplify_function_tree\n");
1293 current_function_decl
= m_inner_fndecl
;
1294 if (m_ctxt
->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
))
1295 dump_function_to_file (m_inner_fndecl
, stderr
, TDF_VOPS
|TDF_MEMSYMS
|TDF_LINENO
);
1296 //debug_tree (m_inner_fndecl);
1298 //printf("about to add to cgraph\n");
1299 /* Add to cgraph: */
1300 cgraph_node::finalize_function (m_inner_fndecl
, false);
1301 /* This can trigger a collection, so we need to have all of
1302 the funcs as roots. */
1304 current_function_decl
= NULL
;
1308 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1312 playback::block::finalizer ()
1317 /* Add an eval of the rvalue to the function's statement list. */
1321 add_eval (location
*loc
,
1324 gcc_assert (rvalue
);
1327 set_tree_location (rvalue
->as_tree (), loc
);
1329 add_stmt (rvalue
->as_tree ());
1332 /* Add an assignment to the function's statement list. */
1336 add_assignment (location
*loc
,
1340 gcc_assert (lvalue
);
1341 gcc_assert (rvalue
);
1343 tree t_lvalue
= lvalue
->as_tree ();
1344 tree t_rvalue
= rvalue
->as_tree ();
1345 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1347 t_rvalue
= build1 (CONVERT_EXPR
,
1348 TREE_TYPE (t_lvalue
),
1351 set_tree_location (t_rvalue
, loc
);
1355 build2 (MODIFY_EXPR
, TREE_TYPE (t_lvalue
),
1356 t_lvalue
, t_rvalue
);
1358 set_tree_location (stmt
, loc
);
1362 /* Add a comment to the function's statement list.
1363 For now this is done by adding a dummy label. */
1367 add_comment (location
*loc
,
1370 /* Wrap the text in C-style comment delimiters. */
1372 (3 /* opening delim */
1374 + 3 /* closing delim */
1375 + 1 /* terminator */);
1376 char *wrapped
= (char *)ggc_internal_alloc (sz
);
1377 snprintf (wrapped
, sz
, "/* %s */", text
);
1379 /* For now we simply implement this by adding a dummy label with a name
1380 containing the given text. */
1381 tree identifier
= get_identifier (wrapped
);
1382 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1383 identifier
, void_type_node
);
1384 DECL_CONTEXT (label_decl
) = m_func
->as_fndecl ();
1386 tree label_expr
= build1 (LABEL_EXPR
, void_type_node
, label_decl
);
1388 set_tree_location (label_expr
, loc
);
1389 add_stmt (label_expr
);
1392 /* Add a conditional jump statement to the function's statement list. */
1396 add_conditional (location
*loc
,
1401 gcc_assert (boolval
);
1402 gcc_assert (on_true
);
1403 gcc_assert (on_false
);
1405 /* COND_EXPR wants statement lists for the true/false operands, but we
1407 Shim it by creating jumps to the labels */
1408 tree true_jump
= build1 (GOTO_EXPR
, void_type_node
,
1409 on_true
->as_label_decl ());
1411 set_tree_location (true_jump
, loc
);
1413 tree false_jump
= build1 (GOTO_EXPR
, void_type_node
,
1414 on_false
->as_label_decl ());
1416 set_tree_location (false_jump
, loc
);
1419 build3 (COND_EXPR
, void_type_node
, boolval
->as_tree (),
1420 true_jump
, false_jump
);
1422 set_tree_location (stmt
, loc
);
1426 /* Add an unconditional jump statement to the function's statement list. */
1430 add_jump (location
*loc
,
1433 gcc_assert (target
);
1435 // see c_finish_loop
1436 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1439 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1440 TREE_USED (target
->as_label_decl ()) = 1;
1441 tree stmt
= build1 (GOTO_EXPR
, void_type_node
, target
->as_label_decl ());
1443 set_tree_location (stmt
, loc
);
1449 c_finish_goto_label (location_t loc, tree label)
1451 tree decl = lookup_label_for_goto (loc, label);
1454 TREE_USED (decl) = 1;
1456 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1457 SET_EXPR_LOCATION (t, loc);
1458 return add_stmt (t);
1465 /* Add a return statement to the function's statement list. */
1469 add_return (location
*loc
,
1472 tree modify_retval
= NULL
;
1473 tree return_type
= m_func
->get_return_type_as_tree ();
1476 tree t_lvalue
= DECL_RESULT (m_func
->as_fndecl ());
1477 tree t_rvalue
= rvalue
->as_tree ();
1478 if (TREE_TYPE (t_rvalue
) != TREE_TYPE (t_lvalue
))
1479 t_rvalue
= build1 (CONVERT_EXPR
,
1480 TREE_TYPE (t_lvalue
),
1482 modify_retval
= build2 (MODIFY_EXPR
, return_type
,
1483 t_lvalue
, t_rvalue
);
1485 set_tree_location (modify_retval
, loc
);
1487 tree return_stmt
= build1 (RETURN_EXPR
, return_type
,
1490 set_tree_location (return_stmt
, loc
);
1492 add_stmt (return_stmt
);
1495 /* Constructor for gcc::jit::playback::block. */
1498 block (function
*func
,
1508 identifier
= get_identifier (name
);
1511 m_label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
1512 identifier
, void_type_node
);
1513 DECL_CONTEXT (m_label_decl
) = func
->as_fndecl ();
1514 m_label_expr
= NULL
;
1517 /* Construct a tempdir path template suitable for use by mkdtemp
1518 e.g. "/tmp/libgccjit-XXXXXX", but respecting the rules in
1519 libiberty's choose_tempdir rather than hardcoding "/tmp/".
1521 The memory is allocated using malloc and must be freed.
1522 Aborts the process if allocation fails. */
1525 make_tempdir_path_template ()
1527 const char *tmpdir_buf
;
1529 const char *file_template_buf
;
1530 size_t file_template_len
;
1533 /* The result of choose_tmpdir is a cached buffer within libiberty, so
1534 we must *not* free it. */
1535 tmpdir_buf
= choose_tmpdir ();
1537 /* choose_tmpdir aborts on malloc failure. */
1538 gcc_assert (tmpdir_buf
);
1540 tmpdir_len
= strlen (tmpdir_buf
);
1541 /* tmpdir_buf should now have a dir separator as the final byte. */
1542 gcc_assert (tmpdir_len
> 0);
1543 gcc_assert (tmpdir_buf
[tmpdir_len
- 1] == DIR_SEPARATOR
);
1545 file_template_buf
= "libgccjit-XXXXXX";
1546 file_template_len
= strlen (file_template_buf
);
1548 result
= XNEWVEC (char, tmpdir_len
+ file_template_len
+ 1);
1549 strcpy (result
, tmpdir_buf
);
1550 strcpy (result
+ tmpdir_len
, file_template_buf
);
1555 /* Compile a playback::context:
1557 - Use the context's options to cconstruct command-line options, and
1558 call into the rest of GCC (toplev::main).
1559 - Assuming it succeeds, we have a .s file; we want a .so file.
1560 Invoke another gcc to convert the .s file to a .so file.
1561 - dlopen the .so file
1562 - Wrap the result up as a playback::result and return it. */
1568 void *handle
= NULL
;
1569 const char *ctxt_progname
;
1570 result
*result_obj
= NULL
;
1572 m_path_template
= make_tempdir_path_template ();
1573 if (!m_path_template
)
1576 /* Create tempdir using mkdtemp. This is created with 0700 perms and
1577 is unique. Hence no other (non-root) users should have access to
1578 the paths within it. */
1579 m_path_tempdir
= mkdtemp (m_path_template
);
1580 if (!m_path_tempdir
)
1582 m_path_c_file
= concat (m_path_tempdir
, "/fake.c", NULL
);
1583 m_path_s_file
= concat (m_path_tempdir
, "/fake.s", NULL
);
1584 m_path_so_file
= concat (m_path_tempdir
, "/fake.so", NULL
);
1586 /* Call into the rest of gcc.
1587 For now, we have to assemble command-line options to pass into
1588 toplev::main, so that they can be parsed. */
1590 /* Pass in user-provided program name as argv0, if any, so that it
1591 makes it into GCC's "progname" global, used in various diagnostics. */
1592 ctxt_progname
= get_str_option (GCC_JIT_STR_OPTION_PROGNAME
);
1595 ctxt_progname
= "libgccjit.so";
1597 auto_vec
<const char *> fake_args
;
1598 make_fake_args (&fake_args
, ctxt_progname
);
1599 if (errors_occurred ())
1602 toplev
toplev (false);
1603 toplev
.main (fake_args
.length (),
1604 const_cast <char **> (fake_args
.address ()));
1607 active_playback_ctxt
= NULL
;
1609 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 ())
1619 /* dlopen the .so file. */
1621 auto_timevar
load_timevar (TV_LOAD
);
1625 /* Clear any existing error. */
1628 handle
= dlopen (m_path_so_file
, RTLD_NOW
| RTLD_LOCAL
);
1629 if ((error
= dlerror()) != NULL
) {
1630 add_error (NULL
, "%s", error
);
1633 result_obj
= new result (handle
);
1641 /* Helper functions for gcc::jit::playback::context::compile. */
1643 /* Build a fake argv for toplev::main from the options set
1644 by the user on the context . */
1648 make_fake_args (auto_vec
<const char *> *argvec
,
1649 const char *ctxt_progname
)
1651 #define ADD_ARG(arg) argvec->safe_push (arg)
1653 ADD_ARG (ctxt_progname
);
1654 ADD_ARG (m_path_c_file
);
1657 /* Handle int options: */
1658 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
))
1662 "unrecognized optimization level: %i",
1663 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
));
1682 /* What about -Os? */
1684 /* Handle bool options: */
1685 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO
))
1688 /* Suppress timing (and other) info. */
1689 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
))
1695 /* Aggressively garbage-collect, to shake out bugs: */
1696 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC
))
1698 ADD_ARG ("--param");
1699 ADD_ARG ("ggc-min-expand=0");
1700 ADD_ARG ("--param");
1701 ADD_ARG ("ggc-min-heapsize=0");
1704 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
))
1706 ADD_ARG ("-fdump-tree-all");
1707 ADD_ARG ("-fdump-rtl-all");
1708 ADD_ARG ("-fdump-ipa-all");
1713 /* Part of playback::context::compile ().
1715 We have a .s file; we want a .so file.
1716 We could reuse parts of gcc/gcc.c to do this.
1717 For now, just use the driver binary from the install, as
1718 named in gcc-driver-name.h
1719 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
1723 convert_to_dso (const char *ctxt_progname
)
1725 /* Currently this lumps together both assembling and linking into
1727 auto_timevar
assemble_timevar (TV_ASSEMBLE
);
1729 const char *argv
[7];
1730 int exit_status
= 0;
1732 const char *gcc_driver_name
= GCC_DRIVER_NAME
;
1734 argv
[0] = gcc_driver_name
;
1735 argv
[1] = "-shared";
1736 /* The input: assembler. */
1737 argv
[2] = m_path_s_file
;
1738 /* The output: shared library. */
1740 argv
[4] = m_path_so_file
;
1742 /* Don't use the linker plugin.
1743 If running with just a "make" and not a "make install", then we'd
1745 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
1746 libto_plugin is a .la at build time, with it becoming installed with
1747 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
1749 argv
[5] = "-fno-use-linker-plugin";
1751 /* pex argv arrays are NULL-terminated. */
1754 /* pex_one's error-handling requires pname to be non-NULL. */
1755 gcc_assert (ctxt_progname
);
1757 errmsg
= pex_one (PEX_SEARCH
, /* int flags, */
1759 const_cast<char * const *> (argv
),
1760 ctxt_progname
, /* const char *pname */
1761 NULL
, /* const char *outname */
1762 NULL
, /* const char *errname */
1763 &exit_status
, /* int *status */
1764 &err
); /* int *err*/
1767 add_error (NULL
, "error invoking gcc driver: %s", errmsg
);
1771 /* pex_one can return a NULL errmsg when the executable wasn't
1772 found (or doesn't exist), so trap these cases also. */
1773 if (exit_status
|| err
)
1776 "error invoking gcc driver: exit_status: %i err: %i",
1779 "whilst attempting to run a driver named: %s",
1788 /* Top-level hook for playing back a recording context.
1790 This plays back m_recording_ctxt, and, if no errors
1791 occurred builds statement lists for and then postprocesses
1792 every function in the result. */
1798 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
1799 tree array_domain_type
= build_index_type (size_int (200));
1800 m_char_array_type_node
1801 = build_array_type (char_type_node
, array_domain_type
);
1804 = build_pointer_type (build_qualified_type (char_type_node
,
1807 /* Replay the recorded events: */
1808 timevar_push (TV_JIT_REPLAY
);
1810 m_recording_ctxt
->replay_into (this);
1812 /* Clean away the temporary references from recording objects
1813 to playback objects. We have to do this now since the
1814 latter are GC-allocated, but the former don't mark these
1815 refs. Hence we must stop using them before the GC can run. */
1816 m_recording_ctxt
->disassociate_from_playback ();
1818 /* The builtins_manager, if any, is associated with the recording::context
1819 and might be reused for future compiles on other playback::contexts,
1820 but its m_attributes array is not GTY-labeled and hence will become
1821 nonsense if the GC runs. Purge this state. */
1822 builtins_manager
*bm
= get_builtins_manager ();
1824 bm
->finish_playback ();
1826 timevar_pop (TV_JIT_REPLAY
);
1828 if (!errors_occurred ())
1833 /* No GC can happen yet; process the cached source locations. */
1834 handle_locations ();
1836 /* We've now created tree nodes for the stmts in the various blocks
1837 in each function, but we haven't built each function's single stmt
1838 list yet. Do so now. */
1839 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
1840 func
->build_stmt_list ();
1842 /* No GC can have happened yet. */
1844 /* Postprocess the functions. This could trigger GC. */
1845 FOR_EACH_VEC_ELT (m_functions
, i
, func
)
1848 func
->postprocess ();
1853 /* Dump the generated .s file to stderr. */
1857 dump_generated_code ()
1861 FILE *f_in
= fopen (m_path_s_file
, "r");
1865 while ( (sz
= fread (buf
, 1, sizeof (buf
), f_in
)) )
1866 fwrite (buf
, 1, sz
, stderr
);
1871 /* qsort comparator for comparing pairs of playback::source_line *,
1872 ordering them by line number. */
1875 line_comparator (const void *lhs
, const void *rhs
)
1877 const playback::source_line
*line_lhs
= \
1878 *static_cast<const playback::source_line
* const*> (lhs
);
1879 const playback::source_line
*line_rhs
= \
1880 *static_cast<const playback::source_line
* const*> (rhs
);
1881 return line_lhs
->get_line_num () - line_rhs
->get_line_num ();
1884 /* qsort comparator for comparing pairs of playback::location *,
1885 ordering them by column number. */
1888 location_comparator (const void *lhs
, const void *rhs
)
1890 const playback::location
*loc_lhs
= \
1891 *static_cast<const playback::location
* const *> (lhs
);
1892 const playback::location
*loc_rhs
= \
1893 *static_cast<const playback::location
* const *> (rhs
);
1894 return loc_lhs
->get_column_num () - loc_rhs
->get_column_num ();
1897 /* Our API allows locations to be created in arbitrary orders, but the
1898 linemap API requires locations to be created in ascending order
1899 as if we were tokenizing files.
1901 This hook sorts all of the the locations that have been created, and
1902 calls into the linemap API, creating linemap entries in sorted order
1903 for our locations. */
1909 /* Create the source code locations, following the ordering rules
1910 imposed by the linemap API.
1912 line_table is a global. */
1916 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
1918 linemap_add (line_table
, LC_ENTER
, false, file
->get_filename (), 0);
1920 /* Sort lines by ascending line numbers. */
1921 file
->m_source_lines
.qsort (&line_comparator
);
1925 FOR_EACH_VEC_ELT (file
->m_source_lines
, j
, line
)
1930 /* Sort locations in line by ascending column numbers. */
1931 line
->m_locations
.qsort (&location_comparator
);
1933 /* Determine maximum column within this line. */
1934 gcc_assert (line
->m_locations
.length () > 0);
1935 location
*final_column
=
1936 line
->m_locations
[line
->m_locations
.length () - 1];
1937 int max_col
= final_column
->get_column_num ();
1939 linemap_line_start (line_table
, line
->get_line_num (), max_col
);
1940 FOR_EACH_VEC_ELT (line
->m_locations
, k
, loc
)
1943 linemap_position_for_column (line_table
, loc
->get_column_num ());
1947 linemap_add (line_table
, LC_LEAVE
, false, NULL
, 0);
1950 /* line_table should now be populated; every playback::location should
1951 now have an m_srcloc. */
1953 /* Now assign them to tree nodes as appropriate. */
1954 std::pair
<tree
, location
*> *cached_location
;
1956 FOR_EACH_VEC_ELT (m_cached_locations
, i
, cached_location
)
1958 tree t
= cached_location
->first
;
1959 source_location srcloc
= cached_location
->second
->m_srcloc
;
1961 /* This covers expressions: */
1962 if (CAN_HAVE_LOCATION_P (t
))
1963 SET_EXPR_LOCATION (t
, srcloc
);
1964 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t
), TS_DECL_MINIMAL
))
1965 DECL_SOURCE_LOCATION (t
) = srcloc
;
1968 /* Don't know how to set location on this node. */
1973 /* We handle errors on a playback::context by adding them to the
1974 corresponding recording::context. */
1978 add_error (location
*loc
, const char *fmt
, ...)
1982 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
1987 /* We handle errors on a playback::context by adding them to the
1988 corresponding recording::context. */
1992 add_error_va (location
*loc
, const char *fmt
, va_list ap
)
1994 m_recording_ctxt
->add_error_va (loc
? loc
->get_recording_loc () : NULL
,
1998 /* Dealing with the linemap API. */
2000 /* Construct a playback::location for a recording::location, if it
2001 doesn't exist already. */
2003 playback::location
*
2005 new_location (recording::location
*rloc
,
2006 const char *filename
,
2010 /* Get the source_file for filename, creating if necessary. */
2011 source_file
*src_file
= get_source_file (filename
);
2012 /* Likewise for the line within the file. */
2013 source_line
*src_line
= src_file
->get_source_line (line
);
2014 /* Likewise for the column within the line. */
2015 location
*loc
= src_line
->get_location (rloc
, column
);
2019 /* Deferred setting of the location for a given tree, by adding the
2020 (tree, playback::location) pair to a list of deferred associations.
2021 We will actually set the location on the tree later on once
2022 the source_location for the playback::location exists. */
2026 set_tree_location (tree t
, location
*loc
)
2029 m_cached_locations
.safe_push (std::make_pair (t
, loc
));
2033 /* Construct a playback::source_file for the given source
2034 filename, if it doesn't exist already. */
2036 playback::source_file
*
2038 get_source_file (const char *filename
)
2041 For simplicitly, this is currently a linear search.
2042 Replace with a hash if this shows up in the profile. */
2045 tree ident_filename
= get_identifier (filename
);
2047 FOR_EACH_VEC_ELT (m_source_files
, i
, file
)
2048 if (file
->filename_as_tree () == ident_filename
)
2052 file
= new source_file (ident_filename
);
2053 m_source_files
.safe_push (file
);
2057 /* Constructor for gcc::jit::playback::source_file. */
2059 playback::source_file::source_file (tree filename
) :
2061 m_filename (filename
)
2065 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2069 playback::source_file::finalizer ()
2071 m_source_lines
.release ();
2074 /* Construct a playback::source_line for the given line
2075 within this source file, if one doesn't exist already. */
2077 playback::source_line
*
2078 playback::source_file::
2079 get_source_line (int line_num
)
2082 For simplicitly, this is currently a linear search.
2083 Replace with a hash if this shows up in the profile. */
2087 FOR_EACH_VEC_ELT (m_source_lines
, i
, line
)
2088 if (line
->get_line_num () == line_num
)
2092 line
= new source_line (this, line_num
);
2093 m_source_lines
.safe_push (line
);
2097 /* Constructor for gcc::jit::playback::source_line. */
2099 playback::source_line::source_line (source_file
*file
, int line_num
) :
2101 m_source_file (file
),
2102 m_line_num (line_num
)
2106 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2110 playback::source_line::finalizer ()
2112 m_locations
.release ();
2115 /* Construct a playback::location for the given column
2116 within this line of a specific source file, if one doesn't exist
2119 playback::location
*
2120 playback::source_line::
2121 get_location (recording::location
*rloc
, int column_num
)
2126 /* Another linear search that probably should be a hash table. */
2127 FOR_EACH_VEC_ELT (m_locations
, i
, loc
)
2128 if (loc
->get_column_num () == column_num
)
2132 loc
= new location (rloc
, this, column_num
);
2133 m_locations
.safe_push (loc
);
2137 /* Constructor for gcc::jit::playback::location. */
2139 playback::location::location (recording::location
*loc
,
2142 m_srcloc (UNKNOWN_LOCATION
),
2143 m_recording_loc (loc
),
2145 m_column_num(column_num
)
2149 /* The active gcc::jit::playback::context instance. This is a singleton,
2150 guarded by jit_mutex. */
2152 playback::context
*active_playback_ctxt
;
2154 } // namespace gcc::jit