2015-10-18 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / jit / jit-playback.c
blob44c3ce00d98b5254a33d220763893e46c687e209
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 (get_timer (), /* external_timer */
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 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2090 /* Acquire the big GCC mutex. */
2091 JIT_LOG_SCOPE (get_logger ());
2092 pthread_mutex_lock (&jit_mutex);
2093 gcc_assert (NULL == active_playback_ctxt);
2094 active_playback_ctxt = this;
2097 /* Release jit_mutex and clear the active playback ctxt. */
2099 void
2100 playback::context::release_mutex ()
2102 /* Release the big GCC mutex. */
2103 JIT_LOG_SCOPE (get_logger ());
2104 gcc_assert (active_playback_ctxt == this);
2105 active_playback_ctxt = NULL;
2106 pthread_mutex_unlock (&jit_mutex);
2109 /* Callback used by gcc::jit::playback::context::make_fake_args when
2110 invoking driver_get_configure_time_options.
2111 Populate a vec <char * > with the configure-time options. */
2113 static void
2114 append_arg_from_driver (const char *option, void *user_data)
2116 gcc_assert (option);
2117 gcc_assert (user_data);
2118 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2119 argvec->safe_push (concat ("-", option, NULL));
2122 /* Build a fake argv for toplev::main from the options set
2123 by the user on the context . */
2125 void
2126 playback::context::
2127 make_fake_args (vec <char *> *argvec,
2128 const char *ctxt_progname,
2129 vec <recording::requested_dump> *requested_dumps)
2131 JIT_LOG_SCOPE (get_logger ());
2133 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2134 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2136 ADD_ARG (ctxt_progname);
2137 ADD_ARG (get_path_c_file ());
2138 ADD_ARG ("-fPIC");
2140 /* Handle int options: */
2141 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2143 default:
2144 add_error (NULL,
2145 "unrecognized optimization level: %i",
2146 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2147 return;
2149 case 0:
2150 ADD_ARG ("-O0");
2151 break;
2153 case 1:
2154 ADD_ARG ("-O1");
2155 break;
2157 case 2:
2158 ADD_ARG ("-O2");
2159 break;
2161 case 3:
2162 ADD_ARG ("-O3");
2163 break;
2165 /* What about -Os? */
2167 /* Handle bool options: */
2168 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2169 ADD_ARG ("-g");
2171 /* Suppress timing (and other) info. */
2172 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2174 ADD_ARG ("-quiet");
2175 quiet_flag = 1;
2178 /* Aggressively garbage-collect, to shake out bugs: */
2179 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2181 ADD_ARG ("--param");
2182 ADD_ARG ("ggc-min-expand=0");
2183 ADD_ARG ("--param");
2184 ADD_ARG ("ggc-min-heapsize=0");
2187 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2189 ADD_ARG ("-fdump-tree-all");
2190 ADD_ARG ("-fdump-rtl-all");
2191 ADD_ARG ("-fdump-ipa-all");
2194 /* Add "-fdump-" options for any calls to
2195 gcc_jit_context_enable_dump. */
2197 int i;
2198 recording::requested_dump *d;
2199 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2201 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2202 ADD_ARG_TAKE_OWNERSHIP (arg);
2206 /* PR jit/64810: Add any target-specific default options
2207 from OPTION_DEFAULT_SPECS, normally provided by the driver
2208 in the non-jit case.
2210 The target-specific code can define OPTION_DEFAULT_SPECS:
2211 default command options in the form of spec macros for the
2212 driver to expand ().
2214 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2215 if not overriden, injects the defaults as extra arguments to
2216 cc1 etc.
2217 For the jit case, we need to add these arguments here. The
2218 input format (using the specs language) means that we have to run
2219 part of the driver code here (driver_get_configure_time_options).
2221 To avoid running the spec-expansion code every time, we just do
2222 it the first time (via a function-static flag), saving the result
2223 into a function-static vec.
2224 This flag and vec are global state (i.e. per-process).
2225 They are guarded by the jit mutex. */
2227 static bool have_configure_time_options = false;
2228 static vec <char *> configure_time_options;
2230 if (have_configure_time_options)
2231 log ("reusing cached configure-time options");
2232 else
2234 have_configure_time_options = true;
2235 log ("getting configure-time options from driver");
2236 driver_get_configure_time_options (append_arg_from_driver,
2237 &configure_time_options);
2240 int i;
2241 char *opt;
2243 if (get_logger ())
2244 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2245 log ("configure_time_options[%i]: %s", i, opt);
2247 /* configure_time_options should now contain the expanded options
2248 from OPTION_DEFAULT_SPECS (if any). */
2249 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2251 gcc_assert (opt);
2252 gcc_assert (opt[0] == '-');
2253 ADD_ARG (opt);
2257 if (get_timer ())
2258 ADD_ARG ("-ftime-report");
2260 /* Add any user-provided extra options, starting with any from
2261 parent contexts. */
2262 m_recording_ctxt->append_command_line_options (argvec);
2264 #undef ADD_ARG
2265 #undef ADD_ARG_TAKE_OWNERSHIP
2268 /* The second half of the implementation of gcc_jit_context_enable_dump.
2269 Iterate through the requested dumps, reading the underlying files
2270 into heap-allocated buffers, writing pointers to the buffers into
2271 the char ** pointers provided by client code.
2272 Client code is responsible for calling free on the results. */
2274 void
2275 playback::context::
2276 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2278 JIT_LOG_SCOPE (get_logger ());
2280 int i;
2281 recording::requested_dump *d;
2282 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2284 dump_file_info *dfi;
2285 char *filename;
2286 char *content;
2288 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2289 if (!dfi)
2291 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2292 continue;
2295 filename = g->get_dumps ()->get_dump_file_name (dfi);
2296 content = read_dump_file (filename);
2297 *(d->m_out_ptr) = content;
2298 free (filename);
2302 /* Helper function for playback::context::extract_any_requested_dumps
2303 (itself for use in implementation of gcc_jit_context_enable_dump).
2305 Attempt to read the complete file at the given path, returning the
2306 bytes found there as a buffer.
2307 The caller is responsible for calling free on the result.
2308 Errors will be reported on the context, and lead to NULL being
2309 returned; an out-of-memory error will terminate the process. */
2311 char *
2312 playback::context::read_dump_file (const char *path)
2314 char *result = NULL;
2315 size_t total_sz = 0;
2316 char buf[4096];
2317 size_t sz;
2318 FILE *f_in;
2320 f_in = fopen (path, "r");
2321 if (!f_in)
2323 add_error (NULL, "unable to open %s for reading", path);
2324 return NULL;
2327 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2329 size_t old_total_sz = total_sz;
2330 total_sz += sz;
2331 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2332 memcpy (result + old_total_sz, buf, sz);
2335 if (!feof (f_in))
2337 add_error (NULL, "error reading from %s", path);
2338 free (result);
2339 fclose (f_in);
2340 return NULL;
2343 fclose (f_in);
2345 if (result)
2347 result[total_sz] = '\0';
2348 return result;
2350 else
2351 return xstrdup ("");
2354 /* Part of playback::context::compile ().
2356 We have a .s file; we want a .so file.
2357 We could reuse parts of gcc/gcc.c to do this.
2358 For now, just use the driver binary from the install, as
2359 named in gcc-driver-name.h
2360 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2362 void
2363 playback::context::
2364 convert_to_dso (const char *ctxt_progname)
2366 JIT_LOG_SCOPE (get_logger ());
2368 invoke_driver (ctxt_progname,
2369 m_tempdir->get_path_s_file (),
2370 m_tempdir->get_path_so_file (),
2371 TV_ASSEMBLE,
2372 true, /* bool shared, */
2373 true);/* bool run_linker */
2376 static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2378 void
2379 playback::context::
2380 invoke_driver (const char *ctxt_progname,
2381 const char *input_file,
2382 const char *output_file,
2383 timevar_id_t tv_id,
2384 bool shared,
2385 bool run_linker)
2387 JIT_LOG_SCOPE (get_logger ());
2389 bool embedded_driver
2390 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
2392 /* Currently this lumps together both assembling and linking into
2393 TV_ASSEMBLE. */
2394 auto_timevar assemble_timevar (get_timer (), tv_id);
2395 auto_argvec argvec;
2396 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2398 ADD_ARG (gcc_driver_name);
2400 add_multilib_driver_arguments (&argvec);
2402 if (shared)
2403 ADD_ARG ("-shared");
2405 if (!run_linker)
2406 ADD_ARG ("-c");
2408 ADD_ARG (input_file);
2409 ADD_ARG ("-o");
2410 ADD_ARG (output_file);
2412 /* Don't use the linker plugin.
2413 If running with just a "make" and not a "make install", then we'd
2414 run into
2415 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2416 libto_plugin is a .la at build time, with it becoming installed with
2417 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2418 time. */
2419 ADD_ARG ("-fno-use-linker-plugin");
2421 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2422 /* OS X's linker defaults to treating undefined symbols as errors.
2423 If the context has any imported functions or globals they will be
2424 undefined until the .so is dynamically-linked into the process.
2425 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2426 linker. */
2427 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2428 #endif
2430 if (0)
2431 ADD_ARG ("-v");
2433 #undef ADD_ARG
2435 /* pex_one's error-handling requires pname to be non-NULL. */
2436 gcc_assert (ctxt_progname);
2438 if (get_logger ())
2439 for (unsigned i = 0; i < argvec.length (); i++)
2440 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2442 if (embedded_driver)
2443 invoke_embedded_driver (&argvec);
2444 else
2445 invoke_external_driver (ctxt_progname, &argvec);
2448 void
2449 playback::context::
2450 invoke_embedded_driver (const vec <char *> *argvec)
2452 JIT_LOG_SCOPE (get_logger ());
2453 driver d (true, /* can_finalize */
2454 false); /* debug */
2455 int result = d.main (argvec->length (),
2456 const_cast <char **> (argvec->address ()));
2457 d.finalize ();
2458 if (result)
2459 add_error (NULL, "error invoking gcc driver");
2462 void
2463 playback::context::
2464 invoke_external_driver (const char *ctxt_progname,
2465 vec <char *> *argvec)
2467 JIT_LOG_SCOPE (get_logger ());
2468 const char *errmsg;
2469 int exit_status = 0;
2470 int err = 0;
2472 /* pex argv arrays are NULL-terminated. */
2473 argvec->safe_push (NULL);
2475 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2476 gcc_driver_name,
2477 const_cast <char *const *> (argvec->address ()),
2478 ctxt_progname, /* const char *pname */
2479 NULL, /* const char *outname */
2480 NULL, /* const char *errname */
2481 &exit_status, /* int *status */
2482 &err); /* int *err*/
2483 if (errmsg)
2485 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2486 return;
2489 /* pex_one can return a NULL errmsg when the executable wasn't
2490 found (or doesn't exist), so trap these cases also. */
2491 if (exit_status || err)
2493 add_error (NULL,
2494 "error invoking gcc driver: exit_status: %i err: %i",
2495 exit_status, err);
2496 add_error (NULL,
2497 "whilst attempting to run a driver named: %s",
2498 gcc_driver_name);
2499 add_error (NULL,
2500 "PATH was: %s",
2501 getenv ("PATH"));
2502 return;
2506 /* Extract the target-specific MULTILIB_DEFAULTS to
2507 multilib_defaults_raw for use by
2508 playback::context::add_multilib_driver_arguments (). */
2510 #ifndef MULTILIB_DEFAULTS
2511 #define MULTILIB_DEFAULTS { "" }
2512 #endif
2514 static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
2516 /* Helper function for playback::context::invoke_driver ().
2518 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2519 a driver binary. We need to pass in options to the shared driver
2520 to get the appropriate assembler/linker options for this multilib
2521 peer. */
2523 void
2524 playback::context::
2525 add_multilib_driver_arguments (vec <char *> *argvec)
2527 JIT_LOG_SCOPE (get_logger ());
2529 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2530 prepending each with a "-". */
2531 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
2532 if (multilib_defaults_raw[i][0])
2533 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
2536 /* Dynamically-link the built DSO file into this process, using dlopen.
2537 Wrap it up within a jit::result *, and return that.
2538 Return NULL if any errors occur, reporting them on this context. */
2540 result *
2541 playback::context::
2542 dlopen_built_dso ()
2544 JIT_LOG_SCOPE (get_logger ());
2545 auto_timevar load_timevar (get_timer (), TV_LOAD);
2546 void *handle = NULL;
2547 const char *error = NULL;
2548 result *result_obj = NULL;
2550 /* Clear any existing error. */
2551 dlerror ();
2553 handle = dlopen (m_tempdir->get_path_so_file (),
2554 RTLD_NOW | RTLD_LOCAL);
2555 if ((error = dlerror()) != NULL) {
2556 add_error (NULL, "%s", error);
2558 if (handle)
2560 /* We've successfully dlopened the result; create a
2561 jit::result object to wrap it.
2563 We're done with the tempdir for now, but if the user
2564 has requested debugging, the user's debugger might not
2565 be capable of dealing with the .so file being unlinked
2566 immediately, so keep it around until after the result
2567 is released. We do this by handing over ownership of
2568 the jit::tempdir to the result. See PR jit/64206. */
2569 tempdir *handover_tempdir;
2570 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2572 handover_tempdir = m_tempdir;
2573 m_tempdir = NULL;
2574 /* The tempdir will eventually be cleaned up in the
2575 jit::result's dtor. */
2576 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2577 " handing over tempdir to jit::result");
2579 else
2581 handover_tempdir = NULL;
2582 /* ... and retain ownership of m_tempdir so we clean it
2583 up it the playback::context's dtor. */
2584 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2585 " retaining ownership of tempdir");
2588 result_obj = new result (get_logger (), handle, handover_tempdir);
2590 else
2591 result_obj = NULL;
2593 return result_obj;
2596 /* Top-level hook for playing back a recording context.
2598 This plays back m_recording_ctxt, and, if no errors
2599 occurred builds statement lists for and then postprocesses
2600 every function in the result. */
2602 void
2603 playback::context::
2604 replay ()
2606 JIT_LOG_SCOPE (get_logger ());
2607 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2608 tree array_domain_type = build_index_type (size_int (200));
2609 m_char_array_type_node
2610 = build_array_type (char_type_node, array_domain_type);
2612 m_const_char_ptr
2613 = build_pointer_type (build_qualified_type (char_type_node,
2614 TYPE_QUAL_CONST));
2616 /* Replay the recorded events: */
2617 timevar_push (TV_JIT_REPLAY);
2619 m_recording_ctxt->replay_into (this);
2621 /* Clean away the temporary references from recording objects
2622 to playback objects. We have to do this now since the
2623 latter are GC-allocated, but the former don't mark these
2624 refs. Hence we must stop using them before the GC can run. */
2625 m_recording_ctxt->disassociate_from_playback ();
2627 /* The builtins_manager, if any, is associated with the recording::context
2628 and might be reused for future compiles on other playback::contexts,
2629 but its m_attributes array is not GTY-labeled and hence will become
2630 nonsense if the GC runs. Purge this state. */
2631 builtins_manager *bm = get_builtins_manager ();
2632 if (bm)
2633 bm->finish_playback ();
2635 timevar_pop (TV_JIT_REPLAY);
2637 if (!errors_occurred ())
2639 int i;
2640 function *func;
2642 /* No GC can happen yet; process the cached source locations. */
2643 handle_locations ();
2645 /* We've now created tree nodes for the stmts in the various blocks
2646 in each function, but we haven't built each function's single stmt
2647 list yet. Do so now. */
2648 FOR_EACH_VEC_ELT (m_functions, i, func)
2649 func->build_stmt_list ();
2651 /* No GC can have happened yet. */
2653 /* Postprocess the functions. This could trigger GC. */
2654 FOR_EACH_VEC_ELT (m_functions, i, func)
2656 gcc_assert (func);
2657 func->postprocess ();
2662 /* Dump the generated .s file to stderr. */
2664 void
2665 playback::context::
2666 dump_generated_code ()
2668 JIT_LOG_SCOPE (get_logger ());
2669 char buf[4096];
2670 size_t sz;
2671 FILE *f_in = fopen (get_path_s_file (), "r");
2672 if (!f_in)
2673 return;
2675 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2676 fwrite (buf, 1, sz, stderr);
2678 fclose (f_in);
2681 /* Get the supposed path of the notional "fake.c" file within the
2682 tempdir. This file doesn't exist, but the rest of the compiler
2683 needs a name. */
2685 const char *
2686 playback::context::
2687 get_path_c_file () const
2689 return m_tempdir->get_path_c_file ();
2692 /* Get the path of the assembler output file "fake.s" file within the
2693 tempdir. */
2695 const char *
2696 playback::context::
2697 get_path_s_file () const
2699 return m_tempdir->get_path_s_file ();
2702 /* Get the path of the DSO object file "fake.so" file within the
2703 tempdir. */
2705 const char *
2706 playback::context::
2707 get_path_so_file () const
2709 return m_tempdir->get_path_so_file ();
2712 /* qsort comparator for comparing pairs of playback::source_line *,
2713 ordering them by line number. */
2715 static int
2716 line_comparator (const void *lhs, const void *rhs)
2718 const playback::source_line *line_lhs = \
2719 *static_cast<const playback::source_line * const*> (lhs);
2720 const playback::source_line *line_rhs = \
2721 *static_cast<const playback::source_line * const*> (rhs);
2722 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2725 /* qsort comparator for comparing pairs of playback::location *,
2726 ordering them by column number. */
2728 static int
2729 location_comparator (const void *lhs, const void *rhs)
2731 const playback::location *loc_lhs = \
2732 *static_cast<const playback::location * const *> (lhs);
2733 const playback::location *loc_rhs = \
2734 *static_cast<const playback::location * const *> (rhs);
2735 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2738 /* Our API allows locations to be created in arbitrary orders, but the
2739 linemap API requires locations to be created in ascending order
2740 as if we were tokenizing files.
2742 This hook sorts all of the locations that have been created, and
2743 calls into the linemap API, creating linemap entries in sorted order
2744 for our locations. */
2746 void
2747 playback::context::
2748 handle_locations ()
2750 /* Create the source code locations, following the ordering rules
2751 imposed by the linemap API.
2753 line_table is a global. */
2754 JIT_LOG_SCOPE (get_logger ());
2755 int i;
2756 source_file *file;
2758 FOR_EACH_VEC_ELT (m_source_files, i, file)
2760 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2762 /* Sort lines by ascending line numbers. */
2763 file->m_source_lines.qsort (&line_comparator);
2765 int j;
2766 source_line *line;
2767 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2769 int k;
2770 location *loc;
2772 /* Sort locations in line by ascending column numbers. */
2773 line->m_locations.qsort (&location_comparator);
2775 /* Determine maximum column within this line. */
2776 gcc_assert (line->m_locations.length () > 0);
2777 location *final_column =
2778 line->m_locations[line->m_locations.length () - 1];
2779 int max_col = final_column->get_column_num ();
2781 linemap_line_start (line_table, line->get_line_num (), max_col);
2782 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2784 loc->m_srcloc = \
2785 linemap_position_for_column (line_table, loc->get_column_num ());
2789 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2792 /* line_table should now be populated; every playback::location should
2793 now have an m_srcloc. */
2795 /* Now assign them to tree nodes as appropriate. */
2796 std::pair<tree, location *> *cached_location;
2798 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2800 tree t = cached_location->first;
2801 source_location srcloc = cached_location->second->m_srcloc;
2803 /* This covers expressions: */
2804 if (CAN_HAVE_LOCATION_P (t))
2805 SET_EXPR_LOCATION (t, srcloc);
2806 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2807 DECL_SOURCE_LOCATION (t) = srcloc;
2808 else
2810 /* Don't know how to set location on this node. */
2815 /* We handle errors on a playback::context by adding them to the
2816 corresponding recording::context. */
2818 void
2819 playback::context::
2820 add_error (location *loc, const char *fmt, ...)
2822 va_list ap;
2823 va_start (ap, fmt);
2824 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2825 fmt, ap);
2826 va_end (ap);
2829 /* We handle errors on a playback::context by adding them to the
2830 corresponding recording::context. */
2832 void
2833 playback::context::
2834 add_error_va (location *loc, const char *fmt, va_list ap)
2836 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2837 fmt, ap);
2840 /* Dealing with the linemap API. */
2842 /* Construct a playback::location for a recording::location, if it
2843 doesn't exist already. */
2845 playback::location *
2846 playback::context::
2847 new_location (recording::location *rloc,
2848 const char *filename,
2849 int line,
2850 int column)
2852 /* Get the source_file for filename, creating if necessary. */
2853 source_file *src_file = get_source_file (filename);
2854 /* Likewise for the line within the file. */
2855 source_line *src_line = src_file->get_source_line (line);
2856 /* Likewise for the column within the line. */
2857 location *loc = src_line->get_location (rloc, column);
2858 return loc;
2861 /* Deferred setting of the location for a given tree, by adding the
2862 (tree, playback::location) pair to a list of deferred associations.
2863 We will actually set the location on the tree later on once
2864 the source_location for the playback::location exists. */
2866 void
2867 playback::context::
2868 set_tree_location (tree t, location *loc)
2870 gcc_assert (loc);
2871 m_cached_locations.safe_push (std::make_pair (t, loc));
2875 /* Construct a playback::source_file for the given source
2876 filename, if it doesn't exist already. */
2878 playback::source_file *
2879 playback::context::
2880 get_source_file (const char *filename)
2882 /* Locate the file.
2883 For simplicitly, this is currently a linear search.
2884 Replace with a hash if this shows up in the profile. */
2885 int i;
2886 source_file *file;
2887 tree ident_filename = get_identifier (filename);
2889 FOR_EACH_VEC_ELT (m_source_files, i, file)
2890 if (file->filename_as_tree () == ident_filename)
2891 return file;
2893 /* Not found. */
2894 file = new source_file (ident_filename);
2895 m_source_files.safe_push (file);
2896 return file;
2899 /* Constructor for gcc::jit::playback::source_file. */
2901 playback::source_file::source_file (tree filename) :
2902 m_source_lines (),
2903 m_filename (filename)
2907 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2908 GC-ed. */
2910 void
2911 playback::source_file::finalizer ()
2913 m_source_lines.release ();
2916 /* Construct a playback::source_line for the given line
2917 within this source file, if one doesn't exist already. */
2919 playback::source_line *
2920 playback::source_file::
2921 get_source_line (int line_num)
2923 /* Locate the line.
2924 For simplicitly, this is currently a linear search.
2925 Replace with a hash if this shows up in the profile. */
2926 int i;
2927 source_line *line;
2929 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2930 if (line->get_line_num () == line_num)
2931 return line;
2933 /* Not found. */
2934 line = new source_line (this, line_num);
2935 m_source_lines.safe_push (line);
2936 return line;
2939 /* Constructor for gcc::jit::playback::source_line. */
2941 playback::source_line::source_line (source_file *file, int line_num) :
2942 m_locations (),
2943 m_source_file (file),
2944 m_line_num (line_num)
2948 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2949 GC-ed. */
2951 void
2952 playback::source_line::finalizer ()
2954 m_locations.release ();
2957 /* Construct a playback::location for the given column
2958 within this line of a specific source file, if one doesn't exist
2959 already. */
2961 playback::location *
2962 playback::source_line::
2963 get_location (recording::location *rloc, int column_num)
2965 int i;
2966 location *loc;
2968 /* Another linear search that probably should be a hash table. */
2969 FOR_EACH_VEC_ELT (m_locations, i, loc)
2970 if (loc->get_column_num () == column_num)
2971 return loc;
2973 /* Not found. */
2974 loc = new location (rloc, this, column_num);
2975 m_locations.safe_push (loc);
2976 return loc;
2979 /* Constructor for gcc::jit::playback::location. */
2981 playback::location::location (recording::location *loc,
2982 source_line *line,
2983 int column_num) :
2984 m_srcloc (UNKNOWN_LOCATION),
2985 m_recording_loc (loc),
2986 m_line (line),
2987 m_column_num(column_num)
2991 /* The active gcc::jit::playback::context instance. This is a singleton,
2992 guarded by jit_mutex. */
2994 playback::context *active_playback_ctxt;
2996 } // namespace gcc::jit
2998 } // namespace gcc