* sv.po: Update.
[official-gcc.git] / gcc / jit / jit-playback.c
blob579230d3f98593886be5da83552e0f332f22adae
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"
41 #include <pthread.h>
43 #include "jit-playback.h"
44 #include "jit-result.h"
45 #include "jit-builtins.h"
46 #include "jit-tempdir.h"
49 /* gcc::jit::playback::context::build_cast uses the convert.h API,
50 which in turn requires the frontend to provide a "convert"
51 function, apparently as a fallback.
53 Hence we provide this dummy one, with the requirement that any casts
54 are handled before reaching this. */
55 extern tree convert (tree type, tree expr);
57 tree
58 convert (tree dst_type, tree expr)
60 gcc_assert (gcc::jit::active_playback_ctxt);
61 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
62 fprintf (stderr, "input expression:\n");
63 debug_tree (expr);
64 fprintf (stderr, "requested type:\n");
65 debug_tree (dst_type);
66 return error_mark_node;
69 namespace gcc {
70 namespace jit {
72 /**********************************************************************
73 Playback.
74 **********************************************************************/
76 /* The constructor for gcc::jit::playback::context. */
78 playback::context::context (recording::context *ctxt)
79 : log_user (ctxt->get_logger ()),
80 m_recording_ctxt (ctxt),
81 m_tempdir (NULL),
82 m_char_array_type_node (NULL),
83 m_const_char_ptr (NULL)
85 JIT_LOG_SCOPE (get_logger ());
86 m_functions.create (0);
87 m_globals.create (0);
88 m_source_files.create (0);
89 m_cached_locations.create (0);
92 /* The destructor for gcc::jit::playback::context. */
94 playback::context::~context ()
96 JIT_LOG_SCOPE (get_logger ());
98 /* Normally the playback::context is responsible for cleaning up the
99 tempdir (including "fake.so" within the filesystem).
101 In the normal case, clean it up now.
103 However m_tempdir can be NULL if the context has handed over
104 responsibility for the tempdir cleanup to the jit::result object, so
105 that the cleanup can be delayed (see PR jit/64206). If that's the
106 case this "delete NULL;" is a no-op. */
107 delete m_tempdir;
109 m_functions.release ();
112 /* A playback::context can reference GC-managed pointers. Mark them
113 ("by hand", rather than by gengtype).
115 This is called on the active playback context (if any) by the
116 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
118 void
119 playback::context::
120 gt_ggc_mx ()
122 int i;
123 function *func;
124 FOR_EACH_VEC_ELT (m_functions, i, func)
126 if (ggc_test_and_set_mark (func))
127 func->gt_ggc_mx ();
131 /* Given an enum gcc_jit_types value, get a "tree" type. */
133 static tree
134 get_tree_node_for_type (enum gcc_jit_types type_)
136 switch (type_)
138 case GCC_JIT_TYPE_VOID:
139 return void_type_node;
141 case GCC_JIT_TYPE_VOID_PTR:
142 return ptr_type_node;
144 case GCC_JIT_TYPE_BOOL:
145 return boolean_type_node;
147 case GCC_JIT_TYPE_CHAR:
148 return char_type_node;
149 case GCC_JIT_TYPE_SIGNED_CHAR:
150 return signed_char_type_node;
151 case GCC_JIT_TYPE_UNSIGNED_CHAR:
152 return unsigned_char_type_node;
154 case GCC_JIT_TYPE_SHORT:
155 return short_integer_type_node;
156 case GCC_JIT_TYPE_UNSIGNED_SHORT:
157 return short_unsigned_type_node;
159 case GCC_JIT_TYPE_CONST_CHAR_PTR:
161 tree const_char = build_qualified_type (char_type_node,
162 TYPE_QUAL_CONST);
163 return build_pointer_type (const_char);
166 case GCC_JIT_TYPE_INT:
167 return integer_type_node;
168 case GCC_JIT_TYPE_UNSIGNED_INT:
169 return unsigned_type_node;
171 case GCC_JIT_TYPE_LONG:
172 return long_integer_type_node;
173 case GCC_JIT_TYPE_UNSIGNED_LONG:
174 return long_unsigned_type_node;
176 case GCC_JIT_TYPE_LONG_LONG:
177 return long_long_integer_type_node;
178 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
179 return long_long_unsigned_type_node;
181 case GCC_JIT_TYPE_FLOAT:
182 return float_type_node;
183 case GCC_JIT_TYPE_DOUBLE:
184 return double_type_node;
185 case GCC_JIT_TYPE_LONG_DOUBLE:
186 return long_double_type_node;
188 case GCC_JIT_TYPE_SIZE_T:
189 return size_type_node;
191 case GCC_JIT_TYPE_FILE_PTR:
192 return fileptr_type_node;
194 case GCC_JIT_TYPE_COMPLEX_FLOAT:
195 return complex_float_type_node;
196 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
197 return complex_double_type_node;
198 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
199 return complex_long_double_type_node;
202 return NULL;
205 /* Construct a playback::type instance (wrapping a tree) for the given
206 enum value. */
208 playback::type *
209 playback::context::
210 get_type (enum gcc_jit_types type_)
212 tree type_node = get_tree_node_for_type (type_);
213 if (NULL == type_node)
215 add_error (NULL,
216 "unrecognized (enum gcc_jit_types) value: %i", type_);
217 return NULL;
220 return new type (type_node);
223 /* Construct a playback::type instance (wrapping a tree) for the given
224 array type. */
226 playback::type *
227 playback::context::
228 new_array_type (playback::location *loc,
229 playback::type *element_type,
230 int num_elements)
232 gcc_assert (element_type);
234 tree t = build_array_type_nelts (element_type->as_tree (),
235 num_elements);
236 layout_type (t);
238 if (loc)
239 set_tree_location (t, loc);
241 return new type (t);
244 /* Construct a playback::field instance (wrapping a tree). */
246 playback::field *
247 playback::context::
248 new_field (location *loc,
249 type *type,
250 const char *name)
252 gcc_assert (type);
253 gcc_assert (name);
255 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
256 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
257 get_identifier (name), type->as_tree ());
259 if (loc)
260 set_tree_location (decl, loc);
262 return new field (decl);
265 /* Construct a playback::compound_type instance (wrapping a tree). */
267 playback::compound_type *
268 playback::context::
269 new_compound_type (location *loc,
270 const char *name,
271 bool is_struct) /* else is union */
273 gcc_assert (name);
275 /* Compare with c/c-decl.c: start_struct. */
277 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
278 TYPE_NAME (t) = get_identifier (name);
279 TYPE_SIZE (t) = 0;
281 if (loc)
282 set_tree_location (t, loc);
284 return new compound_type (t);
287 void
288 playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
290 /* Compare with c/c-decl.c: finish_struct. */
291 tree t = as_tree ();
293 tree fieldlist = NULL;
294 for (unsigned i = 0; i < fields->length (); i++)
296 field *f = (*fields)[i];
297 DECL_CONTEXT (f->as_tree ()) = t;
298 fieldlist = chainon (f->as_tree (), fieldlist);
300 fieldlist = nreverse (fieldlist);
301 TYPE_FIELDS (t) = fieldlist;
303 layout_type (t);
306 /* Construct a playback::type instance (wrapping a tree) for a function
307 type. */
309 playback::type *
310 playback::context::
311 new_function_type (type *return_type,
312 const auto_vec<type *> *param_types,
313 int is_variadic)
315 int i;
316 type *param_type;
318 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
320 FOR_EACH_VEC_ELT (*param_types, i, param_type)
321 arg_types[i] = param_type->as_tree ();
323 tree fn_type;
324 if (is_variadic)
325 fn_type =
326 build_varargs_function_type_array (return_type->as_tree (),
327 param_types->length (),
328 arg_types);
329 else
330 fn_type = build_function_type_array (return_type->as_tree (),
331 param_types->length (),
332 arg_types);
333 free (arg_types);
335 return new type (fn_type);
338 /* Construct a playback::param instance (wrapping a tree). */
340 playback::param *
341 playback::context::
342 new_param (location *loc,
343 type *type,
344 const char *name)
346 gcc_assert (type);
347 gcc_assert (name);
348 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
349 get_identifier (name), type->as_tree ());
350 if (loc)
351 set_tree_location (inner, loc);
353 return new param (this, inner);
356 /* Construct a playback::function instance. */
358 playback::function *
359 playback::context::
360 new_function (location *loc,
361 enum gcc_jit_function_kind kind,
362 type *return_type,
363 const char *name,
364 const auto_vec<param *> *params,
365 int is_variadic,
366 enum built_in_function builtin_id)
368 int i;
369 param *param;
371 //can return_type be NULL?
372 gcc_assert (name);
374 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
375 FOR_EACH_VEC_ELT (*params, i, param)
376 arg_types[i] = TREE_TYPE (param->as_tree ());
378 tree fn_type;
379 if (is_variadic)
380 fn_type = build_varargs_function_type_array (return_type->as_tree (),
381 params->length (), arg_types);
382 else
383 fn_type = build_function_type_array (return_type->as_tree (),
384 params->length (), arg_types);
385 free (arg_types);
387 /* FIXME: this uses input_location: */
388 tree fndecl = build_fn_decl (name, fn_type);
390 if (loc)
391 set_tree_location (fndecl, loc);
393 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
394 NULL_TREE, return_type->as_tree ());
395 DECL_ARTIFICIAL (resdecl) = 1;
396 DECL_IGNORED_P (resdecl) = 1;
397 DECL_RESULT (fndecl) = resdecl;
399 if (builtin_id)
401 DECL_FUNCTION_CODE (fndecl) = builtin_id;
402 gcc_assert (loc == NULL);
403 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
405 DECL_BUILT_IN_CLASS (fndecl) =
406 builtins_manager::get_class (builtin_id);
407 set_builtin_decl (builtin_id, fndecl,
408 builtins_manager::implicit_p (builtin_id));
410 builtins_manager *bm = get_builtins_manager ();
411 tree attrs = bm->get_attrs_tree (builtin_id);
412 if (attrs)
413 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
414 else
415 decl_attributes (&fndecl, NULL_TREE, 0);
418 if (kind != GCC_JIT_FUNCTION_IMPORTED)
420 tree param_decl_list = NULL;
421 FOR_EACH_VEC_ELT (*params, i, param)
423 param_decl_list = chainon (param->as_tree (), param_decl_list);
426 /* The param list was created in reverse order; fix it: */
427 param_decl_list = nreverse (param_decl_list);
429 tree t;
430 for (t = param_decl_list; t; t = DECL_CHAIN (t))
432 DECL_CONTEXT (t) = fndecl;
433 DECL_ARG_TYPE (t) = TREE_TYPE (t);
436 /* Set it up on DECL_ARGUMENTS */
437 DECL_ARGUMENTS(fndecl) = param_decl_list;
440 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
442 DECL_DECLARED_INLINE_P (fndecl) = 1;
444 /* Add attribute "always_inline": */
445 DECL_ATTRIBUTES (fndecl) =
446 tree_cons (get_identifier ("always_inline"),
447 NULL,
448 DECL_ATTRIBUTES (fndecl));
451 function *func = new function (this, fndecl, kind);
452 m_functions.safe_push (func);
453 return func;
456 /* Construct a playback::lvalue instance (wrapping a tree). */
458 playback::lvalue *
459 playback::context::
460 new_global (location *loc,
461 enum gcc_jit_global_kind kind,
462 type *type,
463 const char *name)
465 gcc_assert (type);
466 gcc_assert (name);
467 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
468 get_identifier (name),
469 type->as_tree ());
470 TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
471 DECL_COMMON (inner) = 1;
472 switch (kind)
474 default:
475 gcc_unreachable ();
477 case GCC_JIT_GLOBAL_EXPORTED:
478 TREE_STATIC (inner) = 1;
479 break;
481 case GCC_JIT_GLOBAL_INTERNAL:
482 TREE_STATIC (inner) = 1;
483 break;
485 case GCC_JIT_GLOBAL_IMPORTED:
486 DECL_EXTERNAL (inner) = 1;
487 break;
490 if (loc)
491 set_tree_location (inner, loc);
493 varpool_node::get_create (inner);
495 varpool_node::finalize_decl (inner);
497 m_globals.safe_push (inner);
499 return new lvalue (this, inner);
502 /* Implementation of the various
503 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
504 methods.
505 Each of these constructs a playback::rvalue instance (wrapping a tree).
507 These specializations are required to be in the same namespace
508 as the template, hence we now have to enter the gcc::jit::playback
509 namespace. */
511 namespace playback
514 /* Specialization of making an rvalue from a const, for host <int>. */
516 template <>
517 rvalue *
518 context::
519 new_rvalue_from_const <int> (type *type,
520 int value)
522 // FIXME: type-checking, or coercion?
523 tree inner_type = type->as_tree ();
524 if (INTEGRAL_TYPE_P (inner_type))
526 tree inner = build_int_cst (inner_type, value);
527 return new rvalue (this, inner);
529 else
531 REAL_VALUE_TYPE real_value;
532 real_from_integer (&real_value, VOIDmode, value, SIGNED);
533 tree inner = build_real (inner_type, real_value);
534 return new rvalue (this, inner);
538 /* Specialization of making an rvalue from a const, for host <long>. */
540 template <>
541 rvalue *
542 context::
543 new_rvalue_from_const <long> (type *type,
544 long value)
546 // FIXME: type-checking, or coercion?
547 tree inner_type = type->as_tree ();
548 if (INTEGRAL_TYPE_P (inner_type))
550 tree inner = build_int_cst (inner_type, value);
551 return new rvalue (this, inner);
553 else
555 REAL_VALUE_TYPE real_value;
556 real_from_integer (&real_value, VOIDmode, value, SIGNED);
557 tree inner = build_real (inner_type, real_value);
558 return new rvalue (this, inner);
562 /* Specialization of making an rvalue from a const, for host <double>. */
564 template <>
565 rvalue *
566 context::
567 new_rvalue_from_const <double> (type *type,
568 double value)
570 // FIXME: type-checking, or coercion?
571 tree inner_type = type->as_tree ();
573 /* We have a "double", we want a REAL_VALUE_TYPE.
575 real.c:real_from_target appears to require the representation to be
576 split into 32-bit values, and then sent as an pair of host long
577 ints. */
578 REAL_VALUE_TYPE real_value;
579 union
581 double as_double;
582 uint32_t as_uint32s[2];
583 } u;
584 u.as_double = value;
585 long int as_long_ints[2];
586 as_long_ints[0] = u.as_uint32s[0];
587 as_long_ints[1] = u.as_uint32s[1];
588 real_from_target (&real_value, as_long_ints, DFmode);
589 tree inner = build_real (inner_type, real_value);
590 return new rvalue (this, inner);
593 /* Specialization of making an rvalue from a const, for host <void *>. */
595 template <>
596 rvalue *
597 context::
598 new_rvalue_from_const <void *> (type *type,
599 void *value)
601 tree inner_type = type->as_tree ();
602 /* FIXME: how to ensure we have a wide enough type? */
603 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
604 return new rvalue (this, inner);
607 /* We're done implementing the specializations of
608 gcc::jit::playback::context::new_rvalue_from_const <T>
609 so we can exit the gcc::jit::playback namespace. */
611 } // namespace playback
613 /* Construct a playback::rvalue instance (wrapping a tree). */
615 playback::rvalue *
616 playback::context::
617 new_string_literal (const char *value)
619 tree t_str = build_string (strlen (value), value);
620 gcc_assert (m_char_array_type_node);
621 TREE_TYPE (t_str) = m_char_array_type_node;
623 /* Convert to (const char*), loosely based on
624 c/c-typeck.c: array_to_pointer_conversion,
625 by taking address of start of string. */
626 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
628 return new rvalue (this, t_addr);
631 /* Coerce a tree expression into a boolean tree expression. */
633 tree
634 playback::context::
635 as_truth_value (tree expr, location *loc)
637 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
638 tree typed_zero = fold_build1 (CONVERT_EXPR,
639 TREE_TYPE (expr),
640 integer_zero_node);
641 if (loc)
642 set_tree_location (typed_zero, loc);
644 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
645 if (loc)
646 set_tree_location (expr, loc);
648 return expr;
651 /* Construct a playback::rvalue instance (wrapping a tree) for a
652 unary op. */
654 playback::rvalue *
655 playback::context::
656 new_unary_op (location *loc,
657 enum gcc_jit_unary_op op,
658 type *result_type,
659 rvalue *a)
661 // FIXME: type-checking, or coercion?
662 enum tree_code inner_op;
664 gcc_assert (result_type);
665 gcc_assert (a);
667 tree node = a->as_tree ();
668 tree inner_result = NULL;
670 switch (op)
672 default:
673 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
674 return NULL;
676 case GCC_JIT_UNARY_OP_MINUS:
677 inner_op = NEGATE_EXPR;
678 break;
680 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
681 inner_op = BIT_NOT_EXPR;
682 break;
684 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
685 node = as_truth_value (node, loc);
686 inner_result = invert_truthvalue (node);
687 if (loc)
688 set_tree_location (inner_result, loc);
689 return new rvalue (this, inner_result);
691 case GCC_JIT_UNARY_OP_ABS:
692 inner_op = ABS_EXPR;
693 break;
696 inner_result = build1 (inner_op,
697 result_type->as_tree (),
698 node);
699 if (loc)
700 set_tree_location (inner_result, loc);
702 return new rvalue (this, inner_result);
705 /* Construct a playback::rvalue instance (wrapping a tree) for a
706 binary op. */
708 playback::rvalue *
709 playback::context::
710 new_binary_op (location *loc,
711 enum gcc_jit_binary_op op,
712 type *result_type,
713 rvalue *a, rvalue *b)
715 // FIXME: type-checking, or coercion?
716 enum tree_code inner_op;
718 gcc_assert (result_type);
719 gcc_assert (a);
720 gcc_assert (b);
722 tree node_a = a->as_tree ();
723 tree node_b = b->as_tree ();
725 switch (op)
727 default:
728 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
729 return NULL;
731 case GCC_JIT_BINARY_OP_PLUS:
732 inner_op = PLUS_EXPR;
733 break;
735 case GCC_JIT_BINARY_OP_MINUS:
736 inner_op = MINUS_EXPR;
737 break;
739 case GCC_JIT_BINARY_OP_MULT:
740 inner_op = MULT_EXPR;
741 break;
743 case GCC_JIT_BINARY_OP_DIVIDE:
744 if (FLOAT_TYPE_P (result_type->as_tree ()))
745 /* Floating-point division: */
746 inner_op = RDIV_EXPR;
747 else
748 /* Truncating to zero: */
749 inner_op = TRUNC_DIV_EXPR;
750 break;
752 case GCC_JIT_BINARY_OP_MODULO:
753 inner_op = TRUNC_MOD_EXPR;
754 break;
756 case GCC_JIT_BINARY_OP_BITWISE_AND:
757 inner_op = BIT_AND_EXPR;
758 break;
760 case GCC_JIT_BINARY_OP_BITWISE_XOR:
761 inner_op = BIT_XOR_EXPR;
762 break;
764 case GCC_JIT_BINARY_OP_BITWISE_OR:
765 inner_op = BIT_IOR_EXPR;
766 break;
768 case GCC_JIT_BINARY_OP_LOGICAL_AND:
769 node_a = as_truth_value (node_a, loc);
770 node_b = as_truth_value (node_b, loc);
771 inner_op = TRUTH_ANDIF_EXPR;
772 break;
774 case GCC_JIT_BINARY_OP_LOGICAL_OR:
775 node_a = as_truth_value (node_a, loc);
776 node_b = as_truth_value (node_b, loc);
777 inner_op = TRUTH_ORIF_EXPR;
778 break;
780 case GCC_JIT_BINARY_OP_LSHIFT:
781 inner_op = LSHIFT_EXPR;
782 break;
784 case GCC_JIT_BINARY_OP_RSHIFT:
785 inner_op = RSHIFT_EXPR;
786 break;
789 tree inner_expr = build2 (inner_op,
790 result_type->as_tree (),
791 node_a,
792 node_b);
793 if (loc)
794 set_tree_location (inner_expr, loc);
796 return new rvalue (this, inner_expr);
799 /* Construct a playback::rvalue instance (wrapping a tree) for a
800 comparison. */
802 playback::rvalue *
803 playback::context::
804 new_comparison (location *loc,
805 enum gcc_jit_comparison op,
806 rvalue *a, rvalue *b)
808 // FIXME: type-checking, or coercion?
809 enum tree_code inner_op;
811 gcc_assert (a);
812 gcc_assert (b);
814 switch (op)
816 default:
817 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
818 return NULL;
820 case GCC_JIT_COMPARISON_EQ:
821 inner_op = EQ_EXPR;
822 break;
823 case GCC_JIT_COMPARISON_NE:
824 inner_op = NE_EXPR;
825 break;
826 case GCC_JIT_COMPARISON_LT:
827 inner_op = LT_EXPR;
828 break;
829 case GCC_JIT_COMPARISON_LE:
830 inner_op = LE_EXPR;
831 break;
832 case GCC_JIT_COMPARISON_GT:
833 inner_op = GT_EXPR;
834 break;
835 case GCC_JIT_COMPARISON_GE:
836 inner_op = GE_EXPR;
837 break;
840 tree inner_expr = build2 (inner_op,
841 boolean_type_node,
842 a->as_tree (),
843 b->as_tree ());
844 if (loc)
845 set_tree_location (inner_expr, loc);
846 return new rvalue (this, inner_expr);
849 /* Construct a playback::rvalue instance (wrapping a tree) for a
850 function call. */
852 playback::rvalue *
853 playback::context::
854 build_call (location *loc,
855 tree fn_ptr,
856 const auto_vec<rvalue *> *args)
858 vec<tree, va_gc> *tree_args;
859 vec_alloc (tree_args, args->length ());
860 for (unsigned i = 0; i < args->length (); i++)
861 tree_args->quick_push ((*args)[i]->as_tree ());
863 if (loc)
864 set_tree_location (fn_ptr, loc);
866 tree fn = TREE_TYPE (fn_ptr);
867 tree fn_type = TREE_TYPE (fn);
868 tree return_type = TREE_TYPE (fn_type);
870 return new rvalue (this,
871 build_call_vec (return_type,
872 fn_ptr, tree_args));
874 /* see c-typeck.c: build_function_call
875 which calls build_function_call_vec
877 which does lots of checking, then:
878 result = build_call_array_loc (loc, TREE_TYPE (fntype),
879 function, nargs, argarray);
880 which is in tree.c
881 (see also build_call_vec)
885 /* Construct a playback::rvalue instance (wrapping a tree) for a
886 call to a specific function. */
888 playback::rvalue *
889 playback::context::
890 new_call (location *loc,
891 function *func,
892 const auto_vec<rvalue *> *args)
894 tree fndecl;
896 gcc_assert (func);
898 fndecl = func->as_fndecl ();
900 tree fntype = TREE_TYPE (fndecl);
902 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
904 return build_call (loc, fn, args);
907 /* Construct a playback::rvalue instance (wrapping a tree) for a
908 call through a function pointer. */
910 playback::rvalue *
911 playback::context::
912 new_call_through_ptr (location *loc,
913 rvalue *fn_ptr,
914 const auto_vec<rvalue *> *args)
916 gcc_assert (fn_ptr);
917 tree t_fn_ptr = fn_ptr->as_tree ();
919 return build_call (loc, t_fn_ptr, args);
922 /* Construct a tree for a cast. */
924 tree
925 playback::context::build_cast (playback::location *loc,
926 playback::rvalue *expr,
927 playback::type *type_)
929 /* For comparison, see:
930 - c/c-typeck.c:build_c_cast
931 - c/c-convert.c: convert
932 - convert.h
934 Only some kinds of cast are currently supported here. */
935 tree t_expr = expr->as_tree ();
936 tree t_dst_type = type_->as_tree ();
937 tree t_ret = NULL;
938 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
939 if (t_ret)
940 return t_ret;
941 enum tree_code dst_code = TREE_CODE (t_dst_type);
942 switch (dst_code)
944 case INTEGER_TYPE:
945 case ENUMERAL_TYPE:
946 t_ret = convert_to_integer (t_dst_type, t_expr);
947 goto maybe_fold;
949 case BOOLEAN_TYPE:
950 /* Compare with c_objc_common_truthvalue_conversion and
951 c_common_truthvalue_conversion. */
952 /* For now, convert to: (t_expr != 0) */
953 t_ret = build2 (NE_EXPR, t_dst_type,
954 t_expr,
955 build_int_cst (TREE_TYPE (t_expr), 0));
956 goto maybe_fold;
958 case REAL_TYPE:
959 t_ret = convert_to_real (t_dst_type, t_expr);
960 goto maybe_fold;
962 case POINTER_TYPE:
963 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
964 goto maybe_fold;
966 default:
967 add_error (loc, "couldn't handle cast during playback");
968 fprintf (stderr, "input expression:\n");
969 debug_tree (t_expr);
970 fprintf (stderr, "requested type:\n");
971 debug_tree (t_dst_type);
972 return error_mark_node;
974 maybe_fold:
975 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
976 t_ret = fold (t_ret);
977 return t_ret;
981 /* Construct a playback::rvalue instance (wrapping a tree) for a
982 cast. */
984 playback::rvalue *
985 playback::context::
986 new_cast (playback::location *loc,
987 playback::rvalue *expr,
988 playback::type *type_)
991 tree t_cast = build_cast (loc, expr, type_);
992 if (loc)
993 set_tree_location (t_cast, loc);
994 return new rvalue (this, t_cast);
997 /* Construct a playback::lvalue instance (wrapping a tree) for an
998 array access. */
1000 playback::lvalue *
1001 playback::context::
1002 new_array_access (location *loc,
1003 rvalue *ptr,
1004 rvalue *index)
1006 gcc_assert (ptr);
1007 gcc_assert (index);
1009 /* For comparison, see:
1010 c/c-typeck.c: build_array_ref
1011 c-family/c-common.c: pointer_int_sum
1013 tree t_ptr = ptr->as_tree ();
1014 tree t_index = index->as_tree ();
1015 tree t_type_ptr = TREE_TYPE (t_ptr);
1016 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1018 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1020 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1021 NULL_TREE, NULL_TREE);
1022 if (loc)
1023 set_tree_location (t_result, loc);
1024 return new lvalue (this, t_result);
1026 else
1028 /* Convert index to an offset in bytes. */
1029 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1030 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1031 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
1033 /* Locate (ptr + offset). */
1034 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1036 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1037 if (loc)
1039 set_tree_location (t_sizeof, loc);
1040 set_tree_location (t_offset, loc);
1041 set_tree_location (t_address, loc);
1042 set_tree_location (t_indirection, loc);
1045 return new lvalue (this, t_indirection);
1049 /* Construct a tree for a field access. */
1051 tree
1052 playback::context::
1053 new_field_access (location *loc,
1054 tree datum,
1055 field *field)
1057 gcc_assert (datum);
1058 gcc_assert (field);
1060 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1061 build_component_ref. */
1062 tree type = TREE_TYPE (datum);
1063 gcc_assert (type);
1064 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1066 tree t_field = field->as_tree ();
1067 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1068 t_field, NULL_TREE);
1069 if (loc)
1070 set_tree_location (ref, loc);
1071 return ref;
1074 /* Construct a tree for a dereference. */
1076 tree
1077 playback::context::
1078 new_dereference (tree ptr,
1079 location *loc)
1081 gcc_assert (ptr);
1083 tree type = TREE_TYPE (TREE_TYPE(ptr));
1084 tree datum = build1 (INDIRECT_REF, type, ptr);
1085 if (loc)
1086 set_tree_location (datum, loc);
1087 return datum;
1090 /* Construct a playback::lvalue instance (wrapping a tree) for a
1091 field access. */
1093 playback::lvalue *
1094 playback::lvalue::
1095 access_field (location *loc,
1096 field *field)
1098 tree datum = as_tree ();
1099 tree ref = get_context ()->new_field_access (loc, datum, field);
1100 if (!ref)
1101 return NULL;
1102 return new lvalue (get_context (), ref);
1105 /* Construct a playback::rvalue instance (wrapping a tree) for a
1106 field access. */
1108 playback::rvalue *
1109 playback::rvalue::
1110 access_field (location *loc,
1111 field *field)
1113 tree datum = as_tree ();
1114 tree ref = get_context ()->new_field_access (loc, datum, field);
1115 if (!ref)
1116 return NULL;
1117 return new rvalue (get_context (), ref);
1120 /* Construct a playback::lvalue instance (wrapping a tree) for a
1121 dereferenced field access. */
1123 playback::lvalue *
1124 playback::rvalue::
1125 dereference_field (location *loc,
1126 field *field)
1128 tree ptr = as_tree ();
1129 tree datum = get_context ()->new_dereference (ptr, loc);
1130 if (!datum)
1131 return NULL;
1132 tree ref = get_context ()->new_field_access (loc, datum, field);
1133 if (!ref)
1134 return NULL;
1135 return new lvalue (get_context (), ref);
1138 /* Construct a playback::lvalue instance (wrapping a tree) for a
1139 dereference. */
1141 playback::lvalue *
1142 playback::rvalue::
1143 dereference (location *loc)
1145 tree ptr = as_tree ();
1146 tree datum = get_context ()->new_dereference (ptr, loc);
1147 return new lvalue (get_context (), datum);
1150 /* Mark EXP saying that we need to be able to take the
1151 address of it; it should not be allocated in a register.
1152 Compare with e.g. c/c-typeck.c: c_mark_addressable. */
1154 static void
1155 jit_mark_addressable (tree exp)
1157 tree x = exp;
1159 while (1)
1160 switch (TREE_CODE (x))
1162 case COMPONENT_REF:
1163 /* (we don't yet support bitfields) */
1164 /* fallthrough */
1165 case ADDR_EXPR:
1166 case ARRAY_REF:
1167 case REALPART_EXPR:
1168 case IMAGPART_EXPR:
1169 x = TREE_OPERAND (x, 0);
1170 break;
1172 case COMPOUND_LITERAL_EXPR:
1173 case CONSTRUCTOR:
1174 TREE_ADDRESSABLE (x) = 1;
1175 return;
1177 case VAR_DECL:
1178 case CONST_DECL:
1179 case PARM_DECL:
1180 case RESULT_DECL:
1181 /* (we don't have a concept of a "register" declaration) */
1182 /* fallthrough */
1183 case FUNCTION_DECL:
1184 TREE_ADDRESSABLE (x) = 1;
1185 /* fallthrough */
1186 default:
1187 return;
1191 /* Construct a playback::rvalue instance (wrapping a tree) for an
1192 address-lookup. */
1194 playback::rvalue *
1195 playback::lvalue::
1196 get_address (location *loc)
1198 tree t_lvalue = as_tree ();
1199 tree t_thistype = TREE_TYPE (t_lvalue);
1200 tree t_ptrtype = build_pointer_type (t_thistype);
1201 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1202 if (loc)
1203 get_context ()->set_tree_location (ptr, loc);
1204 jit_mark_addressable (t_lvalue);
1205 return new rvalue (get_context (), ptr);
1208 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1209 Provide this finalization hook for calling then they are collected,
1210 which calls the finalizer vfunc. This allows them to call "release"
1211 on any vec<> within them. */
1213 static void
1214 wrapper_finalizer (void *ptr)
1216 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1217 wrapper->finalizer ();
1220 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1221 allocate them using ggc_internal_cleared_alloc. */
1223 void *
1224 playback::wrapper::
1225 operator new (size_t sz)
1227 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1231 /* Constructor for gcc:jit::playback::function. */
1233 playback::function::
1234 function (context *ctxt,
1235 tree fndecl,
1236 enum gcc_jit_function_kind kind)
1237 : m_ctxt(ctxt),
1238 m_inner_fndecl (fndecl),
1239 m_inner_bind_expr (NULL),
1240 m_kind (kind)
1242 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1244 /* Create a BIND_EXPR, and within it, a statement list. */
1245 m_stmt_list = alloc_stmt_list ();
1246 m_stmt_iter = tsi_start (m_stmt_list);
1247 m_inner_block = make_node (BLOCK);
1248 m_inner_bind_expr =
1249 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1251 else
1253 m_inner_block = NULL;
1254 m_stmt_list = NULL;
1258 /* Hand-written GC-marking hook for playback functions. */
1260 void
1261 playback::function::
1262 gt_ggc_mx ()
1264 gt_ggc_m_9tree_node (m_inner_fndecl);
1265 gt_ggc_m_9tree_node (m_inner_bind_expr);
1266 gt_ggc_m_9tree_node (m_stmt_list);
1267 gt_ggc_m_9tree_node (m_inner_block);
1270 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1271 GC-ed. */
1273 void
1274 playback::function::finalizer ()
1276 m_blocks.release ();
1279 /* Get the return type of a playback function, in tree form. */
1281 tree
1282 playback::function::
1283 get_return_type_as_tree () const
1285 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1288 /* Construct a new local within this playback::function. */
1290 playback::lvalue *
1291 playback::function::
1292 new_local (location *loc,
1293 type *type,
1294 const char *name)
1296 gcc_assert (type);
1297 gcc_assert (name);
1298 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1299 get_identifier (name),
1300 type->as_tree ());
1301 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1303 /* Prepend to BIND_EXPR_VARS: */
1304 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1305 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1307 if (loc)
1308 set_tree_location (inner, loc);
1309 return new lvalue (m_ctxt, inner);
1312 /* Construct a new block within this playback::function. */
1314 playback::block *
1315 playback::function::
1316 new_block (const char *name)
1318 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1320 block *result = new playback::block (this, name);
1321 m_blocks.safe_push (result);
1322 return result;
1325 /* Build a statement list for the function as a whole out of the
1326 lists of statements for the individual blocks, building labels
1327 for each block. */
1329 void
1330 playback::function::
1331 build_stmt_list ()
1333 int i;
1334 block *b;
1336 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1338 FOR_EACH_VEC_ELT (m_blocks, i, b)
1340 int j;
1341 tree stmt;
1343 b->m_label_expr = build1 (LABEL_EXPR,
1344 void_type_node,
1345 b->as_label_decl ());
1346 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1348 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1349 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1353 /* Finish compiling the given function, potentially running the
1354 garbage-collector.
1355 The function will have a statement list by now.
1356 Amongst other things, this gimplifies the statement list,
1357 and calls cgraph_node::finalize_function on the function. */
1359 void
1360 playback::function::
1361 postprocess ()
1363 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1365 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1366 debug_tree (m_stmt_list);
1368 /* Do we need this to force cgraphunit.c to output the function? */
1369 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1371 DECL_EXTERNAL (m_inner_fndecl) = 0;
1372 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1375 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1376 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1378 DECL_EXTERNAL (m_inner_fndecl) = 0;
1379 TREE_PUBLIC (m_inner_fndecl) = 0;
1382 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1384 /* Seem to need this in gimple-low.c: */
1385 gcc_assert (m_inner_block);
1386 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1388 /* how to add to function? the following appears to be how to
1389 set the body of a m_inner_fndecl: */
1390 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1392 /* Ensure that locals appear in the debuginfo. */
1393 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1395 //debug_tree (m_inner_fndecl);
1397 /* Convert to gimple: */
1398 //printf("about to gimplify_function_tree\n");
1399 gimplify_function_tree (m_inner_fndecl);
1400 //printf("finished gimplify_function_tree\n");
1402 current_function_decl = m_inner_fndecl;
1403 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1404 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1405 //debug_tree (m_inner_fndecl);
1407 //printf("about to add to cgraph\n");
1408 /* Add to cgraph: */
1409 cgraph_node::finalize_function (m_inner_fndecl, false);
1410 /* This can trigger a collection, so we need to have all of
1411 the funcs as roots. */
1413 current_function_decl = NULL;
1417 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1418 GC-ed. */
1420 void
1421 playback::block::finalizer ()
1423 m_stmts.release ();
1426 /* Add an eval of the rvalue to the function's statement list. */
1428 void
1429 playback::block::
1430 add_eval (location *loc,
1431 rvalue *rvalue)
1433 gcc_assert (rvalue);
1435 if (loc)
1436 set_tree_location (rvalue->as_tree (), loc);
1438 add_stmt (rvalue->as_tree ());
1441 /* Add an assignment to the function's statement list. */
1443 void
1444 playback::block::
1445 add_assignment (location *loc,
1446 lvalue *lvalue,
1447 rvalue *rvalue)
1449 gcc_assert (lvalue);
1450 gcc_assert (rvalue);
1452 tree t_lvalue = lvalue->as_tree ();
1453 tree t_rvalue = rvalue->as_tree ();
1454 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1456 t_rvalue = build1 (CONVERT_EXPR,
1457 TREE_TYPE (t_lvalue),
1458 t_rvalue);
1459 if (loc)
1460 set_tree_location (t_rvalue, loc);
1463 tree stmt =
1464 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1465 t_lvalue, t_rvalue);
1466 if (loc)
1467 set_tree_location (stmt, loc);
1468 add_stmt (stmt);
1471 /* Add a comment to the function's statement list.
1472 For now this is done by adding a dummy label. */
1474 void
1475 playback::block::
1476 add_comment (location *loc,
1477 const char *text)
1479 /* Wrap the text in C-style comment delimiters. */
1480 size_t sz =
1481 (3 /* opening delim */
1482 + strlen (text)
1483 + 3 /* closing delim */
1484 + 1 /* terminator */);
1485 char *wrapped = (char *)ggc_internal_alloc (sz);
1486 snprintf (wrapped, sz, "/* %s */", text);
1488 /* For now we simply implement this by adding a dummy label with a name
1489 containing the given text. */
1490 tree identifier = get_identifier (wrapped);
1491 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1492 identifier, void_type_node);
1493 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1495 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1496 if (loc)
1497 set_tree_location (label_expr, loc);
1498 add_stmt (label_expr);
1501 /* Add a conditional jump statement to the function's statement list. */
1503 void
1504 playback::block::
1505 add_conditional (location *loc,
1506 rvalue *boolval,
1507 block *on_true,
1508 block *on_false)
1510 gcc_assert (boolval);
1511 gcc_assert (on_true);
1512 gcc_assert (on_false);
1514 /* COND_EXPR wants statement lists for the true/false operands, but we
1515 want labels.
1516 Shim it by creating jumps to the labels */
1517 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1518 on_true->as_label_decl ());
1519 if (loc)
1520 set_tree_location (true_jump, loc);
1522 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1523 on_false->as_label_decl ());
1524 if (loc)
1525 set_tree_location (false_jump, loc);
1527 tree stmt =
1528 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1529 true_jump, false_jump);
1530 if (loc)
1531 set_tree_location (stmt, loc);
1532 add_stmt (stmt);
1535 /* Add an unconditional jump statement to the function's statement list. */
1537 void
1538 playback::block::
1539 add_jump (location *loc,
1540 block *target)
1542 gcc_assert (target);
1544 // see c_finish_loop
1545 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1546 //add_stmt (top);
1548 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1549 TREE_USED (target->as_label_decl ()) = 1;
1550 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1551 if (loc)
1552 set_tree_location (stmt, loc);
1553 add_stmt (stmt);
1556 from c-typeck.c:
1557 tree
1558 c_finish_goto_label (location_t loc, tree label)
1560 tree decl = lookup_label_for_goto (loc, label);
1561 if (!decl)
1562 return NULL_TREE;
1563 TREE_USED (decl) = 1;
1565 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1566 SET_EXPR_LOCATION (t, loc);
1567 return add_stmt (t);
1574 /* Add a return statement to the function's statement list. */
1576 void
1577 playback::block::
1578 add_return (location *loc,
1579 rvalue *rvalue)
1581 tree modify_retval = NULL;
1582 tree return_type = m_func->get_return_type_as_tree ();
1583 if (rvalue)
1585 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1586 tree t_rvalue = rvalue->as_tree ();
1587 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1588 t_rvalue = build1 (CONVERT_EXPR,
1589 TREE_TYPE (t_lvalue),
1590 t_rvalue);
1591 modify_retval = build2 (MODIFY_EXPR, return_type,
1592 t_lvalue, t_rvalue);
1593 if (loc)
1594 set_tree_location (modify_retval, loc);
1596 tree return_stmt = build1 (RETURN_EXPR, return_type,
1597 modify_retval);
1598 if (loc)
1599 set_tree_location (return_stmt, loc);
1601 add_stmt (return_stmt);
1604 /* Helper function for playback::block::add_switch.
1605 Construct a case label for the given range, followed by a goto stmt
1606 to the given block, appending them to stmt list *ptr_t_switch_body. */
1608 static void
1609 add_case (tree *ptr_t_switch_body,
1610 tree t_low_value,
1611 tree t_high_value,
1612 playback::block *dest_block)
1614 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
1615 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
1617 tree t_case_label =
1618 build_case_label (t_low_value, t_high_value, t_label);
1619 append_to_statement_list (t_case_label, ptr_t_switch_body);
1621 tree t_goto_stmt =
1622 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
1623 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
1626 /* Add a switch statement to the function's statement list.
1628 My initial attempt at implementing this constructed a TREE_VEC
1629 of the cases and set it as SWITCH_LABELS (switch_expr). However,
1630 gimplify.c:gimplify_switch_expr is set up to deal with SWITCH_BODY, and
1631 doesn't have any logic for gimplifying SWITCH_LABELS.
1633 Hence we create a switch body, and populate it with case labels, each
1634 followed by a goto to the desired block. */
1636 void
1637 playback::block::
1638 add_switch (location *loc,
1639 rvalue *expr,
1640 block *default_block,
1641 const auto_vec <case_> *cases)
1643 /* Compare with:
1644 - c/c-typeck.c: c_start_case
1645 - c-family/c-common.c:c_add_case_label
1646 - java/expr.c:expand_java_switch and expand_java_add_case
1647 We've already rejected overlaps and duplicates in
1648 libgccjit.c:case_range_validator::validate. */
1650 tree t_expr = expr->as_tree ();
1651 tree t_type = TREE_TYPE (t_expr);
1653 tree t_switch_body = alloc_stmt_list ();
1655 int i;
1656 case_ *c;
1657 FOR_EACH_VEC_ELT (*cases, i, c)
1659 tree t_low_value = c->m_min_value->as_tree ();
1660 tree t_high_value = c->m_max_value->as_tree ();
1661 add_case (&t_switch_body,
1662 t_low_value,
1663 t_high_value,
1664 c->m_dest_block);
1666 /* Default label. */
1667 add_case (&t_switch_body,
1668 NULL_TREE, NULL_TREE,
1669 default_block);
1671 tree switch_stmt = build3 (SWITCH_EXPR, t_type, t_expr,
1672 t_switch_body, NULL_TREE);
1673 if (loc)
1674 set_tree_location (switch_stmt, loc);
1675 add_stmt (switch_stmt);
1678 /* Constructor for gcc::jit::playback::block. */
1680 playback::block::
1681 block (function *func,
1682 const char *name)
1683 : m_func (func),
1684 m_stmts ()
1686 tree identifier;
1688 gcc_assert (func);
1689 // name can be NULL
1690 if (name)
1691 identifier = get_identifier (name);
1692 else
1693 identifier = NULL;
1694 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1695 identifier, void_type_node);
1696 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1697 m_label_expr = NULL;
1700 /* A subclass of auto_vec <char *> that frees all of its elements on
1701 deletion. */
1703 class auto_argvec : public auto_vec <char *>
1705 public:
1706 ~auto_argvec ();
1709 /* auto_argvec's dtor, freeing all contained strings, automatically
1710 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1712 auto_argvec::~auto_argvec ()
1714 int i;
1715 char *str;
1716 FOR_EACH_VEC_ELT (*this, i, str)
1717 free (str);
1720 /* Compile a playback::context:
1722 - Use the context's options to cconstruct command-line options, and
1723 call into the rest of GCC (toplev::main).
1724 - Assuming it succeeds, we have a .s file.
1725 - We then run the "postprocess" vfunc:
1727 (A) In-memory compile ("gcc_jit_context_compile")
1729 For an in-memory compile we have the playback::compile_to_memory
1730 subclass; "postprocess" will convert the .s file to a .so DSO,
1731 and load it in memory (via dlopen), wrapping the result up as
1732 a jit::result and returning it.
1734 (B) Compile to file ("gcc_jit_context_compile_to_file")
1736 When compiling to a file, we have the playback::compile_to_file
1737 subclass; "postprocess" will either copy the .s file to the
1738 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1739 the driver to convert it as necessary, copying the result. */
1741 void
1742 playback::context::
1743 compile ()
1745 JIT_LOG_SCOPE (get_logger ());
1747 const char *ctxt_progname;
1749 int keep_intermediates =
1750 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
1752 m_tempdir = new tempdir (get_logger (), keep_intermediates);
1753 if (!m_tempdir->create ())
1754 return;
1756 /* Call into the rest of gcc.
1757 For now, we have to assemble command-line options to pass into
1758 toplev::main, so that they can be parsed. */
1760 /* Pass in user-provided program name as argv0, if any, so that it
1761 makes it into GCC's "progname" global, used in various diagnostics. */
1762 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1764 if (!ctxt_progname)
1765 ctxt_progname = "libgccjit.so";
1767 auto_vec <recording::requested_dump> requested_dumps;
1768 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1770 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1771 acquire_mutex ();
1773 auto_argvec fake_args;
1774 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
1775 if (errors_occurred ())
1777 release_mutex ();
1778 return;
1781 /* This runs the compiler. */
1782 toplev toplev (get_timer (), /* external_timer */
1783 false); /* init_signals */
1784 enter_scope ("toplev::main");
1785 if (get_logger ())
1786 for (unsigned i = 0; i < fake_args.length (); i++)
1787 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
1788 toplev.main (fake_args.length (),
1789 const_cast <char **> (fake_args.address ()));
1790 exit_scope ("toplev::main");
1792 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1793 need to do it between toplev::main (which creates the dump manager)
1794 and toplev::finalize (which deletes it). */
1795 extract_any_requested_dumps (&requested_dumps);
1797 /* Clean up the compiler. */
1798 enter_scope ("toplev::finalize");
1799 toplev.finalize ();
1800 exit_scope ("toplev::finalize");
1802 /* Ideally we would release the jit mutex here, but we can't yet since
1803 followup activities use timevars, which are global state. */
1805 if (errors_occurred ())
1807 release_mutex ();
1808 return;
1811 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1812 dump_generated_code ();
1814 /* We now have a .s file.
1816 Run any postprocessing steps. This will either convert the .s file to
1817 a .so DSO, and load it in memory (playback::compile_to_memory), or
1818 convert the .s file to the requested output format, and copy it to a
1819 given file (playback::compile_to_file). */
1820 postprocess (ctxt_progname);
1822 release_mutex ();
1825 /* Implementation of class gcc::jit::playback::compile_to_memory,
1826 a subclass of gcc::jit::playback::context. */
1828 /* playback::compile_to_memory's trivial constructor. */
1830 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
1831 playback::context (ctxt),
1832 m_result (NULL)
1834 JIT_LOG_SCOPE (get_logger ());
1837 /* Implementation of the playback::context::process vfunc for compiling
1838 to memory.
1840 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1841 wrapping the result up as a jit::result and returning it. */
1843 void
1844 playback::compile_to_memory::postprocess (const char *ctxt_progname)
1846 JIT_LOG_SCOPE (get_logger ());
1847 convert_to_dso (ctxt_progname);
1848 if (errors_occurred ())
1849 return;
1850 m_result = dlopen_built_dso ();
1853 /* Implementation of class gcc::jit::playback::compile_to_file,
1854 a subclass of gcc::jit::playback::context. */
1856 /* playback::compile_to_file's trivial constructor. */
1858 playback::compile_to_file::compile_to_file (recording::context *ctxt,
1859 enum gcc_jit_output_kind output_kind,
1860 const char *output_path) :
1861 playback::context (ctxt),
1862 m_output_kind (output_kind),
1863 m_output_path (output_path)
1865 JIT_LOG_SCOPE (get_logger ());
1868 /* Implementation of the playback::context::process vfunc for compiling
1869 to a file.
1871 Either copy the .s file to the given destination (for
1872 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1873 as necessary, copying the result. */
1875 void
1876 playback::compile_to_file::postprocess (const char *ctxt_progname)
1878 JIT_LOG_SCOPE (get_logger ());
1880 /* The driver takes different actions based on the filename, so
1881 we provide a filename with an appropriate suffix for the
1882 output kind, and then copy it up to the user-provided path,
1883 rather than directly compiling it to the requested output path. */
1885 switch (m_output_kind)
1887 default:
1888 gcc_unreachable ();
1890 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
1891 copy_file (get_tempdir ()->get_path_s_file (),
1892 m_output_path);
1893 /* The .s file is automatically unlinked by tempdir::~tempdir. */
1894 break;
1896 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
1898 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
1899 "/fake.o",
1900 NULL);
1901 invoke_driver (ctxt_progname,
1902 get_tempdir ()->get_path_s_file (),
1903 tmp_o_path,
1904 TV_ASSEMBLE,
1905 false, /* bool shared, */
1906 false);/* bool run_linker */
1907 if (!errors_occurred ())
1909 copy_file (tmp_o_path,
1910 m_output_path);
1911 get_tempdir ()->add_temp_file (tmp_o_path);
1913 else
1914 free (tmp_o_path);
1916 break;
1918 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
1919 invoke_driver (ctxt_progname,
1920 get_tempdir ()->get_path_s_file (),
1921 get_tempdir ()->get_path_so_file (),
1922 TV_ASSEMBLE,
1923 true, /* bool shared, */
1924 true);/* bool run_linker */
1925 if (!errors_occurred ())
1926 copy_file (get_tempdir ()->get_path_so_file (),
1927 m_output_path);
1928 /* The .so file is automatically unlinked by tempdir::~tempdir. */
1929 break;
1931 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
1933 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
1934 "/fake.exe",
1935 NULL);
1936 invoke_driver (ctxt_progname,
1937 get_tempdir ()->get_path_s_file (),
1938 tmp_exe_path,
1939 TV_ASSEMBLE,
1940 false, /* bool shared, */
1941 true);/* bool run_linker */
1942 if (!errors_occurred ())
1944 copy_file (tmp_exe_path,
1945 m_output_path);
1946 get_tempdir ()->add_temp_file (tmp_exe_path);
1948 else
1949 free (tmp_exe_path);
1951 break;
1957 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
1958 the "executable" bits).
1960 Any errors that occur are reported on the context and hence count as
1961 a failure of the compile.
1963 We can't in general hardlink or use "rename" from the tempdir since
1964 it might be on a different filesystem to the destination. For example,
1965 I get EXDEV: "Invalid cross-device link". */
1967 void
1968 playback::compile_to_file::copy_file (const char *src_path,
1969 const char *dst_path)
1971 JIT_LOG_SCOPE (get_logger ());
1972 if (get_logger ())
1974 get_logger ()->log ("src_path: %s", src_path);
1975 get_logger ()->log ("dst_path: %s", dst_path);
1978 FILE *f_in = NULL;
1979 FILE *f_out = NULL;
1980 size_t total_sz_in = 0;
1981 size_t total_sz_out = 0;
1982 char buf[4096];
1983 size_t sz_in;
1984 struct stat stat_buf;
1986 f_in = fopen (src_path, "rb");
1987 if (!f_in)
1989 add_error (NULL,
1990 "unable to open %s for reading: %s",
1991 src_path,
1992 xstrerror (errno));
1993 return;
1996 /* Use stat on the filedescriptor to get the mode,
1997 so that we can copy it over (in particular, the
1998 "executable" bits). */
1999 if (-1 == fstat (fileno (f_in), &stat_buf))
2001 add_error (NULL,
2002 "unable to fstat %s: %s",
2003 src_path,
2004 xstrerror (errno));
2005 fclose (f_in);
2006 return;
2009 f_out = fopen (dst_path, "wb");
2010 if (!f_out)
2012 add_error (NULL,
2013 "unable to open %s for writing: %s",
2014 dst_path,
2015 xstrerror (errno));
2016 fclose (f_in);
2017 return;
2020 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2022 total_sz_in += sz_in;
2023 size_t sz_out_remaining = sz_in;
2024 size_t sz_out_so_far = 0;
2025 while (sz_out_remaining)
2027 size_t sz_out = fwrite (buf + sz_out_so_far,
2029 sz_out_remaining,
2030 f_out);
2031 gcc_assert (sz_out <= sz_out_remaining);
2032 if (!sz_out)
2034 add_error (NULL,
2035 "error writing to %s: %s",
2036 dst_path,
2037 xstrerror (errno));
2038 fclose (f_in);
2039 fclose (f_out);
2040 return;
2042 total_sz_out += sz_out;
2043 sz_out_so_far += sz_out;
2044 sz_out_remaining -= sz_out;
2046 gcc_assert (sz_out_so_far == sz_in);
2049 if (!feof (f_in))
2050 add_error (NULL,
2051 "error reading from %s: %s",
2052 src_path,
2053 xstrerror (errno));
2055 fclose (f_in);
2057 gcc_assert (total_sz_in == total_sz_out);
2058 if (get_logger ())
2059 get_logger ()->log ("total bytes copied: %ld", total_sz_out);
2061 /* Set the permissions of the copy to those of the original file,
2062 in particular the "executable" bits. */
2063 if (-1 == fchmod (fileno (f_out), stat_buf.st_mode))
2064 add_error (NULL,
2065 "error setting mode of %s: %s",
2066 dst_path,
2067 xstrerror (errno));
2069 fclose (f_out);
2072 /* Helper functions for gcc::jit::playback::context::compile. */
2074 /* This mutex guards gcc::jit::recording::context::compile, so that only
2075 one thread can be accessing the bulk of GCC's state at once. */
2077 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2079 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2081 void
2082 playback::context::acquire_mutex ()
2084 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2086 /* Acquire the big GCC mutex. */
2087 JIT_LOG_SCOPE (get_logger ());
2088 pthread_mutex_lock (&jit_mutex);
2089 gcc_assert (NULL == active_playback_ctxt);
2090 active_playback_ctxt = this;
2093 /* Release jit_mutex and clear the active playback ctxt. */
2095 void
2096 playback::context::release_mutex ()
2098 /* Release the big GCC mutex. */
2099 JIT_LOG_SCOPE (get_logger ());
2100 gcc_assert (active_playback_ctxt == this);
2101 active_playback_ctxt = NULL;
2102 pthread_mutex_unlock (&jit_mutex);
2105 /* Callback used by gcc::jit::playback::context::make_fake_args when
2106 invoking driver_get_configure_time_options.
2107 Populate a vec <char * > with the configure-time options. */
2109 static void
2110 append_arg_from_driver (const char *option, void *user_data)
2112 gcc_assert (option);
2113 gcc_assert (user_data);
2114 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2115 argvec->safe_push (concat ("-", option, NULL));
2118 /* Build a fake argv for toplev::main from the options set
2119 by the user on the context . */
2121 void
2122 playback::context::
2123 make_fake_args (vec <char *> *argvec,
2124 const char *ctxt_progname,
2125 vec <recording::requested_dump> *requested_dumps)
2127 JIT_LOG_SCOPE (get_logger ());
2129 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2130 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2132 ADD_ARG (ctxt_progname);
2133 ADD_ARG (get_path_c_file ());
2134 ADD_ARG ("-fPIC");
2136 /* Handle int options: */
2137 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2139 default:
2140 add_error (NULL,
2141 "unrecognized optimization level: %i",
2142 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2143 return;
2145 case 0:
2146 ADD_ARG ("-O0");
2147 break;
2149 case 1:
2150 ADD_ARG ("-O1");
2151 break;
2153 case 2:
2154 ADD_ARG ("-O2");
2155 break;
2157 case 3:
2158 ADD_ARG ("-O3");
2159 break;
2161 /* What about -Os? */
2163 /* Handle bool options: */
2164 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2165 ADD_ARG ("-g");
2167 /* Suppress timing (and other) info. */
2168 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2170 ADD_ARG ("-quiet");
2171 quiet_flag = 1;
2174 /* Aggressively garbage-collect, to shake out bugs: */
2175 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2177 ADD_ARG ("--param");
2178 ADD_ARG ("ggc-min-expand=0");
2179 ADD_ARG ("--param");
2180 ADD_ARG ("ggc-min-heapsize=0");
2183 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2185 ADD_ARG ("-fdump-tree-all");
2186 ADD_ARG ("-fdump-rtl-all");
2187 ADD_ARG ("-fdump-ipa-all");
2190 /* Add "-fdump-" options for any calls to
2191 gcc_jit_context_enable_dump. */
2193 int i;
2194 recording::requested_dump *d;
2195 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2197 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2198 ADD_ARG_TAKE_OWNERSHIP (arg);
2202 /* PR jit/64810: Add any target-specific default options
2203 from OPTION_DEFAULT_SPECS, normally provided by the driver
2204 in the non-jit case.
2206 The target-specific code can define OPTION_DEFAULT_SPECS:
2207 default command options in the form of spec macros for the
2208 driver to expand ().
2210 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2211 if not overriden, injects the defaults as extra arguments to
2212 cc1 etc.
2213 For the jit case, we need to add these arguments here. The
2214 input format (using the specs language) means that we have to run
2215 part of the driver code here (driver_get_configure_time_options).
2217 To avoid running the spec-expansion code every time, we just do
2218 it the first time (via a function-static flag), saving the result
2219 into a function-static vec.
2220 This flag and vec are global state (i.e. per-process).
2221 They are guarded by the jit mutex. */
2223 static bool have_configure_time_options = false;
2224 static vec <char *> configure_time_options;
2226 if (have_configure_time_options)
2227 log ("reusing cached configure-time options");
2228 else
2230 have_configure_time_options = true;
2231 log ("getting configure-time options from driver");
2232 driver_get_configure_time_options (append_arg_from_driver,
2233 &configure_time_options);
2236 int i;
2237 char *opt;
2239 if (get_logger ())
2240 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2241 log ("configure_time_options[%i]: %s", i, opt);
2243 /* configure_time_options should now contain the expanded options
2244 from OPTION_DEFAULT_SPECS (if any). */
2245 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2247 gcc_assert (opt);
2248 gcc_assert (opt[0] == '-');
2249 ADD_ARG (opt);
2253 if (get_timer ())
2254 ADD_ARG ("-ftime-report");
2256 /* Add any user-provided extra options, starting with any from
2257 parent contexts. */
2258 m_recording_ctxt->append_command_line_options (argvec);
2260 #undef ADD_ARG
2261 #undef ADD_ARG_TAKE_OWNERSHIP
2264 /* The second half of the implementation of gcc_jit_context_enable_dump.
2265 Iterate through the requested dumps, reading the underlying files
2266 into heap-allocated buffers, writing pointers to the buffers into
2267 the char ** pointers provided by client code.
2268 Client code is responsible for calling free on the results. */
2270 void
2271 playback::context::
2272 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2274 JIT_LOG_SCOPE (get_logger ());
2276 int i;
2277 recording::requested_dump *d;
2278 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2280 dump_file_info *dfi;
2281 char *filename;
2282 char *content;
2284 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2285 if (!dfi)
2287 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2288 continue;
2291 filename = g->get_dumps ()->get_dump_file_name (dfi);
2292 content = read_dump_file (filename);
2293 *(d->m_out_ptr) = content;
2294 m_tempdir->add_temp_file (filename);
2298 /* Helper function for playback::context::extract_any_requested_dumps
2299 (itself for use in implementation of gcc_jit_context_enable_dump).
2301 Attempt to read the complete file at the given path, returning the
2302 bytes found there as a buffer.
2303 The caller is responsible for calling free on the result.
2304 Errors will be reported on the context, and lead to NULL being
2305 returned; an out-of-memory error will terminate the process. */
2307 char *
2308 playback::context::read_dump_file (const char *path)
2310 char *result = NULL;
2311 size_t total_sz = 0;
2312 char buf[4096];
2313 size_t sz;
2314 FILE *f_in;
2316 f_in = fopen (path, "r");
2317 if (!f_in)
2319 add_error (NULL, "unable to open %s for reading", path);
2320 return NULL;
2323 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2325 size_t old_total_sz = total_sz;
2326 total_sz += sz;
2327 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2328 memcpy (result + old_total_sz, buf, sz);
2331 if (!feof (f_in))
2333 add_error (NULL, "error reading from %s", path);
2334 free (result);
2335 fclose (f_in);
2336 return NULL;
2339 fclose (f_in);
2341 if (result)
2343 result[total_sz] = '\0';
2344 return result;
2346 else
2347 return xstrdup ("");
2350 /* Part of playback::context::compile ().
2352 We have a .s file; we want a .so file.
2353 We could reuse parts of gcc/gcc.c to do this.
2354 For now, just use the driver binary from the install, as
2355 named in gcc-driver-name.h
2356 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2358 void
2359 playback::context::
2360 convert_to_dso (const char *ctxt_progname)
2362 JIT_LOG_SCOPE (get_logger ());
2364 invoke_driver (ctxt_progname,
2365 m_tempdir->get_path_s_file (),
2366 m_tempdir->get_path_so_file (),
2367 TV_ASSEMBLE,
2368 true, /* bool shared, */
2369 true);/* bool run_linker */
2372 static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2374 void
2375 playback::context::
2376 invoke_driver (const char *ctxt_progname,
2377 const char *input_file,
2378 const char *output_file,
2379 timevar_id_t tv_id,
2380 bool shared,
2381 bool run_linker)
2383 JIT_LOG_SCOPE (get_logger ());
2385 bool embedded_driver
2386 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
2388 /* Currently this lumps together both assembling and linking into
2389 TV_ASSEMBLE. */
2390 auto_timevar assemble_timevar (get_timer (), tv_id);
2391 auto_argvec argvec;
2392 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2394 ADD_ARG (gcc_driver_name);
2396 add_multilib_driver_arguments (&argvec);
2398 if (shared)
2399 ADD_ARG ("-shared");
2401 if (!run_linker)
2402 ADD_ARG ("-c");
2404 ADD_ARG (input_file);
2405 ADD_ARG ("-o");
2406 ADD_ARG (output_file);
2408 /* Don't use the linker plugin.
2409 If running with just a "make" and not a "make install", then we'd
2410 run into
2411 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2412 libto_plugin is a .la at build time, with it becoming installed with
2413 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2414 time. */
2415 ADD_ARG ("-fno-use-linker-plugin");
2417 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2418 /* OS X's linker defaults to treating undefined symbols as errors.
2419 If the context has any imported functions or globals they will be
2420 undefined until the .so is dynamically-linked into the process.
2421 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2422 linker. */
2423 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2424 #endif
2426 if (0)
2427 ADD_ARG ("-v");
2429 #undef ADD_ARG
2431 /* pex_one's error-handling requires pname to be non-NULL. */
2432 gcc_assert (ctxt_progname);
2434 if (get_logger ())
2435 for (unsigned i = 0; i < argvec.length (); i++)
2436 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2438 if (embedded_driver)
2439 invoke_embedded_driver (&argvec);
2440 else
2441 invoke_external_driver (ctxt_progname, &argvec);
2444 void
2445 playback::context::
2446 invoke_embedded_driver (const vec <char *> *argvec)
2448 JIT_LOG_SCOPE (get_logger ());
2449 driver d (true, /* can_finalize */
2450 false); /* debug */
2451 int result = d.main (argvec->length (),
2452 const_cast <char **> (argvec->address ()));
2453 d.finalize ();
2454 if (result)
2455 add_error (NULL, "error invoking gcc driver");
2458 void
2459 playback::context::
2460 invoke_external_driver (const char *ctxt_progname,
2461 vec <char *> *argvec)
2463 JIT_LOG_SCOPE (get_logger ());
2464 const char *errmsg;
2465 int exit_status = 0;
2466 int err = 0;
2468 /* pex argv arrays are NULL-terminated. */
2469 argvec->safe_push (NULL);
2471 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2472 gcc_driver_name,
2473 const_cast <char *const *> (argvec->address ()),
2474 ctxt_progname, /* const char *pname */
2475 NULL, /* const char *outname */
2476 NULL, /* const char *errname */
2477 &exit_status, /* int *status */
2478 &err); /* int *err*/
2479 if (errmsg)
2481 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2482 return;
2485 /* pex_one can return a NULL errmsg when the executable wasn't
2486 found (or doesn't exist), so trap these cases also. */
2487 if (exit_status || err)
2489 add_error (NULL,
2490 "error invoking gcc driver: exit_status: %i err: %i",
2491 exit_status, err);
2492 add_error (NULL,
2493 "whilst attempting to run a driver named: %s",
2494 gcc_driver_name);
2495 add_error (NULL,
2496 "PATH was: %s",
2497 getenv ("PATH"));
2498 return;
2502 /* Extract the target-specific MULTILIB_DEFAULTS to
2503 multilib_defaults_raw for use by
2504 playback::context::add_multilib_driver_arguments (). */
2506 #ifndef MULTILIB_DEFAULTS
2507 #define MULTILIB_DEFAULTS { "" }
2508 #endif
2510 static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
2512 /* Helper function for playback::context::invoke_driver ().
2514 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2515 a driver binary. We need to pass in options to the shared driver
2516 to get the appropriate assembler/linker options for this multilib
2517 peer. */
2519 void
2520 playback::context::
2521 add_multilib_driver_arguments (vec <char *> *argvec)
2523 JIT_LOG_SCOPE (get_logger ());
2525 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2526 prepending each with a "-". */
2527 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
2528 if (multilib_defaults_raw[i][0])
2529 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
2532 /* Dynamically-link the built DSO file into this process, using dlopen.
2533 Wrap it up within a jit::result *, and return that.
2534 Return NULL if any errors occur, reporting them on this context. */
2536 result *
2537 playback::context::
2538 dlopen_built_dso ()
2540 JIT_LOG_SCOPE (get_logger ());
2541 auto_timevar load_timevar (get_timer (), TV_LOAD);
2542 void *handle = NULL;
2543 const char *error = NULL;
2544 result *result_obj = NULL;
2546 /* Clear any existing error. */
2547 dlerror ();
2549 handle = dlopen (m_tempdir->get_path_so_file (),
2550 RTLD_NOW | RTLD_LOCAL);
2551 if ((error = dlerror()) != NULL) {
2552 add_error (NULL, "%s", error);
2554 if (handle)
2556 /* We've successfully dlopened the result; create a
2557 jit::result object to wrap it.
2559 We're done with the tempdir for now, but if the user
2560 has requested debugging, the user's debugger might not
2561 be capable of dealing with the .so file being unlinked
2562 immediately, so keep it around until after the result
2563 is released. We do this by handing over ownership of
2564 the jit::tempdir to the result. See PR jit/64206. */
2565 tempdir *handover_tempdir;
2566 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2568 handover_tempdir = m_tempdir;
2569 m_tempdir = NULL;
2570 /* The tempdir will eventually be cleaned up in the
2571 jit::result's dtor. */
2572 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2573 " handing over tempdir to jit::result");
2575 else
2577 handover_tempdir = NULL;
2578 /* ... and retain ownership of m_tempdir so we clean it
2579 up it the playback::context's dtor. */
2580 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2581 " retaining ownership of tempdir");
2584 result_obj = new result (get_logger (), handle, handover_tempdir);
2586 else
2587 result_obj = NULL;
2589 return result_obj;
2592 /* Top-level hook for playing back a recording context.
2594 This plays back m_recording_ctxt, and, if no errors
2595 occurred builds statement lists for and then postprocesses
2596 every function in the result. */
2598 void
2599 playback::context::
2600 replay ()
2602 JIT_LOG_SCOPE (get_logger ());
2603 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2604 tree array_domain_type = build_index_type (size_int (200));
2605 m_char_array_type_node
2606 = build_array_type (char_type_node, array_domain_type);
2608 m_const_char_ptr
2609 = build_pointer_type (build_qualified_type (char_type_node,
2610 TYPE_QUAL_CONST));
2612 /* Replay the recorded events: */
2613 timevar_push (TV_JIT_REPLAY);
2615 m_recording_ctxt->replay_into (this);
2617 /* Clean away the temporary references from recording objects
2618 to playback objects. We have to do this now since the
2619 latter are GC-allocated, but the former don't mark these
2620 refs. Hence we must stop using them before the GC can run. */
2621 m_recording_ctxt->disassociate_from_playback ();
2623 /* The builtins_manager, if any, is associated with the recording::context
2624 and might be reused for future compiles on other playback::contexts,
2625 but its m_attributes array is not GTY-labeled and hence will become
2626 nonsense if the GC runs. Purge this state. */
2627 builtins_manager *bm = get_builtins_manager ();
2628 if (bm)
2629 bm->finish_playback ();
2631 timevar_pop (TV_JIT_REPLAY);
2633 if (!errors_occurred ())
2635 int i;
2636 function *func;
2638 /* No GC can happen yet; process the cached source locations. */
2639 handle_locations ();
2641 /* We've now created tree nodes for the stmts in the various blocks
2642 in each function, but we haven't built each function's single stmt
2643 list yet. Do so now. */
2644 FOR_EACH_VEC_ELT (m_functions, i, func)
2645 func->build_stmt_list ();
2647 /* No GC can have happened yet. */
2649 /* Postprocess the functions. This could trigger GC. */
2650 FOR_EACH_VEC_ELT (m_functions, i, func)
2652 gcc_assert (func);
2653 func->postprocess ();
2658 /* Dump the generated .s file to stderr. */
2660 void
2661 playback::context::
2662 dump_generated_code ()
2664 JIT_LOG_SCOPE (get_logger ());
2665 char buf[4096];
2666 size_t sz;
2667 FILE *f_in = fopen (get_path_s_file (), "r");
2668 if (!f_in)
2669 return;
2671 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2672 fwrite (buf, 1, sz, stderr);
2674 fclose (f_in);
2677 /* Get the supposed path of the notional "fake.c" file within the
2678 tempdir. This file doesn't exist, but the rest of the compiler
2679 needs a name. */
2681 const char *
2682 playback::context::
2683 get_path_c_file () const
2685 return m_tempdir->get_path_c_file ();
2688 /* Get the path of the assembler output file "fake.s" file within the
2689 tempdir. */
2691 const char *
2692 playback::context::
2693 get_path_s_file () const
2695 return m_tempdir->get_path_s_file ();
2698 /* Get the path of the DSO object file "fake.so" file within the
2699 tempdir. */
2701 const char *
2702 playback::context::
2703 get_path_so_file () const
2705 return m_tempdir->get_path_so_file ();
2708 /* qsort comparator for comparing pairs of playback::source_line *,
2709 ordering them by line number. */
2711 static int
2712 line_comparator (const void *lhs, const void *rhs)
2714 const playback::source_line *line_lhs = \
2715 *static_cast<const playback::source_line * const*> (lhs);
2716 const playback::source_line *line_rhs = \
2717 *static_cast<const playback::source_line * const*> (rhs);
2718 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2721 /* qsort comparator for comparing pairs of playback::location *,
2722 ordering them by column number. */
2724 static int
2725 location_comparator (const void *lhs, const void *rhs)
2727 const playback::location *loc_lhs = \
2728 *static_cast<const playback::location * const *> (lhs);
2729 const playback::location *loc_rhs = \
2730 *static_cast<const playback::location * const *> (rhs);
2731 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2734 /* Our API allows locations to be created in arbitrary orders, but the
2735 linemap API requires locations to be created in ascending order
2736 as if we were tokenizing files.
2738 This hook sorts all of the locations that have been created, and
2739 calls into the linemap API, creating linemap entries in sorted order
2740 for our locations. */
2742 void
2743 playback::context::
2744 handle_locations ()
2746 /* Create the source code locations, following the ordering rules
2747 imposed by the linemap API.
2749 line_table is a global. */
2750 JIT_LOG_SCOPE (get_logger ());
2751 int i;
2752 source_file *file;
2754 FOR_EACH_VEC_ELT (m_source_files, i, file)
2756 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2758 /* Sort lines by ascending line numbers. */
2759 file->m_source_lines.qsort (&line_comparator);
2761 int j;
2762 source_line *line;
2763 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2765 int k;
2766 location *loc;
2768 /* Sort locations in line by ascending column numbers. */
2769 line->m_locations.qsort (&location_comparator);
2771 /* Determine maximum column within this line. */
2772 gcc_assert (line->m_locations.length () > 0);
2773 location *final_column =
2774 line->m_locations[line->m_locations.length () - 1];
2775 int max_col = final_column->get_column_num ();
2777 linemap_line_start (line_table, line->get_line_num (), max_col);
2778 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2780 loc->m_srcloc = \
2781 linemap_position_for_column (line_table, loc->get_column_num ());
2785 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2788 /* line_table should now be populated; every playback::location should
2789 now have an m_srcloc. */
2791 /* Now assign them to tree nodes as appropriate. */
2792 std::pair<tree, location *> *cached_location;
2794 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2796 tree t = cached_location->first;
2797 source_location srcloc = cached_location->second->m_srcloc;
2799 /* This covers expressions: */
2800 if (CAN_HAVE_LOCATION_P (t))
2801 SET_EXPR_LOCATION (t, srcloc);
2802 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2803 DECL_SOURCE_LOCATION (t) = srcloc;
2804 else
2806 /* Don't know how to set location on this node. */
2811 /* We handle errors on a playback::context by adding them to the
2812 corresponding recording::context. */
2814 void
2815 playback::context::
2816 add_error (location *loc, const char *fmt, ...)
2818 va_list ap;
2819 va_start (ap, fmt);
2820 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2821 fmt, ap);
2822 va_end (ap);
2825 /* We handle errors on a playback::context by adding them to the
2826 corresponding recording::context. */
2828 void
2829 playback::context::
2830 add_error_va (location *loc, const char *fmt, va_list ap)
2832 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2833 fmt, ap);
2836 /* Dealing with the linemap API. */
2838 /* Construct a playback::location for a recording::location, if it
2839 doesn't exist already. */
2841 playback::location *
2842 playback::context::
2843 new_location (recording::location *rloc,
2844 const char *filename,
2845 int line,
2846 int column)
2848 /* Get the source_file for filename, creating if necessary. */
2849 source_file *src_file = get_source_file (filename);
2850 /* Likewise for the line within the file. */
2851 source_line *src_line = src_file->get_source_line (line);
2852 /* Likewise for the column within the line. */
2853 location *loc = src_line->get_location (rloc, column);
2854 return loc;
2857 /* Deferred setting of the location for a given tree, by adding the
2858 (tree, playback::location) pair to a list of deferred associations.
2859 We will actually set the location on the tree later on once
2860 the source_location for the playback::location exists. */
2862 void
2863 playback::context::
2864 set_tree_location (tree t, location *loc)
2866 gcc_assert (loc);
2867 m_cached_locations.safe_push (std::make_pair (t, loc));
2871 /* Construct a playback::source_file for the given source
2872 filename, if it doesn't exist already. */
2874 playback::source_file *
2875 playback::context::
2876 get_source_file (const char *filename)
2878 /* Locate the file.
2879 For simplicitly, this is currently a linear search.
2880 Replace with a hash if this shows up in the profile. */
2881 int i;
2882 source_file *file;
2883 tree ident_filename = get_identifier (filename);
2885 FOR_EACH_VEC_ELT (m_source_files, i, file)
2886 if (file->filename_as_tree () == ident_filename)
2887 return file;
2889 /* Not found. */
2890 file = new source_file (ident_filename);
2891 m_source_files.safe_push (file);
2892 return file;
2895 /* Constructor for gcc::jit::playback::source_file. */
2897 playback::source_file::source_file (tree filename) :
2898 m_source_lines (),
2899 m_filename (filename)
2903 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2904 GC-ed. */
2906 void
2907 playback::source_file::finalizer ()
2909 m_source_lines.release ();
2912 /* Construct a playback::source_line for the given line
2913 within this source file, if one doesn't exist already. */
2915 playback::source_line *
2916 playback::source_file::
2917 get_source_line (int line_num)
2919 /* Locate the line.
2920 For simplicitly, this is currently a linear search.
2921 Replace with a hash if this shows up in the profile. */
2922 int i;
2923 source_line *line;
2925 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2926 if (line->get_line_num () == line_num)
2927 return line;
2929 /* Not found. */
2930 line = new source_line (this, line_num);
2931 m_source_lines.safe_push (line);
2932 return line;
2935 /* Constructor for gcc::jit::playback::source_line. */
2937 playback::source_line::source_line (source_file *file, int line_num) :
2938 m_locations (),
2939 m_source_file (file),
2940 m_line_num (line_num)
2944 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2945 GC-ed. */
2947 void
2948 playback::source_line::finalizer ()
2950 m_locations.release ();
2953 /* Construct a playback::location for the given column
2954 within this line of a specific source file, if one doesn't exist
2955 already. */
2957 playback::location *
2958 playback::source_line::
2959 get_location (recording::location *rloc, int column_num)
2961 int i;
2962 location *loc;
2964 /* Another linear search that probably should be a hash table. */
2965 FOR_EACH_VEC_ELT (m_locations, i, loc)
2966 if (loc->get_column_num () == column_num)
2967 return loc;
2969 /* Not found. */
2970 loc = new location (rloc, this, column_num);
2971 m_locations.safe_push (loc);
2972 return loc;
2975 /* Constructor for gcc::jit::playback::location. */
2977 playback::location::location (recording::location *loc,
2978 source_line *line,
2979 int column_num) :
2980 m_srcloc (UNKNOWN_LOCATION),
2981 m_recording_loc (loc),
2982 m_line (line),
2983 m_column_num(column_num)
2987 /* The active gcc::jit::playback::context instance. This is a singleton,
2988 guarded by jit_mutex. */
2990 playback::context *active_playback_ctxt;
2992 } // namespace gcc::jit
2994 } // namespace gcc