Fix version check for ATTRIBUTE_GCC_DUMP_PRINTF
[official-gcc.git] / gcc / jit / jit-playback.c
blobf11642bf4c639864469fa8e4e23b0e0b40b6bcdf
1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2018 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "target.h"
25 #include "tree.h"
26 #include "stringpool.h"
27 #include "cgraph.h"
28 #include "dumpfile.h"
29 #include "toplev.h"
30 #include "tree-cfg.h"
31 #include "convert.h"
32 #include "stor-layout.h"
33 #include "print-tree.h"
34 #include "gimplify.h"
35 #include "gcc-driver-name.h"
36 #include "attribs.h"
37 #include "context.h"
38 #include "fold-const.h"
39 #include "opt-suggestions.h"
40 #include "gcc.h"
41 #include "diagnostic.h"
43 #include <pthread.h>
45 #include "jit-playback.h"
46 #include "jit-result.h"
47 #include "jit-builtins.h"
48 #include "jit-tempdir.h"
51 /* gcc::jit::playback::context::build_cast uses the convert.h API,
52 which in turn requires the frontend to provide a "convert"
53 function, apparently as a fallback.
55 Hence we provide this dummy one, with the requirement that any casts
56 are handled before reaching this. */
57 extern tree convert (tree type, tree expr);
59 tree
60 convert (tree dst_type, tree expr)
62 gcc_assert (gcc::jit::active_playback_ctxt);
63 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
64 fprintf (stderr, "input expression:\n");
65 debug_tree (expr);
66 fprintf (stderr, "requested type:\n");
67 debug_tree (dst_type);
68 return error_mark_node;
71 namespace gcc {
72 namespace jit {
74 /**********************************************************************
75 Playback.
76 **********************************************************************/
78 /* The constructor for gcc::jit::playback::context. */
80 playback::context::context (recording::context *ctxt)
81 : log_user (ctxt->get_logger ()),
82 m_recording_ctxt (ctxt),
83 m_tempdir (NULL),
84 m_char_array_type_node (NULL),
85 m_const_char_ptr (NULL)
87 JIT_LOG_SCOPE (get_logger ());
88 m_functions.create (0);
89 m_globals.create (0);
90 m_source_files.create (0);
91 m_cached_locations.create (0);
94 /* The destructor for gcc::jit::playback::context. */
96 playback::context::~context ()
98 JIT_LOG_SCOPE (get_logger ());
100 /* Normally the playback::context is responsible for cleaning up the
101 tempdir (including "fake.so" within the filesystem).
103 In the normal case, clean it up now.
105 However m_tempdir can be NULL if the context has handed over
106 responsibility for the tempdir cleanup to the jit::result object, so
107 that the cleanup can be delayed (see PR jit/64206). If that's the
108 case this "delete NULL;" is a no-op. */
109 delete m_tempdir;
111 m_functions.release ();
114 /* A playback::context can reference GC-managed pointers. Mark them
115 ("by hand", rather than by gengtype).
117 This is called on the active playback context (if any) by the
118 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
120 void
121 playback::context::
122 gt_ggc_mx ()
124 int i;
125 function *func;
126 FOR_EACH_VEC_ELT (m_functions, i, func)
128 if (ggc_test_and_set_mark (func))
129 func->gt_ggc_mx ();
133 /* Given an enum gcc_jit_types value, get a "tree" type. */
135 static tree
136 get_tree_node_for_type (enum gcc_jit_types type_)
138 switch (type_)
140 case GCC_JIT_TYPE_VOID:
141 return void_type_node;
143 case GCC_JIT_TYPE_VOID_PTR:
144 return ptr_type_node;
146 case GCC_JIT_TYPE_BOOL:
147 return boolean_type_node;
149 case GCC_JIT_TYPE_CHAR:
150 return char_type_node;
151 case GCC_JIT_TYPE_SIGNED_CHAR:
152 return signed_char_type_node;
153 case GCC_JIT_TYPE_UNSIGNED_CHAR:
154 return unsigned_char_type_node;
156 case GCC_JIT_TYPE_SHORT:
157 return short_integer_type_node;
158 case GCC_JIT_TYPE_UNSIGNED_SHORT:
159 return short_unsigned_type_node;
161 case GCC_JIT_TYPE_CONST_CHAR_PTR:
163 tree const_char = build_qualified_type (char_type_node,
164 TYPE_QUAL_CONST);
165 return build_pointer_type (const_char);
168 case GCC_JIT_TYPE_INT:
169 return integer_type_node;
170 case GCC_JIT_TYPE_UNSIGNED_INT:
171 return unsigned_type_node;
173 case GCC_JIT_TYPE_LONG:
174 return long_integer_type_node;
175 case GCC_JIT_TYPE_UNSIGNED_LONG:
176 return long_unsigned_type_node;
178 case GCC_JIT_TYPE_LONG_LONG:
179 return long_long_integer_type_node;
180 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
181 return long_long_unsigned_type_node;
183 case GCC_JIT_TYPE_FLOAT:
184 return float_type_node;
185 case GCC_JIT_TYPE_DOUBLE:
186 return double_type_node;
187 case GCC_JIT_TYPE_LONG_DOUBLE:
188 return long_double_type_node;
190 case GCC_JIT_TYPE_SIZE_T:
191 return size_type_node;
193 case GCC_JIT_TYPE_FILE_PTR:
194 return fileptr_type_node;
196 case GCC_JIT_TYPE_COMPLEX_FLOAT:
197 return complex_float_type_node;
198 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
199 return complex_double_type_node;
200 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
201 return complex_long_double_type_node;
204 return NULL;
207 /* Construct a playback::type instance (wrapping a tree) for the given
208 enum value. */
210 playback::type *
211 playback::context::
212 get_type (enum gcc_jit_types type_)
214 tree type_node = get_tree_node_for_type (type_);
215 if (type_node == NULL)
217 add_error (NULL, "unrecognized (enum gcc_jit_types) value: %i", type_);
218 return NULL;
221 return new type (type_node);
224 /* Construct a playback::type instance (wrapping a tree) for the given
225 array type. */
227 playback::type *
228 playback::context::
229 new_array_type (playback::location *loc,
230 playback::type *element_type,
231 int num_elements)
233 gcc_assert (element_type);
235 tree t = build_array_type_nelts (element_type->as_tree (),
236 num_elements);
237 layout_type (t);
239 if (loc)
240 set_tree_location (t, loc);
242 return new type (t);
245 /* Construct a playback::field instance (wrapping a tree). */
247 playback::field *
248 playback::context::
249 new_field (location *loc,
250 type *type,
251 const char *name)
253 gcc_assert (type);
254 gcc_assert (name);
256 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
257 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
258 get_identifier (name), type->as_tree ());
260 if (loc)
261 set_tree_location (decl, loc);
263 return new field (decl);
266 /* Construct a playback::compound_type instance (wrapping a tree). */
268 playback::compound_type *
269 playback::context::
270 new_compound_type (location *loc,
271 const char *name,
272 bool is_struct) /* else is union */
274 gcc_assert (name);
276 /* Compare with c/c-decl.c: start_struct. */
278 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
279 TYPE_NAME (t) = get_identifier (name);
280 TYPE_SIZE (t) = 0;
282 if (loc)
283 set_tree_location (t, loc);
285 return new compound_type (t);
288 void
289 playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
291 /* Compare with c/c-decl.c: finish_struct. */
292 tree t = as_tree ();
294 tree fieldlist = NULL;
295 for (unsigned i = 0; i < fields->length (); i++)
297 field *f = (*fields)[i];
298 DECL_CONTEXT (f->as_tree ()) = t;
299 fieldlist = chainon (f->as_tree (), fieldlist);
301 fieldlist = nreverse (fieldlist);
302 TYPE_FIELDS (t) = fieldlist;
304 layout_type (t);
307 /* Construct a playback::type instance (wrapping a tree) for a function
308 type. */
310 playback::type *
311 playback::context::
312 new_function_type (type *return_type,
313 const auto_vec<type *> *param_types,
314 int is_variadic)
316 int i;
317 type *param_type;
319 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
321 FOR_EACH_VEC_ELT (*param_types, i, param_type)
322 arg_types[i] = param_type->as_tree ();
324 tree fn_type;
325 if (is_variadic)
326 fn_type =
327 build_varargs_function_type_array (return_type->as_tree (),
328 param_types->length (),
329 arg_types);
330 else
331 fn_type = build_function_type_array (return_type->as_tree (),
332 param_types->length (),
333 arg_types);
334 free (arg_types);
336 return new type (fn_type);
339 /* Construct a playback::param instance (wrapping a tree). */
341 playback::param *
342 playback::context::
343 new_param (location *loc,
344 type *type,
345 const char *name)
347 gcc_assert (type);
348 gcc_assert (name);
349 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
350 get_identifier (name), type->as_tree ());
351 if (loc)
352 set_tree_location (inner, loc);
354 return new param (this, inner);
357 /* Construct a playback::function instance. */
359 playback::function *
360 playback::context::
361 new_function (location *loc,
362 enum gcc_jit_function_kind kind,
363 type *return_type,
364 const char *name,
365 const auto_vec<param *> *params,
366 int is_variadic,
367 enum built_in_function builtin_id)
369 int i;
370 param *param;
372 //can return_type be NULL?
373 gcc_assert (name);
375 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
376 FOR_EACH_VEC_ELT (*params, i, param)
377 arg_types[i] = TREE_TYPE (param->as_tree ());
379 tree fn_type;
380 if (is_variadic)
381 fn_type = build_varargs_function_type_array (return_type->as_tree (),
382 params->length (), arg_types);
383 else
384 fn_type = build_function_type_array (return_type->as_tree (),
385 params->length (), arg_types);
386 free (arg_types);
388 /* FIXME: this uses input_location: */
389 tree fndecl = build_fn_decl (name, fn_type);
391 if (loc)
392 set_tree_location (fndecl, loc);
394 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
395 NULL_TREE, return_type->as_tree ());
396 DECL_ARTIFICIAL (resdecl) = 1;
397 DECL_IGNORED_P (resdecl) = 1;
398 DECL_RESULT (fndecl) = resdecl;
400 if (builtin_id)
402 DECL_FUNCTION_CODE (fndecl) = builtin_id;
403 gcc_assert (loc == NULL);
404 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
406 DECL_BUILT_IN_CLASS (fndecl) =
407 builtins_manager::get_class (builtin_id);
408 set_builtin_decl (builtin_id, fndecl,
409 builtins_manager::implicit_p (builtin_id));
411 builtins_manager *bm = get_builtins_manager ();
412 tree attrs = bm->get_attrs_tree (builtin_id);
413 if (attrs)
414 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
415 else
416 decl_attributes (&fndecl, NULL_TREE, 0);
419 if (kind != GCC_JIT_FUNCTION_IMPORTED)
421 tree param_decl_list = NULL;
422 FOR_EACH_VEC_ELT (*params, i, param)
424 param_decl_list = chainon (param->as_tree (), param_decl_list);
427 /* The param list was created in reverse order; fix it: */
428 param_decl_list = nreverse (param_decl_list);
430 tree t;
431 for (t = param_decl_list; t; t = DECL_CHAIN (t))
433 DECL_CONTEXT (t) = fndecl;
434 DECL_ARG_TYPE (t) = TREE_TYPE (t);
437 /* Set it up on DECL_ARGUMENTS */
438 DECL_ARGUMENTS(fndecl) = param_decl_list;
441 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
443 DECL_DECLARED_INLINE_P (fndecl) = 1;
445 /* Add attribute "always_inline": */
446 DECL_ATTRIBUTES (fndecl) =
447 tree_cons (get_identifier ("always_inline"),
448 NULL,
449 DECL_ATTRIBUTES (fndecl));
452 function *func = new function (this, fndecl, kind);
453 m_functions.safe_push (func);
454 return func;
457 /* Construct a playback::lvalue instance (wrapping a tree). */
459 playback::lvalue *
460 playback::context::
461 new_global (location *loc,
462 enum gcc_jit_global_kind kind,
463 type *type,
464 const char *name)
466 gcc_assert (type);
467 gcc_assert (name);
468 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
469 get_identifier (name),
470 type->as_tree ());
471 TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
472 DECL_COMMON (inner) = 1;
473 switch (kind)
475 default:
476 gcc_unreachable ();
478 case GCC_JIT_GLOBAL_EXPORTED:
479 TREE_STATIC (inner) = 1;
480 break;
482 case GCC_JIT_GLOBAL_INTERNAL:
483 TREE_STATIC (inner) = 1;
484 break;
486 case GCC_JIT_GLOBAL_IMPORTED:
487 DECL_EXTERNAL (inner) = 1;
488 break;
491 if (loc)
492 set_tree_location (inner, loc);
494 varpool_node::get_create (inner);
496 varpool_node::finalize_decl (inner);
498 m_globals.safe_push (inner);
500 return new lvalue (this, inner);
503 /* Implementation of the various
504 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
505 methods.
506 Each of these constructs a playback::rvalue instance (wrapping a tree).
508 These specializations are required to be in the same namespace
509 as the template, hence we now have to enter the gcc::jit::playback
510 namespace. */
512 namespace playback
515 /* Specialization of making an rvalue from a const, for host <int>. */
517 template <>
518 rvalue *
519 context::
520 new_rvalue_from_const <int> (type *type,
521 int value)
523 // FIXME: type-checking, or coercion?
524 tree inner_type = type->as_tree ();
525 if (INTEGRAL_TYPE_P (inner_type))
527 tree inner = build_int_cst (inner_type, value);
528 return new rvalue (this, inner);
530 else
532 REAL_VALUE_TYPE real_value;
533 real_from_integer (&real_value, VOIDmode, value, SIGNED);
534 tree inner = build_real (inner_type, real_value);
535 return new rvalue (this, inner);
539 /* Specialization of making an rvalue from a const, for host <long>. */
541 template <>
542 rvalue *
543 context::
544 new_rvalue_from_const <long> (type *type,
545 long value)
547 // FIXME: type-checking, or coercion?
548 tree inner_type = type->as_tree ();
549 if (INTEGRAL_TYPE_P (inner_type))
551 tree inner = build_int_cst (inner_type, value);
552 return new rvalue (this, inner);
554 else
556 REAL_VALUE_TYPE real_value;
557 real_from_integer (&real_value, VOIDmode, value, SIGNED);
558 tree inner = build_real (inner_type, real_value);
559 return new rvalue (this, inner);
563 /* Specialization of making an rvalue from a const, for host <double>. */
565 template <>
566 rvalue *
567 context::
568 new_rvalue_from_const <double> (type *type,
569 double value)
571 // FIXME: type-checking, or coercion?
572 tree inner_type = type->as_tree ();
574 /* We have a "double", we want a REAL_VALUE_TYPE.
576 real.c:real_from_target appears to require the representation to be
577 split into 32-bit values, and then sent as an pair of host long
578 ints. */
579 REAL_VALUE_TYPE real_value;
580 union
582 double as_double;
583 uint32_t as_uint32s[2];
584 } u;
585 u.as_double = value;
586 long int as_long_ints[2];
587 as_long_ints[0] = u.as_uint32s[0];
588 as_long_ints[1] = u.as_uint32s[1];
589 real_from_target (&real_value, as_long_ints, DFmode);
590 tree inner = build_real (inner_type, real_value);
591 return new rvalue (this, inner);
594 /* Specialization of making an rvalue from a const, for host <void *>. */
596 template <>
597 rvalue *
598 context::
599 new_rvalue_from_const <void *> (type *type,
600 void *value)
602 tree inner_type = type->as_tree ();
603 /* FIXME: how to ensure we have a wide enough type? */
604 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
605 return new rvalue (this, inner);
608 /* We're done implementing the specializations of
609 gcc::jit::playback::context::new_rvalue_from_const <T>
610 so we can exit the gcc::jit::playback namespace. */
612 } // namespace playback
614 /* Construct a playback::rvalue instance (wrapping a tree). */
616 playback::rvalue *
617 playback::context::
618 new_string_literal (const char *value)
620 tree t_str = build_string (strlen (value), value);
621 gcc_assert (m_char_array_type_node);
622 TREE_TYPE (t_str) = m_char_array_type_node;
624 /* Convert to (const char*), loosely based on
625 c/c-typeck.c: array_to_pointer_conversion,
626 by taking address of start of string. */
627 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
629 return new rvalue (this, t_addr);
632 /* Construct a playback::rvalue instance (wrapping a tree) for a
633 vector. */
635 playback::rvalue *
636 playback::context::new_rvalue_from_vector (location *,
637 type *type,
638 const auto_vec<rvalue *> &elements)
640 vec<constructor_elt, va_gc> *v;
641 vec_alloc (v, elements.length ());
642 for (unsigned i = 0; i < elements.length (); ++i)
643 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
644 tree t_ctor = build_constructor (type->as_tree (), v);
645 return new rvalue (this, t_ctor);
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,
874 bool require_tail_call)
876 vec<tree, va_gc> *tree_args;
877 vec_alloc (tree_args, args->length ());
878 for (unsigned i = 0; i < args->length (); i++)
879 tree_args->quick_push ((*args)[i]->as_tree ());
881 if (loc)
882 set_tree_location (fn_ptr, loc);
884 tree fn = TREE_TYPE (fn_ptr);
885 tree fn_type = TREE_TYPE (fn);
886 tree return_type = TREE_TYPE (fn_type);
888 tree call = build_call_vec (return_type,
889 fn_ptr, tree_args);
891 if (require_tail_call)
892 CALL_EXPR_MUST_TAIL_CALL (call) = 1;
894 return new rvalue (this, call);
896 /* see c-typeck.c: build_function_call
897 which calls build_function_call_vec
899 which does lots of checking, then:
900 result = build_call_array_loc (loc, TREE_TYPE (fntype),
901 function, nargs, argarray);
902 which is in tree.c
903 (see also build_call_vec)
907 /* Construct a playback::rvalue instance (wrapping a tree) for a
908 call to a specific function. */
910 playback::rvalue *
911 playback::context::
912 new_call (location *loc,
913 function *func,
914 const auto_vec<rvalue *> *args,
915 bool require_tail_call)
917 tree fndecl;
919 gcc_assert (func);
921 fndecl = func->as_fndecl ();
923 tree fntype = TREE_TYPE (fndecl);
925 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
927 return build_call (loc, fn, args, require_tail_call);
930 /* Construct a playback::rvalue instance (wrapping a tree) for a
931 call through a function pointer. */
933 playback::rvalue *
934 playback::context::
935 new_call_through_ptr (location *loc,
936 rvalue *fn_ptr,
937 const auto_vec<rvalue *> *args,
938 bool require_tail_call)
940 gcc_assert (fn_ptr);
941 tree t_fn_ptr = fn_ptr->as_tree ();
943 return build_call (loc, t_fn_ptr, args, require_tail_call);
946 /* Construct a tree for a cast. */
948 tree
949 playback::context::build_cast (playback::location *loc,
950 playback::rvalue *expr,
951 playback::type *type_)
953 /* For comparison, see:
954 - c/c-typeck.c:build_c_cast
955 - c/c-convert.c: convert
956 - convert.h
958 Only some kinds of cast are currently supported here. */
959 tree t_expr = expr->as_tree ();
960 tree t_dst_type = type_->as_tree ();
961 tree t_ret = NULL;
962 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
963 if (t_ret)
964 return t_ret;
965 enum tree_code dst_code = TREE_CODE (t_dst_type);
966 switch (dst_code)
968 case INTEGER_TYPE:
969 case ENUMERAL_TYPE:
970 t_ret = convert_to_integer (t_dst_type, t_expr);
971 goto maybe_fold;
973 case BOOLEAN_TYPE:
974 /* Compare with c_objc_common_truthvalue_conversion and
975 c_common_truthvalue_conversion. */
976 /* For now, convert to: (t_expr != 0) */
977 t_ret = build2 (NE_EXPR, t_dst_type,
978 t_expr,
979 build_int_cst (TREE_TYPE (t_expr), 0));
980 goto maybe_fold;
982 case REAL_TYPE:
983 t_ret = convert_to_real (t_dst_type, t_expr);
984 goto maybe_fold;
986 case POINTER_TYPE:
987 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
988 goto maybe_fold;
990 default:
991 add_error (loc, "couldn't handle cast during playback");
992 fprintf (stderr, "input expression:\n");
993 debug_tree (t_expr);
994 fprintf (stderr, "requested type:\n");
995 debug_tree (t_dst_type);
996 return error_mark_node;
998 maybe_fold:
999 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
1000 t_ret = fold (t_ret);
1001 return t_ret;
1005 /* Construct a playback::rvalue instance (wrapping a tree) for a
1006 cast. */
1008 playback::rvalue *
1009 playback::context::
1010 new_cast (playback::location *loc,
1011 playback::rvalue *expr,
1012 playback::type *type_)
1015 tree t_cast = build_cast (loc, expr, type_);
1016 if (loc)
1017 set_tree_location (t_cast, loc);
1018 return new rvalue (this, t_cast);
1021 /* Construct a playback::lvalue instance (wrapping a tree) for an
1022 array access. */
1024 playback::lvalue *
1025 playback::context::
1026 new_array_access (location *loc,
1027 rvalue *ptr,
1028 rvalue *index)
1030 gcc_assert (ptr);
1031 gcc_assert (index);
1033 /* For comparison, see:
1034 c/c-typeck.c: build_array_ref
1035 c-family/c-common.c: pointer_int_sum
1037 tree t_ptr = ptr->as_tree ();
1038 tree t_index = index->as_tree ();
1039 tree t_type_ptr = TREE_TYPE (t_ptr);
1040 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1042 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1044 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1045 NULL_TREE, NULL_TREE);
1046 if (loc)
1047 set_tree_location (t_result, loc);
1048 return new lvalue (this, t_result);
1050 else
1052 /* Convert index to an offset in bytes. */
1053 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1054 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1055 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
1057 /* Locate (ptr + offset). */
1058 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1060 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1061 if (loc)
1063 set_tree_location (t_sizeof, loc);
1064 set_tree_location (t_offset, loc);
1065 set_tree_location (t_address, loc);
1066 set_tree_location (t_indirection, loc);
1069 return new lvalue (this, t_indirection);
1073 /* Construct a tree for a field access. */
1075 tree
1076 playback::context::
1077 new_field_access (location *loc,
1078 tree datum,
1079 field *field)
1081 gcc_assert (datum);
1082 gcc_assert (field);
1084 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1085 build_component_ref. */
1086 tree type = TREE_TYPE (datum);
1087 gcc_assert (type);
1088 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1090 tree t_field = field->as_tree ();
1091 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1092 t_field, NULL_TREE);
1093 if (loc)
1094 set_tree_location (ref, loc);
1095 return ref;
1098 /* Construct a tree for a dereference. */
1100 tree
1101 playback::context::
1102 new_dereference (tree ptr,
1103 location *loc)
1105 gcc_assert (ptr);
1107 tree type = TREE_TYPE (TREE_TYPE(ptr));
1108 tree datum = build1 (INDIRECT_REF, type, ptr);
1109 if (loc)
1110 set_tree_location (datum, loc);
1111 return datum;
1114 /* Construct a playback::type instance (wrapping a tree)
1115 with the given alignment. */
1117 playback::type *
1118 playback::type::
1119 get_aligned (size_t alignment_in_bytes) const
1121 tree t_new_type = build_variant_type_copy (m_inner);
1123 SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT);
1124 TYPE_USER_ALIGN (t_new_type) = 1;
1126 return new type (t_new_type);
1129 /* Construct a playback::type instance (wrapping a tree)
1130 for the given vector type. */
1132 playback::type *
1133 playback::type::
1134 get_vector (size_t num_units) const
1136 tree t_new_type = build_vector_type (m_inner, num_units);
1137 return new type (t_new_type);
1140 /* Construct a playback::lvalue instance (wrapping a tree) for a
1141 field access. */
1143 playback::lvalue *
1144 playback::lvalue::
1145 access_field (location *loc,
1146 field *field)
1148 tree datum = as_tree ();
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::rvalue instance (wrapping a tree) for a
1156 field access. */
1158 playback::rvalue *
1159 playback::rvalue::
1160 access_field (location *loc,
1161 field *field)
1163 tree datum = as_tree ();
1164 tree ref = get_context ()->new_field_access (loc, datum, field);
1165 if (!ref)
1166 return NULL;
1167 return new rvalue (get_context (), ref);
1170 /* Construct a playback::lvalue instance (wrapping a tree) for a
1171 dereferenced field access. */
1173 playback::lvalue *
1174 playback::rvalue::
1175 dereference_field (location *loc,
1176 field *field)
1178 tree ptr = as_tree ();
1179 tree datum = get_context ()->new_dereference (ptr, loc);
1180 if (!datum)
1181 return NULL;
1182 tree ref = get_context ()->new_field_access (loc, datum, field);
1183 if (!ref)
1184 return NULL;
1185 return new lvalue (get_context (), ref);
1188 /* Construct a playback::lvalue instance (wrapping a tree) for a
1189 dereference. */
1191 playback::lvalue *
1192 playback::rvalue::
1193 dereference (location *loc)
1195 tree ptr = as_tree ();
1196 tree datum = get_context ()->new_dereference (ptr, loc);
1197 return new lvalue (get_context (), datum);
1200 /* Mark EXP saying that we need to be able to take the
1201 address of it; it should not be allocated in a register.
1202 Compare with e.g. c/c-typeck.c: c_mark_addressable. */
1204 static void
1205 jit_mark_addressable (tree exp)
1207 tree x = exp;
1209 while (1)
1210 switch (TREE_CODE (x))
1212 case COMPONENT_REF:
1213 /* (we don't yet support bitfields) */
1214 /* fallthrough */
1215 case ADDR_EXPR:
1216 case ARRAY_REF:
1217 case REALPART_EXPR:
1218 case IMAGPART_EXPR:
1219 x = TREE_OPERAND (x, 0);
1220 break;
1222 case COMPOUND_LITERAL_EXPR:
1223 case CONSTRUCTOR:
1224 TREE_ADDRESSABLE (x) = 1;
1225 return;
1227 case VAR_DECL:
1228 case CONST_DECL:
1229 case PARM_DECL:
1230 case RESULT_DECL:
1231 /* (we don't have a concept of a "register" declaration) */
1232 /* fallthrough */
1233 case FUNCTION_DECL:
1234 TREE_ADDRESSABLE (x) = 1;
1235 /* fallthrough */
1236 default:
1237 return;
1241 /* Construct a playback::rvalue instance (wrapping a tree) for an
1242 address-lookup. */
1244 playback::rvalue *
1245 playback::lvalue::
1246 get_address (location *loc)
1248 tree t_lvalue = as_tree ();
1249 tree t_thistype = TREE_TYPE (t_lvalue);
1250 tree t_ptrtype = build_pointer_type (t_thistype);
1251 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1252 if (loc)
1253 get_context ()->set_tree_location (ptr, loc);
1254 jit_mark_addressable (t_lvalue);
1255 return new rvalue (get_context (), ptr);
1258 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1259 Provide this finalization hook for calling then they are collected,
1260 which calls the finalizer vfunc. This allows them to call "release"
1261 on any vec<> within them. */
1263 static void
1264 wrapper_finalizer (void *ptr)
1266 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1267 wrapper->finalizer ();
1270 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1271 allocate them using ggc_internal_cleared_alloc. */
1273 void *
1274 playback::wrapper::
1275 operator new (size_t sz)
1277 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1281 /* Constructor for gcc:jit::playback::function. */
1283 playback::function::
1284 function (context *ctxt,
1285 tree fndecl,
1286 enum gcc_jit_function_kind kind)
1287 : m_ctxt(ctxt),
1288 m_inner_fndecl (fndecl),
1289 m_inner_bind_expr (NULL),
1290 m_kind (kind)
1292 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1294 /* Create a BIND_EXPR, and within it, a statement list. */
1295 m_stmt_list = alloc_stmt_list ();
1296 m_stmt_iter = tsi_start (m_stmt_list);
1297 m_inner_block = make_node (BLOCK);
1298 m_inner_bind_expr =
1299 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1301 else
1303 m_inner_block = NULL;
1304 m_stmt_list = NULL;
1308 /* Hand-written GC-marking hook for playback functions. */
1310 void
1311 playback::function::
1312 gt_ggc_mx ()
1314 gt_ggc_m_9tree_node (m_inner_fndecl);
1315 gt_ggc_m_9tree_node (m_inner_bind_expr);
1316 gt_ggc_m_9tree_node (m_stmt_list);
1317 gt_ggc_m_9tree_node (m_inner_block);
1320 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1321 GC-ed. */
1323 void
1324 playback::function::finalizer ()
1326 m_blocks.release ();
1329 /* Get the return type of a playback function, in tree form. */
1331 tree
1332 playback::function::
1333 get_return_type_as_tree () const
1335 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1338 /* Construct a new local within this playback::function. */
1340 playback::lvalue *
1341 playback::function::
1342 new_local (location *loc,
1343 type *type,
1344 const char *name)
1346 gcc_assert (type);
1347 gcc_assert (name);
1348 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1349 get_identifier (name),
1350 type->as_tree ());
1351 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1353 /* Prepend to BIND_EXPR_VARS: */
1354 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1355 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1357 if (loc)
1358 set_tree_location (inner, loc);
1359 return new lvalue (m_ctxt, inner);
1362 /* Construct a new block within this playback::function. */
1364 playback::block *
1365 playback::function::
1366 new_block (const char *name)
1368 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1370 block *result = new playback::block (this, name);
1371 m_blocks.safe_push (result);
1372 return result;
1375 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1376 this playback::function. */
1378 playback::rvalue *
1379 playback::function::get_address (location *loc)
1381 tree t_fndecl = as_fndecl ();
1382 tree t_fntype = TREE_TYPE (t_fndecl);
1383 tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
1384 if (loc)
1385 m_ctxt->set_tree_location (t_fnptr, loc);
1386 return new rvalue (m_ctxt, t_fnptr);
1389 /* Build a statement list for the function as a whole out of the
1390 lists of statements for the individual blocks, building labels
1391 for each block. */
1393 void
1394 playback::function::
1395 build_stmt_list ()
1397 int i;
1398 block *b;
1400 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1402 FOR_EACH_VEC_ELT (m_blocks, i, b)
1404 int j;
1405 tree stmt;
1407 b->m_label_expr = build1 (LABEL_EXPR,
1408 void_type_node,
1409 b->as_label_decl ());
1410 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1412 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1413 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1417 /* Finish compiling the given function, potentially running the
1418 garbage-collector.
1419 The function will have a statement list by now.
1420 Amongst other things, this gimplifies the statement list,
1421 and calls cgraph_node::finalize_function on the function. */
1423 void
1424 playback::function::
1425 postprocess ()
1427 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1429 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1430 debug_tree (m_stmt_list);
1432 /* Do we need this to force cgraphunit.c to output the function? */
1433 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1435 DECL_EXTERNAL (m_inner_fndecl) = 0;
1436 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1439 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1440 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1442 DECL_EXTERNAL (m_inner_fndecl) = 0;
1443 TREE_PUBLIC (m_inner_fndecl) = 0;
1446 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1448 /* Seem to need this in gimple-low.c: */
1449 gcc_assert (m_inner_block);
1450 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1452 /* how to add to function? the following appears to be how to
1453 set the body of a m_inner_fndecl: */
1454 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1456 /* Ensure that locals appear in the debuginfo. */
1457 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1459 //debug_tree (m_inner_fndecl);
1461 /* Convert to gimple: */
1462 //printf("about to gimplify_function_tree\n");
1463 gimplify_function_tree (m_inner_fndecl);
1464 //printf("finished gimplify_function_tree\n");
1466 current_function_decl = m_inner_fndecl;
1467 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1468 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1469 //debug_tree (m_inner_fndecl);
1471 //printf("about to add to cgraph\n");
1472 /* Add to cgraph: */
1473 cgraph_node::finalize_function (m_inner_fndecl, false);
1474 /* This can trigger a collection, so we need to have all of
1475 the funcs as roots. */
1477 current_function_decl = NULL;
1481 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1482 GC-ed. */
1484 void
1485 playback::block::finalizer ()
1487 m_stmts.release ();
1490 /* Add an eval of the rvalue to the function's statement list. */
1492 void
1493 playback::block::
1494 add_eval (location *loc,
1495 rvalue *rvalue)
1497 gcc_assert (rvalue);
1499 if (loc)
1500 set_tree_location (rvalue->as_tree (), loc);
1502 add_stmt (rvalue->as_tree ());
1505 /* Add an assignment to the function's statement list. */
1507 void
1508 playback::block::
1509 add_assignment (location *loc,
1510 lvalue *lvalue,
1511 rvalue *rvalue)
1513 gcc_assert (lvalue);
1514 gcc_assert (rvalue);
1516 tree t_lvalue = lvalue->as_tree ();
1517 tree t_rvalue = rvalue->as_tree ();
1518 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1520 t_rvalue = build1 (CONVERT_EXPR,
1521 TREE_TYPE (t_lvalue),
1522 t_rvalue);
1523 if (loc)
1524 set_tree_location (t_rvalue, loc);
1527 tree stmt =
1528 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1529 t_lvalue, t_rvalue);
1530 if (loc)
1531 set_tree_location (stmt, loc);
1532 add_stmt (stmt);
1535 /* Add a comment to the function's statement list.
1536 For now this is done by adding a dummy label. */
1538 void
1539 playback::block::
1540 add_comment (location *loc,
1541 const char *text)
1543 /* Wrap the text in C-style comment delimiters. */
1544 size_t sz =
1545 (3 /* opening delim */
1546 + strlen (text)
1547 + 3 /* closing delim */
1548 + 1 /* terminator */);
1549 char *wrapped = (char *)ggc_internal_alloc (sz);
1550 snprintf (wrapped, sz, "/* %s */", text);
1552 /* For now we simply implement this by adding a dummy label with a name
1553 containing the given text. */
1554 tree identifier = get_identifier (wrapped);
1555 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1556 identifier, void_type_node);
1557 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1559 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1560 if (loc)
1561 set_tree_location (label_expr, loc);
1562 add_stmt (label_expr);
1565 /* Add a conditional jump statement to the function's statement list. */
1567 void
1568 playback::block::
1569 add_conditional (location *loc,
1570 rvalue *boolval,
1571 block *on_true,
1572 block *on_false)
1574 gcc_assert (boolval);
1575 gcc_assert (on_true);
1576 gcc_assert (on_false);
1578 /* COND_EXPR wants statement lists for the true/false operands, but we
1579 want labels.
1580 Shim it by creating jumps to the labels */
1581 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1582 on_true->as_label_decl ());
1583 if (loc)
1584 set_tree_location (true_jump, loc);
1586 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1587 on_false->as_label_decl ());
1588 if (loc)
1589 set_tree_location (false_jump, loc);
1591 tree stmt =
1592 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1593 true_jump, false_jump);
1594 if (loc)
1595 set_tree_location (stmt, loc);
1596 add_stmt (stmt);
1599 /* Add an unconditional jump statement to the function's statement list. */
1601 void
1602 playback::block::
1603 add_jump (location *loc,
1604 block *target)
1606 gcc_assert (target);
1608 // see c_finish_loop
1609 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1610 //add_stmt (top);
1612 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1613 TREE_USED (target->as_label_decl ()) = 1;
1614 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1615 if (loc)
1616 set_tree_location (stmt, loc);
1617 add_stmt (stmt);
1620 from c-typeck.c:
1621 tree
1622 c_finish_goto_label (location_t loc, tree label)
1624 tree decl = lookup_label_for_goto (loc, label);
1625 if (!decl)
1626 return NULL_TREE;
1627 TREE_USED (decl) = 1;
1629 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1630 SET_EXPR_LOCATION (t, loc);
1631 return add_stmt (t);
1638 /* Add a return statement to the function's statement list. */
1640 void
1641 playback::block::
1642 add_return (location *loc,
1643 rvalue *rvalue)
1645 tree modify_retval = NULL;
1646 tree return_type = m_func->get_return_type_as_tree ();
1647 if (rvalue)
1649 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1650 tree t_rvalue = rvalue->as_tree ();
1651 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1652 t_rvalue = build1 (CONVERT_EXPR,
1653 TREE_TYPE (t_lvalue),
1654 t_rvalue);
1655 modify_retval = build2 (MODIFY_EXPR, return_type,
1656 t_lvalue, t_rvalue);
1657 if (loc)
1658 set_tree_location (modify_retval, loc);
1660 tree return_stmt = build1 (RETURN_EXPR, return_type,
1661 modify_retval);
1662 if (loc)
1663 set_tree_location (return_stmt, loc);
1665 add_stmt (return_stmt);
1668 /* Helper function for playback::block::add_switch.
1669 Construct a case label for the given range, followed by a goto stmt
1670 to the given block, appending them to stmt list *ptr_t_switch_body. */
1672 static void
1673 add_case (tree *ptr_t_switch_body,
1674 tree t_low_value,
1675 tree t_high_value,
1676 playback::block *dest_block)
1678 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
1679 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
1681 tree t_case_label =
1682 build_case_label (t_low_value, t_high_value, t_label);
1683 append_to_statement_list (t_case_label, ptr_t_switch_body);
1685 tree t_goto_stmt =
1686 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
1687 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
1690 /* Add a switch statement to the function's statement list.
1692 We create a switch body, and populate it with case labels, each
1693 followed by a goto to the desired block. */
1695 void
1696 playback::block::
1697 add_switch (location *loc,
1698 rvalue *expr,
1699 block *default_block,
1700 const auto_vec <case_> *cases)
1702 /* Compare with:
1703 - c/c-typeck.c: c_start_case
1704 - c-family/c-common.c:c_add_case_label
1705 - java/expr.c:expand_java_switch and expand_java_add_case
1706 We've already rejected overlaps and duplicates in
1707 libgccjit.c:case_range_validator::validate. */
1709 tree t_expr = expr->as_tree ();
1710 tree t_type = TREE_TYPE (t_expr);
1712 tree t_switch_body = alloc_stmt_list ();
1714 int i;
1715 case_ *c;
1716 FOR_EACH_VEC_ELT (*cases, i, c)
1718 tree t_low_value = c->m_min_value->as_tree ();
1719 tree t_high_value = c->m_max_value->as_tree ();
1720 add_case (&t_switch_body, t_low_value, t_high_value, c->m_dest_block);
1722 /* Default label. */
1723 add_case (&t_switch_body, NULL_TREE, NULL_TREE, default_block);
1725 tree switch_stmt = build2 (SWITCH_EXPR, t_type, t_expr, t_switch_body);
1726 if (loc)
1727 set_tree_location (switch_stmt, loc);
1728 add_stmt (switch_stmt);
1731 /* Constructor for gcc::jit::playback::block. */
1733 playback::block::
1734 block (function *func,
1735 const char *name)
1736 : m_func (func),
1737 m_stmts ()
1739 tree identifier;
1741 gcc_assert (func);
1742 // name can be NULL
1743 if (name)
1744 identifier = get_identifier (name);
1745 else
1746 identifier = NULL;
1747 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1748 identifier, void_type_node);
1749 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1750 m_label_expr = NULL;
1753 /* Compile a playback::context:
1755 - Use the context's options to cconstruct command-line options, and
1756 call into the rest of GCC (toplev::main).
1757 - Assuming it succeeds, we have a .s file.
1758 - We then run the "postprocess" vfunc:
1760 (A) In-memory compile ("gcc_jit_context_compile")
1762 For an in-memory compile we have the playback::compile_to_memory
1763 subclass; "postprocess" will convert the .s file to a .so DSO,
1764 and load it in memory (via dlopen), wrapping the result up as
1765 a jit::result and returning it.
1767 (B) Compile to file ("gcc_jit_context_compile_to_file")
1769 When compiling to a file, we have the playback::compile_to_file
1770 subclass; "postprocess" will either copy the .s file to the
1771 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1772 the driver to convert it as necessary, copying the result. */
1774 void
1775 playback::context::
1776 compile ()
1778 JIT_LOG_SCOPE (get_logger ());
1780 const char *ctxt_progname;
1782 int keep_intermediates =
1783 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
1785 m_tempdir = new tempdir (get_logger (), keep_intermediates);
1786 if (!m_tempdir->create ())
1787 return;
1789 /* Call into the rest of gcc.
1790 For now, we have to assemble command-line options to pass into
1791 toplev::main, so that they can be parsed. */
1793 /* Pass in user-provided program name as argv0, if any, so that it
1794 makes it into GCC's "progname" global, used in various diagnostics. */
1795 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1797 if (!ctxt_progname)
1798 ctxt_progname = "libgccjit.so";
1800 auto_vec <recording::requested_dump> requested_dumps;
1801 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1803 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1804 acquire_mutex ();
1806 auto_string_vec fake_args;
1807 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
1808 if (errors_occurred ())
1810 release_mutex ();
1811 return;
1814 /* This runs the compiler. */
1815 toplev toplev (get_timer (), /* external_timer */
1816 false); /* init_signals */
1817 enter_scope ("toplev::main");
1818 if (get_logger ())
1819 for (unsigned i = 0; i < fake_args.length (); i++)
1820 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
1821 toplev.main (fake_args.length (),
1822 const_cast <char **> (fake_args.address ()));
1823 exit_scope ("toplev::main");
1825 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1826 need to do it between toplev::main (which creates the dump manager)
1827 and toplev::finalize (which deletes it). */
1828 extract_any_requested_dumps (&requested_dumps);
1830 /* Clean up the compiler. */
1831 enter_scope ("toplev::finalize");
1832 toplev.finalize ();
1833 exit_scope ("toplev::finalize");
1835 /* Ideally we would release the jit mutex here, but we can't yet since
1836 followup activities use timevars, which are global state. */
1838 if (errors_occurred ())
1840 release_mutex ();
1841 return;
1844 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1845 dump_generated_code ();
1847 /* We now have a .s file.
1849 Run any postprocessing steps. This will either convert the .s file to
1850 a .so DSO, and load it in memory (playback::compile_to_memory), or
1851 convert the .s file to the requested output format, and copy it to a
1852 given file (playback::compile_to_file). */
1853 postprocess (ctxt_progname);
1855 release_mutex ();
1858 /* Implementation of class gcc::jit::playback::compile_to_memory,
1859 a subclass of gcc::jit::playback::context. */
1861 /* playback::compile_to_memory's trivial constructor. */
1863 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
1864 playback::context (ctxt),
1865 m_result (NULL)
1867 JIT_LOG_SCOPE (get_logger ());
1870 /* Implementation of the playback::context::process vfunc for compiling
1871 to memory.
1873 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1874 wrapping the result up as a jit::result and returning it. */
1876 void
1877 playback::compile_to_memory::postprocess (const char *ctxt_progname)
1879 JIT_LOG_SCOPE (get_logger ());
1880 convert_to_dso (ctxt_progname);
1881 if (errors_occurred ())
1882 return;
1883 m_result = dlopen_built_dso ();
1886 /* Implementation of class gcc::jit::playback::compile_to_file,
1887 a subclass of gcc::jit::playback::context. */
1889 /* playback::compile_to_file's trivial constructor. */
1891 playback::compile_to_file::compile_to_file (recording::context *ctxt,
1892 enum gcc_jit_output_kind output_kind,
1893 const char *output_path) :
1894 playback::context (ctxt),
1895 m_output_kind (output_kind),
1896 m_output_path (output_path)
1898 JIT_LOG_SCOPE (get_logger ());
1901 /* Implementation of the playback::context::process vfunc for compiling
1902 to a file.
1904 Either copy the .s file to the given destination (for
1905 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1906 as necessary, copying the result. */
1908 void
1909 playback::compile_to_file::postprocess (const char *ctxt_progname)
1911 JIT_LOG_SCOPE (get_logger ());
1913 /* The driver takes different actions based on the filename, so
1914 we provide a filename with an appropriate suffix for the
1915 output kind, and then copy it up to the user-provided path,
1916 rather than directly compiling it to the requested output path. */
1918 switch (m_output_kind)
1920 default:
1921 gcc_unreachable ();
1923 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
1924 copy_file (get_tempdir ()->get_path_s_file (),
1925 m_output_path);
1926 /* The .s file is automatically unlinked by tempdir::~tempdir. */
1927 break;
1929 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
1931 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
1932 "/fake.o",
1933 NULL);
1934 invoke_driver (ctxt_progname,
1935 get_tempdir ()->get_path_s_file (),
1936 tmp_o_path,
1937 TV_ASSEMBLE,
1938 false, /* bool shared, */
1939 false);/* bool run_linker */
1940 if (!errors_occurred ())
1942 copy_file (tmp_o_path,
1943 m_output_path);
1944 get_tempdir ()->add_temp_file (tmp_o_path);
1946 else
1947 free (tmp_o_path);
1949 break;
1951 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
1952 invoke_driver (ctxt_progname,
1953 get_tempdir ()->get_path_s_file (),
1954 get_tempdir ()->get_path_so_file (),
1955 TV_ASSEMBLE,
1956 true, /* bool shared, */
1957 true);/* bool run_linker */
1958 if (!errors_occurred ())
1959 copy_file (get_tempdir ()->get_path_so_file (),
1960 m_output_path);
1961 /* The .so file is automatically unlinked by tempdir::~tempdir. */
1962 break;
1964 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
1966 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
1967 "/fake.exe",
1968 NULL);
1969 invoke_driver (ctxt_progname,
1970 get_tempdir ()->get_path_s_file (),
1971 tmp_exe_path,
1972 TV_ASSEMBLE,
1973 false, /* bool shared, */
1974 true);/* bool run_linker */
1975 if (!errors_occurred ())
1977 copy_file (tmp_exe_path,
1978 m_output_path);
1979 get_tempdir ()->add_temp_file (tmp_exe_path);
1981 else
1982 free (tmp_exe_path);
1984 break;
1990 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
1991 the "executable" bits).
1993 Any errors that occur are reported on the context and hence count as
1994 a failure of the compile.
1996 We can't in general hardlink or use "rename" from the tempdir since
1997 it might be on a different filesystem to the destination. For example,
1998 I get EXDEV: "Invalid cross-device link". */
2000 void
2001 playback::compile_to_file::copy_file (const char *src_path,
2002 const char *dst_path)
2004 JIT_LOG_SCOPE (get_logger ());
2005 if (get_logger ())
2007 get_logger ()->log ("src_path: %s", src_path);
2008 get_logger ()->log ("dst_path: %s", dst_path);
2011 FILE *f_in = NULL;
2012 FILE *f_out = NULL;
2013 size_t total_sz_in = 0;
2014 size_t total_sz_out = 0;
2015 char buf[4096];
2016 size_t sz_in;
2017 struct stat stat_buf;
2019 f_in = fopen (src_path, "rb");
2020 if (!f_in)
2022 add_error (NULL,
2023 "unable to open %s for reading: %s",
2024 src_path,
2025 xstrerror (errno));
2026 return;
2029 /* Use stat on the filedescriptor to get the mode,
2030 so that we can copy it over (in particular, the
2031 "executable" bits). */
2032 if (fstat (fileno (f_in), &stat_buf) == -1)
2034 add_error (NULL,
2035 "unable to fstat %s: %s",
2036 src_path,
2037 xstrerror (errno));
2038 fclose (f_in);
2039 return;
2042 f_out = fopen (dst_path, "wb");
2043 if (!f_out)
2045 add_error (NULL,
2046 "unable to open %s for writing: %s",
2047 dst_path,
2048 xstrerror (errno));
2049 fclose (f_in);
2050 return;
2053 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2055 total_sz_in += sz_in;
2056 size_t sz_out_remaining = sz_in;
2057 size_t sz_out_so_far = 0;
2058 while (sz_out_remaining)
2060 size_t sz_out = fwrite (buf + sz_out_so_far,
2062 sz_out_remaining,
2063 f_out);
2064 gcc_assert (sz_out <= sz_out_remaining);
2065 if (!sz_out)
2067 add_error (NULL,
2068 "error writing to %s: %s",
2069 dst_path,
2070 xstrerror (errno));
2071 fclose (f_in);
2072 fclose (f_out);
2073 return;
2075 total_sz_out += sz_out;
2076 sz_out_so_far += sz_out;
2077 sz_out_remaining -= sz_out;
2079 gcc_assert (sz_out_so_far == sz_in);
2082 if (!feof (f_in))
2083 add_error (NULL,
2084 "error reading from %s: %s",
2085 src_path,
2086 xstrerror (errno));
2088 fclose (f_in);
2090 gcc_assert (total_sz_in == total_sz_out);
2091 if (get_logger ())
2092 get_logger ()->log ("total bytes copied: %ld", total_sz_out);
2094 /* Set the permissions of the copy to those of the original file,
2095 in particular the "executable" bits. */
2096 if (fchmod (fileno (f_out), stat_buf.st_mode) == -1)
2097 add_error (NULL,
2098 "error setting mode of %s: %s",
2099 dst_path,
2100 xstrerror (errno));
2102 fclose (f_out);
2105 /* Helper functions for gcc::jit::playback::context::compile. */
2107 /* This mutex guards gcc::jit::recording::context::compile, so that only
2108 one thread can be accessing the bulk of GCC's state at once. */
2110 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2112 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2114 void
2115 playback::context::acquire_mutex ()
2117 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2119 /* Acquire the big GCC mutex. */
2120 JIT_LOG_SCOPE (get_logger ());
2121 pthread_mutex_lock (&jit_mutex);
2122 gcc_assert (active_playback_ctxt == NULL);
2123 active_playback_ctxt = this;
2126 /* Release jit_mutex and clear the active playback ctxt. */
2128 void
2129 playback::context::release_mutex ()
2131 /* Release the big GCC mutex. */
2132 JIT_LOG_SCOPE (get_logger ());
2133 gcc_assert (active_playback_ctxt == this);
2134 active_playback_ctxt = NULL;
2135 pthread_mutex_unlock (&jit_mutex);
2138 /* Callback used by gcc::jit::playback::context::make_fake_args when
2139 invoking driver_get_configure_time_options.
2140 Populate a vec <char * > with the configure-time options. */
2142 static void
2143 append_arg_from_driver (const char *option, void *user_data)
2145 gcc_assert (option);
2146 gcc_assert (user_data);
2147 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2148 argvec->safe_push (concat ("-", option, NULL));
2151 /* Build a fake argv for toplev::main from the options set
2152 by the user on the context . */
2154 void
2155 playback::context::
2156 make_fake_args (vec <char *> *argvec,
2157 const char *ctxt_progname,
2158 vec <recording::requested_dump> *requested_dumps)
2160 JIT_LOG_SCOPE (get_logger ());
2162 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2163 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2165 ADD_ARG (ctxt_progname);
2166 ADD_ARG (get_path_c_file ());
2167 ADD_ARG ("-fPIC");
2169 /* Handle int options: */
2170 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2172 default:
2173 add_error (NULL,
2174 "unrecognized optimization level: %i",
2175 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2176 return;
2178 case 0:
2179 ADD_ARG ("-O0");
2180 break;
2182 case 1:
2183 ADD_ARG ("-O1");
2184 break;
2186 case 2:
2187 ADD_ARG ("-O2");
2188 break;
2190 case 3:
2191 ADD_ARG ("-O3");
2192 break;
2194 /* What about -Os? */
2196 /* Handle bool options: */
2197 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2198 ADD_ARG ("-g");
2200 /* Suppress timing (and other) info. */
2201 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2203 ADD_ARG ("-quiet");
2204 quiet_flag = 1;
2207 /* Aggressively garbage-collect, to shake out bugs: */
2208 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2210 ADD_ARG ("--param");
2211 ADD_ARG ("ggc-min-expand=0");
2212 ADD_ARG ("--param");
2213 ADD_ARG ("ggc-min-heapsize=0");
2216 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2218 ADD_ARG ("-fdump-tree-all");
2219 ADD_ARG ("-fdump-rtl-all");
2220 ADD_ARG ("-fdump-ipa-all");
2223 /* Add "-fdump-" options for any calls to
2224 gcc_jit_context_enable_dump. */
2226 int i;
2227 recording::requested_dump *d;
2228 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2230 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2231 ADD_ARG_TAKE_OWNERSHIP (arg);
2235 /* PR jit/64810: Add any target-specific default options
2236 from OPTION_DEFAULT_SPECS, normally provided by the driver
2237 in the non-jit case.
2239 The target-specific code can define OPTION_DEFAULT_SPECS:
2240 default command options in the form of spec macros for the
2241 driver to expand ().
2243 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2244 if not overriden, injects the defaults as extra arguments to
2245 cc1 etc.
2246 For the jit case, we need to add these arguments here. The
2247 input format (using the specs language) means that we have to run
2248 part of the driver code here (driver_get_configure_time_options).
2250 To avoid running the spec-expansion code every time, we just do
2251 it the first time (via a function-static flag), saving the result
2252 into a function-static vec.
2253 This flag and vec are global state (i.e. per-process).
2254 They are guarded by the jit mutex. */
2256 static bool have_configure_time_options = false;
2257 static vec <char *> configure_time_options;
2259 if (have_configure_time_options)
2260 log ("reusing cached configure-time options");
2261 else
2263 have_configure_time_options = true;
2264 log ("getting configure-time options from driver");
2265 driver_get_configure_time_options (append_arg_from_driver,
2266 &configure_time_options);
2269 int i;
2270 char *opt;
2272 if (get_logger ())
2273 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2274 log ("configure_time_options[%i]: %s", i, opt);
2276 /* configure_time_options should now contain the expanded options
2277 from OPTION_DEFAULT_SPECS (if any). */
2278 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2280 gcc_assert (opt);
2281 gcc_assert (opt[0] == '-');
2282 ADD_ARG (opt);
2286 if (get_timer ())
2287 ADD_ARG ("-ftime-report");
2289 /* Add any user-provided extra options, starting with any from
2290 parent contexts. */
2291 m_recording_ctxt->append_command_line_options (argvec);
2293 #undef ADD_ARG
2294 #undef ADD_ARG_TAKE_OWNERSHIP
2297 /* The second half of the implementation of gcc_jit_context_enable_dump.
2298 Iterate through the requested dumps, reading the underlying files
2299 into heap-allocated buffers, writing pointers to the buffers into
2300 the char ** pointers provided by client code.
2301 Client code is responsible for calling free on the results. */
2303 void
2304 playback::context::
2305 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2307 JIT_LOG_SCOPE (get_logger ());
2309 int i;
2310 recording::requested_dump *d;
2311 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2313 dump_file_info *dfi;
2314 char *filename;
2315 char *content;
2317 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2318 if (!dfi)
2320 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2321 continue;
2324 filename = g->get_dumps ()->get_dump_file_name (dfi);
2325 content = read_dump_file (filename);
2326 *(d->m_out_ptr) = content;
2327 m_tempdir->add_temp_file (filename);
2331 /* Helper function for playback::context::extract_any_requested_dumps
2332 (itself for use in implementation of gcc_jit_context_enable_dump).
2334 Attempt to read the complete file at the given path, returning the
2335 bytes found there as a buffer.
2336 The caller is responsible for calling free on the result.
2337 Errors will be reported on the context, and lead to NULL being
2338 returned; an out-of-memory error will terminate the process. */
2340 char *
2341 playback::context::read_dump_file (const char *path)
2343 char *result = NULL;
2344 size_t total_sz = 0;
2345 char buf[4096];
2346 size_t sz;
2347 FILE *f_in;
2349 f_in = fopen (path, "r");
2350 if (!f_in)
2352 add_error (NULL, "unable to open %s for reading", path);
2353 return NULL;
2356 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2358 size_t old_total_sz = total_sz;
2359 total_sz += sz;
2360 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2361 memcpy (result + old_total_sz, buf, sz);
2364 if (!feof (f_in))
2366 add_error (NULL, "error reading from %s", path);
2367 free (result);
2368 fclose (f_in);
2369 return NULL;
2372 fclose (f_in);
2374 if (result)
2376 result[total_sz] = '\0';
2377 return result;
2379 else
2380 return xstrdup ("");
2383 /* Part of playback::context::compile ().
2385 We have a .s file; we want a .so file.
2386 We could reuse parts of gcc/gcc.c to do this.
2387 For now, just use the driver binary from the install, as
2388 named in gcc-driver-name.h
2389 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2391 void
2392 playback::context::
2393 convert_to_dso (const char *ctxt_progname)
2395 JIT_LOG_SCOPE (get_logger ());
2397 invoke_driver (ctxt_progname,
2398 m_tempdir->get_path_s_file (),
2399 m_tempdir->get_path_so_file (),
2400 TV_ASSEMBLE,
2401 true, /* bool shared, */
2402 true);/* bool run_linker */
2405 static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2407 void
2408 playback::context::
2409 invoke_driver (const char *ctxt_progname,
2410 const char *input_file,
2411 const char *output_file,
2412 timevar_id_t tv_id,
2413 bool shared,
2414 bool run_linker)
2416 JIT_LOG_SCOPE (get_logger ());
2418 bool embedded_driver
2419 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
2421 /* Currently this lumps together both assembling and linking into
2422 TV_ASSEMBLE. */
2423 auto_timevar assemble_timevar (get_timer (), tv_id);
2424 auto_string_vec argvec;
2425 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2427 ADD_ARG (gcc_driver_name);
2429 add_multilib_driver_arguments (&argvec);
2431 if (shared)
2432 ADD_ARG ("-shared");
2434 if (!run_linker)
2435 ADD_ARG ("-c");
2437 ADD_ARG (input_file);
2438 ADD_ARG ("-o");
2439 ADD_ARG (output_file);
2441 /* Don't use the linker plugin.
2442 If running with just a "make" and not a "make install", then we'd
2443 run into
2444 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2445 libto_plugin is a .la at build time, with it becoming installed with
2446 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2447 time. */
2448 ADD_ARG ("-fno-use-linker-plugin");
2450 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2451 /* OS X's linker defaults to treating undefined symbols as errors.
2452 If the context has any imported functions or globals they will be
2453 undefined until the .so is dynamically-linked into the process.
2454 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2455 linker. */
2456 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2457 #endif
2459 if (0)
2460 ADD_ARG ("-v");
2462 #undef ADD_ARG
2464 /* pex_one's error-handling requires pname to be non-NULL. */
2465 gcc_assert (ctxt_progname);
2467 if (get_logger ())
2468 for (unsigned i = 0; i < argvec.length (); i++)
2469 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2471 if (embedded_driver)
2472 invoke_embedded_driver (&argvec);
2473 else
2474 invoke_external_driver (ctxt_progname, &argvec);
2477 void
2478 playback::context::
2479 invoke_embedded_driver (const vec <char *> *argvec)
2481 JIT_LOG_SCOPE (get_logger ());
2482 driver d (true, /* can_finalize */
2483 false); /* debug */
2484 int result = d.main (argvec->length (),
2485 const_cast <char **> (argvec->address ()));
2486 d.finalize ();
2487 if (result)
2488 add_error (NULL, "error invoking gcc driver");
2491 void
2492 playback::context::
2493 invoke_external_driver (const char *ctxt_progname,
2494 vec <char *> *argvec)
2496 JIT_LOG_SCOPE (get_logger ());
2497 const char *errmsg;
2498 int exit_status = 0;
2499 int err = 0;
2501 /* pex argv arrays are NULL-terminated. */
2502 argvec->safe_push (NULL);
2504 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2505 gcc_driver_name,
2506 const_cast <char *const *> (argvec->address ()),
2507 ctxt_progname, /* const char *pname */
2508 NULL, /* const char *outname */
2509 NULL, /* const char *errname */
2510 &exit_status, /* int *status */
2511 &err); /* int *err*/
2512 if (errmsg)
2514 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2515 return;
2518 /* pex_one can return a NULL errmsg when the executable wasn't
2519 found (or doesn't exist), so trap these cases also. */
2520 if (exit_status || err)
2522 add_error (NULL,
2523 "error invoking gcc driver: exit_status: %i err: %i",
2524 exit_status, err);
2525 add_error (NULL,
2526 "whilst attempting to run a driver named: %s",
2527 gcc_driver_name);
2528 add_error (NULL,
2529 "PATH was: %s",
2530 getenv ("PATH"));
2531 return;
2535 /* Extract the target-specific MULTILIB_DEFAULTS to
2536 multilib_defaults_raw for use by
2537 playback::context::add_multilib_driver_arguments (). */
2539 #ifndef MULTILIB_DEFAULTS
2540 #define MULTILIB_DEFAULTS { "" }
2541 #endif
2543 static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
2545 /* Helper function for playback::context::invoke_driver ().
2547 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2548 a driver binary. We need to pass in options to the shared driver
2549 to get the appropriate assembler/linker options for this multilib
2550 peer. */
2552 void
2553 playback::context::
2554 add_multilib_driver_arguments (vec <char *> *argvec)
2556 JIT_LOG_SCOPE (get_logger ());
2558 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2559 prepending each with a "-". */
2560 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
2561 if (multilib_defaults_raw[i][0])
2562 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
2565 /* Dynamically-link the built DSO file into this process, using dlopen.
2566 Wrap it up within a jit::result *, and return that.
2567 Return NULL if any errors occur, reporting them on this context. */
2569 result *
2570 playback::context::
2571 dlopen_built_dso ()
2573 JIT_LOG_SCOPE (get_logger ());
2574 auto_timevar load_timevar (get_timer (), TV_LOAD);
2575 void *handle = NULL;
2576 const char *error = NULL;
2577 result *result_obj = NULL;
2579 /* Clear any existing error. */
2580 dlerror ();
2582 handle = dlopen (m_tempdir->get_path_so_file (),
2583 RTLD_NOW | RTLD_LOCAL);
2584 if ((error = dlerror()) != NULL) {
2585 add_error (NULL, "%s", error);
2587 if (handle)
2589 /* We've successfully dlopened the result; create a
2590 jit::result object to wrap it.
2592 We're done with the tempdir for now, but if the user
2593 has requested debugging, the user's debugger might not
2594 be capable of dealing with the .so file being unlinked
2595 immediately, so keep it around until after the result
2596 is released. We do this by handing over ownership of
2597 the jit::tempdir to the result. See PR jit/64206. */
2598 tempdir *handover_tempdir;
2599 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2601 handover_tempdir = m_tempdir;
2602 m_tempdir = NULL;
2603 /* The tempdir will eventually be cleaned up in the
2604 jit::result's dtor. */
2605 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2606 " handing over tempdir to jit::result");
2608 else
2610 handover_tempdir = NULL;
2611 /* ... and retain ownership of m_tempdir so we clean it
2612 up it the playback::context's dtor. */
2613 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2614 " retaining ownership of tempdir");
2617 result_obj = new result (get_logger (), handle, handover_tempdir);
2619 else
2620 result_obj = NULL;
2622 return result_obj;
2625 /* Top-level hook for playing back a recording context.
2627 This plays back m_recording_ctxt, and, if no errors
2628 occurred builds statement lists for and then postprocesses
2629 every function in the result. */
2631 void
2632 playback::context::
2633 replay ()
2635 JIT_LOG_SCOPE (get_logger ());
2636 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2637 tree array_domain_type = build_index_type (size_int (200));
2638 m_char_array_type_node
2639 = build_array_type (char_type_node, array_domain_type);
2641 m_const_char_ptr
2642 = build_pointer_type (build_qualified_type (char_type_node,
2643 TYPE_QUAL_CONST));
2645 /* Replay the recorded events: */
2646 timevar_push (TV_JIT_REPLAY);
2648 m_recording_ctxt->replay_into (this);
2650 /* Clean away the temporary references from recording objects
2651 to playback objects. We have to do this now since the
2652 latter are GC-allocated, but the former don't mark these
2653 refs. Hence we must stop using them before the GC can run. */
2654 m_recording_ctxt->disassociate_from_playback ();
2656 /* The builtins_manager, if any, is associated with the recording::context
2657 and might be reused for future compiles on other playback::contexts,
2658 but its m_attributes array is not GTY-labeled and hence will become
2659 nonsense if the GC runs. Purge this state. */
2660 builtins_manager *bm = get_builtins_manager ();
2661 if (bm)
2662 bm->finish_playback ();
2664 timevar_pop (TV_JIT_REPLAY);
2666 if (!errors_occurred ())
2668 int i;
2669 function *func;
2671 /* No GC can happen yet; process the cached source locations. */
2672 handle_locations ();
2674 /* We've now created tree nodes for the stmts in the various blocks
2675 in each function, but we haven't built each function's single stmt
2676 list yet. Do so now. */
2677 FOR_EACH_VEC_ELT (m_functions, i, func)
2678 func->build_stmt_list ();
2680 /* No GC can have happened yet. */
2682 /* Postprocess the functions. This could trigger GC. */
2683 FOR_EACH_VEC_ELT (m_functions, i, func)
2685 gcc_assert (func);
2686 func->postprocess ();
2691 /* Dump the generated .s file to stderr. */
2693 void
2694 playback::context::
2695 dump_generated_code ()
2697 JIT_LOG_SCOPE (get_logger ());
2698 char buf[4096];
2699 size_t sz;
2700 FILE *f_in = fopen (get_path_s_file (), "r");
2701 if (!f_in)
2702 return;
2704 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2705 fwrite (buf, 1, sz, stderr);
2707 fclose (f_in);
2710 /* Get the supposed path of the notional "fake.c" file within the
2711 tempdir. This file doesn't exist, but the rest of the compiler
2712 needs a name. */
2714 const char *
2715 playback::context::
2716 get_path_c_file () const
2718 return m_tempdir->get_path_c_file ();
2721 /* Get the path of the assembler output file "fake.s" file within the
2722 tempdir. */
2724 const char *
2725 playback::context::
2726 get_path_s_file () const
2728 return m_tempdir->get_path_s_file ();
2731 /* Get the path of the DSO object file "fake.so" file within the
2732 tempdir. */
2734 const char *
2735 playback::context::
2736 get_path_so_file () const
2738 return m_tempdir->get_path_so_file ();
2741 /* qsort comparator for comparing pairs of playback::source_line *,
2742 ordering them by line number. */
2744 static int
2745 line_comparator (const void *lhs, const void *rhs)
2747 const playback::source_line *line_lhs = \
2748 *static_cast<const playback::source_line * const*> (lhs);
2749 const playback::source_line *line_rhs = \
2750 *static_cast<const playback::source_line * const*> (rhs);
2751 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2754 /* qsort comparator for comparing pairs of playback::location *,
2755 ordering them by column number. */
2757 static int
2758 location_comparator (const void *lhs, const void *rhs)
2760 const playback::location *loc_lhs = \
2761 *static_cast<const playback::location * const *> (lhs);
2762 const playback::location *loc_rhs = \
2763 *static_cast<const playback::location * const *> (rhs);
2764 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2767 /* Our API allows locations to be created in arbitrary orders, but the
2768 linemap API requires locations to be created in ascending order
2769 as if we were tokenizing files.
2771 This hook sorts all of the locations that have been created, and
2772 calls into the linemap API, creating linemap entries in sorted order
2773 for our locations. */
2775 void
2776 playback::context::
2777 handle_locations ()
2779 /* Create the source code locations, following the ordering rules
2780 imposed by the linemap API.
2782 line_table is a global. */
2783 JIT_LOG_SCOPE (get_logger ());
2784 int i;
2785 source_file *file;
2787 FOR_EACH_VEC_ELT (m_source_files, i, file)
2789 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2791 /* Sort lines by ascending line numbers. */
2792 file->m_source_lines.qsort (&line_comparator);
2794 int j;
2795 source_line *line;
2796 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2798 int k;
2799 location *loc;
2801 /* Sort locations in line by ascending column numbers. */
2802 line->m_locations.qsort (&location_comparator);
2804 /* Determine maximum column within this line. */
2805 gcc_assert (line->m_locations.length () > 0);
2806 location *final_column =
2807 line->m_locations[line->m_locations.length () - 1];
2808 int max_col = final_column->get_column_num ();
2810 linemap_line_start (line_table, line->get_line_num (), max_col);
2811 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2813 loc->m_srcloc = \
2814 linemap_position_for_column (line_table, loc->get_column_num ());
2818 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2821 /* line_table should now be populated; every playback::location should
2822 now have an m_srcloc. */
2824 /* Now assign them to tree nodes as appropriate. */
2825 std::pair<tree, location *> *cached_location;
2827 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2829 tree t = cached_location->first;
2830 source_location srcloc = cached_location->second->m_srcloc;
2832 /* This covers expressions: */
2833 if (CAN_HAVE_LOCATION_P (t))
2834 SET_EXPR_LOCATION (t, srcloc);
2835 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2836 DECL_SOURCE_LOCATION (t) = srcloc;
2837 else
2839 /* Don't know how to set location on this node. */
2844 /* We handle errors on a playback::context by adding them to the
2845 corresponding recording::context. */
2847 void
2848 playback::context::
2849 add_error (location *loc, const char *fmt, ...)
2851 va_list ap;
2852 va_start (ap, fmt);
2853 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2854 fmt, ap);
2855 va_end (ap);
2858 /* We handle errors on a playback::context by adding them to the
2859 corresponding recording::context. */
2861 void
2862 playback::context::
2863 add_error_va (location *loc, const char *fmt, va_list ap)
2865 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2866 fmt, ap);
2869 /* Report a diagnostic up to the jit context as an error,
2870 so that the compilation is treated as a failure.
2871 For now, any kind of diagnostic is treated as an error by the jit
2872 API. */
2874 void
2875 playback::context::
2876 add_diagnostic (struct diagnostic_context *diag_context,
2877 struct diagnostic_info *diagnostic)
2879 /* At this point the text has been formatted into the pretty-printer's
2880 output buffer. */
2881 pretty_printer *pp = diag_context->printer;
2882 const char *text = pp_formatted_text (pp);
2884 /* Get location information (if any) from the diagnostic.
2885 The recording::context::add_error[_va] methods require a
2886 recording::location. We can't lookup the playback::location
2887 from the file/line/column since any playback location instances
2888 may have been garbage-collected away by now, so instead we create
2889 another recording::location directly. */
2890 location_t gcc_loc = diagnostic_location (diagnostic);
2891 recording::location *rec_loc = NULL;
2892 if (gcc_loc)
2894 expanded_location exploc = expand_location (gcc_loc);
2895 if (exploc.file)
2896 rec_loc = m_recording_ctxt->new_location (exploc.file,
2897 exploc.line,
2898 exploc.column,
2899 false);
2902 m_recording_ctxt->add_error (rec_loc, "%s", text);
2903 pp_clear_output_area (pp);
2906 /* Dealing with the linemap API. */
2908 /* Construct a playback::location for a recording::location, if it
2909 doesn't exist already. */
2911 playback::location *
2912 playback::context::
2913 new_location (recording::location *rloc,
2914 const char *filename,
2915 int line,
2916 int column)
2918 /* Get the source_file for filename, creating if necessary. */
2919 source_file *src_file = get_source_file (filename);
2920 /* Likewise for the line within the file. */
2921 source_line *src_line = src_file->get_source_line (line);
2922 /* Likewise for the column within the line. */
2923 location *loc = src_line->get_location (rloc, column);
2924 return loc;
2927 /* Deferred setting of the location for a given tree, by adding the
2928 (tree, playback::location) pair to a list of deferred associations.
2929 We will actually set the location on the tree later on once
2930 the source_location for the playback::location exists. */
2932 void
2933 playback::context::
2934 set_tree_location (tree t, location *loc)
2936 gcc_assert (loc);
2937 m_cached_locations.safe_push (std::make_pair (t, loc));
2941 /* Construct a playback::source_file for the given source
2942 filename, if it doesn't exist already. */
2944 playback::source_file *
2945 playback::context::
2946 get_source_file (const char *filename)
2948 /* Locate the file.
2949 For simplicitly, this is currently a linear search.
2950 Replace with a hash if this shows up in the profile. */
2951 int i;
2952 source_file *file;
2953 tree ident_filename = get_identifier (filename);
2955 FOR_EACH_VEC_ELT (m_source_files, i, file)
2956 if (file->filename_as_tree () == ident_filename)
2957 return file;
2959 /* Not found. */
2960 file = new source_file (ident_filename);
2961 m_source_files.safe_push (file);
2962 return file;
2965 /* Constructor for gcc::jit::playback::source_file. */
2967 playback::source_file::source_file (tree filename) :
2968 m_source_lines (),
2969 m_filename (filename)
2973 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2974 GC-ed. */
2976 void
2977 playback::source_file::finalizer ()
2979 m_source_lines.release ();
2982 /* Construct a playback::source_line for the given line
2983 within this source file, if one doesn't exist already. */
2985 playback::source_line *
2986 playback::source_file::
2987 get_source_line (int line_num)
2989 /* Locate the line.
2990 For simplicitly, this is currently a linear search.
2991 Replace with a hash if this shows up in the profile. */
2992 int i;
2993 source_line *line;
2995 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2996 if (line->get_line_num () == line_num)
2997 return line;
2999 /* Not found. */
3000 line = new source_line (this, line_num);
3001 m_source_lines.safe_push (line);
3002 return line;
3005 /* Constructor for gcc::jit::playback::source_line. */
3007 playback::source_line::source_line (source_file *file, int line_num) :
3008 m_locations (),
3009 m_source_file (file),
3010 m_line_num (line_num)
3014 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3015 GC-ed. */
3017 void
3018 playback::source_line::finalizer ()
3020 m_locations.release ();
3023 /* Construct a playback::location for the given column
3024 within this line of a specific source file, if one doesn't exist
3025 already. */
3027 playback::location *
3028 playback::source_line::
3029 get_location (recording::location *rloc, int column_num)
3031 int i;
3032 location *loc;
3034 /* Another linear search that probably should be a hash table. */
3035 FOR_EACH_VEC_ELT (m_locations, i, loc)
3036 if (loc->get_column_num () == column_num)
3037 return loc;
3039 /* Not found. */
3040 loc = new location (rloc, this, column_num);
3041 m_locations.safe_push (loc);
3042 return loc;
3045 /* Constructor for gcc::jit::playback::location. */
3047 playback::location::location (recording::location *loc,
3048 source_line *line,
3049 int column_num) :
3050 m_srcloc (UNKNOWN_LOCATION),
3051 m_recording_loc (loc),
3052 m_line (line),
3053 m_column_num(column_num)
3057 /* The active gcc::jit::playback::context instance. This is a singleton,
3058 guarded by jit_mutex. */
3060 playback::context *active_playback_ctxt;
3062 } // namespace gcc::jit
3064 } // namespace gcc