2016-07-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
[official-gcc.git] / gcc / jit / jit-playback.c
blobc9f40848be073cb128b1c23b7699614bc7b01a05
1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2016 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 "gcc.h"
40 #include "diagnostic.h"
42 #include <pthread.h>
44 #include "jit-playback.h"
45 #include "jit-result.h"
46 #include "jit-builtins.h"
47 #include "jit-tempdir.h"
50 /* gcc::jit::playback::context::build_cast uses the convert.h API,
51 which in turn requires the frontend to provide a "convert"
52 function, apparently as a fallback.
54 Hence we provide this dummy one, with the requirement that any casts
55 are handled before reaching this. */
56 extern tree convert (tree type, tree expr);
58 tree
59 convert (tree dst_type, tree expr)
61 gcc_assert (gcc::jit::active_playback_ctxt);
62 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
63 fprintf (stderr, "input expression:\n");
64 debug_tree (expr);
65 fprintf (stderr, "requested type:\n");
66 debug_tree (dst_type);
67 return error_mark_node;
70 namespace gcc {
71 namespace jit {
73 /**********************************************************************
74 Playback.
75 **********************************************************************/
77 /* The constructor for gcc::jit::playback::context. */
79 playback::context::context (recording::context *ctxt)
80 : log_user (ctxt->get_logger ()),
81 m_recording_ctxt (ctxt),
82 m_tempdir (NULL),
83 m_char_array_type_node (NULL),
84 m_const_char_ptr (NULL)
86 JIT_LOG_SCOPE (get_logger ());
87 m_functions.create (0);
88 m_globals.create (0);
89 m_source_files.create (0);
90 m_cached_locations.create (0);
93 /* The destructor for gcc::jit::playback::context. */
95 playback::context::~context ()
97 JIT_LOG_SCOPE (get_logger ());
99 /* Normally the playback::context is responsible for cleaning up the
100 tempdir (including "fake.so" within the filesystem).
102 In the normal case, clean it up now.
104 However m_tempdir can be NULL if the context has handed over
105 responsibility for the tempdir cleanup to the jit::result object, so
106 that the cleanup can be delayed (see PR jit/64206). If that's the
107 case this "delete NULL;" is a no-op. */
108 delete m_tempdir;
110 m_functions.release ();
113 /* A playback::context can reference GC-managed pointers. Mark them
114 ("by hand", rather than by gengtype).
116 This is called on the active playback context (if any) by the
117 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
119 void
120 playback::context::
121 gt_ggc_mx ()
123 int i;
124 function *func;
125 FOR_EACH_VEC_ELT (m_functions, i, func)
127 if (ggc_test_and_set_mark (func))
128 func->gt_ggc_mx ();
132 /* Given an enum gcc_jit_types value, get a "tree" type. */
134 static tree
135 get_tree_node_for_type (enum gcc_jit_types type_)
137 switch (type_)
139 case GCC_JIT_TYPE_VOID:
140 return void_type_node;
142 case GCC_JIT_TYPE_VOID_PTR:
143 return ptr_type_node;
145 case GCC_JIT_TYPE_BOOL:
146 return boolean_type_node;
148 case GCC_JIT_TYPE_CHAR:
149 return char_type_node;
150 case GCC_JIT_TYPE_SIGNED_CHAR:
151 return signed_char_type_node;
152 case GCC_JIT_TYPE_UNSIGNED_CHAR:
153 return unsigned_char_type_node;
155 case GCC_JIT_TYPE_SHORT:
156 return short_integer_type_node;
157 case GCC_JIT_TYPE_UNSIGNED_SHORT:
158 return short_unsigned_type_node;
160 case GCC_JIT_TYPE_CONST_CHAR_PTR:
162 tree const_char = build_qualified_type (char_type_node,
163 TYPE_QUAL_CONST);
164 return build_pointer_type (const_char);
167 case GCC_JIT_TYPE_INT:
168 return integer_type_node;
169 case GCC_JIT_TYPE_UNSIGNED_INT:
170 return unsigned_type_node;
172 case GCC_JIT_TYPE_LONG:
173 return long_integer_type_node;
174 case GCC_JIT_TYPE_UNSIGNED_LONG:
175 return long_unsigned_type_node;
177 case GCC_JIT_TYPE_LONG_LONG:
178 return long_long_integer_type_node;
179 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
180 return long_long_unsigned_type_node;
182 case GCC_JIT_TYPE_FLOAT:
183 return float_type_node;
184 case GCC_JIT_TYPE_DOUBLE:
185 return double_type_node;
186 case GCC_JIT_TYPE_LONG_DOUBLE:
187 return long_double_type_node;
189 case GCC_JIT_TYPE_SIZE_T:
190 return size_type_node;
192 case GCC_JIT_TYPE_FILE_PTR:
193 return fileptr_type_node;
195 case GCC_JIT_TYPE_COMPLEX_FLOAT:
196 return complex_float_type_node;
197 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
198 return complex_double_type_node;
199 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
200 return complex_long_double_type_node;
203 return NULL;
206 /* Construct a playback::type instance (wrapping a tree) for the given
207 enum value. */
209 playback::type *
210 playback::context::
211 get_type (enum gcc_jit_types type_)
213 tree type_node = get_tree_node_for_type (type_);
214 if (NULL == type_node)
216 add_error (NULL,
217 "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 /* Coerce a tree expression into a boolean tree expression. */
634 tree
635 playback::context::
636 as_truth_value (tree expr, location *loc)
638 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
639 tree typed_zero = fold_build1 (CONVERT_EXPR,
640 TREE_TYPE (expr),
641 integer_zero_node);
642 if (loc)
643 set_tree_location (typed_zero, loc);
645 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
646 if (loc)
647 set_tree_location (expr, loc);
649 return expr;
652 /* Construct a playback::rvalue instance (wrapping a tree) for a
653 unary op. */
655 playback::rvalue *
656 playback::context::
657 new_unary_op (location *loc,
658 enum gcc_jit_unary_op op,
659 type *result_type,
660 rvalue *a)
662 // FIXME: type-checking, or coercion?
663 enum tree_code inner_op;
665 gcc_assert (result_type);
666 gcc_assert (a);
668 tree node = a->as_tree ();
669 tree inner_result = NULL;
671 switch (op)
673 default:
674 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
675 return NULL;
677 case GCC_JIT_UNARY_OP_MINUS:
678 inner_op = NEGATE_EXPR;
679 break;
681 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
682 inner_op = BIT_NOT_EXPR;
683 break;
685 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
686 node = as_truth_value (node, loc);
687 inner_result = invert_truthvalue (node);
688 if (loc)
689 set_tree_location (inner_result, loc);
690 return new rvalue (this, inner_result);
692 case GCC_JIT_UNARY_OP_ABS:
693 inner_op = ABS_EXPR;
694 break;
697 inner_result = build1 (inner_op,
698 result_type->as_tree (),
699 node);
700 if (loc)
701 set_tree_location (inner_result, loc);
703 return new rvalue (this, inner_result);
706 /* Construct a playback::rvalue instance (wrapping a tree) for a
707 binary op. */
709 playback::rvalue *
710 playback::context::
711 new_binary_op (location *loc,
712 enum gcc_jit_binary_op op,
713 type *result_type,
714 rvalue *a, rvalue *b)
716 // FIXME: type-checking, or coercion?
717 enum tree_code inner_op;
719 gcc_assert (result_type);
720 gcc_assert (a);
721 gcc_assert (b);
723 tree node_a = a->as_tree ();
724 tree node_b = b->as_tree ();
726 switch (op)
728 default:
729 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
730 return NULL;
732 case GCC_JIT_BINARY_OP_PLUS:
733 inner_op = PLUS_EXPR;
734 break;
736 case GCC_JIT_BINARY_OP_MINUS:
737 inner_op = MINUS_EXPR;
738 break;
740 case GCC_JIT_BINARY_OP_MULT:
741 inner_op = MULT_EXPR;
742 break;
744 case GCC_JIT_BINARY_OP_DIVIDE:
745 if (FLOAT_TYPE_P (result_type->as_tree ()))
746 /* Floating-point division: */
747 inner_op = RDIV_EXPR;
748 else
749 /* Truncating to zero: */
750 inner_op = TRUNC_DIV_EXPR;
751 break;
753 case GCC_JIT_BINARY_OP_MODULO:
754 inner_op = TRUNC_MOD_EXPR;
755 break;
757 case GCC_JIT_BINARY_OP_BITWISE_AND:
758 inner_op = BIT_AND_EXPR;
759 break;
761 case GCC_JIT_BINARY_OP_BITWISE_XOR:
762 inner_op = BIT_XOR_EXPR;
763 break;
765 case GCC_JIT_BINARY_OP_BITWISE_OR:
766 inner_op = BIT_IOR_EXPR;
767 break;
769 case GCC_JIT_BINARY_OP_LOGICAL_AND:
770 node_a = as_truth_value (node_a, loc);
771 node_b = as_truth_value (node_b, loc);
772 inner_op = TRUTH_ANDIF_EXPR;
773 break;
775 case GCC_JIT_BINARY_OP_LOGICAL_OR:
776 node_a = as_truth_value (node_a, loc);
777 node_b = as_truth_value (node_b, loc);
778 inner_op = TRUTH_ORIF_EXPR;
779 break;
781 case GCC_JIT_BINARY_OP_LSHIFT:
782 inner_op = LSHIFT_EXPR;
783 break;
785 case GCC_JIT_BINARY_OP_RSHIFT:
786 inner_op = RSHIFT_EXPR;
787 break;
790 tree inner_expr = build2 (inner_op,
791 result_type->as_tree (),
792 node_a,
793 node_b);
794 if (loc)
795 set_tree_location (inner_expr, loc);
797 return new rvalue (this, inner_expr);
800 /* Construct a playback::rvalue instance (wrapping a tree) for a
801 comparison. */
803 playback::rvalue *
804 playback::context::
805 new_comparison (location *loc,
806 enum gcc_jit_comparison op,
807 rvalue *a, rvalue *b)
809 // FIXME: type-checking, or coercion?
810 enum tree_code inner_op;
812 gcc_assert (a);
813 gcc_assert (b);
815 switch (op)
817 default:
818 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
819 return NULL;
821 case GCC_JIT_COMPARISON_EQ:
822 inner_op = EQ_EXPR;
823 break;
824 case GCC_JIT_COMPARISON_NE:
825 inner_op = NE_EXPR;
826 break;
827 case GCC_JIT_COMPARISON_LT:
828 inner_op = LT_EXPR;
829 break;
830 case GCC_JIT_COMPARISON_LE:
831 inner_op = LE_EXPR;
832 break;
833 case GCC_JIT_COMPARISON_GT:
834 inner_op = GT_EXPR;
835 break;
836 case GCC_JIT_COMPARISON_GE:
837 inner_op = GE_EXPR;
838 break;
841 tree inner_expr = build2 (inner_op,
842 boolean_type_node,
843 a->as_tree (),
844 b->as_tree ());
845 if (loc)
846 set_tree_location (inner_expr, loc);
847 return new rvalue (this, inner_expr);
850 /* Construct a playback::rvalue instance (wrapping a tree) for a
851 function call. */
853 playback::rvalue *
854 playback::context::
855 build_call (location *loc,
856 tree fn_ptr,
857 const auto_vec<rvalue *> *args,
858 bool require_tail_call)
860 vec<tree, va_gc> *tree_args;
861 vec_alloc (tree_args, args->length ());
862 for (unsigned i = 0; i < args->length (); i++)
863 tree_args->quick_push ((*args)[i]->as_tree ());
865 if (loc)
866 set_tree_location (fn_ptr, loc);
868 tree fn = TREE_TYPE (fn_ptr);
869 tree fn_type = TREE_TYPE (fn);
870 tree return_type = TREE_TYPE (fn_type);
872 tree call = build_call_vec (return_type,
873 fn_ptr, tree_args);
875 if (require_tail_call)
876 CALL_EXPR_MUST_TAIL_CALL (call) = 1;
878 return new rvalue (this, call);
880 /* see c-typeck.c: build_function_call
881 which calls build_function_call_vec
883 which does lots of checking, then:
884 result = build_call_array_loc (loc, TREE_TYPE (fntype),
885 function, nargs, argarray);
886 which is in tree.c
887 (see also build_call_vec)
891 /* Construct a playback::rvalue instance (wrapping a tree) for a
892 call to a specific function. */
894 playback::rvalue *
895 playback::context::
896 new_call (location *loc,
897 function *func,
898 const auto_vec<rvalue *> *args,
899 bool require_tail_call)
901 tree fndecl;
903 gcc_assert (func);
905 fndecl = func->as_fndecl ();
907 tree fntype = TREE_TYPE (fndecl);
909 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
911 return build_call (loc, fn, args, require_tail_call);
914 /* Construct a playback::rvalue instance (wrapping a tree) for a
915 call through a function pointer. */
917 playback::rvalue *
918 playback::context::
919 new_call_through_ptr (location *loc,
920 rvalue *fn_ptr,
921 const auto_vec<rvalue *> *args,
922 bool require_tail_call)
924 gcc_assert (fn_ptr);
925 tree t_fn_ptr = fn_ptr->as_tree ();
927 return build_call (loc, t_fn_ptr, args, require_tail_call);
930 /* Construct a tree for a cast. */
932 tree
933 playback::context::build_cast (playback::location *loc,
934 playback::rvalue *expr,
935 playback::type *type_)
937 /* For comparison, see:
938 - c/c-typeck.c:build_c_cast
939 - c/c-convert.c: convert
940 - convert.h
942 Only some kinds of cast are currently supported here. */
943 tree t_expr = expr->as_tree ();
944 tree t_dst_type = type_->as_tree ();
945 tree t_ret = NULL;
946 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
947 if (t_ret)
948 return t_ret;
949 enum tree_code dst_code = TREE_CODE (t_dst_type);
950 switch (dst_code)
952 case INTEGER_TYPE:
953 case ENUMERAL_TYPE:
954 t_ret = convert_to_integer (t_dst_type, t_expr);
955 goto maybe_fold;
957 case BOOLEAN_TYPE:
958 /* Compare with c_objc_common_truthvalue_conversion and
959 c_common_truthvalue_conversion. */
960 /* For now, convert to: (t_expr != 0) */
961 t_ret = build2 (NE_EXPR, t_dst_type,
962 t_expr,
963 build_int_cst (TREE_TYPE (t_expr), 0));
964 goto maybe_fold;
966 case REAL_TYPE:
967 t_ret = convert_to_real (t_dst_type, t_expr);
968 goto maybe_fold;
970 case POINTER_TYPE:
971 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
972 goto maybe_fold;
974 default:
975 add_error (loc, "couldn't handle cast during playback");
976 fprintf (stderr, "input expression:\n");
977 debug_tree (t_expr);
978 fprintf (stderr, "requested type:\n");
979 debug_tree (t_dst_type);
980 return error_mark_node;
982 maybe_fold:
983 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
984 t_ret = fold (t_ret);
985 return t_ret;
989 /* Construct a playback::rvalue instance (wrapping a tree) for a
990 cast. */
992 playback::rvalue *
993 playback::context::
994 new_cast (playback::location *loc,
995 playback::rvalue *expr,
996 playback::type *type_)
999 tree t_cast = build_cast (loc, expr, type_);
1000 if (loc)
1001 set_tree_location (t_cast, loc);
1002 return new rvalue (this, t_cast);
1005 /* Construct a playback::lvalue instance (wrapping a tree) for an
1006 array access. */
1008 playback::lvalue *
1009 playback::context::
1010 new_array_access (location *loc,
1011 rvalue *ptr,
1012 rvalue *index)
1014 gcc_assert (ptr);
1015 gcc_assert (index);
1017 /* For comparison, see:
1018 c/c-typeck.c: build_array_ref
1019 c-family/c-common.c: pointer_int_sum
1021 tree t_ptr = ptr->as_tree ();
1022 tree t_index = index->as_tree ();
1023 tree t_type_ptr = TREE_TYPE (t_ptr);
1024 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1026 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1028 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1029 NULL_TREE, NULL_TREE);
1030 if (loc)
1031 set_tree_location (t_result, loc);
1032 return new lvalue (this, t_result);
1034 else
1036 /* Convert index to an offset in bytes. */
1037 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1038 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1039 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
1041 /* Locate (ptr + offset). */
1042 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1044 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1045 if (loc)
1047 set_tree_location (t_sizeof, loc);
1048 set_tree_location (t_offset, loc);
1049 set_tree_location (t_address, loc);
1050 set_tree_location (t_indirection, loc);
1053 return new lvalue (this, t_indirection);
1057 /* Construct a tree for a field access. */
1059 tree
1060 playback::context::
1061 new_field_access (location *loc,
1062 tree datum,
1063 field *field)
1065 gcc_assert (datum);
1066 gcc_assert (field);
1068 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1069 build_component_ref. */
1070 tree type = TREE_TYPE (datum);
1071 gcc_assert (type);
1072 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1074 tree t_field = field->as_tree ();
1075 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1076 t_field, NULL_TREE);
1077 if (loc)
1078 set_tree_location (ref, loc);
1079 return ref;
1082 /* Construct a tree for a dereference. */
1084 tree
1085 playback::context::
1086 new_dereference (tree ptr,
1087 location *loc)
1089 gcc_assert (ptr);
1091 tree type = TREE_TYPE (TREE_TYPE(ptr));
1092 tree datum = build1 (INDIRECT_REF, type, ptr);
1093 if (loc)
1094 set_tree_location (datum, loc);
1095 return datum;
1098 /* Construct a playback::lvalue instance (wrapping a tree) for a
1099 field access. */
1101 playback::lvalue *
1102 playback::lvalue::
1103 access_field (location *loc,
1104 field *field)
1106 tree datum = as_tree ();
1107 tree ref = get_context ()->new_field_access (loc, datum, field);
1108 if (!ref)
1109 return NULL;
1110 return new lvalue (get_context (), ref);
1113 /* Construct a playback::rvalue instance (wrapping a tree) for a
1114 field access. */
1116 playback::rvalue *
1117 playback::rvalue::
1118 access_field (location *loc,
1119 field *field)
1121 tree datum = as_tree ();
1122 tree ref = get_context ()->new_field_access (loc, datum, field);
1123 if (!ref)
1124 return NULL;
1125 return new rvalue (get_context (), ref);
1128 /* Construct a playback::lvalue instance (wrapping a tree) for a
1129 dereferenced field access. */
1131 playback::lvalue *
1132 playback::rvalue::
1133 dereference_field (location *loc,
1134 field *field)
1136 tree ptr = as_tree ();
1137 tree datum = get_context ()->new_dereference (ptr, loc);
1138 if (!datum)
1139 return NULL;
1140 tree ref = get_context ()->new_field_access (loc, datum, field);
1141 if (!ref)
1142 return NULL;
1143 return new lvalue (get_context (), ref);
1146 /* Construct a playback::lvalue instance (wrapping a tree) for a
1147 dereference. */
1149 playback::lvalue *
1150 playback::rvalue::
1151 dereference (location *loc)
1153 tree ptr = as_tree ();
1154 tree datum = get_context ()->new_dereference (ptr, loc);
1155 return new lvalue (get_context (), datum);
1158 /* Mark EXP saying that we need to be able to take the
1159 address of it; it should not be allocated in a register.
1160 Compare with e.g. c/c-typeck.c: c_mark_addressable. */
1162 static void
1163 jit_mark_addressable (tree exp)
1165 tree x = exp;
1167 while (1)
1168 switch (TREE_CODE (x))
1170 case COMPONENT_REF:
1171 /* (we don't yet support bitfields) */
1172 /* fallthrough */
1173 case ADDR_EXPR:
1174 case ARRAY_REF:
1175 case REALPART_EXPR:
1176 case IMAGPART_EXPR:
1177 x = TREE_OPERAND (x, 0);
1178 break;
1180 case COMPOUND_LITERAL_EXPR:
1181 case CONSTRUCTOR:
1182 TREE_ADDRESSABLE (x) = 1;
1183 return;
1185 case VAR_DECL:
1186 case CONST_DECL:
1187 case PARM_DECL:
1188 case RESULT_DECL:
1189 /* (we don't have a concept of a "register" declaration) */
1190 /* fallthrough */
1191 case FUNCTION_DECL:
1192 TREE_ADDRESSABLE (x) = 1;
1193 /* fallthrough */
1194 default:
1195 return;
1199 /* Construct a playback::rvalue instance (wrapping a tree) for an
1200 address-lookup. */
1202 playback::rvalue *
1203 playback::lvalue::
1204 get_address (location *loc)
1206 tree t_lvalue = as_tree ();
1207 tree t_thistype = TREE_TYPE (t_lvalue);
1208 tree t_ptrtype = build_pointer_type (t_thistype);
1209 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1210 if (loc)
1211 get_context ()->set_tree_location (ptr, loc);
1212 jit_mark_addressable (t_lvalue);
1213 return new rvalue (get_context (), ptr);
1216 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1217 Provide this finalization hook for calling then they are collected,
1218 which calls the finalizer vfunc. This allows them to call "release"
1219 on any vec<> within them. */
1221 static void
1222 wrapper_finalizer (void *ptr)
1224 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1225 wrapper->finalizer ();
1228 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1229 allocate them using ggc_internal_cleared_alloc. */
1231 void *
1232 playback::wrapper::
1233 operator new (size_t sz)
1235 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1239 /* Constructor for gcc:jit::playback::function. */
1241 playback::function::
1242 function (context *ctxt,
1243 tree fndecl,
1244 enum gcc_jit_function_kind kind)
1245 : m_ctxt(ctxt),
1246 m_inner_fndecl (fndecl),
1247 m_inner_bind_expr (NULL),
1248 m_kind (kind)
1250 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1252 /* Create a BIND_EXPR, and within it, a statement list. */
1253 m_stmt_list = alloc_stmt_list ();
1254 m_stmt_iter = tsi_start (m_stmt_list);
1255 m_inner_block = make_node (BLOCK);
1256 m_inner_bind_expr =
1257 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1259 else
1261 m_inner_block = NULL;
1262 m_stmt_list = NULL;
1266 /* Hand-written GC-marking hook for playback functions. */
1268 void
1269 playback::function::
1270 gt_ggc_mx ()
1272 gt_ggc_m_9tree_node (m_inner_fndecl);
1273 gt_ggc_m_9tree_node (m_inner_bind_expr);
1274 gt_ggc_m_9tree_node (m_stmt_list);
1275 gt_ggc_m_9tree_node (m_inner_block);
1278 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1279 GC-ed. */
1281 void
1282 playback::function::finalizer ()
1284 m_blocks.release ();
1287 /* Get the return type of a playback function, in tree form. */
1289 tree
1290 playback::function::
1291 get_return_type_as_tree () const
1293 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1296 /* Construct a new local within this playback::function. */
1298 playback::lvalue *
1299 playback::function::
1300 new_local (location *loc,
1301 type *type,
1302 const char *name)
1304 gcc_assert (type);
1305 gcc_assert (name);
1306 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1307 get_identifier (name),
1308 type->as_tree ());
1309 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1311 /* Prepend to BIND_EXPR_VARS: */
1312 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1313 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1315 if (loc)
1316 set_tree_location (inner, loc);
1317 return new lvalue (m_ctxt, inner);
1320 /* Construct a new block within this playback::function. */
1322 playback::block *
1323 playback::function::
1324 new_block (const char *name)
1326 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1328 block *result = new playback::block (this, name);
1329 m_blocks.safe_push (result);
1330 return result;
1333 /* Build a statement list for the function as a whole out of the
1334 lists of statements for the individual blocks, building labels
1335 for each block. */
1337 void
1338 playback::function::
1339 build_stmt_list ()
1341 int i;
1342 block *b;
1344 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1346 FOR_EACH_VEC_ELT (m_blocks, i, b)
1348 int j;
1349 tree stmt;
1351 b->m_label_expr = build1 (LABEL_EXPR,
1352 void_type_node,
1353 b->as_label_decl ());
1354 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1356 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1357 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1361 /* Finish compiling the given function, potentially running the
1362 garbage-collector.
1363 The function will have a statement list by now.
1364 Amongst other things, this gimplifies the statement list,
1365 and calls cgraph_node::finalize_function on the function. */
1367 void
1368 playback::function::
1369 postprocess ()
1371 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1373 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1374 debug_tree (m_stmt_list);
1376 /* Do we need this to force cgraphunit.c to output the function? */
1377 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1379 DECL_EXTERNAL (m_inner_fndecl) = 0;
1380 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1383 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1384 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1386 DECL_EXTERNAL (m_inner_fndecl) = 0;
1387 TREE_PUBLIC (m_inner_fndecl) = 0;
1390 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1392 /* Seem to need this in gimple-low.c: */
1393 gcc_assert (m_inner_block);
1394 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1396 /* how to add to function? the following appears to be how to
1397 set the body of a m_inner_fndecl: */
1398 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1400 /* Ensure that locals appear in the debuginfo. */
1401 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1403 //debug_tree (m_inner_fndecl);
1405 /* Convert to gimple: */
1406 //printf("about to gimplify_function_tree\n");
1407 gimplify_function_tree (m_inner_fndecl);
1408 //printf("finished gimplify_function_tree\n");
1410 current_function_decl = m_inner_fndecl;
1411 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1412 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1413 //debug_tree (m_inner_fndecl);
1415 //printf("about to add to cgraph\n");
1416 /* Add to cgraph: */
1417 cgraph_node::finalize_function (m_inner_fndecl, false);
1418 /* This can trigger a collection, so we need to have all of
1419 the funcs as roots. */
1421 current_function_decl = NULL;
1425 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1426 GC-ed. */
1428 void
1429 playback::block::finalizer ()
1431 m_stmts.release ();
1434 /* Add an eval of the rvalue to the function's statement list. */
1436 void
1437 playback::block::
1438 add_eval (location *loc,
1439 rvalue *rvalue)
1441 gcc_assert (rvalue);
1443 if (loc)
1444 set_tree_location (rvalue->as_tree (), loc);
1446 add_stmt (rvalue->as_tree ());
1449 /* Add an assignment to the function's statement list. */
1451 void
1452 playback::block::
1453 add_assignment (location *loc,
1454 lvalue *lvalue,
1455 rvalue *rvalue)
1457 gcc_assert (lvalue);
1458 gcc_assert (rvalue);
1460 tree t_lvalue = lvalue->as_tree ();
1461 tree t_rvalue = rvalue->as_tree ();
1462 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1464 t_rvalue = build1 (CONVERT_EXPR,
1465 TREE_TYPE (t_lvalue),
1466 t_rvalue);
1467 if (loc)
1468 set_tree_location (t_rvalue, loc);
1471 tree stmt =
1472 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1473 t_lvalue, t_rvalue);
1474 if (loc)
1475 set_tree_location (stmt, loc);
1476 add_stmt (stmt);
1479 /* Add a comment to the function's statement list.
1480 For now this is done by adding a dummy label. */
1482 void
1483 playback::block::
1484 add_comment (location *loc,
1485 const char *text)
1487 /* Wrap the text in C-style comment delimiters. */
1488 size_t sz =
1489 (3 /* opening delim */
1490 + strlen (text)
1491 + 3 /* closing delim */
1492 + 1 /* terminator */);
1493 char *wrapped = (char *)ggc_internal_alloc (sz);
1494 snprintf (wrapped, sz, "/* %s */", text);
1496 /* For now we simply implement this by adding a dummy label with a name
1497 containing the given text. */
1498 tree identifier = get_identifier (wrapped);
1499 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1500 identifier, void_type_node);
1501 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1503 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1504 if (loc)
1505 set_tree_location (label_expr, loc);
1506 add_stmt (label_expr);
1509 /* Add a conditional jump statement to the function's statement list. */
1511 void
1512 playback::block::
1513 add_conditional (location *loc,
1514 rvalue *boolval,
1515 block *on_true,
1516 block *on_false)
1518 gcc_assert (boolval);
1519 gcc_assert (on_true);
1520 gcc_assert (on_false);
1522 /* COND_EXPR wants statement lists for the true/false operands, but we
1523 want labels.
1524 Shim it by creating jumps to the labels */
1525 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1526 on_true->as_label_decl ());
1527 if (loc)
1528 set_tree_location (true_jump, loc);
1530 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1531 on_false->as_label_decl ());
1532 if (loc)
1533 set_tree_location (false_jump, loc);
1535 tree stmt =
1536 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1537 true_jump, false_jump);
1538 if (loc)
1539 set_tree_location (stmt, loc);
1540 add_stmt (stmt);
1543 /* Add an unconditional jump statement to the function's statement list. */
1545 void
1546 playback::block::
1547 add_jump (location *loc,
1548 block *target)
1550 gcc_assert (target);
1552 // see c_finish_loop
1553 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1554 //add_stmt (top);
1556 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1557 TREE_USED (target->as_label_decl ()) = 1;
1558 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1559 if (loc)
1560 set_tree_location (stmt, loc);
1561 add_stmt (stmt);
1564 from c-typeck.c:
1565 tree
1566 c_finish_goto_label (location_t loc, tree label)
1568 tree decl = lookup_label_for_goto (loc, label);
1569 if (!decl)
1570 return NULL_TREE;
1571 TREE_USED (decl) = 1;
1573 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1574 SET_EXPR_LOCATION (t, loc);
1575 return add_stmt (t);
1582 /* Add a return statement to the function's statement list. */
1584 void
1585 playback::block::
1586 add_return (location *loc,
1587 rvalue *rvalue)
1589 tree modify_retval = NULL;
1590 tree return_type = m_func->get_return_type_as_tree ();
1591 if (rvalue)
1593 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1594 tree t_rvalue = rvalue->as_tree ();
1595 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1596 t_rvalue = build1 (CONVERT_EXPR,
1597 TREE_TYPE (t_lvalue),
1598 t_rvalue);
1599 modify_retval = build2 (MODIFY_EXPR, return_type,
1600 t_lvalue, t_rvalue);
1601 if (loc)
1602 set_tree_location (modify_retval, loc);
1604 tree return_stmt = build1 (RETURN_EXPR, return_type,
1605 modify_retval);
1606 if (loc)
1607 set_tree_location (return_stmt, loc);
1609 add_stmt (return_stmt);
1612 /* Helper function for playback::block::add_switch.
1613 Construct a case label for the given range, followed by a goto stmt
1614 to the given block, appending them to stmt list *ptr_t_switch_body. */
1616 static void
1617 add_case (tree *ptr_t_switch_body,
1618 tree t_low_value,
1619 tree t_high_value,
1620 playback::block *dest_block)
1622 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
1623 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
1625 tree t_case_label =
1626 build_case_label (t_low_value, t_high_value, t_label);
1627 append_to_statement_list (t_case_label, ptr_t_switch_body);
1629 tree t_goto_stmt =
1630 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
1631 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
1634 /* Add a switch statement to the function's statement list.
1636 My initial attempt at implementing this constructed a TREE_VEC
1637 of the cases and set it as SWITCH_LABELS (switch_expr). However,
1638 gimplify.c:gimplify_switch_expr is set up to deal with SWITCH_BODY, and
1639 doesn't have any logic for gimplifying SWITCH_LABELS.
1641 Hence we create a switch body, and populate it with case labels, each
1642 followed by a goto to the desired block. */
1644 void
1645 playback::block::
1646 add_switch (location *loc,
1647 rvalue *expr,
1648 block *default_block,
1649 const auto_vec <case_> *cases)
1651 /* Compare with:
1652 - c/c-typeck.c: c_start_case
1653 - c-family/c-common.c:c_add_case_label
1654 - java/expr.c:expand_java_switch and expand_java_add_case
1655 We've already rejected overlaps and duplicates in
1656 libgccjit.c:case_range_validator::validate. */
1658 tree t_expr = expr->as_tree ();
1659 tree t_type = TREE_TYPE (t_expr);
1661 tree t_switch_body = alloc_stmt_list ();
1663 int i;
1664 case_ *c;
1665 FOR_EACH_VEC_ELT (*cases, i, c)
1667 tree t_low_value = c->m_min_value->as_tree ();
1668 tree t_high_value = c->m_max_value->as_tree ();
1669 add_case (&t_switch_body,
1670 t_low_value,
1671 t_high_value,
1672 c->m_dest_block);
1674 /* Default label. */
1675 add_case (&t_switch_body,
1676 NULL_TREE, NULL_TREE,
1677 default_block);
1679 tree switch_stmt = build3 (SWITCH_EXPR, t_type, t_expr,
1680 t_switch_body, NULL_TREE);
1681 if (loc)
1682 set_tree_location (switch_stmt, loc);
1683 add_stmt (switch_stmt);
1686 /* Constructor for gcc::jit::playback::block. */
1688 playback::block::
1689 block (function *func,
1690 const char *name)
1691 : m_func (func),
1692 m_stmts ()
1694 tree identifier;
1696 gcc_assert (func);
1697 // name can be NULL
1698 if (name)
1699 identifier = get_identifier (name);
1700 else
1701 identifier = NULL;
1702 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1703 identifier, void_type_node);
1704 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1705 m_label_expr = NULL;
1708 /* A subclass of auto_vec <char *> that frees all of its elements on
1709 deletion. */
1711 class auto_argvec : public auto_vec <char *>
1713 public:
1714 ~auto_argvec ();
1717 /* auto_argvec's dtor, freeing all contained strings, automatically
1718 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1720 auto_argvec::~auto_argvec ()
1722 int i;
1723 char *str;
1724 FOR_EACH_VEC_ELT (*this, i, str)
1725 free (str);
1728 /* Compile a playback::context:
1730 - Use the context's options to cconstruct command-line options, and
1731 call into the rest of GCC (toplev::main).
1732 - Assuming it succeeds, we have a .s file.
1733 - We then run the "postprocess" vfunc:
1735 (A) In-memory compile ("gcc_jit_context_compile")
1737 For an in-memory compile we have the playback::compile_to_memory
1738 subclass; "postprocess" will convert the .s file to a .so DSO,
1739 and load it in memory (via dlopen), wrapping the result up as
1740 a jit::result and returning it.
1742 (B) Compile to file ("gcc_jit_context_compile_to_file")
1744 When compiling to a file, we have the playback::compile_to_file
1745 subclass; "postprocess" will either copy the .s file to the
1746 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1747 the driver to convert it as necessary, copying the result. */
1749 void
1750 playback::context::
1751 compile ()
1753 JIT_LOG_SCOPE (get_logger ());
1755 const char *ctxt_progname;
1757 int keep_intermediates =
1758 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
1760 m_tempdir = new tempdir (get_logger (), keep_intermediates);
1761 if (!m_tempdir->create ())
1762 return;
1764 /* Call into the rest of gcc.
1765 For now, we have to assemble command-line options to pass into
1766 toplev::main, so that they can be parsed. */
1768 /* Pass in user-provided program name as argv0, if any, so that it
1769 makes it into GCC's "progname" global, used in various diagnostics. */
1770 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1772 if (!ctxt_progname)
1773 ctxt_progname = "libgccjit.so";
1775 auto_vec <recording::requested_dump> requested_dumps;
1776 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1778 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1779 acquire_mutex ();
1781 auto_argvec fake_args;
1782 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
1783 if (errors_occurred ())
1785 release_mutex ();
1786 return;
1789 /* This runs the compiler. */
1790 toplev toplev (get_timer (), /* external_timer */
1791 false); /* init_signals */
1792 enter_scope ("toplev::main");
1793 if (get_logger ())
1794 for (unsigned i = 0; i < fake_args.length (); i++)
1795 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
1796 toplev.main (fake_args.length (),
1797 const_cast <char **> (fake_args.address ()));
1798 exit_scope ("toplev::main");
1800 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1801 need to do it between toplev::main (which creates the dump manager)
1802 and toplev::finalize (which deletes it). */
1803 extract_any_requested_dumps (&requested_dumps);
1805 /* Clean up the compiler. */
1806 enter_scope ("toplev::finalize");
1807 toplev.finalize ();
1808 exit_scope ("toplev::finalize");
1810 /* Ideally we would release the jit mutex here, but we can't yet since
1811 followup activities use timevars, which are global state. */
1813 if (errors_occurred ())
1815 release_mutex ();
1816 return;
1819 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1820 dump_generated_code ();
1822 /* We now have a .s file.
1824 Run any postprocessing steps. This will either convert the .s file to
1825 a .so DSO, and load it in memory (playback::compile_to_memory), or
1826 convert the .s file to the requested output format, and copy it to a
1827 given file (playback::compile_to_file). */
1828 postprocess (ctxt_progname);
1830 release_mutex ();
1833 /* Implementation of class gcc::jit::playback::compile_to_memory,
1834 a subclass of gcc::jit::playback::context. */
1836 /* playback::compile_to_memory's trivial constructor. */
1838 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
1839 playback::context (ctxt),
1840 m_result (NULL)
1842 JIT_LOG_SCOPE (get_logger ());
1845 /* Implementation of the playback::context::process vfunc for compiling
1846 to memory.
1848 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1849 wrapping the result up as a jit::result and returning it. */
1851 void
1852 playback::compile_to_memory::postprocess (const char *ctxt_progname)
1854 JIT_LOG_SCOPE (get_logger ());
1855 convert_to_dso (ctxt_progname);
1856 if (errors_occurred ())
1857 return;
1858 m_result = dlopen_built_dso ();
1861 /* Implementation of class gcc::jit::playback::compile_to_file,
1862 a subclass of gcc::jit::playback::context. */
1864 /* playback::compile_to_file's trivial constructor. */
1866 playback::compile_to_file::compile_to_file (recording::context *ctxt,
1867 enum gcc_jit_output_kind output_kind,
1868 const char *output_path) :
1869 playback::context (ctxt),
1870 m_output_kind (output_kind),
1871 m_output_path (output_path)
1873 JIT_LOG_SCOPE (get_logger ());
1876 /* Implementation of the playback::context::process vfunc for compiling
1877 to a file.
1879 Either copy the .s file to the given destination (for
1880 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1881 as necessary, copying the result. */
1883 void
1884 playback::compile_to_file::postprocess (const char *ctxt_progname)
1886 JIT_LOG_SCOPE (get_logger ());
1888 /* The driver takes different actions based on the filename, so
1889 we provide a filename with an appropriate suffix for the
1890 output kind, and then copy it up to the user-provided path,
1891 rather than directly compiling it to the requested output path. */
1893 switch (m_output_kind)
1895 default:
1896 gcc_unreachable ();
1898 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
1899 copy_file (get_tempdir ()->get_path_s_file (),
1900 m_output_path);
1901 /* The .s file is automatically unlinked by tempdir::~tempdir. */
1902 break;
1904 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
1906 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
1907 "/fake.o",
1908 NULL);
1909 invoke_driver (ctxt_progname,
1910 get_tempdir ()->get_path_s_file (),
1911 tmp_o_path,
1912 TV_ASSEMBLE,
1913 false, /* bool shared, */
1914 false);/* bool run_linker */
1915 if (!errors_occurred ())
1917 copy_file (tmp_o_path,
1918 m_output_path);
1919 get_tempdir ()->add_temp_file (tmp_o_path);
1921 else
1922 free (tmp_o_path);
1924 break;
1926 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
1927 invoke_driver (ctxt_progname,
1928 get_tempdir ()->get_path_s_file (),
1929 get_tempdir ()->get_path_so_file (),
1930 TV_ASSEMBLE,
1931 true, /* bool shared, */
1932 true);/* bool run_linker */
1933 if (!errors_occurred ())
1934 copy_file (get_tempdir ()->get_path_so_file (),
1935 m_output_path);
1936 /* The .so file is automatically unlinked by tempdir::~tempdir. */
1937 break;
1939 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
1941 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
1942 "/fake.exe",
1943 NULL);
1944 invoke_driver (ctxt_progname,
1945 get_tempdir ()->get_path_s_file (),
1946 tmp_exe_path,
1947 TV_ASSEMBLE,
1948 false, /* bool shared, */
1949 true);/* bool run_linker */
1950 if (!errors_occurred ())
1952 copy_file (tmp_exe_path,
1953 m_output_path);
1954 get_tempdir ()->add_temp_file (tmp_exe_path);
1956 else
1957 free (tmp_exe_path);
1959 break;
1965 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
1966 the "executable" bits).
1968 Any errors that occur are reported on the context and hence count as
1969 a failure of the compile.
1971 We can't in general hardlink or use "rename" from the tempdir since
1972 it might be on a different filesystem to the destination. For example,
1973 I get EXDEV: "Invalid cross-device link". */
1975 void
1976 playback::compile_to_file::copy_file (const char *src_path,
1977 const char *dst_path)
1979 JIT_LOG_SCOPE (get_logger ());
1980 if (get_logger ())
1982 get_logger ()->log ("src_path: %s", src_path);
1983 get_logger ()->log ("dst_path: %s", dst_path);
1986 FILE *f_in = NULL;
1987 FILE *f_out = NULL;
1988 size_t total_sz_in = 0;
1989 size_t total_sz_out = 0;
1990 char buf[4096];
1991 size_t sz_in;
1992 struct stat stat_buf;
1994 f_in = fopen (src_path, "rb");
1995 if (!f_in)
1997 add_error (NULL,
1998 "unable to open %s for reading: %s",
1999 src_path,
2000 xstrerror (errno));
2001 return;
2004 /* Use stat on the filedescriptor to get the mode,
2005 so that we can copy it over (in particular, the
2006 "executable" bits). */
2007 if (-1 == fstat (fileno (f_in), &stat_buf))
2009 add_error (NULL,
2010 "unable to fstat %s: %s",
2011 src_path,
2012 xstrerror (errno));
2013 fclose (f_in);
2014 return;
2017 f_out = fopen (dst_path, "wb");
2018 if (!f_out)
2020 add_error (NULL,
2021 "unable to open %s for writing: %s",
2022 dst_path,
2023 xstrerror (errno));
2024 fclose (f_in);
2025 return;
2028 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2030 total_sz_in += sz_in;
2031 size_t sz_out_remaining = sz_in;
2032 size_t sz_out_so_far = 0;
2033 while (sz_out_remaining)
2035 size_t sz_out = fwrite (buf + sz_out_so_far,
2037 sz_out_remaining,
2038 f_out);
2039 gcc_assert (sz_out <= sz_out_remaining);
2040 if (!sz_out)
2042 add_error (NULL,
2043 "error writing to %s: %s",
2044 dst_path,
2045 xstrerror (errno));
2046 fclose (f_in);
2047 fclose (f_out);
2048 return;
2050 total_sz_out += sz_out;
2051 sz_out_so_far += sz_out;
2052 sz_out_remaining -= sz_out;
2054 gcc_assert (sz_out_so_far == sz_in);
2057 if (!feof (f_in))
2058 add_error (NULL,
2059 "error reading from %s: %s",
2060 src_path,
2061 xstrerror (errno));
2063 fclose (f_in);
2065 gcc_assert (total_sz_in == total_sz_out);
2066 if (get_logger ())
2067 get_logger ()->log ("total bytes copied: %ld", total_sz_out);
2069 /* Set the permissions of the copy to those of the original file,
2070 in particular the "executable" bits. */
2071 if (-1 == fchmod (fileno (f_out), stat_buf.st_mode))
2072 add_error (NULL,
2073 "error setting mode of %s: %s",
2074 dst_path,
2075 xstrerror (errno));
2077 fclose (f_out);
2080 /* Helper functions for gcc::jit::playback::context::compile. */
2082 /* This mutex guards gcc::jit::recording::context::compile, so that only
2083 one thread can be accessing the bulk of GCC's state at once. */
2085 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2087 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2089 void
2090 playback::context::acquire_mutex ()
2092 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2094 /* Acquire the big GCC mutex. */
2095 JIT_LOG_SCOPE (get_logger ());
2096 pthread_mutex_lock (&jit_mutex);
2097 gcc_assert (NULL == active_playback_ctxt);
2098 active_playback_ctxt = this;
2101 /* Release jit_mutex and clear the active playback ctxt. */
2103 void
2104 playback::context::release_mutex ()
2106 /* Release the big GCC mutex. */
2107 JIT_LOG_SCOPE (get_logger ());
2108 gcc_assert (active_playback_ctxt == this);
2109 active_playback_ctxt = NULL;
2110 pthread_mutex_unlock (&jit_mutex);
2113 /* Callback used by gcc::jit::playback::context::make_fake_args when
2114 invoking driver_get_configure_time_options.
2115 Populate a vec <char * > with the configure-time options. */
2117 static void
2118 append_arg_from_driver (const char *option, void *user_data)
2120 gcc_assert (option);
2121 gcc_assert (user_data);
2122 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2123 argvec->safe_push (concat ("-", option, NULL));
2126 /* Build a fake argv for toplev::main from the options set
2127 by the user on the context . */
2129 void
2130 playback::context::
2131 make_fake_args (vec <char *> *argvec,
2132 const char *ctxt_progname,
2133 vec <recording::requested_dump> *requested_dumps)
2135 JIT_LOG_SCOPE (get_logger ());
2137 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2138 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2140 ADD_ARG (ctxt_progname);
2141 ADD_ARG (get_path_c_file ());
2142 ADD_ARG ("-fPIC");
2144 /* Handle int options: */
2145 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2147 default:
2148 add_error (NULL,
2149 "unrecognized optimization level: %i",
2150 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2151 return;
2153 case 0:
2154 ADD_ARG ("-O0");
2155 break;
2157 case 1:
2158 ADD_ARG ("-O1");
2159 break;
2161 case 2:
2162 ADD_ARG ("-O2");
2163 break;
2165 case 3:
2166 ADD_ARG ("-O3");
2167 break;
2169 /* What about -Os? */
2171 /* Handle bool options: */
2172 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2173 ADD_ARG ("-g");
2175 /* Suppress timing (and other) info. */
2176 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2178 ADD_ARG ("-quiet");
2179 quiet_flag = 1;
2182 /* Aggressively garbage-collect, to shake out bugs: */
2183 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2185 ADD_ARG ("--param");
2186 ADD_ARG ("ggc-min-expand=0");
2187 ADD_ARG ("--param");
2188 ADD_ARG ("ggc-min-heapsize=0");
2191 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2193 ADD_ARG ("-fdump-tree-all");
2194 ADD_ARG ("-fdump-rtl-all");
2195 ADD_ARG ("-fdump-ipa-all");
2198 /* Add "-fdump-" options for any calls to
2199 gcc_jit_context_enable_dump. */
2201 int i;
2202 recording::requested_dump *d;
2203 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2205 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2206 ADD_ARG_TAKE_OWNERSHIP (arg);
2210 /* PR jit/64810: Add any target-specific default options
2211 from OPTION_DEFAULT_SPECS, normally provided by the driver
2212 in the non-jit case.
2214 The target-specific code can define OPTION_DEFAULT_SPECS:
2215 default command options in the form of spec macros for the
2216 driver to expand ().
2218 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2219 if not overriden, injects the defaults as extra arguments to
2220 cc1 etc.
2221 For the jit case, we need to add these arguments here. The
2222 input format (using the specs language) means that we have to run
2223 part of the driver code here (driver_get_configure_time_options).
2225 To avoid running the spec-expansion code every time, we just do
2226 it the first time (via a function-static flag), saving the result
2227 into a function-static vec.
2228 This flag and vec are global state (i.e. per-process).
2229 They are guarded by the jit mutex. */
2231 static bool have_configure_time_options = false;
2232 static vec <char *> configure_time_options;
2234 if (have_configure_time_options)
2235 log ("reusing cached configure-time options");
2236 else
2238 have_configure_time_options = true;
2239 log ("getting configure-time options from driver");
2240 driver_get_configure_time_options (append_arg_from_driver,
2241 &configure_time_options);
2244 int i;
2245 char *opt;
2247 if (get_logger ())
2248 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2249 log ("configure_time_options[%i]: %s", i, opt);
2251 /* configure_time_options should now contain the expanded options
2252 from OPTION_DEFAULT_SPECS (if any). */
2253 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2255 gcc_assert (opt);
2256 gcc_assert (opt[0] == '-');
2257 ADD_ARG (opt);
2261 if (get_timer ())
2262 ADD_ARG ("-ftime-report");
2264 /* Add any user-provided extra options, starting with any from
2265 parent contexts. */
2266 m_recording_ctxt->append_command_line_options (argvec);
2268 #undef ADD_ARG
2269 #undef ADD_ARG_TAKE_OWNERSHIP
2272 /* The second half of the implementation of gcc_jit_context_enable_dump.
2273 Iterate through the requested dumps, reading the underlying files
2274 into heap-allocated buffers, writing pointers to the buffers into
2275 the char ** pointers provided by client code.
2276 Client code is responsible for calling free on the results. */
2278 void
2279 playback::context::
2280 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2282 JIT_LOG_SCOPE (get_logger ());
2284 int i;
2285 recording::requested_dump *d;
2286 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2288 dump_file_info *dfi;
2289 char *filename;
2290 char *content;
2292 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2293 if (!dfi)
2295 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2296 continue;
2299 filename = g->get_dumps ()->get_dump_file_name (dfi);
2300 content = read_dump_file (filename);
2301 *(d->m_out_ptr) = content;
2302 m_tempdir->add_temp_file (filename);
2306 /* Helper function for playback::context::extract_any_requested_dumps
2307 (itself for use in implementation of gcc_jit_context_enable_dump).
2309 Attempt to read the complete file at the given path, returning the
2310 bytes found there as a buffer.
2311 The caller is responsible for calling free on the result.
2312 Errors will be reported on the context, and lead to NULL being
2313 returned; an out-of-memory error will terminate the process. */
2315 char *
2316 playback::context::read_dump_file (const char *path)
2318 char *result = NULL;
2319 size_t total_sz = 0;
2320 char buf[4096];
2321 size_t sz;
2322 FILE *f_in;
2324 f_in = fopen (path, "r");
2325 if (!f_in)
2327 add_error (NULL, "unable to open %s for reading", path);
2328 return NULL;
2331 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2333 size_t old_total_sz = total_sz;
2334 total_sz += sz;
2335 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2336 memcpy (result + old_total_sz, buf, sz);
2339 if (!feof (f_in))
2341 add_error (NULL, "error reading from %s", path);
2342 free (result);
2343 fclose (f_in);
2344 return NULL;
2347 fclose (f_in);
2349 if (result)
2351 result[total_sz] = '\0';
2352 return result;
2354 else
2355 return xstrdup ("");
2358 /* Part of playback::context::compile ().
2360 We have a .s file; we want a .so file.
2361 We could reuse parts of gcc/gcc.c to do this.
2362 For now, just use the driver binary from the install, as
2363 named in gcc-driver-name.h
2364 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2366 void
2367 playback::context::
2368 convert_to_dso (const char *ctxt_progname)
2370 JIT_LOG_SCOPE (get_logger ());
2372 invoke_driver (ctxt_progname,
2373 m_tempdir->get_path_s_file (),
2374 m_tempdir->get_path_so_file (),
2375 TV_ASSEMBLE,
2376 true, /* bool shared, */
2377 true);/* bool run_linker */
2380 static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2382 void
2383 playback::context::
2384 invoke_driver (const char *ctxt_progname,
2385 const char *input_file,
2386 const char *output_file,
2387 timevar_id_t tv_id,
2388 bool shared,
2389 bool run_linker)
2391 JIT_LOG_SCOPE (get_logger ());
2393 bool embedded_driver
2394 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
2396 /* Currently this lumps together both assembling and linking into
2397 TV_ASSEMBLE. */
2398 auto_timevar assemble_timevar (get_timer (), tv_id);
2399 auto_argvec argvec;
2400 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2402 ADD_ARG (gcc_driver_name);
2404 add_multilib_driver_arguments (&argvec);
2406 if (shared)
2407 ADD_ARG ("-shared");
2409 if (!run_linker)
2410 ADD_ARG ("-c");
2412 ADD_ARG (input_file);
2413 ADD_ARG ("-o");
2414 ADD_ARG (output_file);
2416 /* Don't use the linker plugin.
2417 If running with just a "make" and not a "make install", then we'd
2418 run into
2419 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2420 libto_plugin is a .la at build time, with it becoming installed with
2421 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2422 time. */
2423 ADD_ARG ("-fno-use-linker-plugin");
2425 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2426 /* OS X's linker defaults to treating undefined symbols as errors.
2427 If the context has any imported functions or globals they will be
2428 undefined until the .so is dynamically-linked into the process.
2429 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2430 linker. */
2431 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2432 #endif
2434 if (0)
2435 ADD_ARG ("-v");
2437 #undef ADD_ARG
2439 /* pex_one's error-handling requires pname to be non-NULL. */
2440 gcc_assert (ctxt_progname);
2442 if (get_logger ())
2443 for (unsigned i = 0; i < argvec.length (); i++)
2444 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2446 if (embedded_driver)
2447 invoke_embedded_driver (&argvec);
2448 else
2449 invoke_external_driver (ctxt_progname, &argvec);
2452 void
2453 playback::context::
2454 invoke_embedded_driver (const vec <char *> *argvec)
2456 JIT_LOG_SCOPE (get_logger ());
2457 driver d (true, /* can_finalize */
2458 false); /* debug */
2459 int result = d.main (argvec->length (),
2460 const_cast <char **> (argvec->address ()));
2461 d.finalize ();
2462 if (result)
2463 add_error (NULL, "error invoking gcc driver");
2466 void
2467 playback::context::
2468 invoke_external_driver (const char *ctxt_progname,
2469 vec <char *> *argvec)
2471 JIT_LOG_SCOPE (get_logger ());
2472 const char *errmsg;
2473 int exit_status = 0;
2474 int err = 0;
2476 /* pex argv arrays are NULL-terminated. */
2477 argvec->safe_push (NULL);
2479 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2480 gcc_driver_name,
2481 const_cast <char *const *> (argvec->address ()),
2482 ctxt_progname, /* const char *pname */
2483 NULL, /* const char *outname */
2484 NULL, /* const char *errname */
2485 &exit_status, /* int *status */
2486 &err); /* int *err*/
2487 if (errmsg)
2489 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2490 return;
2493 /* pex_one can return a NULL errmsg when the executable wasn't
2494 found (or doesn't exist), so trap these cases also. */
2495 if (exit_status || err)
2497 add_error (NULL,
2498 "error invoking gcc driver: exit_status: %i err: %i",
2499 exit_status, err);
2500 add_error (NULL,
2501 "whilst attempting to run a driver named: %s",
2502 gcc_driver_name);
2503 add_error (NULL,
2504 "PATH was: %s",
2505 getenv ("PATH"));
2506 return;
2510 /* Extract the target-specific MULTILIB_DEFAULTS to
2511 multilib_defaults_raw for use by
2512 playback::context::add_multilib_driver_arguments (). */
2514 #ifndef MULTILIB_DEFAULTS
2515 #define MULTILIB_DEFAULTS { "" }
2516 #endif
2518 static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
2520 /* Helper function for playback::context::invoke_driver ().
2522 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2523 a driver binary. We need to pass in options to the shared driver
2524 to get the appropriate assembler/linker options for this multilib
2525 peer. */
2527 void
2528 playback::context::
2529 add_multilib_driver_arguments (vec <char *> *argvec)
2531 JIT_LOG_SCOPE (get_logger ());
2533 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2534 prepending each with a "-". */
2535 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
2536 if (multilib_defaults_raw[i][0])
2537 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
2540 /* Dynamically-link the built DSO file into this process, using dlopen.
2541 Wrap it up within a jit::result *, and return that.
2542 Return NULL if any errors occur, reporting them on this context. */
2544 result *
2545 playback::context::
2546 dlopen_built_dso ()
2548 JIT_LOG_SCOPE (get_logger ());
2549 auto_timevar load_timevar (get_timer (), TV_LOAD);
2550 void *handle = NULL;
2551 const char *error = NULL;
2552 result *result_obj = NULL;
2554 /* Clear any existing error. */
2555 dlerror ();
2557 handle = dlopen (m_tempdir->get_path_so_file (),
2558 RTLD_NOW | RTLD_LOCAL);
2559 if ((error = dlerror()) != NULL) {
2560 add_error (NULL, "%s", error);
2562 if (handle)
2564 /* We've successfully dlopened the result; create a
2565 jit::result object to wrap it.
2567 We're done with the tempdir for now, but if the user
2568 has requested debugging, the user's debugger might not
2569 be capable of dealing with the .so file being unlinked
2570 immediately, so keep it around until after the result
2571 is released. We do this by handing over ownership of
2572 the jit::tempdir to the result. See PR jit/64206. */
2573 tempdir *handover_tempdir;
2574 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2576 handover_tempdir = m_tempdir;
2577 m_tempdir = NULL;
2578 /* The tempdir will eventually be cleaned up in the
2579 jit::result's dtor. */
2580 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2581 " handing over tempdir to jit::result");
2583 else
2585 handover_tempdir = NULL;
2586 /* ... and retain ownership of m_tempdir so we clean it
2587 up it the playback::context's dtor. */
2588 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2589 " retaining ownership of tempdir");
2592 result_obj = new result (get_logger (), handle, handover_tempdir);
2594 else
2595 result_obj = NULL;
2597 return result_obj;
2600 /* Top-level hook for playing back a recording context.
2602 This plays back m_recording_ctxt, and, if no errors
2603 occurred builds statement lists for and then postprocesses
2604 every function in the result. */
2606 void
2607 playback::context::
2608 replay ()
2610 JIT_LOG_SCOPE (get_logger ());
2611 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2612 tree array_domain_type = build_index_type (size_int (200));
2613 m_char_array_type_node
2614 = build_array_type (char_type_node, array_domain_type);
2616 m_const_char_ptr
2617 = build_pointer_type (build_qualified_type (char_type_node,
2618 TYPE_QUAL_CONST));
2620 /* Replay the recorded events: */
2621 timevar_push (TV_JIT_REPLAY);
2623 m_recording_ctxt->replay_into (this);
2625 /* Clean away the temporary references from recording objects
2626 to playback objects. We have to do this now since the
2627 latter are GC-allocated, but the former don't mark these
2628 refs. Hence we must stop using them before the GC can run. */
2629 m_recording_ctxt->disassociate_from_playback ();
2631 /* The builtins_manager, if any, is associated with the recording::context
2632 and might be reused for future compiles on other playback::contexts,
2633 but its m_attributes array is not GTY-labeled and hence will become
2634 nonsense if the GC runs. Purge this state. */
2635 builtins_manager *bm = get_builtins_manager ();
2636 if (bm)
2637 bm->finish_playback ();
2639 timevar_pop (TV_JIT_REPLAY);
2641 if (!errors_occurred ())
2643 int i;
2644 function *func;
2646 /* No GC can happen yet; process the cached source locations. */
2647 handle_locations ();
2649 /* We've now created tree nodes for the stmts in the various blocks
2650 in each function, but we haven't built each function's single stmt
2651 list yet. Do so now. */
2652 FOR_EACH_VEC_ELT (m_functions, i, func)
2653 func->build_stmt_list ();
2655 /* No GC can have happened yet. */
2657 /* Postprocess the functions. This could trigger GC. */
2658 FOR_EACH_VEC_ELT (m_functions, i, func)
2660 gcc_assert (func);
2661 func->postprocess ();
2666 /* Dump the generated .s file to stderr. */
2668 void
2669 playback::context::
2670 dump_generated_code ()
2672 JIT_LOG_SCOPE (get_logger ());
2673 char buf[4096];
2674 size_t sz;
2675 FILE *f_in = fopen (get_path_s_file (), "r");
2676 if (!f_in)
2677 return;
2679 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2680 fwrite (buf, 1, sz, stderr);
2682 fclose (f_in);
2685 /* Get the supposed path of the notional "fake.c" file within the
2686 tempdir. This file doesn't exist, but the rest of the compiler
2687 needs a name. */
2689 const char *
2690 playback::context::
2691 get_path_c_file () const
2693 return m_tempdir->get_path_c_file ();
2696 /* Get the path of the assembler output file "fake.s" file within the
2697 tempdir. */
2699 const char *
2700 playback::context::
2701 get_path_s_file () const
2703 return m_tempdir->get_path_s_file ();
2706 /* Get the path of the DSO object file "fake.so" file within the
2707 tempdir. */
2709 const char *
2710 playback::context::
2711 get_path_so_file () const
2713 return m_tempdir->get_path_so_file ();
2716 /* qsort comparator for comparing pairs of playback::source_line *,
2717 ordering them by line number. */
2719 static int
2720 line_comparator (const void *lhs, const void *rhs)
2722 const playback::source_line *line_lhs = \
2723 *static_cast<const playback::source_line * const*> (lhs);
2724 const playback::source_line *line_rhs = \
2725 *static_cast<const playback::source_line * const*> (rhs);
2726 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2729 /* qsort comparator for comparing pairs of playback::location *,
2730 ordering them by column number. */
2732 static int
2733 location_comparator (const void *lhs, const void *rhs)
2735 const playback::location *loc_lhs = \
2736 *static_cast<const playback::location * const *> (lhs);
2737 const playback::location *loc_rhs = \
2738 *static_cast<const playback::location * const *> (rhs);
2739 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2742 /* Our API allows locations to be created in arbitrary orders, but the
2743 linemap API requires locations to be created in ascending order
2744 as if we were tokenizing files.
2746 This hook sorts all of the locations that have been created, and
2747 calls into the linemap API, creating linemap entries in sorted order
2748 for our locations. */
2750 void
2751 playback::context::
2752 handle_locations ()
2754 /* Create the source code locations, following the ordering rules
2755 imposed by the linemap API.
2757 line_table is a global. */
2758 JIT_LOG_SCOPE (get_logger ());
2759 int i;
2760 source_file *file;
2762 FOR_EACH_VEC_ELT (m_source_files, i, file)
2764 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2766 /* Sort lines by ascending line numbers. */
2767 file->m_source_lines.qsort (&line_comparator);
2769 int j;
2770 source_line *line;
2771 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2773 int k;
2774 location *loc;
2776 /* Sort locations in line by ascending column numbers. */
2777 line->m_locations.qsort (&location_comparator);
2779 /* Determine maximum column within this line. */
2780 gcc_assert (line->m_locations.length () > 0);
2781 location *final_column =
2782 line->m_locations[line->m_locations.length () - 1];
2783 int max_col = final_column->get_column_num ();
2785 linemap_line_start (line_table, line->get_line_num (), max_col);
2786 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2788 loc->m_srcloc = \
2789 linemap_position_for_column (line_table, loc->get_column_num ());
2793 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2796 /* line_table should now be populated; every playback::location should
2797 now have an m_srcloc. */
2799 /* Now assign them to tree nodes as appropriate. */
2800 std::pair<tree, location *> *cached_location;
2802 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2804 tree t = cached_location->first;
2805 source_location srcloc = cached_location->second->m_srcloc;
2807 /* This covers expressions: */
2808 if (CAN_HAVE_LOCATION_P (t))
2809 SET_EXPR_LOCATION (t, srcloc);
2810 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2811 DECL_SOURCE_LOCATION (t) = srcloc;
2812 else
2814 /* Don't know how to set location on this node. */
2819 /* We handle errors on a playback::context by adding them to the
2820 corresponding recording::context. */
2822 void
2823 playback::context::
2824 add_error (location *loc, const char *fmt, ...)
2826 va_list ap;
2827 va_start (ap, fmt);
2828 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2829 fmt, ap);
2830 va_end (ap);
2833 /* We handle errors on a playback::context by adding them to the
2834 corresponding recording::context. */
2836 void
2837 playback::context::
2838 add_error_va (location *loc, const char *fmt, va_list ap)
2840 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2841 fmt, ap);
2844 /* Report a diagnostic up to the jit context as an error,
2845 so that the compilation is treated as a failure.
2846 For now, any kind of diagnostic is treated as an error by the jit
2847 API. */
2849 void
2850 playback::context::
2851 add_diagnostic (struct diagnostic_context *diag_context,
2852 struct diagnostic_info *diagnostic)
2854 /* At this point the text has been formatted into the pretty-printer's
2855 output buffer. */
2856 pretty_printer *pp = diag_context->printer;
2857 const char *text = pp_formatted_text (pp);
2859 /* Get location information (if any) from the diagnostic.
2860 The recording::context::add_error[_va] methods require a
2861 recording::location. We can't lookup the playback::location
2862 from the file/line/column since any playback location instances
2863 may have been garbage-collected away by now, so instead we create
2864 another recording::location directly. */
2865 location_t gcc_loc = diagnostic_location (diagnostic);
2866 recording::location *rec_loc = NULL;
2867 if (gcc_loc)
2869 expanded_location exploc = expand_location (gcc_loc);
2870 if (exploc.file)
2871 rec_loc = m_recording_ctxt->new_location (exploc.file,
2872 exploc.line,
2873 exploc.column,
2874 false);
2877 m_recording_ctxt->add_error (rec_loc, "%s", text);
2878 pp_clear_output_area (pp);
2881 /* Dealing with the linemap API. */
2883 /* Construct a playback::location for a recording::location, if it
2884 doesn't exist already. */
2886 playback::location *
2887 playback::context::
2888 new_location (recording::location *rloc,
2889 const char *filename,
2890 int line,
2891 int column)
2893 /* Get the source_file for filename, creating if necessary. */
2894 source_file *src_file = get_source_file (filename);
2895 /* Likewise for the line within the file. */
2896 source_line *src_line = src_file->get_source_line (line);
2897 /* Likewise for the column within the line. */
2898 location *loc = src_line->get_location (rloc, column);
2899 return loc;
2902 /* Deferred setting of the location for a given tree, by adding the
2903 (tree, playback::location) pair to a list of deferred associations.
2904 We will actually set the location on the tree later on once
2905 the source_location for the playback::location exists. */
2907 void
2908 playback::context::
2909 set_tree_location (tree t, location *loc)
2911 gcc_assert (loc);
2912 m_cached_locations.safe_push (std::make_pair (t, loc));
2916 /* Construct a playback::source_file for the given source
2917 filename, if it doesn't exist already. */
2919 playback::source_file *
2920 playback::context::
2921 get_source_file (const char *filename)
2923 /* Locate the file.
2924 For simplicitly, this is currently a linear search.
2925 Replace with a hash if this shows up in the profile. */
2926 int i;
2927 source_file *file;
2928 tree ident_filename = get_identifier (filename);
2930 FOR_EACH_VEC_ELT (m_source_files, i, file)
2931 if (file->filename_as_tree () == ident_filename)
2932 return file;
2934 /* Not found. */
2935 file = new source_file (ident_filename);
2936 m_source_files.safe_push (file);
2937 return file;
2940 /* Constructor for gcc::jit::playback::source_file. */
2942 playback::source_file::source_file (tree filename) :
2943 m_source_lines (),
2944 m_filename (filename)
2948 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2949 GC-ed. */
2951 void
2952 playback::source_file::finalizer ()
2954 m_source_lines.release ();
2957 /* Construct a playback::source_line for the given line
2958 within this source file, if one doesn't exist already. */
2960 playback::source_line *
2961 playback::source_file::
2962 get_source_line (int line_num)
2964 /* Locate the line.
2965 For simplicitly, this is currently a linear search.
2966 Replace with a hash if this shows up in the profile. */
2967 int i;
2968 source_line *line;
2970 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2971 if (line->get_line_num () == line_num)
2972 return line;
2974 /* Not found. */
2975 line = new source_line (this, line_num);
2976 m_source_lines.safe_push (line);
2977 return line;
2980 /* Constructor for gcc::jit::playback::source_line. */
2982 playback::source_line::source_line (source_file *file, int line_num) :
2983 m_locations (),
2984 m_source_file (file),
2985 m_line_num (line_num)
2989 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2990 GC-ed. */
2992 void
2993 playback::source_line::finalizer ()
2995 m_locations.release ();
2998 /* Construct a playback::location for the given column
2999 within this line of a specific source file, if one doesn't exist
3000 already. */
3002 playback::location *
3003 playback::source_line::
3004 get_location (recording::location *rloc, int column_num)
3006 int i;
3007 location *loc;
3009 /* Another linear search that probably should be a hash table. */
3010 FOR_EACH_VEC_ELT (m_locations, i, loc)
3011 if (loc->get_column_num () == column_num)
3012 return loc;
3014 /* Not found. */
3015 loc = new location (rloc, this, column_num);
3016 m_locations.safe_push (loc);
3017 return loc;
3020 /* Constructor for gcc::jit::playback::location. */
3022 playback::location::location (recording::location *loc,
3023 source_line *line,
3024 int column_num) :
3025 m_srcloc (UNKNOWN_LOCATION),
3026 m_recording_loc (loc),
3027 m_line (line),
3028 m_column_num(column_num)
3032 /* The active gcc::jit::playback::context instance. This is a singleton,
3033 guarded by jit_mutex. */
3035 playback::context *active_playback_ctxt;
3037 } // namespace gcc::jit
3039 } // namespace gcc