2015-07-14 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / gcc / jit / jit-playback.c
blob8d0c210a55636ce7a50d6980c1901fdf302cc608
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 "tree.h"
30 #include "inchash.h"
31 #include "hash-map.h"
32 #include "vec.h"
33 #include "hashtab.h"
34 #include "tm.h"
35 #include "hard-reg-set.h"
36 #include "function.h"
37 #include "dumpfile.h"
38 #include "cgraph.h"
39 #include "toplev.h"
40 #include "timevar.h"
41 #include "tree-cfg.h"
42 #include "target.h"
43 #include "convert.h"
44 #include "stringpool.h"
45 #include "stor-layout.h"
46 #include "print-tree.h"
47 #include "gimplify.h"
48 #include "gcc-driver-name.h"
49 #include "attribs.h"
50 #include "context.h"
51 #include "fold-const.h"
52 #include "debug.h"
53 #include "gcc.h"
55 #include "jit-common.h"
56 #include "jit-logging.h"
57 #include "jit-playback.h"
58 #include "jit-result.h"
59 #include "jit-builtins.h"
60 #include "jit-tempdir.h"
63 /* gcc::jit::playback::context::build_cast uses the convert.h API,
64 which in turn requires the frontend to provide a "convert"
65 function, apparently as a fallback.
67 Hence we provide this dummy one, with the requirement that any casts
68 are handled before reaching this. */
69 extern tree convert (tree type, tree expr);
71 tree
72 convert (tree dst_type, tree expr)
74 gcc_assert (gcc::jit::active_playback_ctxt);
75 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
76 fprintf (stderr, "input expression:\n");
77 debug_tree (expr);
78 fprintf (stderr, "requested type:\n");
79 debug_tree (dst_type);
80 return error_mark_node;
83 namespace gcc {
84 namespace jit {
86 /**********************************************************************
87 Playback.
88 **********************************************************************/
90 /* The constructor for gcc::jit::playback::context. */
92 playback::context::context (recording::context *ctxt)
93 : log_user (ctxt->get_logger ()),
94 m_recording_ctxt (ctxt),
95 m_tempdir (NULL),
96 m_char_array_type_node (NULL),
97 m_const_char_ptr (NULL)
99 JIT_LOG_SCOPE (get_logger ());
100 m_functions.create (0);
101 m_globals.create (0);
102 m_source_files.create (0);
103 m_cached_locations.create (0);
106 /* The destructor for gcc::jit::playback::context. */
108 playback::context::~context ()
110 JIT_LOG_SCOPE (get_logger ());
112 /* Normally the playback::context is responsible for cleaning up the
113 tempdir (including "fake.so" within the filesystem).
115 In the normal case, clean it up now.
117 However m_tempdir can be NULL if the context has handed over
118 responsibility for the tempdir cleanup to the jit::result object, so
119 that the cleanup can be delayed (see PR jit/64206). If that's the
120 case this "delete NULL;" is a no-op. */
121 delete m_tempdir;
123 m_functions.release ();
126 /* A playback::context can reference GC-managed pointers. Mark them
127 ("by hand", rather than by gengtype).
129 This is called on the active playback context (if any) by the
130 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
132 void
133 playback::context::
134 gt_ggc_mx ()
136 int i;
137 function *func;
138 FOR_EACH_VEC_ELT (m_functions, i, func)
140 if (ggc_test_and_set_mark (func))
141 func->gt_ggc_mx ();
145 /* Given an enum gcc_jit_types value, get a "tree" type. */
147 static tree
148 get_tree_node_for_type (enum gcc_jit_types type_)
150 switch (type_)
152 case GCC_JIT_TYPE_VOID:
153 return void_type_node;
155 case GCC_JIT_TYPE_VOID_PTR:
156 return ptr_type_node;
158 case GCC_JIT_TYPE_BOOL:
159 return boolean_type_node;
161 case GCC_JIT_TYPE_CHAR:
162 return char_type_node;
163 case GCC_JIT_TYPE_SIGNED_CHAR:
164 return signed_char_type_node;
165 case GCC_JIT_TYPE_UNSIGNED_CHAR:
166 return unsigned_char_type_node;
168 case GCC_JIT_TYPE_SHORT:
169 return short_integer_type_node;
170 case GCC_JIT_TYPE_UNSIGNED_SHORT:
171 return short_unsigned_type_node;
173 case GCC_JIT_TYPE_CONST_CHAR_PTR:
175 tree const_char = build_qualified_type (char_type_node,
176 TYPE_QUAL_CONST);
177 return build_pointer_type (const_char);
180 case GCC_JIT_TYPE_INT:
181 return integer_type_node;
182 case GCC_JIT_TYPE_UNSIGNED_INT:
183 return unsigned_type_node;
185 case GCC_JIT_TYPE_LONG:
186 return long_integer_type_node;
187 case GCC_JIT_TYPE_UNSIGNED_LONG:
188 return long_unsigned_type_node;
190 case GCC_JIT_TYPE_LONG_LONG:
191 return long_long_integer_type_node;
192 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
193 return long_long_unsigned_type_node;
195 case GCC_JIT_TYPE_FLOAT:
196 return float_type_node;
197 case GCC_JIT_TYPE_DOUBLE:
198 return double_type_node;
199 case GCC_JIT_TYPE_LONG_DOUBLE:
200 return long_double_type_node;
202 case GCC_JIT_TYPE_SIZE_T:
203 return size_type_node;
205 case GCC_JIT_TYPE_FILE_PTR:
206 return fileptr_type_node;
208 case GCC_JIT_TYPE_COMPLEX_FLOAT:
209 return complex_float_type_node;
210 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
211 return complex_double_type_node;
212 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
213 return complex_long_double_type_node;
216 return NULL;
219 /* Construct a playback::type instance (wrapping a tree) for the given
220 enum value. */
222 playback::type *
223 playback::context::
224 get_type (enum gcc_jit_types type_)
226 tree type_node = get_tree_node_for_type (type_);
227 if (NULL == type_node)
229 add_error (NULL,
230 "unrecognized (enum gcc_jit_types) value: %i", type_);
231 return NULL;
234 return new type (type_node);
237 /* Construct a playback::type instance (wrapping a tree) for the given
238 array type. */
240 playback::type *
241 playback::context::
242 new_array_type (playback::location *loc,
243 playback::type *element_type,
244 int num_elements)
246 gcc_assert (element_type);
248 tree t = build_array_type_nelts (element_type->as_tree (),
249 num_elements);
250 layout_type (t);
252 if (loc)
253 set_tree_location (t, loc);
255 return new type (t);
258 /* Construct a playback::field instance (wrapping a tree). */
260 playback::field *
261 playback::context::
262 new_field (location *loc,
263 type *type,
264 const char *name)
266 gcc_assert (type);
267 gcc_assert (name);
269 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
270 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
271 get_identifier (name), type->as_tree ());
273 if (loc)
274 set_tree_location (decl, loc);
276 return new field (decl);
279 /* Construct a playback::compound_type instance (wrapping a tree). */
281 playback::compound_type *
282 playback::context::
283 new_compound_type (location *loc,
284 const char *name,
285 bool is_struct) /* else is union */
287 gcc_assert (name);
289 /* Compare with c/c-decl.c: start_struct. */
291 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
292 TYPE_NAME (t) = get_identifier (name);
293 TYPE_SIZE (t) = 0;
295 if (loc)
296 set_tree_location (t, loc);
298 return new compound_type (t);
301 void
302 playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
304 /* Compare with c/c-decl.c: finish_struct. */
305 tree t = as_tree ();
307 tree fieldlist = NULL;
308 for (unsigned i = 0; i < fields->length (); i++)
310 field *f = (*fields)[i];
311 DECL_CONTEXT (f->as_tree ()) = t;
312 fieldlist = chainon (f->as_tree (), fieldlist);
314 fieldlist = nreverse (fieldlist);
315 TYPE_FIELDS (t) = fieldlist;
317 layout_type (t);
320 /* Construct a playback::type instance (wrapping a tree) for a function
321 type. */
323 playback::type *
324 playback::context::
325 new_function_type (type *return_type,
326 const auto_vec<type *> *param_types,
327 int is_variadic)
329 int i;
330 type *param_type;
332 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
334 FOR_EACH_VEC_ELT (*param_types, i, param_type)
335 arg_types[i] = param_type->as_tree ();
337 tree fn_type;
338 if (is_variadic)
339 fn_type =
340 build_varargs_function_type_array (return_type->as_tree (),
341 param_types->length (),
342 arg_types);
343 else
344 fn_type = build_function_type_array (return_type->as_tree (),
345 param_types->length (),
346 arg_types);
347 free (arg_types);
349 return new type (fn_type);
352 /* Construct a playback::param instance (wrapping a tree). */
354 playback::param *
355 playback::context::
356 new_param (location *loc,
357 type *type,
358 const char *name)
360 gcc_assert (type);
361 gcc_assert (name);
362 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
363 get_identifier (name), type->as_tree ());
364 if (loc)
365 set_tree_location (inner, loc);
367 return new param (this, inner);
370 /* Construct a playback::function instance. */
372 playback::function *
373 playback::context::
374 new_function (location *loc,
375 enum gcc_jit_function_kind kind,
376 type *return_type,
377 const char *name,
378 const auto_vec<param *> *params,
379 int is_variadic,
380 enum built_in_function builtin_id)
382 int i;
383 param *param;
385 //can return_type be NULL?
386 gcc_assert (name);
388 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
389 FOR_EACH_VEC_ELT (*params, i, param)
390 arg_types[i] = TREE_TYPE (param->as_tree ());
392 tree fn_type;
393 if (is_variadic)
394 fn_type = build_varargs_function_type_array (return_type->as_tree (),
395 params->length (), arg_types);
396 else
397 fn_type = build_function_type_array (return_type->as_tree (),
398 params->length (), arg_types);
399 free (arg_types);
401 /* FIXME: this uses input_location: */
402 tree fndecl = build_fn_decl (name, fn_type);
404 if (loc)
405 set_tree_location (fndecl, loc);
407 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
408 NULL_TREE, return_type->as_tree ());
409 DECL_ARTIFICIAL (resdecl) = 1;
410 DECL_IGNORED_P (resdecl) = 1;
411 DECL_RESULT (fndecl) = resdecl;
413 if (builtin_id)
415 DECL_FUNCTION_CODE (fndecl) = builtin_id;
416 gcc_assert (loc == NULL);
417 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
419 DECL_BUILT_IN_CLASS (fndecl) =
420 builtins_manager::get_class (builtin_id);
421 set_builtin_decl (builtin_id, fndecl,
422 builtins_manager::implicit_p (builtin_id));
424 builtins_manager *bm = get_builtins_manager ();
425 tree attrs = bm->get_attrs_tree (builtin_id);
426 if (attrs)
427 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
428 else
429 decl_attributes (&fndecl, NULL_TREE, 0);
432 if (kind != GCC_JIT_FUNCTION_IMPORTED)
434 tree param_decl_list = NULL;
435 FOR_EACH_VEC_ELT (*params, i, param)
437 param_decl_list = chainon (param->as_tree (), param_decl_list);
440 /* The param list was created in reverse order; fix it: */
441 param_decl_list = nreverse (param_decl_list);
443 tree t;
444 for (t = param_decl_list; t; t = DECL_CHAIN (t))
446 DECL_CONTEXT (t) = fndecl;
447 DECL_ARG_TYPE (t) = TREE_TYPE (t);
450 /* Set it up on DECL_ARGUMENTS */
451 DECL_ARGUMENTS(fndecl) = param_decl_list;
454 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
456 DECL_DECLARED_INLINE_P (fndecl) = 1;
458 /* Add attribute "always_inline": */
459 DECL_ATTRIBUTES (fndecl) =
460 tree_cons (get_identifier ("always_inline"),
461 NULL,
462 DECL_ATTRIBUTES (fndecl));
465 function *func = new function (this, fndecl, kind);
466 m_functions.safe_push (func);
467 return func;
470 /* Construct a playback::lvalue instance (wrapping a tree). */
472 playback::lvalue *
473 playback::context::
474 new_global (location *loc,
475 enum gcc_jit_global_kind kind,
476 type *type,
477 const char *name)
479 gcc_assert (type);
480 gcc_assert (name);
481 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
482 get_identifier (name),
483 type->as_tree ());
484 TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
485 DECL_COMMON (inner) = 1;
486 switch (kind)
488 default:
489 gcc_unreachable ();
491 case GCC_JIT_GLOBAL_EXPORTED:
492 TREE_STATIC (inner) = 1;
493 break;
495 case GCC_JIT_GLOBAL_INTERNAL:
496 TREE_STATIC (inner) = 1;
497 break;
499 case GCC_JIT_GLOBAL_IMPORTED:
500 DECL_EXTERNAL (inner) = 1;
501 break;
504 if (loc)
505 set_tree_location (inner, loc);
507 varpool_node::get_create (inner);
509 varpool_node::finalize_decl (inner);
511 m_globals.safe_push (inner);
513 return new lvalue (this, inner);
516 /* Implementation of the various
517 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
518 methods.
519 Each of these constructs a playback::rvalue instance (wrapping a tree).
521 These specializations are required to be in the same namespace
522 as the template, hence we now have to enter the gcc::jit::playback
523 namespace. */
525 namespace playback
528 /* Specialization of making an rvalue from a const, for host <int>. */
530 template <>
531 rvalue *
532 context::
533 new_rvalue_from_const <int> (type *type,
534 int value)
536 // FIXME: type-checking, or coercion?
537 tree inner_type = type->as_tree ();
538 if (INTEGRAL_TYPE_P (inner_type))
540 tree inner = build_int_cst (inner_type, value);
541 return new rvalue (this, inner);
543 else
545 REAL_VALUE_TYPE real_value;
546 real_from_integer (&real_value, VOIDmode, value, SIGNED);
547 tree inner = build_real (inner_type, real_value);
548 return new rvalue (this, inner);
552 /* Specialization of making an rvalue from a const, for host <long>. */
554 template <>
555 rvalue *
556 context::
557 new_rvalue_from_const <long> (type *type,
558 long value)
560 // FIXME: type-checking, or coercion?
561 tree inner_type = type->as_tree ();
562 if (INTEGRAL_TYPE_P (inner_type))
564 tree inner = build_int_cst (inner_type, value);
565 return new rvalue (this, inner);
567 else
569 REAL_VALUE_TYPE real_value;
570 real_from_integer (&real_value, VOIDmode, value, SIGNED);
571 tree inner = build_real (inner_type, real_value);
572 return new rvalue (this, inner);
576 /* Specialization of making an rvalue from a const, for host <double>. */
578 template <>
579 rvalue *
580 context::
581 new_rvalue_from_const <double> (type *type,
582 double value)
584 // FIXME: type-checking, or coercion?
585 tree inner_type = type->as_tree ();
587 /* We have a "double", we want a REAL_VALUE_TYPE.
589 real.c:real_from_target appears to require the representation to be
590 split into 32-bit values, and then sent as an pair of host long
591 ints. */
592 REAL_VALUE_TYPE real_value;
593 union
595 double as_double;
596 uint32_t as_uint32s[2];
597 } u;
598 u.as_double = value;
599 long int as_long_ints[2];
600 as_long_ints[0] = u.as_uint32s[0];
601 as_long_ints[1] = u.as_uint32s[1];
602 real_from_target (&real_value, as_long_ints, DFmode);
603 tree inner = build_real (inner_type, real_value);
604 return new rvalue (this, inner);
607 /* Specialization of making an rvalue from a const, for host <void *>. */
609 template <>
610 rvalue *
611 context::
612 new_rvalue_from_const <void *> (type *type,
613 void *value)
615 tree inner_type = type->as_tree ();
616 /* FIXME: how to ensure we have a wide enough type? */
617 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
618 return new rvalue (this, inner);
621 /* We're done implementing the specializations of
622 gcc::jit::playback::context::new_rvalue_from_const <T>
623 so we can exit the gcc::jit::playback namespace. */
625 } // namespace playback
627 /* Construct a playback::rvalue instance (wrapping a tree). */
629 playback::rvalue *
630 playback::context::
631 new_string_literal (const char *value)
633 tree t_str = build_string (strlen (value), value);
634 gcc_assert (m_char_array_type_node);
635 TREE_TYPE (t_str) = m_char_array_type_node;
637 /* Convert to (const char*), loosely based on
638 c/c-typeck.c: array_to_pointer_conversion,
639 by taking address of start of string. */
640 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
642 return new rvalue (this, t_addr);
645 /* Coerce a tree expression into a boolean tree expression. */
647 tree
648 playback::context::
649 as_truth_value (tree expr, location *loc)
651 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
652 tree typed_zero = fold_build1 (CONVERT_EXPR,
653 TREE_TYPE (expr),
654 integer_zero_node);
655 if (loc)
656 set_tree_location (typed_zero, loc);
658 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
659 if (loc)
660 set_tree_location (expr, loc);
662 return expr;
665 /* Construct a playback::rvalue instance (wrapping a tree) for a
666 unary op. */
668 playback::rvalue *
669 playback::context::
670 new_unary_op (location *loc,
671 enum gcc_jit_unary_op op,
672 type *result_type,
673 rvalue *a)
675 // FIXME: type-checking, or coercion?
676 enum tree_code inner_op;
678 gcc_assert (result_type);
679 gcc_assert (a);
681 tree node = a->as_tree ();
682 tree inner_result = NULL;
684 switch (op)
686 default:
687 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
688 return NULL;
690 case GCC_JIT_UNARY_OP_MINUS:
691 inner_op = NEGATE_EXPR;
692 break;
694 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
695 inner_op = BIT_NOT_EXPR;
696 break;
698 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
699 node = as_truth_value (node, loc);
700 inner_result = invert_truthvalue (node);
701 if (loc)
702 set_tree_location (inner_result, loc);
703 return new rvalue (this, inner_result);
705 case GCC_JIT_UNARY_OP_ABS:
706 inner_op = ABS_EXPR;
707 break;
710 inner_result = build1 (inner_op,
711 result_type->as_tree (),
712 node);
713 if (loc)
714 set_tree_location (inner_result, loc);
716 return new rvalue (this, inner_result);
719 /* Construct a playback::rvalue instance (wrapping a tree) for a
720 binary op. */
722 playback::rvalue *
723 playback::context::
724 new_binary_op (location *loc,
725 enum gcc_jit_binary_op op,
726 type *result_type,
727 rvalue *a, rvalue *b)
729 // FIXME: type-checking, or coercion?
730 enum tree_code inner_op;
732 gcc_assert (result_type);
733 gcc_assert (a);
734 gcc_assert (b);
736 tree node_a = a->as_tree ();
737 tree node_b = b->as_tree ();
739 switch (op)
741 default:
742 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
743 return NULL;
745 case GCC_JIT_BINARY_OP_PLUS:
746 inner_op = PLUS_EXPR;
747 break;
749 case GCC_JIT_BINARY_OP_MINUS:
750 inner_op = MINUS_EXPR;
751 break;
753 case GCC_JIT_BINARY_OP_MULT:
754 inner_op = MULT_EXPR;
755 break;
757 case GCC_JIT_BINARY_OP_DIVIDE:
758 if (FLOAT_TYPE_P (result_type->as_tree ()))
759 /* Floating-point division: */
760 inner_op = RDIV_EXPR;
761 else
762 /* Truncating to zero: */
763 inner_op = TRUNC_DIV_EXPR;
764 break;
766 case GCC_JIT_BINARY_OP_MODULO:
767 inner_op = TRUNC_MOD_EXPR;
768 break;
770 case GCC_JIT_BINARY_OP_BITWISE_AND:
771 inner_op = BIT_AND_EXPR;
772 break;
774 case GCC_JIT_BINARY_OP_BITWISE_XOR:
775 inner_op = BIT_XOR_EXPR;
776 break;
778 case GCC_JIT_BINARY_OP_BITWISE_OR:
779 inner_op = BIT_IOR_EXPR;
780 break;
782 case GCC_JIT_BINARY_OP_LOGICAL_AND:
783 node_a = as_truth_value (node_a, loc);
784 node_b = as_truth_value (node_b, loc);
785 inner_op = TRUTH_ANDIF_EXPR;
786 break;
788 case GCC_JIT_BINARY_OP_LOGICAL_OR:
789 node_a = as_truth_value (node_a, loc);
790 node_b = as_truth_value (node_b, loc);
791 inner_op = TRUTH_ORIF_EXPR;
792 break;
794 case GCC_JIT_BINARY_OP_LSHIFT:
795 inner_op = LSHIFT_EXPR;
796 break;
798 case GCC_JIT_BINARY_OP_RSHIFT:
799 inner_op = RSHIFT_EXPR;
800 break;
803 tree inner_expr = build2 (inner_op,
804 result_type->as_tree (),
805 node_a,
806 node_b);
807 if (loc)
808 set_tree_location (inner_expr, loc);
810 return new rvalue (this, inner_expr);
813 /* Construct a playback::rvalue instance (wrapping a tree) for a
814 comparison. */
816 playback::rvalue *
817 playback::context::
818 new_comparison (location *loc,
819 enum gcc_jit_comparison op,
820 rvalue *a, rvalue *b)
822 // FIXME: type-checking, or coercion?
823 enum tree_code inner_op;
825 gcc_assert (a);
826 gcc_assert (b);
828 switch (op)
830 default:
831 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
832 return NULL;
834 case GCC_JIT_COMPARISON_EQ:
835 inner_op = EQ_EXPR;
836 break;
837 case GCC_JIT_COMPARISON_NE:
838 inner_op = NE_EXPR;
839 break;
840 case GCC_JIT_COMPARISON_LT:
841 inner_op = LT_EXPR;
842 break;
843 case GCC_JIT_COMPARISON_LE:
844 inner_op = LE_EXPR;
845 break;
846 case GCC_JIT_COMPARISON_GT:
847 inner_op = GT_EXPR;
848 break;
849 case GCC_JIT_COMPARISON_GE:
850 inner_op = GE_EXPR;
851 break;
854 tree inner_expr = build2 (inner_op,
855 boolean_type_node,
856 a->as_tree (),
857 b->as_tree ());
858 if (loc)
859 set_tree_location (inner_expr, loc);
860 return new rvalue (this, inner_expr);
863 /* Construct a playback::rvalue instance (wrapping a tree) for a
864 function call. */
866 playback::rvalue *
867 playback::context::
868 build_call (location *loc,
869 tree fn_ptr,
870 const auto_vec<rvalue *> *args)
872 vec<tree, va_gc> *tree_args;
873 vec_alloc (tree_args, args->length ());
874 for (unsigned i = 0; i < args->length (); i++)
875 tree_args->quick_push ((*args)[i]->as_tree ());
877 if (loc)
878 set_tree_location (fn_ptr, loc);
880 tree fn = TREE_TYPE (fn_ptr);
881 tree fn_type = TREE_TYPE (fn);
882 tree return_type = TREE_TYPE (fn_type);
884 return new rvalue (this,
885 build_call_vec (return_type,
886 fn_ptr, tree_args));
888 /* see c-typeck.c: build_function_call
889 which calls build_function_call_vec
891 which does lots of checking, then:
892 result = build_call_array_loc (loc, TREE_TYPE (fntype),
893 function, nargs, argarray);
894 which is in tree.c
895 (see also build_call_vec)
899 /* Construct a playback::rvalue instance (wrapping a tree) for a
900 call to a specific function. */
902 playback::rvalue *
903 playback::context::
904 new_call (location *loc,
905 function *func,
906 const auto_vec<rvalue *> *args)
908 tree fndecl;
910 gcc_assert (func);
912 fndecl = func->as_fndecl ();
914 tree fntype = TREE_TYPE (fndecl);
916 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
918 return build_call (loc, fn, args);
921 /* Construct a playback::rvalue instance (wrapping a tree) for a
922 call through a function pointer. */
924 playback::rvalue *
925 playback::context::
926 new_call_through_ptr (location *loc,
927 rvalue *fn_ptr,
928 const auto_vec<rvalue *> *args)
930 gcc_assert (fn_ptr);
931 tree t_fn_ptr = fn_ptr->as_tree ();
933 return build_call (loc, t_fn_ptr, args);
936 /* Construct a tree for a cast. */
938 tree
939 playback::context::build_cast (playback::location *loc,
940 playback::rvalue *expr,
941 playback::type *type_)
943 /* For comparison, see:
944 - c/c-typeck.c:build_c_cast
945 - c/c-convert.c: convert
946 - convert.h
948 Only some kinds of cast are currently supported here. */
949 tree t_expr = expr->as_tree ();
950 tree t_dst_type = type_->as_tree ();
951 tree t_ret = NULL;
952 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
953 if (t_ret)
954 return t_ret;
955 enum tree_code dst_code = TREE_CODE (t_dst_type);
956 switch (dst_code)
958 case INTEGER_TYPE:
959 case ENUMERAL_TYPE:
960 t_ret = convert_to_integer (t_dst_type, t_expr);
961 goto maybe_fold;
963 case BOOLEAN_TYPE:
964 /* Compare with c_objc_common_truthvalue_conversion and
965 c_common_truthvalue_conversion. */
966 /* For now, convert to: (t_expr != 0) */
967 t_ret = build2 (NE_EXPR, t_dst_type,
968 t_expr,
969 build_int_cst (TREE_TYPE (t_expr), 0));
970 goto maybe_fold;
972 case REAL_TYPE:
973 t_ret = convert_to_real (t_dst_type, t_expr);
974 goto maybe_fold;
976 case POINTER_TYPE:
977 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
978 goto maybe_fold;
980 default:
981 add_error (loc, "couldn't handle cast during playback");
982 fprintf (stderr, "input expression:\n");
983 debug_tree (t_expr);
984 fprintf (stderr, "requested type:\n");
985 debug_tree (t_dst_type);
986 return error_mark_node;
988 maybe_fold:
989 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
990 t_ret = fold (t_ret);
991 return t_ret;
995 /* Construct a playback::rvalue instance (wrapping a tree) for a
996 cast. */
998 playback::rvalue *
999 playback::context::
1000 new_cast (playback::location *loc,
1001 playback::rvalue *expr,
1002 playback::type *type_)
1005 tree t_cast = build_cast (loc, expr, type_);
1006 if (loc)
1007 set_tree_location (t_cast, loc);
1008 return new rvalue (this, t_cast);
1011 /* Construct a playback::lvalue instance (wrapping a tree) for an
1012 array access. */
1014 playback::lvalue *
1015 playback::context::
1016 new_array_access (location *loc,
1017 rvalue *ptr,
1018 rvalue *index)
1020 gcc_assert (ptr);
1021 gcc_assert (index);
1023 /* For comparison, see:
1024 c/c-typeck.c: build_array_ref
1025 c-family/c-common.c: pointer_int_sum
1027 tree t_ptr = ptr->as_tree ();
1028 tree t_index = index->as_tree ();
1029 tree t_type_ptr = TREE_TYPE (t_ptr);
1030 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1032 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1034 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1035 NULL_TREE, NULL_TREE);
1036 if (loc)
1037 set_tree_location (t_result, loc);
1038 return new lvalue (this, t_result);
1040 else
1042 /* Convert index to an offset in bytes. */
1043 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1044 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1045 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
1047 /* Locate (ptr + offset). */
1048 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1050 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1051 if (loc)
1053 set_tree_location (t_sizeof, loc);
1054 set_tree_location (t_offset, loc);
1055 set_tree_location (t_address, loc);
1056 set_tree_location (t_indirection, loc);
1059 return new lvalue (this, t_indirection);
1063 /* Construct a tree for a field access. */
1065 tree
1066 playback::context::
1067 new_field_access (location *loc,
1068 tree datum,
1069 field *field)
1071 gcc_assert (datum);
1072 gcc_assert (field);
1074 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1075 build_component_ref. */
1076 tree type = TREE_TYPE (datum);
1077 gcc_assert (type);
1078 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1080 tree t_field = field->as_tree ();
1081 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1082 t_field, NULL_TREE);
1083 if (loc)
1084 set_tree_location (ref, loc);
1085 return ref;
1088 /* Construct a tree for a dereference. */
1090 tree
1091 playback::context::
1092 new_dereference (tree ptr,
1093 location *loc)
1095 gcc_assert (ptr);
1097 tree type = TREE_TYPE (TREE_TYPE(ptr));
1098 tree datum = build1 (INDIRECT_REF, type, ptr);
1099 if (loc)
1100 set_tree_location (datum, loc);
1101 return datum;
1104 /* Construct a playback::lvalue instance (wrapping a tree) for a
1105 field access. */
1107 playback::lvalue *
1108 playback::lvalue::
1109 access_field (location *loc,
1110 field *field)
1112 tree datum = as_tree ();
1113 tree ref = get_context ()->new_field_access (loc, datum, field);
1114 if (!ref)
1115 return NULL;
1116 return new lvalue (get_context (), ref);
1119 /* Construct a playback::rvalue instance (wrapping a tree) for a
1120 field access. */
1122 playback::rvalue *
1123 playback::rvalue::
1124 access_field (location *loc,
1125 field *field)
1127 tree datum = as_tree ();
1128 tree ref = get_context ()->new_field_access (loc, datum, field);
1129 if (!ref)
1130 return NULL;
1131 return new rvalue (get_context (), ref);
1134 /* Construct a playback::lvalue instance (wrapping a tree) for a
1135 dereferenced field access. */
1137 playback::lvalue *
1138 playback::rvalue::
1139 dereference_field (location *loc,
1140 field *field)
1142 tree ptr = as_tree ();
1143 tree datum = get_context ()->new_dereference (ptr, loc);
1144 if (!datum)
1145 return NULL;
1146 tree ref = get_context ()->new_field_access (loc, datum, field);
1147 if (!ref)
1148 return NULL;
1149 return new lvalue (get_context (), ref);
1152 /* Construct a playback::lvalue instance (wrapping a tree) for a
1153 dereference. */
1155 playback::lvalue *
1156 playback::rvalue::
1157 dereference (location *loc)
1159 tree ptr = as_tree ();
1160 tree datum = get_context ()->new_dereference (ptr, loc);
1161 return new lvalue (get_context (), datum);
1164 /* Mark EXP saying that we need to be able to take the
1165 address of it; it should not be allocated in a register.
1166 Compare with e.g. c/c-typeck.c: c_mark_addressable. */
1168 static void
1169 jit_mark_addressable (tree exp)
1171 tree x = exp;
1173 while (1)
1174 switch (TREE_CODE (x))
1176 case COMPONENT_REF:
1177 /* (we don't yet support bitfields) */
1178 /* fallthrough */
1179 case ADDR_EXPR:
1180 case ARRAY_REF:
1181 case REALPART_EXPR:
1182 case IMAGPART_EXPR:
1183 x = TREE_OPERAND (x, 0);
1184 break;
1186 case COMPOUND_LITERAL_EXPR:
1187 case CONSTRUCTOR:
1188 TREE_ADDRESSABLE (x) = 1;
1189 return;
1191 case VAR_DECL:
1192 case CONST_DECL:
1193 case PARM_DECL:
1194 case RESULT_DECL:
1195 /* (we don't have a concept of a "register" declaration) */
1196 /* fallthrough */
1197 case FUNCTION_DECL:
1198 TREE_ADDRESSABLE (x) = 1;
1199 /* fallthrough */
1200 default:
1201 return;
1205 /* Construct a playback::rvalue instance (wrapping a tree) for an
1206 address-lookup. */
1208 playback::rvalue *
1209 playback::lvalue::
1210 get_address (location *loc)
1212 tree t_lvalue = as_tree ();
1213 tree t_thistype = TREE_TYPE (t_lvalue);
1214 tree t_ptrtype = build_pointer_type (t_thistype);
1215 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1216 if (loc)
1217 get_context ()->set_tree_location (ptr, loc);
1218 jit_mark_addressable (t_lvalue);
1219 return new rvalue (get_context (), ptr);
1222 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1223 Provide this finalization hook for calling then they are collected,
1224 which calls the finalizer vfunc. This allows them to call "release"
1225 on any vec<> within them. */
1227 static void
1228 wrapper_finalizer (void *ptr)
1230 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1231 wrapper->finalizer ();
1234 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1235 allocate them using ggc_internal_cleared_alloc. */
1237 void *
1238 playback::wrapper::
1239 operator new (size_t sz)
1241 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1245 /* Constructor for gcc:jit::playback::function. */
1247 playback::function::
1248 function (context *ctxt,
1249 tree fndecl,
1250 enum gcc_jit_function_kind kind)
1251 : m_ctxt(ctxt),
1252 m_inner_fndecl (fndecl),
1253 m_inner_bind_expr (NULL),
1254 m_kind (kind)
1256 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1258 /* Create a BIND_EXPR, and within it, a statement list. */
1259 m_stmt_list = alloc_stmt_list ();
1260 m_stmt_iter = tsi_start (m_stmt_list);
1261 m_inner_block = make_node (BLOCK);
1262 m_inner_bind_expr =
1263 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1265 else
1267 m_inner_block = NULL;
1268 m_stmt_list = NULL;
1272 /* Hand-written GC-marking hook for playback functions. */
1274 void
1275 playback::function::
1276 gt_ggc_mx ()
1278 gt_ggc_m_9tree_node (m_inner_fndecl);
1279 gt_ggc_m_9tree_node (m_inner_bind_expr);
1280 gt_ggc_m_9tree_node (m_stmt_list);
1281 gt_ggc_m_9tree_node (m_inner_block);
1284 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1285 GC-ed. */
1287 void
1288 playback::function::finalizer ()
1290 m_blocks.release ();
1293 /* Get the return type of a playback function, in tree form. */
1295 tree
1296 playback::function::
1297 get_return_type_as_tree () const
1299 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1302 /* Construct a new local within this playback::function. */
1304 playback::lvalue *
1305 playback::function::
1306 new_local (location *loc,
1307 type *type,
1308 const char *name)
1310 gcc_assert (type);
1311 gcc_assert (name);
1312 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1313 get_identifier (name),
1314 type->as_tree ());
1315 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1317 /* Prepend to BIND_EXPR_VARS: */
1318 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1319 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1321 if (loc)
1322 set_tree_location (inner, loc);
1323 return new lvalue (m_ctxt, inner);
1326 /* Construct a new block within this playback::function. */
1328 playback::block *
1329 playback::function::
1330 new_block (const char *name)
1332 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1334 block *result = new playback::block (this, name);
1335 m_blocks.safe_push (result);
1336 return result;
1339 /* Build a statement list for the function as a whole out of the
1340 lists of statements for the individual blocks, building labels
1341 for each block. */
1343 void
1344 playback::function::
1345 build_stmt_list ()
1347 int i;
1348 block *b;
1350 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1352 FOR_EACH_VEC_ELT (m_blocks, i, b)
1354 int j;
1355 tree stmt;
1357 b->m_label_expr = build1 (LABEL_EXPR,
1358 void_type_node,
1359 b->as_label_decl ());
1360 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1362 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1363 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1367 /* Finish compiling the given function, potentially running the
1368 garbage-collector.
1369 The function will have a statement list by now.
1370 Amongst other things, this gimplifies the statement list,
1371 and calls cgraph_node::finalize_function on the function. */
1373 void
1374 playback::function::
1375 postprocess ()
1377 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1379 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1380 debug_tree (m_stmt_list);
1382 /* Do we need this to force cgraphunit.c to output the function? */
1383 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1385 DECL_EXTERNAL (m_inner_fndecl) = 0;
1386 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1389 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1390 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1392 DECL_EXTERNAL (m_inner_fndecl) = 0;
1393 TREE_PUBLIC (m_inner_fndecl) = 0;
1396 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1398 /* Seem to need this in gimple-low.c: */
1399 gcc_assert (m_inner_block);
1400 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1402 /* how to add to function? the following appears to be how to
1403 set the body of a m_inner_fndecl: */
1404 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1406 /* Ensure that locals appear in the debuginfo. */
1407 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1409 //debug_tree (m_inner_fndecl);
1411 /* Convert to gimple: */
1412 //printf("about to gimplify_function_tree\n");
1413 gimplify_function_tree (m_inner_fndecl);
1414 //printf("finished gimplify_function_tree\n");
1416 current_function_decl = m_inner_fndecl;
1417 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1418 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1419 //debug_tree (m_inner_fndecl);
1421 //printf("about to add to cgraph\n");
1422 /* Add to cgraph: */
1423 cgraph_node::finalize_function (m_inner_fndecl, false);
1424 /* This can trigger a collection, so we need to have all of
1425 the funcs as roots. */
1427 current_function_decl = NULL;
1431 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1432 GC-ed. */
1434 void
1435 playback::block::finalizer ()
1437 m_stmts.release ();
1440 /* Add an eval of the rvalue to the function's statement list. */
1442 void
1443 playback::block::
1444 add_eval (location *loc,
1445 rvalue *rvalue)
1447 gcc_assert (rvalue);
1449 if (loc)
1450 set_tree_location (rvalue->as_tree (), loc);
1452 add_stmt (rvalue->as_tree ());
1455 /* Add an assignment to the function's statement list. */
1457 void
1458 playback::block::
1459 add_assignment (location *loc,
1460 lvalue *lvalue,
1461 rvalue *rvalue)
1463 gcc_assert (lvalue);
1464 gcc_assert (rvalue);
1466 tree t_lvalue = lvalue->as_tree ();
1467 tree t_rvalue = rvalue->as_tree ();
1468 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1470 t_rvalue = build1 (CONVERT_EXPR,
1471 TREE_TYPE (t_lvalue),
1472 t_rvalue);
1473 if (loc)
1474 set_tree_location (t_rvalue, loc);
1477 tree stmt =
1478 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1479 t_lvalue, t_rvalue);
1480 if (loc)
1481 set_tree_location (stmt, loc);
1482 add_stmt (stmt);
1485 /* Add a comment to the function's statement list.
1486 For now this is done by adding a dummy label. */
1488 void
1489 playback::block::
1490 add_comment (location *loc,
1491 const char *text)
1493 /* Wrap the text in C-style comment delimiters. */
1494 size_t sz =
1495 (3 /* opening delim */
1496 + strlen (text)
1497 + 3 /* closing delim */
1498 + 1 /* terminator */);
1499 char *wrapped = (char *)ggc_internal_alloc (sz);
1500 snprintf (wrapped, sz, "/* %s */", text);
1502 /* For now we simply implement this by adding a dummy label with a name
1503 containing the given text. */
1504 tree identifier = get_identifier (wrapped);
1505 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1506 identifier, void_type_node);
1507 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1509 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1510 if (loc)
1511 set_tree_location (label_expr, loc);
1512 add_stmt (label_expr);
1515 /* Add a conditional jump statement to the function's statement list. */
1517 void
1518 playback::block::
1519 add_conditional (location *loc,
1520 rvalue *boolval,
1521 block *on_true,
1522 block *on_false)
1524 gcc_assert (boolval);
1525 gcc_assert (on_true);
1526 gcc_assert (on_false);
1528 /* COND_EXPR wants statement lists for the true/false operands, but we
1529 want labels.
1530 Shim it by creating jumps to the labels */
1531 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1532 on_true->as_label_decl ());
1533 if (loc)
1534 set_tree_location (true_jump, loc);
1536 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1537 on_false->as_label_decl ());
1538 if (loc)
1539 set_tree_location (false_jump, loc);
1541 tree stmt =
1542 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1543 true_jump, false_jump);
1544 if (loc)
1545 set_tree_location (stmt, loc);
1546 add_stmt (stmt);
1549 /* Add an unconditional jump statement to the function's statement list. */
1551 void
1552 playback::block::
1553 add_jump (location *loc,
1554 block *target)
1556 gcc_assert (target);
1558 // see c_finish_loop
1559 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1560 //add_stmt (top);
1562 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1563 TREE_USED (target->as_label_decl ()) = 1;
1564 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1565 if (loc)
1566 set_tree_location (stmt, loc);
1567 add_stmt (stmt);
1570 from c-typeck.c:
1571 tree
1572 c_finish_goto_label (location_t loc, tree label)
1574 tree decl = lookup_label_for_goto (loc, label);
1575 if (!decl)
1576 return NULL_TREE;
1577 TREE_USED (decl) = 1;
1579 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1580 SET_EXPR_LOCATION (t, loc);
1581 return add_stmt (t);
1588 /* Add a return statement to the function's statement list. */
1590 void
1591 playback::block::
1592 add_return (location *loc,
1593 rvalue *rvalue)
1595 tree modify_retval = NULL;
1596 tree return_type = m_func->get_return_type_as_tree ();
1597 if (rvalue)
1599 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1600 tree t_rvalue = rvalue->as_tree ();
1601 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1602 t_rvalue = build1 (CONVERT_EXPR,
1603 TREE_TYPE (t_lvalue),
1604 t_rvalue);
1605 modify_retval = build2 (MODIFY_EXPR, return_type,
1606 t_lvalue, t_rvalue);
1607 if (loc)
1608 set_tree_location (modify_retval, loc);
1610 tree return_stmt = build1 (RETURN_EXPR, return_type,
1611 modify_retval);
1612 if (loc)
1613 set_tree_location (return_stmt, loc);
1615 add_stmt (return_stmt);
1618 /* Helper function for playback::block::add_switch.
1619 Construct a case label for the given range, followed by a goto stmt
1620 to the given block, appending them to stmt list *ptr_t_switch_body. */
1622 static void
1623 add_case (tree *ptr_t_switch_body,
1624 tree t_low_value,
1625 tree t_high_value,
1626 playback::block *dest_block)
1628 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
1629 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
1631 tree t_case_label =
1632 build_case_label (t_low_value, t_high_value, t_label);
1633 append_to_statement_list (t_case_label, ptr_t_switch_body);
1635 tree t_goto_stmt =
1636 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
1637 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
1640 /* Add a switch statement to the function's statement list.
1642 My initial attempt at implementing this constructed a TREE_VEC
1643 of the cases and set it as SWITCH_LABELS (switch_expr). However,
1644 gimplify.c:gimplify_switch_expr is set up to deal with SWITCH_BODY, and
1645 doesn't have any logic for gimplifying SWITCH_LABELS.
1647 Hence we create a switch body, and populate it with case labels, each
1648 followed by a goto to the desired block. */
1650 void
1651 playback::block::
1652 add_switch (location *loc,
1653 rvalue *expr,
1654 block *default_block,
1655 const auto_vec <case_> *cases)
1657 /* Compare with:
1658 - c/c-typeck.c: c_start_case
1659 - c-family/c-common.c:c_add_case_label
1660 - java/expr.c:expand_java_switch and expand_java_add_case
1661 We've already rejected overlaps and duplicates in
1662 libgccjit.c:case_range_validator::validate. */
1664 tree t_expr = expr->as_tree ();
1665 tree t_type = TREE_TYPE (t_expr);
1667 tree t_switch_body = alloc_stmt_list ();
1669 int i;
1670 case_ *c;
1671 FOR_EACH_VEC_ELT (*cases, i, c)
1673 tree t_low_value = c->m_min_value->as_tree ();
1674 tree t_high_value = c->m_max_value->as_tree ();
1675 add_case (&t_switch_body,
1676 t_low_value,
1677 t_high_value,
1678 c->m_dest_block);
1680 /* Default label. */
1681 add_case (&t_switch_body,
1682 NULL_TREE, NULL_TREE,
1683 default_block);
1685 tree switch_stmt = build3 (SWITCH_EXPR, t_type, t_expr,
1686 t_switch_body, NULL_TREE);
1687 if (loc)
1688 set_tree_location (switch_stmt, loc);
1689 add_stmt (switch_stmt);
1692 /* Constructor for gcc::jit::playback::block. */
1694 playback::block::
1695 block (function *func,
1696 const char *name)
1697 : m_func (func),
1698 m_stmts ()
1700 tree identifier;
1702 gcc_assert (func);
1703 // name can be NULL
1704 if (name)
1705 identifier = get_identifier (name);
1706 else
1707 identifier = NULL;
1708 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1709 identifier, void_type_node);
1710 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1711 m_label_expr = NULL;
1714 /* A subclass of auto_vec <char *> that frees all of its elements on
1715 deletion. */
1717 class auto_argvec : public auto_vec <char *>
1719 public:
1720 ~auto_argvec ();
1723 /* auto_argvec's dtor, freeing all contained strings, automatically
1724 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1726 auto_argvec::~auto_argvec ()
1728 int i;
1729 char *str;
1730 FOR_EACH_VEC_ELT (*this, i, str)
1731 free (str);
1734 /* Compile a playback::context:
1736 - Use the context's options to cconstruct command-line options, and
1737 call into the rest of GCC (toplev::main).
1738 - Assuming it succeeds, we have a .s file.
1739 - We then run the "postprocess" vfunc:
1741 (A) In-memory compile ("gcc_jit_context_compile")
1743 For an in-memory compile we have the playback::compile_to_memory
1744 subclass; "postprocess" will convert the .s file to a .so DSO,
1745 and load it in memory (via dlopen), wrapping the result up as
1746 a jit::result and returning it.
1748 (B) Compile to file ("gcc_jit_context_compile_to_file")
1750 When compiling to a file, we have the playback::compile_to_file
1751 subclass; "postprocess" will either copy the .s file to the
1752 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1753 the driver to convert it as necessary, copying the result. */
1755 void
1756 playback::context::
1757 compile ()
1759 JIT_LOG_SCOPE (get_logger ());
1761 const char *ctxt_progname;
1763 int keep_intermediates =
1764 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
1766 m_tempdir = new tempdir (get_logger (), keep_intermediates);
1767 if (!m_tempdir->create ())
1768 return;
1770 /* Call into the rest of gcc.
1771 For now, we have to assemble command-line options to pass into
1772 toplev::main, so that they can be parsed. */
1774 /* Pass in user-provided program name as argv0, if any, so that it
1775 makes it into GCC's "progname" global, used in various diagnostics. */
1776 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1778 if (!ctxt_progname)
1779 ctxt_progname = "libgccjit.so";
1781 auto_vec <recording::requested_dump> requested_dumps;
1782 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1784 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1785 acquire_mutex ();
1787 auto_argvec fake_args;
1788 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
1789 if (errors_occurred ())
1791 release_mutex ();
1792 return;
1795 /* This runs the compiler. */
1796 toplev toplev (false, /* use_TV_TOTAL */
1797 false); /* init_signals */
1798 enter_scope ("toplev::main");
1799 if (get_logger ())
1800 for (unsigned i = 0; i < fake_args.length (); i++)
1801 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
1802 toplev.main (fake_args.length (),
1803 const_cast <char **> (fake_args.address ()));
1804 exit_scope ("toplev::main");
1806 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1807 need to do it between toplev::main (which creates the dump manager)
1808 and toplev::finalize (which deletes it). */
1809 extract_any_requested_dumps (&requested_dumps);
1811 /* Clean up the compiler. */
1812 enter_scope ("toplev::finalize");
1813 toplev.finalize ();
1814 exit_scope ("toplev::finalize");
1816 /* Ideally we would release the jit mutex here, but we can't yet since
1817 followup activities use timevars, which are global state. */
1819 if (errors_occurred ())
1821 release_mutex ();
1822 return;
1825 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1826 dump_generated_code ();
1828 /* We now have a .s file.
1830 Run any postprocessing steps. This will either convert the .s file to
1831 a .so DSO, and load it in memory (playback::compile_to_memory), or
1832 convert the .s file to the requested output format, and copy it to a
1833 given file (playback::compile_to_file). */
1834 postprocess (ctxt_progname);
1836 release_mutex ();
1839 /* Implementation of class gcc::jit::playback::compile_to_memory,
1840 a subclass of gcc::jit::playback::context. */
1842 /* playback::compile_to_memory's trivial constructor. */
1844 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
1845 playback::context (ctxt),
1846 m_result (NULL)
1848 JIT_LOG_SCOPE (get_logger ());
1851 /* Implementation of the playback::context::process vfunc for compiling
1852 to memory.
1854 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1855 wrapping the result up as a jit::result and returning it. */
1857 void
1858 playback::compile_to_memory::postprocess (const char *ctxt_progname)
1860 JIT_LOG_SCOPE (get_logger ());
1861 convert_to_dso (ctxt_progname);
1862 if (errors_occurred ())
1863 return;
1864 m_result = dlopen_built_dso ();
1867 /* Implementation of class gcc::jit::playback::compile_to_file,
1868 a subclass of gcc::jit::playback::context. */
1870 /* playback::compile_to_file's trivial constructor. */
1872 playback::compile_to_file::compile_to_file (recording::context *ctxt,
1873 enum gcc_jit_output_kind output_kind,
1874 const char *output_path) :
1875 playback::context (ctxt),
1876 m_output_kind (output_kind),
1877 m_output_path (output_path)
1879 JIT_LOG_SCOPE (get_logger ());
1882 /* Implementation of the playback::context::process vfunc for compiling
1883 to a file.
1885 Either copy the .s file to the given destination (for
1886 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1887 as necessary, copying the result. */
1889 void
1890 playback::compile_to_file::postprocess (const char *ctxt_progname)
1892 JIT_LOG_SCOPE (get_logger ());
1894 /* The driver takes different actions based on the filename, so
1895 we provide a filename with an appropriate suffix for the
1896 output kind, and then copy it up to the user-provided path,
1897 rather than directly compiling it to the requested output path. */
1899 switch (m_output_kind)
1901 default:
1902 gcc_unreachable ();
1904 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
1905 copy_file (get_tempdir ()->get_path_s_file (),
1906 m_output_path);
1907 break;
1909 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
1911 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
1912 "/fake.o",
1913 NULL);
1914 invoke_driver (ctxt_progname,
1915 get_tempdir ()->get_path_s_file (),
1916 tmp_o_path,
1917 TV_ASSEMBLE,
1918 false, /* bool shared, */
1919 false);/* bool run_linker */
1920 if (!errors_occurred ())
1921 copy_file (tmp_o_path,
1922 m_output_path);
1923 free (tmp_o_path);
1925 break;
1927 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
1928 invoke_driver (ctxt_progname,
1929 get_tempdir ()->get_path_s_file (),
1930 get_tempdir ()->get_path_so_file (),
1931 TV_ASSEMBLE,
1932 true, /* bool shared, */
1933 true);/* bool run_linker */
1934 if (!errors_occurred ())
1935 copy_file (get_tempdir ()->get_path_so_file (),
1936 m_output_path);
1937 break;
1939 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
1941 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
1942 "/fake.exe",
1943 NULL);
1944 invoke_driver (ctxt_progname,
1945 get_tempdir ()->get_path_s_file (),
1946 tmp_exe_path,
1947 TV_ASSEMBLE,
1948 false, /* bool shared, */
1949 true);/* bool run_linker */
1950 if (!errors_occurred ())
1951 copy_file (tmp_exe_path,
1952 m_output_path);
1953 free (tmp_exe_path);
1955 break;
1961 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
1962 the "executable" bits).
1964 Any errors that occur are reported on the context and hence count as
1965 a failure of the compile.
1967 We can't in general hardlink or use "rename" from the tempdir since
1968 it might be on a different filesystem to the destination. For example,
1969 I get EXDEV: "Invalid cross-device link". */
1971 void
1972 playback::compile_to_file::copy_file (const char *src_path,
1973 const char *dst_path)
1975 JIT_LOG_SCOPE (get_logger ());
1976 if (get_logger ())
1978 get_logger ()->log ("src_path: %s", src_path);
1979 get_logger ()->log ("dst_path: %s", dst_path);
1982 FILE *f_in = NULL;
1983 FILE *f_out = NULL;
1984 size_t total_sz_in = 0;
1985 size_t total_sz_out = 0;
1986 char buf[4096];
1987 size_t sz_in;
1988 struct stat stat_buf;
1990 f_in = fopen (src_path, "rb");
1991 if (!f_in)
1993 add_error (NULL,
1994 "unable to open %s for reading: %s",
1995 src_path,
1996 xstrerror (errno));
1997 return;
2000 /* Use stat on the filedescriptor to get the mode,
2001 so that we can copy it over (in particular, the
2002 "executable" bits). */
2003 if (-1 == fstat (fileno (f_in), &stat_buf))
2005 add_error (NULL,
2006 "unable to fstat %s: %s",
2007 src_path,
2008 xstrerror (errno));
2009 fclose (f_in);
2010 return;
2013 f_out = fopen (dst_path, "wb");
2014 if (!f_out)
2016 add_error (NULL,
2017 "unable to open %s for writing: %s",
2018 dst_path,
2019 xstrerror (errno));
2020 fclose (f_in);
2021 return;
2024 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2026 total_sz_in += sz_in;
2027 size_t sz_out_remaining = sz_in;
2028 size_t sz_out_so_far = 0;
2029 while (sz_out_remaining)
2031 size_t sz_out = fwrite (buf + sz_out_so_far,
2033 sz_out_remaining,
2034 f_out);
2035 gcc_assert (sz_out <= sz_out_remaining);
2036 if (!sz_out)
2038 add_error (NULL,
2039 "error writing to %s: %s",
2040 dst_path,
2041 xstrerror (errno));
2042 fclose (f_in);
2043 fclose (f_out);
2044 return;
2046 total_sz_out += sz_out;
2047 sz_out_so_far += sz_out;
2048 sz_out_remaining -= sz_out;
2050 gcc_assert (sz_out_so_far == sz_in);
2053 if (!feof (f_in))
2054 add_error (NULL,
2055 "error reading from %s: %s",
2056 src_path,
2057 xstrerror (errno));
2059 fclose (f_in);
2061 gcc_assert (total_sz_in == total_sz_out);
2062 if (get_logger ())
2063 get_logger ()->log ("total bytes copied: %ld", total_sz_out);
2065 /* Set the permissions of the copy to those of the original file,
2066 in particular the "executable" bits. */
2067 if (-1 == fchmod (fileno (f_out), stat_buf.st_mode))
2068 add_error (NULL,
2069 "error setting mode of %s: %s",
2070 dst_path,
2071 xstrerror (errno));
2073 fclose (f_out);
2076 /* Helper functions for gcc::jit::playback::context::compile. */
2078 /* This mutex guards gcc::jit::recording::context::compile, so that only
2079 one thread can be accessing the bulk of GCC's state at once. */
2081 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2083 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2085 void
2086 playback::context::acquire_mutex ()
2088 /* Acquire the big GCC mutex. */
2089 JIT_LOG_SCOPE (get_logger ());
2090 pthread_mutex_lock (&jit_mutex);
2091 gcc_assert (NULL == active_playback_ctxt);
2092 active_playback_ctxt = this;
2095 /* Release jit_mutex and clear the active playback ctxt. */
2097 void
2098 playback::context::release_mutex ()
2100 /* Release the big GCC mutex. */
2101 JIT_LOG_SCOPE (get_logger ());
2102 gcc_assert (active_playback_ctxt == this);
2103 active_playback_ctxt = NULL;
2104 pthread_mutex_unlock (&jit_mutex);
2107 /* Callback used by gcc::jit::playback::context::make_fake_args when
2108 invoking driver_get_configure_time_options.
2109 Populate a vec <char * > with the configure-time options. */
2111 static void
2112 append_arg_from_driver (const char *option, void *user_data)
2114 gcc_assert (option);
2115 gcc_assert (user_data);
2116 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2117 argvec->safe_push (concat ("-", option, NULL));
2120 /* Build a fake argv for toplev::main from the options set
2121 by the user on the context . */
2123 void
2124 playback::context::
2125 make_fake_args (vec <char *> *argvec,
2126 const char *ctxt_progname,
2127 vec <recording::requested_dump> *requested_dumps)
2129 JIT_LOG_SCOPE (get_logger ());
2131 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2132 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2134 ADD_ARG (ctxt_progname);
2135 ADD_ARG (get_path_c_file ());
2136 ADD_ARG ("-fPIC");
2138 /* Handle int options: */
2139 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2141 default:
2142 add_error (NULL,
2143 "unrecognized optimization level: %i",
2144 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2145 return;
2147 case 0:
2148 ADD_ARG ("-O0");
2149 break;
2151 case 1:
2152 ADD_ARG ("-O1");
2153 break;
2155 case 2:
2156 ADD_ARG ("-O2");
2157 break;
2159 case 3:
2160 ADD_ARG ("-O3");
2161 break;
2163 /* What about -Os? */
2165 /* Handle bool options: */
2166 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2167 ADD_ARG ("-g");
2169 /* Suppress timing (and other) info. */
2170 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2172 ADD_ARG ("-quiet");
2173 quiet_flag = 1;
2176 /* Aggressively garbage-collect, to shake out bugs: */
2177 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2179 ADD_ARG ("--param");
2180 ADD_ARG ("ggc-min-expand=0");
2181 ADD_ARG ("--param");
2182 ADD_ARG ("ggc-min-heapsize=0");
2185 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2187 ADD_ARG ("-fdump-tree-all");
2188 ADD_ARG ("-fdump-rtl-all");
2189 ADD_ARG ("-fdump-ipa-all");
2192 /* Add "-fdump-" options for any calls to
2193 gcc_jit_context_enable_dump. */
2195 int i;
2196 recording::requested_dump *d;
2197 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2199 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2200 ADD_ARG_TAKE_OWNERSHIP (arg);
2204 /* PR jit/64810: Add any target-specific default options
2205 from OPTION_DEFAULT_SPECS, normally provided by the driver
2206 in the non-jit case.
2208 The target-specific code can define OPTION_DEFAULT_SPECS:
2209 default command options in the form of spec macros for the
2210 driver to expand ().
2212 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2213 if not overriden, injects the defaults as extra arguments to
2214 cc1 etc.
2215 For the jit case, we need to add these arguments here. The
2216 input format (using the specs language) means that we have to run
2217 part of the driver code here (driver_get_configure_time_options).
2219 To avoid running the spec-expansion code every time, we just do
2220 it the first time (via a function-static flag), saving the result
2221 into a function-static vec.
2222 This flag and vec are global state (i.e. per-process).
2223 They are guarded by the jit mutex. */
2225 static bool have_configure_time_options = false;
2226 static vec <char *> configure_time_options;
2228 if (have_configure_time_options)
2229 log ("reusing cached configure-time options");
2230 else
2232 have_configure_time_options = true;
2233 log ("getting configure-time options from driver");
2234 driver_get_configure_time_options (append_arg_from_driver,
2235 &configure_time_options);
2238 int i;
2239 char *opt;
2241 if (get_logger ())
2242 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2243 log ("configure_time_options[%i]: %s", i, opt);
2245 /* configure_time_options should now contain the expanded options
2246 from OPTION_DEFAULT_SPECS (if any). */
2247 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2249 gcc_assert (opt);
2250 gcc_assert (opt[0] == '-');
2251 ADD_ARG (opt);
2255 /* Add any user-provided extra options, starting with any from
2256 parent contexts. */
2257 m_recording_ctxt->append_command_line_options (argvec);
2259 #undef ADD_ARG
2260 #undef ADD_ARG_TAKE_OWNERSHIP
2263 /* The second half of the implementation of gcc_jit_context_enable_dump.
2264 Iterate through the requested dumps, reading the underlying files
2265 into heap-allocated buffers, writing pointers to the buffers into
2266 the char ** pointers provided by client code.
2267 Client code is responsible for calling free on the results. */
2269 void
2270 playback::context::
2271 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2273 JIT_LOG_SCOPE (get_logger ());
2275 int i;
2276 recording::requested_dump *d;
2277 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2279 dump_file_info *dfi;
2280 char *filename;
2281 char *content;
2283 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2284 if (!dfi)
2286 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2287 continue;
2290 filename = g->get_dumps ()->get_dump_file_name (dfi);
2291 content = read_dump_file (filename);
2292 *(d->m_out_ptr) = content;
2293 free (filename);
2297 /* Helper function for playback::context::extract_any_requested_dumps
2298 (itself for use in implementation of gcc_jit_context_enable_dump).
2300 Attempt to read the complete file at the given path, returning the
2301 bytes found there as a buffer.
2302 The caller is responsible for calling free on the result.
2303 Errors will be reported on the context, and lead to NULL being
2304 returned; an out-of-memory error will terminate the process. */
2306 char *
2307 playback::context::read_dump_file (const char *path)
2309 char *result = NULL;
2310 size_t total_sz = 0;
2311 char buf[4096];
2312 size_t sz;
2313 FILE *f_in;
2315 f_in = fopen (path, "r");
2316 if (!f_in)
2318 add_error (NULL, "unable to open %s for reading", path);
2319 return NULL;
2322 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2324 size_t old_total_sz = total_sz;
2325 total_sz += sz;
2326 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2327 memcpy (result + old_total_sz, buf, sz);
2330 if (!feof (f_in))
2332 add_error (NULL, "error reading from %s", path);
2333 free (result);
2334 fclose (f_in);
2335 return NULL;
2338 fclose (f_in);
2340 if (result)
2342 result[total_sz] = '\0';
2343 return result;
2345 else
2346 return xstrdup ("");
2349 /* Part of playback::context::compile ().
2351 We have a .s file; we want a .so file.
2352 We could reuse parts of gcc/gcc.c to do this.
2353 For now, just use the driver binary from the install, as
2354 named in gcc-driver-name.h
2355 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2357 void
2358 playback::context::
2359 convert_to_dso (const char *ctxt_progname)
2361 JIT_LOG_SCOPE (get_logger ());
2363 invoke_driver (ctxt_progname,
2364 m_tempdir->get_path_s_file (),
2365 m_tempdir->get_path_so_file (),
2366 TV_ASSEMBLE,
2367 true, /* bool shared, */
2368 true);/* bool run_linker */
2371 void
2372 playback::context::
2373 invoke_driver (const char *ctxt_progname,
2374 const char *input_file,
2375 const char *output_file,
2376 timevar_id_t tv_id,
2377 bool shared,
2378 bool run_linker)
2380 JIT_LOG_SCOPE (get_logger ());
2381 /* Currently this lumps together both assembling and linking into
2382 TV_ASSEMBLE. */
2383 auto_timevar assemble_timevar (tv_id);
2384 const char *errmsg;
2385 auto_vec <const char *> argvec;
2386 #define ADD_ARG(arg) argvec.safe_push (arg)
2387 int exit_status = 0;
2388 int err = 0;
2389 const char *gcc_driver_name = GCC_DRIVER_NAME;
2391 ADD_ARG (gcc_driver_name);
2393 if (shared)
2394 ADD_ARG ("-shared");
2396 if (!run_linker)
2397 ADD_ARG ("-c");
2399 ADD_ARG (input_file);
2400 ADD_ARG ("-o");
2401 ADD_ARG (output_file);
2403 /* Don't use the linker plugin.
2404 If running with just a "make" and not a "make install", then we'd
2405 run into
2406 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2407 libto_plugin is a .la at build time, with it becoming installed with
2408 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2409 time. */
2410 ADD_ARG ("-fno-use-linker-plugin");
2412 /* pex argv arrays are NULL-terminated. */
2413 ADD_ARG (NULL);
2415 /* pex_one's error-handling requires pname to be non-NULL. */
2416 gcc_assert (ctxt_progname);
2418 if (get_logger ())
2419 for (unsigned i = 0; i < argvec.length (); i++)
2420 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2422 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2423 gcc_driver_name,
2424 const_cast <char *const *> (argvec.address ()),
2425 ctxt_progname, /* const char *pname */
2426 NULL, /* const char *outname */
2427 NULL, /* const char *errname */
2428 &exit_status, /* int *status */
2429 &err); /* int *err*/
2430 if (errmsg)
2432 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2433 return;
2436 /* pex_one can return a NULL errmsg when the executable wasn't
2437 found (or doesn't exist), so trap these cases also. */
2438 if (exit_status || err)
2440 add_error (NULL,
2441 "error invoking gcc driver: exit_status: %i err: %i",
2442 exit_status, err);
2443 add_error (NULL,
2444 "whilst attempting to run a driver named: %s",
2445 gcc_driver_name);
2446 add_error (NULL,
2447 "PATH was: %s",
2448 getenv ("PATH"));
2449 return;
2451 #undef ADD_ARG
2454 /* Dynamically-link the built DSO file into this process, using dlopen.
2455 Wrap it up within a jit::result *, and return that.
2456 Return NULL if any errors occur, reporting them on this context. */
2458 result *
2459 playback::context::
2460 dlopen_built_dso ()
2462 JIT_LOG_SCOPE (get_logger ());
2463 auto_timevar load_timevar (TV_LOAD);
2464 void *handle = NULL;
2465 const char *error = NULL;
2466 result *result_obj = NULL;
2468 /* Clear any existing error. */
2469 dlerror ();
2471 handle = dlopen (m_tempdir->get_path_so_file (),
2472 RTLD_NOW | RTLD_LOCAL);
2473 if ((error = dlerror()) != NULL) {
2474 add_error (NULL, "%s", error);
2476 if (handle)
2478 /* We've successfully dlopened the result; create a
2479 jit::result object to wrap it.
2481 We're done with the tempdir for now, but if the user
2482 has requested debugging, the user's debugger might not
2483 be capable of dealing with the .so file being unlinked
2484 immediately, so keep it around until after the result
2485 is released. We do this by handing over ownership of
2486 the jit::tempdir to the result. See PR jit/64206. */
2487 tempdir *handover_tempdir;
2488 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2490 handover_tempdir = m_tempdir;
2491 m_tempdir = NULL;
2492 /* The tempdir will eventually be cleaned up in the
2493 jit::result's dtor. */
2494 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2495 " handing over tempdir to jit::result");
2497 else
2499 handover_tempdir = NULL;
2500 /* ... and retain ownership of m_tempdir so we clean it
2501 up it the playback::context's dtor. */
2502 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2503 " retaining ownership of tempdir");
2506 result_obj = new result (get_logger (), handle, handover_tempdir);
2508 else
2509 result_obj = NULL;
2511 return result_obj;
2514 /* Top-level hook for playing back a recording context.
2516 This plays back m_recording_ctxt, and, if no errors
2517 occurred builds statement lists for and then postprocesses
2518 every function in the result. */
2520 void
2521 playback::context::
2522 replay ()
2524 JIT_LOG_SCOPE (get_logger ());
2525 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2526 tree array_domain_type = build_index_type (size_int (200));
2527 m_char_array_type_node
2528 = build_array_type (char_type_node, array_domain_type);
2530 m_const_char_ptr
2531 = build_pointer_type (build_qualified_type (char_type_node,
2532 TYPE_QUAL_CONST));
2534 /* Replay the recorded events: */
2535 timevar_push (TV_JIT_REPLAY);
2537 m_recording_ctxt->replay_into (this);
2539 /* Clean away the temporary references from recording objects
2540 to playback objects. We have to do this now since the
2541 latter are GC-allocated, but the former don't mark these
2542 refs. Hence we must stop using them before the GC can run. */
2543 m_recording_ctxt->disassociate_from_playback ();
2545 /* The builtins_manager, if any, is associated with the recording::context
2546 and might be reused for future compiles on other playback::contexts,
2547 but its m_attributes array is not GTY-labeled and hence will become
2548 nonsense if the GC runs. Purge this state. */
2549 builtins_manager *bm = get_builtins_manager ();
2550 if (bm)
2551 bm->finish_playback ();
2553 timevar_pop (TV_JIT_REPLAY);
2555 if (!errors_occurred ())
2557 int i;
2558 function *func;
2560 /* No GC can happen yet; process the cached source locations. */
2561 handle_locations ();
2563 /* We've now created tree nodes for the stmts in the various blocks
2564 in each function, but we haven't built each function's single stmt
2565 list yet. Do so now. */
2566 FOR_EACH_VEC_ELT (m_functions, i, func)
2567 func->build_stmt_list ();
2569 /* No GC can have happened yet. */
2571 /* Postprocess the functions. This could trigger GC. */
2572 FOR_EACH_VEC_ELT (m_functions, i, func)
2574 gcc_assert (func);
2575 func->postprocess ();
2580 /* Dump the generated .s file to stderr. */
2582 void
2583 playback::context::
2584 dump_generated_code ()
2586 JIT_LOG_SCOPE (get_logger ());
2587 char buf[4096];
2588 size_t sz;
2589 FILE *f_in = fopen (get_path_s_file (), "r");
2590 if (!f_in)
2591 return;
2593 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2594 fwrite (buf, 1, sz, stderr);
2596 fclose (f_in);
2599 /* Get the supposed path of the notional "fake.c" file within the
2600 tempdir. This file doesn't exist, but the rest of the compiler
2601 needs a name. */
2603 const char *
2604 playback::context::
2605 get_path_c_file () const
2607 return m_tempdir->get_path_c_file ();
2610 /* Get the path of the assembler output file "fake.s" file within the
2611 tempdir. */
2613 const char *
2614 playback::context::
2615 get_path_s_file () const
2617 return m_tempdir->get_path_s_file ();
2620 /* Get the path of the DSO object file "fake.so" file within the
2621 tempdir. */
2623 const char *
2624 playback::context::
2625 get_path_so_file () const
2627 return m_tempdir->get_path_so_file ();
2630 /* qsort comparator for comparing pairs of playback::source_line *,
2631 ordering them by line number. */
2633 static int
2634 line_comparator (const void *lhs, const void *rhs)
2636 const playback::source_line *line_lhs = \
2637 *static_cast<const playback::source_line * const*> (lhs);
2638 const playback::source_line *line_rhs = \
2639 *static_cast<const playback::source_line * const*> (rhs);
2640 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2643 /* qsort comparator for comparing pairs of playback::location *,
2644 ordering them by column number. */
2646 static int
2647 location_comparator (const void *lhs, const void *rhs)
2649 const playback::location *loc_lhs = \
2650 *static_cast<const playback::location * const *> (lhs);
2651 const playback::location *loc_rhs = \
2652 *static_cast<const playback::location * const *> (rhs);
2653 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2656 /* Our API allows locations to be created in arbitrary orders, but the
2657 linemap API requires locations to be created in ascending order
2658 as if we were tokenizing files.
2660 This hook sorts all of the locations that have been created, and
2661 calls into the linemap API, creating linemap entries in sorted order
2662 for our locations. */
2664 void
2665 playback::context::
2666 handle_locations ()
2668 /* Create the source code locations, following the ordering rules
2669 imposed by the linemap API.
2671 line_table is a global. */
2672 JIT_LOG_SCOPE (get_logger ());
2673 int i;
2674 source_file *file;
2676 FOR_EACH_VEC_ELT (m_source_files, i, file)
2678 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2680 /* Sort lines by ascending line numbers. */
2681 file->m_source_lines.qsort (&line_comparator);
2683 int j;
2684 source_line *line;
2685 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2687 int k;
2688 location *loc;
2690 /* Sort locations in line by ascending column numbers. */
2691 line->m_locations.qsort (&location_comparator);
2693 /* Determine maximum column within this line. */
2694 gcc_assert (line->m_locations.length () > 0);
2695 location *final_column =
2696 line->m_locations[line->m_locations.length () - 1];
2697 int max_col = final_column->get_column_num ();
2699 linemap_line_start (line_table, line->get_line_num (), max_col);
2700 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2702 loc->m_srcloc = \
2703 linemap_position_for_column (line_table, loc->get_column_num ());
2707 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2710 /* line_table should now be populated; every playback::location should
2711 now have an m_srcloc. */
2713 /* Now assign them to tree nodes as appropriate. */
2714 std::pair<tree, location *> *cached_location;
2716 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2718 tree t = cached_location->first;
2719 source_location srcloc = cached_location->second->m_srcloc;
2721 /* This covers expressions: */
2722 if (CAN_HAVE_LOCATION_P (t))
2723 SET_EXPR_LOCATION (t, srcloc);
2724 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2725 DECL_SOURCE_LOCATION (t) = srcloc;
2726 else
2728 /* Don't know how to set location on this node. */
2733 /* We handle errors on a playback::context by adding them to the
2734 corresponding recording::context. */
2736 void
2737 playback::context::
2738 add_error (location *loc, const char *fmt, ...)
2740 va_list ap;
2741 va_start (ap, fmt);
2742 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2743 fmt, ap);
2744 va_end (ap);
2747 /* We handle errors on a playback::context by adding them to the
2748 corresponding recording::context. */
2750 void
2751 playback::context::
2752 add_error_va (location *loc, const char *fmt, va_list ap)
2754 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2755 fmt, ap);
2758 /* Dealing with the linemap API. */
2760 /* Construct a playback::location for a recording::location, if it
2761 doesn't exist already. */
2763 playback::location *
2764 playback::context::
2765 new_location (recording::location *rloc,
2766 const char *filename,
2767 int line,
2768 int column)
2770 /* Get the source_file for filename, creating if necessary. */
2771 source_file *src_file = get_source_file (filename);
2772 /* Likewise for the line within the file. */
2773 source_line *src_line = src_file->get_source_line (line);
2774 /* Likewise for the column within the line. */
2775 location *loc = src_line->get_location (rloc, column);
2776 return loc;
2779 /* Deferred setting of the location for a given tree, by adding the
2780 (tree, playback::location) pair to a list of deferred associations.
2781 We will actually set the location on the tree later on once
2782 the source_location for the playback::location exists. */
2784 void
2785 playback::context::
2786 set_tree_location (tree t, location *loc)
2788 gcc_assert (loc);
2789 m_cached_locations.safe_push (std::make_pair (t, loc));
2793 /* Construct a playback::source_file for the given source
2794 filename, if it doesn't exist already. */
2796 playback::source_file *
2797 playback::context::
2798 get_source_file (const char *filename)
2800 /* Locate the file.
2801 For simplicitly, this is currently a linear search.
2802 Replace with a hash if this shows up in the profile. */
2803 int i;
2804 source_file *file;
2805 tree ident_filename = get_identifier (filename);
2807 FOR_EACH_VEC_ELT (m_source_files, i, file)
2808 if (file->filename_as_tree () == ident_filename)
2809 return file;
2811 /* Not found. */
2812 file = new source_file (ident_filename);
2813 m_source_files.safe_push (file);
2814 return file;
2817 /* Constructor for gcc::jit::playback::source_file. */
2819 playback::source_file::source_file (tree filename) :
2820 m_source_lines (),
2821 m_filename (filename)
2825 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2826 GC-ed. */
2828 void
2829 playback::source_file::finalizer ()
2831 m_source_lines.release ();
2834 /* Construct a playback::source_line for the given line
2835 within this source file, if one doesn't exist already. */
2837 playback::source_line *
2838 playback::source_file::
2839 get_source_line (int line_num)
2841 /* Locate the line.
2842 For simplicitly, this is currently a linear search.
2843 Replace with a hash if this shows up in the profile. */
2844 int i;
2845 source_line *line;
2847 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2848 if (line->get_line_num () == line_num)
2849 return line;
2851 /* Not found. */
2852 line = new source_line (this, line_num);
2853 m_source_lines.safe_push (line);
2854 return line;
2857 /* Constructor for gcc::jit::playback::source_line. */
2859 playback::source_line::source_line (source_file *file, int line_num) :
2860 m_locations (),
2861 m_source_file (file),
2862 m_line_num (line_num)
2866 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2867 GC-ed. */
2869 void
2870 playback::source_line::finalizer ()
2872 m_locations.release ();
2875 /* Construct a playback::location for the given column
2876 within this line of a specific source file, if one doesn't exist
2877 already. */
2879 playback::location *
2880 playback::source_line::
2881 get_location (recording::location *rloc, int column_num)
2883 int i;
2884 location *loc;
2886 /* Another linear search that probably should be a hash table. */
2887 FOR_EACH_VEC_ELT (m_locations, i, loc)
2888 if (loc->get_column_num () == column_num)
2889 return loc;
2891 /* Not found. */
2892 loc = new location (rloc, this, column_num);
2893 m_locations.safe_push (loc);
2894 return loc;
2897 /* Constructor for gcc::jit::playback::location. */
2899 playback::location::location (recording::location *loc,
2900 source_line *line,
2901 int column_num) :
2902 m_srcloc (UNKNOWN_LOCATION),
2903 m_recording_loc (loc),
2904 m_line (line),
2905 m_column_num(column_num)
2909 /* The active gcc::jit::playback::context instance. This is a singleton,
2910 guarded by jit_mutex. */
2912 playback::context *active_playback_ctxt;
2914 } // namespace gcc::jit
2916 } // namespace gcc