Remove unused variable
[official-gcc.git] / gcc / jit / jit-playback.c
blob258ebe8ef86f035a087875198ede880a394a6d86
1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2018 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "target.h"
25 #include "tree.h"
26 #include "stringpool.h"
27 #include "cgraph.h"
28 #include "dumpfile.h"
29 #include "toplev.h"
30 #include "tree-cfg.h"
31 #include "convert.h"
32 #include "stor-layout.h"
33 #include "print-tree.h"
34 #include "gimplify.h"
35 #include "gcc-driver-name.h"
36 #include "attribs.h"
37 #include "context.h"
38 #include "fold-const.h"
39 #include "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 (type_node == NULL)
216 add_error (NULL, "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 /* Construct a playback::rvalue instance (wrapping a tree) for a
632 vector. */
634 playback::rvalue *
635 playback::context::new_rvalue_from_vector (location *,
636 type *type,
637 const auto_vec<rvalue *> &elements)
639 vec<constructor_elt, va_gc> *v;
640 vec_alloc (v, elements.length ());
641 for (unsigned i = 0; i < elements.length (); ++i)
642 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
643 tree t_ctor = build_constructor (type->as_tree (), v);
644 return new rvalue (this, t_ctor);
647 /* Coerce a tree expression into a boolean tree expression. */
649 tree
650 playback::context::
651 as_truth_value (tree expr, location *loc)
653 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
654 tree typed_zero = fold_build1 (CONVERT_EXPR,
655 TREE_TYPE (expr),
656 integer_zero_node);
657 if (loc)
658 set_tree_location (typed_zero, loc);
660 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
661 if (loc)
662 set_tree_location (expr, loc);
664 return expr;
667 /* Construct a playback::rvalue instance (wrapping a tree) for a
668 unary op. */
670 playback::rvalue *
671 playback::context::
672 new_unary_op (location *loc,
673 enum gcc_jit_unary_op op,
674 type *result_type,
675 rvalue *a)
677 // FIXME: type-checking, or coercion?
678 enum tree_code inner_op;
680 gcc_assert (result_type);
681 gcc_assert (a);
683 tree node = a->as_tree ();
684 tree inner_result = NULL;
686 switch (op)
688 default:
689 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
690 return NULL;
692 case GCC_JIT_UNARY_OP_MINUS:
693 inner_op = NEGATE_EXPR;
694 break;
696 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
697 inner_op = BIT_NOT_EXPR;
698 break;
700 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
701 node = as_truth_value (node, loc);
702 inner_result = invert_truthvalue (node);
703 if (loc)
704 set_tree_location (inner_result, loc);
705 return new rvalue (this, inner_result);
707 case GCC_JIT_UNARY_OP_ABS:
708 inner_op = ABS_EXPR;
709 break;
712 inner_result = build1 (inner_op,
713 result_type->as_tree (),
714 node);
715 if (loc)
716 set_tree_location (inner_result, loc);
718 return new rvalue (this, inner_result);
721 /* Construct a playback::rvalue instance (wrapping a tree) for a
722 binary op. */
724 playback::rvalue *
725 playback::context::
726 new_binary_op (location *loc,
727 enum gcc_jit_binary_op op,
728 type *result_type,
729 rvalue *a, rvalue *b)
731 // FIXME: type-checking, or coercion?
732 enum tree_code inner_op;
734 gcc_assert (result_type);
735 gcc_assert (a);
736 gcc_assert (b);
738 tree node_a = a->as_tree ();
739 tree node_b = b->as_tree ();
741 switch (op)
743 default:
744 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
745 return NULL;
747 case GCC_JIT_BINARY_OP_PLUS:
748 inner_op = PLUS_EXPR;
749 break;
751 case GCC_JIT_BINARY_OP_MINUS:
752 inner_op = MINUS_EXPR;
753 break;
755 case GCC_JIT_BINARY_OP_MULT:
756 inner_op = MULT_EXPR;
757 break;
759 case GCC_JIT_BINARY_OP_DIVIDE:
760 if (FLOAT_TYPE_P (result_type->as_tree ()))
761 /* Floating-point division: */
762 inner_op = RDIV_EXPR;
763 else
764 /* Truncating to zero: */
765 inner_op = TRUNC_DIV_EXPR;
766 break;
768 case GCC_JIT_BINARY_OP_MODULO:
769 inner_op = TRUNC_MOD_EXPR;
770 break;
772 case GCC_JIT_BINARY_OP_BITWISE_AND:
773 inner_op = BIT_AND_EXPR;
774 break;
776 case GCC_JIT_BINARY_OP_BITWISE_XOR:
777 inner_op = BIT_XOR_EXPR;
778 break;
780 case GCC_JIT_BINARY_OP_BITWISE_OR:
781 inner_op = BIT_IOR_EXPR;
782 break;
784 case GCC_JIT_BINARY_OP_LOGICAL_AND:
785 node_a = as_truth_value (node_a, loc);
786 node_b = as_truth_value (node_b, loc);
787 inner_op = TRUTH_ANDIF_EXPR;
788 break;
790 case GCC_JIT_BINARY_OP_LOGICAL_OR:
791 node_a = as_truth_value (node_a, loc);
792 node_b = as_truth_value (node_b, loc);
793 inner_op = TRUTH_ORIF_EXPR;
794 break;
796 case GCC_JIT_BINARY_OP_LSHIFT:
797 inner_op = LSHIFT_EXPR;
798 break;
800 case GCC_JIT_BINARY_OP_RSHIFT:
801 inner_op = RSHIFT_EXPR;
802 break;
805 tree inner_expr = build2 (inner_op,
806 result_type->as_tree (),
807 node_a,
808 node_b);
809 if (loc)
810 set_tree_location (inner_expr, loc);
812 return new rvalue (this, inner_expr);
815 /* Construct a playback::rvalue instance (wrapping a tree) for a
816 comparison. */
818 playback::rvalue *
819 playback::context::
820 new_comparison (location *loc,
821 enum gcc_jit_comparison op,
822 rvalue *a, rvalue *b)
824 // FIXME: type-checking, or coercion?
825 enum tree_code inner_op;
827 gcc_assert (a);
828 gcc_assert (b);
830 switch (op)
832 default:
833 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
834 return NULL;
836 case GCC_JIT_COMPARISON_EQ:
837 inner_op = EQ_EXPR;
838 break;
839 case GCC_JIT_COMPARISON_NE:
840 inner_op = NE_EXPR;
841 break;
842 case GCC_JIT_COMPARISON_LT:
843 inner_op = LT_EXPR;
844 break;
845 case GCC_JIT_COMPARISON_LE:
846 inner_op = LE_EXPR;
847 break;
848 case GCC_JIT_COMPARISON_GT:
849 inner_op = GT_EXPR;
850 break;
851 case GCC_JIT_COMPARISON_GE:
852 inner_op = GE_EXPR;
853 break;
856 tree inner_expr = build2 (inner_op,
857 boolean_type_node,
858 a->as_tree (),
859 b->as_tree ());
860 if (loc)
861 set_tree_location (inner_expr, loc);
862 return new rvalue (this, inner_expr);
865 /* Construct a playback::rvalue instance (wrapping a tree) for a
866 function call. */
868 playback::rvalue *
869 playback::context::
870 build_call (location *loc,
871 tree fn_ptr,
872 const auto_vec<rvalue *> *args,
873 bool require_tail_call)
875 vec<tree, va_gc> *tree_args;
876 vec_alloc (tree_args, args->length ());
877 for (unsigned i = 0; i < args->length (); i++)
878 tree_args->quick_push ((*args)[i]->as_tree ());
880 if (loc)
881 set_tree_location (fn_ptr, loc);
883 tree fn = TREE_TYPE (fn_ptr);
884 tree fn_type = TREE_TYPE (fn);
885 tree return_type = TREE_TYPE (fn_type);
887 tree call = build_call_vec (return_type,
888 fn_ptr, tree_args);
890 if (require_tail_call)
891 CALL_EXPR_MUST_TAIL_CALL (call) = 1;
893 return new rvalue (this, call);
895 /* see c-typeck.c: build_function_call
896 which calls build_function_call_vec
898 which does lots of checking, then:
899 result = build_call_array_loc (loc, TREE_TYPE (fntype),
900 function, nargs, argarray);
901 which is in tree.c
902 (see also build_call_vec)
906 /* Construct a playback::rvalue instance (wrapping a tree) for a
907 call to a specific function. */
909 playback::rvalue *
910 playback::context::
911 new_call (location *loc,
912 function *func,
913 const auto_vec<rvalue *> *args,
914 bool require_tail_call)
916 tree fndecl;
918 gcc_assert (func);
920 fndecl = func->as_fndecl ();
922 tree fntype = TREE_TYPE (fndecl);
924 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
926 return build_call (loc, fn, args, require_tail_call);
929 /* Construct a playback::rvalue instance (wrapping a tree) for a
930 call through a function pointer. */
932 playback::rvalue *
933 playback::context::
934 new_call_through_ptr (location *loc,
935 rvalue *fn_ptr,
936 const auto_vec<rvalue *> *args,
937 bool require_tail_call)
939 gcc_assert (fn_ptr);
940 tree t_fn_ptr = fn_ptr->as_tree ();
942 return build_call (loc, t_fn_ptr, args, require_tail_call);
945 /* Construct a tree for a cast. */
947 tree
948 playback::context::build_cast (playback::location *loc,
949 playback::rvalue *expr,
950 playback::type *type_)
952 /* For comparison, see:
953 - c/c-typeck.c:build_c_cast
954 - c/c-convert.c: convert
955 - convert.h
957 Only some kinds of cast are currently supported here. */
958 tree t_expr = expr->as_tree ();
959 tree t_dst_type = type_->as_tree ();
960 tree t_ret = NULL;
961 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
962 if (t_ret)
963 return t_ret;
964 enum tree_code dst_code = TREE_CODE (t_dst_type);
965 switch (dst_code)
967 case INTEGER_TYPE:
968 case ENUMERAL_TYPE:
969 t_ret = convert_to_integer (t_dst_type, t_expr);
970 goto maybe_fold;
972 case BOOLEAN_TYPE:
973 /* Compare with c_objc_common_truthvalue_conversion and
974 c_common_truthvalue_conversion. */
975 /* For now, convert to: (t_expr != 0) */
976 t_ret = build2 (NE_EXPR, t_dst_type,
977 t_expr,
978 build_int_cst (TREE_TYPE (t_expr), 0));
979 goto maybe_fold;
981 case REAL_TYPE:
982 t_ret = convert_to_real (t_dst_type, t_expr);
983 goto maybe_fold;
985 case POINTER_TYPE:
986 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
987 goto maybe_fold;
989 default:
990 add_error (loc, "couldn't handle cast during playback");
991 fprintf (stderr, "input expression:\n");
992 debug_tree (t_expr);
993 fprintf (stderr, "requested type:\n");
994 debug_tree (t_dst_type);
995 return error_mark_node;
997 maybe_fold:
998 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
999 t_ret = fold (t_ret);
1000 return t_ret;
1004 /* Construct a playback::rvalue instance (wrapping a tree) for a
1005 cast. */
1007 playback::rvalue *
1008 playback::context::
1009 new_cast (playback::location *loc,
1010 playback::rvalue *expr,
1011 playback::type *type_)
1014 tree t_cast = build_cast (loc, expr, type_);
1015 if (loc)
1016 set_tree_location (t_cast, loc);
1017 return new rvalue (this, t_cast);
1020 /* Construct a playback::lvalue instance (wrapping a tree) for an
1021 array access. */
1023 playback::lvalue *
1024 playback::context::
1025 new_array_access (location *loc,
1026 rvalue *ptr,
1027 rvalue *index)
1029 gcc_assert (ptr);
1030 gcc_assert (index);
1032 /* For comparison, see:
1033 c/c-typeck.c: build_array_ref
1034 c-family/c-common.c: pointer_int_sum
1036 tree t_ptr = ptr->as_tree ();
1037 tree t_index = index->as_tree ();
1038 tree t_type_ptr = TREE_TYPE (t_ptr);
1039 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1041 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1043 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1044 NULL_TREE, NULL_TREE);
1045 if (loc)
1046 set_tree_location (t_result, loc);
1047 return new lvalue (this, t_result);
1049 else
1051 /* Convert index to an offset in bytes. */
1052 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1053 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1054 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
1056 /* Locate (ptr + offset). */
1057 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1059 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1060 if (loc)
1062 set_tree_location (t_sizeof, loc);
1063 set_tree_location (t_offset, loc);
1064 set_tree_location (t_address, loc);
1065 set_tree_location (t_indirection, loc);
1068 return new lvalue (this, t_indirection);
1072 /* Construct a tree for a field access. */
1074 tree
1075 playback::context::
1076 new_field_access (location *loc,
1077 tree datum,
1078 field *field)
1080 gcc_assert (datum);
1081 gcc_assert (field);
1083 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1084 build_component_ref. */
1085 tree type = TREE_TYPE (datum);
1086 gcc_assert (type);
1087 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1089 tree t_field = field->as_tree ();
1090 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1091 t_field, NULL_TREE);
1092 if (loc)
1093 set_tree_location (ref, loc);
1094 return ref;
1097 /* Construct a tree for a dereference. */
1099 tree
1100 playback::context::
1101 new_dereference (tree ptr,
1102 location *loc)
1104 gcc_assert (ptr);
1106 tree type = TREE_TYPE (TREE_TYPE(ptr));
1107 tree datum = build1 (INDIRECT_REF, type, ptr);
1108 if (loc)
1109 set_tree_location (datum, loc);
1110 return datum;
1113 /* Construct a playback::type instance (wrapping a tree)
1114 with the given alignment. */
1116 playback::type *
1117 playback::type::
1118 get_aligned (size_t alignment_in_bytes) const
1120 tree t_new_type = build_variant_type_copy (m_inner);
1122 SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT);
1123 TYPE_USER_ALIGN (t_new_type) = 1;
1125 return new type (t_new_type);
1128 /* Construct a playback::type instance (wrapping a tree)
1129 for the given vector type. */
1131 playback::type *
1132 playback::type::
1133 get_vector (size_t num_units) const
1135 tree t_new_type = build_vector_type (m_inner, num_units);
1136 return new type (t_new_type);
1139 /* Construct a playback::lvalue instance (wrapping a tree) for a
1140 field access. */
1142 playback::lvalue *
1143 playback::lvalue::
1144 access_field (location *loc,
1145 field *field)
1147 tree datum = as_tree ();
1148 tree ref = get_context ()->new_field_access (loc, datum, field);
1149 if (!ref)
1150 return NULL;
1151 return new lvalue (get_context (), ref);
1154 /* Construct a playback::rvalue instance (wrapping a tree) for a
1155 field access. */
1157 playback::rvalue *
1158 playback::rvalue::
1159 access_field (location *loc,
1160 field *field)
1162 tree datum = as_tree ();
1163 tree ref = get_context ()->new_field_access (loc, datum, field);
1164 if (!ref)
1165 return NULL;
1166 return new rvalue (get_context (), ref);
1169 /* Construct a playback::lvalue instance (wrapping a tree) for a
1170 dereferenced field access. */
1172 playback::lvalue *
1173 playback::rvalue::
1174 dereference_field (location *loc,
1175 field *field)
1177 tree ptr = as_tree ();
1178 tree datum = get_context ()->new_dereference (ptr, loc);
1179 if (!datum)
1180 return NULL;
1181 tree ref = get_context ()->new_field_access (loc, datum, field);
1182 if (!ref)
1183 return NULL;
1184 return new lvalue (get_context (), ref);
1187 /* Construct a playback::lvalue instance (wrapping a tree) for a
1188 dereference. */
1190 playback::lvalue *
1191 playback::rvalue::
1192 dereference (location *loc)
1194 tree ptr = as_tree ();
1195 tree datum = get_context ()->new_dereference (ptr, loc);
1196 return new lvalue (get_context (), datum);
1199 /* Mark EXP saying that we need to be able to take the
1200 address of it; it should not be allocated in a register.
1201 Compare with e.g. c/c-typeck.c: c_mark_addressable. */
1203 static void
1204 jit_mark_addressable (tree exp)
1206 tree x = exp;
1208 while (1)
1209 switch (TREE_CODE (x))
1211 case COMPONENT_REF:
1212 /* (we don't yet support bitfields) */
1213 /* fallthrough */
1214 case ADDR_EXPR:
1215 case ARRAY_REF:
1216 case REALPART_EXPR:
1217 case IMAGPART_EXPR:
1218 x = TREE_OPERAND (x, 0);
1219 break;
1221 case COMPOUND_LITERAL_EXPR:
1222 case CONSTRUCTOR:
1223 TREE_ADDRESSABLE (x) = 1;
1224 return;
1226 case VAR_DECL:
1227 case CONST_DECL:
1228 case PARM_DECL:
1229 case RESULT_DECL:
1230 /* (we don't have a concept of a "register" declaration) */
1231 /* fallthrough */
1232 case FUNCTION_DECL:
1233 TREE_ADDRESSABLE (x) = 1;
1234 /* fallthrough */
1235 default:
1236 return;
1240 /* Construct a playback::rvalue instance (wrapping a tree) for an
1241 address-lookup. */
1243 playback::rvalue *
1244 playback::lvalue::
1245 get_address (location *loc)
1247 tree t_lvalue = as_tree ();
1248 tree t_thistype = TREE_TYPE (t_lvalue);
1249 tree t_ptrtype = build_pointer_type (t_thistype);
1250 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1251 if (loc)
1252 get_context ()->set_tree_location (ptr, loc);
1253 jit_mark_addressable (t_lvalue);
1254 return new rvalue (get_context (), ptr);
1257 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1258 Provide this finalization hook for calling then they are collected,
1259 which calls the finalizer vfunc. This allows them to call "release"
1260 on any vec<> within them. */
1262 static void
1263 wrapper_finalizer (void *ptr)
1265 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1266 wrapper->finalizer ();
1269 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1270 allocate them using ggc_internal_cleared_alloc. */
1272 void *
1273 playback::wrapper::
1274 operator new (size_t sz)
1276 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1280 /* Constructor for gcc:jit::playback::function. */
1282 playback::function::
1283 function (context *ctxt,
1284 tree fndecl,
1285 enum gcc_jit_function_kind kind)
1286 : m_ctxt(ctxt),
1287 m_inner_fndecl (fndecl),
1288 m_inner_bind_expr (NULL),
1289 m_kind (kind)
1291 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1293 /* Create a BIND_EXPR, and within it, a statement list. */
1294 m_stmt_list = alloc_stmt_list ();
1295 m_stmt_iter = tsi_start (m_stmt_list);
1296 m_inner_block = make_node (BLOCK);
1297 m_inner_bind_expr =
1298 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1300 else
1302 m_inner_block = NULL;
1303 m_stmt_list = NULL;
1307 /* Hand-written GC-marking hook for playback functions. */
1309 void
1310 playback::function::
1311 gt_ggc_mx ()
1313 gt_ggc_m_9tree_node (m_inner_fndecl);
1314 gt_ggc_m_9tree_node (m_inner_bind_expr);
1315 gt_ggc_m_9tree_node (m_stmt_list);
1316 gt_ggc_m_9tree_node (m_inner_block);
1319 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1320 GC-ed. */
1322 void
1323 playback::function::finalizer ()
1325 m_blocks.release ();
1328 /* Get the return type of a playback function, in tree form. */
1330 tree
1331 playback::function::
1332 get_return_type_as_tree () const
1334 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1337 /* Construct a new local within this playback::function. */
1339 playback::lvalue *
1340 playback::function::
1341 new_local (location *loc,
1342 type *type,
1343 const char *name)
1345 gcc_assert (type);
1346 gcc_assert (name);
1347 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1348 get_identifier (name),
1349 type->as_tree ());
1350 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1352 /* Prepend to BIND_EXPR_VARS: */
1353 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1354 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1356 if (loc)
1357 set_tree_location (inner, loc);
1358 return new lvalue (m_ctxt, inner);
1361 /* Construct a new block within this playback::function. */
1363 playback::block *
1364 playback::function::
1365 new_block (const char *name)
1367 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1369 block *result = new playback::block (this, name);
1370 m_blocks.safe_push (result);
1371 return result;
1374 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1375 this playback::function. */
1377 playback::rvalue *
1378 playback::function::get_address (location *loc)
1380 tree t_fndecl = as_fndecl ();
1381 tree t_fntype = TREE_TYPE (t_fndecl);
1382 tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
1383 if (loc)
1384 m_ctxt->set_tree_location (t_fnptr, loc);
1385 return new rvalue (m_ctxt, t_fnptr);
1388 /* Build a statement list for the function as a whole out of the
1389 lists of statements for the individual blocks, building labels
1390 for each block. */
1392 void
1393 playback::function::
1394 build_stmt_list ()
1396 int i;
1397 block *b;
1399 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1401 FOR_EACH_VEC_ELT (m_blocks, i, b)
1403 int j;
1404 tree stmt;
1406 b->m_label_expr = build1 (LABEL_EXPR,
1407 void_type_node,
1408 b->as_label_decl ());
1409 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1411 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1412 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1416 /* Finish compiling the given function, potentially running the
1417 garbage-collector.
1418 The function will have a statement list by now.
1419 Amongst other things, this gimplifies the statement list,
1420 and calls cgraph_node::finalize_function on the function. */
1422 void
1423 playback::function::
1424 postprocess ()
1426 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1428 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1429 debug_tree (m_stmt_list);
1431 /* Do we need this to force cgraphunit.c to output the function? */
1432 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1434 DECL_EXTERNAL (m_inner_fndecl) = 0;
1435 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1438 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1439 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1441 DECL_EXTERNAL (m_inner_fndecl) = 0;
1442 TREE_PUBLIC (m_inner_fndecl) = 0;
1445 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1447 /* Seem to need this in gimple-low.c: */
1448 gcc_assert (m_inner_block);
1449 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1451 /* how to add to function? the following appears to be how to
1452 set the body of a m_inner_fndecl: */
1453 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1455 /* Ensure that locals appear in the debuginfo. */
1456 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1458 //debug_tree (m_inner_fndecl);
1460 /* Convert to gimple: */
1461 //printf("about to gimplify_function_tree\n");
1462 gimplify_function_tree (m_inner_fndecl);
1463 //printf("finished gimplify_function_tree\n");
1465 current_function_decl = m_inner_fndecl;
1466 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1467 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1468 //debug_tree (m_inner_fndecl);
1470 //printf("about to add to cgraph\n");
1471 /* Add to cgraph: */
1472 cgraph_node::finalize_function (m_inner_fndecl, false);
1473 /* This can trigger a collection, so we need to have all of
1474 the funcs as roots. */
1476 current_function_decl = NULL;
1480 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1481 GC-ed. */
1483 void
1484 playback::block::finalizer ()
1486 m_stmts.release ();
1489 /* Add an eval of the rvalue to the function's statement list. */
1491 void
1492 playback::block::
1493 add_eval (location *loc,
1494 rvalue *rvalue)
1496 gcc_assert (rvalue);
1498 if (loc)
1499 set_tree_location (rvalue->as_tree (), loc);
1501 add_stmt (rvalue->as_tree ());
1504 /* Add an assignment to the function's statement list. */
1506 void
1507 playback::block::
1508 add_assignment (location *loc,
1509 lvalue *lvalue,
1510 rvalue *rvalue)
1512 gcc_assert (lvalue);
1513 gcc_assert (rvalue);
1515 tree t_lvalue = lvalue->as_tree ();
1516 tree t_rvalue = rvalue->as_tree ();
1517 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1519 t_rvalue = build1 (CONVERT_EXPR,
1520 TREE_TYPE (t_lvalue),
1521 t_rvalue);
1522 if (loc)
1523 set_tree_location (t_rvalue, loc);
1526 tree stmt =
1527 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1528 t_lvalue, t_rvalue);
1529 if (loc)
1530 set_tree_location (stmt, loc);
1531 add_stmt (stmt);
1534 /* Add a comment to the function's statement list.
1535 For now this is done by adding a dummy label. */
1537 void
1538 playback::block::
1539 add_comment (location *loc,
1540 const char *text)
1542 /* Wrap the text in C-style comment delimiters. */
1543 size_t sz =
1544 (3 /* opening delim */
1545 + strlen (text)
1546 + 3 /* closing delim */
1547 + 1 /* terminator */);
1548 char *wrapped = (char *)ggc_internal_alloc (sz);
1549 snprintf (wrapped, sz, "/* %s */", text);
1551 /* For now we simply implement this by adding a dummy label with a name
1552 containing the given text. */
1553 tree identifier = get_identifier (wrapped);
1554 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1555 identifier, void_type_node);
1556 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1558 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1559 if (loc)
1560 set_tree_location (label_expr, loc);
1561 add_stmt (label_expr);
1564 /* Add a conditional jump statement to the function's statement list. */
1566 void
1567 playback::block::
1568 add_conditional (location *loc,
1569 rvalue *boolval,
1570 block *on_true,
1571 block *on_false)
1573 gcc_assert (boolval);
1574 gcc_assert (on_true);
1575 gcc_assert (on_false);
1577 /* COND_EXPR wants statement lists for the true/false operands, but we
1578 want labels.
1579 Shim it by creating jumps to the labels */
1580 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1581 on_true->as_label_decl ());
1582 if (loc)
1583 set_tree_location (true_jump, loc);
1585 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1586 on_false->as_label_decl ());
1587 if (loc)
1588 set_tree_location (false_jump, loc);
1590 tree stmt =
1591 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1592 true_jump, false_jump);
1593 if (loc)
1594 set_tree_location (stmt, loc);
1595 add_stmt (stmt);
1598 /* Add an unconditional jump statement to the function's statement list. */
1600 void
1601 playback::block::
1602 add_jump (location *loc,
1603 block *target)
1605 gcc_assert (target);
1607 // see c_finish_loop
1608 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1609 //add_stmt (top);
1611 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1612 TREE_USED (target->as_label_decl ()) = 1;
1613 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1614 if (loc)
1615 set_tree_location (stmt, loc);
1616 add_stmt (stmt);
1619 from c-typeck.c:
1620 tree
1621 c_finish_goto_label (location_t loc, tree label)
1623 tree decl = lookup_label_for_goto (loc, label);
1624 if (!decl)
1625 return NULL_TREE;
1626 TREE_USED (decl) = 1;
1628 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1629 SET_EXPR_LOCATION (t, loc);
1630 return add_stmt (t);
1637 /* Add a return statement to the function's statement list. */
1639 void
1640 playback::block::
1641 add_return (location *loc,
1642 rvalue *rvalue)
1644 tree modify_retval = NULL;
1645 tree return_type = m_func->get_return_type_as_tree ();
1646 if (rvalue)
1648 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1649 tree t_rvalue = rvalue->as_tree ();
1650 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1651 t_rvalue = build1 (CONVERT_EXPR,
1652 TREE_TYPE (t_lvalue),
1653 t_rvalue);
1654 modify_retval = build2 (MODIFY_EXPR, return_type,
1655 t_lvalue, t_rvalue);
1656 if (loc)
1657 set_tree_location (modify_retval, loc);
1659 tree return_stmt = build1 (RETURN_EXPR, return_type,
1660 modify_retval);
1661 if (loc)
1662 set_tree_location (return_stmt, loc);
1664 add_stmt (return_stmt);
1667 /* Helper function for playback::block::add_switch.
1668 Construct a case label for the given range, followed by a goto stmt
1669 to the given block, appending them to stmt list *ptr_t_switch_body. */
1671 static void
1672 add_case (tree *ptr_t_switch_body,
1673 tree t_low_value,
1674 tree t_high_value,
1675 playback::block *dest_block)
1677 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
1678 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
1680 tree t_case_label =
1681 build_case_label (t_low_value, t_high_value, t_label);
1682 append_to_statement_list (t_case_label, ptr_t_switch_body);
1684 tree t_goto_stmt =
1685 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
1686 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
1689 /* Add a switch statement to the function's statement list.
1691 We create a switch body, and populate it with case labels, each
1692 followed by a goto to the desired block. */
1694 void
1695 playback::block::
1696 add_switch (location *loc,
1697 rvalue *expr,
1698 block *default_block,
1699 const auto_vec <case_> *cases)
1701 /* Compare with:
1702 - c/c-typeck.c: c_start_case
1703 - c-family/c-common.c:c_add_case_label
1704 - java/expr.c:expand_java_switch and expand_java_add_case
1705 We've already rejected overlaps and duplicates in
1706 libgccjit.c:case_range_validator::validate. */
1708 tree t_expr = expr->as_tree ();
1709 tree t_type = TREE_TYPE (t_expr);
1711 tree t_switch_body = alloc_stmt_list ();
1713 int i;
1714 case_ *c;
1715 FOR_EACH_VEC_ELT (*cases, i, c)
1717 tree t_low_value = c->m_min_value->as_tree ();
1718 tree t_high_value = c->m_max_value->as_tree ();
1719 add_case (&t_switch_body, t_low_value, t_high_value, c->m_dest_block);
1721 /* Default label. */
1722 add_case (&t_switch_body, NULL_TREE, NULL_TREE, default_block);
1724 tree switch_stmt = build2 (SWITCH_EXPR, t_type, t_expr, t_switch_body);
1725 if (loc)
1726 set_tree_location (switch_stmt, loc);
1727 add_stmt (switch_stmt);
1730 /* Constructor for gcc::jit::playback::block. */
1732 playback::block::
1733 block (function *func,
1734 const char *name)
1735 : m_func (func),
1736 m_stmts ()
1738 tree identifier;
1740 gcc_assert (func);
1741 // name can be NULL
1742 if (name)
1743 identifier = get_identifier (name);
1744 else
1745 identifier = NULL;
1746 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1747 identifier, void_type_node);
1748 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1749 m_label_expr = NULL;
1752 /* A subclass of auto_vec <char *> that frees all of its elements on
1753 deletion. */
1755 class auto_argvec : public auto_vec <char *>
1757 public:
1758 ~auto_argvec ();
1761 /* auto_argvec's dtor, freeing all contained strings, automatically
1762 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1764 auto_argvec::~auto_argvec ()
1766 int i;
1767 char *str;
1768 FOR_EACH_VEC_ELT (*this, i, str)
1769 free (str);
1772 /* Compile a playback::context:
1774 - Use the context's options to cconstruct command-line options, and
1775 call into the rest of GCC (toplev::main).
1776 - Assuming it succeeds, we have a .s file.
1777 - We then run the "postprocess" vfunc:
1779 (A) In-memory compile ("gcc_jit_context_compile")
1781 For an in-memory compile we have the playback::compile_to_memory
1782 subclass; "postprocess" will convert the .s file to a .so DSO,
1783 and load it in memory (via dlopen), wrapping the result up as
1784 a jit::result and returning it.
1786 (B) Compile to file ("gcc_jit_context_compile_to_file")
1788 When compiling to a file, we have the playback::compile_to_file
1789 subclass; "postprocess" will either copy the .s file to the
1790 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1791 the driver to convert it as necessary, copying the result. */
1793 void
1794 playback::context::
1795 compile ()
1797 JIT_LOG_SCOPE (get_logger ());
1799 const char *ctxt_progname;
1801 int keep_intermediates =
1802 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
1804 m_tempdir = new tempdir (get_logger (), keep_intermediates);
1805 if (!m_tempdir->create ())
1806 return;
1808 /* Call into the rest of gcc.
1809 For now, we have to assemble command-line options to pass into
1810 toplev::main, so that they can be parsed. */
1812 /* Pass in user-provided program name as argv0, if any, so that it
1813 makes it into GCC's "progname" global, used in various diagnostics. */
1814 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1816 if (!ctxt_progname)
1817 ctxt_progname = "libgccjit.so";
1819 auto_vec <recording::requested_dump> requested_dumps;
1820 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1822 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1823 acquire_mutex ();
1825 auto_argvec fake_args;
1826 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
1827 if (errors_occurred ())
1829 release_mutex ();
1830 return;
1833 /* This runs the compiler. */
1834 toplev toplev (get_timer (), /* external_timer */
1835 false); /* init_signals */
1836 enter_scope ("toplev::main");
1837 if (get_logger ())
1838 for (unsigned i = 0; i < fake_args.length (); i++)
1839 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
1840 toplev.main (fake_args.length (),
1841 const_cast <char **> (fake_args.address ()));
1842 exit_scope ("toplev::main");
1844 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1845 need to do it between toplev::main (which creates the dump manager)
1846 and toplev::finalize (which deletes it). */
1847 extract_any_requested_dumps (&requested_dumps);
1849 /* Clean up the compiler. */
1850 enter_scope ("toplev::finalize");
1851 toplev.finalize ();
1852 exit_scope ("toplev::finalize");
1854 /* Ideally we would release the jit mutex here, but we can't yet since
1855 followup activities use timevars, which are global state. */
1857 if (errors_occurred ())
1859 release_mutex ();
1860 return;
1863 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1864 dump_generated_code ();
1866 /* We now have a .s file.
1868 Run any postprocessing steps. This will either convert the .s file to
1869 a .so DSO, and load it in memory (playback::compile_to_memory), or
1870 convert the .s file to the requested output format, and copy it to a
1871 given file (playback::compile_to_file). */
1872 postprocess (ctxt_progname);
1874 release_mutex ();
1877 /* Implementation of class gcc::jit::playback::compile_to_memory,
1878 a subclass of gcc::jit::playback::context. */
1880 /* playback::compile_to_memory's trivial constructor. */
1882 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
1883 playback::context (ctxt),
1884 m_result (NULL)
1886 JIT_LOG_SCOPE (get_logger ());
1889 /* Implementation of the playback::context::process vfunc for compiling
1890 to memory.
1892 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1893 wrapping the result up as a jit::result and returning it. */
1895 void
1896 playback::compile_to_memory::postprocess (const char *ctxt_progname)
1898 JIT_LOG_SCOPE (get_logger ());
1899 convert_to_dso (ctxt_progname);
1900 if (errors_occurred ())
1901 return;
1902 m_result = dlopen_built_dso ();
1905 /* Implementation of class gcc::jit::playback::compile_to_file,
1906 a subclass of gcc::jit::playback::context. */
1908 /* playback::compile_to_file's trivial constructor. */
1910 playback::compile_to_file::compile_to_file (recording::context *ctxt,
1911 enum gcc_jit_output_kind output_kind,
1912 const char *output_path) :
1913 playback::context (ctxt),
1914 m_output_kind (output_kind),
1915 m_output_path (output_path)
1917 JIT_LOG_SCOPE (get_logger ());
1920 /* Implementation of the playback::context::process vfunc for compiling
1921 to a file.
1923 Either copy the .s file to the given destination (for
1924 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1925 as necessary, copying the result. */
1927 void
1928 playback::compile_to_file::postprocess (const char *ctxt_progname)
1930 JIT_LOG_SCOPE (get_logger ());
1932 /* The driver takes different actions based on the filename, so
1933 we provide a filename with an appropriate suffix for the
1934 output kind, and then copy it up to the user-provided path,
1935 rather than directly compiling it to the requested output path. */
1937 switch (m_output_kind)
1939 default:
1940 gcc_unreachable ();
1942 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
1943 copy_file (get_tempdir ()->get_path_s_file (),
1944 m_output_path);
1945 /* The .s file is automatically unlinked by tempdir::~tempdir. */
1946 break;
1948 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
1950 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
1951 "/fake.o",
1952 NULL);
1953 invoke_driver (ctxt_progname,
1954 get_tempdir ()->get_path_s_file (),
1955 tmp_o_path,
1956 TV_ASSEMBLE,
1957 false, /* bool shared, */
1958 false);/* bool run_linker */
1959 if (!errors_occurred ())
1961 copy_file (tmp_o_path,
1962 m_output_path);
1963 get_tempdir ()->add_temp_file (tmp_o_path);
1965 else
1966 free (tmp_o_path);
1968 break;
1970 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
1971 invoke_driver (ctxt_progname,
1972 get_tempdir ()->get_path_s_file (),
1973 get_tempdir ()->get_path_so_file (),
1974 TV_ASSEMBLE,
1975 true, /* bool shared, */
1976 true);/* bool run_linker */
1977 if (!errors_occurred ())
1978 copy_file (get_tempdir ()->get_path_so_file (),
1979 m_output_path);
1980 /* The .so file is automatically unlinked by tempdir::~tempdir. */
1981 break;
1983 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
1985 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
1986 "/fake.exe",
1987 NULL);
1988 invoke_driver (ctxt_progname,
1989 get_tempdir ()->get_path_s_file (),
1990 tmp_exe_path,
1991 TV_ASSEMBLE,
1992 false, /* bool shared, */
1993 true);/* bool run_linker */
1994 if (!errors_occurred ())
1996 copy_file (tmp_exe_path,
1997 m_output_path);
1998 get_tempdir ()->add_temp_file (tmp_exe_path);
2000 else
2001 free (tmp_exe_path);
2003 break;
2009 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2010 the "executable" bits).
2012 Any errors that occur are reported on the context and hence count as
2013 a failure of the compile.
2015 We can't in general hardlink or use "rename" from the tempdir since
2016 it might be on a different filesystem to the destination. For example,
2017 I get EXDEV: "Invalid cross-device link". */
2019 void
2020 playback::compile_to_file::copy_file (const char *src_path,
2021 const char *dst_path)
2023 JIT_LOG_SCOPE (get_logger ());
2024 if (get_logger ())
2026 get_logger ()->log ("src_path: %s", src_path);
2027 get_logger ()->log ("dst_path: %s", dst_path);
2030 FILE *f_in = NULL;
2031 FILE *f_out = NULL;
2032 size_t total_sz_in = 0;
2033 size_t total_sz_out = 0;
2034 char buf[4096];
2035 size_t sz_in;
2036 struct stat stat_buf;
2038 f_in = fopen (src_path, "rb");
2039 if (!f_in)
2041 add_error (NULL,
2042 "unable to open %s for reading: %s",
2043 src_path,
2044 xstrerror (errno));
2045 return;
2048 /* Use stat on the filedescriptor to get the mode,
2049 so that we can copy it over (in particular, the
2050 "executable" bits). */
2051 if (fstat (fileno (f_in), &stat_buf) == -1)
2053 add_error (NULL,
2054 "unable to fstat %s: %s",
2055 src_path,
2056 xstrerror (errno));
2057 fclose (f_in);
2058 return;
2061 f_out = fopen (dst_path, "wb");
2062 if (!f_out)
2064 add_error (NULL,
2065 "unable to open %s for writing: %s",
2066 dst_path,
2067 xstrerror (errno));
2068 fclose (f_in);
2069 return;
2072 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2074 total_sz_in += sz_in;
2075 size_t sz_out_remaining = sz_in;
2076 size_t sz_out_so_far = 0;
2077 while (sz_out_remaining)
2079 size_t sz_out = fwrite (buf + sz_out_so_far,
2081 sz_out_remaining,
2082 f_out);
2083 gcc_assert (sz_out <= sz_out_remaining);
2084 if (!sz_out)
2086 add_error (NULL,
2087 "error writing to %s: %s",
2088 dst_path,
2089 xstrerror (errno));
2090 fclose (f_in);
2091 fclose (f_out);
2092 return;
2094 total_sz_out += sz_out;
2095 sz_out_so_far += sz_out;
2096 sz_out_remaining -= sz_out;
2098 gcc_assert (sz_out_so_far == sz_in);
2101 if (!feof (f_in))
2102 add_error (NULL,
2103 "error reading from %s: %s",
2104 src_path,
2105 xstrerror (errno));
2107 fclose (f_in);
2109 gcc_assert (total_sz_in == total_sz_out);
2110 if (get_logger ())
2111 get_logger ()->log ("total bytes copied: %ld", total_sz_out);
2113 /* Set the permissions of the copy to those of the original file,
2114 in particular the "executable" bits. */
2115 if (fchmod (fileno (f_out), stat_buf.st_mode) == -1)
2116 add_error (NULL,
2117 "error setting mode of %s: %s",
2118 dst_path,
2119 xstrerror (errno));
2121 fclose (f_out);
2124 /* Helper functions for gcc::jit::playback::context::compile. */
2126 /* This mutex guards gcc::jit::recording::context::compile, so that only
2127 one thread can be accessing the bulk of GCC's state at once. */
2129 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2131 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2133 void
2134 playback::context::acquire_mutex ()
2136 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2138 /* Acquire the big GCC mutex. */
2139 JIT_LOG_SCOPE (get_logger ());
2140 pthread_mutex_lock (&jit_mutex);
2141 gcc_assert (active_playback_ctxt == NULL);
2142 active_playback_ctxt = this;
2145 /* Release jit_mutex and clear the active playback ctxt. */
2147 void
2148 playback::context::release_mutex ()
2150 /* Release the big GCC mutex. */
2151 JIT_LOG_SCOPE (get_logger ());
2152 gcc_assert (active_playback_ctxt == this);
2153 active_playback_ctxt = NULL;
2154 pthread_mutex_unlock (&jit_mutex);
2157 /* Callback used by gcc::jit::playback::context::make_fake_args when
2158 invoking driver_get_configure_time_options.
2159 Populate a vec <char * > with the configure-time options. */
2161 static void
2162 append_arg_from_driver (const char *option, void *user_data)
2164 gcc_assert (option);
2165 gcc_assert (user_data);
2166 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2167 argvec->safe_push (concat ("-", option, NULL));
2170 /* Build a fake argv for toplev::main from the options set
2171 by the user on the context . */
2173 void
2174 playback::context::
2175 make_fake_args (vec <char *> *argvec,
2176 const char *ctxt_progname,
2177 vec <recording::requested_dump> *requested_dumps)
2179 JIT_LOG_SCOPE (get_logger ());
2181 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2182 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2184 ADD_ARG (ctxt_progname);
2185 ADD_ARG (get_path_c_file ());
2186 ADD_ARG ("-fPIC");
2188 /* Handle int options: */
2189 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2191 default:
2192 add_error (NULL,
2193 "unrecognized optimization level: %i",
2194 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2195 return;
2197 case 0:
2198 ADD_ARG ("-O0");
2199 break;
2201 case 1:
2202 ADD_ARG ("-O1");
2203 break;
2205 case 2:
2206 ADD_ARG ("-O2");
2207 break;
2209 case 3:
2210 ADD_ARG ("-O3");
2211 break;
2213 /* What about -Os? */
2215 /* Handle bool options: */
2216 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2217 ADD_ARG ("-g");
2219 /* Suppress timing (and other) info. */
2220 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2222 ADD_ARG ("-quiet");
2223 quiet_flag = 1;
2226 /* Aggressively garbage-collect, to shake out bugs: */
2227 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2229 ADD_ARG ("--param");
2230 ADD_ARG ("ggc-min-expand=0");
2231 ADD_ARG ("--param");
2232 ADD_ARG ("ggc-min-heapsize=0");
2235 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2237 ADD_ARG ("-fdump-tree-all");
2238 ADD_ARG ("-fdump-rtl-all");
2239 ADD_ARG ("-fdump-ipa-all");
2242 /* Add "-fdump-" options for any calls to
2243 gcc_jit_context_enable_dump. */
2245 int i;
2246 recording::requested_dump *d;
2247 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2249 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2250 ADD_ARG_TAKE_OWNERSHIP (arg);
2254 /* PR jit/64810: Add any target-specific default options
2255 from OPTION_DEFAULT_SPECS, normally provided by the driver
2256 in the non-jit case.
2258 The target-specific code can define OPTION_DEFAULT_SPECS:
2259 default command options in the form of spec macros for the
2260 driver to expand ().
2262 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2263 if not overriden, injects the defaults as extra arguments to
2264 cc1 etc.
2265 For the jit case, we need to add these arguments here. The
2266 input format (using the specs language) means that we have to run
2267 part of the driver code here (driver_get_configure_time_options).
2269 To avoid running the spec-expansion code every time, we just do
2270 it the first time (via a function-static flag), saving the result
2271 into a function-static vec.
2272 This flag and vec are global state (i.e. per-process).
2273 They are guarded by the jit mutex. */
2275 static bool have_configure_time_options = false;
2276 static vec <char *> configure_time_options;
2278 if (have_configure_time_options)
2279 log ("reusing cached configure-time options");
2280 else
2282 have_configure_time_options = true;
2283 log ("getting configure-time options from driver");
2284 driver_get_configure_time_options (append_arg_from_driver,
2285 &configure_time_options);
2288 int i;
2289 char *opt;
2291 if (get_logger ())
2292 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2293 log ("configure_time_options[%i]: %s", i, opt);
2295 /* configure_time_options should now contain the expanded options
2296 from OPTION_DEFAULT_SPECS (if any). */
2297 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2299 gcc_assert (opt);
2300 gcc_assert (opt[0] == '-');
2301 ADD_ARG (opt);
2305 if (get_timer ())
2306 ADD_ARG ("-ftime-report");
2308 /* Add any user-provided extra options, starting with any from
2309 parent contexts. */
2310 m_recording_ctxt->append_command_line_options (argvec);
2312 #undef ADD_ARG
2313 #undef ADD_ARG_TAKE_OWNERSHIP
2316 /* The second half of the implementation of gcc_jit_context_enable_dump.
2317 Iterate through the requested dumps, reading the underlying files
2318 into heap-allocated buffers, writing pointers to the buffers into
2319 the char ** pointers provided by client code.
2320 Client code is responsible for calling free on the results. */
2322 void
2323 playback::context::
2324 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2326 JIT_LOG_SCOPE (get_logger ());
2328 int i;
2329 recording::requested_dump *d;
2330 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2332 dump_file_info *dfi;
2333 char *filename;
2334 char *content;
2336 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2337 if (!dfi)
2339 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2340 continue;
2343 filename = g->get_dumps ()->get_dump_file_name (dfi);
2344 content = read_dump_file (filename);
2345 *(d->m_out_ptr) = content;
2346 m_tempdir->add_temp_file (filename);
2350 /* Helper function for playback::context::extract_any_requested_dumps
2351 (itself for use in implementation of gcc_jit_context_enable_dump).
2353 Attempt to read the complete file at the given path, returning the
2354 bytes found there as a buffer.
2355 The caller is responsible for calling free on the result.
2356 Errors will be reported on the context, and lead to NULL being
2357 returned; an out-of-memory error will terminate the process. */
2359 char *
2360 playback::context::read_dump_file (const char *path)
2362 char *result = NULL;
2363 size_t total_sz = 0;
2364 char buf[4096];
2365 size_t sz;
2366 FILE *f_in;
2368 f_in = fopen (path, "r");
2369 if (!f_in)
2371 add_error (NULL, "unable to open %s for reading", path);
2372 return NULL;
2375 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2377 size_t old_total_sz = total_sz;
2378 total_sz += sz;
2379 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2380 memcpy (result + old_total_sz, buf, sz);
2383 if (!feof (f_in))
2385 add_error (NULL, "error reading from %s", path);
2386 free (result);
2387 fclose (f_in);
2388 return NULL;
2391 fclose (f_in);
2393 if (result)
2395 result[total_sz] = '\0';
2396 return result;
2398 else
2399 return xstrdup ("");
2402 /* Part of playback::context::compile ().
2404 We have a .s file; we want a .so file.
2405 We could reuse parts of gcc/gcc.c to do this.
2406 For now, just use the driver binary from the install, as
2407 named in gcc-driver-name.h
2408 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2410 void
2411 playback::context::
2412 convert_to_dso (const char *ctxt_progname)
2414 JIT_LOG_SCOPE (get_logger ());
2416 invoke_driver (ctxt_progname,
2417 m_tempdir->get_path_s_file (),
2418 m_tempdir->get_path_so_file (),
2419 TV_ASSEMBLE,
2420 true, /* bool shared, */
2421 true);/* bool run_linker */
2424 static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2426 void
2427 playback::context::
2428 invoke_driver (const char *ctxt_progname,
2429 const char *input_file,
2430 const char *output_file,
2431 timevar_id_t tv_id,
2432 bool shared,
2433 bool run_linker)
2435 JIT_LOG_SCOPE (get_logger ());
2437 bool embedded_driver
2438 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
2440 /* Currently this lumps together both assembling and linking into
2441 TV_ASSEMBLE. */
2442 auto_timevar assemble_timevar (get_timer (), tv_id);
2443 auto_argvec argvec;
2444 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2446 ADD_ARG (gcc_driver_name);
2448 add_multilib_driver_arguments (&argvec);
2450 if (shared)
2451 ADD_ARG ("-shared");
2453 if (!run_linker)
2454 ADD_ARG ("-c");
2456 ADD_ARG (input_file);
2457 ADD_ARG ("-o");
2458 ADD_ARG (output_file);
2460 /* Don't use the linker plugin.
2461 If running with just a "make" and not a "make install", then we'd
2462 run into
2463 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2464 libto_plugin is a .la at build time, with it becoming installed with
2465 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2466 time. */
2467 ADD_ARG ("-fno-use-linker-plugin");
2469 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2470 /* OS X's linker defaults to treating undefined symbols as errors.
2471 If the context has any imported functions or globals they will be
2472 undefined until the .so is dynamically-linked into the process.
2473 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2474 linker. */
2475 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2476 #endif
2478 if (0)
2479 ADD_ARG ("-v");
2481 #undef ADD_ARG
2483 /* pex_one's error-handling requires pname to be non-NULL. */
2484 gcc_assert (ctxt_progname);
2486 if (get_logger ())
2487 for (unsigned i = 0; i < argvec.length (); i++)
2488 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2490 if (embedded_driver)
2491 invoke_embedded_driver (&argvec);
2492 else
2493 invoke_external_driver (ctxt_progname, &argvec);
2496 void
2497 playback::context::
2498 invoke_embedded_driver (const vec <char *> *argvec)
2500 JIT_LOG_SCOPE (get_logger ());
2501 driver d (true, /* can_finalize */
2502 false); /* debug */
2503 int result = d.main (argvec->length (),
2504 const_cast <char **> (argvec->address ()));
2505 d.finalize ();
2506 if (result)
2507 add_error (NULL, "error invoking gcc driver");
2510 void
2511 playback::context::
2512 invoke_external_driver (const char *ctxt_progname,
2513 vec <char *> *argvec)
2515 JIT_LOG_SCOPE (get_logger ());
2516 const char *errmsg;
2517 int exit_status = 0;
2518 int err = 0;
2520 /* pex argv arrays are NULL-terminated. */
2521 argvec->safe_push (NULL);
2523 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2524 gcc_driver_name,
2525 const_cast <char *const *> (argvec->address ()),
2526 ctxt_progname, /* const char *pname */
2527 NULL, /* const char *outname */
2528 NULL, /* const char *errname */
2529 &exit_status, /* int *status */
2530 &err); /* int *err*/
2531 if (errmsg)
2533 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2534 return;
2537 /* pex_one can return a NULL errmsg when the executable wasn't
2538 found (or doesn't exist), so trap these cases also. */
2539 if (exit_status || err)
2541 add_error (NULL,
2542 "error invoking gcc driver: exit_status: %i err: %i",
2543 exit_status, err);
2544 add_error (NULL,
2545 "whilst attempting to run a driver named: %s",
2546 gcc_driver_name);
2547 add_error (NULL,
2548 "PATH was: %s",
2549 getenv ("PATH"));
2550 return;
2554 /* Extract the target-specific MULTILIB_DEFAULTS to
2555 multilib_defaults_raw for use by
2556 playback::context::add_multilib_driver_arguments (). */
2558 #ifndef MULTILIB_DEFAULTS
2559 #define MULTILIB_DEFAULTS { "" }
2560 #endif
2562 static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
2564 /* Helper function for playback::context::invoke_driver ().
2566 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2567 a driver binary. We need to pass in options to the shared driver
2568 to get the appropriate assembler/linker options for this multilib
2569 peer. */
2571 void
2572 playback::context::
2573 add_multilib_driver_arguments (vec <char *> *argvec)
2575 JIT_LOG_SCOPE (get_logger ());
2577 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2578 prepending each with a "-". */
2579 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
2580 if (multilib_defaults_raw[i][0])
2581 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
2584 /* Dynamically-link the built DSO file into this process, using dlopen.
2585 Wrap it up within a jit::result *, and return that.
2586 Return NULL if any errors occur, reporting them on this context. */
2588 result *
2589 playback::context::
2590 dlopen_built_dso ()
2592 JIT_LOG_SCOPE (get_logger ());
2593 auto_timevar load_timevar (get_timer (), TV_LOAD);
2594 void *handle = NULL;
2595 const char *error = NULL;
2596 result *result_obj = NULL;
2598 /* Clear any existing error. */
2599 dlerror ();
2601 handle = dlopen (m_tempdir->get_path_so_file (),
2602 RTLD_NOW | RTLD_LOCAL);
2603 if ((error = dlerror()) != NULL) {
2604 add_error (NULL, "%s", error);
2606 if (handle)
2608 /* We've successfully dlopened the result; create a
2609 jit::result object to wrap it.
2611 We're done with the tempdir for now, but if the user
2612 has requested debugging, the user's debugger might not
2613 be capable of dealing with the .so file being unlinked
2614 immediately, so keep it around until after the result
2615 is released. We do this by handing over ownership of
2616 the jit::tempdir to the result. See PR jit/64206. */
2617 tempdir *handover_tempdir;
2618 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2620 handover_tempdir = m_tempdir;
2621 m_tempdir = NULL;
2622 /* The tempdir will eventually be cleaned up in the
2623 jit::result's dtor. */
2624 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2625 " handing over tempdir to jit::result");
2627 else
2629 handover_tempdir = NULL;
2630 /* ... and retain ownership of m_tempdir so we clean it
2631 up it the playback::context's dtor. */
2632 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2633 " retaining ownership of tempdir");
2636 result_obj = new result (get_logger (), handle, handover_tempdir);
2638 else
2639 result_obj = NULL;
2641 return result_obj;
2644 /* Top-level hook for playing back a recording context.
2646 This plays back m_recording_ctxt, and, if no errors
2647 occurred builds statement lists for and then postprocesses
2648 every function in the result. */
2650 void
2651 playback::context::
2652 replay ()
2654 JIT_LOG_SCOPE (get_logger ());
2655 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2656 tree array_domain_type = build_index_type (size_int (200));
2657 m_char_array_type_node
2658 = build_array_type (char_type_node, array_domain_type);
2660 m_const_char_ptr
2661 = build_pointer_type (build_qualified_type (char_type_node,
2662 TYPE_QUAL_CONST));
2664 /* Replay the recorded events: */
2665 timevar_push (TV_JIT_REPLAY);
2667 m_recording_ctxt->replay_into (this);
2669 /* Clean away the temporary references from recording objects
2670 to playback objects. We have to do this now since the
2671 latter are GC-allocated, but the former don't mark these
2672 refs. Hence we must stop using them before the GC can run. */
2673 m_recording_ctxt->disassociate_from_playback ();
2675 /* The builtins_manager, if any, is associated with the recording::context
2676 and might be reused for future compiles on other playback::contexts,
2677 but its m_attributes array is not GTY-labeled and hence will become
2678 nonsense if the GC runs. Purge this state. */
2679 builtins_manager *bm = get_builtins_manager ();
2680 if (bm)
2681 bm->finish_playback ();
2683 timevar_pop (TV_JIT_REPLAY);
2685 if (!errors_occurred ())
2687 int i;
2688 function *func;
2690 /* No GC can happen yet; process the cached source locations. */
2691 handle_locations ();
2693 /* We've now created tree nodes for the stmts in the various blocks
2694 in each function, but we haven't built each function's single stmt
2695 list yet. Do so now. */
2696 FOR_EACH_VEC_ELT (m_functions, i, func)
2697 func->build_stmt_list ();
2699 /* No GC can have happened yet. */
2701 /* Postprocess the functions. This could trigger GC. */
2702 FOR_EACH_VEC_ELT (m_functions, i, func)
2704 gcc_assert (func);
2705 func->postprocess ();
2710 /* Dump the generated .s file to stderr. */
2712 void
2713 playback::context::
2714 dump_generated_code ()
2716 JIT_LOG_SCOPE (get_logger ());
2717 char buf[4096];
2718 size_t sz;
2719 FILE *f_in = fopen (get_path_s_file (), "r");
2720 if (!f_in)
2721 return;
2723 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2724 fwrite (buf, 1, sz, stderr);
2726 fclose (f_in);
2729 /* Get the supposed path of the notional "fake.c" file within the
2730 tempdir. This file doesn't exist, but the rest of the compiler
2731 needs a name. */
2733 const char *
2734 playback::context::
2735 get_path_c_file () const
2737 return m_tempdir->get_path_c_file ();
2740 /* Get the path of the assembler output file "fake.s" file within the
2741 tempdir. */
2743 const char *
2744 playback::context::
2745 get_path_s_file () const
2747 return m_tempdir->get_path_s_file ();
2750 /* Get the path of the DSO object file "fake.so" file within the
2751 tempdir. */
2753 const char *
2754 playback::context::
2755 get_path_so_file () const
2757 return m_tempdir->get_path_so_file ();
2760 /* qsort comparator for comparing pairs of playback::source_line *,
2761 ordering them by line number. */
2763 static int
2764 line_comparator (const void *lhs, const void *rhs)
2766 const playback::source_line *line_lhs = \
2767 *static_cast<const playback::source_line * const*> (lhs);
2768 const playback::source_line *line_rhs = \
2769 *static_cast<const playback::source_line * const*> (rhs);
2770 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2773 /* qsort comparator for comparing pairs of playback::location *,
2774 ordering them by column number. */
2776 static int
2777 location_comparator (const void *lhs, const void *rhs)
2779 const playback::location *loc_lhs = \
2780 *static_cast<const playback::location * const *> (lhs);
2781 const playback::location *loc_rhs = \
2782 *static_cast<const playback::location * const *> (rhs);
2783 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2786 /* Our API allows locations to be created in arbitrary orders, but the
2787 linemap API requires locations to be created in ascending order
2788 as if we were tokenizing files.
2790 This hook sorts all of the locations that have been created, and
2791 calls into the linemap API, creating linemap entries in sorted order
2792 for our locations. */
2794 void
2795 playback::context::
2796 handle_locations ()
2798 /* Create the source code locations, following the ordering rules
2799 imposed by the linemap API.
2801 line_table is a global. */
2802 JIT_LOG_SCOPE (get_logger ());
2803 int i;
2804 source_file *file;
2806 FOR_EACH_VEC_ELT (m_source_files, i, file)
2808 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2810 /* Sort lines by ascending line numbers. */
2811 file->m_source_lines.qsort (&line_comparator);
2813 int j;
2814 source_line *line;
2815 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2817 int k;
2818 location *loc;
2820 /* Sort locations in line by ascending column numbers. */
2821 line->m_locations.qsort (&location_comparator);
2823 /* Determine maximum column within this line. */
2824 gcc_assert (line->m_locations.length () > 0);
2825 location *final_column =
2826 line->m_locations[line->m_locations.length () - 1];
2827 int max_col = final_column->get_column_num ();
2829 linemap_line_start (line_table, line->get_line_num (), max_col);
2830 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2832 loc->m_srcloc = \
2833 linemap_position_for_column (line_table, loc->get_column_num ());
2837 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2840 /* line_table should now be populated; every playback::location should
2841 now have an m_srcloc. */
2843 /* Now assign them to tree nodes as appropriate. */
2844 std::pair<tree, location *> *cached_location;
2846 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2848 tree t = cached_location->first;
2849 source_location srcloc = cached_location->second->m_srcloc;
2851 /* This covers expressions: */
2852 if (CAN_HAVE_LOCATION_P (t))
2853 SET_EXPR_LOCATION (t, srcloc);
2854 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2855 DECL_SOURCE_LOCATION (t) = srcloc;
2856 else
2858 /* Don't know how to set location on this node. */
2863 /* We handle errors on a playback::context by adding them to the
2864 corresponding recording::context. */
2866 void
2867 playback::context::
2868 add_error (location *loc, const char *fmt, ...)
2870 va_list ap;
2871 va_start (ap, fmt);
2872 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2873 fmt, ap);
2874 va_end (ap);
2877 /* We handle errors on a playback::context by adding them to the
2878 corresponding recording::context. */
2880 void
2881 playback::context::
2882 add_error_va (location *loc, const char *fmt, va_list ap)
2884 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2885 fmt, ap);
2888 /* Report a diagnostic up to the jit context as an error,
2889 so that the compilation is treated as a failure.
2890 For now, any kind of diagnostic is treated as an error by the jit
2891 API. */
2893 void
2894 playback::context::
2895 add_diagnostic (struct diagnostic_context *diag_context,
2896 struct diagnostic_info *diagnostic)
2898 /* At this point the text has been formatted into the pretty-printer's
2899 output buffer. */
2900 pretty_printer *pp = diag_context->printer;
2901 const char *text = pp_formatted_text (pp);
2903 /* Get location information (if any) from the diagnostic.
2904 The recording::context::add_error[_va] methods require a
2905 recording::location. We can't lookup the playback::location
2906 from the file/line/column since any playback location instances
2907 may have been garbage-collected away by now, so instead we create
2908 another recording::location directly. */
2909 location_t gcc_loc = diagnostic_location (diagnostic);
2910 recording::location *rec_loc = NULL;
2911 if (gcc_loc)
2913 expanded_location exploc = expand_location (gcc_loc);
2914 if (exploc.file)
2915 rec_loc = m_recording_ctxt->new_location (exploc.file,
2916 exploc.line,
2917 exploc.column,
2918 false);
2921 m_recording_ctxt->add_error (rec_loc, "%s", text);
2922 pp_clear_output_area (pp);
2925 /* Dealing with the linemap API. */
2927 /* Construct a playback::location for a recording::location, if it
2928 doesn't exist already. */
2930 playback::location *
2931 playback::context::
2932 new_location (recording::location *rloc,
2933 const char *filename,
2934 int line,
2935 int column)
2937 /* Get the source_file for filename, creating if necessary. */
2938 source_file *src_file = get_source_file (filename);
2939 /* Likewise for the line within the file. */
2940 source_line *src_line = src_file->get_source_line (line);
2941 /* Likewise for the column within the line. */
2942 location *loc = src_line->get_location (rloc, column);
2943 return loc;
2946 /* Deferred setting of the location for a given tree, by adding the
2947 (tree, playback::location) pair to a list of deferred associations.
2948 We will actually set the location on the tree later on once
2949 the source_location for the playback::location exists. */
2951 void
2952 playback::context::
2953 set_tree_location (tree t, location *loc)
2955 gcc_assert (loc);
2956 m_cached_locations.safe_push (std::make_pair (t, loc));
2960 /* Construct a playback::source_file for the given source
2961 filename, if it doesn't exist already. */
2963 playback::source_file *
2964 playback::context::
2965 get_source_file (const char *filename)
2967 /* Locate the file.
2968 For simplicitly, this is currently a linear search.
2969 Replace with a hash if this shows up in the profile. */
2970 int i;
2971 source_file *file;
2972 tree ident_filename = get_identifier (filename);
2974 FOR_EACH_VEC_ELT (m_source_files, i, file)
2975 if (file->filename_as_tree () == ident_filename)
2976 return file;
2978 /* Not found. */
2979 file = new source_file (ident_filename);
2980 m_source_files.safe_push (file);
2981 return file;
2984 /* Constructor for gcc::jit::playback::source_file. */
2986 playback::source_file::source_file (tree filename) :
2987 m_source_lines (),
2988 m_filename (filename)
2992 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2993 GC-ed. */
2995 void
2996 playback::source_file::finalizer ()
2998 m_source_lines.release ();
3001 /* Construct a playback::source_line for the given line
3002 within this source file, if one doesn't exist already. */
3004 playback::source_line *
3005 playback::source_file::
3006 get_source_line (int line_num)
3008 /* Locate the line.
3009 For simplicitly, this is currently a linear search.
3010 Replace with a hash if this shows up in the profile. */
3011 int i;
3012 source_line *line;
3014 FOR_EACH_VEC_ELT (m_source_lines, i, line)
3015 if (line->get_line_num () == line_num)
3016 return line;
3018 /* Not found. */
3019 line = new source_line (this, line_num);
3020 m_source_lines.safe_push (line);
3021 return line;
3024 /* Constructor for gcc::jit::playback::source_line. */
3026 playback::source_line::source_line (source_file *file, int line_num) :
3027 m_locations (),
3028 m_source_file (file),
3029 m_line_num (line_num)
3033 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3034 GC-ed. */
3036 void
3037 playback::source_line::finalizer ()
3039 m_locations.release ();
3042 /* Construct a playback::location for the given column
3043 within this line of a specific source file, if one doesn't exist
3044 already. */
3046 playback::location *
3047 playback::source_line::
3048 get_location (recording::location *rloc, int column_num)
3050 int i;
3051 location *loc;
3053 /* Another linear search that probably should be a hash table. */
3054 FOR_EACH_VEC_ELT (m_locations, i, loc)
3055 if (loc->get_column_num () == column_num)
3056 return loc;
3058 /* Not found. */
3059 loc = new location (rloc, this, column_num);
3060 m_locations.safe_push (loc);
3061 return loc;
3064 /* Constructor for gcc::jit::playback::location. */
3066 playback::location::location (recording::location *loc,
3067 source_line *line,
3068 int column_num) :
3069 m_srcloc (UNKNOWN_LOCATION),
3070 m_recording_loc (loc),
3071 m_line (line),
3072 m_column_num(column_num)
3076 /* The active gcc::jit::playback::context instance. This is a singleton,
3077 guarded by jit_mutex. */
3079 playback::context *active_playback_ctxt;
3081 } // namespace gcc::jit
3083 } // namespace gcc