PR rtl-optimization/82913
[official-gcc.git] / gcc / jit / jit-playback.c
blob95126c94393c0896234b3187e089cf118fa7660b
1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2017 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 /* Construct a playback::rvalue instance (wrapping a tree) for a
633 vector. */
635 playback::rvalue *
636 playback::context::new_rvalue_from_vector (location *,
637 type *type,
638 const auto_vec<rvalue *> &elements)
640 vec<constructor_elt, va_gc> *v;
641 vec_alloc (v, elements.length ());
642 for (unsigned i = 0; i < elements.length (); ++i)
643 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
644 tree t_ctor = build_constructor (type->as_tree (), v);
645 return new rvalue (this, t_ctor);
648 /* Coerce a tree expression into a boolean tree expression. */
650 tree
651 playback::context::
652 as_truth_value (tree expr, location *loc)
654 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
655 tree typed_zero = fold_build1 (CONVERT_EXPR,
656 TREE_TYPE (expr),
657 integer_zero_node);
658 if (loc)
659 set_tree_location (typed_zero, loc);
661 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
662 if (loc)
663 set_tree_location (expr, loc);
665 return expr;
668 /* Construct a playback::rvalue instance (wrapping a tree) for a
669 unary op. */
671 playback::rvalue *
672 playback::context::
673 new_unary_op (location *loc,
674 enum gcc_jit_unary_op op,
675 type *result_type,
676 rvalue *a)
678 // FIXME: type-checking, or coercion?
679 enum tree_code inner_op;
681 gcc_assert (result_type);
682 gcc_assert (a);
684 tree node = a->as_tree ();
685 tree inner_result = NULL;
687 switch (op)
689 default:
690 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
691 return NULL;
693 case GCC_JIT_UNARY_OP_MINUS:
694 inner_op = NEGATE_EXPR;
695 break;
697 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
698 inner_op = BIT_NOT_EXPR;
699 break;
701 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
702 node = as_truth_value (node, loc);
703 inner_result = invert_truthvalue (node);
704 if (loc)
705 set_tree_location (inner_result, loc);
706 return new rvalue (this, inner_result);
708 case GCC_JIT_UNARY_OP_ABS:
709 inner_op = ABS_EXPR;
710 break;
713 inner_result = build1 (inner_op,
714 result_type->as_tree (),
715 node);
716 if (loc)
717 set_tree_location (inner_result, loc);
719 return new rvalue (this, inner_result);
722 /* Construct a playback::rvalue instance (wrapping a tree) for a
723 binary op. */
725 playback::rvalue *
726 playback::context::
727 new_binary_op (location *loc,
728 enum gcc_jit_binary_op op,
729 type *result_type,
730 rvalue *a, rvalue *b)
732 // FIXME: type-checking, or coercion?
733 enum tree_code inner_op;
735 gcc_assert (result_type);
736 gcc_assert (a);
737 gcc_assert (b);
739 tree node_a = a->as_tree ();
740 tree node_b = b->as_tree ();
742 switch (op)
744 default:
745 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
746 return NULL;
748 case GCC_JIT_BINARY_OP_PLUS:
749 inner_op = PLUS_EXPR;
750 break;
752 case GCC_JIT_BINARY_OP_MINUS:
753 inner_op = MINUS_EXPR;
754 break;
756 case GCC_JIT_BINARY_OP_MULT:
757 inner_op = MULT_EXPR;
758 break;
760 case GCC_JIT_BINARY_OP_DIVIDE:
761 if (FLOAT_TYPE_P (result_type->as_tree ()))
762 /* Floating-point division: */
763 inner_op = RDIV_EXPR;
764 else
765 /* Truncating to zero: */
766 inner_op = TRUNC_DIV_EXPR;
767 break;
769 case GCC_JIT_BINARY_OP_MODULO:
770 inner_op = TRUNC_MOD_EXPR;
771 break;
773 case GCC_JIT_BINARY_OP_BITWISE_AND:
774 inner_op = BIT_AND_EXPR;
775 break;
777 case GCC_JIT_BINARY_OP_BITWISE_XOR:
778 inner_op = BIT_XOR_EXPR;
779 break;
781 case GCC_JIT_BINARY_OP_BITWISE_OR:
782 inner_op = BIT_IOR_EXPR;
783 break;
785 case GCC_JIT_BINARY_OP_LOGICAL_AND:
786 node_a = as_truth_value (node_a, loc);
787 node_b = as_truth_value (node_b, loc);
788 inner_op = TRUTH_ANDIF_EXPR;
789 break;
791 case GCC_JIT_BINARY_OP_LOGICAL_OR:
792 node_a = as_truth_value (node_a, loc);
793 node_b = as_truth_value (node_b, loc);
794 inner_op = TRUTH_ORIF_EXPR;
795 break;
797 case GCC_JIT_BINARY_OP_LSHIFT:
798 inner_op = LSHIFT_EXPR;
799 break;
801 case GCC_JIT_BINARY_OP_RSHIFT:
802 inner_op = RSHIFT_EXPR;
803 break;
806 tree inner_expr = build2 (inner_op,
807 result_type->as_tree (),
808 node_a,
809 node_b);
810 if (loc)
811 set_tree_location (inner_expr, loc);
813 return new rvalue (this, inner_expr);
816 /* Construct a playback::rvalue instance (wrapping a tree) for a
817 comparison. */
819 playback::rvalue *
820 playback::context::
821 new_comparison (location *loc,
822 enum gcc_jit_comparison op,
823 rvalue *a, rvalue *b)
825 // FIXME: type-checking, or coercion?
826 enum tree_code inner_op;
828 gcc_assert (a);
829 gcc_assert (b);
831 switch (op)
833 default:
834 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
835 return NULL;
837 case GCC_JIT_COMPARISON_EQ:
838 inner_op = EQ_EXPR;
839 break;
840 case GCC_JIT_COMPARISON_NE:
841 inner_op = NE_EXPR;
842 break;
843 case GCC_JIT_COMPARISON_LT:
844 inner_op = LT_EXPR;
845 break;
846 case GCC_JIT_COMPARISON_LE:
847 inner_op = LE_EXPR;
848 break;
849 case GCC_JIT_COMPARISON_GT:
850 inner_op = GT_EXPR;
851 break;
852 case GCC_JIT_COMPARISON_GE:
853 inner_op = GE_EXPR;
854 break;
857 tree inner_expr = build2 (inner_op,
858 boolean_type_node,
859 a->as_tree (),
860 b->as_tree ());
861 if (loc)
862 set_tree_location (inner_expr, loc);
863 return new rvalue (this, inner_expr);
866 /* Construct a playback::rvalue instance (wrapping a tree) for a
867 function call. */
869 playback::rvalue *
870 playback::context::
871 build_call (location *loc,
872 tree fn_ptr,
873 const auto_vec<rvalue *> *args,
874 bool require_tail_call)
876 vec<tree, va_gc> *tree_args;
877 vec_alloc (tree_args, args->length ());
878 for (unsigned i = 0; i < args->length (); i++)
879 tree_args->quick_push ((*args)[i]->as_tree ());
881 if (loc)
882 set_tree_location (fn_ptr, loc);
884 tree fn = TREE_TYPE (fn_ptr);
885 tree fn_type = TREE_TYPE (fn);
886 tree return_type = TREE_TYPE (fn_type);
888 tree call = build_call_vec (return_type,
889 fn_ptr, tree_args);
891 if (require_tail_call)
892 CALL_EXPR_MUST_TAIL_CALL (call) = 1;
894 return new rvalue (this, call);
896 /* see c-typeck.c: build_function_call
897 which calls build_function_call_vec
899 which does lots of checking, then:
900 result = build_call_array_loc (loc, TREE_TYPE (fntype),
901 function, nargs, argarray);
902 which is in tree.c
903 (see also build_call_vec)
907 /* Construct a playback::rvalue instance (wrapping a tree) for a
908 call to a specific function. */
910 playback::rvalue *
911 playback::context::
912 new_call (location *loc,
913 function *func,
914 const auto_vec<rvalue *> *args,
915 bool require_tail_call)
917 tree fndecl;
919 gcc_assert (func);
921 fndecl = func->as_fndecl ();
923 tree fntype = TREE_TYPE (fndecl);
925 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
927 return build_call (loc, fn, args, require_tail_call);
930 /* Construct a playback::rvalue instance (wrapping a tree) for a
931 call through a function pointer. */
933 playback::rvalue *
934 playback::context::
935 new_call_through_ptr (location *loc,
936 rvalue *fn_ptr,
937 const auto_vec<rvalue *> *args,
938 bool require_tail_call)
940 gcc_assert (fn_ptr);
941 tree t_fn_ptr = fn_ptr->as_tree ();
943 return build_call (loc, t_fn_ptr, args, require_tail_call);
946 /* Construct a tree for a cast. */
948 tree
949 playback::context::build_cast (playback::location *loc,
950 playback::rvalue *expr,
951 playback::type *type_)
953 /* For comparison, see:
954 - c/c-typeck.c:build_c_cast
955 - c/c-convert.c: convert
956 - convert.h
958 Only some kinds of cast are currently supported here. */
959 tree t_expr = expr->as_tree ();
960 tree t_dst_type = type_->as_tree ();
961 tree t_ret = NULL;
962 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
963 if (t_ret)
964 return t_ret;
965 enum tree_code dst_code = TREE_CODE (t_dst_type);
966 switch (dst_code)
968 case INTEGER_TYPE:
969 case ENUMERAL_TYPE:
970 t_ret = convert_to_integer (t_dst_type, t_expr);
971 goto maybe_fold;
973 case BOOLEAN_TYPE:
974 /* Compare with c_objc_common_truthvalue_conversion and
975 c_common_truthvalue_conversion. */
976 /* For now, convert to: (t_expr != 0) */
977 t_ret = build2 (NE_EXPR, t_dst_type,
978 t_expr,
979 build_int_cst (TREE_TYPE (t_expr), 0));
980 goto maybe_fold;
982 case REAL_TYPE:
983 t_ret = convert_to_real (t_dst_type, t_expr);
984 goto maybe_fold;
986 case POINTER_TYPE:
987 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
988 goto maybe_fold;
990 default:
991 add_error (loc, "couldn't handle cast during playback");
992 fprintf (stderr, "input expression:\n");
993 debug_tree (t_expr);
994 fprintf (stderr, "requested type:\n");
995 debug_tree (t_dst_type);
996 return error_mark_node;
998 maybe_fold:
999 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
1000 t_ret = fold (t_ret);
1001 return t_ret;
1005 /* Construct a playback::rvalue instance (wrapping a tree) for a
1006 cast. */
1008 playback::rvalue *
1009 playback::context::
1010 new_cast (playback::location *loc,
1011 playback::rvalue *expr,
1012 playback::type *type_)
1015 tree t_cast = build_cast (loc, expr, type_);
1016 if (loc)
1017 set_tree_location (t_cast, loc);
1018 return new rvalue (this, t_cast);
1021 /* Construct a playback::lvalue instance (wrapping a tree) for an
1022 array access. */
1024 playback::lvalue *
1025 playback::context::
1026 new_array_access (location *loc,
1027 rvalue *ptr,
1028 rvalue *index)
1030 gcc_assert (ptr);
1031 gcc_assert (index);
1033 /* For comparison, see:
1034 c/c-typeck.c: build_array_ref
1035 c-family/c-common.c: pointer_int_sum
1037 tree t_ptr = ptr->as_tree ();
1038 tree t_index = index->as_tree ();
1039 tree t_type_ptr = TREE_TYPE (t_ptr);
1040 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1042 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1044 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1045 NULL_TREE, NULL_TREE);
1046 if (loc)
1047 set_tree_location (t_result, loc);
1048 return new lvalue (this, t_result);
1050 else
1052 /* Convert index to an offset in bytes. */
1053 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1054 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1055 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
1057 /* Locate (ptr + offset). */
1058 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1060 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1061 if (loc)
1063 set_tree_location (t_sizeof, loc);
1064 set_tree_location (t_offset, loc);
1065 set_tree_location (t_address, loc);
1066 set_tree_location (t_indirection, loc);
1069 return new lvalue (this, t_indirection);
1073 /* Construct a tree for a field access. */
1075 tree
1076 playback::context::
1077 new_field_access (location *loc,
1078 tree datum,
1079 field *field)
1081 gcc_assert (datum);
1082 gcc_assert (field);
1084 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1085 build_component_ref. */
1086 tree type = TREE_TYPE (datum);
1087 gcc_assert (type);
1088 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1090 tree t_field = field->as_tree ();
1091 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1092 t_field, NULL_TREE);
1093 if (loc)
1094 set_tree_location (ref, loc);
1095 return ref;
1098 /* Construct a tree for a dereference. */
1100 tree
1101 playback::context::
1102 new_dereference (tree ptr,
1103 location *loc)
1105 gcc_assert (ptr);
1107 tree type = TREE_TYPE (TREE_TYPE(ptr));
1108 tree datum = build1 (INDIRECT_REF, type, ptr);
1109 if (loc)
1110 set_tree_location (datum, loc);
1111 return datum;
1114 /* Construct a playback::type instance (wrapping a tree)
1115 with the given alignment. */
1117 playback::type *
1118 playback::type::
1119 get_aligned (size_t alignment_in_bytes) const
1121 tree t_new_type = build_variant_type_copy (m_inner);
1123 SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT);
1124 TYPE_USER_ALIGN (t_new_type) = 1;
1126 return new type (t_new_type);
1129 /* Construct a playback::type instance (wrapping a tree)
1130 for the given vector type. */
1132 playback::type *
1133 playback::type::
1134 get_vector (size_t num_units) const
1136 tree t_new_type = build_vector_type (m_inner, num_units);
1137 return new type (t_new_type);
1140 /* Construct a playback::lvalue instance (wrapping a tree) for a
1141 field access. */
1143 playback::lvalue *
1144 playback::lvalue::
1145 access_field (location *loc,
1146 field *field)
1148 tree datum = as_tree ();
1149 tree ref = get_context ()->new_field_access (loc, datum, field);
1150 if (!ref)
1151 return NULL;
1152 return new lvalue (get_context (), ref);
1155 /* Construct a playback::rvalue instance (wrapping a tree) for a
1156 field access. */
1158 playback::rvalue *
1159 playback::rvalue::
1160 access_field (location *loc,
1161 field *field)
1163 tree datum = as_tree ();
1164 tree ref = get_context ()->new_field_access (loc, datum, field);
1165 if (!ref)
1166 return NULL;
1167 return new rvalue (get_context (), ref);
1170 /* Construct a playback::lvalue instance (wrapping a tree) for a
1171 dereferenced field access. */
1173 playback::lvalue *
1174 playback::rvalue::
1175 dereference_field (location *loc,
1176 field *field)
1178 tree ptr = as_tree ();
1179 tree datum = get_context ()->new_dereference (ptr, loc);
1180 if (!datum)
1181 return NULL;
1182 tree ref = get_context ()->new_field_access (loc, datum, field);
1183 if (!ref)
1184 return NULL;
1185 return new lvalue (get_context (), ref);
1188 /* Construct a playback::lvalue instance (wrapping a tree) for a
1189 dereference. */
1191 playback::lvalue *
1192 playback::rvalue::
1193 dereference (location *loc)
1195 tree ptr = as_tree ();
1196 tree datum = get_context ()->new_dereference (ptr, loc);
1197 return new lvalue (get_context (), datum);
1200 /* Mark EXP saying that we need to be able to take the
1201 address of it; it should not be allocated in a register.
1202 Compare with e.g. c/c-typeck.c: c_mark_addressable. */
1204 static void
1205 jit_mark_addressable (tree exp)
1207 tree x = exp;
1209 while (1)
1210 switch (TREE_CODE (x))
1212 case COMPONENT_REF:
1213 /* (we don't yet support bitfields) */
1214 /* fallthrough */
1215 case ADDR_EXPR:
1216 case ARRAY_REF:
1217 case REALPART_EXPR:
1218 case IMAGPART_EXPR:
1219 x = TREE_OPERAND (x, 0);
1220 break;
1222 case COMPOUND_LITERAL_EXPR:
1223 case CONSTRUCTOR:
1224 TREE_ADDRESSABLE (x) = 1;
1225 return;
1227 case VAR_DECL:
1228 case CONST_DECL:
1229 case PARM_DECL:
1230 case RESULT_DECL:
1231 /* (we don't have a concept of a "register" declaration) */
1232 /* fallthrough */
1233 case FUNCTION_DECL:
1234 TREE_ADDRESSABLE (x) = 1;
1235 /* fallthrough */
1236 default:
1237 return;
1241 /* Construct a playback::rvalue instance (wrapping a tree) for an
1242 address-lookup. */
1244 playback::rvalue *
1245 playback::lvalue::
1246 get_address (location *loc)
1248 tree t_lvalue = as_tree ();
1249 tree t_thistype = TREE_TYPE (t_lvalue);
1250 tree t_ptrtype = build_pointer_type (t_thistype);
1251 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1252 if (loc)
1253 get_context ()->set_tree_location (ptr, loc);
1254 jit_mark_addressable (t_lvalue);
1255 return new rvalue (get_context (), ptr);
1258 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1259 Provide this finalization hook for calling then they are collected,
1260 which calls the finalizer vfunc. This allows them to call "release"
1261 on any vec<> within them. */
1263 static void
1264 wrapper_finalizer (void *ptr)
1266 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1267 wrapper->finalizer ();
1270 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1271 allocate them using ggc_internal_cleared_alloc. */
1273 void *
1274 playback::wrapper::
1275 operator new (size_t sz)
1277 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1281 /* Constructor for gcc:jit::playback::function. */
1283 playback::function::
1284 function (context *ctxt,
1285 tree fndecl,
1286 enum gcc_jit_function_kind kind)
1287 : m_ctxt(ctxt),
1288 m_inner_fndecl (fndecl),
1289 m_inner_bind_expr (NULL),
1290 m_kind (kind)
1292 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1294 /* Create a BIND_EXPR, and within it, a statement list. */
1295 m_stmt_list = alloc_stmt_list ();
1296 m_stmt_iter = tsi_start (m_stmt_list);
1297 m_inner_block = make_node (BLOCK);
1298 m_inner_bind_expr =
1299 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1301 else
1303 m_inner_block = NULL;
1304 m_stmt_list = NULL;
1308 /* Hand-written GC-marking hook for playback functions. */
1310 void
1311 playback::function::
1312 gt_ggc_mx ()
1314 gt_ggc_m_9tree_node (m_inner_fndecl);
1315 gt_ggc_m_9tree_node (m_inner_bind_expr);
1316 gt_ggc_m_9tree_node (m_stmt_list);
1317 gt_ggc_m_9tree_node (m_inner_block);
1320 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1321 GC-ed. */
1323 void
1324 playback::function::finalizer ()
1326 m_blocks.release ();
1329 /* Get the return type of a playback function, in tree form. */
1331 tree
1332 playback::function::
1333 get_return_type_as_tree () const
1335 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1338 /* Construct a new local within this playback::function. */
1340 playback::lvalue *
1341 playback::function::
1342 new_local (location *loc,
1343 type *type,
1344 const char *name)
1346 gcc_assert (type);
1347 gcc_assert (name);
1348 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1349 get_identifier (name),
1350 type->as_tree ());
1351 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1353 /* Prepend to BIND_EXPR_VARS: */
1354 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1355 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1357 if (loc)
1358 set_tree_location (inner, loc);
1359 return new lvalue (m_ctxt, inner);
1362 /* Construct a new block within this playback::function. */
1364 playback::block *
1365 playback::function::
1366 new_block (const char *name)
1368 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1370 block *result = new playback::block (this, name);
1371 m_blocks.safe_push (result);
1372 return result;
1375 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1376 this playback::function. */
1378 playback::rvalue *
1379 playback::function::get_address (location *loc)
1381 tree t_fndecl = as_fndecl ();
1382 tree t_fntype = TREE_TYPE (t_fndecl);
1383 tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
1384 if (loc)
1385 m_ctxt->set_tree_location (t_fnptr, loc);
1386 return new rvalue (m_ctxt, t_fnptr);
1389 /* Build a statement list for the function as a whole out of the
1390 lists of statements for the individual blocks, building labels
1391 for each block. */
1393 void
1394 playback::function::
1395 build_stmt_list ()
1397 int i;
1398 block *b;
1400 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1402 FOR_EACH_VEC_ELT (m_blocks, i, b)
1404 int j;
1405 tree stmt;
1407 b->m_label_expr = build1 (LABEL_EXPR,
1408 void_type_node,
1409 b->as_label_decl ());
1410 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1412 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1413 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1417 /* Finish compiling the given function, potentially running the
1418 garbage-collector.
1419 The function will have a statement list by now.
1420 Amongst other things, this gimplifies the statement list,
1421 and calls cgraph_node::finalize_function on the function. */
1423 void
1424 playback::function::
1425 postprocess ()
1427 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1429 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1430 debug_tree (m_stmt_list);
1432 /* Do we need this to force cgraphunit.c to output the function? */
1433 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1435 DECL_EXTERNAL (m_inner_fndecl) = 0;
1436 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1439 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1440 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1442 DECL_EXTERNAL (m_inner_fndecl) = 0;
1443 TREE_PUBLIC (m_inner_fndecl) = 0;
1446 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1448 /* Seem to need this in gimple-low.c: */
1449 gcc_assert (m_inner_block);
1450 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1452 /* how to add to function? the following appears to be how to
1453 set the body of a m_inner_fndecl: */
1454 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1456 /* Ensure that locals appear in the debuginfo. */
1457 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1459 //debug_tree (m_inner_fndecl);
1461 /* Convert to gimple: */
1462 //printf("about to gimplify_function_tree\n");
1463 gimplify_function_tree (m_inner_fndecl);
1464 //printf("finished gimplify_function_tree\n");
1466 current_function_decl = m_inner_fndecl;
1467 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1468 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1469 //debug_tree (m_inner_fndecl);
1471 //printf("about to add to cgraph\n");
1472 /* Add to cgraph: */
1473 cgraph_node::finalize_function (m_inner_fndecl, false);
1474 /* This can trigger a collection, so we need to have all of
1475 the funcs as roots. */
1477 current_function_decl = NULL;
1481 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1482 GC-ed. */
1484 void
1485 playback::block::finalizer ()
1487 m_stmts.release ();
1490 /* Add an eval of the rvalue to the function's statement list. */
1492 void
1493 playback::block::
1494 add_eval (location *loc,
1495 rvalue *rvalue)
1497 gcc_assert (rvalue);
1499 if (loc)
1500 set_tree_location (rvalue->as_tree (), loc);
1502 add_stmt (rvalue->as_tree ());
1505 /* Add an assignment to the function's statement list. */
1507 void
1508 playback::block::
1509 add_assignment (location *loc,
1510 lvalue *lvalue,
1511 rvalue *rvalue)
1513 gcc_assert (lvalue);
1514 gcc_assert (rvalue);
1516 tree t_lvalue = lvalue->as_tree ();
1517 tree t_rvalue = rvalue->as_tree ();
1518 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1520 t_rvalue = build1 (CONVERT_EXPR,
1521 TREE_TYPE (t_lvalue),
1522 t_rvalue);
1523 if (loc)
1524 set_tree_location (t_rvalue, loc);
1527 tree stmt =
1528 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1529 t_lvalue, t_rvalue);
1530 if (loc)
1531 set_tree_location (stmt, loc);
1532 add_stmt (stmt);
1535 /* Add a comment to the function's statement list.
1536 For now this is done by adding a dummy label. */
1538 void
1539 playback::block::
1540 add_comment (location *loc,
1541 const char *text)
1543 /* Wrap the text in C-style comment delimiters. */
1544 size_t sz =
1545 (3 /* opening delim */
1546 + strlen (text)
1547 + 3 /* closing delim */
1548 + 1 /* terminator */);
1549 char *wrapped = (char *)ggc_internal_alloc (sz);
1550 snprintf (wrapped, sz, "/* %s */", text);
1552 /* For now we simply implement this by adding a dummy label with a name
1553 containing the given text. */
1554 tree identifier = get_identifier (wrapped);
1555 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1556 identifier, void_type_node);
1557 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1559 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1560 if (loc)
1561 set_tree_location (label_expr, loc);
1562 add_stmt (label_expr);
1565 /* Add a conditional jump statement to the function's statement list. */
1567 void
1568 playback::block::
1569 add_conditional (location *loc,
1570 rvalue *boolval,
1571 block *on_true,
1572 block *on_false)
1574 gcc_assert (boolval);
1575 gcc_assert (on_true);
1576 gcc_assert (on_false);
1578 /* COND_EXPR wants statement lists for the true/false operands, but we
1579 want labels.
1580 Shim it by creating jumps to the labels */
1581 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1582 on_true->as_label_decl ());
1583 if (loc)
1584 set_tree_location (true_jump, loc);
1586 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1587 on_false->as_label_decl ());
1588 if (loc)
1589 set_tree_location (false_jump, loc);
1591 tree stmt =
1592 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1593 true_jump, false_jump);
1594 if (loc)
1595 set_tree_location (stmt, loc);
1596 add_stmt (stmt);
1599 /* Add an unconditional jump statement to the function's statement list. */
1601 void
1602 playback::block::
1603 add_jump (location *loc,
1604 block *target)
1606 gcc_assert (target);
1608 // see c_finish_loop
1609 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1610 //add_stmt (top);
1612 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1613 TREE_USED (target->as_label_decl ()) = 1;
1614 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1615 if (loc)
1616 set_tree_location (stmt, loc);
1617 add_stmt (stmt);
1620 from c-typeck.c:
1621 tree
1622 c_finish_goto_label (location_t loc, tree label)
1624 tree decl = lookup_label_for_goto (loc, label);
1625 if (!decl)
1626 return NULL_TREE;
1627 TREE_USED (decl) = 1;
1629 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1630 SET_EXPR_LOCATION (t, loc);
1631 return add_stmt (t);
1638 /* Add a return statement to the function's statement list. */
1640 void
1641 playback::block::
1642 add_return (location *loc,
1643 rvalue *rvalue)
1645 tree modify_retval = NULL;
1646 tree return_type = m_func->get_return_type_as_tree ();
1647 if (rvalue)
1649 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1650 tree t_rvalue = rvalue->as_tree ();
1651 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1652 t_rvalue = build1 (CONVERT_EXPR,
1653 TREE_TYPE (t_lvalue),
1654 t_rvalue);
1655 modify_retval = build2 (MODIFY_EXPR, return_type,
1656 t_lvalue, t_rvalue);
1657 if (loc)
1658 set_tree_location (modify_retval, loc);
1660 tree return_stmt = build1 (RETURN_EXPR, return_type,
1661 modify_retval);
1662 if (loc)
1663 set_tree_location (return_stmt, loc);
1665 add_stmt (return_stmt);
1668 /* Helper function for playback::block::add_switch.
1669 Construct a case label for the given range, followed by a goto stmt
1670 to the given block, appending them to stmt list *ptr_t_switch_body. */
1672 static void
1673 add_case (tree *ptr_t_switch_body,
1674 tree t_low_value,
1675 tree t_high_value,
1676 playback::block *dest_block)
1678 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
1679 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
1681 tree t_case_label =
1682 build_case_label (t_low_value, t_high_value, t_label);
1683 append_to_statement_list (t_case_label, ptr_t_switch_body);
1685 tree t_goto_stmt =
1686 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
1687 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
1690 /* Add a switch statement to the function's statement list.
1692 My initial attempt at implementing this constructed a TREE_VEC
1693 of the cases and set it as SWITCH_LABELS (switch_expr). However,
1694 gimplify.c:gimplify_switch_expr is set up to deal with SWITCH_BODY, and
1695 doesn't have any logic for gimplifying SWITCH_LABELS.
1697 Hence we create a switch body, and populate it with case labels, each
1698 followed by a goto to the desired block. */
1700 void
1701 playback::block::
1702 add_switch (location *loc,
1703 rvalue *expr,
1704 block *default_block,
1705 const auto_vec <case_> *cases)
1707 /* Compare with:
1708 - c/c-typeck.c: c_start_case
1709 - c-family/c-common.c:c_add_case_label
1710 - java/expr.c:expand_java_switch and expand_java_add_case
1711 We've already rejected overlaps and duplicates in
1712 libgccjit.c:case_range_validator::validate. */
1714 tree t_expr = expr->as_tree ();
1715 tree t_type = TREE_TYPE (t_expr);
1717 tree t_switch_body = alloc_stmt_list ();
1719 int i;
1720 case_ *c;
1721 FOR_EACH_VEC_ELT (*cases, i, c)
1723 tree t_low_value = c->m_min_value->as_tree ();
1724 tree t_high_value = c->m_max_value->as_tree ();
1725 add_case (&t_switch_body,
1726 t_low_value,
1727 t_high_value,
1728 c->m_dest_block);
1730 /* Default label. */
1731 add_case (&t_switch_body,
1732 NULL_TREE, NULL_TREE,
1733 default_block);
1735 tree switch_stmt = build3 (SWITCH_EXPR, t_type, t_expr,
1736 t_switch_body, NULL_TREE);
1737 if (loc)
1738 set_tree_location (switch_stmt, loc);
1739 add_stmt (switch_stmt);
1742 /* Constructor for gcc::jit::playback::block. */
1744 playback::block::
1745 block (function *func,
1746 const char *name)
1747 : m_func (func),
1748 m_stmts ()
1750 tree identifier;
1752 gcc_assert (func);
1753 // name can be NULL
1754 if (name)
1755 identifier = get_identifier (name);
1756 else
1757 identifier = NULL;
1758 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1759 identifier, void_type_node);
1760 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1761 m_label_expr = NULL;
1764 /* A subclass of auto_vec <char *> that frees all of its elements on
1765 deletion. */
1767 class auto_argvec : public auto_vec <char *>
1769 public:
1770 ~auto_argvec ();
1773 /* auto_argvec's dtor, freeing all contained strings, automatically
1774 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1776 auto_argvec::~auto_argvec ()
1778 int i;
1779 char *str;
1780 FOR_EACH_VEC_ELT (*this, i, str)
1781 free (str);
1784 /* Compile a playback::context:
1786 - Use the context's options to cconstruct command-line options, and
1787 call into the rest of GCC (toplev::main).
1788 - Assuming it succeeds, we have a .s file.
1789 - We then run the "postprocess" vfunc:
1791 (A) In-memory compile ("gcc_jit_context_compile")
1793 For an in-memory compile we have the playback::compile_to_memory
1794 subclass; "postprocess" will convert the .s file to a .so DSO,
1795 and load it in memory (via dlopen), wrapping the result up as
1796 a jit::result and returning it.
1798 (B) Compile to file ("gcc_jit_context_compile_to_file")
1800 When compiling to a file, we have the playback::compile_to_file
1801 subclass; "postprocess" will either copy the .s file to the
1802 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1803 the driver to convert it as necessary, copying the result. */
1805 void
1806 playback::context::
1807 compile ()
1809 JIT_LOG_SCOPE (get_logger ());
1811 const char *ctxt_progname;
1813 int keep_intermediates =
1814 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
1816 m_tempdir = new tempdir (get_logger (), keep_intermediates);
1817 if (!m_tempdir->create ())
1818 return;
1820 /* Call into the rest of gcc.
1821 For now, we have to assemble command-line options to pass into
1822 toplev::main, so that they can be parsed. */
1824 /* Pass in user-provided program name as argv0, if any, so that it
1825 makes it into GCC's "progname" global, used in various diagnostics. */
1826 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1828 if (!ctxt_progname)
1829 ctxt_progname = "libgccjit.so";
1831 auto_vec <recording::requested_dump> requested_dumps;
1832 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1834 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1835 acquire_mutex ();
1837 auto_argvec fake_args;
1838 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
1839 if (errors_occurred ())
1841 release_mutex ();
1842 return;
1845 /* This runs the compiler. */
1846 toplev toplev (get_timer (), /* external_timer */
1847 false); /* init_signals */
1848 enter_scope ("toplev::main");
1849 if (get_logger ())
1850 for (unsigned i = 0; i < fake_args.length (); i++)
1851 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
1852 toplev.main (fake_args.length (),
1853 const_cast <char **> (fake_args.address ()));
1854 exit_scope ("toplev::main");
1856 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1857 need to do it between toplev::main (which creates the dump manager)
1858 and toplev::finalize (which deletes it). */
1859 extract_any_requested_dumps (&requested_dumps);
1861 /* Clean up the compiler. */
1862 enter_scope ("toplev::finalize");
1863 toplev.finalize ();
1864 exit_scope ("toplev::finalize");
1866 /* Ideally we would release the jit mutex here, but we can't yet since
1867 followup activities use timevars, which are global state. */
1869 if (errors_occurred ())
1871 release_mutex ();
1872 return;
1875 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1876 dump_generated_code ();
1878 /* We now have a .s file.
1880 Run any postprocessing steps. This will either convert the .s file to
1881 a .so DSO, and load it in memory (playback::compile_to_memory), or
1882 convert the .s file to the requested output format, and copy it to a
1883 given file (playback::compile_to_file). */
1884 postprocess (ctxt_progname);
1886 release_mutex ();
1889 /* Implementation of class gcc::jit::playback::compile_to_memory,
1890 a subclass of gcc::jit::playback::context. */
1892 /* playback::compile_to_memory's trivial constructor. */
1894 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
1895 playback::context (ctxt),
1896 m_result (NULL)
1898 JIT_LOG_SCOPE (get_logger ());
1901 /* Implementation of the playback::context::process vfunc for compiling
1902 to memory.
1904 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1905 wrapping the result up as a jit::result and returning it. */
1907 void
1908 playback::compile_to_memory::postprocess (const char *ctxt_progname)
1910 JIT_LOG_SCOPE (get_logger ());
1911 convert_to_dso (ctxt_progname);
1912 if (errors_occurred ())
1913 return;
1914 m_result = dlopen_built_dso ();
1917 /* Implementation of class gcc::jit::playback::compile_to_file,
1918 a subclass of gcc::jit::playback::context. */
1920 /* playback::compile_to_file's trivial constructor. */
1922 playback::compile_to_file::compile_to_file (recording::context *ctxt,
1923 enum gcc_jit_output_kind output_kind,
1924 const char *output_path) :
1925 playback::context (ctxt),
1926 m_output_kind (output_kind),
1927 m_output_path (output_path)
1929 JIT_LOG_SCOPE (get_logger ());
1932 /* Implementation of the playback::context::process vfunc for compiling
1933 to a file.
1935 Either copy the .s file to the given destination (for
1936 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1937 as necessary, copying the result. */
1939 void
1940 playback::compile_to_file::postprocess (const char *ctxt_progname)
1942 JIT_LOG_SCOPE (get_logger ());
1944 /* The driver takes different actions based on the filename, so
1945 we provide a filename with an appropriate suffix for the
1946 output kind, and then copy it up to the user-provided path,
1947 rather than directly compiling it to the requested output path. */
1949 switch (m_output_kind)
1951 default:
1952 gcc_unreachable ();
1954 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
1955 copy_file (get_tempdir ()->get_path_s_file (),
1956 m_output_path);
1957 /* The .s file is automatically unlinked by tempdir::~tempdir. */
1958 break;
1960 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
1962 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
1963 "/fake.o",
1964 NULL);
1965 invoke_driver (ctxt_progname,
1966 get_tempdir ()->get_path_s_file (),
1967 tmp_o_path,
1968 TV_ASSEMBLE,
1969 false, /* bool shared, */
1970 false);/* bool run_linker */
1971 if (!errors_occurred ())
1973 copy_file (tmp_o_path,
1974 m_output_path);
1975 get_tempdir ()->add_temp_file (tmp_o_path);
1977 else
1978 free (tmp_o_path);
1980 break;
1982 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
1983 invoke_driver (ctxt_progname,
1984 get_tempdir ()->get_path_s_file (),
1985 get_tempdir ()->get_path_so_file (),
1986 TV_ASSEMBLE,
1987 true, /* bool shared, */
1988 true);/* bool run_linker */
1989 if (!errors_occurred ())
1990 copy_file (get_tempdir ()->get_path_so_file (),
1991 m_output_path);
1992 /* The .so file is automatically unlinked by tempdir::~tempdir. */
1993 break;
1995 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
1997 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
1998 "/fake.exe",
1999 NULL);
2000 invoke_driver (ctxt_progname,
2001 get_tempdir ()->get_path_s_file (),
2002 tmp_exe_path,
2003 TV_ASSEMBLE,
2004 false, /* bool shared, */
2005 true);/* bool run_linker */
2006 if (!errors_occurred ())
2008 copy_file (tmp_exe_path,
2009 m_output_path);
2010 get_tempdir ()->add_temp_file (tmp_exe_path);
2012 else
2013 free (tmp_exe_path);
2015 break;
2021 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2022 the "executable" bits).
2024 Any errors that occur are reported on the context and hence count as
2025 a failure of the compile.
2027 We can't in general hardlink or use "rename" from the tempdir since
2028 it might be on a different filesystem to the destination. For example,
2029 I get EXDEV: "Invalid cross-device link". */
2031 void
2032 playback::compile_to_file::copy_file (const char *src_path,
2033 const char *dst_path)
2035 JIT_LOG_SCOPE (get_logger ());
2036 if (get_logger ())
2038 get_logger ()->log ("src_path: %s", src_path);
2039 get_logger ()->log ("dst_path: %s", dst_path);
2042 FILE *f_in = NULL;
2043 FILE *f_out = NULL;
2044 size_t total_sz_in = 0;
2045 size_t total_sz_out = 0;
2046 char buf[4096];
2047 size_t sz_in;
2048 struct stat stat_buf;
2050 f_in = fopen (src_path, "rb");
2051 if (!f_in)
2053 add_error (NULL,
2054 "unable to open %s for reading: %s",
2055 src_path,
2056 xstrerror (errno));
2057 return;
2060 /* Use stat on the filedescriptor to get the mode,
2061 so that we can copy it over (in particular, the
2062 "executable" bits). */
2063 if (-1 == fstat (fileno (f_in), &stat_buf))
2065 add_error (NULL,
2066 "unable to fstat %s: %s",
2067 src_path,
2068 xstrerror (errno));
2069 fclose (f_in);
2070 return;
2073 f_out = fopen (dst_path, "wb");
2074 if (!f_out)
2076 add_error (NULL,
2077 "unable to open %s for writing: %s",
2078 dst_path,
2079 xstrerror (errno));
2080 fclose (f_in);
2081 return;
2084 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2086 total_sz_in += sz_in;
2087 size_t sz_out_remaining = sz_in;
2088 size_t sz_out_so_far = 0;
2089 while (sz_out_remaining)
2091 size_t sz_out = fwrite (buf + sz_out_so_far,
2093 sz_out_remaining,
2094 f_out);
2095 gcc_assert (sz_out <= sz_out_remaining);
2096 if (!sz_out)
2098 add_error (NULL,
2099 "error writing to %s: %s",
2100 dst_path,
2101 xstrerror (errno));
2102 fclose (f_in);
2103 fclose (f_out);
2104 return;
2106 total_sz_out += sz_out;
2107 sz_out_so_far += sz_out;
2108 sz_out_remaining -= sz_out;
2110 gcc_assert (sz_out_so_far == sz_in);
2113 if (!feof (f_in))
2114 add_error (NULL,
2115 "error reading from %s: %s",
2116 src_path,
2117 xstrerror (errno));
2119 fclose (f_in);
2121 gcc_assert (total_sz_in == total_sz_out);
2122 if (get_logger ())
2123 get_logger ()->log ("total bytes copied: %ld", total_sz_out);
2125 /* Set the permissions of the copy to those of the original file,
2126 in particular the "executable" bits. */
2127 if (-1 == fchmod (fileno (f_out), stat_buf.st_mode))
2128 add_error (NULL,
2129 "error setting mode of %s: %s",
2130 dst_path,
2131 xstrerror (errno));
2133 fclose (f_out);
2136 /* Helper functions for gcc::jit::playback::context::compile. */
2138 /* This mutex guards gcc::jit::recording::context::compile, so that only
2139 one thread can be accessing the bulk of GCC's state at once. */
2141 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2143 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2145 void
2146 playback::context::acquire_mutex ()
2148 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2150 /* Acquire the big GCC mutex. */
2151 JIT_LOG_SCOPE (get_logger ());
2152 pthread_mutex_lock (&jit_mutex);
2153 gcc_assert (NULL == active_playback_ctxt);
2154 active_playback_ctxt = this;
2157 /* Release jit_mutex and clear the active playback ctxt. */
2159 void
2160 playback::context::release_mutex ()
2162 /* Release the big GCC mutex. */
2163 JIT_LOG_SCOPE (get_logger ());
2164 gcc_assert (active_playback_ctxt == this);
2165 active_playback_ctxt = NULL;
2166 pthread_mutex_unlock (&jit_mutex);
2169 /* Callback used by gcc::jit::playback::context::make_fake_args when
2170 invoking driver_get_configure_time_options.
2171 Populate a vec <char * > with the configure-time options. */
2173 static void
2174 append_arg_from_driver (const char *option, void *user_data)
2176 gcc_assert (option);
2177 gcc_assert (user_data);
2178 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2179 argvec->safe_push (concat ("-", option, NULL));
2182 /* Build a fake argv for toplev::main from the options set
2183 by the user on the context . */
2185 void
2186 playback::context::
2187 make_fake_args (vec <char *> *argvec,
2188 const char *ctxt_progname,
2189 vec <recording::requested_dump> *requested_dumps)
2191 JIT_LOG_SCOPE (get_logger ());
2193 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2194 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2196 ADD_ARG (ctxt_progname);
2197 ADD_ARG (get_path_c_file ());
2198 ADD_ARG ("-fPIC");
2200 /* Handle int options: */
2201 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2203 default:
2204 add_error (NULL,
2205 "unrecognized optimization level: %i",
2206 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2207 return;
2209 case 0:
2210 ADD_ARG ("-O0");
2211 break;
2213 case 1:
2214 ADD_ARG ("-O1");
2215 break;
2217 case 2:
2218 ADD_ARG ("-O2");
2219 break;
2221 case 3:
2222 ADD_ARG ("-O3");
2223 break;
2225 /* What about -Os? */
2227 /* Handle bool options: */
2228 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2229 ADD_ARG ("-g");
2231 /* Suppress timing (and other) info. */
2232 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2234 ADD_ARG ("-quiet");
2235 quiet_flag = 1;
2238 /* Aggressively garbage-collect, to shake out bugs: */
2239 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2241 ADD_ARG ("--param");
2242 ADD_ARG ("ggc-min-expand=0");
2243 ADD_ARG ("--param");
2244 ADD_ARG ("ggc-min-heapsize=0");
2247 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2249 ADD_ARG ("-fdump-tree-all");
2250 ADD_ARG ("-fdump-rtl-all");
2251 ADD_ARG ("-fdump-ipa-all");
2254 /* Add "-fdump-" options for any calls to
2255 gcc_jit_context_enable_dump. */
2257 int i;
2258 recording::requested_dump *d;
2259 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2261 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2262 ADD_ARG_TAKE_OWNERSHIP (arg);
2266 /* PR jit/64810: Add any target-specific default options
2267 from OPTION_DEFAULT_SPECS, normally provided by the driver
2268 in the non-jit case.
2270 The target-specific code can define OPTION_DEFAULT_SPECS:
2271 default command options in the form of spec macros for the
2272 driver to expand ().
2274 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2275 if not overriden, injects the defaults as extra arguments to
2276 cc1 etc.
2277 For the jit case, we need to add these arguments here. The
2278 input format (using the specs language) means that we have to run
2279 part of the driver code here (driver_get_configure_time_options).
2281 To avoid running the spec-expansion code every time, we just do
2282 it the first time (via a function-static flag), saving the result
2283 into a function-static vec.
2284 This flag and vec are global state (i.e. per-process).
2285 They are guarded by the jit mutex. */
2287 static bool have_configure_time_options = false;
2288 static vec <char *> configure_time_options;
2290 if (have_configure_time_options)
2291 log ("reusing cached configure-time options");
2292 else
2294 have_configure_time_options = true;
2295 log ("getting configure-time options from driver");
2296 driver_get_configure_time_options (append_arg_from_driver,
2297 &configure_time_options);
2300 int i;
2301 char *opt;
2303 if (get_logger ())
2304 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2305 log ("configure_time_options[%i]: %s", i, opt);
2307 /* configure_time_options should now contain the expanded options
2308 from OPTION_DEFAULT_SPECS (if any). */
2309 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2311 gcc_assert (opt);
2312 gcc_assert (opt[0] == '-');
2313 ADD_ARG (opt);
2317 if (get_timer ())
2318 ADD_ARG ("-ftime-report");
2320 /* Add any user-provided extra options, starting with any from
2321 parent contexts. */
2322 m_recording_ctxt->append_command_line_options (argvec);
2324 #undef ADD_ARG
2325 #undef ADD_ARG_TAKE_OWNERSHIP
2328 /* The second half of the implementation of gcc_jit_context_enable_dump.
2329 Iterate through the requested dumps, reading the underlying files
2330 into heap-allocated buffers, writing pointers to the buffers into
2331 the char ** pointers provided by client code.
2332 Client code is responsible for calling free on the results. */
2334 void
2335 playback::context::
2336 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2338 JIT_LOG_SCOPE (get_logger ());
2340 int i;
2341 recording::requested_dump *d;
2342 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2344 dump_file_info *dfi;
2345 char *filename;
2346 char *content;
2348 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2349 if (!dfi)
2351 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2352 continue;
2355 filename = g->get_dumps ()->get_dump_file_name (dfi);
2356 content = read_dump_file (filename);
2357 *(d->m_out_ptr) = content;
2358 m_tempdir->add_temp_file (filename);
2362 /* Helper function for playback::context::extract_any_requested_dumps
2363 (itself for use in implementation of gcc_jit_context_enable_dump).
2365 Attempt to read the complete file at the given path, returning the
2366 bytes found there as a buffer.
2367 The caller is responsible for calling free on the result.
2368 Errors will be reported on the context, and lead to NULL being
2369 returned; an out-of-memory error will terminate the process. */
2371 char *
2372 playback::context::read_dump_file (const char *path)
2374 char *result = NULL;
2375 size_t total_sz = 0;
2376 char buf[4096];
2377 size_t sz;
2378 FILE *f_in;
2380 f_in = fopen (path, "r");
2381 if (!f_in)
2383 add_error (NULL, "unable to open %s for reading", path);
2384 return NULL;
2387 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2389 size_t old_total_sz = total_sz;
2390 total_sz += sz;
2391 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2392 memcpy (result + old_total_sz, buf, sz);
2395 if (!feof (f_in))
2397 add_error (NULL, "error reading from %s", path);
2398 free (result);
2399 fclose (f_in);
2400 return NULL;
2403 fclose (f_in);
2405 if (result)
2407 result[total_sz] = '\0';
2408 return result;
2410 else
2411 return xstrdup ("");
2414 /* Part of playback::context::compile ().
2416 We have a .s file; we want a .so file.
2417 We could reuse parts of gcc/gcc.c to do this.
2418 For now, just use the driver binary from the install, as
2419 named in gcc-driver-name.h
2420 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2422 void
2423 playback::context::
2424 convert_to_dso (const char *ctxt_progname)
2426 JIT_LOG_SCOPE (get_logger ());
2428 invoke_driver (ctxt_progname,
2429 m_tempdir->get_path_s_file (),
2430 m_tempdir->get_path_so_file (),
2431 TV_ASSEMBLE,
2432 true, /* bool shared, */
2433 true);/* bool run_linker */
2436 static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2438 void
2439 playback::context::
2440 invoke_driver (const char *ctxt_progname,
2441 const char *input_file,
2442 const char *output_file,
2443 timevar_id_t tv_id,
2444 bool shared,
2445 bool run_linker)
2447 JIT_LOG_SCOPE (get_logger ());
2449 bool embedded_driver
2450 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
2452 /* Currently this lumps together both assembling and linking into
2453 TV_ASSEMBLE. */
2454 auto_timevar assemble_timevar (get_timer (), tv_id);
2455 auto_argvec argvec;
2456 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2458 ADD_ARG (gcc_driver_name);
2460 add_multilib_driver_arguments (&argvec);
2462 if (shared)
2463 ADD_ARG ("-shared");
2465 if (!run_linker)
2466 ADD_ARG ("-c");
2468 ADD_ARG (input_file);
2469 ADD_ARG ("-o");
2470 ADD_ARG (output_file);
2472 /* Don't use the linker plugin.
2473 If running with just a "make" and not a "make install", then we'd
2474 run into
2475 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2476 libto_plugin is a .la at build time, with it becoming installed with
2477 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2478 time. */
2479 ADD_ARG ("-fno-use-linker-plugin");
2481 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2482 /* OS X's linker defaults to treating undefined symbols as errors.
2483 If the context has any imported functions or globals they will be
2484 undefined until the .so is dynamically-linked into the process.
2485 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2486 linker. */
2487 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2488 #endif
2490 if (0)
2491 ADD_ARG ("-v");
2493 #undef ADD_ARG
2495 /* pex_one's error-handling requires pname to be non-NULL. */
2496 gcc_assert (ctxt_progname);
2498 if (get_logger ())
2499 for (unsigned i = 0; i < argvec.length (); i++)
2500 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2502 if (embedded_driver)
2503 invoke_embedded_driver (&argvec);
2504 else
2505 invoke_external_driver (ctxt_progname, &argvec);
2508 void
2509 playback::context::
2510 invoke_embedded_driver (const vec <char *> *argvec)
2512 JIT_LOG_SCOPE (get_logger ());
2513 driver d (true, /* can_finalize */
2514 false); /* debug */
2515 int result = d.main (argvec->length (),
2516 const_cast <char **> (argvec->address ()));
2517 d.finalize ();
2518 if (result)
2519 add_error (NULL, "error invoking gcc driver");
2522 void
2523 playback::context::
2524 invoke_external_driver (const char *ctxt_progname,
2525 vec <char *> *argvec)
2527 JIT_LOG_SCOPE (get_logger ());
2528 const char *errmsg;
2529 int exit_status = 0;
2530 int err = 0;
2532 /* pex argv arrays are NULL-terminated. */
2533 argvec->safe_push (NULL);
2535 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2536 gcc_driver_name,
2537 const_cast <char *const *> (argvec->address ()),
2538 ctxt_progname, /* const char *pname */
2539 NULL, /* const char *outname */
2540 NULL, /* const char *errname */
2541 &exit_status, /* int *status */
2542 &err); /* int *err*/
2543 if (errmsg)
2545 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2546 return;
2549 /* pex_one can return a NULL errmsg when the executable wasn't
2550 found (or doesn't exist), so trap these cases also. */
2551 if (exit_status || err)
2553 add_error (NULL,
2554 "error invoking gcc driver: exit_status: %i err: %i",
2555 exit_status, err);
2556 add_error (NULL,
2557 "whilst attempting to run a driver named: %s",
2558 gcc_driver_name);
2559 add_error (NULL,
2560 "PATH was: %s",
2561 getenv ("PATH"));
2562 return;
2566 /* Extract the target-specific MULTILIB_DEFAULTS to
2567 multilib_defaults_raw for use by
2568 playback::context::add_multilib_driver_arguments (). */
2570 #ifndef MULTILIB_DEFAULTS
2571 #define MULTILIB_DEFAULTS { "" }
2572 #endif
2574 static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
2576 /* Helper function for playback::context::invoke_driver ().
2578 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2579 a driver binary. We need to pass in options to the shared driver
2580 to get the appropriate assembler/linker options for this multilib
2581 peer. */
2583 void
2584 playback::context::
2585 add_multilib_driver_arguments (vec <char *> *argvec)
2587 JIT_LOG_SCOPE (get_logger ());
2589 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2590 prepending each with a "-". */
2591 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
2592 if (multilib_defaults_raw[i][0])
2593 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
2596 /* Dynamically-link the built DSO file into this process, using dlopen.
2597 Wrap it up within a jit::result *, and return that.
2598 Return NULL if any errors occur, reporting them on this context. */
2600 result *
2601 playback::context::
2602 dlopen_built_dso ()
2604 JIT_LOG_SCOPE (get_logger ());
2605 auto_timevar load_timevar (get_timer (), TV_LOAD);
2606 void *handle = NULL;
2607 const char *error = NULL;
2608 result *result_obj = NULL;
2610 /* Clear any existing error. */
2611 dlerror ();
2613 handle = dlopen (m_tempdir->get_path_so_file (),
2614 RTLD_NOW | RTLD_LOCAL);
2615 if ((error = dlerror()) != NULL) {
2616 add_error (NULL, "%s", error);
2618 if (handle)
2620 /* We've successfully dlopened the result; create a
2621 jit::result object to wrap it.
2623 We're done with the tempdir for now, but if the user
2624 has requested debugging, the user's debugger might not
2625 be capable of dealing with the .so file being unlinked
2626 immediately, so keep it around until after the result
2627 is released. We do this by handing over ownership of
2628 the jit::tempdir to the result. See PR jit/64206. */
2629 tempdir *handover_tempdir;
2630 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2632 handover_tempdir = m_tempdir;
2633 m_tempdir = NULL;
2634 /* The tempdir will eventually be cleaned up in the
2635 jit::result's dtor. */
2636 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2637 " handing over tempdir to jit::result");
2639 else
2641 handover_tempdir = NULL;
2642 /* ... and retain ownership of m_tempdir so we clean it
2643 up it the playback::context's dtor. */
2644 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2645 " retaining ownership of tempdir");
2648 result_obj = new result (get_logger (), handle, handover_tempdir);
2650 else
2651 result_obj = NULL;
2653 return result_obj;
2656 /* Top-level hook for playing back a recording context.
2658 This plays back m_recording_ctxt, and, if no errors
2659 occurred builds statement lists for and then postprocesses
2660 every function in the result. */
2662 void
2663 playback::context::
2664 replay ()
2666 JIT_LOG_SCOPE (get_logger ());
2667 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2668 tree array_domain_type = build_index_type (size_int (200));
2669 m_char_array_type_node
2670 = build_array_type (char_type_node, array_domain_type);
2672 m_const_char_ptr
2673 = build_pointer_type (build_qualified_type (char_type_node,
2674 TYPE_QUAL_CONST));
2676 /* Replay the recorded events: */
2677 timevar_push (TV_JIT_REPLAY);
2679 m_recording_ctxt->replay_into (this);
2681 /* Clean away the temporary references from recording objects
2682 to playback objects. We have to do this now since the
2683 latter are GC-allocated, but the former don't mark these
2684 refs. Hence we must stop using them before the GC can run. */
2685 m_recording_ctxt->disassociate_from_playback ();
2687 /* The builtins_manager, if any, is associated with the recording::context
2688 and might be reused for future compiles on other playback::contexts,
2689 but its m_attributes array is not GTY-labeled and hence will become
2690 nonsense if the GC runs. Purge this state. */
2691 builtins_manager *bm = get_builtins_manager ();
2692 if (bm)
2693 bm->finish_playback ();
2695 timevar_pop (TV_JIT_REPLAY);
2697 if (!errors_occurred ())
2699 int i;
2700 function *func;
2702 /* No GC can happen yet; process the cached source locations. */
2703 handle_locations ();
2705 /* We've now created tree nodes for the stmts in the various blocks
2706 in each function, but we haven't built each function's single stmt
2707 list yet. Do so now. */
2708 FOR_EACH_VEC_ELT (m_functions, i, func)
2709 func->build_stmt_list ();
2711 /* No GC can have happened yet. */
2713 /* Postprocess the functions. This could trigger GC. */
2714 FOR_EACH_VEC_ELT (m_functions, i, func)
2716 gcc_assert (func);
2717 func->postprocess ();
2722 /* Dump the generated .s file to stderr. */
2724 void
2725 playback::context::
2726 dump_generated_code ()
2728 JIT_LOG_SCOPE (get_logger ());
2729 char buf[4096];
2730 size_t sz;
2731 FILE *f_in = fopen (get_path_s_file (), "r");
2732 if (!f_in)
2733 return;
2735 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2736 fwrite (buf, 1, sz, stderr);
2738 fclose (f_in);
2741 /* Get the supposed path of the notional "fake.c" file within the
2742 tempdir. This file doesn't exist, but the rest of the compiler
2743 needs a name. */
2745 const char *
2746 playback::context::
2747 get_path_c_file () const
2749 return m_tempdir->get_path_c_file ();
2752 /* Get the path of the assembler output file "fake.s" file within the
2753 tempdir. */
2755 const char *
2756 playback::context::
2757 get_path_s_file () const
2759 return m_tempdir->get_path_s_file ();
2762 /* Get the path of the DSO object file "fake.so" file within the
2763 tempdir. */
2765 const char *
2766 playback::context::
2767 get_path_so_file () const
2769 return m_tempdir->get_path_so_file ();
2772 /* qsort comparator for comparing pairs of playback::source_line *,
2773 ordering them by line number. */
2775 static int
2776 line_comparator (const void *lhs, const void *rhs)
2778 const playback::source_line *line_lhs = \
2779 *static_cast<const playback::source_line * const*> (lhs);
2780 const playback::source_line *line_rhs = \
2781 *static_cast<const playback::source_line * const*> (rhs);
2782 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2785 /* qsort comparator for comparing pairs of playback::location *,
2786 ordering them by column number. */
2788 static int
2789 location_comparator (const void *lhs, const void *rhs)
2791 const playback::location *loc_lhs = \
2792 *static_cast<const playback::location * const *> (lhs);
2793 const playback::location *loc_rhs = \
2794 *static_cast<const playback::location * const *> (rhs);
2795 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2798 /* Our API allows locations to be created in arbitrary orders, but the
2799 linemap API requires locations to be created in ascending order
2800 as if we were tokenizing files.
2802 This hook sorts all of the locations that have been created, and
2803 calls into the linemap API, creating linemap entries in sorted order
2804 for our locations. */
2806 void
2807 playback::context::
2808 handle_locations ()
2810 /* Create the source code locations, following the ordering rules
2811 imposed by the linemap API.
2813 line_table is a global. */
2814 JIT_LOG_SCOPE (get_logger ());
2815 int i;
2816 source_file *file;
2818 FOR_EACH_VEC_ELT (m_source_files, i, file)
2820 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2822 /* Sort lines by ascending line numbers. */
2823 file->m_source_lines.qsort (&line_comparator);
2825 int j;
2826 source_line *line;
2827 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2829 int k;
2830 location *loc;
2832 /* Sort locations in line by ascending column numbers. */
2833 line->m_locations.qsort (&location_comparator);
2835 /* Determine maximum column within this line. */
2836 gcc_assert (line->m_locations.length () > 0);
2837 location *final_column =
2838 line->m_locations[line->m_locations.length () - 1];
2839 int max_col = final_column->get_column_num ();
2841 linemap_line_start (line_table, line->get_line_num (), max_col);
2842 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2844 loc->m_srcloc = \
2845 linemap_position_for_column (line_table, loc->get_column_num ());
2849 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2852 /* line_table should now be populated; every playback::location should
2853 now have an m_srcloc. */
2855 /* Now assign them to tree nodes as appropriate. */
2856 std::pair<tree, location *> *cached_location;
2858 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2860 tree t = cached_location->first;
2861 source_location srcloc = cached_location->second->m_srcloc;
2863 /* This covers expressions: */
2864 if (CAN_HAVE_LOCATION_P (t))
2865 SET_EXPR_LOCATION (t, srcloc);
2866 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2867 DECL_SOURCE_LOCATION (t) = srcloc;
2868 else
2870 /* Don't know how to set location on this node. */
2875 /* We handle errors on a playback::context by adding them to the
2876 corresponding recording::context. */
2878 void
2879 playback::context::
2880 add_error (location *loc, const char *fmt, ...)
2882 va_list ap;
2883 va_start (ap, fmt);
2884 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2885 fmt, ap);
2886 va_end (ap);
2889 /* We handle errors on a playback::context by adding them to the
2890 corresponding recording::context. */
2892 void
2893 playback::context::
2894 add_error_va (location *loc, const char *fmt, va_list ap)
2896 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2897 fmt, ap);
2900 /* Report a diagnostic up to the jit context as an error,
2901 so that the compilation is treated as a failure.
2902 For now, any kind of diagnostic is treated as an error by the jit
2903 API. */
2905 void
2906 playback::context::
2907 add_diagnostic (struct diagnostic_context *diag_context,
2908 struct diagnostic_info *diagnostic)
2910 /* At this point the text has been formatted into the pretty-printer's
2911 output buffer. */
2912 pretty_printer *pp = diag_context->printer;
2913 const char *text = pp_formatted_text (pp);
2915 /* Get location information (if any) from the diagnostic.
2916 The recording::context::add_error[_va] methods require a
2917 recording::location. We can't lookup the playback::location
2918 from the file/line/column since any playback location instances
2919 may have been garbage-collected away by now, so instead we create
2920 another recording::location directly. */
2921 location_t gcc_loc = diagnostic_location (diagnostic);
2922 recording::location *rec_loc = NULL;
2923 if (gcc_loc)
2925 expanded_location exploc = expand_location (gcc_loc);
2926 if (exploc.file)
2927 rec_loc = m_recording_ctxt->new_location (exploc.file,
2928 exploc.line,
2929 exploc.column,
2930 false);
2933 m_recording_ctxt->add_error (rec_loc, "%s", text);
2934 pp_clear_output_area (pp);
2937 /* Dealing with the linemap API. */
2939 /* Construct a playback::location for a recording::location, if it
2940 doesn't exist already. */
2942 playback::location *
2943 playback::context::
2944 new_location (recording::location *rloc,
2945 const char *filename,
2946 int line,
2947 int column)
2949 /* Get the source_file for filename, creating if necessary. */
2950 source_file *src_file = get_source_file (filename);
2951 /* Likewise for the line within the file. */
2952 source_line *src_line = src_file->get_source_line (line);
2953 /* Likewise for the column within the line. */
2954 location *loc = src_line->get_location (rloc, column);
2955 return loc;
2958 /* Deferred setting of the location for a given tree, by adding the
2959 (tree, playback::location) pair to a list of deferred associations.
2960 We will actually set the location on the tree later on once
2961 the source_location for the playback::location exists. */
2963 void
2964 playback::context::
2965 set_tree_location (tree t, location *loc)
2967 gcc_assert (loc);
2968 m_cached_locations.safe_push (std::make_pair (t, loc));
2972 /* Construct a playback::source_file for the given source
2973 filename, if it doesn't exist already. */
2975 playback::source_file *
2976 playback::context::
2977 get_source_file (const char *filename)
2979 /* Locate the file.
2980 For simplicitly, this is currently a linear search.
2981 Replace with a hash if this shows up in the profile. */
2982 int i;
2983 source_file *file;
2984 tree ident_filename = get_identifier (filename);
2986 FOR_EACH_VEC_ELT (m_source_files, i, file)
2987 if (file->filename_as_tree () == ident_filename)
2988 return file;
2990 /* Not found. */
2991 file = new source_file (ident_filename);
2992 m_source_files.safe_push (file);
2993 return file;
2996 /* Constructor for gcc::jit::playback::source_file. */
2998 playback::source_file::source_file (tree filename) :
2999 m_source_lines (),
3000 m_filename (filename)
3004 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3005 GC-ed. */
3007 void
3008 playback::source_file::finalizer ()
3010 m_source_lines.release ();
3013 /* Construct a playback::source_line for the given line
3014 within this source file, if one doesn't exist already. */
3016 playback::source_line *
3017 playback::source_file::
3018 get_source_line (int line_num)
3020 /* Locate the line.
3021 For simplicitly, this is currently a linear search.
3022 Replace with a hash if this shows up in the profile. */
3023 int i;
3024 source_line *line;
3026 FOR_EACH_VEC_ELT (m_source_lines, i, line)
3027 if (line->get_line_num () == line_num)
3028 return line;
3030 /* Not found. */
3031 line = new source_line (this, line_num);
3032 m_source_lines.safe_push (line);
3033 return line;
3036 /* Constructor for gcc::jit::playback::source_line. */
3038 playback::source_line::source_line (source_file *file, int line_num) :
3039 m_locations (),
3040 m_source_file (file),
3041 m_line_num (line_num)
3045 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3046 GC-ed. */
3048 void
3049 playback::source_line::finalizer ()
3051 m_locations.release ();
3054 /* Construct a playback::location for the given column
3055 within this line of a specific source file, if one doesn't exist
3056 already. */
3058 playback::location *
3059 playback::source_line::
3060 get_location (recording::location *rloc, int column_num)
3062 int i;
3063 location *loc;
3065 /* Another linear search that probably should be a hash table. */
3066 FOR_EACH_VEC_ELT (m_locations, i, loc)
3067 if (loc->get_column_num () == column_num)
3068 return loc;
3070 /* Not found. */
3071 loc = new location (rloc, this, column_num);
3072 m_locations.safe_push (loc);
3073 return loc;
3076 /* Constructor for gcc::jit::playback::location. */
3078 playback::location::location (recording::location *loc,
3079 source_line *line,
3080 int column_num) :
3081 m_srcloc (UNKNOWN_LOCATION),
3082 m_recording_loc (loc),
3083 m_line (line),
3084 m_column_num(column_num)
3088 /* The active gcc::jit::playback::context instance. This is a singleton,
3089 guarded by jit_mutex. */
3091 playback::context *active_playback_ctxt;
3093 } // namespace gcc::jit
3095 } // namespace gcc