Add emergency dump after an ICE
[official-gcc.git] / gcc / jit / jit-playback.c
blob0fddf04da873a98a0004694e58f141da9b2d68a5
1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2020 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)
10 any later version.
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/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "target.h"
25 #include "tree.h"
26 #include "stringpool.h"
27 #include "cgraph.h"
28 #include "dumpfile.h"
29 #include "toplev.h"
30 #include "tree-cfg.h"
31 #include "convert.h"
32 #include "stor-layout.h"
33 #include "print-tree.h"
34 #include "gimplify.h"
35 #include "gcc-driver-name.h"
36 #include "attribs.h"
37 #include "context.h"
38 #include "fold-const.h"
39 #include "opt-suggestions.h"
40 #include "gcc.h"
41 #include "diagnostic.h"
43 #include <pthread.h>
45 #include "jit-playback.h"
46 #include "jit-result.h"
47 #include "jit-builtins.h"
48 #include "jit-tempdir.h"
50 #ifdef _WIN32
51 #include "jit-w32.h"
52 #endif
54 /* Compare with gcc/c-family/c-common.h: DECL_C_BIT_FIELD,
55 SET_DECL_C_BIT_FIELD.
56 These are redefined here to avoid depending from the C frontend. */
57 #define DECL_JIT_BIT_FIELD(NODE) \
58 (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1)
59 #define SET_DECL_JIT_BIT_FIELD(NODE) \
60 (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1)
62 /* gcc::jit::playback::context::build_cast uses the convert.h API,
63 which in turn requires the frontend to provide a "convert"
64 function, apparently as a fallback.
66 Hence we provide this dummy one, with the requirement that any casts
67 are handled before reaching this. */
68 extern tree convert (tree type, tree expr);
70 tree
71 convert (tree dst_type, tree expr)
73 gcc_assert (gcc::jit::active_playback_ctxt);
74 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
75 fprintf (stderr, "input expression:\n");
76 debug_tree (expr);
77 fprintf (stderr, "requested type:\n");
78 debug_tree (dst_type);
79 return error_mark_node;
82 namespace gcc {
83 namespace jit {
85 /**********************************************************************
86 Playback.
87 **********************************************************************/
89 /* The constructor for gcc::jit::playback::context. */
91 playback::context::context (recording::context *ctxt)
92 : log_user (ctxt->get_logger ()),
93 m_recording_ctxt (ctxt),
94 m_tempdir (NULL),
95 m_const_char_ptr (NULL)
97 JIT_LOG_SCOPE (get_logger ());
98 m_functions.create (0);
99 m_globals.create (0);
100 m_source_files.create (0);
101 m_cached_locations.create (0);
104 /* The destructor for gcc::jit::playback::context. */
106 playback::context::~context ()
108 JIT_LOG_SCOPE (get_logger ());
110 /* Normally the playback::context is responsible for cleaning up the
111 tempdir (including "fake.so" within the filesystem).
113 In the normal case, clean it up now.
115 However m_tempdir can be NULL if the context has handed over
116 responsibility for the tempdir cleanup to the jit::result object, so
117 that the cleanup can be delayed (see PR jit/64206). If that's the
118 case this "delete NULL;" is a no-op. */
119 delete m_tempdir;
121 m_functions.release ();
124 /* A playback::context can reference GC-managed pointers. Mark them
125 ("by hand", rather than by gengtype).
127 This is called on the active playback context (if any) by the
128 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
130 void
131 playback::context::
132 gt_ggc_mx ()
134 int i;
135 function *func;
136 FOR_EACH_VEC_ELT (m_functions, i, func)
138 if (ggc_test_and_set_mark (func))
139 func->gt_ggc_mx ();
143 /* Given an enum gcc_jit_types value, get a "tree" type. */
145 static tree
146 get_tree_node_for_type (enum gcc_jit_types type_)
148 switch (type_)
150 case GCC_JIT_TYPE_VOID:
151 return void_type_node;
153 case GCC_JIT_TYPE_VOID_PTR:
154 return ptr_type_node;
156 case GCC_JIT_TYPE_BOOL:
157 return boolean_type_node;
159 case GCC_JIT_TYPE_CHAR:
160 return char_type_node;
161 case GCC_JIT_TYPE_SIGNED_CHAR:
162 return signed_char_type_node;
163 case GCC_JIT_TYPE_UNSIGNED_CHAR:
164 return unsigned_char_type_node;
166 case GCC_JIT_TYPE_SHORT:
167 return short_integer_type_node;
168 case GCC_JIT_TYPE_UNSIGNED_SHORT:
169 return short_unsigned_type_node;
171 case GCC_JIT_TYPE_CONST_CHAR_PTR:
173 tree const_char = build_qualified_type (char_type_node,
174 TYPE_QUAL_CONST);
175 return build_pointer_type (const_char);
178 case GCC_JIT_TYPE_INT:
179 return integer_type_node;
180 case GCC_JIT_TYPE_UNSIGNED_INT:
181 return unsigned_type_node;
183 case GCC_JIT_TYPE_LONG:
184 return long_integer_type_node;
185 case GCC_JIT_TYPE_UNSIGNED_LONG:
186 return long_unsigned_type_node;
188 case GCC_JIT_TYPE_LONG_LONG:
189 return long_long_integer_type_node;
190 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
191 return long_long_unsigned_type_node;
193 case GCC_JIT_TYPE_FLOAT:
194 return float_type_node;
195 case GCC_JIT_TYPE_DOUBLE:
196 return double_type_node;
197 case GCC_JIT_TYPE_LONG_DOUBLE:
198 return long_double_type_node;
200 case GCC_JIT_TYPE_SIZE_T:
201 return size_type_node;
203 case GCC_JIT_TYPE_FILE_PTR:
204 return fileptr_type_node;
206 case GCC_JIT_TYPE_COMPLEX_FLOAT:
207 return complex_float_type_node;
208 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
209 return complex_double_type_node;
210 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
211 return complex_long_double_type_node;
214 return NULL;
217 /* Construct a playback::type instance (wrapping a tree) for the given
218 enum value. */
220 playback::type *
221 playback::context::
222 get_type (enum gcc_jit_types type_)
224 tree type_node = get_tree_node_for_type (type_);
225 if (type_node == NULL)
227 add_error (NULL, "unrecognized (enum gcc_jit_types) value: %i", type_);
228 return NULL;
231 return new type (type_node);
234 /* Construct a playback::type instance (wrapping a tree) for the given
235 array type. */
237 playback::type *
238 playback::context::
239 new_array_type (playback::location *loc,
240 playback::type *element_type,
241 int num_elements)
243 gcc_assert (element_type);
245 tree t = build_array_type_nelts (element_type->as_tree (),
246 num_elements);
247 layout_type (t);
249 if (loc)
250 set_tree_location (t, loc);
252 return new type (t);
255 /* Construct a playback::field instance (wrapping a tree). */
257 playback::field *
258 playback::context::
259 new_field (location *loc,
260 type *type,
261 const char *name)
263 gcc_assert (type);
264 gcc_assert (name);
266 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
267 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
268 get_identifier (name), type->as_tree ());
270 if (loc)
271 set_tree_location (decl, loc);
273 return new field (decl);
276 /* Construct a playback::bitfield instance (wrapping a tree). */
278 playback::field *
279 playback::context::
280 new_bitfield (location *loc,
281 type *type,
282 int width,
283 const char *name)
285 gcc_assert (type);
286 gcc_assert (name);
287 gcc_assert (width);
289 /* compare with c/c-decl.c:grokfield, grokdeclarator and
290 check_bitfield_type_and_width. */
292 tree tree_type = type->as_tree ();
293 gcc_assert (INTEGRAL_TYPE_P (tree_type));
294 tree tree_width = build_int_cst (integer_type_node, width);
295 if (compare_tree_int (tree_width, TYPE_PRECISION (tree_type)) > 0)
297 add_error (
298 loc,
299 "width of bit-field %s (width: %i) is wider than its type (width: %i)",
300 name, width, TYPE_PRECISION (tree_type));
301 return NULL;
304 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
305 get_identifier (name), type->as_tree ());
306 DECL_NONADDRESSABLE_P (decl) = true;
307 DECL_INITIAL (decl) = tree_width;
308 SET_DECL_JIT_BIT_FIELD (decl);
310 if (loc)
311 set_tree_location (decl, loc);
313 return new field (decl);
316 /* Construct a playback::compound_type instance (wrapping a tree). */
318 playback::compound_type *
319 playback::context::
320 new_compound_type (location *loc,
321 const char *name,
322 bool is_struct) /* else is union */
324 gcc_assert (name);
326 /* Compare with c/c-decl.c: start_struct. */
328 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
329 TYPE_NAME (t) = get_identifier (name);
330 TYPE_SIZE (t) = 0;
332 if (loc)
333 set_tree_location (t, loc);
335 return new compound_type (t);
338 void
339 playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
341 /* Compare with c/c-decl.c: finish_struct. */
342 tree t = as_tree ();
344 tree fieldlist = NULL;
345 for (unsigned i = 0; i < fields->length (); i++)
347 field *f = (*fields)[i];
348 tree x = f->as_tree ();
349 DECL_CONTEXT (x) = t;
350 if (DECL_JIT_BIT_FIELD (x))
352 unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (x));
353 DECL_SIZE (x) = bitsize_int (width);
354 DECL_BIT_FIELD (x) = 1;
356 fieldlist = chainon (x, fieldlist);
358 fieldlist = nreverse (fieldlist);
359 TYPE_FIELDS (t) = fieldlist;
361 layout_type (t);
364 /* Construct a playback::type instance (wrapping a tree) for a function
365 type. */
367 playback::type *
368 playback::context::
369 new_function_type (type *return_type,
370 const auto_vec<type *> *param_types,
371 int is_variadic)
373 int i;
374 type *param_type;
376 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
378 FOR_EACH_VEC_ELT (*param_types, i, param_type)
379 arg_types[i] = param_type->as_tree ();
381 tree fn_type;
382 if (is_variadic)
383 fn_type =
384 build_varargs_function_type_array (return_type->as_tree (),
385 param_types->length (),
386 arg_types);
387 else
388 fn_type = build_function_type_array (return_type->as_tree (),
389 param_types->length (),
390 arg_types);
391 free (arg_types);
393 return new type (fn_type);
396 /* Construct a playback::param instance (wrapping a tree). */
398 playback::param *
399 playback::context::
400 new_param (location *loc,
401 type *type,
402 const char *name)
404 gcc_assert (type);
405 gcc_assert (name);
406 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
407 get_identifier (name), type->as_tree ());
408 if (loc)
409 set_tree_location (inner, loc);
411 return new param (this, inner);
414 /* Construct a playback::function instance. */
416 playback::function *
417 playback::context::
418 new_function (location *loc,
419 enum gcc_jit_function_kind kind,
420 type *return_type,
421 const char *name,
422 const auto_vec<param *> *params,
423 int is_variadic,
424 enum built_in_function builtin_id)
426 int i;
427 param *param;
429 //can return_type be NULL?
430 gcc_assert (name);
432 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
433 FOR_EACH_VEC_ELT (*params, i, param)
434 arg_types[i] = TREE_TYPE (param->as_tree ());
436 tree fn_type;
437 if (is_variadic)
438 fn_type = build_varargs_function_type_array (return_type->as_tree (),
439 params->length (), arg_types);
440 else
441 fn_type = build_function_type_array (return_type->as_tree (),
442 params->length (), arg_types);
443 free (arg_types);
445 /* FIXME: this uses input_location: */
446 tree fndecl = build_fn_decl (name, fn_type);
448 if (loc)
449 set_tree_location (fndecl, loc);
451 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
452 NULL_TREE, return_type->as_tree ());
453 DECL_ARTIFICIAL (resdecl) = 1;
454 DECL_IGNORED_P (resdecl) = 1;
455 DECL_RESULT (fndecl) = resdecl;
457 if (builtin_id)
459 gcc_assert (loc == NULL);
460 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
462 built_in_class fclass = builtins_manager::get_class (builtin_id);
463 set_decl_built_in_function (fndecl, fclass, builtin_id);
464 set_builtin_decl (builtin_id, fndecl,
465 builtins_manager::implicit_p (builtin_id));
467 builtins_manager *bm = get_builtins_manager ();
468 tree attrs = bm->get_attrs_tree (builtin_id);
469 if (attrs)
470 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
471 else
472 decl_attributes (&fndecl, NULL_TREE, 0);
475 if (kind != GCC_JIT_FUNCTION_IMPORTED)
477 tree param_decl_list = NULL;
478 FOR_EACH_VEC_ELT (*params, i, param)
480 param_decl_list = chainon (param->as_tree (), param_decl_list);
483 /* The param list was created in reverse order; fix it: */
484 param_decl_list = nreverse (param_decl_list);
486 tree t;
487 for (t = param_decl_list; t; t = DECL_CHAIN (t))
489 DECL_CONTEXT (t) = fndecl;
490 DECL_ARG_TYPE (t) = TREE_TYPE (t);
493 /* Set it up on DECL_ARGUMENTS */
494 DECL_ARGUMENTS(fndecl) = param_decl_list;
497 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
499 DECL_DECLARED_INLINE_P (fndecl) = 1;
501 /* Add attribute "always_inline": */
502 DECL_ATTRIBUTES (fndecl) =
503 tree_cons (get_identifier ("always_inline"),
504 NULL,
505 DECL_ATTRIBUTES (fndecl));
508 function *func = new function (this, fndecl, kind);
509 m_functions.safe_push (func);
510 return func;
513 /* Construct a playback::lvalue instance (wrapping a tree). */
515 playback::lvalue *
516 playback::context::
517 new_global (location *loc,
518 enum gcc_jit_global_kind kind,
519 type *type,
520 const char *name)
522 gcc_assert (type);
523 gcc_assert (name);
524 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
525 get_identifier (name),
526 type->as_tree ());
527 TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
528 DECL_COMMON (inner) = 1;
529 switch (kind)
531 default:
532 gcc_unreachable ();
534 case GCC_JIT_GLOBAL_EXPORTED:
535 TREE_STATIC (inner) = 1;
536 break;
538 case GCC_JIT_GLOBAL_INTERNAL:
539 TREE_STATIC (inner) = 1;
540 break;
542 case GCC_JIT_GLOBAL_IMPORTED:
543 DECL_EXTERNAL (inner) = 1;
544 break;
547 if (loc)
548 set_tree_location (inner, loc);
550 varpool_node::get_create (inner);
552 varpool_node::finalize_decl (inner);
554 m_globals.safe_push (inner);
556 return new lvalue (this, inner);
559 /* Implementation of the various
560 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
561 methods.
562 Each of these constructs a playback::rvalue instance (wrapping a tree).
564 These specializations are required to be in the same namespace
565 as the template, hence we now have to enter the gcc::jit::playback
566 namespace. */
568 namespace playback
571 /* Specialization of making an rvalue from a const, for host <int>. */
573 template <>
574 rvalue *
575 context::
576 new_rvalue_from_const <int> (type *type,
577 int value)
579 // FIXME: type-checking, or coercion?
580 tree inner_type = type->as_tree ();
581 if (INTEGRAL_TYPE_P (inner_type))
583 tree inner = build_int_cst (inner_type, value);
584 return new rvalue (this, inner);
586 else
588 REAL_VALUE_TYPE real_value;
589 real_from_integer (&real_value, VOIDmode, value, SIGNED);
590 tree inner = build_real (inner_type, real_value);
591 return new rvalue (this, inner);
595 /* Specialization of making an rvalue from a const, for host <long>. */
597 template <>
598 rvalue *
599 context::
600 new_rvalue_from_const <long> (type *type,
601 long value)
603 // FIXME: type-checking, or coercion?
604 tree inner_type = type->as_tree ();
605 if (INTEGRAL_TYPE_P (inner_type))
607 tree inner = build_int_cst (inner_type, value);
608 return new rvalue (this, inner);
610 else
612 REAL_VALUE_TYPE real_value;
613 real_from_integer (&real_value, VOIDmode, value, SIGNED);
614 tree inner = build_real (inner_type, real_value);
615 return new rvalue (this, inner);
619 /* Specialization of making an rvalue from a const, for host <double>. */
621 template <>
622 rvalue *
623 context::
624 new_rvalue_from_const <double> (type *type,
625 double value)
627 // FIXME: type-checking, or coercion?
628 tree inner_type = type->as_tree ();
630 /* We have a "double", we want a REAL_VALUE_TYPE.
632 real.c:real_from_target appears to require the representation to be
633 split into 32-bit values, and then sent as an pair of host long
634 ints. */
635 REAL_VALUE_TYPE real_value;
636 union
638 double as_double;
639 uint32_t as_uint32s[2];
640 } u;
641 u.as_double = value;
642 long int as_long_ints[2];
643 as_long_ints[0] = u.as_uint32s[0];
644 as_long_ints[1] = u.as_uint32s[1];
645 real_from_target (&real_value, as_long_ints, DFmode);
646 tree inner = build_real (inner_type, real_value);
647 return new rvalue (this, inner);
650 /* Specialization of making an rvalue from a const, for host <void *>. */
652 template <>
653 rvalue *
654 context::
655 new_rvalue_from_const <void *> (type *type,
656 void *value)
658 tree inner_type = type->as_tree ();
659 /* FIXME: how to ensure we have a wide enough type? */
660 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
661 return new rvalue (this, inner);
664 /* We're done implementing the specializations of
665 gcc::jit::playback::context::new_rvalue_from_const <T>
666 so we can exit the gcc::jit::playback namespace. */
668 } // namespace playback
670 /* Construct a playback::rvalue instance (wrapping a tree). */
672 playback::rvalue *
673 playback::context::
674 new_string_literal (const char *value)
676 /* Compare with c-family/c-common.c: fix_string_type. */
677 size_t len = strlen (value);
678 tree i_type = build_index_type (size_int (len));
679 tree a_type = build_array_type (char_type_node, i_type);
680 /* build_string len parameter must include NUL terminator when
681 building C strings. */
682 tree t_str = build_string (len + 1, value);
683 TREE_TYPE (t_str) = a_type;
685 /* Convert to (const char*), loosely based on
686 c/c-typeck.c: array_to_pointer_conversion,
687 by taking address of start of string. */
688 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
690 return new rvalue (this, t_addr);
693 /* Construct a playback::rvalue instance (wrapping a tree) for a
694 vector. */
696 playback::rvalue *
697 playback::context::new_rvalue_from_vector (location *,
698 type *type,
699 const auto_vec<rvalue *> &elements)
701 vec<constructor_elt, va_gc> *v;
702 vec_alloc (v, elements.length ());
703 for (unsigned i = 0; i < elements.length (); ++i)
704 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
705 tree t_ctor = build_constructor (type->as_tree (), v);
706 return new rvalue (this, t_ctor);
709 /* Coerce a tree expression into a boolean tree expression. */
711 tree
712 playback::context::
713 as_truth_value (tree expr, location *loc)
715 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
716 tree typed_zero = fold_build1 (CONVERT_EXPR,
717 TREE_TYPE (expr),
718 integer_zero_node);
719 if (loc)
720 set_tree_location (typed_zero, loc);
722 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
723 if (loc)
724 set_tree_location (expr, loc);
726 return expr;
729 /* Construct a playback::rvalue instance (wrapping a tree) for a
730 unary op. */
732 playback::rvalue *
733 playback::context::
734 new_unary_op (location *loc,
735 enum gcc_jit_unary_op op,
736 type *result_type,
737 rvalue *a)
739 // FIXME: type-checking, or coercion?
740 enum tree_code inner_op;
742 gcc_assert (result_type);
743 gcc_assert (a);
745 tree node = a->as_tree ();
746 tree inner_result = NULL;
748 switch (op)
750 default:
751 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
752 return NULL;
754 case GCC_JIT_UNARY_OP_MINUS:
755 inner_op = NEGATE_EXPR;
756 break;
758 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
759 inner_op = BIT_NOT_EXPR;
760 break;
762 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
763 node = as_truth_value (node, loc);
764 inner_result = invert_truthvalue (node);
765 if (loc)
766 set_tree_location (inner_result, loc);
767 return new rvalue (this, inner_result);
769 case GCC_JIT_UNARY_OP_ABS:
770 inner_op = ABS_EXPR;
771 break;
774 inner_result = build1 (inner_op,
775 result_type->as_tree (),
776 node);
777 if (loc)
778 set_tree_location (inner_result, loc);
780 return new rvalue (this, inner_result);
783 /* Construct a playback::rvalue instance (wrapping a tree) for a
784 binary op. */
786 playback::rvalue *
787 playback::context::
788 new_binary_op (location *loc,
789 enum gcc_jit_binary_op op,
790 type *result_type,
791 rvalue *a, rvalue *b)
793 // FIXME: type-checking, or coercion?
794 enum tree_code inner_op;
796 gcc_assert (result_type);
797 gcc_assert (a);
798 gcc_assert (b);
800 tree node_a = a->as_tree ();
801 tree node_b = b->as_tree ();
803 switch (op)
805 default:
806 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
807 return NULL;
809 case GCC_JIT_BINARY_OP_PLUS:
810 inner_op = PLUS_EXPR;
811 break;
813 case GCC_JIT_BINARY_OP_MINUS:
814 inner_op = MINUS_EXPR;
815 break;
817 case GCC_JIT_BINARY_OP_MULT:
818 inner_op = MULT_EXPR;
819 break;
821 case GCC_JIT_BINARY_OP_DIVIDE:
822 if (FLOAT_TYPE_P (result_type->as_tree ()))
823 /* Floating-point division: */
824 inner_op = RDIV_EXPR;
825 else
826 /* Truncating to zero: */
827 inner_op = TRUNC_DIV_EXPR;
828 break;
830 case GCC_JIT_BINARY_OP_MODULO:
831 inner_op = TRUNC_MOD_EXPR;
832 break;
834 case GCC_JIT_BINARY_OP_BITWISE_AND:
835 inner_op = BIT_AND_EXPR;
836 break;
838 case GCC_JIT_BINARY_OP_BITWISE_XOR:
839 inner_op = BIT_XOR_EXPR;
840 break;
842 case GCC_JIT_BINARY_OP_BITWISE_OR:
843 inner_op = BIT_IOR_EXPR;
844 break;
846 case GCC_JIT_BINARY_OP_LOGICAL_AND:
847 node_a = as_truth_value (node_a, loc);
848 node_b = as_truth_value (node_b, loc);
849 inner_op = TRUTH_ANDIF_EXPR;
850 break;
852 case GCC_JIT_BINARY_OP_LOGICAL_OR:
853 node_a = as_truth_value (node_a, loc);
854 node_b = as_truth_value (node_b, loc);
855 inner_op = TRUTH_ORIF_EXPR;
856 break;
858 case GCC_JIT_BINARY_OP_LSHIFT:
859 inner_op = LSHIFT_EXPR;
860 break;
862 case GCC_JIT_BINARY_OP_RSHIFT:
863 inner_op = RSHIFT_EXPR;
864 break;
867 tree inner_expr = build2 (inner_op,
868 result_type->as_tree (),
869 node_a,
870 node_b);
871 if (loc)
872 set_tree_location (inner_expr, loc);
874 return new rvalue (this, inner_expr);
877 /* Construct a playback::rvalue instance (wrapping a tree) for a
878 comparison. */
880 playback::rvalue *
881 playback::context::
882 new_comparison (location *loc,
883 enum gcc_jit_comparison op,
884 rvalue *a, rvalue *b)
886 // FIXME: type-checking, or coercion?
887 enum tree_code inner_op;
889 gcc_assert (a);
890 gcc_assert (b);
892 switch (op)
894 default:
895 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
896 return NULL;
898 case GCC_JIT_COMPARISON_EQ:
899 inner_op = EQ_EXPR;
900 break;
901 case GCC_JIT_COMPARISON_NE:
902 inner_op = NE_EXPR;
903 break;
904 case GCC_JIT_COMPARISON_LT:
905 inner_op = LT_EXPR;
906 break;
907 case GCC_JIT_COMPARISON_LE:
908 inner_op = LE_EXPR;
909 break;
910 case GCC_JIT_COMPARISON_GT:
911 inner_op = GT_EXPR;
912 break;
913 case GCC_JIT_COMPARISON_GE:
914 inner_op = GE_EXPR;
915 break;
918 tree inner_expr = build2 (inner_op,
919 boolean_type_node,
920 a->as_tree (),
921 b->as_tree ());
922 if (loc)
923 set_tree_location (inner_expr, loc);
924 return new rvalue (this, inner_expr);
927 /* Construct a playback::rvalue instance (wrapping a tree) for a
928 function call. */
930 playback::rvalue *
931 playback::context::
932 build_call (location *loc,
933 tree fn_ptr,
934 const auto_vec<rvalue *> *args,
935 bool require_tail_call)
937 vec<tree, va_gc> *tree_args;
938 vec_alloc (tree_args, args->length ());
939 for (unsigned i = 0; i < args->length (); i++)
940 tree_args->quick_push ((*args)[i]->as_tree ());
942 if (loc)
943 set_tree_location (fn_ptr, loc);
945 tree fn = TREE_TYPE (fn_ptr);
946 tree fn_type = TREE_TYPE (fn);
947 tree return_type = TREE_TYPE (fn_type);
949 tree call = build_call_vec (return_type,
950 fn_ptr, tree_args);
952 if (require_tail_call)
953 CALL_EXPR_MUST_TAIL_CALL (call) = 1;
955 return new rvalue (this, call);
957 /* see c-typeck.c: build_function_call
958 which calls build_function_call_vec
960 which does lots of checking, then:
961 result = build_call_array_loc (loc, TREE_TYPE (fntype),
962 function, nargs, argarray);
963 which is in tree.c
964 (see also build_call_vec)
968 /* Construct a playback::rvalue instance (wrapping a tree) for a
969 call to a specific function. */
971 playback::rvalue *
972 playback::context::
973 new_call (location *loc,
974 function *func,
975 const auto_vec<rvalue *> *args,
976 bool require_tail_call)
978 tree fndecl;
980 gcc_assert (func);
982 fndecl = func->as_fndecl ();
984 tree fntype = TREE_TYPE (fndecl);
986 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
988 return build_call (loc, fn, args, require_tail_call);
991 /* Construct a playback::rvalue instance (wrapping a tree) for a
992 call through a function pointer. */
994 playback::rvalue *
995 playback::context::
996 new_call_through_ptr (location *loc,
997 rvalue *fn_ptr,
998 const auto_vec<rvalue *> *args,
999 bool require_tail_call)
1001 gcc_assert (fn_ptr);
1002 tree t_fn_ptr = fn_ptr->as_tree ();
1004 return build_call (loc, t_fn_ptr, args, require_tail_call);
1007 /* Construct a tree for a cast. */
1009 tree
1010 playback::context::build_cast (playback::location *loc,
1011 playback::rvalue *expr,
1012 playback::type *type_)
1014 /* For comparison, see:
1015 - c/c-typeck.c:build_c_cast
1016 - c/c-convert.c: convert
1017 - convert.h
1019 Only some kinds of cast are currently supported here. */
1020 tree t_expr = expr->as_tree ();
1021 tree t_dst_type = type_->as_tree ();
1022 tree t_ret = NULL;
1023 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
1024 if (t_ret)
1025 return t_ret;
1026 enum tree_code dst_code = TREE_CODE (t_dst_type);
1027 switch (dst_code)
1029 case INTEGER_TYPE:
1030 case ENUMERAL_TYPE:
1031 t_ret = convert_to_integer (t_dst_type, t_expr);
1032 goto maybe_fold;
1034 case BOOLEAN_TYPE:
1035 /* Compare with c_objc_common_truthvalue_conversion and
1036 c_common_truthvalue_conversion. */
1037 /* For now, convert to: (t_expr != 0) */
1038 t_ret = build2 (NE_EXPR, t_dst_type,
1039 t_expr,
1040 build_int_cst (TREE_TYPE (t_expr), 0));
1041 goto maybe_fold;
1043 case REAL_TYPE:
1044 t_ret = convert_to_real (t_dst_type, t_expr);
1045 goto maybe_fold;
1047 case POINTER_TYPE:
1048 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
1049 goto maybe_fold;
1051 default:
1052 add_error (loc, "couldn't handle cast during playback");
1053 fprintf (stderr, "input expression:\n");
1054 debug_tree (t_expr);
1055 fprintf (stderr, "requested type:\n");
1056 debug_tree (t_dst_type);
1057 return error_mark_node;
1059 maybe_fold:
1060 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
1061 t_ret = fold (t_ret);
1062 return t_ret;
1066 /* Construct a playback::rvalue instance (wrapping a tree) for a
1067 cast. */
1069 playback::rvalue *
1070 playback::context::
1071 new_cast (playback::location *loc,
1072 playback::rvalue *expr,
1073 playback::type *type_)
1076 tree t_cast = build_cast (loc, expr, type_);
1077 if (loc)
1078 set_tree_location (t_cast, loc);
1079 return new rvalue (this, t_cast);
1082 /* Construct a playback::lvalue instance (wrapping a tree) for an
1083 array access. */
1085 playback::lvalue *
1086 playback::context::
1087 new_array_access (location *loc,
1088 rvalue *ptr,
1089 rvalue *index)
1091 gcc_assert (ptr);
1092 gcc_assert (index);
1094 /* For comparison, see:
1095 c/c-typeck.c: build_array_ref
1096 c-family/c-common.c: pointer_int_sum
1098 tree t_ptr = ptr->as_tree ();
1099 tree t_index = index->as_tree ();
1100 tree t_type_ptr = TREE_TYPE (t_ptr);
1101 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1103 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1105 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1106 NULL_TREE, NULL_TREE);
1107 if (loc)
1108 set_tree_location (t_result, loc);
1109 return new lvalue (this, t_result);
1111 else
1113 /* Convert index to an offset in bytes. */
1114 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1115 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1116 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
1118 /* Locate (ptr + offset). */
1119 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1121 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1122 if (loc)
1124 set_tree_location (t_sizeof, loc);
1125 set_tree_location (t_offset, loc);
1126 set_tree_location (t_address, loc);
1127 set_tree_location (t_indirection, loc);
1130 return new lvalue (this, t_indirection);
1134 /* Construct a tree for a field access. */
1136 tree
1137 playback::context::
1138 new_field_access (location *loc,
1139 tree datum,
1140 field *field)
1142 gcc_assert (datum);
1143 gcc_assert (field);
1145 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1146 build_component_ref. */
1147 tree type = TREE_TYPE (datum);
1148 gcc_assert (type);
1149 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1151 tree t_field = field->as_tree ();
1152 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1153 t_field, NULL_TREE);
1154 if (loc)
1155 set_tree_location (ref, loc);
1156 return ref;
1159 /* Construct a tree for a dereference. */
1161 tree
1162 playback::context::
1163 new_dereference (tree ptr,
1164 location *loc)
1166 gcc_assert (ptr);
1168 tree type = TREE_TYPE (TREE_TYPE(ptr));
1169 tree datum = build1 (INDIRECT_REF, type, ptr);
1170 if (loc)
1171 set_tree_location (datum, loc);
1172 return datum;
1175 /* Construct a playback::type instance (wrapping a tree)
1176 with the given alignment. */
1178 playback::type *
1179 playback::type::
1180 get_aligned (size_t alignment_in_bytes) const
1182 tree t_new_type = build_variant_type_copy (m_inner);
1184 SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT);
1185 TYPE_USER_ALIGN (t_new_type) = 1;
1187 return new type (t_new_type);
1190 /* Construct a playback::type instance (wrapping a tree)
1191 for the given vector type. */
1193 playback::type *
1194 playback::type::
1195 get_vector (size_t num_units) const
1197 tree t_new_type = build_vector_type (m_inner, num_units);
1198 return new type (t_new_type);
1201 /* Construct a playback::lvalue instance (wrapping a tree) for a
1202 field access. */
1204 playback::lvalue *
1205 playback::lvalue::
1206 access_field (location *loc,
1207 field *field)
1209 tree datum = as_tree ();
1210 tree ref = get_context ()->new_field_access (loc, datum, field);
1211 if (!ref)
1212 return NULL;
1213 return new lvalue (get_context (), ref);
1216 /* Construct a playback::rvalue instance (wrapping a tree) for a
1217 field access. */
1219 playback::rvalue *
1220 playback::rvalue::
1221 access_field (location *loc,
1222 field *field)
1224 tree datum = as_tree ();
1225 tree ref = get_context ()->new_field_access (loc, datum, field);
1226 if (!ref)
1227 return NULL;
1228 return new rvalue (get_context (), ref);
1231 /* Construct a playback::lvalue instance (wrapping a tree) for a
1232 dereferenced field access. */
1234 playback::lvalue *
1235 playback::rvalue::
1236 dereference_field (location *loc,
1237 field *field)
1239 tree ptr = as_tree ();
1240 tree datum = get_context ()->new_dereference (ptr, loc);
1241 if (!datum)
1242 return NULL;
1243 tree ref = get_context ()->new_field_access (loc, datum, field);
1244 if (!ref)
1245 return NULL;
1246 return new lvalue (get_context (), ref);
1249 /* Construct a playback::lvalue instance (wrapping a tree) for a
1250 dereference. */
1252 playback::lvalue *
1253 playback::rvalue::
1254 dereference (location *loc)
1256 tree ptr = as_tree ();
1257 tree datum = get_context ()->new_dereference (ptr, loc);
1258 return new lvalue (get_context (), datum);
1261 /* Mark the lvalue saying that we need to be able to take the
1262 address of it; it should not be allocated in a register.
1263 Compare with e.g. c/c-typeck.c: c_mark_addressable really_atomic_lvalue.
1264 Returns false if a failure occurred (an error will already have been
1265 added to the active context for this case). */
1267 bool
1268 playback::lvalue::
1269 mark_addressable (location *loc)
1271 tree x = as_tree ();;
1273 while (1)
1274 switch (TREE_CODE (x))
1276 case COMPONENT_REF:
1277 if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x, 1)))
1279 gcc_assert (gcc::jit::active_playback_ctxt);
1280 gcc::jit::
1281 active_playback_ctxt->add_error (loc,
1282 "cannot take address of "
1283 "bit-field");
1284 return false;
1286 /* fallthrough */
1287 case ADDR_EXPR:
1288 case ARRAY_REF:
1289 case REALPART_EXPR:
1290 case IMAGPART_EXPR:
1291 x = TREE_OPERAND (x, 0);
1292 break;
1294 case COMPOUND_LITERAL_EXPR:
1295 case CONSTRUCTOR:
1296 TREE_ADDRESSABLE (x) = 1;
1297 return true;
1299 case VAR_DECL:
1300 case CONST_DECL:
1301 case PARM_DECL:
1302 case RESULT_DECL:
1303 /* (we don't have a concept of a "register" declaration) */
1304 /* fallthrough */
1305 case FUNCTION_DECL:
1306 TREE_ADDRESSABLE (x) = 1;
1307 /* fallthrough */
1308 default:
1309 return true;
1313 /* Construct a playback::rvalue instance (wrapping a tree) for an
1314 address-lookup. */
1316 playback::rvalue *
1317 playback::lvalue::
1318 get_address (location *loc)
1320 tree t_lvalue = as_tree ();
1321 tree t_thistype = TREE_TYPE (t_lvalue);
1322 tree t_ptrtype = build_pointer_type (t_thistype);
1323 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1324 if (loc)
1325 get_context ()->set_tree_location (ptr, loc);
1326 if (mark_addressable (loc))
1327 return new rvalue (get_context (), ptr);
1328 else
1329 return NULL;
1332 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1333 Provide this finalization hook for calling then they are collected,
1334 which calls the finalizer vfunc. This allows them to call "release"
1335 on any vec<> within them. */
1337 static void
1338 wrapper_finalizer (void *ptr)
1340 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1341 wrapper->finalizer ();
1344 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1345 allocate them using ggc_internal_cleared_alloc. */
1347 void *
1348 playback::wrapper::
1349 operator new (size_t sz)
1351 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1355 /* Constructor for gcc:jit::playback::function. */
1357 playback::function::
1358 function (context *ctxt,
1359 tree fndecl,
1360 enum gcc_jit_function_kind kind)
1361 : m_ctxt(ctxt),
1362 m_inner_fndecl (fndecl),
1363 m_inner_bind_expr (NULL),
1364 m_kind (kind)
1366 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1368 /* Create a BIND_EXPR, and within it, a statement list. */
1369 m_stmt_list = alloc_stmt_list ();
1370 m_stmt_iter = tsi_start (m_stmt_list);
1371 m_inner_block = make_node (BLOCK);
1372 m_inner_bind_expr =
1373 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1375 else
1377 m_inner_block = NULL;
1378 m_stmt_list = NULL;
1382 /* Hand-written GC-marking hook for playback functions. */
1384 void
1385 playback::function::
1386 gt_ggc_mx ()
1388 gt_ggc_m_9tree_node (m_inner_fndecl);
1389 gt_ggc_m_9tree_node (m_inner_bind_expr);
1390 gt_ggc_m_9tree_node (m_stmt_list);
1391 gt_ggc_m_9tree_node (m_inner_block);
1394 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1395 GC-ed. */
1397 void
1398 playback::function::finalizer ()
1400 m_blocks.release ();
1403 /* Get the return type of a playback function, in tree form. */
1405 tree
1406 playback::function::
1407 get_return_type_as_tree () const
1409 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1412 /* Construct a new local within this playback::function. */
1414 playback::lvalue *
1415 playback::function::
1416 new_local (location *loc,
1417 type *type,
1418 const char *name)
1420 gcc_assert (type);
1421 gcc_assert (name);
1422 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1423 get_identifier (name),
1424 type->as_tree ());
1425 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1427 /* Prepend to BIND_EXPR_VARS: */
1428 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1429 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1431 if (loc)
1432 set_tree_location (inner, loc);
1433 return new lvalue (m_ctxt, inner);
1436 /* Construct a new block within this playback::function. */
1438 playback::block *
1439 playback::function::
1440 new_block (const char *name)
1442 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1444 block *result = new playback::block (this, name);
1445 m_blocks.safe_push (result);
1446 return result;
1449 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1450 this playback::function. */
1452 playback::rvalue *
1453 playback::function::get_address (location *loc)
1455 tree t_fndecl = as_fndecl ();
1456 tree t_fntype = TREE_TYPE (t_fndecl);
1457 tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
1458 if (loc)
1459 m_ctxt->set_tree_location (t_fnptr, loc);
1460 return new rvalue (m_ctxt, t_fnptr);
1463 /* Build a statement list for the function as a whole out of the
1464 lists of statements for the individual blocks, building labels
1465 for each block. */
1467 void
1468 playback::function::
1469 build_stmt_list ()
1471 int i;
1472 block *b;
1474 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1476 FOR_EACH_VEC_ELT (m_blocks, i, b)
1478 int j;
1479 tree stmt;
1481 b->m_label_expr = build1 (LABEL_EXPR,
1482 void_type_node,
1483 b->as_label_decl ());
1484 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1486 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1487 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1491 /* Finish compiling the given function, potentially running the
1492 garbage-collector.
1493 The function will have a statement list by now.
1494 Amongst other things, this gimplifies the statement list,
1495 and calls cgraph_node::finalize_function on the function. */
1497 void
1498 playback::function::
1499 postprocess ()
1501 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1503 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1504 debug_tree (m_stmt_list);
1506 /* Do we need this to force cgraphunit.c to output the function? */
1507 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1509 DECL_EXTERNAL (m_inner_fndecl) = 0;
1510 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1513 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1514 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1516 DECL_EXTERNAL (m_inner_fndecl) = 0;
1517 TREE_PUBLIC (m_inner_fndecl) = 0;
1520 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1522 /* Seem to need this in gimple-low.c: */
1523 gcc_assert (m_inner_block);
1524 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1526 /* how to add to function? the following appears to be how to
1527 set the body of a m_inner_fndecl: */
1528 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1530 /* Ensure that locals appear in the debuginfo. */
1531 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1533 //debug_tree (m_inner_fndecl);
1535 /* Convert to gimple: */
1536 //printf("about to gimplify_function_tree\n");
1537 gimplify_function_tree (m_inner_fndecl);
1538 //printf("finished gimplify_function_tree\n");
1540 current_function_decl = m_inner_fndecl;
1541 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1542 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1543 //debug_tree (m_inner_fndecl);
1545 //printf("about to add to cgraph\n");
1546 /* Add to cgraph: */
1547 cgraph_node::finalize_function (m_inner_fndecl, false);
1548 /* This can trigger a collection, so we need to have all of
1549 the funcs as roots. */
1551 current_function_decl = NULL;
1555 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1556 GC-ed. */
1558 void
1559 playback::block::finalizer ()
1561 m_stmts.release ();
1564 /* Add an eval of the rvalue to the function's statement list. */
1566 void
1567 playback::block::
1568 add_eval (location *loc,
1569 rvalue *rvalue)
1571 gcc_assert (rvalue);
1573 if (loc)
1574 set_tree_location (rvalue->as_tree (), loc);
1576 add_stmt (rvalue->as_tree ());
1579 /* Add an assignment to the function's statement list. */
1581 void
1582 playback::block::
1583 add_assignment (location *loc,
1584 lvalue *lvalue,
1585 rvalue *rvalue)
1587 gcc_assert (lvalue);
1588 gcc_assert (rvalue);
1590 tree t_lvalue = lvalue->as_tree ();
1591 tree t_rvalue = rvalue->as_tree ();
1592 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1594 t_rvalue = build1 (CONVERT_EXPR,
1595 TREE_TYPE (t_lvalue),
1596 t_rvalue);
1597 if (loc)
1598 set_tree_location (t_rvalue, loc);
1601 tree stmt =
1602 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1603 t_lvalue, t_rvalue);
1604 if (loc)
1605 set_tree_location (stmt, loc);
1606 add_stmt (stmt);
1609 /* Add a comment to the function's statement list.
1610 For now this is done by adding a dummy label. */
1612 void
1613 playback::block::
1614 add_comment (location *loc,
1615 const char *text)
1617 /* Wrap the text in C-style comment delimiters. */
1618 size_t sz =
1619 (3 /* opening delim */
1620 + strlen (text)
1621 + 3 /* closing delim */
1622 + 1 /* terminator */);
1623 char *wrapped = (char *)ggc_internal_alloc (sz);
1624 snprintf (wrapped, sz, "/* %s */", text);
1626 /* For now we simply implement this by adding a dummy label with a name
1627 containing the given text. */
1628 tree identifier = get_identifier (wrapped);
1629 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1630 identifier, void_type_node);
1631 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1633 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1634 if (loc)
1635 set_tree_location (label_expr, loc);
1636 add_stmt (label_expr);
1639 /* Add a conditional jump statement to the function's statement list. */
1641 void
1642 playback::block::
1643 add_conditional (location *loc,
1644 rvalue *boolval,
1645 block *on_true,
1646 block *on_false)
1648 gcc_assert (boolval);
1649 gcc_assert (on_true);
1650 gcc_assert (on_false);
1652 /* COND_EXPR wants statement lists for the true/false operands, but we
1653 want labels.
1654 Shim it by creating jumps to the labels */
1655 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1656 on_true->as_label_decl ());
1657 if (loc)
1658 set_tree_location (true_jump, loc);
1660 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1661 on_false->as_label_decl ());
1662 if (loc)
1663 set_tree_location (false_jump, loc);
1665 tree stmt =
1666 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1667 true_jump, false_jump);
1668 if (loc)
1669 set_tree_location (stmt, loc);
1670 add_stmt (stmt);
1673 /* Add an unconditional jump statement to the function's statement list. */
1675 void
1676 playback::block::
1677 add_jump (location *loc,
1678 block *target)
1680 gcc_assert (target);
1682 // see c_finish_loop
1683 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1684 //add_stmt (top);
1686 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1687 TREE_USED (target->as_label_decl ()) = 1;
1688 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1689 if (loc)
1690 set_tree_location (stmt, loc);
1691 add_stmt (stmt);
1694 from c-typeck.c:
1695 tree
1696 c_finish_goto_label (location_t loc, tree label)
1698 tree decl = lookup_label_for_goto (loc, label);
1699 if (!decl)
1700 return NULL_TREE;
1701 TREE_USED (decl) = 1;
1703 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1704 SET_EXPR_LOCATION (t, loc);
1705 return add_stmt (t);
1712 /* Add a return statement to the function's statement list. */
1714 void
1715 playback::block::
1716 add_return (location *loc,
1717 rvalue *rvalue)
1719 tree modify_retval = NULL;
1720 tree return_type = m_func->get_return_type_as_tree ();
1721 if (rvalue)
1723 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1724 tree t_rvalue = rvalue->as_tree ();
1725 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1726 t_rvalue = build1 (CONVERT_EXPR,
1727 TREE_TYPE (t_lvalue),
1728 t_rvalue);
1729 modify_retval = build2 (MODIFY_EXPR, return_type,
1730 t_lvalue, t_rvalue);
1731 if (loc)
1732 set_tree_location (modify_retval, loc);
1734 tree return_stmt = build1 (RETURN_EXPR, return_type,
1735 modify_retval);
1736 if (loc)
1737 set_tree_location (return_stmt, loc);
1739 add_stmt (return_stmt);
1742 /* Helper function for playback::block::add_switch.
1743 Construct a case label for the given range, followed by a goto stmt
1744 to the given block, appending them to stmt list *ptr_t_switch_body. */
1746 static void
1747 add_case (tree *ptr_t_switch_body,
1748 tree t_low_value,
1749 tree t_high_value,
1750 playback::block *dest_block)
1752 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
1753 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
1755 tree t_case_label =
1756 build_case_label (t_low_value, t_high_value, t_label);
1757 append_to_statement_list (t_case_label, ptr_t_switch_body);
1759 tree t_goto_stmt =
1760 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
1761 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
1764 /* Add a switch statement to the function's statement list.
1766 We create a switch body, and populate it with case labels, each
1767 followed by a goto to the desired block. */
1769 void
1770 playback::block::
1771 add_switch (location *loc,
1772 rvalue *expr,
1773 block *default_block,
1774 const auto_vec <case_> *cases)
1776 /* Compare with:
1777 - c/c-typeck.c: c_start_case
1778 - c-family/c-common.c:c_add_case_label
1779 - java/expr.c:expand_java_switch and expand_java_add_case
1780 We've already rejected overlaps and duplicates in
1781 libgccjit.c:case_range_validator::validate. */
1783 tree t_expr = expr->as_tree ();
1784 tree t_type = TREE_TYPE (t_expr);
1786 tree t_switch_body = alloc_stmt_list ();
1788 int i;
1789 case_ *c;
1790 FOR_EACH_VEC_ELT (*cases, i, c)
1792 tree t_low_value = c->m_min_value->as_tree ();
1793 tree t_high_value = c->m_max_value->as_tree ();
1794 add_case (&t_switch_body, t_low_value, t_high_value, c->m_dest_block);
1796 /* Default label. */
1797 add_case (&t_switch_body, NULL_TREE, NULL_TREE, default_block);
1799 tree switch_stmt = build2 (SWITCH_EXPR, t_type, t_expr, t_switch_body);
1800 if (loc)
1801 set_tree_location (switch_stmt, loc);
1802 add_stmt (switch_stmt);
1805 /* Constructor for gcc::jit::playback::block. */
1807 playback::block::
1808 block (function *func,
1809 const char *name)
1810 : m_func (func),
1811 m_stmts ()
1813 tree identifier;
1815 gcc_assert (func);
1816 // name can be NULL
1817 if (name)
1818 identifier = get_identifier (name);
1819 else
1820 identifier = NULL;
1821 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1822 identifier, void_type_node);
1823 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1824 m_label_expr = NULL;
1827 /* Compile a playback::context:
1829 - Use the context's options to cconstruct command-line options, and
1830 call into the rest of GCC (toplev::main).
1831 - Assuming it succeeds, we have a .s file.
1832 - We then run the "postprocess" vfunc:
1834 (A) In-memory compile ("gcc_jit_context_compile")
1836 For an in-memory compile we have the playback::compile_to_memory
1837 subclass; "postprocess" will convert the .s file to a .so DSO,
1838 and load it in memory (via dlopen), wrapping the result up as
1839 a jit::result and returning it.
1841 (B) Compile to file ("gcc_jit_context_compile_to_file")
1843 When compiling to a file, we have the playback::compile_to_file
1844 subclass; "postprocess" will either copy the .s file to the
1845 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1846 the driver to convert it as necessary, copying the result. */
1848 void
1849 playback::context::
1850 compile ()
1852 JIT_LOG_SCOPE (get_logger ());
1854 const char *ctxt_progname;
1856 int keep_intermediates =
1857 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
1859 m_tempdir = new tempdir (get_logger (), keep_intermediates);
1860 if (!m_tempdir->create ())
1861 return;
1863 /* Call into the rest of gcc.
1864 For now, we have to assemble command-line options to pass into
1865 toplev::main, so that they can be parsed. */
1867 /* Pass in user-provided program name as argv0, if any, so that it
1868 makes it into GCC's "progname" global, used in various diagnostics. */
1869 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1871 if (!ctxt_progname)
1872 ctxt_progname = "libgccjit.so";
1874 auto_vec <recording::requested_dump> requested_dumps;
1875 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1877 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1878 acquire_mutex ();
1880 auto_string_vec fake_args;
1881 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
1882 if (errors_occurred ())
1884 release_mutex ();
1885 return;
1888 /* This runs the compiler. */
1889 toplev toplev (get_timer (), /* external_timer */
1890 false); /* init_signals */
1891 enter_scope ("toplev::main");
1892 if (get_logger ())
1893 for (unsigned i = 0; i < fake_args.length (); i++)
1894 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
1895 toplev.main (fake_args.length (),
1896 const_cast <char **> (fake_args.address ()));
1897 exit_scope ("toplev::main");
1899 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1900 need to do it between toplev::main (which creates the dump manager)
1901 and toplev::finalize (which deletes it). */
1902 extract_any_requested_dumps (&requested_dumps);
1904 /* Clean up the compiler. */
1905 enter_scope ("toplev::finalize");
1906 toplev.finalize ();
1907 exit_scope ("toplev::finalize");
1909 /* Ideally we would release the jit mutex here, but we can't yet since
1910 followup activities use timevars, which are global state. */
1912 if (errors_occurred ())
1914 release_mutex ();
1915 return;
1918 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1919 dump_generated_code ();
1921 /* We now have a .s file.
1923 Run any postprocessing steps. This will either convert the .s file to
1924 a .so DSO, and load it in memory (playback::compile_to_memory), or
1925 convert the .s file to the requested output format, and copy it to a
1926 given file (playback::compile_to_file). */
1927 postprocess (ctxt_progname);
1929 release_mutex ();
1932 /* Implementation of class gcc::jit::playback::compile_to_memory,
1933 a subclass of gcc::jit::playback::context. */
1935 /* playback::compile_to_memory's trivial constructor. */
1937 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
1938 playback::context (ctxt),
1939 m_result (NULL)
1941 JIT_LOG_SCOPE (get_logger ());
1944 /* Implementation of the playback::context::process vfunc for compiling
1945 to memory.
1947 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1948 wrapping the result up as a jit::result and returning it. */
1950 void
1951 playback::compile_to_memory::postprocess (const char *ctxt_progname)
1953 JIT_LOG_SCOPE (get_logger ());
1954 convert_to_dso (ctxt_progname);
1955 if (errors_occurred ())
1956 return;
1957 m_result = dlopen_built_dso ();
1960 /* Implementation of class gcc::jit::playback::compile_to_file,
1961 a subclass of gcc::jit::playback::context. */
1963 /* playback::compile_to_file's trivial constructor. */
1965 playback::compile_to_file::compile_to_file (recording::context *ctxt,
1966 enum gcc_jit_output_kind output_kind,
1967 const char *output_path) :
1968 playback::context (ctxt),
1969 m_output_kind (output_kind),
1970 m_output_path (output_path)
1972 JIT_LOG_SCOPE (get_logger ());
1975 /* Implementation of the playback::context::process vfunc for compiling
1976 to a file.
1978 Either copy the .s file to the given destination (for
1979 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1980 as necessary, copying the result. */
1982 void
1983 playback::compile_to_file::postprocess (const char *ctxt_progname)
1985 JIT_LOG_SCOPE (get_logger ());
1987 /* The driver takes different actions based on the filename, so
1988 we provide a filename with an appropriate suffix for the
1989 output kind, and then copy it up to the user-provided path,
1990 rather than directly compiling it to the requested output path. */
1992 switch (m_output_kind)
1994 default:
1995 gcc_unreachable ();
1997 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
1998 copy_file (get_tempdir ()->get_path_s_file (),
1999 m_output_path);
2000 /* The .s file is automatically unlinked by tempdir::~tempdir. */
2001 break;
2003 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
2005 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
2006 "/fake.o",
2007 NULL);
2008 invoke_driver (ctxt_progname,
2009 get_tempdir ()->get_path_s_file (),
2010 tmp_o_path,
2011 TV_ASSEMBLE,
2012 false, /* bool shared, */
2013 false);/* bool run_linker */
2014 if (!errors_occurred ())
2016 copy_file (tmp_o_path,
2017 m_output_path);
2018 get_tempdir ()->add_temp_file (tmp_o_path);
2020 else
2021 free (tmp_o_path);
2023 break;
2025 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
2026 invoke_driver (ctxt_progname,
2027 get_tempdir ()->get_path_s_file (),
2028 get_tempdir ()->get_path_so_file (),
2029 TV_ASSEMBLE,
2030 true, /* bool shared, */
2031 true);/* bool run_linker */
2032 if (!errors_occurred ())
2033 copy_file (get_tempdir ()->get_path_so_file (),
2034 m_output_path);
2035 /* The .so file is automatically unlinked by tempdir::~tempdir. */
2036 break;
2038 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
2040 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
2041 "/fake.exe",
2042 NULL);
2043 invoke_driver (ctxt_progname,
2044 get_tempdir ()->get_path_s_file (),
2045 tmp_exe_path,
2046 TV_ASSEMBLE,
2047 false, /* bool shared, */
2048 true);/* bool run_linker */
2049 if (!errors_occurred ())
2051 copy_file (tmp_exe_path,
2052 m_output_path);
2053 get_tempdir ()->add_temp_file (tmp_exe_path);
2055 else
2056 free (tmp_exe_path);
2058 break;
2064 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2065 the "executable" bits).
2067 Any errors that occur are reported on the context and hence count as
2068 a failure of the compile.
2070 We can't in general hardlink or use "rename" from the tempdir since
2071 it might be on a different filesystem to the destination. For example,
2072 I get EXDEV: "Invalid cross-device link". */
2074 void
2075 playback::compile_to_file::copy_file (const char *src_path,
2076 const char *dst_path)
2078 JIT_LOG_SCOPE (get_logger ());
2079 if (get_logger ())
2081 get_logger ()->log ("src_path: %s", src_path);
2082 get_logger ()->log ("dst_path: %s", dst_path);
2085 FILE *f_in = NULL;
2086 FILE *f_out = NULL;
2087 size_t total_sz_in = 0;
2088 size_t total_sz_out = 0;
2089 char buf[4096];
2090 size_t sz_in;
2091 struct stat stat_buf;
2093 f_in = fopen (src_path, "rb");
2094 if (!f_in)
2096 add_error (NULL,
2097 "unable to open %s for reading: %s",
2098 src_path,
2099 xstrerror (errno));
2100 return;
2103 /* Use stat on the filedescriptor to get the mode,
2104 so that we can copy it over (in particular, the
2105 "executable" bits). */
2106 if (fstat (fileno (f_in), &stat_buf) == -1)
2108 add_error (NULL,
2109 "unable to fstat %s: %s",
2110 src_path,
2111 xstrerror (errno));
2112 fclose (f_in);
2113 return;
2116 f_out = fopen (dst_path, "wb");
2117 if (!f_out)
2119 add_error (NULL,
2120 "unable to open %s for writing: %s",
2121 dst_path,
2122 xstrerror (errno));
2123 fclose (f_in);
2124 return;
2127 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2129 total_sz_in += sz_in;
2130 size_t sz_out_remaining = sz_in;
2131 size_t sz_out_so_far = 0;
2132 while (sz_out_remaining)
2134 size_t sz_out = fwrite (buf + sz_out_so_far,
2136 sz_out_remaining,
2137 f_out);
2138 gcc_assert (sz_out <= sz_out_remaining);
2139 if (!sz_out)
2141 add_error (NULL,
2142 "error writing to %s: %s",
2143 dst_path,
2144 xstrerror (errno));
2145 fclose (f_in);
2146 fclose (f_out);
2147 return;
2149 total_sz_out += sz_out;
2150 sz_out_so_far += sz_out;
2151 sz_out_remaining -= sz_out;
2153 gcc_assert (sz_out_so_far == sz_in);
2156 if (!feof (f_in))
2157 add_error (NULL,
2158 "error reading from %s: %s",
2159 src_path,
2160 xstrerror (errno));
2162 fclose (f_in);
2164 gcc_assert (total_sz_in == total_sz_out);
2165 if (get_logger ())
2166 get_logger ()->log ("total bytes copied: %zu", total_sz_out);
2168 /* fchmod does not exist in Windows. */
2169 #ifndef _WIN32
2170 /* Set the permissions of the copy to those of the original file,
2171 in particular the "executable" bits. */
2172 if (fchmod (fileno (f_out), stat_buf.st_mode) == -1)
2173 add_error (NULL,
2174 "error setting mode of %s: %s",
2175 dst_path,
2176 xstrerror (errno));
2177 #endif
2179 fclose (f_out);
2182 /* Helper functions for gcc::jit::playback::context::compile. */
2184 /* This mutex guards gcc::jit::recording::context::compile, so that only
2185 one thread can be accessing the bulk of GCC's state at once. */
2187 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2189 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2191 void
2192 playback::context::acquire_mutex ()
2194 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2196 /* Acquire the big GCC mutex. */
2197 JIT_LOG_SCOPE (get_logger ());
2198 pthread_mutex_lock (&jit_mutex);
2199 gcc_assert (active_playback_ctxt == NULL);
2200 active_playback_ctxt = this;
2203 /* Release jit_mutex and clear the active playback ctxt. */
2205 void
2206 playback::context::release_mutex ()
2208 /* Release the big GCC mutex. */
2209 JIT_LOG_SCOPE (get_logger ());
2210 gcc_assert (active_playback_ctxt == this);
2211 active_playback_ctxt = NULL;
2212 pthread_mutex_unlock (&jit_mutex);
2215 /* Callback used by gcc::jit::playback::context::make_fake_args when
2216 invoking driver_get_configure_time_options.
2217 Populate a vec <char * > with the configure-time options. */
2219 static void
2220 append_arg_from_driver (const char *option, void *user_data)
2222 gcc_assert (option);
2223 gcc_assert (user_data);
2224 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2225 argvec->safe_push (concat ("-", option, NULL));
2228 /* Build a fake argv for toplev::main from the options set
2229 by the user on the context . */
2231 void
2232 playback::context::
2233 make_fake_args (vec <char *> *argvec,
2234 const char *ctxt_progname,
2235 vec <recording::requested_dump> *requested_dumps)
2237 JIT_LOG_SCOPE (get_logger ());
2239 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2240 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2242 ADD_ARG (ctxt_progname);
2243 ADD_ARG (get_path_c_file ());
2244 ADD_ARG ("-fPIC");
2246 /* Handle int options: */
2247 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2249 default:
2250 add_error (NULL,
2251 "unrecognized optimization level: %i",
2252 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2253 return;
2255 case 0:
2256 ADD_ARG ("-O0");
2257 break;
2259 case 1:
2260 ADD_ARG ("-O1");
2261 break;
2263 case 2:
2264 ADD_ARG ("-O2");
2265 break;
2267 case 3:
2268 ADD_ARG ("-O3");
2269 break;
2271 /* What about -Os? */
2273 /* Handle bool options: */
2274 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2275 ADD_ARG ("-g");
2277 /* Suppress timing (and other) info. */
2278 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2280 ADD_ARG ("-quiet");
2281 quiet_flag = 1;
2284 /* Aggressively garbage-collect, to shake out bugs: */
2285 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2287 ADD_ARG ("--param=ggc-min-expand=0");
2288 ADD_ARG ("--param=ggc-min-heapsize=0");
2291 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2293 ADD_ARG ("-fdump-tree-all");
2294 ADD_ARG ("-fdump-rtl-all");
2295 ADD_ARG ("-fdump-ipa-all");
2298 /* Add "-fdump-" options for any calls to
2299 gcc_jit_context_enable_dump. */
2301 int i;
2302 recording::requested_dump *d;
2303 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2305 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2306 ADD_ARG_TAKE_OWNERSHIP (arg);
2310 /* PR jit/64810: Add any target-specific default options
2311 from OPTION_DEFAULT_SPECS, normally provided by the driver
2312 in the non-jit case.
2314 The target-specific code can define OPTION_DEFAULT_SPECS:
2315 default command options in the form of spec macros for the
2316 driver to expand ().
2318 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2319 if not overriden, injects the defaults as extra arguments to
2320 cc1 etc.
2321 For the jit case, we need to add these arguments here. The
2322 input format (using the specs language) means that we have to run
2323 part of the driver code here (driver_get_configure_time_options).
2325 To avoid running the spec-expansion code every time, we just do
2326 it the first time (via a function-static flag), saving the result
2327 into a function-static vec.
2328 This flag and vec are global state (i.e. per-process).
2329 They are guarded by the jit mutex. */
2331 static bool have_configure_time_options = false;
2332 static vec <char *> configure_time_options;
2334 if (have_configure_time_options)
2335 log ("reusing cached configure-time options");
2336 else
2338 have_configure_time_options = true;
2339 log ("getting configure-time options from driver");
2340 driver_get_configure_time_options (append_arg_from_driver,
2341 &configure_time_options);
2344 int i;
2345 char *opt;
2347 if (get_logger ())
2348 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2349 log ("configure_time_options[%i]: %s", i, opt);
2351 /* configure_time_options should now contain the expanded options
2352 from OPTION_DEFAULT_SPECS (if any). */
2353 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2355 gcc_assert (opt);
2356 gcc_assert (opt[0] == '-');
2357 ADD_ARG (opt);
2361 if (get_timer ())
2362 ADD_ARG ("-ftime-report");
2364 /* Add any user-provided extra options, starting with any from
2365 parent contexts. */
2366 m_recording_ctxt->append_command_line_options (argvec);
2368 #undef ADD_ARG
2369 #undef ADD_ARG_TAKE_OWNERSHIP
2372 /* The second half of the implementation of gcc_jit_context_enable_dump.
2373 Iterate through the requested dumps, reading the underlying files
2374 into heap-allocated buffers, writing pointers to the buffers into
2375 the char ** pointers provided by client code.
2376 Client code is responsible for calling free on the results. */
2378 void
2379 playback::context::
2380 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2382 JIT_LOG_SCOPE (get_logger ());
2384 int i;
2385 recording::requested_dump *d;
2386 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2388 dump_file_info *dfi;
2389 char *filename;
2390 char *content;
2392 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2393 if (!dfi)
2395 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2396 continue;
2399 filename = g->get_dumps ()->get_dump_file_name (dfi);
2400 content = read_dump_file (filename);
2401 *(d->m_out_ptr) = content;
2402 m_tempdir->add_temp_file (filename);
2406 /* Helper function for playback::context::extract_any_requested_dumps
2407 (itself for use in implementation of gcc_jit_context_enable_dump).
2409 Attempt to read the complete file at the given path, returning the
2410 bytes found there as a buffer.
2411 The caller is responsible for calling free on the result.
2412 Errors will be reported on the context, and lead to NULL being
2413 returned; an out-of-memory error will terminate the process. */
2415 char *
2416 playback::context::read_dump_file (const char *path)
2418 char *result = NULL;
2419 size_t total_sz = 0;
2420 char buf[4096];
2421 size_t sz;
2422 FILE *f_in;
2424 f_in = fopen (path, "r");
2425 if (!f_in)
2427 add_error (NULL, "unable to open %s for reading", path);
2428 return NULL;
2431 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2433 size_t old_total_sz = total_sz;
2434 total_sz += sz;
2435 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2436 memcpy (result + old_total_sz, buf, sz);
2439 if (!feof (f_in))
2441 add_error (NULL, "error reading from %s", path);
2442 free (result);
2443 fclose (f_in);
2444 return NULL;
2447 fclose (f_in);
2449 if (result)
2451 result[total_sz] = '\0';
2452 return result;
2454 else
2455 return xstrdup ("");
2458 /* Part of playback::context::compile ().
2460 We have a .s file; we want a .so file.
2461 We could reuse parts of gcc/gcc.c to do this.
2462 For now, just use the driver binary from the install, as
2463 named in gcc-driver-name.h
2464 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2466 void
2467 playback::context::
2468 convert_to_dso (const char *ctxt_progname)
2470 JIT_LOG_SCOPE (get_logger ());
2472 invoke_driver (ctxt_progname,
2473 m_tempdir->get_path_s_file (),
2474 m_tempdir->get_path_so_file (),
2475 TV_ASSEMBLE,
2476 true, /* bool shared, */
2477 true);/* bool run_linker */
2480 static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2482 void
2483 playback::context::
2484 invoke_driver (const char *ctxt_progname,
2485 const char *input_file,
2486 const char *output_file,
2487 timevar_id_t tv_id,
2488 bool shared,
2489 bool run_linker)
2491 JIT_LOG_SCOPE (get_logger ());
2493 bool embedded_driver
2494 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
2496 /* Currently this lumps together both assembling and linking into
2497 TV_ASSEMBLE. */
2498 auto_timevar assemble_timevar (get_timer (), tv_id);
2499 auto_string_vec argvec;
2500 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2502 ADD_ARG (gcc_driver_name);
2504 add_multilib_driver_arguments (&argvec);
2506 if (shared)
2507 ADD_ARG ("-shared");
2509 if (!run_linker)
2510 ADD_ARG ("-c");
2512 ADD_ARG (input_file);
2513 ADD_ARG ("-o");
2514 ADD_ARG (output_file);
2516 /* Don't use the linker plugin.
2517 If running with just a "make" and not a "make install", then we'd
2518 run into
2519 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2520 libto_plugin is a .la at build time, with it becoming installed with
2521 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2522 time. */
2523 ADD_ARG ("-fno-use-linker-plugin");
2525 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2526 /* OS X's linker defaults to treating undefined symbols as errors.
2527 If the context has any imported functions or globals they will be
2528 undefined until the .so is dynamically-linked into the process.
2529 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2530 linker. */
2531 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2532 #endif
2534 if (0)
2535 ADD_ARG ("-v");
2537 /* Add any user-provided driver extra options. */
2539 m_recording_ctxt->append_driver_options (&argvec);
2541 #undef ADD_ARG
2543 /* pex_one's error-handling requires pname to be non-NULL. */
2544 gcc_assert (ctxt_progname);
2546 if (get_logger ())
2547 for (unsigned i = 0; i < argvec.length (); i++)
2548 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2550 if (embedded_driver)
2551 invoke_embedded_driver (&argvec);
2552 else
2553 invoke_external_driver (ctxt_progname, &argvec);
2556 void
2557 playback::context::
2558 invoke_embedded_driver (const vec <char *> *argvec)
2560 JIT_LOG_SCOPE (get_logger ());
2561 driver d (true, /* can_finalize */
2562 false); /* debug */
2563 int result = d.main (argvec->length (),
2564 const_cast <char **> (argvec->address ()));
2565 d.finalize ();
2566 if (result)
2567 add_error (NULL, "error invoking gcc driver");
2570 void
2571 playback::context::
2572 invoke_external_driver (const char *ctxt_progname,
2573 vec <char *> *argvec)
2575 JIT_LOG_SCOPE (get_logger ());
2576 const char *errmsg;
2577 int exit_status = 0;
2578 int err = 0;
2580 /* pex argv arrays are NULL-terminated. */
2581 argvec->safe_push (NULL);
2583 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2584 gcc_driver_name,
2585 const_cast <char *const *> (argvec->address ()),
2586 ctxt_progname, /* const char *pname */
2587 NULL, /* const char *outname */
2588 NULL, /* const char *errname */
2589 &exit_status, /* int *status */
2590 &err); /* int *err*/
2591 if (errmsg)
2593 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2594 return;
2597 /* pex_one can return a NULL errmsg when the executable wasn't
2598 found (or doesn't exist), so trap these cases also. */
2599 if (exit_status || err)
2601 add_error (NULL,
2602 "error invoking gcc driver: exit_status: %i err: %i",
2603 exit_status, err);
2604 add_error (NULL,
2605 "whilst attempting to run a driver named: %s",
2606 gcc_driver_name);
2607 add_error (NULL,
2608 "PATH was: %s",
2609 getenv ("PATH"));
2610 return;
2614 /* Extract the target-specific MULTILIB_DEFAULTS to
2615 multilib_defaults_raw for use by
2616 playback::context::add_multilib_driver_arguments (). */
2618 #ifndef MULTILIB_DEFAULTS
2619 #define MULTILIB_DEFAULTS { "" }
2620 #endif
2622 static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
2624 /* Helper function for playback::context::invoke_driver ().
2626 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2627 a driver binary. We need to pass in options to the shared driver
2628 to get the appropriate assembler/linker options for this multilib
2629 peer. */
2631 void
2632 playback::context::
2633 add_multilib_driver_arguments (vec <char *> *argvec)
2635 JIT_LOG_SCOPE (get_logger ());
2637 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2638 prepending each with a "-". */
2639 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
2640 if (multilib_defaults_raw[i][0])
2641 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
2644 /* Dynamically-link the built DSO file into this process, using dlopen.
2645 Wrap it up within a jit::result *, and return that.
2646 Return NULL if any errors occur, reporting them on this context. */
2648 result *
2649 playback::context::
2650 dlopen_built_dso ()
2652 JIT_LOG_SCOPE (get_logger ());
2653 auto_timevar load_timevar (get_timer (), TV_LOAD);
2654 result::handle handle = NULL;
2655 result *result_obj = NULL;
2657 #ifdef _WIN32
2658 /* Clear any existing error. */
2659 SetLastError(0);
2661 handle = LoadLibrary(m_tempdir->get_path_so_file ());
2662 if (GetLastError() != 0) {
2663 print_last_error();
2665 #else
2666 const char *error = NULL;
2667 /* Clear any existing error. */
2668 dlerror ();
2670 handle = dlopen (m_tempdir->get_path_so_file (),
2671 RTLD_NOW | RTLD_LOCAL);
2672 if ((error = dlerror()) != NULL) {
2673 add_error (NULL, "%s", error);
2675 #endif
2677 if (handle)
2679 /* We've successfully dlopened the result; create a
2680 jit::result object to wrap it.
2682 We're done with the tempdir for now, but if the user
2683 has requested debugging, the user's debugger might not
2684 be capable of dealing with the .so file being unlinked
2685 immediately, so keep it around until after the result
2686 is released. We do this by handing over ownership of
2687 the jit::tempdir to the result. See PR jit/64206. */
2688 tempdir *handover_tempdir;
2689 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2691 handover_tempdir = m_tempdir;
2692 m_tempdir = NULL;
2693 /* The tempdir will eventually be cleaned up in the
2694 jit::result's dtor. */
2695 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2696 " handing over tempdir to jit::result");
2698 else
2700 handover_tempdir = NULL;
2701 /* ... and retain ownership of m_tempdir so we clean it
2702 up it the playback::context's dtor. */
2703 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2704 " retaining ownership of tempdir");
2707 result_obj = new result (get_logger (), handle, handover_tempdir);
2709 else
2710 result_obj = NULL;
2712 return result_obj;
2715 /* Top-level hook for playing back a recording context.
2717 This plays back m_recording_ctxt, and, if no errors
2718 occurred builds statement lists for and then postprocesses
2719 every function in the result. */
2721 void
2722 playback::context::
2723 replay ()
2725 JIT_LOG_SCOPE (get_logger ());
2727 m_const_char_ptr
2728 = build_pointer_type (build_qualified_type (char_type_node,
2729 TYPE_QUAL_CONST));
2731 /* Replay the recorded events: */
2732 timevar_push (TV_JIT_REPLAY);
2734 m_recording_ctxt->replay_into (this);
2736 /* Clean away the temporary references from recording objects
2737 to playback objects. We have to do this now since the
2738 latter are GC-allocated, but the former don't mark these
2739 refs. Hence we must stop using them before the GC can run. */
2740 m_recording_ctxt->disassociate_from_playback ();
2742 /* The builtins_manager, if any, is associated with the recording::context
2743 and might be reused for future compiles on other playback::contexts,
2744 but its m_attributes array is not GTY-labeled and hence will become
2745 nonsense if the GC runs. Purge this state. */
2746 builtins_manager *bm = get_builtins_manager ();
2747 if (bm)
2748 bm->finish_playback ();
2750 timevar_pop (TV_JIT_REPLAY);
2752 if (!errors_occurred ())
2754 int i;
2755 function *func;
2757 /* No GC can happen yet; process the cached source locations. */
2758 handle_locations ();
2760 /* We've now created tree nodes for the stmts in the various blocks
2761 in each function, but we haven't built each function's single stmt
2762 list yet. Do so now. */
2763 FOR_EACH_VEC_ELT (m_functions, i, func)
2764 func->build_stmt_list ();
2766 /* No GC can have happened yet. */
2768 /* Postprocess the functions. This could trigger GC. */
2769 FOR_EACH_VEC_ELT (m_functions, i, func)
2771 gcc_assert (func);
2772 func->postprocess ();
2777 /* Dump the generated .s file to stderr. */
2779 void
2780 playback::context::
2781 dump_generated_code ()
2783 JIT_LOG_SCOPE (get_logger ());
2784 char buf[4096];
2785 size_t sz;
2786 FILE *f_in = fopen (get_path_s_file (), "r");
2787 if (!f_in)
2788 return;
2790 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2791 fwrite (buf, 1, sz, stderr);
2793 fclose (f_in);
2796 /* Get the supposed path of the notional "fake.c" file within the
2797 tempdir. This file doesn't exist, but the rest of the compiler
2798 needs a name. */
2800 const char *
2801 playback::context::
2802 get_path_c_file () const
2804 return m_tempdir->get_path_c_file ();
2807 /* Get the path of the assembler output file "fake.s" file within the
2808 tempdir. */
2810 const char *
2811 playback::context::
2812 get_path_s_file () const
2814 return m_tempdir->get_path_s_file ();
2817 /* Get the path of the DSO object file "fake.so" file within the
2818 tempdir. */
2820 const char *
2821 playback::context::
2822 get_path_so_file () const
2824 return m_tempdir->get_path_so_file ();
2827 /* qsort comparator for comparing pairs of playback::source_line *,
2828 ordering them by line number. */
2830 static int
2831 line_comparator (const void *lhs, const void *rhs)
2833 const playback::source_line *line_lhs = \
2834 *static_cast<const playback::source_line * const*> (lhs);
2835 const playback::source_line *line_rhs = \
2836 *static_cast<const playback::source_line * const*> (rhs);
2837 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2840 /* qsort comparator for comparing pairs of playback::location *,
2841 ordering them by column number. */
2843 static int
2844 location_comparator (const void *lhs, const void *rhs)
2846 const playback::location *loc_lhs = \
2847 *static_cast<const playback::location * const *> (lhs);
2848 const playback::location *loc_rhs = \
2849 *static_cast<const playback::location * const *> (rhs);
2850 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2853 /* Our API allows locations to be created in arbitrary orders, but the
2854 linemap API requires locations to be created in ascending order
2855 as if we were tokenizing files.
2857 This hook sorts all of the locations that have been created, and
2858 calls into the linemap API, creating linemap entries in sorted order
2859 for our locations. */
2861 void
2862 playback::context::
2863 handle_locations ()
2865 /* Create the source code locations, following the ordering rules
2866 imposed by the linemap API.
2868 line_table is a global. */
2869 JIT_LOG_SCOPE (get_logger ());
2870 int i;
2871 source_file *file;
2873 FOR_EACH_VEC_ELT (m_source_files, i, file)
2875 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2877 /* Sort lines by ascending line numbers. */
2878 file->m_source_lines.qsort (&line_comparator);
2880 int j;
2881 source_line *line;
2882 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2884 int k;
2885 location *loc;
2887 /* Sort locations in line by ascending column numbers. */
2888 line->m_locations.qsort (&location_comparator);
2890 /* Determine maximum column within this line. */
2891 gcc_assert (line->m_locations.length () > 0);
2892 location *final_column =
2893 line->m_locations[line->m_locations.length () - 1];
2894 int max_col = final_column->get_column_num ();
2896 linemap_line_start (line_table, line->get_line_num (), max_col);
2897 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2899 loc->m_srcloc = \
2900 linemap_position_for_column (line_table, loc->get_column_num ());
2904 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2907 /* line_table should now be populated; every playback::location should
2908 now have an m_srcloc. */
2910 /* Now assign them to tree nodes as appropriate. */
2911 std::pair<tree, location *> *cached_location;
2913 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2915 tree t = cached_location->first;
2916 location_t srcloc = cached_location->second->m_srcloc;
2918 /* This covers expressions: */
2919 if (CAN_HAVE_LOCATION_P (t))
2920 SET_EXPR_LOCATION (t, srcloc);
2921 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2922 DECL_SOURCE_LOCATION (t) = srcloc;
2923 else
2925 /* Don't know how to set location on this node. */
2930 /* We handle errors on a playback::context by adding them to the
2931 corresponding recording::context. */
2933 void
2934 playback::context::
2935 add_error (location *loc, const char *fmt, ...)
2937 va_list ap;
2938 va_start (ap, fmt);
2939 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2940 fmt, ap);
2941 va_end (ap);
2944 /* We handle errors on a playback::context by adding them to the
2945 corresponding recording::context. */
2947 void
2948 playback::context::
2949 add_error_va (location *loc, const char *fmt, va_list ap)
2951 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2952 fmt, ap);
2955 /* Report a diagnostic up to the jit context as an error,
2956 so that the compilation is treated as a failure.
2957 For now, any kind of diagnostic is treated as an error by the jit
2958 API. */
2960 void
2961 playback::context::
2962 add_diagnostic (struct diagnostic_context *diag_context,
2963 struct diagnostic_info *diagnostic)
2965 /* At this point the text has been formatted into the pretty-printer's
2966 output buffer. */
2967 pretty_printer *pp = diag_context->printer;
2968 const char *text = pp_formatted_text (pp);
2970 /* Get location information (if any) from the diagnostic.
2971 The recording::context::add_error[_va] methods require a
2972 recording::location. We can't lookup the playback::location
2973 from the file/line/column since any playback location instances
2974 may have been garbage-collected away by now, so instead we create
2975 another recording::location directly. */
2976 location_t gcc_loc = diagnostic_location (diagnostic);
2977 recording::location *rec_loc = NULL;
2978 if (gcc_loc)
2980 expanded_location exploc = expand_location (gcc_loc);
2981 if (exploc.file)
2982 rec_loc = m_recording_ctxt->new_location (exploc.file,
2983 exploc.line,
2984 exploc.column,
2985 false);
2988 m_recording_ctxt->add_error (rec_loc, "%s", text);
2989 pp_clear_output_area (pp);
2992 /* Dealing with the linemap API. */
2994 /* Construct a playback::location for a recording::location, if it
2995 doesn't exist already. */
2997 playback::location *
2998 playback::context::
2999 new_location (recording::location *rloc,
3000 const char *filename,
3001 int line,
3002 int column)
3004 /* Get the source_file for filename, creating if necessary. */
3005 source_file *src_file = get_source_file (filename);
3006 /* Likewise for the line within the file. */
3007 source_line *src_line = src_file->get_source_line (line);
3008 /* Likewise for the column within the line. */
3009 location *loc = src_line->get_location (rloc, column);
3010 return loc;
3013 /* Deferred setting of the location for a given tree, by adding the
3014 (tree, playback::location) pair to a list of deferred associations.
3015 We will actually set the location on the tree later on once
3016 the location_t for the playback::location exists. */
3018 void
3019 playback::context::
3020 set_tree_location (tree t, location *loc)
3022 gcc_assert (loc);
3023 m_cached_locations.safe_push (std::make_pair (t, loc));
3027 /* Construct a playback::source_file for the given source
3028 filename, if it doesn't exist already. */
3030 playback::source_file *
3031 playback::context::
3032 get_source_file (const char *filename)
3034 /* Locate the file.
3035 For simplicitly, this is currently a linear search.
3036 Replace with a hash if this shows up in the profile. */
3037 int i;
3038 source_file *file;
3039 tree ident_filename = get_identifier (filename);
3041 FOR_EACH_VEC_ELT (m_source_files, i, file)
3042 if (file->filename_as_tree () == ident_filename)
3043 return file;
3045 /* Not found. */
3046 file = new source_file (ident_filename);
3047 m_source_files.safe_push (file);
3048 return file;
3051 /* Constructor for gcc::jit::playback::source_file. */
3053 playback::source_file::source_file (tree filename) :
3054 m_source_lines (),
3055 m_filename (filename)
3059 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3060 GC-ed. */
3062 void
3063 playback::source_file::finalizer ()
3065 m_source_lines.release ();
3068 /* Construct a playback::source_line for the given line
3069 within this source file, if one doesn't exist already. */
3071 playback::source_line *
3072 playback::source_file::
3073 get_source_line (int line_num)
3075 /* Locate the line.
3076 For simplicitly, this is currently a linear search.
3077 Replace with a hash if this shows up in the profile. */
3078 int i;
3079 source_line *line;
3081 FOR_EACH_VEC_ELT (m_source_lines, i, line)
3082 if (line->get_line_num () == line_num)
3083 return line;
3085 /* Not found. */
3086 line = new source_line (this, line_num);
3087 m_source_lines.safe_push (line);
3088 return line;
3091 /* Constructor for gcc::jit::playback::source_line. */
3093 playback::source_line::source_line (source_file *file, int line_num) :
3094 m_locations (),
3095 m_source_file (file),
3096 m_line_num (line_num)
3100 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3101 GC-ed. */
3103 void
3104 playback::source_line::finalizer ()
3106 m_locations.release ();
3109 /* Construct a playback::location for the given column
3110 within this line of a specific source file, if one doesn't exist
3111 already. */
3113 playback::location *
3114 playback::source_line::
3115 get_location (recording::location *rloc, int column_num)
3117 int i;
3118 location *loc;
3120 /* Another linear search that probably should be a hash table. */
3121 FOR_EACH_VEC_ELT (m_locations, i, loc)
3122 if (loc->get_column_num () == column_num)
3123 return loc;
3125 /* Not found. */
3126 loc = new location (rloc, this, column_num);
3127 m_locations.safe_push (loc);
3128 return loc;
3131 /* Constructor for gcc::jit::playback::location. */
3133 playback::location::location (recording::location *loc,
3134 source_line *line,
3135 int column_num) :
3136 m_srcloc (UNKNOWN_LOCATION),
3137 m_recording_loc (loc),
3138 m_line (line),
3139 m_column_num(column_num)
3143 /* The active gcc::jit::playback::context instance. This is a singleton,
3144 guarded by jit_mutex. */
3146 playback::context *active_playback_ctxt;
3148 } // namespace gcc::jit
3150 } // namespace gcc