PR target/66563
[official-gcc.git] / gcc / jit / jit-playback.c
blob14ed277402fcbfa27a383c67e5c21ae383d596da
1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2015 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
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 "opts.h"
25 #include "hashtab.h"
26 #include "statistics.h"
27 #include "vec.h"
28 #include "alias.h"
29 #include "flags.h"
30 #include "symtab.h"
31 #include "tree-core.h"
32 #include "inchash.h"
33 #include "tree.h"
34 #include "hash-map.h"
35 #include "plugin-api.h"
36 #include "vec.h"
37 #include "hashtab.h"
38 #include "tm.h"
39 #include "hard-reg-set.h"
40 #include "function.h"
41 #include "ipa-ref.h"
42 #include "dumpfile.h"
43 #include "cgraph.h"
44 #include "toplev.h"
45 #include "timevar.h"
46 #include "tree-cfg.h"
47 #include "target.h"
48 #include "convert.h"
49 #include "stringpool.h"
50 #include "stor-layout.h"
51 #include "print-tree.h"
52 #include "gimplify.h"
53 #include "gcc-driver-name.h"
54 #include "attribs.h"
55 #include "context.h"
56 #include "fold-const.h"
57 #include "debug.h"
58 #include "gcc.h"
60 #include "jit-common.h"
61 #include "jit-logging.h"
62 #include "jit-playback.h"
63 #include "jit-result.h"
64 #include "jit-builtins.h"
65 #include "jit-tempdir.h"
68 /* gcc::jit::playback::context::build_cast uses the convert.h API,
69 which in turn requires the frontend to provide a "convert"
70 function, apparently as a fallback.
72 Hence we provide this dummy one, with the requirement that any casts
73 are handled before reaching this. */
74 extern tree convert (tree type, tree expr);
76 tree
77 convert (tree dst_type, tree expr)
79 gcc_assert (gcc::jit::active_playback_ctxt);
80 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
81 fprintf (stderr, "input expression:\n");
82 debug_tree (expr);
83 fprintf (stderr, "requested type:\n");
84 debug_tree (dst_type);
85 return error_mark_node;
88 namespace gcc {
89 namespace jit {
91 /**********************************************************************
92 Playback.
93 **********************************************************************/
95 /* The constructor for gcc::jit::playback::context. */
97 playback::context::context (recording::context *ctxt)
98 : log_user (ctxt->get_logger ()),
99 m_recording_ctxt (ctxt),
100 m_tempdir (NULL),
101 m_char_array_type_node (NULL),
102 m_const_char_ptr (NULL)
104 JIT_LOG_SCOPE (get_logger ());
105 m_functions.create (0);
106 m_globals.create (0);
107 m_source_files.create (0);
108 m_cached_locations.create (0);
111 /* The destructor for gcc::jit::playback::context. */
113 playback::context::~context ()
115 JIT_LOG_SCOPE (get_logger ());
117 /* Normally the playback::context is responsible for cleaning up the
118 tempdir (including "fake.so" within the filesystem).
120 In the normal case, clean it up now.
122 However m_tempdir can be NULL if the context has handed over
123 responsibility for the tempdir cleanup to the jit::result object, so
124 that the cleanup can be delayed (see PR jit/64206). If that's the
125 case this "delete NULL;" is a no-op. */
126 delete m_tempdir;
128 m_functions.release ();
131 /* A playback::context can reference GC-managed pointers. Mark them
132 ("by hand", rather than by gengtype).
134 This is called on the active playback context (if any) by the
135 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
137 void
138 playback::context::
139 gt_ggc_mx ()
141 int i;
142 function *func;
143 FOR_EACH_VEC_ELT (m_functions, i, func)
145 if (ggc_test_and_set_mark (func))
146 func->gt_ggc_mx ();
150 /* Given an enum gcc_jit_types value, get a "tree" type. */
152 static tree
153 get_tree_node_for_type (enum gcc_jit_types type_)
155 switch (type_)
157 case GCC_JIT_TYPE_VOID:
158 return void_type_node;
160 case GCC_JIT_TYPE_VOID_PTR:
161 return ptr_type_node;
163 case GCC_JIT_TYPE_BOOL:
164 return boolean_type_node;
166 case GCC_JIT_TYPE_CHAR:
167 return char_type_node;
168 case GCC_JIT_TYPE_SIGNED_CHAR:
169 return signed_char_type_node;
170 case GCC_JIT_TYPE_UNSIGNED_CHAR:
171 return unsigned_char_type_node;
173 case GCC_JIT_TYPE_SHORT:
174 return short_integer_type_node;
175 case GCC_JIT_TYPE_UNSIGNED_SHORT:
176 return short_unsigned_type_node;
178 case GCC_JIT_TYPE_CONST_CHAR_PTR:
180 tree const_char = build_qualified_type (char_type_node,
181 TYPE_QUAL_CONST);
182 return build_pointer_type (const_char);
185 case GCC_JIT_TYPE_INT:
186 return integer_type_node;
187 case GCC_JIT_TYPE_UNSIGNED_INT:
188 return unsigned_type_node;
190 case GCC_JIT_TYPE_LONG:
191 return long_integer_type_node;
192 case GCC_JIT_TYPE_UNSIGNED_LONG:
193 return long_unsigned_type_node;
195 case GCC_JIT_TYPE_LONG_LONG:
196 return long_long_integer_type_node;
197 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
198 return long_long_unsigned_type_node;
200 case GCC_JIT_TYPE_FLOAT:
201 return float_type_node;
202 case GCC_JIT_TYPE_DOUBLE:
203 return double_type_node;
204 case GCC_JIT_TYPE_LONG_DOUBLE:
205 return long_double_type_node;
207 case GCC_JIT_TYPE_SIZE_T:
208 return size_type_node;
210 case GCC_JIT_TYPE_FILE_PTR:
211 return fileptr_type_node;
213 case GCC_JIT_TYPE_COMPLEX_FLOAT:
214 return complex_float_type_node;
215 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
216 return complex_double_type_node;
217 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
218 return complex_long_double_type_node;
221 return NULL;
224 /* Construct a playback::type instance (wrapping a tree) for the given
225 enum value. */
227 playback::type *
228 playback::context::
229 get_type (enum gcc_jit_types type_)
231 tree type_node = get_tree_node_for_type (type_);
232 if (NULL == type_node)
234 add_error (NULL,
235 "unrecognized (enum gcc_jit_types) value: %i", type_);
236 return NULL;
239 return new type (type_node);
242 /* Construct a playback::type instance (wrapping a tree) for the given
243 array type. */
245 playback::type *
246 playback::context::
247 new_array_type (playback::location *loc,
248 playback::type *element_type,
249 int num_elements)
251 gcc_assert (element_type);
253 tree t = build_array_type_nelts (element_type->as_tree (),
254 num_elements);
255 layout_type (t);
257 if (loc)
258 set_tree_location (t, loc);
260 return new type (t);
263 /* Construct a playback::field instance (wrapping a tree). */
265 playback::field *
266 playback::context::
267 new_field (location *loc,
268 type *type,
269 const char *name)
271 gcc_assert (type);
272 gcc_assert (name);
274 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
275 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
276 get_identifier (name), type->as_tree ());
278 if (loc)
279 set_tree_location (decl, loc);
281 return new field (decl);
284 /* Construct a playback::compound_type instance (wrapping a tree). */
286 playback::compound_type *
287 playback::context::
288 new_compound_type (location *loc,
289 const char *name,
290 bool is_struct) /* else is union */
292 gcc_assert (name);
294 /* Compare with c/c-decl.c: start_struct. */
296 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
297 TYPE_NAME (t) = get_identifier (name);
298 TYPE_SIZE (t) = 0;
300 if (loc)
301 set_tree_location (t, loc);
303 return new compound_type (t);
306 void
307 playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
309 /* Compare with c/c-decl.c: finish_struct. */
310 tree t = as_tree ();
312 tree fieldlist = NULL;
313 for (unsigned i = 0; i < fields->length (); i++)
315 field *f = (*fields)[i];
316 DECL_CONTEXT (f->as_tree ()) = t;
317 fieldlist = chainon (f->as_tree (), fieldlist);
319 fieldlist = nreverse (fieldlist);
320 TYPE_FIELDS (t) = fieldlist;
322 layout_type (t);
325 /* Construct a playback::type instance (wrapping a tree) for a function
326 type. */
328 playback::type *
329 playback::context::
330 new_function_type (type *return_type,
331 const auto_vec<type *> *param_types,
332 int is_variadic)
334 int i;
335 type *param_type;
337 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
339 FOR_EACH_VEC_ELT (*param_types, i, param_type)
340 arg_types[i] = param_type->as_tree ();
342 tree fn_type;
343 if (is_variadic)
344 fn_type =
345 build_varargs_function_type_array (return_type->as_tree (),
346 param_types->length (),
347 arg_types);
348 else
349 fn_type = build_function_type_array (return_type->as_tree (),
350 param_types->length (),
351 arg_types);
352 free (arg_types);
354 return new type (fn_type);
357 /* Construct a playback::param instance (wrapping a tree). */
359 playback::param *
360 playback::context::
361 new_param (location *loc,
362 type *type,
363 const char *name)
365 gcc_assert (type);
366 gcc_assert (name);
367 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
368 get_identifier (name), type->as_tree ());
369 if (loc)
370 set_tree_location (inner, loc);
372 return new param (this, inner);
375 /* Construct a playback::function instance. */
377 playback::function *
378 playback::context::
379 new_function (location *loc,
380 enum gcc_jit_function_kind kind,
381 type *return_type,
382 const char *name,
383 const auto_vec<param *> *params,
384 int is_variadic,
385 enum built_in_function builtin_id)
387 int i;
388 param *param;
390 //can return_type be NULL?
391 gcc_assert (name);
393 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
394 FOR_EACH_VEC_ELT (*params, i, param)
395 arg_types[i] = TREE_TYPE (param->as_tree ());
397 tree fn_type;
398 if (is_variadic)
399 fn_type = build_varargs_function_type_array (return_type->as_tree (),
400 params->length (), arg_types);
401 else
402 fn_type = build_function_type_array (return_type->as_tree (),
403 params->length (), arg_types);
404 free (arg_types);
406 /* FIXME: this uses input_location: */
407 tree fndecl = build_fn_decl (name, fn_type);
409 if (loc)
410 set_tree_location (fndecl, loc);
412 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
413 NULL_TREE, return_type->as_tree ());
414 DECL_ARTIFICIAL (resdecl) = 1;
415 DECL_IGNORED_P (resdecl) = 1;
416 DECL_RESULT (fndecl) = resdecl;
418 if (builtin_id)
420 DECL_FUNCTION_CODE (fndecl) = builtin_id;
421 gcc_assert (loc == NULL);
422 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
424 DECL_BUILT_IN_CLASS (fndecl) =
425 builtins_manager::get_class (builtin_id);
426 set_builtin_decl (builtin_id, fndecl,
427 builtins_manager::implicit_p (builtin_id));
429 builtins_manager *bm = get_builtins_manager ();
430 tree attrs = bm->get_attrs_tree (builtin_id);
431 if (attrs)
432 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
433 else
434 decl_attributes (&fndecl, NULL_TREE, 0);
437 if (kind != GCC_JIT_FUNCTION_IMPORTED)
439 tree param_decl_list = NULL;
440 FOR_EACH_VEC_ELT (*params, i, param)
442 param_decl_list = chainon (param->as_tree (), param_decl_list);
445 /* The param list was created in reverse order; fix it: */
446 param_decl_list = nreverse (param_decl_list);
448 tree t;
449 for (t = param_decl_list; t; t = DECL_CHAIN (t))
451 DECL_CONTEXT (t) = fndecl;
452 DECL_ARG_TYPE (t) = TREE_TYPE (t);
455 /* Set it up on DECL_ARGUMENTS */
456 DECL_ARGUMENTS(fndecl) = param_decl_list;
459 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
461 DECL_DECLARED_INLINE_P (fndecl) = 1;
463 /* Add attribute "always_inline": */
464 DECL_ATTRIBUTES (fndecl) =
465 tree_cons (get_identifier ("always_inline"),
466 NULL,
467 DECL_ATTRIBUTES (fndecl));
470 function *func = new function (this, fndecl, kind);
471 m_functions.safe_push (func);
472 return func;
475 /* Construct a playback::lvalue instance (wrapping a tree). */
477 playback::lvalue *
478 playback::context::
479 new_global (location *loc,
480 enum gcc_jit_global_kind kind,
481 type *type,
482 const char *name)
484 gcc_assert (type);
485 gcc_assert (name);
486 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
487 get_identifier (name),
488 type->as_tree ());
489 TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
490 DECL_COMMON (inner) = 1;
491 switch (kind)
493 default:
494 gcc_unreachable ();
496 case GCC_JIT_GLOBAL_EXPORTED:
497 TREE_STATIC (inner) = 1;
498 break;
500 case GCC_JIT_GLOBAL_INTERNAL:
501 TREE_STATIC (inner) = 1;
502 break;
504 case GCC_JIT_GLOBAL_IMPORTED:
505 DECL_EXTERNAL (inner) = 1;
506 break;
509 if (loc)
510 set_tree_location (inner, loc);
512 varpool_node::get_create (inner);
514 varpool_node::finalize_decl (inner);
516 m_globals.safe_push (inner);
518 return new lvalue (this, inner);
521 /* Implementation of the various
522 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
523 methods.
524 Each of these constructs a playback::rvalue instance (wrapping a tree).
526 These specializations are required to be in the same namespace
527 as the template, hence we now have to enter the gcc::jit::playback
528 namespace. */
530 namespace playback
533 /* Specialization of making an rvalue from a const, for host <int>. */
535 template <>
536 rvalue *
537 context::
538 new_rvalue_from_const <int> (type *type,
539 int value)
541 // FIXME: type-checking, or coercion?
542 tree inner_type = type->as_tree ();
543 if (INTEGRAL_TYPE_P (inner_type))
545 tree inner = build_int_cst (inner_type, value);
546 return new rvalue (this, inner);
548 else
550 REAL_VALUE_TYPE real_value;
551 real_from_integer (&real_value, VOIDmode, value, SIGNED);
552 tree inner = build_real (inner_type, real_value);
553 return new rvalue (this, inner);
557 /* Specialization of making an rvalue from a const, for host <long>. */
559 template <>
560 rvalue *
561 context::
562 new_rvalue_from_const <long> (type *type,
563 long value)
565 // FIXME: type-checking, or coercion?
566 tree inner_type = type->as_tree ();
567 if (INTEGRAL_TYPE_P (inner_type))
569 tree inner = build_int_cst (inner_type, value);
570 return new rvalue (this, inner);
572 else
574 REAL_VALUE_TYPE real_value;
575 real_from_integer (&real_value, VOIDmode, value, SIGNED);
576 tree inner = build_real (inner_type, real_value);
577 return new rvalue (this, inner);
581 /* Specialization of making an rvalue from a const, for host <double>. */
583 template <>
584 rvalue *
585 context::
586 new_rvalue_from_const <double> (type *type,
587 double value)
589 // FIXME: type-checking, or coercion?
590 tree inner_type = type->as_tree ();
592 /* We have a "double", we want a REAL_VALUE_TYPE.
594 real.c:real_from_target appears to require the representation to be
595 split into 32-bit values, and then sent as an pair of host long
596 ints. */
597 REAL_VALUE_TYPE real_value;
598 union
600 double as_double;
601 uint32_t as_uint32s[2];
602 } u;
603 u.as_double = value;
604 long int as_long_ints[2];
605 as_long_ints[0] = u.as_uint32s[0];
606 as_long_ints[1] = u.as_uint32s[1];
607 real_from_target (&real_value, as_long_ints, DFmode);
608 tree inner = build_real (inner_type, real_value);
609 return new rvalue (this, inner);
612 /* Specialization of making an rvalue from a const, for host <void *>. */
614 template <>
615 rvalue *
616 context::
617 new_rvalue_from_const <void *> (type *type,
618 void *value)
620 tree inner_type = type->as_tree ();
621 /* FIXME: how to ensure we have a wide enough type? */
622 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
623 return new rvalue (this, inner);
626 /* We're done implementing the specializations of
627 gcc::jit::playback::context::new_rvalue_from_const <T>
628 so we can exit the gcc::jit::playback namespace. */
630 } // namespace playback
632 /* Construct a playback::rvalue instance (wrapping a tree). */
634 playback::rvalue *
635 playback::context::
636 new_string_literal (const char *value)
638 tree t_str = build_string (strlen (value), value);
639 gcc_assert (m_char_array_type_node);
640 TREE_TYPE (t_str) = m_char_array_type_node;
642 /* Convert to (const char*), loosely based on
643 c/c-typeck.c: array_to_pointer_conversion,
644 by taking address of start of string. */
645 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
647 return new rvalue (this, t_addr);
650 /* Coerce a tree expression into a boolean tree expression. */
652 tree
653 playback::context::
654 as_truth_value (tree expr, location *loc)
656 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
657 tree typed_zero = fold_build1 (CONVERT_EXPR,
658 TREE_TYPE (expr),
659 integer_zero_node);
660 if (loc)
661 set_tree_location (typed_zero, loc);
663 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
664 if (loc)
665 set_tree_location (expr, loc);
667 return expr;
670 /* Construct a playback::rvalue instance (wrapping a tree) for a
671 unary op. */
673 playback::rvalue *
674 playback::context::
675 new_unary_op (location *loc,
676 enum gcc_jit_unary_op op,
677 type *result_type,
678 rvalue *a)
680 // FIXME: type-checking, or coercion?
681 enum tree_code inner_op;
683 gcc_assert (result_type);
684 gcc_assert (a);
686 tree node = a->as_tree ();
687 tree inner_result = NULL;
689 switch (op)
691 default:
692 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
693 return NULL;
695 case GCC_JIT_UNARY_OP_MINUS:
696 inner_op = NEGATE_EXPR;
697 break;
699 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
700 inner_op = BIT_NOT_EXPR;
701 break;
703 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
704 node = as_truth_value (node, loc);
705 inner_result = invert_truthvalue (node);
706 if (loc)
707 set_tree_location (inner_result, loc);
708 return new rvalue (this, inner_result);
710 case GCC_JIT_UNARY_OP_ABS:
711 inner_op = ABS_EXPR;
712 break;
715 inner_result = build1 (inner_op,
716 result_type->as_tree (),
717 node);
718 if (loc)
719 set_tree_location (inner_result, loc);
721 return new rvalue (this, inner_result);
724 /* Construct a playback::rvalue instance (wrapping a tree) for a
725 binary op. */
727 playback::rvalue *
728 playback::context::
729 new_binary_op (location *loc,
730 enum gcc_jit_binary_op op,
731 type *result_type,
732 rvalue *a, rvalue *b)
734 // FIXME: type-checking, or coercion?
735 enum tree_code inner_op;
737 gcc_assert (result_type);
738 gcc_assert (a);
739 gcc_assert (b);
741 tree node_a = a->as_tree ();
742 tree node_b = b->as_tree ();
744 switch (op)
746 default:
747 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
748 return NULL;
750 case GCC_JIT_BINARY_OP_PLUS:
751 inner_op = PLUS_EXPR;
752 break;
754 case GCC_JIT_BINARY_OP_MINUS:
755 inner_op = MINUS_EXPR;
756 break;
758 case GCC_JIT_BINARY_OP_MULT:
759 inner_op = MULT_EXPR;
760 break;
762 case GCC_JIT_BINARY_OP_DIVIDE:
763 if (FLOAT_TYPE_P (result_type->as_tree ()))
764 /* Floating-point division: */
765 inner_op = RDIV_EXPR;
766 else
767 /* Truncating to zero: */
768 inner_op = TRUNC_DIV_EXPR;
769 break;
771 case GCC_JIT_BINARY_OP_MODULO:
772 inner_op = TRUNC_MOD_EXPR;
773 break;
775 case GCC_JIT_BINARY_OP_BITWISE_AND:
776 inner_op = BIT_AND_EXPR;
777 break;
779 case GCC_JIT_BINARY_OP_BITWISE_XOR:
780 inner_op = BIT_XOR_EXPR;
781 break;
783 case GCC_JIT_BINARY_OP_BITWISE_OR:
784 inner_op = BIT_IOR_EXPR;
785 break;
787 case GCC_JIT_BINARY_OP_LOGICAL_AND:
788 node_a = as_truth_value (node_a, loc);
789 node_b = as_truth_value (node_b, loc);
790 inner_op = TRUTH_ANDIF_EXPR;
791 break;
793 case GCC_JIT_BINARY_OP_LOGICAL_OR:
794 node_a = as_truth_value (node_a, loc);
795 node_b = as_truth_value (node_b, loc);
796 inner_op = TRUTH_ORIF_EXPR;
797 break;
799 case GCC_JIT_BINARY_OP_LSHIFT:
800 inner_op = LSHIFT_EXPR;
801 break;
803 case GCC_JIT_BINARY_OP_RSHIFT:
804 inner_op = RSHIFT_EXPR;
805 break;
808 tree inner_expr = build2 (inner_op,
809 result_type->as_tree (),
810 node_a,
811 node_b);
812 if (loc)
813 set_tree_location (inner_expr, loc);
815 return new rvalue (this, inner_expr);
818 /* Construct a playback::rvalue instance (wrapping a tree) for a
819 comparison. */
821 playback::rvalue *
822 playback::context::
823 new_comparison (location *loc,
824 enum gcc_jit_comparison op,
825 rvalue *a, rvalue *b)
827 // FIXME: type-checking, or coercion?
828 enum tree_code inner_op;
830 gcc_assert (a);
831 gcc_assert (b);
833 switch (op)
835 default:
836 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
837 return NULL;
839 case GCC_JIT_COMPARISON_EQ:
840 inner_op = EQ_EXPR;
841 break;
842 case GCC_JIT_COMPARISON_NE:
843 inner_op = NE_EXPR;
844 break;
845 case GCC_JIT_COMPARISON_LT:
846 inner_op = LT_EXPR;
847 break;
848 case GCC_JIT_COMPARISON_LE:
849 inner_op = LE_EXPR;
850 break;
851 case GCC_JIT_COMPARISON_GT:
852 inner_op = GT_EXPR;
853 break;
854 case GCC_JIT_COMPARISON_GE:
855 inner_op = GE_EXPR;
856 break;
859 tree inner_expr = build2 (inner_op,
860 boolean_type_node,
861 a->as_tree (),
862 b->as_tree ());
863 if (loc)
864 set_tree_location (inner_expr, loc);
865 return new rvalue (this, inner_expr);
868 /* Construct a playback::rvalue instance (wrapping a tree) for a
869 function call. */
871 playback::rvalue *
872 playback::context::
873 build_call (location *loc,
874 tree fn_ptr,
875 const auto_vec<rvalue *> *args)
877 vec<tree, va_gc> *tree_args;
878 vec_alloc (tree_args, args->length ());
879 for (unsigned i = 0; i < args->length (); i++)
880 tree_args->quick_push ((*args)[i]->as_tree ());
882 if (loc)
883 set_tree_location (fn_ptr, loc);
885 tree fn = TREE_TYPE (fn_ptr);
886 tree fn_type = TREE_TYPE (fn);
887 tree return_type = TREE_TYPE (fn_type);
889 return new rvalue (this,
890 build_call_vec (return_type,
891 fn_ptr, tree_args));
893 /* see c-typeck.c: build_function_call
894 which calls build_function_call_vec
896 which does lots of checking, then:
897 result = build_call_array_loc (loc, TREE_TYPE (fntype),
898 function, nargs, argarray);
899 which is in tree.c
900 (see also build_call_vec)
904 /* Construct a playback::rvalue instance (wrapping a tree) for a
905 call to a specific function. */
907 playback::rvalue *
908 playback::context::
909 new_call (location *loc,
910 function *func,
911 const auto_vec<rvalue *> *args)
913 tree fndecl;
915 gcc_assert (func);
917 fndecl = func->as_fndecl ();
919 tree fntype = TREE_TYPE (fndecl);
921 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
923 return build_call (loc, fn, args);
926 /* Construct a playback::rvalue instance (wrapping a tree) for a
927 call through a function pointer. */
929 playback::rvalue *
930 playback::context::
931 new_call_through_ptr (location *loc,
932 rvalue *fn_ptr,
933 const auto_vec<rvalue *> *args)
935 gcc_assert (fn_ptr);
936 tree t_fn_ptr = fn_ptr->as_tree ();
938 return build_call (loc, t_fn_ptr, args);
941 /* Construct a tree for a cast. */
943 tree
944 playback::context::build_cast (playback::location *loc,
945 playback::rvalue *expr,
946 playback::type *type_)
948 /* For comparison, see:
949 - c/c-typeck.c:build_c_cast
950 - c/c-convert.c: convert
951 - convert.h
953 Only some kinds of cast are currently supported here. */
954 tree t_expr = expr->as_tree ();
955 tree t_dst_type = type_->as_tree ();
956 tree t_ret = NULL;
957 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
958 if (t_ret)
959 return t_ret;
960 enum tree_code dst_code = TREE_CODE (t_dst_type);
961 switch (dst_code)
963 case INTEGER_TYPE:
964 case ENUMERAL_TYPE:
965 t_ret = convert_to_integer (t_dst_type, t_expr);
966 goto maybe_fold;
968 case BOOLEAN_TYPE:
969 /* Compare with c_objc_common_truthvalue_conversion and
970 c_common_truthvalue_conversion. */
971 /* For now, convert to: (t_expr != 0) */
972 t_ret = build2 (NE_EXPR, t_dst_type,
973 t_expr,
974 build_int_cst (TREE_TYPE (t_expr), 0));
975 goto maybe_fold;
977 case REAL_TYPE:
978 t_ret = convert_to_real (t_dst_type, t_expr);
979 goto maybe_fold;
981 case POINTER_TYPE:
982 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
983 goto maybe_fold;
985 default:
986 add_error (loc, "couldn't handle cast during playback");
987 fprintf (stderr, "input expression:\n");
988 debug_tree (t_expr);
989 fprintf (stderr, "requested type:\n");
990 debug_tree (t_dst_type);
991 return error_mark_node;
993 maybe_fold:
994 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
995 t_ret = fold (t_ret);
996 return t_ret;
1000 /* Construct a playback::rvalue instance (wrapping a tree) for a
1001 cast. */
1003 playback::rvalue *
1004 playback::context::
1005 new_cast (playback::location *loc,
1006 playback::rvalue *expr,
1007 playback::type *type_)
1010 tree t_cast = build_cast (loc, expr, type_);
1011 if (loc)
1012 set_tree_location (t_cast, loc);
1013 return new rvalue (this, t_cast);
1016 /* Construct a playback::lvalue instance (wrapping a tree) for an
1017 array access. */
1019 playback::lvalue *
1020 playback::context::
1021 new_array_access (location *loc,
1022 rvalue *ptr,
1023 rvalue *index)
1025 gcc_assert (ptr);
1026 gcc_assert (index);
1028 /* For comparison, see:
1029 c/c-typeck.c: build_array_ref
1030 c-family/c-common.c: pointer_int_sum
1032 tree t_ptr = ptr->as_tree ();
1033 tree t_index = index->as_tree ();
1034 tree t_type_ptr = TREE_TYPE (t_ptr);
1035 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1037 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1039 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1040 NULL_TREE, NULL_TREE);
1041 if (loc)
1042 set_tree_location (t_result, loc);
1043 return new lvalue (this, t_result);
1045 else
1047 /* Convert index to an offset in bytes. */
1048 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1049 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1050 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
1052 /* Locate (ptr + offset). */
1053 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1055 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1056 if (loc)
1058 set_tree_location (t_sizeof, loc);
1059 set_tree_location (t_offset, loc);
1060 set_tree_location (t_address, loc);
1061 set_tree_location (t_indirection, loc);
1064 return new lvalue (this, t_indirection);
1068 /* Construct a tree for a field access. */
1070 tree
1071 playback::context::
1072 new_field_access (location *loc,
1073 tree datum,
1074 field *field)
1076 gcc_assert (datum);
1077 gcc_assert (field);
1079 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1080 build_component_ref. */
1081 tree type = TREE_TYPE (datum);
1082 gcc_assert (type);
1083 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1085 tree t_field = field->as_tree ();
1086 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1087 t_field, NULL_TREE);
1088 if (loc)
1089 set_tree_location (ref, loc);
1090 return ref;
1093 /* Construct a tree for a dereference. */
1095 tree
1096 playback::context::
1097 new_dereference (tree ptr,
1098 location *loc)
1100 gcc_assert (ptr);
1102 tree type = TREE_TYPE (TREE_TYPE(ptr));
1103 tree datum = build1 (INDIRECT_REF, type, ptr);
1104 if (loc)
1105 set_tree_location (datum, loc);
1106 return datum;
1109 /* Construct a playback::lvalue instance (wrapping a tree) for a
1110 field access. */
1112 playback::lvalue *
1113 playback::lvalue::
1114 access_field (location *loc,
1115 field *field)
1117 tree datum = as_tree ();
1118 tree ref = get_context ()->new_field_access (loc, datum, field);
1119 if (!ref)
1120 return NULL;
1121 return new lvalue (get_context (), ref);
1124 /* Construct a playback::rvalue instance (wrapping a tree) for a
1125 field access. */
1127 playback::rvalue *
1128 playback::rvalue::
1129 access_field (location *loc,
1130 field *field)
1132 tree datum = as_tree ();
1133 tree ref = get_context ()->new_field_access (loc, datum, field);
1134 if (!ref)
1135 return NULL;
1136 return new rvalue (get_context (), ref);
1139 /* Construct a playback::lvalue instance (wrapping a tree) for a
1140 dereferenced field access. */
1142 playback::lvalue *
1143 playback::rvalue::
1144 dereference_field (location *loc,
1145 field *field)
1147 tree ptr = as_tree ();
1148 tree datum = get_context ()->new_dereference (ptr, loc);
1149 if (!datum)
1150 return NULL;
1151 tree ref = get_context ()->new_field_access (loc, datum, field);
1152 if (!ref)
1153 return NULL;
1154 return new lvalue (get_context (), ref);
1157 /* Construct a playback::lvalue instance (wrapping a tree) for a
1158 dereference. */
1160 playback::lvalue *
1161 playback::rvalue::
1162 dereference (location *loc)
1164 tree ptr = as_tree ();
1165 tree datum = get_context ()->new_dereference (ptr, loc);
1166 return new lvalue (get_context (), datum);
1169 /* Construct a playback::rvalue instance (wrapping a tree) for an
1170 address-lookup. */
1172 playback::rvalue *
1173 playback::lvalue::
1174 get_address (location *loc)
1176 tree t_lvalue = as_tree ();
1177 tree t_thistype = TREE_TYPE (t_lvalue);
1178 tree t_ptrtype = build_pointer_type (t_thistype);
1179 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1180 if (loc)
1181 get_context ()->set_tree_location (ptr, loc);
1182 return new rvalue (get_context (), ptr);
1185 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1186 Provide this finalization hook for calling then they are collected,
1187 which calls the finalizer vfunc. This allows them to call "release"
1188 on any vec<> within them. */
1190 static void
1191 wrapper_finalizer (void *ptr)
1193 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1194 wrapper->finalizer ();
1197 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1198 allocate them using ggc_internal_cleared_alloc. */
1200 void *
1201 playback::wrapper::
1202 operator new (size_t sz)
1204 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1208 /* Constructor for gcc:jit::playback::function. */
1210 playback::function::
1211 function (context *ctxt,
1212 tree fndecl,
1213 enum gcc_jit_function_kind kind)
1214 : m_ctxt(ctxt),
1215 m_inner_fndecl (fndecl),
1216 m_inner_bind_expr (NULL),
1217 m_kind (kind)
1219 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1221 /* Create a BIND_EXPR, and within it, a statement list. */
1222 m_stmt_list = alloc_stmt_list ();
1223 m_stmt_iter = tsi_start (m_stmt_list);
1224 m_inner_block = make_node (BLOCK);
1225 m_inner_bind_expr =
1226 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1228 else
1230 m_inner_block = NULL;
1231 m_stmt_list = NULL;
1235 /* Hand-written GC-marking hook for playback functions. */
1237 void
1238 playback::function::
1239 gt_ggc_mx ()
1241 gt_ggc_m_9tree_node (m_inner_fndecl);
1242 gt_ggc_m_9tree_node (m_inner_bind_expr);
1243 gt_ggc_m_9tree_node (m_stmt_list);
1244 gt_ggc_m_9tree_node (m_inner_block);
1247 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1248 GC-ed. */
1250 void
1251 playback::function::finalizer ()
1253 m_blocks.release ();
1256 /* Get the return type of a playback function, in tree form. */
1258 tree
1259 playback::function::
1260 get_return_type_as_tree () const
1262 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1265 /* Construct a new local within this playback::function. */
1267 playback::lvalue *
1268 playback::function::
1269 new_local (location *loc,
1270 type *type,
1271 const char *name)
1273 gcc_assert (type);
1274 gcc_assert (name);
1275 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1276 get_identifier (name),
1277 type->as_tree ());
1278 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1280 /* Prepend to BIND_EXPR_VARS: */
1281 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1282 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1284 if (loc)
1285 set_tree_location (inner, loc);
1286 return new lvalue (m_ctxt, inner);
1289 /* Construct a new block within this playback::function. */
1291 playback::block *
1292 playback::function::
1293 new_block (const char *name)
1295 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1297 block *result = new playback::block (this, name);
1298 m_blocks.safe_push (result);
1299 return result;
1302 /* Build a statement list for the function as a whole out of the
1303 lists of statements for the individual blocks, building labels
1304 for each block. */
1306 void
1307 playback::function::
1308 build_stmt_list ()
1310 int i;
1311 block *b;
1313 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1315 FOR_EACH_VEC_ELT (m_blocks, i, b)
1317 int j;
1318 tree stmt;
1320 b->m_label_expr = build1 (LABEL_EXPR,
1321 void_type_node,
1322 b->as_label_decl ());
1323 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1325 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1326 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1330 /* Finish compiling the given function, potentially running the
1331 garbage-collector.
1332 The function will have a statement list by now.
1333 Amongst other things, this gimplifies the statement list,
1334 and calls cgraph_node::finalize_function on the function. */
1336 void
1337 playback::function::
1338 postprocess ()
1340 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1342 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1343 debug_tree (m_stmt_list);
1345 /* Do we need this to force cgraphunit.c to output the function? */
1346 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1348 DECL_EXTERNAL (m_inner_fndecl) = 0;
1349 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1352 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1353 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1355 DECL_EXTERNAL (m_inner_fndecl) = 0;
1356 TREE_PUBLIC (m_inner_fndecl) = 0;
1359 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1361 /* Seem to need this in gimple-low.c: */
1362 gcc_assert (m_inner_block);
1363 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1365 /* how to add to function? the following appears to be how to
1366 set the body of a m_inner_fndecl: */
1367 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1369 /* Ensure that locals appear in the debuginfo. */
1370 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1372 //debug_tree (m_inner_fndecl);
1374 /* Convert to gimple: */
1375 //printf("about to gimplify_function_tree\n");
1376 gimplify_function_tree (m_inner_fndecl);
1377 //printf("finished gimplify_function_tree\n");
1379 current_function_decl = m_inner_fndecl;
1380 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1381 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1382 //debug_tree (m_inner_fndecl);
1384 //printf("about to add to cgraph\n");
1385 /* Add to cgraph: */
1386 cgraph_node::finalize_function (m_inner_fndecl, false);
1387 /* This can trigger a collection, so we need to have all of
1388 the funcs as roots. */
1390 current_function_decl = NULL;
1394 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1395 GC-ed. */
1397 void
1398 playback::block::finalizer ()
1400 m_stmts.release ();
1403 /* Add an eval of the rvalue to the function's statement list. */
1405 void
1406 playback::block::
1407 add_eval (location *loc,
1408 rvalue *rvalue)
1410 gcc_assert (rvalue);
1412 if (loc)
1413 set_tree_location (rvalue->as_tree (), loc);
1415 add_stmt (rvalue->as_tree ());
1418 /* Add an assignment to the function's statement list. */
1420 void
1421 playback::block::
1422 add_assignment (location *loc,
1423 lvalue *lvalue,
1424 rvalue *rvalue)
1426 gcc_assert (lvalue);
1427 gcc_assert (rvalue);
1429 tree t_lvalue = lvalue->as_tree ();
1430 tree t_rvalue = rvalue->as_tree ();
1431 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1433 t_rvalue = build1 (CONVERT_EXPR,
1434 TREE_TYPE (t_lvalue),
1435 t_rvalue);
1436 if (loc)
1437 set_tree_location (t_rvalue, loc);
1440 tree stmt =
1441 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1442 t_lvalue, t_rvalue);
1443 if (loc)
1444 set_tree_location (stmt, loc);
1445 add_stmt (stmt);
1448 /* Add a comment to the function's statement list.
1449 For now this is done by adding a dummy label. */
1451 void
1452 playback::block::
1453 add_comment (location *loc,
1454 const char *text)
1456 /* Wrap the text in C-style comment delimiters. */
1457 size_t sz =
1458 (3 /* opening delim */
1459 + strlen (text)
1460 + 3 /* closing delim */
1461 + 1 /* terminator */);
1462 char *wrapped = (char *)ggc_internal_alloc (sz);
1463 snprintf (wrapped, sz, "/* %s */", text);
1465 /* For now we simply implement this by adding a dummy label with a name
1466 containing the given text. */
1467 tree identifier = get_identifier (wrapped);
1468 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1469 identifier, void_type_node);
1470 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1472 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1473 if (loc)
1474 set_tree_location (label_expr, loc);
1475 add_stmt (label_expr);
1478 /* Add a conditional jump statement to the function's statement list. */
1480 void
1481 playback::block::
1482 add_conditional (location *loc,
1483 rvalue *boolval,
1484 block *on_true,
1485 block *on_false)
1487 gcc_assert (boolval);
1488 gcc_assert (on_true);
1489 gcc_assert (on_false);
1491 /* COND_EXPR wants statement lists for the true/false operands, but we
1492 want labels.
1493 Shim it by creating jumps to the labels */
1494 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1495 on_true->as_label_decl ());
1496 if (loc)
1497 set_tree_location (true_jump, loc);
1499 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1500 on_false->as_label_decl ());
1501 if (loc)
1502 set_tree_location (false_jump, loc);
1504 tree stmt =
1505 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1506 true_jump, false_jump);
1507 if (loc)
1508 set_tree_location (stmt, loc);
1509 add_stmt (stmt);
1512 /* Add an unconditional jump statement to the function's statement list. */
1514 void
1515 playback::block::
1516 add_jump (location *loc,
1517 block *target)
1519 gcc_assert (target);
1521 // see c_finish_loop
1522 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1523 //add_stmt (top);
1525 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1526 TREE_USED (target->as_label_decl ()) = 1;
1527 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1528 if (loc)
1529 set_tree_location (stmt, loc);
1530 add_stmt (stmt);
1533 from c-typeck.c:
1534 tree
1535 c_finish_goto_label (location_t loc, tree label)
1537 tree decl = lookup_label_for_goto (loc, label);
1538 if (!decl)
1539 return NULL_TREE;
1540 TREE_USED (decl) = 1;
1542 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1543 SET_EXPR_LOCATION (t, loc);
1544 return add_stmt (t);
1551 /* Add a return statement to the function's statement list. */
1553 void
1554 playback::block::
1555 add_return (location *loc,
1556 rvalue *rvalue)
1558 tree modify_retval = NULL;
1559 tree return_type = m_func->get_return_type_as_tree ();
1560 if (rvalue)
1562 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1563 tree t_rvalue = rvalue->as_tree ();
1564 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1565 t_rvalue = build1 (CONVERT_EXPR,
1566 TREE_TYPE (t_lvalue),
1567 t_rvalue);
1568 modify_retval = build2 (MODIFY_EXPR, return_type,
1569 t_lvalue, t_rvalue);
1570 if (loc)
1571 set_tree_location (modify_retval, loc);
1573 tree return_stmt = build1 (RETURN_EXPR, return_type,
1574 modify_retval);
1575 if (loc)
1576 set_tree_location (return_stmt, loc);
1578 add_stmt (return_stmt);
1581 /* Constructor for gcc::jit::playback::block. */
1583 playback::block::
1584 block (function *func,
1585 const char *name)
1586 : m_func (func),
1587 m_stmts ()
1589 tree identifier;
1591 gcc_assert (func);
1592 // name can be NULL
1593 if (name)
1594 identifier = get_identifier (name);
1595 else
1596 identifier = NULL;
1597 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1598 identifier, void_type_node);
1599 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1600 m_label_expr = NULL;
1603 /* A subclass of auto_vec <char *> that frees all of its elements on
1604 deletion. */
1606 class auto_argvec : public auto_vec <char *>
1608 public:
1609 ~auto_argvec ();
1612 /* auto_argvec's dtor, freeing all contained strings, automatically
1613 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1615 auto_argvec::~auto_argvec ()
1617 int i;
1618 char *str;
1619 FOR_EACH_VEC_ELT (*this, i, str)
1620 free (str);
1623 /* Compile a playback::context:
1625 - Use the context's options to cconstruct command-line options, and
1626 call into the rest of GCC (toplev::main).
1627 - Assuming it succeeds, we have a .s file.
1628 - We then run the "postprocess" vfunc:
1630 (A) In-memory compile ("gcc_jit_context_compile")
1632 For an in-memory compile we have the playback::compile_to_memory
1633 subclass; "postprocess" will convert the .s file to a .so DSO,
1634 and load it in memory (via dlopen), wrapping the result up as
1635 a jit::result and returning it.
1637 (B) Compile to file ("gcc_jit_context_compile_to_file")
1639 When compiling to a file, we have the playback::compile_to_file
1640 subclass; "postprocess" will either copy the .s file to the
1641 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1642 the driver to convert it as necessary, copying the result. */
1644 void
1645 playback::context::
1646 compile ()
1648 JIT_LOG_SCOPE (get_logger ());
1650 const char *ctxt_progname;
1652 int keep_intermediates =
1653 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
1655 m_tempdir = new tempdir (get_logger (), keep_intermediates);
1656 if (!m_tempdir->create ())
1657 return;
1659 /* Call into the rest of gcc.
1660 For now, we have to assemble command-line options to pass into
1661 toplev::main, so that they can be parsed. */
1663 /* Pass in user-provided program name as argv0, if any, so that it
1664 makes it into GCC's "progname" global, used in various diagnostics. */
1665 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1667 if (!ctxt_progname)
1668 ctxt_progname = "libgccjit.so";
1670 auto_vec <recording::requested_dump> requested_dumps;
1671 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1673 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1674 acquire_mutex ();
1676 auto_argvec fake_args;
1677 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
1678 if (errors_occurred ())
1680 release_mutex ();
1681 return;
1684 /* This runs the compiler. */
1685 toplev toplev (false, /* use_TV_TOTAL */
1686 false); /* init_signals */
1687 enter_scope ("toplev::main");
1688 if (get_logger ())
1689 for (unsigned i = 0; i < fake_args.length (); i++)
1690 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
1691 toplev.main (fake_args.length (),
1692 const_cast <char **> (fake_args.address ()));
1693 exit_scope ("toplev::main");
1695 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1696 need to do it between toplev::main (which creates the dump manager)
1697 and toplev::finalize (which deletes it). */
1698 extract_any_requested_dumps (&requested_dumps);
1700 /* Clean up the compiler. */
1701 enter_scope ("toplev::finalize");
1702 toplev.finalize ();
1703 exit_scope ("toplev::finalize");
1705 /* Ideally we would release the jit mutex here, but we can't yet since
1706 followup activities use timevars, which are global state. */
1708 if (errors_occurred ())
1710 release_mutex ();
1711 return;
1714 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1715 dump_generated_code ();
1717 /* We now have a .s file.
1719 Run any postprocessing steps. This will either convert the .s file to
1720 a .so DSO, and load it in memory (playback::compile_to_memory), or
1721 convert the .s file to the requested output format, and copy it to a
1722 given file (playback::compile_to_file). */
1723 postprocess (ctxt_progname);
1725 release_mutex ();
1728 /* Implementation of class gcc::jit::playback::compile_to_memory,
1729 a subclass of gcc::jit::playback::context. */
1731 /* playback::compile_to_memory's trivial constructor. */
1733 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
1734 playback::context (ctxt),
1735 m_result (NULL)
1737 JIT_LOG_SCOPE (get_logger ());
1740 /* Implementation of the playback::context::process vfunc for compiling
1741 to memory.
1743 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1744 wrapping the result up as a jit::result and returning it. */
1746 void
1747 playback::compile_to_memory::postprocess (const char *ctxt_progname)
1749 JIT_LOG_SCOPE (get_logger ());
1750 convert_to_dso (ctxt_progname);
1751 if (errors_occurred ())
1752 return;
1753 m_result = dlopen_built_dso ();
1756 /* Implementation of class gcc::jit::playback::compile_to_file,
1757 a subclass of gcc::jit::playback::context. */
1759 /* playback::compile_to_file's trivial constructor. */
1761 playback::compile_to_file::compile_to_file (recording::context *ctxt,
1762 enum gcc_jit_output_kind output_kind,
1763 const char *output_path) :
1764 playback::context (ctxt),
1765 m_output_kind (output_kind),
1766 m_output_path (output_path)
1768 JIT_LOG_SCOPE (get_logger ());
1771 /* Implementation of the playback::context::process vfunc for compiling
1772 to a file.
1774 Either copy the .s file to the given destination (for
1775 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1776 as necessary, copying the result. */
1778 void
1779 playback::compile_to_file::postprocess (const char *ctxt_progname)
1781 JIT_LOG_SCOPE (get_logger ());
1783 /* The driver takes different actions based on the filename, so
1784 we provide a filename with an appropriate suffix for the
1785 output kind, and then copy it up to the user-provided path,
1786 rather than directly compiling it to the requested output path. */
1788 switch (m_output_kind)
1790 default:
1791 gcc_unreachable ();
1793 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
1794 copy_file (get_tempdir ()->get_path_s_file (),
1795 m_output_path);
1796 break;
1798 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
1800 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
1801 "/fake.o",
1802 NULL);
1803 invoke_driver (ctxt_progname,
1804 get_tempdir ()->get_path_s_file (),
1805 tmp_o_path,
1806 TV_ASSEMBLE,
1807 false, /* bool shared, */
1808 false);/* bool run_linker */
1809 if (!errors_occurred ())
1810 copy_file (tmp_o_path,
1811 m_output_path);
1812 free (tmp_o_path);
1814 break;
1816 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
1817 invoke_driver (ctxt_progname,
1818 get_tempdir ()->get_path_s_file (),
1819 get_tempdir ()->get_path_so_file (),
1820 TV_ASSEMBLE,
1821 true, /* bool shared, */
1822 true);/* bool run_linker */
1823 if (!errors_occurred ())
1824 copy_file (get_tempdir ()->get_path_so_file (),
1825 m_output_path);
1826 break;
1828 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
1830 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
1831 "/fake.exe",
1832 NULL);
1833 invoke_driver (ctxt_progname,
1834 get_tempdir ()->get_path_s_file (),
1835 tmp_exe_path,
1836 TV_ASSEMBLE,
1837 false, /* bool shared, */
1838 true);/* bool run_linker */
1839 if (!errors_occurred ())
1840 copy_file (tmp_exe_path,
1841 m_output_path);
1842 free (tmp_exe_path);
1844 break;
1850 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
1851 the "executable" bits).
1853 Any errors that occur are reported on the context and hence count as
1854 a failure of the compile.
1856 We can't in general hardlink or use "rename" from the tempdir since
1857 it might be on a different filesystem to the destination. For example,
1858 I get EXDEV: "Invalid cross-device link". */
1860 void
1861 playback::compile_to_file::copy_file (const char *src_path,
1862 const char *dst_path)
1864 JIT_LOG_SCOPE (get_logger ());
1865 if (get_logger ())
1867 get_logger ()->log ("src_path: %s", src_path);
1868 get_logger ()->log ("dst_path: %s", dst_path);
1871 FILE *f_in = NULL;
1872 FILE *f_out = NULL;
1873 size_t total_sz_in = 0;
1874 size_t total_sz_out = 0;
1875 char buf[4096];
1876 size_t sz_in;
1877 struct stat stat_buf;
1879 f_in = fopen (src_path, "rb");
1880 if (!f_in)
1882 add_error (NULL,
1883 "unable to open %s for reading: %s",
1884 src_path,
1885 xstrerror (errno));
1886 return;
1889 /* Use stat on the filedescriptor to get the mode,
1890 so that we can copy it over (in particular, the
1891 "executable" bits). */
1892 if (-1 == fstat (fileno (f_in), &stat_buf))
1894 add_error (NULL,
1895 "unable to fstat %s: %s",
1896 src_path,
1897 xstrerror (errno));
1898 fclose (f_in);
1899 return;
1902 f_out = fopen (dst_path, "wb");
1903 if (!f_out)
1905 add_error (NULL,
1906 "unable to open %s for writing: %s",
1907 dst_path,
1908 xstrerror (errno));
1909 fclose (f_in);
1910 return;
1913 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
1915 total_sz_in += sz_in;
1916 size_t sz_out_remaining = sz_in;
1917 size_t sz_out_so_far = 0;
1918 while (sz_out_remaining)
1920 size_t sz_out = fwrite (buf + sz_out_so_far,
1922 sz_out_remaining,
1923 f_out);
1924 gcc_assert (sz_out <= sz_out_remaining);
1925 if (!sz_out)
1927 add_error (NULL,
1928 "error writing to %s: %s",
1929 dst_path,
1930 xstrerror (errno));
1931 fclose (f_in);
1932 fclose (f_out);
1933 return;
1935 total_sz_out += sz_out;
1936 sz_out_so_far += sz_out;
1937 sz_out_remaining -= sz_out;
1939 gcc_assert (sz_out_so_far == sz_in);
1942 if (!feof (f_in))
1943 add_error (NULL,
1944 "error reading from %s: %s",
1945 src_path,
1946 xstrerror (errno));
1948 fclose (f_in);
1950 gcc_assert (total_sz_in == total_sz_out);
1951 if (get_logger ())
1952 get_logger ()->log ("total bytes copied: %ld", total_sz_out);
1954 /* Set the permissions of the copy to those of the original file,
1955 in particular the "executable" bits. */
1956 if (-1 == fchmod (fileno (f_out), stat_buf.st_mode))
1957 add_error (NULL,
1958 "error setting mode of %s: %s",
1959 dst_path,
1960 xstrerror (errno));
1962 fclose (f_out);
1965 /* Helper functions for gcc::jit::playback::context::compile. */
1967 /* This mutex guards gcc::jit::recording::context::compile, so that only
1968 one thread can be accessing the bulk of GCC's state at once. */
1970 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
1972 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
1974 void
1975 playback::context::acquire_mutex ()
1977 /* Acquire the big GCC mutex. */
1978 JIT_LOG_SCOPE (get_logger ());
1979 pthread_mutex_lock (&jit_mutex);
1980 gcc_assert (NULL == active_playback_ctxt);
1981 active_playback_ctxt = this;
1984 /* Release jit_mutex and clear the active playback ctxt. */
1986 void
1987 playback::context::release_mutex ()
1989 /* Release the big GCC mutex. */
1990 JIT_LOG_SCOPE (get_logger ());
1991 gcc_assert (active_playback_ctxt == this);
1992 active_playback_ctxt = NULL;
1993 pthread_mutex_unlock (&jit_mutex);
1996 /* Callback used by gcc::jit::playback::context::make_fake_args when
1997 invoking driver_get_configure_time_options.
1998 Populate a vec <char * > with the configure-time options. */
2000 static void
2001 append_arg_from_driver (const char *option, void *user_data)
2003 gcc_assert (option);
2004 gcc_assert (user_data);
2005 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2006 argvec->safe_push (concat ("-", option, NULL));
2009 /* Build a fake argv for toplev::main from the options set
2010 by the user on the context . */
2012 void
2013 playback::context::
2014 make_fake_args (vec <char *> *argvec,
2015 const char *ctxt_progname,
2016 vec <recording::requested_dump> *requested_dumps)
2018 JIT_LOG_SCOPE (get_logger ());
2020 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2021 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2023 ADD_ARG (ctxt_progname);
2024 ADD_ARG (get_path_c_file ());
2025 ADD_ARG ("-fPIC");
2027 /* Handle int options: */
2028 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2030 default:
2031 add_error (NULL,
2032 "unrecognized optimization level: %i",
2033 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2034 return;
2036 case 0:
2037 ADD_ARG ("-O0");
2038 break;
2040 case 1:
2041 ADD_ARG ("-O1");
2042 break;
2044 case 2:
2045 ADD_ARG ("-O2");
2046 break;
2048 case 3:
2049 ADD_ARG ("-O3");
2050 break;
2052 /* What about -Os? */
2054 /* Handle bool options: */
2055 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2056 ADD_ARG ("-g");
2058 /* Suppress timing (and other) info. */
2059 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2061 ADD_ARG ("-quiet");
2062 quiet_flag = 1;
2065 /* Aggressively garbage-collect, to shake out bugs: */
2066 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2068 ADD_ARG ("--param");
2069 ADD_ARG ("ggc-min-expand=0");
2070 ADD_ARG ("--param");
2071 ADD_ARG ("ggc-min-heapsize=0");
2074 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2076 ADD_ARG ("-fdump-tree-all");
2077 ADD_ARG ("-fdump-rtl-all");
2078 ADD_ARG ("-fdump-ipa-all");
2081 /* Add "-fdump-" options for any calls to
2082 gcc_jit_context_enable_dump. */
2084 int i;
2085 recording::requested_dump *d;
2086 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2088 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2089 ADD_ARG_TAKE_OWNERSHIP (arg);
2093 /* PR jit/64810: Add any target-specific default options
2094 from OPTION_DEFAULT_SPECS, normally provided by the driver
2095 in the non-jit case.
2097 The target-specific code can define OPTION_DEFAULT_SPECS:
2098 default command options in the form of spec macros for the
2099 driver to expand ().
2101 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2102 if not overriden, injects the defaults as extra arguments to
2103 cc1 etc.
2104 For the jit case, we need to add these arguments here. The
2105 input format (using the specs language) means that we have to run
2106 part of the driver code here (driver_get_configure_time_options).
2108 To avoid running the spec-expansion code every time, we just do
2109 it the first time (via a function-static flag), saving the result
2110 into a function-static vec.
2111 This flag and vec are global state (i.e. per-process).
2112 They are guarded by the jit mutex. */
2114 static bool have_configure_time_options = false;
2115 static vec <char *> configure_time_options;
2117 if (have_configure_time_options)
2118 log ("reusing cached configure-time options");
2119 else
2121 have_configure_time_options = true;
2122 log ("getting configure-time options from driver");
2123 driver_get_configure_time_options (append_arg_from_driver,
2124 &configure_time_options);
2127 int i;
2128 char *opt;
2130 if (get_logger ())
2131 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2132 log ("configure_time_options[%i]: %s", i, opt);
2134 /* configure_time_options should now contain the expanded options
2135 from OPTION_DEFAULT_SPECS (if any). */
2136 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2138 gcc_assert (opt);
2139 gcc_assert (opt[0] == '-');
2140 ADD_ARG (opt);
2144 #undef ADD_ARG
2145 #undef ADD_ARG_TAKE_OWNERSHIP
2148 /* The second half of the implementation of gcc_jit_context_enable_dump.
2149 Iterate through the requested dumps, reading the underlying files
2150 into heap-allocated buffers, writing pointers to the buffers into
2151 the char ** pointers provided by client code.
2152 Client code is responsible for calling free on the results. */
2154 void
2155 playback::context::
2156 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2158 JIT_LOG_SCOPE (get_logger ());
2160 int i;
2161 recording::requested_dump *d;
2162 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2164 dump_file_info *dfi;
2165 char *filename;
2166 char *content;
2168 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2169 if (!dfi)
2171 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2172 continue;
2175 filename = g->get_dumps ()->get_dump_file_name (dfi);
2176 content = read_dump_file (filename);
2177 *(d->m_out_ptr) = content;
2178 free (filename);
2182 /* Helper function for playback::context::extract_any_requested_dumps
2183 (itself for use in implementation of gcc_jit_context_enable_dump).
2185 Attempt to read the complete file at the given path, returning the
2186 bytes found there as a buffer.
2187 The caller is responsible for calling free on the result.
2188 Errors will be reported on the context, and lead to NULL being
2189 returned; an out-of-memory error will terminate the process. */
2191 char *
2192 playback::context::read_dump_file (const char *path)
2194 char *result = NULL;
2195 size_t total_sz = 0;
2196 char buf[4096];
2197 size_t sz;
2198 FILE *f_in;
2200 f_in = fopen (path, "r");
2201 if (!f_in)
2203 add_error (NULL, "unable to open %s for reading", path);
2204 return NULL;
2207 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2209 size_t old_total_sz = total_sz;
2210 total_sz += sz;
2211 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2212 memcpy (result + old_total_sz, buf, sz);
2215 if (!feof (f_in))
2217 add_error (NULL, "error reading from %s", path);
2218 free (result);
2219 fclose (f_in);
2220 return NULL;
2223 fclose (f_in);
2225 if (result)
2227 result[total_sz] = '\0';
2228 return result;
2230 else
2231 return xstrdup ("");
2234 /* Part of playback::context::compile ().
2236 We have a .s file; we want a .so file.
2237 We could reuse parts of gcc/gcc.c to do this.
2238 For now, just use the driver binary from the install, as
2239 named in gcc-driver-name.h
2240 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2242 void
2243 playback::context::
2244 convert_to_dso (const char *ctxt_progname)
2246 JIT_LOG_SCOPE (get_logger ());
2248 invoke_driver (ctxt_progname,
2249 m_tempdir->get_path_s_file (),
2250 m_tempdir->get_path_so_file (),
2251 TV_ASSEMBLE,
2252 true, /* bool shared, */
2253 true);/* bool run_linker */
2256 void
2257 playback::context::
2258 invoke_driver (const char *ctxt_progname,
2259 const char *input_file,
2260 const char *output_file,
2261 timevar_id_t tv_id,
2262 bool shared,
2263 bool run_linker)
2265 JIT_LOG_SCOPE (get_logger ());
2266 /* Currently this lumps together both assembling and linking into
2267 TV_ASSEMBLE. */
2268 auto_timevar assemble_timevar (tv_id);
2269 const char *errmsg;
2270 auto_vec <const char *> argvec;
2271 #define ADD_ARG(arg) argvec.safe_push (arg)
2272 int exit_status = 0;
2273 int err = 0;
2274 const char *gcc_driver_name = GCC_DRIVER_NAME;
2276 ADD_ARG (gcc_driver_name);
2278 if (shared)
2279 ADD_ARG ("-shared");
2281 if (!run_linker)
2282 ADD_ARG ("-c");
2284 ADD_ARG (input_file);
2285 ADD_ARG ("-o");
2286 ADD_ARG (output_file);
2288 /* Don't use the linker plugin.
2289 If running with just a "make" and not a "make install", then we'd
2290 run into
2291 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2292 libto_plugin is a .la at build time, with it becoming installed with
2293 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2294 time. */
2295 ADD_ARG ("-fno-use-linker-plugin");
2297 /* pex argv arrays are NULL-terminated. */
2298 ADD_ARG (NULL);
2300 /* pex_one's error-handling requires pname to be non-NULL. */
2301 gcc_assert (ctxt_progname);
2303 if (get_logger ())
2304 for (unsigned i = 0; i < argvec.length (); i++)
2305 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2307 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2308 gcc_driver_name,
2309 const_cast <char *const *> (argvec.address ()),
2310 ctxt_progname, /* const char *pname */
2311 NULL, /* const char *outname */
2312 NULL, /* const char *errname */
2313 &exit_status, /* int *status */
2314 &err); /* int *err*/
2315 if (errmsg)
2317 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2318 return;
2321 /* pex_one can return a NULL errmsg when the executable wasn't
2322 found (or doesn't exist), so trap these cases also. */
2323 if (exit_status || err)
2325 add_error (NULL,
2326 "error invoking gcc driver: exit_status: %i err: %i",
2327 exit_status, err);
2328 add_error (NULL,
2329 "whilst attempting to run a driver named: %s",
2330 gcc_driver_name);
2331 add_error (NULL,
2332 "PATH was: %s",
2333 getenv ("PATH"));
2334 return;
2336 #undef ADD_ARG
2339 /* Dynamically-link the built DSO file into this process, using dlopen.
2340 Wrap it up within a jit::result *, and return that.
2341 Return NULL if any errors occur, reporting them on this context. */
2343 result *
2344 playback::context::
2345 dlopen_built_dso ()
2347 JIT_LOG_SCOPE (get_logger ());
2348 auto_timevar load_timevar (TV_LOAD);
2349 void *handle = NULL;
2350 const char *error = NULL;
2351 result *result_obj = NULL;
2353 /* Clear any existing error. */
2354 dlerror ();
2356 handle = dlopen (m_tempdir->get_path_so_file (),
2357 RTLD_NOW | RTLD_LOCAL);
2358 if ((error = dlerror()) != NULL) {
2359 add_error (NULL, "%s", error);
2361 if (handle)
2363 /* We've successfully dlopened the result; create a
2364 jit::result object to wrap it.
2366 We're done with the tempdir for now, but if the user
2367 has requested debugging, the user's debugger might not
2368 be capable of dealing with the .so file being unlinked
2369 immediately, so keep it around until after the result
2370 is released. We do this by handing over ownership of
2371 the jit::tempdir to the result. See PR jit/64206. */
2372 tempdir *handover_tempdir;
2373 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2375 handover_tempdir = m_tempdir;
2376 m_tempdir = NULL;
2377 /* The tempdir will eventually be cleaned up in the
2378 jit::result's dtor. */
2379 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2380 " handing over tempdir to jit::result");
2382 else
2384 handover_tempdir = NULL;
2385 /* ... and retain ownership of m_tempdir so we clean it
2386 up it the playback::context's dtor. */
2387 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2388 " retaining ownership of tempdir");
2391 result_obj = new result (get_logger (), handle, handover_tempdir);
2393 else
2394 result_obj = NULL;
2396 return result_obj;
2399 /* Top-level hook for playing back a recording context.
2401 This plays back m_recording_ctxt, and, if no errors
2402 occurred builds statement lists for and then postprocesses
2403 every function in the result. */
2405 void
2406 playback::context::
2407 replay ()
2409 JIT_LOG_SCOPE (get_logger ());
2410 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2411 tree array_domain_type = build_index_type (size_int (200));
2412 m_char_array_type_node
2413 = build_array_type (char_type_node, array_domain_type);
2415 m_const_char_ptr
2416 = build_pointer_type (build_qualified_type (char_type_node,
2417 TYPE_QUAL_CONST));
2419 /* Replay the recorded events: */
2420 timevar_push (TV_JIT_REPLAY);
2422 m_recording_ctxt->replay_into (this);
2424 /* Clean away the temporary references from recording objects
2425 to playback objects. We have to do this now since the
2426 latter are GC-allocated, but the former don't mark these
2427 refs. Hence we must stop using them before the GC can run. */
2428 m_recording_ctxt->disassociate_from_playback ();
2430 /* The builtins_manager, if any, is associated with the recording::context
2431 and might be reused for future compiles on other playback::contexts,
2432 but its m_attributes array is not GTY-labeled and hence will become
2433 nonsense if the GC runs. Purge this state. */
2434 builtins_manager *bm = get_builtins_manager ();
2435 if (bm)
2436 bm->finish_playback ();
2438 timevar_pop (TV_JIT_REPLAY);
2440 if (!errors_occurred ())
2442 int i;
2443 function *func;
2445 /* No GC can happen yet; process the cached source locations. */
2446 handle_locations ();
2448 /* We've now created tree nodes for the stmts in the various blocks
2449 in each function, but we haven't built each function's single stmt
2450 list yet. Do so now. */
2451 FOR_EACH_VEC_ELT (m_functions, i, func)
2452 func->build_stmt_list ();
2454 /* No GC can have happened yet. */
2456 /* Postprocess the functions. This could trigger GC. */
2457 FOR_EACH_VEC_ELT (m_functions, i, func)
2459 gcc_assert (func);
2460 func->postprocess ();
2465 /* Dump the generated .s file to stderr. */
2467 void
2468 playback::context::
2469 dump_generated_code ()
2471 JIT_LOG_SCOPE (get_logger ());
2472 char buf[4096];
2473 size_t sz;
2474 FILE *f_in = fopen (get_path_s_file (), "r");
2475 if (!f_in)
2476 return;
2478 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2479 fwrite (buf, 1, sz, stderr);
2481 fclose (f_in);
2484 /* Get the supposed path of the notional "fake.c" file within the
2485 tempdir. This file doesn't exist, but the rest of the compiler
2486 needs a name. */
2488 const char *
2489 playback::context::
2490 get_path_c_file () const
2492 return m_tempdir->get_path_c_file ();
2495 /* Get the path of the assembler output file "fake.s" file within the
2496 tempdir. */
2498 const char *
2499 playback::context::
2500 get_path_s_file () const
2502 return m_tempdir->get_path_s_file ();
2505 /* Get the path of the DSO object file "fake.so" file within the
2506 tempdir. */
2508 const char *
2509 playback::context::
2510 get_path_so_file () const
2512 return m_tempdir->get_path_so_file ();
2515 /* qsort comparator for comparing pairs of playback::source_line *,
2516 ordering them by line number. */
2518 static int
2519 line_comparator (const void *lhs, const void *rhs)
2521 const playback::source_line *line_lhs = \
2522 *static_cast<const playback::source_line * const*> (lhs);
2523 const playback::source_line *line_rhs = \
2524 *static_cast<const playback::source_line * const*> (rhs);
2525 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2528 /* qsort comparator for comparing pairs of playback::location *,
2529 ordering them by column number. */
2531 static int
2532 location_comparator (const void *lhs, const void *rhs)
2534 const playback::location *loc_lhs = \
2535 *static_cast<const playback::location * const *> (lhs);
2536 const playback::location *loc_rhs = \
2537 *static_cast<const playback::location * const *> (rhs);
2538 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2541 /* Our API allows locations to be created in arbitrary orders, but the
2542 linemap API requires locations to be created in ascending order
2543 as if we were tokenizing files.
2545 This hook sorts all of the the locations that have been created, and
2546 calls into the linemap API, creating linemap entries in sorted order
2547 for our locations. */
2549 void
2550 playback::context::
2551 handle_locations ()
2553 /* Create the source code locations, following the ordering rules
2554 imposed by the linemap API.
2556 line_table is a global. */
2557 JIT_LOG_SCOPE (get_logger ());
2558 int i;
2559 source_file *file;
2561 FOR_EACH_VEC_ELT (m_source_files, i, file)
2563 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2565 /* Sort lines by ascending line numbers. */
2566 file->m_source_lines.qsort (&line_comparator);
2568 int j;
2569 source_line *line;
2570 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2572 int k;
2573 location *loc;
2575 /* Sort locations in line by ascending column numbers. */
2576 line->m_locations.qsort (&location_comparator);
2578 /* Determine maximum column within this line. */
2579 gcc_assert (line->m_locations.length () > 0);
2580 location *final_column =
2581 line->m_locations[line->m_locations.length () - 1];
2582 int max_col = final_column->get_column_num ();
2584 linemap_line_start (line_table, line->get_line_num (), max_col);
2585 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2587 loc->m_srcloc = \
2588 linemap_position_for_column (line_table, loc->get_column_num ());
2592 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2595 /* line_table should now be populated; every playback::location should
2596 now have an m_srcloc. */
2598 /* Now assign them to tree nodes as appropriate. */
2599 std::pair<tree, location *> *cached_location;
2601 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2603 tree t = cached_location->first;
2604 source_location srcloc = cached_location->second->m_srcloc;
2606 /* This covers expressions: */
2607 if (CAN_HAVE_LOCATION_P (t))
2608 SET_EXPR_LOCATION (t, srcloc);
2609 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2610 DECL_SOURCE_LOCATION (t) = srcloc;
2611 else
2613 /* Don't know how to set location on this node. */
2618 /* We handle errors on a playback::context by adding them to the
2619 corresponding recording::context. */
2621 void
2622 playback::context::
2623 add_error (location *loc, const char *fmt, ...)
2625 va_list ap;
2626 va_start (ap, fmt);
2627 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2628 fmt, ap);
2629 va_end (ap);
2632 /* We handle errors on a playback::context by adding them to the
2633 corresponding recording::context. */
2635 void
2636 playback::context::
2637 add_error_va (location *loc, const char *fmt, va_list ap)
2639 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2640 fmt, ap);
2643 /* Dealing with the linemap API. */
2645 /* Construct a playback::location for a recording::location, if it
2646 doesn't exist already. */
2648 playback::location *
2649 playback::context::
2650 new_location (recording::location *rloc,
2651 const char *filename,
2652 int line,
2653 int column)
2655 /* Get the source_file for filename, creating if necessary. */
2656 source_file *src_file = get_source_file (filename);
2657 /* Likewise for the line within the file. */
2658 source_line *src_line = src_file->get_source_line (line);
2659 /* Likewise for the column within the line. */
2660 location *loc = src_line->get_location (rloc, column);
2661 return loc;
2664 /* Deferred setting of the location for a given tree, by adding the
2665 (tree, playback::location) pair to a list of deferred associations.
2666 We will actually set the location on the tree later on once
2667 the source_location for the playback::location exists. */
2669 void
2670 playback::context::
2671 set_tree_location (tree t, location *loc)
2673 gcc_assert (loc);
2674 m_cached_locations.safe_push (std::make_pair (t, loc));
2678 /* Construct a playback::source_file for the given source
2679 filename, if it doesn't exist already. */
2681 playback::source_file *
2682 playback::context::
2683 get_source_file (const char *filename)
2685 /* Locate the file.
2686 For simplicitly, this is currently a linear search.
2687 Replace with a hash if this shows up in the profile. */
2688 int i;
2689 source_file *file;
2690 tree ident_filename = get_identifier (filename);
2692 FOR_EACH_VEC_ELT (m_source_files, i, file)
2693 if (file->filename_as_tree () == ident_filename)
2694 return file;
2696 /* Not found. */
2697 file = new source_file (ident_filename);
2698 m_source_files.safe_push (file);
2699 return file;
2702 /* Constructor for gcc::jit::playback::source_file. */
2704 playback::source_file::source_file (tree filename) :
2705 m_source_lines (),
2706 m_filename (filename)
2710 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2711 GC-ed. */
2713 void
2714 playback::source_file::finalizer ()
2716 m_source_lines.release ();
2719 /* Construct a playback::source_line for the given line
2720 within this source file, if one doesn't exist already. */
2722 playback::source_line *
2723 playback::source_file::
2724 get_source_line (int line_num)
2726 /* Locate the line.
2727 For simplicitly, this is currently a linear search.
2728 Replace with a hash if this shows up in the profile. */
2729 int i;
2730 source_line *line;
2732 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2733 if (line->get_line_num () == line_num)
2734 return line;
2736 /* Not found. */
2737 line = new source_line (this, line_num);
2738 m_source_lines.safe_push (line);
2739 return line;
2742 /* Constructor for gcc::jit::playback::source_line. */
2744 playback::source_line::source_line (source_file *file, int line_num) :
2745 m_locations (),
2746 m_source_file (file),
2747 m_line_num (line_num)
2751 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2752 GC-ed. */
2754 void
2755 playback::source_line::finalizer ()
2757 m_locations.release ();
2760 /* Construct a playback::location for the given column
2761 within this line of a specific source file, if one doesn't exist
2762 already. */
2764 playback::location *
2765 playback::source_line::
2766 get_location (recording::location *rloc, int column_num)
2768 int i;
2769 location *loc;
2771 /* Another linear search that probably should be a hash table. */
2772 FOR_EACH_VEC_ELT (m_locations, i, loc)
2773 if (loc->get_column_num () == column_num)
2774 return loc;
2776 /* Not found. */
2777 loc = new location (rloc, this, column_num);
2778 m_locations.safe_push (loc);
2779 return loc;
2782 /* Constructor for gcc::jit::playback::location. */
2784 playback::location::location (recording::location *loc,
2785 source_line *line,
2786 int column_num) :
2787 m_srcloc (UNKNOWN_LOCATION),
2788 m_recording_loc (loc),
2789 m_line (line),
2790 m_column_num(column_num)
2794 /* The active gcc::jit::playback::context instance. This is a singleton,
2795 guarded by jit_mutex. */
2797 playback::context *active_playback_ctxt;
2799 } // namespace gcc::jit
2801 } // namespace gcc