Daily bump.
[official-gcc.git] / gcc / jit / jit-playback.c
blob1fe1091f7d32e2f0797d84fea583b593b72184a6
1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2015 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "opts.h"
25 #include "hashtab.h"
26 #include "statistics.h"
27 #include "vec.h"
28 #include "alias.h"
29 #include "flags.h"
30 #include "symtab.h"
31 #include "tree-core.h"
32 #include "inchash.h"
33 #include "tree.h"
34 #include "hash-map.h"
35 #include "vec.h"
36 #include "hashtab.h"
37 #include "tm.h"
38 #include "hard-reg-set.h"
39 #include "function.h"
40 #include "dumpfile.h"
41 #include "cgraph.h"
42 #include "toplev.h"
43 #include "timevar.h"
44 #include "tree-cfg.h"
45 #include "target.h"
46 #include "convert.h"
47 #include "stringpool.h"
48 #include "stor-layout.h"
49 #include "print-tree.h"
50 #include "gimplify.h"
51 #include "gcc-driver-name.h"
52 #include "attribs.h"
53 #include "context.h"
54 #include "fold-const.h"
55 #include "debug.h"
56 #include "gcc.h"
58 #include "jit-common.h"
59 #include "jit-logging.h"
60 #include "jit-playback.h"
61 #include "jit-result.h"
62 #include "jit-builtins.h"
63 #include "jit-tempdir.h"
66 /* gcc::jit::playback::context::build_cast uses the convert.h API,
67 which in turn requires the frontend to provide a "convert"
68 function, apparently as a fallback.
70 Hence we provide this dummy one, with the requirement that any casts
71 are handled before reaching this. */
72 extern tree convert (tree type, tree expr);
74 tree
75 convert (tree dst_type, tree expr)
77 gcc_assert (gcc::jit::active_playback_ctxt);
78 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
79 fprintf (stderr, "input expression:\n");
80 debug_tree (expr);
81 fprintf (stderr, "requested type:\n");
82 debug_tree (dst_type);
83 return error_mark_node;
86 namespace gcc {
87 namespace jit {
89 /**********************************************************************
90 Playback.
91 **********************************************************************/
93 /* The constructor for gcc::jit::playback::context. */
95 playback::context::context (recording::context *ctxt)
96 : log_user (ctxt->get_logger ()),
97 m_recording_ctxt (ctxt),
98 m_tempdir (NULL),
99 m_char_array_type_node (NULL),
100 m_const_char_ptr (NULL)
102 JIT_LOG_SCOPE (get_logger ());
103 m_functions.create (0);
104 m_globals.create (0);
105 m_source_files.create (0);
106 m_cached_locations.create (0);
109 /* The destructor for gcc::jit::playback::context. */
111 playback::context::~context ()
113 JIT_LOG_SCOPE (get_logger ());
115 /* Normally the playback::context is responsible for cleaning up the
116 tempdir (including "fake.so" within the filesystem).
118 In the normal case, clean it up now.
120 However m_tempdir can be NULL if the context has handed over
121 responsibility for the tempdir cleanup to the jit::result object, so
122 that the cleanup can be delayed (see PR jit/64206). If that's the
123 case this "delete NULL;" is a no-op. */
124 delete m_tempdir;
126 m_functions.release ();
129 /* A playback::context can reference GC-managed pointers. Mark them
130 ("by hand", rather than by gengtype).
132 This is called on the active playback context (if any) by the
133 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
135 void
136 playback::context::
137 gt_ggc_mx ()
139 int i;
140 function *func;
141 FOR_EACH_VEC_ELT (m_functions, i, func)
143 if (ggc_test_and_set_mark (func))
144 func->gt_ggc_mx ();
148 /* Given an enum gcc_jit_types value, get a "tree" type. */
150 static tree
151 get_tree_node_for_type (enum gcc_jit_types type_)
153 switch (type_)
155 case GCC_JIT_TYPE_VOID:
156 return void_type_node;
158 case GCC_JIT_TYPE_VOID_PTR:
159 return ptr_type_node;
161 case GCC_JIT_TYPE_BOOL:
162 return boolean_type_node;
164 case GCC_JIT_TYPE_CHAR:
165 return char_type_node;
166 case GCC_JIT_TYPE_SIGNED_CHAR:
167 return signed_char_type_node;
168 case GCC_JIT_TYPE_UNSIGNED_CHAR:
169 return unsigned_char_type_node;
171 case GCC_JIT_TYPE_SHORT:
172 return short_integer_type_node;
173 case GCC_JIT_TYPE_UNSIGNED_SHORT:
174 return short_unsigned_type_node;
176 case GCC_JIT_TYPE_CONST_CHAR_PTR:
178 tree const_char = build_qualified_type (char_type_node,
179 TYPE_QUAL_CONST);
180 return build_pointer_type (const_char);
183 case GCC_JIT_TYPE_INT:
184 return integer_type_node;
185 case GCC_JIT_TYPE_UNSIGNED_INT:
186 return unsigned_type_node;
188 case GCC_JIT_TYPE_LONG:
189 return long_integer_type_node;
190 case GCC_JIT_TYPE_UNSIGNED_LONG:
191 return long_unsigned_type_node;
193 case GCC_JIT_TYPE_LONG_LONG:
194 return long_long_integer_type_node;
195 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
196 return long_long_unsigned_type_node;
198 case GCC_JIT_TYPE_FLOAT:
199 return float_type_node;
200 case GCC_JIT_TYPE_DOUBLE:
201 return double_type_node;
202 case GCC_JIT_TYPE_LONG_DOUBLE:
203 return long_double_type_node;
205 case GCC_JIT_TYPE_SIZE_T:
206 return size_type_node;
208 case GCC_JIT_TYPE_FILE_PTR:
209 return fileptr_type_node;
211 case GCC_JIT_TYPE_COMPLEX_FLOAT:
212 return complex_float_type_node;
213 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
214 return complex_double_type_node;
215 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
216 return complex_long_double_type_node;
219 return NULL;
222 /* Construct a playback::type instance (wrapping a tree) for the given
223 enum value. */
225 playback::type *
226 playback::context::
227 get_type (enum gcc_jit_types type_)
229 tree type_node = get_tree_node_for_type (type_);
230 if (NULL == type_node)
232 add_error (NULL,
233 "unrecognized (enum gcc_jit_types) value: %i", type_);
234 return NULL;
237 return new type (type_node);
240 /* Construct a playback::type instance (wrapping a tree) for the given
241 array type. */
243 playback::type *
244 playback::context::
245 new_array_type (playback::location *loc,
246 playback::type *element_type,
247 int num_elements)
249 gcc_assert (element_type);
251 tree t = build_array_type_nelts (element_type->as_tree (),
252 num_elements);
253 layout_type (t);
255 if (loc)
256 set_tree_location (t, loc);
258 return new type (t);
261 /* Construct a playback::field instance (wrapping a tree). */
263 playback::field *
264 playback::context::
265 new_field (location *loc,
266 type *type,
267 const char *name)
269 gcc_assert (type);
270 gcc_assert (name);
272 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
273 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
274 get_identifier (name), type->as_tree ());
276 if (loc)
277 set_tree_location (decl, loc);
279 return new field (decl);
282 /* Construct a playback::compound_type instance (wrapping a tree). */
284 playback::compound_type *
285 playback::context::
286 new_compound_type (location *loc,
287 const char *name,
288 bool is_struct) /* else is union */
290 gcc_assert (name);
292 /* Compare with c/c-decl.c: start_struct. */
294 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
295 TYPE_NAME (t) = get_identifier (name);
296 TYPE_SIZE (t) = 0;
298 if (loc)
299 set_tree_location (t, loc);
301 return new compound_type (t);
304 void
305 playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
307 /* Compare with c/c-decl.c: finish_struct. */
308 tree t = as_tree ();
310 tree fieldlist = NULL;
311 for (unsigned i = 0; i < fields->length (); i++)
313 field *f = (*fields)[i];
314 DECL_CONTEXT (f->as_tree ()) = t;
315 fieldlist = chainon (f->as_tree (), fieldlist);
317 fieldlist = nreverse (fieldlist);
318 TYPE_FIELDS (t) = fieldlist;
320 layout_type (t);
323 /* Construct a playback::type instance (wrapping a tree) for a function
324 type. */
326 playback::type *
327 playback::context::
328 new_function_type (type *return_type,
329 const auto_vec<type *> *param_types,
330 int is_variadic)
332 int i;
333 type *param_type;
335 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
337 FOR_EACH_VEC_ELT (*param_types, i, param_type)
338 arg_types[i] = param_type->as_tree ();
340 tree fn_type;
341 if (is_variadic)
342 fn_type =
343 build_varargs_function_type_array (return_type->as_tree (),
344 param_types->length (),
345 arg_types);
346 else
347 fn_type = build_function_type_array (return_type->as_tree (),
348 param_types->length (),
349 arg_types);
350 free (arg_types);
352 return new type (fn_type);
355 /* Construct a playback::param instance (wrapping a tree). */
357 playback::param *
358 playback::context::
359 new_param (location *loc,
360 type *type,
361 const char *name)
363 gcc_assert (type);
364 gcc_assert (name);
365 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
366 get_identifier (name), type->as_tree ());
367 if (loc)
368 set_tree_location (inner, loc);
370 return new param (this, inner);
373 /* Construct a playback::function instance. */
375 playback::function *
376 playback::context::
377 new_function (location *loc,
378 enum gcc_jit_function_kind kind,
379 type *return_type,
380 const char *name,
381 const auto_vec<param *> *params,
382 int is_variadic,
383 enum built_in_function builtin_id)
385 int i;
386 param *param;
388 //can return_type be NULL?
389 gcc_assert (name);
391 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
392 FOR_EACH_VEC_ELT (*params, i, param)
393 arg_types[i] = TREE_TYPE (param->as_tree ());
395 tree fn_type;
396 if (is_variadic)
397 fn_type = build_varargs_function_type_array (return_type->as_tree (),
398 params->length (), arg_types);
399 else
400 fn_type = build_function_type_array (return_type->as_tree (),
401 params->length (), arg_types);
402 free (arg_types);
404 /* FIXME: this uses input_location: */
405 tree fndecl = build_fn_decl (name, fn_type);
407 if (loc)
408 set_tree_location (fndecl, loc);
410 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
411 NULL_TREE, return_type->as_tree ());
412 DECL_ARTIFICIAL (resdecl) = 1;
413 DECL_IGNORED_P (resdecl) = 1;
414 DECL_RESULT (fndecl) = resdecl;
416 if (builtin_id)
418 DECL_FUNCTION_CODE (fndecl) = builtin_id;
419 gcc_assert (loc == NULL);
420 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
422 DECL_BUILT_IN_CLASS (fndecl) =
423 builtins_manager::get_class (builtin_id);
424 set_builtin_decl (builtin_id, fndecl,
425 builtins_manager::implicit_p (builtin_id));
427 builtins_manager *bm = get_builtins_manager ();
428 tree attrs = bm->get_attrs_tree (builtin_id);
429 if (attrs)
430 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
431 else
432 decl_attributes (&fndecl, NULL_TREE, 0);
435 if (kind != GCC_JIT_FUNCTION_IMPORTED)
437 tree param_decl_list = NULL;
438 FOR_EACH_VEC_ELT (*params, i, param)
440 param_decl_list = chainon (param->as_tree (), param_decl_list);
443 /* The param list was created in reverse order; fix it: */
444 param_decl_list = nreverse (param_decl_list);
446 tree t;
447 for (t = param_decl_list; t; t = DECL_CHAIN (t))
449 DECL_CONTEXT (t) = fndecl;
450 DECL_ARG_TYPE (t) = TREE_TYPE (t);
453 /* Set it up on DECL_ARGUMENTS */
454 DECL_ARGUMENTS(fndecl) = param_decl_list;
457 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
459 DECL_DECLARED_INLINE_P (fndecl) = 1;
461 /* Add attribute "always_inline": */
462 DECL_ATTRIBUTES (fndecl) =
463 tree_cons (get_identifier ("always_inline"),
464 NULL,
465 DECL_ATTRIBUTES (fndecl));
468 function *func = new function (this, fndecl, kind);
469 m_functions.safe_push (func);
470 return func;
473 /* Construct a playback::lvalue instance (wrapping a tree). */
475 playback::lvalue *
476 playback::context::
477 new_global (location *loc,
478 enum gcc_jit_global_kind kind,
479 type *type,
480 const char *name)
482 gcc_assert (type);
483 gcc_assert (name);
484 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
485 get_identifier (name),
486 type->as_tree ());
487 TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
488 DECL_COMMON (inner) = 1;
489 switch (kind)
491 default:
492 gcc_unreachable ();
494 case GCC_JIT_GLOBAL_EXPORTED:
495 TREE_STATIC (inner) = 1;
496 break;
498 case GCC_JIT_GLOBAL_INTERNAL:
499 TREE_STATIC (inner) = 1;
500 break;
502 case GCC_JIT_GLOBAL_IMPORTED:
503 DECL_EXTERNAL (inner) = 1;
504 break;
507 if (loc)
508 set_tree_location (inner, loc);
510 varpool_node::get_create (inner);
512 varpool_node::finalize_decl (inner);
514 m_globals.safe_push (inner);
516 return new lvalue (this, inner);
519 /* Implementation of the various
520 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
521 methods.
522 Each of these constructs a playback::rvalue instance (wrapping a tree).
524 These specializations are required to be in the same namespace
525 as the template, hence we now have to enter the gcc::jit::playback
526 namespace. */
528 namespace playback
531 /* Specialization of making an rvalue from a const, for host <int>. */
533 template <>
534 rvalue *
535 context::
536 new_rvalue_from_const <int> (type *type,
537 int value)
539 // FIXME: type-checking, or coercion?
540 tree inner_type = type->as_tree ();
541 if (INTEGRAL_TYPE_P (inner_type))
543 tree inner = build_int_cst (inner_type, value);
544 return new rvalue (this, inner);
546 else
548 REAL_VALUE_TYPE real_value;
549 real_from_integer (&real_value, VOIDmode, value, SIGNED);
550 tree inner = build_real (inner_type, real_value);
551 return new rvalue (this, inner);
555 /* Specialization of making an rvalue from a const, for host <long>. */
557 template <>
558 rvalue *
559 context::
560 new_rvalue_from_const <long> (type *type,
561 long value)
563 // FIXME: type-checking, or coercion?
564 tree inner_type = type->as_tree ();
565 if (INTEGRAL_TYPE_P (inner_type))
567 tree inner = build_int_cst (inner_type, value);
568 return new rvalue (this, inner);
570 else
572 REAL_VALUE_TYPE real_value;
573 real_from_integer (&real_value, VOIDmode, value, SIGNED);
574 tree inner = build_real (inner_type, real_value);
575 return new rvalue (this, inner);
579 /* Specialization of making an rvalue from a const, for host <double>. */
581 template <>
582 rvalue *
583 context::
584 new_rvalue_from_const <double> (type *type,
585 double value)
587 // FIXME: type-checking, or coercion?
588 tree inner_type = type->as_tree ();
590 /* We have a "double", we want a REAL_VALUE_TYPE.
592 real.c:real_from_target appears to require the representation to be
593 split into 32-bit values, and then sent as an pair of host long
594 ints. */
595 REAL_VALUE_TYPE real_value;
596 union
598 double as_double;
599 uint32_t as_uint32s[2];
600 } u;
601 u.as_double = value;
602 long int as_long_ints[2];
603 as_long_ints[0] = u.as_uint32s[0];
604 as_long_ints[1] = u.as_uint32s[1];
605 real_from_target (&real_value, as_long_ints, DFmode);
606 tree inner = build_real (inner_type, real_value);
607 return new rvalue (this, inner);
610 /* Specialization of making an rvalue from a const, for host <void *>. */
612 template <>
613 rvalue *
614 context::
615 new_rvalue_from_const <void *> (type *type,
616 void *value)
618 tree inner_type = type->as_tree ();
619 /* FIXME: how to ensure we have a wide enough type? */
620 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
621 return new rvalue (this, inner);
624 /* We're done implementing the specializations of
625 gcc::jit::playback::context::new_rvalue_from_const <T>
626 so we can exit the gcc::jit::playback namespace. */
628 } // namespace playback
630 /* Construct a playback::rvalue instance (wrapping a tree). */
632 playback::rvalue *
633 playback::context::
634 new_string_literal (const char *value)
636 tree t_str = build_string (strlen (value), value);
637 gcc_assert (m_char_array_type_node);
638 TREE_TYPE (t_str) = m_char_array_type_node;
640 /* Convert to (const char*), loosely based on
641 c/c-typeck.c: array_to_pointer_conversion,
642 by taking address of start of string. */
643 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
645 return new rvalue (this, t_addr);
648 /* Coerce a tree expression into a boolean tree expression. */
650 tree
651 playback::context::
652 as_truth_value (tree expr, location *loc)
654 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
655 tree typed_zero = fold_build1 (CONVERT_EXPR,
656 TREE_TYPE (expr),
657 integer_zero_node);
658 if (loc)
659 set_tree_location (typed_zero, loc);
661 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
662 if (loc)
663 set_tree_location (expr, loc);
665 return expr;
668 /* Construct a playback::rvalue instance (wrapping a tree) for a
669 unary op. */
671 playback::rvalue *
672 playback::context::
673 new_unary_op (location *loc,
674 enum gcc_jit_unary_op op,
675 type *result_type,
676 rvalue *a)
678 // FIXME: type-checking, or coercion?
679 enum tree_code inner_op;
681 gcc_assert (result_type);
682 gcc_assert (a);
684 tree node = a->as_tree ();
685 tree inner_result = NULL;
687 switch (op)
689 default:
690 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
691 return NULL;
693 case GCC_JIT_UNARY_OP_MINUS:
694 inner_op = NEGATE_EXPR;
695 break;
697 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
698 inner_op = BIT_NOT_EXPR;
699 break;
701 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
702 node = as_truth_value (node, loc);
703 inner_result = invert_truthvalue (node);
704 if (loc)
705 set_tree_location (inner_result, loc);
706 return new rvalue (this, inner_result);
708 case GCC_JIT_UNARY_OP_ABS:
709 inner_op = ABS_EXPR;
710 break;
713 inner_result = build1 (inner_op,
714 result_type->as_tree (),
715 node);
716 if (loc)
717 set_tree_location (inner_result, loc);
719 return new rvalue (this, inner_result);
722 /* Construct a playback::rvalue instance (wrapping a tree) for a
723 binary op. */
725 playback::rvalue *
726 playback::context::
727 new_binary_op (location *loc,
728 enum gcc_jit_binary_op op,
729 type *result_type,
730 rvalue *a, rvalue *b)
732 // FIXME: type-checking, or coercion?
733 enum tree_code inner_op;
735 gcc_assert (result_type);
736 gcc_assert (a);
737 gcc_assert (b);
739 tree node_a = a->as_tree ();
740 tree node_b = b->as_tree ();
742 switch (op)
744 default:
745 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
746 return NULL;
748 case GCC_JIT_BINARY_OP_PLUS:
749 inner_op = PLUS_EXPR;
750 break;
752 case GCC_JIT_BINARY_OP_MINUS:
753 inner_op = MINUS_EXPR;
754 break;
756 case GCC_JIT_BINARY_OP_MULT:
757 inner_op = MULT_EXPR;
758 break;
760 case GCC_JIT_BINARY_OP_DIVIDE:
761 if (FLOAT_TYPE_P (result_type->as_tree ()))
762 /* Floating-point division: */
763 inner_op = RDIV_EXPR;
764 else
765 /* Truncating to zero: */
766 inner_op = TRUNC_DIV_EXPR;
767 break;
769 case GCC_JIT_BINARY_OP_MODULO:
770 inner_op = TRUNC_MOD_EXPR;
771 break;
773 case GCC_JIT_BINARY_OP_BITWISE_AND:
774 inner_op = BIT_AND_EXPR;
775 break;
777 case GCC_JIT_BINARY_OP_BITWISE_XOR:
778 inner_op = BIT_XOR_EXPR;
779 break;
781 case GCC_JIT_BINARY_OP_BITWISE_OR:
782 inner_op = BIT_IOR_EXPR;
783 break;
785 case GCC_JIT_BINARY_OP_LOGICAL_AND:
786 node_a = as_truth_value (node_a, loc);
787 node_b = as_truth_value (node_b, loc);
788 inner_op = TRUTH_ANDIF_EXPR;
789 break;
791 case GCC_JIT_BINARY_OP_LOGICAL_OR:
792 node_a = as_truth_value (node_a, loc);
793 node_b = as_truth_value (node_b, loc);
794 inner_op = TRUTH_ORIF_EXPR;
795 break;
797 case GCC_JIT_BINARY_OP_LSHIFT:
798 inner_op = LSHIFT_EXPR;
799 break;
801 case GCC_JIT_BINARY_OP_RSHIFT:
802 inner_op = RSHIFT_EXPR;
803 break;
806 tree inner_expr = build2 (inner_op,
807 result_type->as_tree (),
808 node_a,
809 node_b);
810 if (loc)
811 set_tree_location (inner_expr, loc);
813 return new rvalue (this, inner_expr);
816 /* Construct a playback::rvalue instance (wrapping a tree) for a
817 comparison. */
819 playback::rvalue *
820 playback::context::
821 new_comparison (location *loc,
822 enum gcc_jit_comparison op,
823 rvalue *a, rvalue *b)
825 // FIXME: type-checking, or coercion?
826 enum tree_code inner_op;
828 gcc_assert (a);
829 gcc_assert (b);
831 switch (op)
833 default:
834 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
835 return NULL;
837 case GCC_JIT_COMPARISON_EQ:
838 inner_op = EQ_EXPR;
839 break;
840 case GCC_JIT_COMPARISON_NE:
841 inner_op = NE_EXPR;
842 break;
843 case GCC_JIT_COMPARISON_LT:
844 inner_op = LT_EXPR;
845 break;
846 case GCC_JIT_COMPARISON_LE:
847 inner_op = LE_EXPR;
848 break;
849 case GCC_JIT_COMPARISON_GT:
850 inner_op = GT_EXPR;
851 break;
852 case GCC_JIT_COMPARISON_GE:
853 inner_op = GE_EXPR;
854 break;
857 tree inner_expr = build2 (inner_op,
858 boolean_type_node,
859 a->as_tree (),
860 b->as_tree ());
861 if (loc)
862 set_tree_location (inner_expr, loc);
863 return new rvalue (this, inner_expr);
866 /* Construct a playback::rvalue instance (wrapping a tree) for a
867 function call. */
869 playback::rvalue *
870 playback::context::
871 build_call (location *loc,
872 tree fn_ptr,
873 const auto_vec<rvalue *> *args)
875 vec<tree, va_gc> *tree_args;
876 vec_alloc (tree_args, args->length ());
877 for (unsigned i = 0; i < args->length (); i++)
878 tree_args->quick_push ((*args)[i]->as_tree ());
880 if (loc)
881 set_tree_location (fn_ptr, loc);
883 tree fn = TREE_TYPE (fn_ptr);
884 tree fn_type = TREE_TYPE (fn);
885 tree return_type = TREE_TYPE (fn_type);
887 return new rvalue (this,
888 build_call_vec (return_type,
889 fn_ptr, tree_args));
891 /* see c-typeck.c: build_function_call
892 which calls build_function_call_vec
894 which does lots of checking, then:
895 result = build_call_array_loc (loc, TREE_TYPE (fntype),
896 function, nargs, argarray);
897 which is in tree.c
898 (see also build_call_vec)
902 /* Construct a playback::rvalue instance (wrapping a tree) for a
903 call to a specific function. */
905 playback::rvalue *
906 playback::context::
907 new_call (location *loc,
908 function *func,
909 const auto_vec<rvalue *> *args)
911 tree fndecl;
913 gcc_assert (func);
915 fndecl = func->as_fndecl ();
917 tree fntype = TREE_TYPE (fndecl);
919 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
921 return build_call (loc, fn, args);
924 /* Construct a playback::rvalue instance (wrapping a tree) for a
925 call through a function pointer. */
927 playback::rvalue *
928 playback::context::
929 new_call_through_ptr (location *loc,
930 rvalue *fn_ptr,
931 const auto_vec<rvalue *> *args)
933 gcc_assert (fn_ptr);
934 tree t_fn_ptr = fn_ptr->as_tree ();
936 return build_call (loc, t_fn_ptr, args);
939 /* Construct a tree for a cast. */
941 tree
942 playback::context::build_cast (playback::location *loc,
943 playback::rvalue *expr,
944 playback::type *type_)
946 /* For comparison, see:
947 - c/c-typeck.c:build_c_cast
948 - c/c-convert.c: convert
949 - convert.h
951 Only some kinds of cast are currently supported here. */
952 tree t_expr = expr->as_tree ();
953 tree t_dst_type = type_->as_tree ();
954 tree t_ret = NULL;
955 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
956 if (t_ret)
957 return t_ret;
958 enum tree_code dst_code = TREE_CODE (t_dst_type);
959 switch (dst_code)
961 case INTEGER_TYPE:
962 case ENUMERAL_TYPE:
963 t_ret = convert_to_integer (t_dst_type, t_expr);
964 goto maybe_fold;
966 case BOOLEAN_TYPE:
967 /* Compare with c_objc_common_truthvalue_conversion and
968 c_common_truthvalue_conversion. */
969 /* For now, convert to: (t_expr != 0) */
970 t_ret = build2 (NE_EXPR, t_dst_type,
971 t_expr,
972 build_int_cst (TREE_TYPE (t_expr), 0));
973 goto maybe_fold;
975 case REAL_TYPE:
976 t_ret = convert_to_real (t_dst_type, t_expr);
977 goto maybe_fold;
979 case POINTER_TYPE:
980 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
981 goto maybe_fold;
983 default:
984 add_error (loc, "couldn't handle cast during playback");
985 fprintf (stderr, "input expression:\n");
986 debug_tree (t_expr);
987 fprintf (stderr, "requested type:\n");
988 debug_tree (t_dst_type);
989 return error_mark_node;
991 maybe_fold:
992 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
993 t_ret = fold (t_ret);
994 return t_ret;
998 /* Construct a playback::rvalue instance (wrapping a tree) for a
999 cast. */
1001 playback::rvalue *
1002 playback::context::
1003 new_cast (playback::location *loc,
1004 playback::rvalue *expr,
1005 playback::type *type_)
1008 tree t_cast = build_cast (loc, expr, type_);
1009 if (loc)
1010 set_tree_location (t_cast, loc);
1011 return new rvalue (this, t_cast);
1014 /* Construct a playback::lvalue instance (wrapping a tree) for an
1015 array access. */
1017 playback::lvalue *
1018 playback::context::
1019 new_array_access (location *loc,
1020 rvalue *ptr,
1021 rvalue *index)
1023 gcc_assert (ptr);
1024 gcc_assert (index);
1026 /* For comparison, see:
1027 c/c-typeck.c: build_array_ref
1028 c-family/c-common.c: pointer_int_sum
1030 tree t_ptr = ptr->as_tree ();
1031 tree t_index = index->as_tree ();
1032 tree t_type_ptr = TREE_TYPE (t_ptr);
1033 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1035 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1037 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1038 NULL_TREE, NULL_TREE);
1039 if (loc)
1040 set_tree_location (t_result, loc);
1041 return new lvalue (this, t_result);
1043 else
1045 /* Convert index to an offset in bytes. */
1046 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1047 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1048 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
1050 /* Locate (ptr + offset). */
1051 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1053 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1054 if (loc)
1056 set_tree_location (t_sizeof, loc);
1057 set_tree_location (t_offset, loc);
1058 set_tree_location (t_address, loc);
1059 set_tree_location (t_indirection, loc);
1062 return new lvalue (this, t_indirection);
1066 /* Construct a tree for a field access. */
1068 tree
1069 playback::context::
1070 new_field_access (location *loc,
1071 tree datum,
1072 field *field)
1074 gcc_assert (datum);
1075 gcc_assert (field);
1077 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1078 build_component_ref. */
1079 tree type = TREE_TYPE (datum);
1080 gcc_assert (type);
1081 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1083 tree t_field = field->as_tree ();
1084 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1085 t_field, NULL_TREE);
1086 if (loc)
1087 set_tree_location (ref, loc);
1088 return ref;
1091 /* Construct a tree for a dereference. */
1093 tree
1094 playback::context::
1095 new_dereference (tree ptr,
1096 location *loc)
1098 gcc_assert (ptr);
1100 tree type = TREE_TYPE (TREE_TYPE(ptr));
1101 tree datum = build1 (INDIRECT_REF, type, ptr);
1102 if (loc)
1103 set_tree_location (datum, loc);
1104 return datum;
1107 /* Construct a playback::lvalue instance (wrapping a tree) for a
1108 field access. */
1110 playback::lvalue *
1111 playback::lvalue::
1112 access_field (location *loc,
1113 field *field)
1115 tree datum = as_tree ();
1116 tree ref = get_context ()->new_field_access (loc, datum, field);
1117 if (!ref)
1118 return NULL;
1119 return new lvalue (get_context (), ref);
1122 /* Construct a playback::rvalue instance (wrapping a tree) for a
1123 field access. */
1125 playback::rvalue *
1126 playback::rvalue::
1127 access_field (location *loc,
1128 field *field)
1130 tree datum = as_tree ();
1131 tree ref = get_context ()->new_field_access (loc, datum, field);
1132 if (!ref)
1133 return NULL;
1134 return new rvalue (get_context (), ref);
1137 /* Construct a playback::lvalue instance (wrapping a tree) for a
1138 dereferenced field access. */
1140 playback::lvalue *
1141 playback::rvalue::
1142 dereference_field (location *loc,
1143 field *field)
1145 tree ptr = as_tree ();
1146 tree datum = get_context ()->new_dereference (ptr, loc);
1147 if (!datum)
1148 return NULL;
1149 tree ref = get_context ()->new_field_access (loc, datum, field);
1150 if (!ref)
1151 return NULL;
1152 return new lvalue (get_context (), ref);
1155 /* Construct a playback::lvalue instance (wrapping a tree) for a
1156 dereference. */
1158 playback::lvalue *
1159 playback::rvalue::
1160 dereference (location *loc)
1162 tree ptr = as_tree ();
1163 tree datum = get_context ()->new_dereference (ptr, loc);
1164 return new lvalue (get_context (), datum);
1167 /* Mark EXP saying that we need to be able to take the
1168 address of it; it should not be allocated in a register.
1169 Compare with e.g. c/c-typeck.c: c_mark_addressable. */
1171 static void
1172 jit_mark_addressable (tree exp)
1174 tree x = exp;
1176 while (1)
1177 switch (TREE_CODE (x))
1179 case COMPONENT_REF:
1180 /* (we don't yet support bitfields) */
1181 /* fallthrough */
1182 case ADDR_EXPR:
1183 case ARRAY_REF:
1184 case REALPART_EXPR:
1185 case IMAGPART_EXPR:
1186 x = TREE_OPERAND (x, 0);
1187 break;
1189 case COMPOUND_LITERAL_EXPR:
1190 case CONSTRUCTOR:
1191 TREE_ADDRESSABLE (x) = 1;
1192 return;
1194 case VAR_DECL:
1195 case CONST_DECL:
1196 case PARM_DECL:
1197 case RESULT_DECL:
1198 /* (we don't have a concept of a "register" declaration) */
1199 /* fallthrough */
1200 case FUNCTION_DECL:
1201 TREE_ADDRESSABLE (x) = 1;
1202 /* fallthrough */
1203 default:
1204 return;
1208 /* Construct a playback::rvalue instance (wrapping a tree) for an
1209 address-lookup. */
1211 playback::rvalue *
1212 playback::lvalue::
1213 get_address (location *loc)
1215 tree t_lvalue = as_tree ();
1216 tree t_thistype = TREE_TYPE (t_lvalue);
1217 tree t_ptrtype = build_pointer_type (t_thistype);
1218 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1219 if (loc)
1220 get_context ()->set_tree_location (ptr, loc);
1221 jit_mark_addressable (t_lvalue);
1222 return new rvalue (get_context (), ptr);
1225 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1226 Provide this finalization hook for calling then they are collected,
1227 which calls the finalizer vfunc. This allows them to call "release"
1228 on any vec<> within them. */
1230 static void
1231 wrapper_finalizer (void *ptr)
1233 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1234 wrapper->finalizer ();
1237 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1238 allocate them using ggc_internal_cleared_alloc. */
1240 void *
1241 playback::wrapper::
1242 operator new (size_t sz)
1244 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1248 /* Constructor for gcc:jit::playback::function. */
1250 playback::function::
1251 function (context *ctxt,
1252 tree fndecl,
1253 enum gcc_jit_function_kind kind)
1254 : m_ctxt(ctxt),
1255 m_inner_fndecl (fndecl),
1256 m_inner_bind_expr (NULL),
1257 m_kind (kind)
1259 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1261 /* Create a BIND_EXPR, and within it, a statement list. */
1262 m_stmt_list = alloc_stmt_list ();
1263 m_stmt_iter = tsi_start (m_stmt_list);
1264 m_inner_block = make_node (BLOCK);
1265 m_inner_bind_expr =
1266 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1268 else
1270 m_inner_block = NULL;
1271 m_stmt_list = NULL;
1275 /* Hand-written GC-marking hook for playback functions. */
1277 void
1278 playback::function::
1279 gt_ggc_mx ()
1281 gt_ggc_m_9tree_node (m_inner_fndecl);
1282 gt_ggc_m_9tree_node (m_inner_bind_expr);
1283 gt_ggc_m_9tree_node (m_stmt_list);
1284 gt_ggc_m_9tree_node (m_inner_block);
1287 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1288 GC-ed. */
1290 void
1291 playback::function::finalizer ()
1293 m_blocks.release ();
1296 /* Get the return type of a playback function, in tree form. */
1298 tree
1299 playback::function::
1300 get_return_type_as_tree () const
1302 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1305 /* Construct a new local within this playback::function. */
1307 playback::lvalue *
1308 playback::function::
1309 new_local (location *loc,
1310 type *type,
1311 const char *name)
1313 gcc_assert (type);
1314 gcc_assert (name);
1315 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1316 get_identifier (name),
1317 type->as_tree ());
1318 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1320 /* Prepend to BIND_EXPR_VARS: */
1321 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1322 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1324 if (loc)
1325 set_tree_location (inner, loc);
1326 return new lvalue (m_ctxt, inner);
1329 /* Construct a new block within this playback::function. */
1331 playback::block *
1332 playback::function::
1333 new_block (const char *name)
1335 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1337 block *result = new playback::block (this, name);
1338 m_blocks.safe_push (result);
1339 return result;
1342 /* Build a statement list for the function as a whole out of the
1343 lists of statements for the individual blocks, building labels
1344 for each block. */
1346 void
1347 playback::function::
1348 build_stmt_list ()
1350 int i;
1351 block *b;
1353 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1355 FOR_EACH_VEC_ELT (m_blocks, i, b)
1357 int j;
1358 tree stmt;
1360 b->m_label_expr = build1 (LABEL_EXPR,
1361 void_type_node,
1362 b->as_label_decl ());
1363 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1365 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1366 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1370 /* Finish compiling the given function, potentially running the
1371 garbage-collector.
1372 The function will have a statement list by now.
1373 Amongst other things, this gimplifies the statement list,
1374 and calls cgraph_node::finalize_function on the function. */
1376 void
1377 playback::function::
1378 postprocess ()
1380 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1382 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1383 debug_tree (m_stmt_list);
1385 /* Do we need this to force cgraphunit.c to output the function? */
1386 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1388 DECL_EXTERNAL (m_inner_fndecl) = 0;
1389 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1392 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1393 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1395 DECL_EXTERNAL (m_inner_fndecl) = 0;
1396 TREE_PUBLIC (m_inner_fndecl) = 0;
1399 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1401 /* Seem to need this in gimple-low.c: */
1402 gcc_assert (m_inner_block);
1403 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1405 /* how to add to function? the following appears to be how to
1406 set the body of a m_inner_fndecl: */
1407 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1409 /* Ensure that locals appear in the debuginfo. */
1410 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1412 //debug_tree (m_inner_fndecl);
1414 /* Convert to gimple: */
1415 //printf("about to gimplify_function_tree\n");
1416 gimplify_function_tree (m_inner_fndecl);
1417 //printf("finished gimplify_function_tree\n");
1419 current_function_decl = m_inner_fndecl;
1420 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1421 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1422 //debug_tree (m_inner_fndecl);
1424 //printf("about to add to cgraph\n");
1425 /* Add to cgraph: */
1426 cgraph_node::finalize_function (m_inner_fndecl, false);
1427 /* This can trigger a collection, so we need to have all of
1428 the funcs as roots. */
1430 current_function_decl = NULL;
1434 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1435 GC-ed. */
1437 void
1438 playback::block::finalizer ()
1440 m_stmts.release ();
1443 /* Add an eval of the rvalue to the function's statement list. */
1445 void
1446 playback::block::
1447 add_eval (location *loc,
1448 rvalue *rvalue)
1450 gcc_assert (rvalue);
1452 if (loc)
1453 set_tree_location (rvalue->as_tree (), loc);
1455 add_stmt (rvalue->as_tree ());
1458 /* Add an assignment to the function's statement list. */
1460 void
1461 playback::block::
1462 add_assignment (location *loc,
1463 lvalue *lvalue,
1464 rvalue *rvalue)
1466 gcc_assert (lvalue);
1467 gcc_assert (rvalue);
1469 tree t_lvalue = lvalue->as_tree ();
1470 tree t_rvalue = rvalue->as_tree ();
1471 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1473 t_rvalue = build1 (CONVERT_EXPR,
1474 TREE_TYPE (t_lvalue),
1475 t_rvalue);
1476 if (loc)
1477 set_tree_location (t_rvalue, loc);
1480 tree stmt =
1481 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1482 t_lvalue, t_rvalue);
1483 if (loc)
1484 set_tree_location (stmt, loc);
1485 add_stmt (stmt);
1488 /* Add a comment to the function's statement list.
1489 For now this is done by adding a dummy label. */
1491 void
1492 playback::block::
1493 add_comment (location *loc,
1494 const char *text)
1496 /* Wrap the text in C-style comment delimiters. */
1497 size_t sz =
1498 (3 /* opening delim */
1499 + strlen (text)
1500 + 3 /* closing delim */
1501 + 1 /* terminator */);
1502 char *wrapped = (char *)ggc_internal_alloc (sz);
1503 snprintf (wrapped, sz, "/* %s */", text);
1505 /* For now we simply implement this by adding a dummy label with a name
1506 containing the given text. */
1507 tree identifier = get_identifier (wrapped);
1508 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1509 identifier, void_type_node);
1510 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1512 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1513 if (loc)
1514 set_tree_location (label_expr, loc);
1515 add_stmt (label_expr);
1518 /* Add a conditional jump statement to the function's statement list. */
1520 void
1521 playback::block::
1522 add_conditional (location *loc,
1523 rvalue *boolval,
1524 block *on_true,
1525 block *on_false)
1527 gcc_assert (boolval);
1528 gcc_assert (on_true);
1529 gcc_assert (on_false);
1531 /* COND_EXPR wants statement lists for the true/false operands, but we
1532 want labels.
1533 Shim it by creating jumps to the labels */
1534 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1535 on_true->as_label_decl ());
1536 if (loc)
1537 set_tree_location (true_jump, loc);
1539 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1540 on_false->as_label_decl ());
1541 if (loc)
1542 set_tree_location (false_jump, loc);
1544 tree stmt =
1545 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1546 true_jump, false_jump);
1547 if (loc)
1548 set_tree_location (stmt, loc);
1549 add_stmt (stmt);
1552 /* Add an unconditional jump statement to the function's statement list. */
1554 void
1555 playback::block::
1556 add_jump (location *loc,
1557 block *target)
1559 gcc_assert (target);
1561 // see c_finish_loop
1562 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1563 //add_stmt (top);
1565 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1566 TREE_USED (target->as_label_decl ()) = 1;
1567 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1568 if (loc)
1569 set_tree_location (stmt, loc);
1570 add_stmt (stmt);
1573 from c-typeck.c:
1574 tree
1575 c_finish_goto_label (location_t loc, tree label)
1577 tree decl = lookup_label_for_goto (loc, label);
1578 if (!decl)
1579 return NULL_TREE;
1580 TREE_USED (decl) = 1;
1582 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1583 SET_EXPR_LOCATION (t, loc);
1584 return add_stmt (t);
1591 /* Add a return statement to the function's statement list. */
1593 void
1594 playback::block::
1595 add_return (location *loc,
1596 rvalue *rvalue)
1598 tree modify_retval = NULL;
1599 tree return_type = m_func->get_return_type_as_tree ();
1600 if (rvalue)
1602 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1603 tree t_rvalue = rvalue->as_tree ();
1604 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1605 t_rvalue = build1 (CONVERT_EXPR,
1606 TREE_TYPE (t_lvalue),
1607 t_rvalue);
1608 modify_retval = build2 (MODIFY_EXPR, return_type,
1609 t_lvalue, t_rvalue);
1610 if (loc)
1611 set_tree_location (modify_retval, loc);
1613 tree return_stmt = build1 (RETURN_EXPR, return_type,
1614 modify_retval);
1615 if (loc)
1616 set_tree_location (return_stmt, loc);
1618 add_stmt (return_stmt);
1621 /* Helper function for playback::block::add_switch.
1622 Construct a case label for the given range, followed by a goto stmt
1623 to the given block, appending them to stmt list *ptr_t_switch_body. */
1625 static void
1626 add_case (tree *ptr_t_switch_body,
1627 tree t_low_value,
1628 tree t_high_value,
1629 playback::block *dest_block)
1631 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
1632 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
1634 tree t_case_label =
1635 build_case_label (t_low_value, t_high_value, t_label);
1636 append_to_statement_list (t_case_label, ptr_t_switch_body);
1638 tree t_goto_stmt =
1639 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
1640 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
1643 /* Add a switch statement to the function's statement list.
1645 My initial attempt at implementing this constructed a TREE_VEC
1646 of the cases and set it as SWITCH_LABELS (switch_expr). However,
1647 gimplify.c:gimplify_switch_expr is set up to deal with SWITCH_BODY, and
1648 doesn't have any logic for gimplifying SWITCH_LABELS.
1650 Hence we create a switch body, and populate it with case labels, each
1651 followed by a goto to the desired block. */
1653 void
1654 playback::block::
1655 add_switch (location *loc,
1656 rvalue *expr,
1657 block *default_block,
1658 const auto_vec <case_> *cases)
1660 /* Compare with:
1661 - c/c-typeck.c: c_start_case
1662 - c-family/c-common.c:c_add_case_label
1663 - java/expr.c:expand_java_switch and expand_java_add_case
1664 We've already rejected overlaps and duplicates in
1665 libgccjit.c:case_range_validator::validate. */
1667 tree t_expr = expr->as_tree ();
1668 tree t_type = TREE_TYPE (t_expr);
1670 tree t_switch_body = alloc_stmt_list ();
1672 int i;
1673 case_ *c;
1674 FOR_EACH_VEC_ELT (*cases, i, c)
1676 tree t_low_value = c->m_min_value->as_tree ();
1677 tree t_high_value = c->m_max_value->as_tree ();
1678 add_case (&t_switch_body,
1679 t_low_value,
1680 t_high_value,
1681 c->m_dest_block);
1683 /* Default label. */
1684 add_case (&t_switch_body,
1685 NULL_TREE, NULL_TREE,
1686 default_block);
1688 tree switch_stmt = build3 (SWITCH_EXPR, t_type, t_expr,
1689 t_switch_body, NULL_TREE);
1690 if (loc)
1691 set_tree_location (switch_stmt, loc);
1692 add_stmt (switch_stmt);
1695 /* Constructor for gcc::jit::playback::block. */
1697 playback::block::
1698 block (function *func,
1699 const char *name)
1700 : m_func (func),
1701 m_stmts ()
1703 tree identifier;
1705 gcc_assert (func);
1706 // name can be NULL
1707 if (name)
1708 identifier = get_identifier (name);
1709 else
1710 identifier = NULL;
1711 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1712 identifier, void_type_node);
1713 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1714 m_label_expr = NULL;
1717 /* A subclass of auto_vec <char *> that frees all of its elements on
1718 deletion. */
1720 class auto_argvec : public auto_vec <char *>
1722 public:
1723 ~auto_argvec ();
1726 /* auto_argvec's dtor, freeing all contained strings, automatically
1727 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1729 auto_argvec::~auto_argvec ()
1731 int i;
1732 char *str;
1733 FOR_EACH_VEC_ELT (*this, i, str)
1734 free (str);
1737 /* Compile a playback::context:
1739 - Use the context's options to cconstruct command-line options, and
1740 call into the rest of GCC (toplev::main).
1741 - Assuming it succeeds, we have a .s file.
1742 - We then run the "postprocess" vfunc:
1744 (A) In-memory compile ("gcc_jit_context_compile")
1746 For an in-memory compile we have the playback::compile_to_memory
1747 subclass; "postprocess" will convert the .s file to a .so DSO,
1748 and load it in memory (via dlopen), wrapping the result up as
1749 a jit::result and returning it.
1751 (B) Compile to file ("gcc_jit_context_compile_to_file")
1753 When compiling to a file, we have the playback::compile_to_file
1754 subclass; "postprocess" will either copy the .s file to the
1755 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1756 the driver to convert it as necessary, copying the result. */
1758 void
1759 playback::context::
1760 compile ()
1762 JIT_LOG_SCOPE (get_logger ());
1764 const char *ctxt_progname;
1766 int keep_intermediates =
1767 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
1769 m_tempdir = new tempdir (get_logger (), keep_intermediates);
1770 if (!m_tempdir->create ())
1771 return;
1773 /* Call into the rest of gcc.
1774 For now, we have to assemble command-line options to pass into
1775 toplev::main, so that they can be parsed. */
1777 /* Pass in user-provided program name as argv0, if any, so that it
1778 makes it into GCC's "progname" global, used in various diagnostics. */
1779 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1781 if (!ctxt_progname)
1782 ctxt_progname = "libgccjit.so";
1784 auto_vec <recording::requested_dump> requested_dumps;
1785 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1787 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1788 acquire_mutex ();
1790 auto_argvec fake_args;
1791 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
1792 if (errors_occurred ())
1794 release_mutex ();
1795 return;
1798 /* This runs the compiler. */
1799 toplev toplev (false, /* use_TV_TOTAL */
1800 false); /* init_signals */
1801 enter_scope ("toplev::main");
1802 if (get_logger ())
1803 for (unsigned i = 0; i < fake_args.length (); i++)
1804 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
1805 toplev.main (fake_args.length (),
1806 const_cast <char **> (fake_args.address ()));
1807 exit_scope ("toplev::main");
1809 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1810 need to do it between toplev::main (which creates the dump manager)
1811 and toplev::finalize (which deletes it). */
1812 extract_any_requested_dumps (&requested_dumps);
1814 /* Clean up the compiler. */
1815 enter_scope ("toplev::finalize");
1816 toplev.finalize ();
1817 exit_scope ("toplev::finalize");
1819 /* Ideally we would release the jit mutex here, but we can't yet since
1820 followup activities use timevars, which are global state. */
1822 if (errors_occurred ())
1824 release_mutex ();
1825 return;
1828 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1829 dump_generated_code ();
1831 /* We now have a .s file.
1833 Run any postprocessing steps. This will either convert the .s file to
1834 a .so DSO, and load it in memory (playback::compile_to_memory), or
1835 convert the .s file to the requested output format, and copy it to a
1836 given file (playback::compile_to_file). */
1837 postprocess (ctxt_progname);
1839 release_mutex ();
1842 /* Implementation of class gcc::jit::playback::compile_to_memory,
1843 a subclass of gcc::jit::playback::context. */
1845 /* playback::compile_to_memory's trivial constructor. */
1847 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
1848 playback::context (ctxt),
1849 m_result (NULL)
1851 JIT_LOG_SCOPE (get_logger ());
1854 /* Implementation of the playback::context::process vfunc for compiling
1855 to memory.
1857 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1858 wrapping the result up as a jit::result and returning it. */
1860 void
1861 playback::compile_to_memory::postprocess (const char *ctxt_progname)
1863 JIT_LOG_SCOPE (get_logger ());
1864 convert_to_dso (ctxt_progname);
1865 if (errors_occurred ())
1866 return;
1867 m_result = dlopen_built_dso ();
1870 /* Implementation of class gcc::jit::playback::compile_to_file,
1871 a subclass of gcc::jit::playback::context. */
1873 /* playback::compile_to_file's trivial constructor. */
1875 playback::compile_to_file::compile_to_file (recording::context *ctxt,
1876 enum gcc_jit_output_kind output_kind,
1877 const char *output_path) :
1878 playback::context (ctxt),
1879 m_output_kind (output_kind),
1880 m_output_path (output_path)
1882 JIT_LOG_SCOPE (get_logger ());
1885 /* Implementation of the playback::context::process vfunc for compiling
1886 to a file.
1888 Either copy the .s file to the given destination (for
1889 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1890 as necessary, copying the result. */
1892 void
1893 playback::compile_to_file::postprocess (const char *ctxt_progname)
1895 JIT_LOG_SCOPE (get_logger ());
1897 /* The driver takes different actions based on the filename, so
1898 we provide a filename with an appropriate suffix for the
1899 output kind, and then copy it up to the user-provided path,
1900 rather than directly compiling it to the requested output path. */
1902 switch (m_output_kind)
1904 default:
1905 gcc_unreachable ();
1907 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
1908 copy_file (get_tempdir ()->get_path_s_file (),
1909 m_output_path);
1910 break;
1912 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
1914 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
1915 "/fake.o",
1916 NULL);
1917 invoke_driver (ctxt_progname,
1918 get_tempdir ()->get_path_s_file (),
1919 tmp_o_path,
1920 TV_ASSEMBLE,
1921 false, /* bool shared, */
1922 false);/* bool run_linker */
1923 if (!errors_occurred ())
1924 copy_file (tmp_o_path,
1925 m_output_path);
1926 free (tmp_o_path);
1928 break;
1930 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
1931 invoke_driver (ctxt_progname,
1932 get_tempdir ()->get_path_s_file (),
1933 get_tempdir ()->get_path_so_file (),
1934 TV_ASSEMBLE,
1935 true, /* bool shared, */
1936 true);/* bool run_linker */
1937 if (!errors_occurred ())
1938 copy_file (get_tempdir ()->get_path_so_file (),
1939 m_output_path);
1940 break;
1942 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
1944 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
1945 "/fake.exe",
1946 NULL);
1947 invoke_driver (ctxt_progname,
1948 get_tempdir ()->get_path_s_file (),
1949 tmp_exe_path,
1950 TV_ASSEMBLE,
1951 false, /* bool shared, */
1952 true);/* bool run_linker */
1953 if (!errors_occurred ())
1954 copy_file (tmp_exe_path,
1955 m_output_path);
1956 free (tmp_exe_path);
1958 break;
1964 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
1965 the "executable" bits).
1967 Any errors that occur are reported on the context and hence count as
1968 a failure of the compile.
1970 We can't in general hardlink or use "rename" from the tempdir since
1971 it might be on a different filesystem to the destination. For example,
1972 I get EXDEV: "Invalid cross-device link". */
1974 void
1975 playback::compile_to_file::copy_file (const char *src_path,
1976 const char *dst_path)
1978 JIT_LOG_SCOPE (get_logger ());
1979 if (get_logger ())
1981 get_logger ()->log ("src_path: %s", src_path);
1982 get_logger ()->log ("dst_path: %s", dst_path);
1985 FILE *f_in = NULL;
1986 FILE *f_out = NULL;
1987 size_t total_sz_in = 0;
1988 size_t total_sz_out = 0;
1989 char buf[4096];
1990 size_t sz_in;
1991 struct stat stat_buf;
1993 f_in = fopen (src_path, "rb");
1994 if (!f_in)
1996 add_error (NULL,
1997 "unable to open %s for reading: %s",
1998 src_path,
1999 xstrerror (errno));
2000 return;
2003 /* Use stat on the filedescriptor to get the mode,
2004 so that we can copy it over (in particular, the
2005 "executable" bits). */
2006 if (-1 == fstat (fileno (f_in), &stat_buf))
2008 add_error (NULL,
2009 "unable to fstat %s: %s",
2010 src_path,
2011 xstrerror (errno));
2012 fclose (f_in);
2013 return;
2016 f_out = fopen (dst_path, "wb");
2017 if (!f_out)
2019 add_error (NULL,
2020 "unable to open %s for writing: %s",
2021 dst_path,
2022 xstrerror (errno));
2023 fclose (f_in);
2024 return;
2027 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2029 total_sz_in += sz_in;
2030 size_t sz_out_remaining = sz_in;
2031 size_t sz_out_so_far = 0;
2032 while (sz_out_remaining)
2034 size_t sz_out = fwrite (buf + sz_out_so_far,
2036 sz_out_remaining,
2037 f_out);
2038 gcc_assert (sz_out <= sz_out_remaining);
2039 if (!sz_out)
2041 add_error (NULL,
2042 "error writing to %s: %s",
2043 dst_path,
2044 xstrerror (errno));
2045 fclose (f_in);
2046 fclose (f_out);
2047 return;
2049 total_sz_out += sz_out;
2050 sz_out_so_far += sz_out;
2051 sz_out_remaining -= sz_out;
2053 gcc_assert (sz_out_so_far == sz_in);
2056 if (!feof (f_in))
2057 add_error (NULL,
2058 "error reading from %s: %s",
2059 src_path,
2060 xstrerror (errno));
2062 fclose (f_in);
2064 gcc_assert (total_sz_in == total_sz_out);
2065 if (get_logger ())
2066 get_logger ()->log ("total bytes copied: %ld", total_sz_out);
2068 /* Set the permissions of the copy to those of the original file,
2069 in particular the "executable" bits. */
2070 if (-1 == fchmod (fileno (f_out), stat_buf.st_mode))
2071 add_error (NULL,
2072 "error setting mode of %s: %s",
2073 dst_path,
2074 xstrerror (errno));
2076 fclose (f_out);
2079 /* Helper functions for gcc::jit::playback::context::compile. */
2081 /* This mutex guards gcc::jit::recording::context::compile, so that only
2082 one thread can be accessing the bulk of GCC's state at once. */
2084 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2086 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2088 void
2089 playback::context::acquire_mutex ()
2091 /* Acquire the big GCC mutex. */
2092 JIT_LOG_SCOPE (get_logger ());
2093 pthread_mutex_lock (&jit_mutex);
2094 gcc_assert (NULL == active_playback_ctxt);
2095 active_playback_ctxt = this;
2098 /* Release jit_mutex and clear the active playback ctxt. */
2100 void
2101 playback::context::release_mutex ()
2103 /* Release the big GCC mutex. */
2104 JIT_LOG_SCOPE (get_logger ());
2105 gcc_assert (active_playback_ctxt == this);
2106 active_playback_ctxt = NULL;
2107 pthread_mutex_unlock (&jit_mutex);
2110 /* Callback used by gcc::jit::playback::context::make_fake_args when
2111 invoking driver_get_configure_time_options.
2112 Populate a vec <char * > with the configure-time options. */
2114 static void
2115 append_arg_from_driver (const char *option, void *user_data)
2117 gcc_assert (option);
2118 gcc_assert (user_data);
2119 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2120 argvec->safe_push (concat ("-", option, NULL));
2123 /* Build a fake argv for toplev::main from the options set
2124 by the user on the context . */
2126 void
2127 playback::context::
2128 make_fake_args (vec <char *> *argvec,
2129 const char *ctxt_progname,
2130 vec <recording::requested_dump> *requested_dumps)
2132 JIT_LOG_SCOPE (get_logger ());
2134 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2135 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2137 ADD_ARG (ctxt_progname);
2138 ADD_ARG (get_path_c_file ());
2139 ADD_ARG ("-fPIC");
2141 /* Handle int options: */
2142 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2144 default:
2145 add_error (NULL,
2146 "unrecognized optimization level: %i",
2147 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2148 return;
2150 case 0:
2151 ADD_ARG ("-O0");
2152 break;
2154 case 1:
2155 ADD_ARG ("-O1");
2156 break;
2158 case 2:
2159 ADD_ARG ("-O2");
2160 break;
2162 case 3:
2163 ADD_ARG ("-O3");
2164 break;
2166 /* What about -Os? */
2168 /* Handle bool options: */
2169 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2170 ADD_ARG ("-g");
2172 /* Suppress timing (and other) info. */
2173 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2175 ADD_ARG ("-quiet");
2176 quiet_flag = 1;
2179 /* Aggressively garbage-collect, to shake out bugs: */
2180 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2182 ADD_ARG ("--param");
2183 ADD_ARG ("ggc-min-expand=0");
2184 ADD_ARG ("--param");
2185 ADD_ARG ("ggc-min-heapsize=0");
2188 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2190 ADD_ARG ("-fdump-tree-all");
2191 ADD_ARG ("-fdump-rtl-all");
2192 ADD_ARG ("-fdump-ipa-all");
2195 /* Add "-fdump-" options for any calls to
2196 gcc_jit_context_enable_dump. */
2198 int i;
2199 recording::requested_dump *d;
2200 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2202 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2203 ADD_ARG_TAKE_OWNERSHIP (arg);
2207 /* PR jit/64810: Add any target-specific default options
2208 from OPTION_DEFAULT_SPECS, normally provided by the driver
2209 in the non-jit case.
2211 The target-specific code can define OPTION_DEFAULT_SPECS:
2212 default command options in the form of spec macros for the
2213 driver to expand ().
2215 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2216 if not overriden, injects the defaults as extra arguments to
2217 cc1 etc.
2218 For the jit case, we need to add these arguments here. The
2219 input format (using the specs language) means that we have to run
2220 part of the driver code here (driver_get_configure_time_options).
2222 To avoid running the spec-expansion code every time, we just do
2223 it the first time (via a function-static flag), saving the result
2224 into a function-static vec.
2225 This flag and vec are global state (i.e. per-process).
2226 They are guarded by the jit mutex. */
2228 static bool have_configure_time_options = false;
2229 static vec <char *> configure_time_options;
2231 if (have_configure_time_options)
2232 log ("reusing cached configure-time options");
2233 else
2235 have_configure_time_options = true;
2236 log ("getting configure-time options from driver");
2237 driver_get_configure_time_options (append_arg_from_driver,
2238 &configure_time_options);
2241 int i;
2242 char *opt;
2244 if (get_logger ())
2245 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2246 log ("configure_time_options[%i]: %s", i, opt);
2248 /* configure_time_options should now contain the expanded options
2249 from OPTION_DEFAULT_SPECS (if any). */
2250 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2252 gcc_assert (opt);
2253 gcc_assert (opt[0] == '-');
2254 ADD_ARG (opt);
2258 /* Add any user-provided extra options, starting with any from
2259 parent contexts. */
2260 m_recording_ctxt->append_command_line_options (argvec);
2262 #undef ADD_ARG
2263 #undef ADD_ARG_TAKE_OWNERSHIP
2266 /* The second half of the implementation of gcc_jit_context_enable_dump.
2267 Iterate through the requested dumps, reading the underlying files
2268 into heap-allocated buffers, writing pointers to the buffers into
2269 the char ** pointers provided by client code.
2270 Client code is responsible for calling free on the results. */
2272 void
2273 playback::context::
2274 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2276 JIT_LOG_SCOPE (get_logger ());
2278 int i;
2279 recording::requested_dump *d;
2280 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2282 dump_file_info *dfi;
2283 char *filename;
2284 char *content;
2286 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2287 if (!dfi)
2289 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2290 continue;
2293 filename = g->get_dumps ()->get_dump_file_name (dfi);
2294 content = read_dump_file (filename);
2295 *(d->m_out_ptr) = content;
2296 free (filename);
2300 /* Helper function for playback::context::extract_any_requested_dumps
2301 (itself for use in implementation of gcc_jit_context_enable_dump).
2303 Attempt to read the complete file at the given path, returning the
2304 bytes found there as a buffer.
2305 The caller is responsible for calling free on the result.
2306 Errors will be reported on the context, and lead to NULL being
2307 returned; an out-of-memory error will terminate the process. */
2309 char *
2310 playback::context::read_dump_file (const char *path)
2312 char *result = NULL;
2313 size_t total_sz = 0;
2314 char buf[4096];
2315 size_t sz;
2316 FILE *f_in;
2318 f_in = fopen (path, "r");
2319 if (!f_in)
2321 add_error (NULL, "unable to open %s for reading", path);
2322 return NULL;
2325 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2327 size_t old_total_sz = total_sz;
2328 total_sz += sz;
2329 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2330 memcpy (result + old_total_sz, buf, sz);
2333 if (!feof (f_in))
2335 add_error (NULL, "error reading from %s", path);
2336 free (result);
2337 fclose (f_in);
2338 return NULL;
2341 fclose (f_in);
2343 if (result)
2345 result[total_sz] = '\0';
2346 return result;
2348 else
2349 return xstrdup ("");
2352 /* Part of playback::context::compile ().
2354 We have a .s file; we want a .so file.
2355 We could reuse parts of gcc/gcc.c to do this.
2356 For now, just use the driver binary from the install, as
2357 named in gcc-driver-name.h
2358 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2360 void
2361 playback::context::
2362 convert_to_dso (const char *ctxt_progname)
2364 JIT_LOG_SCOPE (get_logger ());
2366 invoke_driver (ctxt_progname,
2367 m_tempdir->get_path_s_file (),
2368 m_tempdir->get_path_so_file (),
2369 TV_ASSEMBLE,
2370 true, /* bool shared, */
2371 true);/* bool run_linker */
2374 void
2375 playback::context::
2376 invoke_driver (const char *ctxt_progname,
2377 const char *input_file,
2378 const char *output_file,
2379 timevar_id_t tv_id,
2380 bool shared,
2381 bool run_linker)
2383 JIT_LOG_SCOPE (get_logger ());
2384 /* Currently this lumps together both assembling and linking into
2385 TV_ASSEMBLE. */
2386 auto_timevar assemble_timevar (tv_id);
2387 const char *errmsg;
2388 auto_vec <const char *> argvec;
2389 #define ADD_ARG(arg) argvec.safe_push (arg)
2390 int exit_status = 0;
2391 int err = 0;
2392 const char *gcc_driver_name = GCC_DRIVER_NAME;
2394 ADD_ARG (gcc_driver_name);
2396 if (shared)
2397 ADD_ARG ("-shared");
2399 if (!run_linker)
2400 ADD_ARG ("-c");
2402 ADD_ARG (input_file);
2403 ADD_ARG ("-o");
2404 ADD_ARG (output_file);
2406 /* Don't use the linker plugin.
2407 If running with just a "make" and not a "make install", then we'd
2408 run into
2409 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2410 libto_plugin is a .la at build time, with it becoming installed with
2411 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2412 time. */
2413 ADD_ARG ("-fno-use-linker-plugin");
2415 /* pex argv arrays are NULL-terminated. */
2416 ADD_ARG (NULL);
2418 /* pex_one's error-handling requires pname to be non-NULL. */
2419 gcc_assert (ctxt_progname);
2421 if (get_logger ())
2422 for (unsigned i = 0; i < argvec.length (); i++)
2423 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2425 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2426 gcc_driver_name,
2427 const_cast <char *const *> (argvec.address ()),
2428 ctxt_progname, /* const char *pname */
2429 NULL, /* const char *outname */
2430 NULL, /* const char *errname */
2431 &exit_status, /* int *status */
2432 &err); /* int *err*/
2433 if (errmsg)
2435 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2436 return;
2439 /* pex_one can return a NULL errmsg when the executable wasn't
2440 found (or doesn't exist), so trap these cases also. */
2441 if (exit_status || err)
2443 add_error (NULL,
2444 "error invoking gcc driver: exit_status: %i err: %i",
2445 exit_status, err);
2446 add_error (NULL,
2447 "whilst attempting to run a driver named: %s",
2448 gcc_driver_name);
2449 add_error (NULL,
2450 "PATH was: %s",
2451 getenv ("PATH"));
2452 return;
2454 #undef ADD_ARG
2457 /* Dynamically-link the built DSO file into this process, using dlopen.
2458 Wrap it up within a jit::result *, and return that.
2459 Return NULL if any errors occur, reporting them on this context. */
2461 result *
2462 playback::context::
2463 dlopen_built_dso ()
2465 JIT_LOG_SCOPE (get_logger ());
2466 auto_timevar load_timevar (TV_LOAD);
2467 void *handle = NULL;
2468 const char *error = NULL;
2469 result *result_obj = NULL;
2471 /* Clear any existing error. */
2472 dlerror ();
2474 handle = dlopen (m_tempdir->get_path_so_file (),
2475 RTLD_NOW | RTLD_LOCAL);
2476 if ((error = dlerror()) != NULL) {
2477 add_error (NULL, "%s", error);
2479 if (handle)
2481 /* We've successfully dlopened the result; create a
2482 jit::result object to wrap it.
2484 We're done with the tempdir for now, but if the user
2485 has requested debugging, the user's debugger might not
2486 be capable of dealing with the .so file being unlinked
2487 immediately, so keep it around until after the result
2488 is released. We do this by handing over ownership of
2489 the jit::tempdir to the result. See PR jit/64206. */
2490 tempdir *handover_tempdir;
2491 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2493 handover_tempdir = m_tempdir;
2494 m_tempdir = NULL;
2495 /* The tempdir will eventually be cleaned up in the
2496 jit::result's dtor. */
2497 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2498 " handing over tempdir to jit::result");
2500 else
2502 handover_tempdir = NULL;
2503 /* ... and retain ownership of m_tempdir so we clean it
2504 up it the playback::context's dtor. */
2505 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2506 " retaining ownership of tempdir");
2509 result_obj = new result (get_logger (), handle, handover_tempdir);
2511 else
2512 result_obj = NULL;
2514 return result_obj;
2517 /* Top-level hook for playing back a recording context.
2519 This plays back m_recording_ctxt, and, if no errors
2520 occurred builds statement lists for and then postprocesses
2521 every function in the result. */
2523 void
2524 playback::context::
2525 replay ()
2527 JIT_LOG_SCOPE (get_logger ());
2528 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2529 tree array_domain_type = build_index_type (size_int (200));
2530 m_char_array_type_node
2531 = build_array_type (char_type_node, array_domain_type);
2533 m_const_char_ptr
2534 = build_pointer_type (build_qualified_type (char_type_node,
2535 TYPE_QUAL_CONST));
2537 /* Replay the recorded events: */
2538 timevar_push (TV_JIT_REPLAY);
2540 m_recording_ctxt->replay_into (this);
2542 /* Clean away the temporary references from recording objects
2543 to playback objects. We have to do this now since the
2544 latter are GC-allocated, but the former don't mark these
2545 refs. Hence we must stop using them before the GC can run. */
2546 m_recording_ctxt->disassociate_from_playback ();
2548 /* The builtins_manager, if any, is associated with the recording::context
2549 and might be reused for future compiles on other playback::contexts,
2550 but its m_attributes array is not GTY-labeled and hence will become
2551 nonsense if the GC runs. Purge this state. */
2552 builtins_manager *bm = get_builtins_manager ();
2553 if (bm)
2554 bm->finish_playback ();
2556 timevar_pop (TV_JIT_REPLAY);
2558 if (!errors_occurred ())
2560 int i;
2561 function *func;
2563 /* No GC can happen yet; process the cached source locations. */
2564 handle_locations ();
2566 /* We've now created tree nodes for the stmts in the various blocks
2567 in each function, but we haven't built each function's single stmt
2568 list yet. Do so now. */
2569 FOR_EACH_VEC_ELT (m_functions, i, func)
2570 func->build_stmt_list ();
2572 /* No GC can have happened yet. */
2574 /* Postprocess the functions. This could trigger GC. */
2575 FOR_EACH_VEC_ELT (m_functions, i, func)
2577 gcc_assert (func);
2578 func->postprocess ();
2583 /* Dump the generated .s file to stderr. */
2585 void
2586 playback::context::
2587 dump_generated_code ()
2589 JIT_LOG_SCOPE (get_logger ());
2590 char buf[4096];
2591 size_t sz;
2592 FILE *f_in = fopen (get_path_s_file (), "r");
2593 if (!f_in)
2594 return;
2596 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2597 fwrite (buf, 1, sz, stderr);
2599 fclose (f_in);
2602 /* Get the supposed path of the notional "fake.c" file within the
2603 tempdir. This file doesn't exist, but the rest of the compiler
2604 needs a name. */
2606 const char *
2607 playback::context::
2608 get_path_c_file () const
2610 return m_tempdir->get_path_c_file ();
2613 /* Get the path of the assembler output file "fake.s" file within the
2614 tempdir. */
2616 const char *
2617 playback::context::
2618 get_path_s_file () const
2620 return m_tempdir->get_path_s_file ();
2623 /* Get the path of the DSO object file "fake.so" file within the
2624 tempdir. */
2626 const char *
2627 playback::context::
2628 get_path_so_file () const
2630 return m_tempdir->get_path_so_file ();
2633 /* qsort comparator for comparing pairs of playback::source_line *,
2634 ordering them by line number. */
2636 static int
2637 line_comparator (const void *lhs, const void *rhs)
2639 const playback::source_line *line_lhs = \
2640 *static_cast<const playback::source_line * const*> (lhs);
2641 const playback::source_line *line_rhs = \
2642 *static_cast<const playback::source_line * const*> (rhs);
2643 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2646 /* qsort comparator for comparing pairs of playback::location *,
2647 ordering them by column number. */
2649 static int
2650 location_comparator (const void *lhs, const void *rhs)
2652 const playback::location *loc_lhs = \
2653 *static_cast<const playback::location * const *> (lhs);
2654 const playback::location *loc_rhs = \
2655 *static_cast<const playback::location * const *> (rhs);
2656 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2659 /* Our API allows locations to be created in arbitrary orders, but the
2660 linemap API requires locations to be created in ascending order
2661 as if we were tokenizing files.
2663 This hook sorts all of the the locations that have been created, and
2664 calls into the linemap API, creating linemap entries in sorted order
2665 for our locations. */
2667 void
2668 playback::context::
2669 handle_locations ()
2671 /* Create the source code locations, following the ordering rules
2672 imposed by the linemap API.
2674 line_table is a global. */
2675 JIT_LOG_SCOPE (get_logger ());
2676 int i;
2677 source_file *file;
2679 FOR_EACH_VEC_ELT (m_source_files, i, file)
2681 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2683 /* Sort lines by ascending line numbers. */
2684 file->m_source_lines.qsort (&line_comparator);
2686 int j;
2687 source_line *line;
2688 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2690 int k;
2691 location *loc;
2693 /* Sort locations in line by ascending column numbers. */
2694 line->m_locations.qsort (&location_comparator);
2696 /* Determine maximum column within this line. */
2697 gcc_assert (line->m_locations.length () > 0);
2698 location *final_column =
2699 line->m_locations[line->m_locations.length () - 1];
2700 int max_col = final_column->get_column_num ();
2702 linemap_line_start (line_table, line->get_line_num (), max_col);
2703 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2705 loc->m_srcloc = \
2706 linemap_position_for_column (line_table, loc->get_column_num ());
2710 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2713 /* line_table should now be populated; every playback::location should
2714 now have an m_srcloc. */
2716 /* Now assign them to tree nodes as appropriate. */
2717 std::pair<tree, location *> *cached_location;
2719 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2721 tree t = cached_location->first;
2722 source_location srcloc = cached_location->second->m_srcloc;
2724 /* This covers expressions: */
2725 if (CAN_HAVE_LOCATION_P (t))
2726 SET_EXPR_LOCATION (t, srcloc);
2727 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2728 DECL_SOURCE_LOCATION (t) = srcloc;
2729 else
2731 /* Don't know how to set location on this node. */
2736 /* We handle errors on a playback::context by adding them to the
2737 corresponding recording::context. */
2739 void
2740 playback::context::
2741 add_error (location *loc, const char *fmt, ...)
2743 va_list ap;
2744 va_start (ap, fmt);
2745 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2746 fmt, ap);
2747 va_end (ap);
2750 /* We handle errors on a playback::context by adding them to the
2751 corresponding recording::context. */
2753 void
2754 playback::context::
2755 add_error_va (location *loc, const char *fmt, va_list ap)
2757 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2758 fmt, ap);
2761 /* Dealing with the linemap API. */
2763 /* Construct a playback::location for a recording::location, if it
2764 doesn't exist already. */
2766 playback::location *
2767 playback::context::
2768 new_location (recording::location *rloc,
2769 const char *filename,
2770 int line,
2771 int column)
2773 /* Get the source_file for filename, creating if necessary. */
2774 source_file *src_file = get_source_file (filename);
2775 /* Likewise for the line within the file. */
2776 source_line *src_line = src_file->get_source_line (line);
2777 /* Likewise for the column within the line. */
2778 location *loc = src_line->get_location (rloc, column);
2779 return loc;
2782 /* Deferred setting of the location for a given tree, by adding the
2783 (tree, playback::location) pair to a list of deferred associations.
2784 We will actually set the location on the tree later on once
2785 the source_location for the playback::location exists. */
2787 void
2788 playback::context::
2789 set_tree_location (tree t, location *loc)
2791 gcc_assert (loc);
2792 m_cached_locations.safe_push (std::make_pair (t, loc));
2796 /* Construct a playback::source_file for the given source
2797 filename, if it doesn't exist already. */
2799 playback::source_file *
2800 playback::context::
2801 get_source_file (const char *filename)
2803 /* Locate the file.
2804 For simplicitly, this is currently a linear search.
2805 Replace with a hash if this shows up in the profile. */
2806 int i;
2807 source_file *file;
2808 tree ident_filename = get_identifier (filename);
2810 FOR_EACH_VEC_ELT (m_source_files, i, file)
2811 if (file->filename_as_tree () == ident_filename)
2812 return file;
2814 /* Not found. */
2815 file = new source_file (ident_filename);
2816 m_source_files.safe_push (file);
2817 return file;
2820 /* Constructor for gcc::jit::playback::source_file. */
2822 playback::source_file::source_file (tree filename) :
2823 m_source_lines (),
2824 m_filename (filename)
2828 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2829 GC-ed. */
2831 void
2832 playback::source_file::finalizer ()
2834 m_source_lines.release ();
2837 /* Construct a playback::source_line for the given line
2838 within this source file, if one doesn't exist already. */
2840 playback::source_line *
2841 playback::source_file::
2842 get_source_line (int line_num)
2844 /* Locate the line.
2845 For simplicitly, this is currently a linear search.
2846 Replace with a hash if this shows up in the profile. */
2847 int i;
2848 source_line *line;
2850 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2851 if (line->get_line_num () == line_num)
2852 return line;
2854 /* Not found. */
2855 line = new source_line (this, line_num);
2856 m_source_lines.safe_push (line);
2857 return line;
2860 /* Constructor for gcc::jit::playback::source_line. */
2862 playback::source_line::source_line (source_file *file, int line_num) :
2863 m_locations (),
2864 m_source_file (file),
2865 m_line_num (line_num)
2869 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2870 GC-ed. */
2872 void
2873 playback::source_line::finalizer ()
2875 m_locations.release ();
2878 /* Construct a playback::location for the given column
2879 within this line of a specific source file, if one doesn't exist
2880 already. */
2882 playback::location *
2883 playback::source_line::
2884 get_location (recording::location *rloc, int column_num)
2886 int i;
2887 location *loc;
2889 /* Another linear search that probably should be a hash table. */
2890 FOR_EACH_VEC_ELT (m_locations, i, loc)
2891 if (loc->get_column_num () == column_num)
2892 return loc;
2894 /* Not found. */
2895 loc = new location (rloc, this, column_num);
2896 m_locations.safe_push (loc);
2897 return loc;
2900 /* Constructor for gcc::jit::playback::location. */
2902 playback::location::location (recording::location *loc,
2903 source_line *line,
2904 int column_num) :
2905 m_srcloc (UNKNOWN_LOCATION),
2906 m_recording_loc (loc),
2907 m_line (line),
2908 m_column_num(column_num)
2912 /* The active gcc::jit::playback::context instance. This is a singleton,
2913 guarded by jit_mutex. */
2915 playback::context *active_playback_ctxt;
2917 } // namespace gcc::jit
2919 } // namespace gcc