New jit API entrypoint: gcc_jit_context_set_logfile
[official-gcc.git] / gcc / jit / jit-playback.c
bloba8a281a66843fb27bd562805d739744e056658ab
1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2015 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 "opts.h"
25 #include "tree.h"
26 #include "hash-map.h"
27 #include "is-a.h"
28 #include "plugin-api.h"
29 #include "vec.h"
30 #include "hashtab.h"
31 #include "hash-set.h"
32 #include "machmode.h"
33 #include "tm.h"
34 #include "hard-reg-set.h"
35 #include "function.h"
36 #include "ipa-ref.h"
37 #include "dumpfile.h"
38 #include "cgraph.h"
39 #include "toplev.h"
40 #include "timevar.h"
41 #include "tree-cfg.h"
42 #include "target.h"
43 #include "convert.h"
44 #include "stringpool.h"
45 #include "stor-layout.h"
46 #include "print-tree.h"
47 #include "gimplify.h"
48 #include "gcc-driver-name.h"
49 #include "attribs.h"
50 #include "context.h"
52 #include "jit-common.h"
53 #include "jit-logging.h"
54 #include "jit-playback.h"
55 #include "jit-result.h"
56 #include "jit-builtins.h"
57 #include "jit-tempdir.h"
60 /* gcc::jit::playback::context::build_cast uses the convert.h API,
61 which in turn requires the frontend to provide a "convert"
62 function, apparently as a fallback.
64 Hence we provide this dummy one, with the requirement that any casts
65 are handled before reaching this. */
66 extern tree convert (tree type, tree expr);
68 tree
69 convert (tree dst_type, tree expr)
71 gcc_assert (gcc::jit::active_playback_ctxt);
72 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
73 fprintf (stderr, "input expression:\n");
74 debug_tree (expr);
75 fprintf (stderr, "requested type:\n");
76 debug_tree (dst_type);
77 return error_mark_node;
80 namespace gcc {
81 namespace jit {
83 /**********************************************************************
84 Playback.
85 **********************************************************************/
87 /* The constructor for gcc::jit::playback::context. */
89 playback::context::context (recording::context *ctxt)
90 : log_user (ctxt->get_logger ()),
91 m_recording_ctxt (ctxt),
92 m_tempdir (NULL),
93 m_char_array_type_node (NULL),
94 m_const_char_ptr (NULL)
96 JIT_LOG_SCOPE (get_logger ());
97 m_functions.create (0);
98 m_source_files.create (0);
99 m_cached_locations.create (0);
102 /* The destructor for gcc::jit::playback::context. */
104 playback::context::~context ()
106 JIT_LOG_SCOPE (get_logger ());
107 if (m_tempdir)
108 delete m_tempdir;
109 m_functions.release ();
112 /* A playback::context can reference GC-managed pointers. Mark them
113 ("by hand", rather than by gengtype).
115 This is called on the active playback context (if any) by the
116 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
118 void
119 playback::context::
120 gt_ggc_mx ()
122 int i;
123 function *func;
124 FOR_EACH_VEC_ELT (m_functions, i, func)
126 if (ggc_test_and_set_mark (func))
127 func->gt_ggc_mx ();
131 /* Given an enum gcc_jit_types value, get a "tree" type. */
133 static tree
134 get_tree_node_for_type (enum gcc_jit_types type_)
136 switch (type_)
138 case GCC_JIT_TYPE_VOID:
139 return void_type_node;
141 case GCC_JIT_TYPE_VOID_PTR:
142 return ptr_type_node;
144 case GCC_JIT_TYPE_BOOL:
145 return boolean_type_node;
147 case GCC_JIT_TYPE_CHAR:
148 return char_type_node;
149 case GCC_JIT_TYPE_SIGNED_CHAR:
150 return signed_char_type_node;
151 case GCC_JIT_TYPE_UNSIGNED_CHAR:
152 return unsigned_char_type_node;
154 case GCC_JIT_TYPE_SHORT:
155 return short_integer_type_node;
156 case GCC_JIT_TYPE_UNSIGNED_SHORT:
157 return short_unsigned_type_node;
159 case GCC_JIT_TYPE_CONST_CHAR_PTR:
161 tree const_char = build_qualified_type (char_type_node,
162 TYPE_QUAL_CONST);
163 return build_pointer_type (const_char);
166 case GCC_JIT_TYPE_INT:
167 return integer_type_node;
168 case GCC_JIT_TYPE_UNSIGNED_INT:
169 return unsigned_type_node;
171 case GCC_JIT_TYPE_LONG:
172 return long_integer_type_node;
173 case GCC_JIT_TYPE_UNSIGNED_LONG:
174 return long_unsigned_type_node;
176 case GCC_JIT_TYPE_LONG_LONG:
177 return long_long_integer_type_node;
178 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
179 return long_long_unsigned_type_node;
181 case GCC_JIT_TYPE_FLOAT:
182 return float_type_node;
183 case GCC_JIT_TYPE_DOUBLE:
184 return double_type_node;
185 case GCC_JIT_TYPE_LONG_DOUBLE:
186 return long_double_type_node;
188 case GCC_JIT_TYPE_SIZE_T:
189 return size_type_node;
191 case GCC_JIT_TYPE_FILE_PTR:
192 return fileptr_type_node;
194 case GCC_JIT_TYPE_COMPLEX_FLOAT:
195 return complex_float_type_node;
196 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
197 return complex_double_type_node;
198 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
199 return complex_long_double_type_node;
202 return NULL;
205 /* Construct a playback::type instance (wrapping a tree) for the given
206 enum value. */
208 playback::type *
209 playback::context::
210 get_type (enum gcc_jit_types type_)
212 tree type_node = get_tree_node_for_type (type_);
213 if (NULL == type_node)
215 add_error (NULL,
216 "unrecognized (enum gcc_jit_types) value: %i", type_);
217 return NULL;
220 return new type (type_node);
223 /* Construct a playback::type instance (wrapping a tree) for the given
224 array type. */
226 playback::type *
227 playback::context::
228 new_array_type (playback::location *loc,
229 playback::type *element_type,
230 int num_elements)
232 gcc_assert (element_type);
234 tree t = build_array_type_nelts (element_type->as_tree (),
235 num_elements);
236 layout_type (t);
238 if (loc)
239 set_tree_location (t, loc);
241 return new type (t);
244 /* Construct a playback::field instance (wrapping a tree). */
246 playback::field *
247 playback::context::
248 new_field (location *loc,
249 type *type,
250 const char *name)
252 gcc_assert (type);
253 gcc_assert (name);
255 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
256 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
257 get_identifier (name), type->as_tree ());
259 if (loc)
260 set_tree_location (decl, loc);
262 return new field (decl);
265 /* Construct a playback::compound_type instance (wrapping a tree). */
267 playback::compound_type *
268 playback::context::
269 new_compound_type (location *loc,
270 const char *name,
271 bool is_struct) /* else is union */
273 gcc_assert (name);
275 /* Compare with c/c-decl.c: start_struct. */
277 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
278 TYPE_NAME (t) = get_identifier (name);
279 TYPE_SIZE (t) = 0;
281 if (loc)
282 set_tree_location (t, loc);
284 return new compound_type (t);
287 void
288 playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
290 /* Compare with c/c-decl.c: finish_struct. */
291 tree t = as_tree ();
293 tree fieldlist = NULL;
294 for (unsigned i = 0; i < fields->length (); i++)
296 field *f = (*fields)[i];
297 DECL_CONTEXT (f->as_tree ()) = t;
298 fieldlist = chainon (f->as_tree (), fieldlist);
300 fieldlist = nreverse (fieldlist);
301 TYPE_FIELDS (t) = fieldlist;
303 layout_type (t);
306 /* Construct a playback::type instance (wrapping a tree) for a function
307 type. */
309 playback::type *
310 playback::context::
311 new_function_type (type *return_type,
312 const auto_vec<type *> *param_types,
313 int is_variadic)
315 int i;
316 type *param_type;
318 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
320 FOR_EACH_VEC_ELT (*param_types, i, param_type)
321 arg_types[i] = param_type->as_tree ();
323 tree fn_type;
324 if (is_variadic)
325 fn_type =
326 build_varargs_function_type_array (return_type->as_tree (),
327 param_types->length (),
328 arg_types);
329 else
330 fn_type = build_function_type_array (return_type->as_tree (),
331 param_types->length (),
332 arg_types);
333 free (arg_types);
335 return new type (fn_type);
338 /* Construct a playback::param instance (wrapping a tree). */
340 playback::param *
341 playback::context::
342 new_param (location *loc,
343 type *type,
344 const char *name)
346 gcc_assert (type);
347 gcc_assert (name);
348 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
349 get_identifier (name), type->as_tree ());
350 if (loc)
351 set_tree_location (inner, loc);
353 return new param (this, inner);
356 /* Construct a playback::function instance. */
358 playback::function *
359 playback::context::
360 new_function (location *loc,
361 enum gcc_jit_function_kind kind,
362 type *return_type,
363 const char *name,
364 const auto_vec<param *> *params,
365 int is_variadic,
366 enum built_in_function builtin_id)
368 int i;
369 param *param;
371 //can return_type be NULL?
372 gcc_assert (name);
374 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
375 FOR_EACH_VEC_ELT (*params, i, param)
376 arg_types[i] = TREE_TYPE (param->as_tree ());
378 tree fn_type;
379 if (is_variadic)
380 fn_type = build_varargs_function_type_array (return_type->as_tree (),
381 params->length (), arg_types);
382 else
383 fn_type = build_function_type_array (return_type->as_tree (),
384 params->length (), arg_types);
385 free (arg_types);
387 /* FIXME: this uses input_location: */
388 tree fndecl = build_fn_decl (name, fn_type);
390 if (loc)
391 set_tree_location (fndecl, loc);
393 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
394 NULL_TREE, return_type->as_tree ());
395 DECL_ARTIFICIAL (resdecl) = 1;
396 DECL_IGNORED_P (resdecl) = 1;
397 DECL_RESULT (fndecl) = resdecl;
399 if (builtin_id)
401 DECL_FUNCTION_CODE (fndecl) = builtin_id;
402 gcc_assert (loc == NULL);
403 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
405 DECL_BUILT_IN_CLASS (fndecl) =
406 builtins_manager::get_class (builtin_id);
407 set_builtin_decl (builtin_id, fndecl,
408 builtins_manager::implicit_p (builtin_id));
410 builtins_manager *bm = get_builtins_manager ();
411 tree attrs = bm->get_attrs_tree (builtin_id);
412 if (attrs)
413 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
414 else
415 decl_attributes (&fndecl, NULL_TREE, 0);
418 if (kind != GCC_JIT_FUNCTION_IMPORTED)
420 tree param_decl_list = NULL;
421 FOR_EACH_VEC_ELT (*params, i, param)
423 param_decl_list = chainon (param->as_tree (), param_decl_list);
426 /* The param list was created in reverse order; fix it: */
427 param_decl_list = nreverse (param_decl_list);
429 tree t;
430 for (t = param_decl_list; t; t = DECL_CHAIN (t))
432 DECL_CONTEXT (t) = fndecl;
433 DECL_ARG_TYPE (t) = TREE_TYPE (t);
436 /* Set it up on DECL_ARGUMENTS */
437 DECL_ARGUMENTS(fndecl) = param_decl_list;
440 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
442 DECL_DECLARED_INLINE_P (fndecl) = 1;
444 /* Add attribute "always_inline": */
445 DECL_ATTRIBUTES (fndecl) =
446 tree_cons (get_identifier ("always_inline"),
447 NULL,
448 DECL_ATTRIBUTES (fndecl));
451 function *func = new function (this, fndecl, kind);
452 m_functions.safe_push (func);
453 return func;
456 /* Construct a playback::lvalue instance (wrapping a tree). */
458 playback::lvalue *
459 playback::context::
460 new_global (location *loc,
461 type *type,
462 const char *name)
464 gcc_assert (type);
465 gcc_assert (name);
466 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
467 get_identifier (name),
468 type->as_tree ());
469 TREE_PUBLIC (inner) = 1;
470 DECL_COMMON (inner) = 1;
471 DECL_EXTERNAL (inner) = 1;
473 if (loc)
474 set_tree_location (inner, loc);
476 return new lvalue (this, inner);
479 /* Construct a playback::rvalue instance (wrapping a tree). */
481 playback::rvalue *
482 playback::context::
483 new_rvalue_from_int (type *type,
484 int value)
486 // FIXME: type-checking, or coercion?
487 tree inner_type = type->as_tree ();
488 if (INTEGRAL_TYPE_P (inner_type))
490 tree inner = build_int_cst (inner_type, value);
491 return new rvalue (this, inner);
493 else
495 REAL_VALUE_TYPE real_value;
496 real_from_integer (&real_value, VOIDmode, value, SIGNED);
497 tree inner = build_real (inner_type, real_value);
498 return new rvalue (this, inner);
502 /* Construct a playback::rvalue instance (wrapping a tree). */
504 playback::rvalue *
505 playback::context::
506 new_rvalue_from_double (type *type,
507 double value)
509 // FIXME: type-checking, or coercion?
510 tree inner_type = type->as_tree ();
512 /* We have a "double", we want a REAL_VALUE_TYPE.
514 real.c:real_from_target appears to require the representation to be
515 split into 32-bit values, and then sent as an pair of host long
516 ints. */
517 REAL_VALUE_TYPE real_value;
518 union
520 double as_double;
521 uint32_t as_uint32s[2];
522 } u;
523 u.as_double = value;
524 long int as_long_ints[2];
525 as_long_ints[0] = u.as_uint32s[0];
526 as_long_ints[1] = u.as_uint32s[1];
527 real_from_target (&real_value, as_long_ints, DFmode);
528 tree inner = build_real (inner_type, real_value);
529 return new rvalue (this, inner);
532 /* Construct a playback::rvalue instance (wrapping a tree). */
534 playback::rvalue *
535 playback::context::
536 new_rvalue_from_ptr (type *type,
537 void *value)
539 tree inner_type = type->as_tree ();
540 /* FIXME: how to ensure we have a wide enough type? */
541 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
542 return new rvalue (this, inner);
545 /* Construct a playback::rvalue instance (wrapping a tree). */
547 playback::rvalue *
548 playback::context::
549 new_string_literal (const char *value)
551 tree t_str = build_string (strlen (value), value);
552 gcc_assert (m_char_array_type_node);
553 TREE_TYPE (t_str) = m_char_array_type_node;
555 /* Convert to (const char*), loosely based on
556 c/c-typeck.c: array_to_pointer_conversion,
557 by taking address of start of string. */
558 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
560 return new rvalue (this, t_addr);
563 /* Coerce a tree expression into a boolean tree expression. */
565 tree
566 playback::context::
567 as_truth_value (tree expr, location *loc)
569 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
570 tree typed_zero = fold_build1 (CONVERT_EXPR,
571 TREE_TYPE (expr),
572 integer_zero_node);
573 if (loc)
574 set_tree_location (typed_zero, loc);
576 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
577 if (loc)
578 set_tree_location (expr, loc);
580 return expr;
583 /* Construct a playback::rvalue instance (wrapping a tree) for a
584 unary op. */
586 playback::rvalue *
587 playback::context::
588 new_unary_op (location *loc,
589 enum gcc_jit_unary_op op,
590 type *result_type,
591 rvalue *a)
593 // FIXME: type-checking, or coercion?
594 enum tree_code inner_op;
596 gcc_assert (result_type);
597 gcc_assert (a);
599 tree node = a->as_tree ();
600 tree inner_result = NULL;
602 switch (op)
604 default:
605 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
606 return NULL;
608 case GCC_JIT_UNARY_OP_MINUS:
609 inner_op = NEGATE_EXPR;
610 break;
612 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
613 inner_op = BIT_NOT_EXPR;
614 break;
616 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
617 node = as_truth_value (node, loc);
618 inner_result = invert_truthvalue (node);
619 if (loc)
620 set_tree_location (inner_result, loc);
621 return new rvalue (this, inner_result);
623 case GCC_JIT_UNARY_OP_ABS:
624 inner_op = ABS_EXPR;
625 break;
628 inner_result = build1 (inner_op,
629 result_type->as_tree (),
630 node);
631 if (loc)
632 set_tree_location (inner_result, loc);
634 return new rvalue (this, inner_result);
637 /* Construct a playback::rvalue instance (wrapping a tree) for a
638 binary op. */
640 playback::rvalue *
641 playback::context::
642 new_binary_op (location *loc,
643 enum gcc_jit_binary_op op,
644 type *result_type,
645 rvalue *a, rvalue *b)
647 // FIXME: type-checking, or coercion?
648 enum tree_code inner_op;
650 gcc_assert (result_type);
651 gcc_assert (a);
652 gcc_assert (b);
654 tree node_a = a->as_tree ();
655 tree node_b = b->as_tree ();
657 switch (op)
659 default:
660 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
661 return NULL;
663 case GCC_JIT_BINARY_OP_PLUS:
664 inner_op = PLUS_EXPR;
665 break;
667 case GCC_JIT_BINARY_OP_MINUS:
668 inner_op = MINUS_EXPR;
669 break;
671 case GCC_JIT_BINARY_OP_MULT:
672 inner_op = MULT_EXPR;
673 break;
675 case GCC_JIT_BINARY_OP_DIVIDE:
676 if (FLOAT_TYPE_P (result_type->as_tree ()))
677 /* Floating-point division: */
678 inner_op = RDIV_EXPR;
679 else
680 /* Truncating to zero: */
681 inner_op = TRUNC_DIV_EXPR;
682 break;
684 case GCC_JIT_BINARY_OP_MODULO:
685 inner_op = TRUNC_MOD_EXPR;
686 break;
688 case GCC_JIT_BINARY_OP_BITWISE_AND:
689 inner_op = BIT_AND_EXPR;
690 break;
692 case GCC_JIT_BINARY_OP_BITWISE_XOR:
693 inner_op = BIT_XOR_EXPR;
694 break;
696 case GCC_JIT_BINARY_OP_BITWISE_OR:
697 inner_op = BIT_IOR_EXPR;
698 break;
700 case GCC_JIT_BINARY_OP_LOGICAL_AND:
701 node_a = as_truth_value (node_a, loc);
702 node_b = as_truth_value (node_b, loc);
703 inner_op = TRUTH_ANDIF_EXPR;
704 break;
706 case GCC_JIT_BINARY_OP_LOGICAL_OR:
707 node_a = as_truth_value (node_a, loc);
708 node_b = as_truth_value (node_b, loc);
709 inner_op = TRUTH_ORIF_EXPR;
710 break;
712 case GCC_JIT_BINARY_OP_LSHIFT:
713 inner_op = LSHIFT_EXPR;
714 break;
716 case GCC_JIT_BINARY_OP_RSHIFT:
717 inner_op = RSHIFT_EXPR;
718 break;
721 tree inner_expr = build2 (inner_op,
722 result_type->as_tree (),
723 node_a,
724 node_b);
725 if (loc)
726 set_tree_location (inner_expr, loc);
728 return new rvalue (this, inner_expr);
731 /* Construct a playback::rvalue instance (wrapping a tree) for a
732 comparison. */
734 playback::rvalue *
735 playback::context::
736 new_comparison (location *loc,
737 enum gcc_jit_comparison op,
738 rvalue *a, rvalue *b)
740 // FIXME: type-checking, or coercion?
741 enum tree_code inner_op;
743 gcc_assert (a);
744 gcc_assert (b);
746 switch (op)
748 default:
749 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
750 return NULL;
752 case GCC_JIT_COMPARISON_EQ:
753 inner_op = EQ_EXPR;
754 break;
755 case GCC_JIT_COMPARISON_NE:
756 inner_op = NE_EXPR;
757 break;
758 case GCC_JIT_COMPARISON_LT:
759 inner_op = LT_EXPR;
760 break;
761 case GCC_JIT_COMPARISON_LE:
762 inner_op = LE_EXPR;
763 break;
764 case GCC_JIT_COMPARISON_GT:
765 inner_op = GT_EXPR;
766 break;
767 case GCC_JIT_COMPARISON_GE:
768 inner_op = GE_EXPR;
769 break;
772 tree inner_expr = build2 (inner_op,
773 boolean_type_node,
774 a->as_tree (),
775 b->as_tree ());
776 if (loc)
777 set_tree_location (inner_expr, loc);
778 return new rvalue (this, inner_expr);
781 /* Construct a playback::rvalue instance (wrapping a tree) for a
782 function call. */
784 playback::rvalue *
785 playback::context::
786 build_call (location *loc,
787 tree fn_ptr,
788 const auto_vec<rvalue *> *args)
790 vec<tree, va_gc> *tree_args;
791 vec_alloc (tree_args, args->length ());
792 for (unsigned i = 0; i < args->length (); i++)
793 tree_args->quick_push ((*args)[i]->as_tree ());
795 if (loc)
796 set_tree_location (fn_ptr, loc);
798 tree fn = TREE_TYPE (fn_ptr);
799 tree fn_type = TREE_TYPE (fn);
800 tree return_type = TREE_TYPE (fn_type);
802 return new rvalue (this,
803 build_call_vec (return_type,
804 fn_ptr, tree_args));
806 /* see c-typeck.c: build_function_call
807 which calls build_function_call_vec
809 which does lots of checking, then:
810 result = build_call_array_loc (loc, TREE_TYPE (fntype),
811 function, nargs, argarray);
812 which is in tree.c
813 (see also build_call_vec)
817 /* Construct a playback::rvalue instance (wrapping a tree) for a
818 call to a specific function. */
820 playback::rvalue *
821 playback::context::
822 new_call (location *loc,
823 function *func,
824 const auto_vec<rvalue *> *args)
826 tree fndecl;
828 gcc_assert (func);
830 fndecl = func->as_fndecl ();
832 tree fntype = TREE_TYPE (fndecl);
834 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
836 return build_call (loc, fn, args);
839 /* Construct a playback::rvalue instance (wrapping a tree) for a
840 call through a function pointer. */
842 playback::rvalue *
843 playback::context::
844 new_call_through_ptr (location *loc,
845 rvalue *fn_ptr,
846 const auto_vec<rvalue *> *args)
848 gcc_assert (fn_ptr);
849 tree t_fn_ptr = fn_ptr->as_tree ();
851 return build_call (loc, t_fn_ptr, args);
854 /* Construct a tree for a cast. */
856 tree
857 playback::context::build_cast (playback::location *loc,
858 playback::rvalue *expr,
859 playback::type *type_)
861 /* For comparison, see:
862 - c/c-typeck.c:build_c_cast
863 - c/c-convert.c: convert
864 - convert.h
866 Only some kinds of cast are currently supported here. */
867 tree t_expr = expr->as_tree ();
868 tree t_dst_type = type_->as_tree ();
869 tree t_ret = NULL;
870 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
871 if (t_ret)
872 return t_ret;
873 enum tree_code dst_code = TREE_CODE (t_dst_type);
874 switch (dst_code)
876 case INTEGER_TYPE:
877 case ENUMERAL_TYPE:
878 t_ret = convert_to_integer (t_dst_type, t_expr);
879 goto maybe_fold;
881 case BOOLEAN_TYPE:
882 /* Compare with c_objc_common_truthvalue_conversion and
883 c_common_truthvalue_conversion. */
884 /* For now, convert to: (t_expr != 0) */
885 t_ret = build2 (NE_EXPR, t_dst_type,
886 t_expr,
887 build_int_cst (TREE_TYPE (t_expr), 0));
888 goto maybe_fold;
890 case REAL_TYPE:
891 t_ret = convert_to_real (t_dst_type, t_expr);
892 goto maybe_fold;
894 case POINTER_TYPE:
895 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
896 goto maybe_fold;
898 default:
899 add_error (loc, "couldn't handle cast during playback");
900 fprintf (stderr, "input expression:\n");
901 debug_tree (t_expr);
902 fprintf (stderr, "requested type:\n");
903 debug_tree (t_dst_type);
904 return error_mark_node;
906 maybe_fold:
907 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
908 t_ret = fold (t_ret);
909 return t_ret;
913 /* Construct a playback::rvalue instance (wrapping a tree) for a
914 cast. */
916 playback::rvalue *
917 playback::context::
918 new_cast (playback::location *loc,
919 playback::rvalue *expr,
920 playback::type *type_)
923 tree t_cast = build_cast (loc, expr, type_);
924 if (loc)
925 set_tree_location (t_cast, loc);
926 return new rvalue (this, t_cast);
929 /* Construct a playback::lvalue instance (wrapping a tree) for an
930 array access. */
932 playback::lvalue *
933 playback::context::
934 new_array_access (location *loc,
935 rvalue *ptr,
936 rvalue *index)
938 gcc_assert (ptr);
939 gcc_assert (index);
941 /* For comparison, see:
942 c/c-typeck.c: build_array_ref
943 c-family/c-common.c: pointer_int_sum
945 tree t_ptr = ptr->as_tree ();
946 tree t_index = index->as_tree ();
947 tree t_type_ptr = TREE_TYPE (t_ptr);
948 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
950 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
952 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
953 NULL_TREE, NULL_TREE);
954 if (loc)
955 set_tree_location (t_result, loc);
956 return new lvalue (this, t_result);
958 else
960 /* Convert index to an offset in bytes. */
961 tree t_sizeof = size_in_bytes (t_type_star_ptr);
962 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
963 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
965 /* Locate (ptr + offset). */
966 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
968 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
969 if (loc)
971 set_tree_location (t_sizeof, loc);
972 set_tree_location (t_offset, loc);
973 set_tree_location (t_address, loc);
974 set_tree_location (t_indirection, loc);
977 return new lvalue (this, t_indirection);
981 /* Construct a tree for a field access. */
983 tree
984 playback::context::
985 new_field_access (location *loc,
986 tree datum,
987 field *field)
989 gcc_assert (datum);
990 gcc_assert (field);
992 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
993 build_component_ref. */
994 tree type = TREE_TYPE (datum);
995 gcc_assert (type);
996 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
998 tree t_field = field->as_tree ();
999 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1000 t_field, NULL_TREE);
1001 if (loc)
1002 set_tree_location (ref, loc);
1003 return ref;
1006 /* Construct a tree for a dereference. */
1008 tree
1009 playback::context::
1010 new_dereference (tree ptr,
1011 location *loc)
1013 gcc_assert (ptr);
1015 tree type = TREE_TYPE (TREE_TYPE(ptr));
1016 tree datum = build1 (INDIRECT_REF, type, ptr);
1017 if (loc)
1018 set_tree_location (datum, loc);
1019 return datum;
1022 /* Construct a playback::lvalue instance (wrapping a tree) for a
1023 field access. */
1025 playback::lvalue *
1026 playback::lvalue::
1027 access_field (location *loc,
1028 field *field)
1030 tree datum = as_tree ();
1031 tree ref = get_context ()->new_field_access (loc, datum, field);
1032 if (!ref)
1033 return NULL;
1034 return new lvalue (get_context (), ref);
1037 /* Construct a playback::rvalue instance (wrapping a tree) for a
1038 field access. */
1040 playback::rvalue *
1041 playback::rvalue::
1042 access_field (location *loc,
1043 field *field)
1045 tree datum = as_tree ();
1046 tree ref = get_context ()->new_field_access (loc, datum, field);
1047 if (!ref)
1048 return NULL;
1049 return new rvalue (get_context (), ref);
1052 /* Construct a playback::lvalue instance (wrapping a tree) for a
1053 dereferenced field access. */
1055 playback::lvalue *
1056 playback::rvalue::
1057 dereference_field (location *loc,
1058 field *field)
1060 tree ptr = as_tree ();
1061 tree datum = get_context ()->new_dereference (ptr, loc);
1062 if (!datum)
1063 return NULL;
1064 tree ref = get_context ()->new_field_access (loc, datum, field);
1065 if (!ref)
1066 return NULL;
1067 return new lvalue (get_context (), ref);
1070 /* Construct a playback::lvalue instance (wrapping a tree) for a
1071 dereference. */
1073 playback::lvalue *
1074 playback::rvalue::
1075 dereference (location *loc)
1077 tree ptr = as_tree ();
1078 tree datum = get_context ()->new_dereference (ptr, loc);
1079 return new lvalue (get_context (), datum);
1082 /* Construct a playback::rvalue instance (wrapping a tree) for an
1083 address-lookup. */
1085 playback::rvalue *
1086 playback::lvalue::
1087 get_address (location *loc)
1089 tree t_lvalue = as_tree ();
1090 tree t_thistype = TREE_TYPE (t_lvalue);
1091 tree t_ptrtype = build_pointer_type (t_thistype);
1092 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1093 if (loc)
1094 get_context ()->set_tree_location (ptr, loc);
1095 return new rvalue (get_context (), ptr);
1098 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1099 Provide this finalization hook for calling then they are collected,
1100 which calls the finalizer vfunc. This allows them to call "release"
1101 on any vec<> within them. */
1103 static void
1104 wrapper_finalizer (void *ptr)
1106 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1107 wrapper->finalizer ();
1110 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1111 allocate them using ggc_internal_cleared_alloc. */
1113 void *
1114 playback::wrapper::
1115 operator new (size_t sz)
1117 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1121 /* Constructor for gcc:jit::playback::function. */
1123 playback::function::
1124 function (context *ctxt,
1125 tree fndecl,
1126 enum gcc_jit_function_kind kind)
1127 : m_ctxt(ctxt),
1128 m_inner_fndecl (fndecl),
1129 m_inner_bind_expr (NULL),
1130 m_kind (kind)
1132 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1134 /* Create a BIND_EXPR, and within it, a statement list. */
1135 m_stmt_list = alloc_stmt_list ();
1136 m_stmt_iter = tsi_start (m_stmt_list);
1137 m_inner_block = make_node (BLOCK);
1138 m_inner_bind_expr =
1139 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1141 else
1143 m_inner_block = NULL;
1144 m_stmt_list = NULL;
1148 /* Hand-written GC-marking hook for playback functions. */
1150 void
1151 playback::function::
1152 gt_ggc_mx ()
1154 gt_ggc_m_9tree_node (m_inner_fndecl);
1155 gt_ggc_m_9tree_node (m_inner_bind_expr);
1156 gt_ggc_m_9tree_node (m_stmt_list);
1157 gt_ggc_m_9tree_node (m_inner_block);
1160 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1161 GC-ed. */
1163 void
1164 playback::function::finalizer ()
1166 m_blocks.release ();
1169 /* Get the return type of a playback function, in tree form. */
1171 tree
1172 playback::function::
1173 get_return_type_as_tree () const
1175 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1178 /* Construct a new local within this playback::function. */
1180 playback::lvalue *
1181 playback::function::
1182 new_local (location *loc,
1183 type *type,
1184 const char *name)
1186 gcc_assert (type);
1187 gcc_assert (name);
1188 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1189 get_identifier (name),
1190 type->as_tree ());
1191 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1193 /* Prepend to BIND_EXPR_VARS: */
1194 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1195 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1197 if (loc)
1198 set_tree_location (inner, loc);
1199 return new lvalue (m_ctxt, inner);
1202 /* Construct a new block within this playback::function. */
1204 playback::block *
1205 playback::function::
1206 new_block (const char *name)
1208 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1210 block *result = new playback::block (this, name);
1211 m_blocks.safe_push (result);
1212 return result;
1215 /* Build a statement list for the function as a whole out of the
1216 lists of statements for the individual blocks, building labels
1217 for each block. */
1219 void
1220 playback::function::
1221 build_stmt_list ()
1223 int i;
1224 block *b;
1226 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1228 FOR_EACH_VEC_ELT (m_blocks, i, b)
1230 int j;
1231 tree stmt;
1233 b->m_label_expr = build1 (LABEL_EXPR,
1234 void_type_node,
1235 b->as_label_decl ());
1236 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1238 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1239 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1243 /* Finish compiling the given function, potentially running the
1244 garbage-collector.
1245 The function will have a statement list by now.
1246 Amongst other things, this gimplifies the statement list,
1247 and calls cgraph_node::finalize_function on the function. */
1249 void
1250 playback::function::
1251 postprocess ()
1253 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1255 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1256 debug_tree (m_stmt_list);
1258 /* Do we need this to force cgraphunit.c to output the function? */
1259 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1261 DECL_EXTERNAL (m_inner_fndecl) = 0;
1262 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1265 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1266 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1268 DECL_EXTERNAL (m_inner_fndecl) = 0;
1269 TREE_PUBLIC (m_inner_fndecl) = 0;
1272 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1274 /* Seem to need this in gimple-low.c: */
1275 gcc_assert (m_inner_block);
1276 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1278 /* how to add to function? the following appears to be how to
1279 set the body of a m_inner_fndecl: */
1280 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1282 /* Ensure that locals appear in the debuginfo. */
1283 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1285 //debug_tree (m_inner_fndecl);
1287 /* Convert to gimple: */
1288 //printf("about to gimplify_function_tree\n");
1289 gimplify_function_tree (m_inner_fndecl);
1290 //printf("finished gimplify_function_tree\n");
1292 current_function_decl = m_inner_fndecl;
1293 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1294 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1295 //debug_tree (m_inner_fndecl);
1297 //printf("about to add to cgraph\n");
1298 /* Add to cgraph: */
1299 cgraph_node::finalize_function (m_inner_fndecl, false);
1300 /* This can trigger a collection, so we need to have all of
1301 the funcs as roots. */
1303 current_function_decl = NULL;
1307 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1308 GC-ed. */
1310 void
1311 playback::block::finalizer ()
1313 m_stmts.release ();
1316 /* Add an eval of the rvalue to the function's statement list. */
1318 void
1319 playback::block::
1320 add_eval (location *loc,
1321 rvalue *rvalue)
1323 gcc_assert (rvalue);
1325 if (loc)
1326 set_tree_location (rvalue->as_tree (), loc);
1328 add_stmt (rvalue->as_tree ());
1331 /* Add an assignment to the function's statement list. */
1333 void
1334 playback::block::
1335 add_assignment (location *loc,
1336 lvalue *lvalue,
1337 rvalue *rvalue)
1339 gcc_assert (lvalue);
1340 gcc_assert (rvalue);
1342 tree t_lvalue = lvalue->as_tree ();
1343 tree t_rvalue = rvalue->as_tree ();
1344 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1346 t_rvalue = build1 (CONVERT_EXPR,
1347 TREE_TYPE (t_lvalue),
1348 t_rvalue);
1349 if (loc)
1350 set_tree_location (t_rvalue, loc);
1353 tree stmt =
1354 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1355 t_lvalue, t_rvalue);
1356 if (loc)
1357 set_tree_location (stmt, loc);
1358 add_stmt (stmt);
1361 /* Add a comment to the function's statement list.
1362 For now this is done by adding a dummy label. */
1364 void
1365 playback::block::
1366 add_comment (location *loc,
1367 const char *text)
1369 /* Wrap the text in C-style comment delimiters. */
1370 size_t sz =
1371 (3 /* opening delim */
1372 + strlen (text)
1373 + 3 /* closing delim */
1374 + 1 /* terminator */);
1375 char *wrapped = (char *)ggc_internal_alloc (sz);
1376 snprintf (wrapped, sz, "/* %s */", text);
1378 /* For now we simply implement this by adding a dummy label with a name
1379 containing the given text. */
1380 tree identifier = get_identifier (wrapped);
1381 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1382 identifier, void_type_node);
1383 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1385 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1386 if (loc)
1387 set_tree_location (label_expr, loc);
1388 add_stmt (label_expr);
1391 /* Add a conditional jump statement to the function's statement list. */
1393 void
1394 playback::block::
1395 add_conditional (location *loc,
1396 rvalue *boolval,
1397 block *on_true,
1398 block *on_false)
1400 gcc_assert (boolval);
1401 gcc_assert (on_true);
1402 gcc_assert (on_false);
1404 /* COND_EXPR wants statement lists for the true/false operands, but we
1405 want labels.
1406 Shim it by creating jumps to the labels */
1407 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1408 on_true->as_label_decl ());
1409 if (loc)
1410 set_tree_location (true_jump, loc);
1412 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1413 on_false->as_label_decl ());
1414 if (loc)
1415 set_tree_location (false_jump, loc);
1417 tree stmt =
1418 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1419 true_jump, false_jump);
1420 if (loc)
1421 set_tree_location (stmt, loc);
1422 add_stmt (stmt);
1425 /* Add an unconditional jump statement to the function's statement list. */
1427 void
1428 playback::block::
1429 add_jump (location *loc,
1430 block *target)
1432 gcc_assert (target);
1434 // see c_finish_loop
1435 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1436 //add_stmt (top);
1438 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1439 TREE_USED (target->as_label_decl ()) = 1;
1440 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1441 if (loc)
1442 set_tree_location (stmt, loc);
1443 add_stmt (stmt);
1446 from c-typeck.c:
1447 tree
1448 c_finish_goto_label (location_t loc, tree label)
1450 tree decl = lookup_label_for_goto (loc, label);
1451 if (!decl)
1452 return NULL_TREE;
1453 TREE_USED (decl) = 1;
1455 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1456 SET_EXPR_LOCATION (t, loc);
1457 return add_stmt (t);
1464 /* Add a return statement to the function's statement list. */
1466 void
1467 playback::block::
1468 add_return (location *loc,
1469 rvalue *rvalue)
1471 tree modify_retval = NULL;
1472 tree return_type = m_func->get_return_type_as_tree ();
1473 if (rvalue)
1475 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1476 tree t_rvalue = rvalue->as_tree ();
1477 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1478 t_rvalue = build1 (CONVERT_EXPR,
1479 TREE_TYPE (t_lvalue),
1480 t_rvalue);
1481 modify_retval = build2 (MODIFY_EXPR, return_type,
1482 t_lvalue, t_rvalue);
1483 if (loc)
1484 set_tree_location (modify_retval, loc);
1486 tree return_stmt = build1 (RETURN_EXPR, return_type,
1487 modify_retval);
1488 if (loc)
1489 set_tree_location (return_stmt, loc);
1491 add_stmt (return_stmt);
1494 /* Constructor for gcc::jit::playback::block. */
1496 playback::block::
1497 block (function *func,
1498 const char *name)
1499 : m_func (func),
1500 m_stmts ()
1502 tree identifier;
1504 gcc_assert (func);
1505 // name can be NULL
1506 if (name)
1507 identifier = get_identifier (name);
1508 else
1509 identifier = NULL;
1510 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1511 identifier, void_type_node);
1512 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1513 m_label_expr = NULL;
1516 /* A subclass of auto_vec <char *> that frees all of its elements on
1517 deletion. */
1519 class auto_argvec : public auto_vec <char *>
1521 public:
1522 ~auto_argvec ();
1525 /* auto_argvec's dtor, freeing all contained strings, automatically
1526 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1528 auto_argvec::~auto_argvec ()
1530 int i;
1531 char *str;
1532 FOR_EACH_VEC_ELT (*this, i, str)
1533 free (str);
1536 /* Compile a playback::context:
1538 - Use the context's options to cconstruct command-line options, and
1539 call into the rest of GCC (toplev::main).
1540 - Assuming it succeeds, we have a .s file; we want a .so file.
1541 Invoke another gcc to convert the .s file to a .so file.
1542 - dlopen the .so file
1543 - Wrap the result up as a playback::result and return it. */
1545 result *
1546 playback::context::
1547 compile ()
1549 JIT_LOG_SCOPE (get_logger ());
1551 const char *ctxt_progname;
1552 result *result_obj = NULL;
1554 int keep_intermediates =
1555 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
1557 m_tempdir = new tempdir (keep_intermediates);
1558 if (!m_tempdir->create ())
1559 return NULL;
1561 /* Call into the rest of gcc.
1562 For now, we have to assemble command-line options to pass into
1563 toplev::main, so that they can be parsed. */
1565 /* Pass in user-provided program name as argv0, if any, so that it
1566 makes it into GCC's "progname" global, used in various diagnostics. */
1567 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1569 if (!ctxt_progname)
1570 ctxt_progname = "libgccjit.so";
1572 auto_vec <recording::requested_dump> requested_dumps;
1573 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1575 auto_argvec fake_args;
1576 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
1577 if (errors_occurred ())
1578 return NULL;
1580 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1581 acquire_mutex ();
1583 /* This runs the compiler. */
1584 toplev toplev (false);
1585 enter_scope ("toplev::main");
1586 if (get_logger ())
1587 for (unsigned i = 0; i < fake_args.length (); i++)
1588 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
1589 toplev.main (fake_args.length (),
1590 const_cast <char **> (fake_args.address ()));
1591 exit_scope ("toplev::main");
1593 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1594 need to do it between toplev::main (which creates the dump manager)
1595 and toplev::finalize (which deletes it). */
1596 extract_any_requested_dumps (&requested_dumps);
1598 /* Clean up the compiler. */
1599 enter_scope ("toplev::finalize");
1600 toplev.finalize ();
1601 exit_scope ("toplev::finalize");
1603 /* Ideally we would release the jit mutex here, but we can't yet since
1604 followup activities use timevars, which are global state. */
1606 if (errors_occurred ())
1608 release_mutex ();
1609 return NULL;
1612 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1613 dump_generated_code ();
1615 convert_to_dso (ctxt_progname);
1616 if (errors_occurred ())
1618 release_mutex ();
1619 return NULL;
1622 result_obj = dlopen_built_dso ();
1624 release_mutex ();
1626 return result_obj;
1629 /* Helper functions for gcc::jit::playback::context::compile. */
1631 /* This mutex guards gcc::jit::recording::context::compile, so that only
1632 one thread can be accessing the bulk of GCC's state at once. */
1634 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
1636 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
1638 void
1639 playback::context::acquire_mutex ()
1641 /* Acquire the big GCC mutex. */
1642 JIT_LOG_SCOPE (get_logger ());
1643 pthread_mutex_lock (&jit_mutex);
1644 gcc_assert (NULL == active_playback_ctxt);
1645 active_playback_ctxt = this;
1648 /* Release jit_mutex and clear the active playback ctxt. */
1650 void
1651 playback::context::release_mutex ()
1653 /* Release the big GCC mutex. */
1654 JIT_LOG_SCOPE (get_logger ());
1655 gcc_assert (active_playback_ctxt == this);
1656 active_playback_ctxt = NULL;
1657 pthread_mutex_unlock (&jit_mutex);
1660 /* Build a fake argv for toplev::main from the options set
1661 by the user on the context . */
1663 void
1664 playback::context::
1665 make_fake_args (vec <char *> *argvec,
1666 const char *ctxt_progname,
1667 vec <recording::requested_dump> *requested_dumps)
1669 JIT_LOG_SCOPE (get_logger ());
1671 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
1672 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
1674 ADD_ARG (ctxt_progname);
1675 ADD_ARG (get_path_c_file ());
1676 ADD_ARG ("-fPIC");
1678 /* Handle int options: */
1679 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
1681 default:
1682 add_error (NULL,
1683 "unrecognized optimization level: %i",
1684 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
1685 return;
1687 case 0:
1688 ADD_ARG ("-O0");
1689 break;
1691 case 1:
1692 ADD_ARG ("-O1");
1693 break;
1695 case 2:
1696 ADD_ARG ("-O2");
1697 break;
1699 case 3:
1700 ADD_ARG ("-O3");
1701 break;
1703 /* What about -Os? */
1705 /* Handle bool options: */
1706 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
1707 ADD_ARG ("-g");
1709 /* Suppress timing (and other) info. */
1710 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
1712 ADD_ARG ("-quiet");
1713 quiet_flag = 1;
1716 /* Aggressively garbage-collect, to shake out bugs: */
1717 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
1719 ADD_ARG ("--param");
1720 ADD_ARG ("ggc-min-expand=0");
1721 ADD_ARG ("--param");
1722 ADD_ARG ("ggc-min-heapsize=0");
1725 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
1727 ADD_ARG ("-fdump-tree-all");
1728 ADD_ARG ("-fdump-rtl-all");
1729 ADD_ARG ("-fdump-ipa-all");
1732 /* Add "-fdump-" options for any calls to
1733 gcc_jit_context_enable_dump. */
1735 int i;
1736 recording::requested_dump *d;
1737 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
1739 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
1740 ADD_ARG_TAKE_OWNERSHIP (arg);
1744 #undef ADD_ARG
1745 #undef ADD_ARG_TAKE_OWNERSHIP
1748 /* The second half of the implementation of gcc_jit_context_enable_dump.
1749 Iterate through the requested dumps, reading the underlying files
1750 into heap-allocated buffers, writing pointers to the buffers into
1751 the char ** pointers provided by client code.
1752 Client code is responsible for calling free on the results. */
1754 void
1755 playback::context::
1756 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
1758 JIT_LOG_SCOPE (get_logger ());
1760 int i;
1761 recording::requested_dump *d;
1762 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
1764 dump_file_info *dfi;
1765 char *filename;
1766 char *content;
1768 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
1769 if (!dfi)
1771 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
1772 continue;
1775 filename = g->get_dumps ()->get_dump_file_name (dfi);
1776 content = read_dump_file (filename);
1777 *(d->m_out_ptr) = content;
1778 free (filename);
1782 /* Helper function for playback::context::extract_any_requested_dumps
1783 (itself for use in implementation of gcc_jit_context_enable_dump).
1785 Attempt to read the complete file at the given path, returning the
1786 bytes found there as a buffer.
1787 The caller is responsible for calling free on the result.
1788 Errors will be reported on the context, and lead to NULL being
1789 returned; an out-of-memory error will terminate the process. */
1791 char *
1792 playback::context::read_dump_file (const char *path)
1794 char *result = NULL;
1795 size_t total_sz = 0;
1796 char buf[4096];
1797 size_t sz;
1798 FILE *f_in;
1800 f_in = fopen (path, "r");
1801 if (!f_in)
1803 add_error (NULL, "unable to open %s for reading", path);
1804 return NULL;
1807 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
1809 size_t old_total_sz = total_sz;
1810 total_sz += sz;
1811 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
1812 memcpy (result + old_total_sz, buf, sz);
1815 if (!feof (f_in))
1817 add_error (NULL, "error reading from %s", path);
1818 free (result);
1819 return NULL;
1822 fclose (f_in);
1824 if (result)
1826 result[total_sz] = '\0';
1827 return result;
1829 else
1830 return xstrdup ("");
1833 /* Part of playback::context::compile ().
1835 We have a .s file; we want a .so file.
1836 We could reuse parts of gcc/gcc.c to do this.
1837 For now, just use the driver binary from the install, as
1838 named in gcc-driver-name.h
1839 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
1841 void
1842 playback::context::
1843 convert_to_dso (const char *ctxt_progname)
1845 JIT_LOG_SCOPE (get_logger ());
1846 /* Currently this lumps together both assembling and linking into
1847 TV_ASSEMBLE. */
1848 auto_timevar assemble_timevar (TV_ASSEMBLE);
1849 const char *errmsg;
1850 auto_vec <const char *> argvec;
1851 #define ADD_ARG(arg) argvec.safe_push (arg)
1852 int exit_status = 0;
1853 int err = 0;
1854 const char *gcc_driver_name = GCC_DRIVER_NAME;
1856 ADD_ARG (gcc_driver_name);
1857 ADD_ARG ("-shared");
1858 /* The input: assembler. */
1859 ADD_ARG (m_tempdir->get_path_s_file ());
1860 /* The output: shared library. */
1861 ADD_ARG ("-o");
1862 ADD_ARG (m_tempdir->get_path_so_file ());
1864 /* Don't use the linker plugin.
1865 If running with just a "make" and not a "make install", then we'd
1866 run into
1867 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
1868 libto_plugin is a .la at build time, with it becoming installed with
1869 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
1870 time. */
1871 ADD_ARG ("-fno-use-linker-plugin");
1873 /* pex argv arrays are NULL-terminated. */
1874 ADD_ARG (NULL);
1876 /* pex_one's error-handling requires pname to be non-NULL. */
1877 gcc_assert (ctxt_progname);
1879 if (get_logger ())
1880 for (unsigned i = 0; i < argvec.length (); i++)
1881 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
1883 errmsg = pex_one (PEX_SEARCH, /* int flags, */
1884 gcc_driver_name,
1885 const_cast <char *const *> (argvec.address ()),
1886 ctxt_progname, /* const char *pname */
1887 NULL, /* const char *outname */
1888 NULL, /* const char *errname */
1889 &exit_status, /* int *status */
1890 &err); /* int *err*/
1891 if (errmsg)
1893 add_error (NULL, "error invoking gcc driver: %s", errmsg);
1894 return;
1897 /* pex_one can return a NULL errmsg when the executable wasn't
1898 found (or doesn't exist), so trap these cases also. */
1899 if (exit_status || err)
1901 add_error (NULL,
1902 "error invoking gcc driver: exit_status: %i err: %i",
1903 exit_status, err);
1904 add_error (NULL,
1905 "whilst attempting to run a driver named: %s",
1906 gcc_driver_name);
1907 add_error (NULL,
1908 "PATH was: %s",
1909 getenv ("PATH"));
1910 return;
1912 #undef ADD_ARG
1915 /* Dynamically-link the built DSO file into this process, using dlopen.
1916 Wrap it up within a jit::result *, and return that.
1917 Return NULL if any errors occur, reporting them on this context. */
1919 result *
1920 playback::context::
1921 dlopen_built_dso ()
1923 JIT_LOG_SCOPE (get_logger ());
1924 auto_timevar load_timevar (TV_LOAD);
1925 void *handle = NULL;
1926 const char *error = NULL;
1927 result *result_obj = NULL;
1929 /* Clear any existing error. */
1930 dlerror ();
1932 handle = dlopen (m_tempdir->get_path_so_file (),
1933 RTLD_NOW | RTLD_LOCAL);
1934 if ((error = dlerror()) != NULL) {
1935 add_error (NULL, "%s", error);
1937 if (handle)
1938 result_obj = new result (get_logger (), handle);
1939 else
1940 result_obj = NULL;
1942 return result_obj;
1945 /* Top-level hook for playing back a recording context.
1947 This plays back m_recording_ctxt, and, if no errors
1948 occurred builds statement lists for and then postprocesses
1949 every function in the result. */
1951 void
1952 playback::context::
1953 replay ()
1955 JIT_LOG_SCOPE (get_logger ());
1956 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
1957 tree array_domain_type = build_index_type (size_int (200));
1958 m_char_array_type_node
1959 = build_array_type (char_type_node, array_domain_type);
1961 m_const_char_ptr
1962 = build_pointer_type (build_qualified_type (char_type_node,
1963 TYPE_QUAL_CONST));
1965 /* Replay the recorded events: */
1966 timevar_push (TV_JIT_REPLAY);
1968 m_recording_ctxt->replay_into (this);
1970 /* Clean away the temporary references from recording objects
1971 to playback objects. We have to do this now since the
1972 latter are GC-allocated, but the former don't mark these
1973 refs. Hence we must stop using them before the GC can run. */
1974 m_recording_ctxt->disassociate_from_playback ();
1976 /* The builtins_manager, if any, is associated with the recording::context
1977 and might be reused for future compiles on other playback::contexts,
1978 but its m_attributes array is not GTY-labeled and hence will become
1979 nonsense if the GC runs. Purge this state. */
1980 builtins_manager *bm = get_builtins_manager ();
1981 if (bm)
1982 bm->finish_playback ();
1984 timevar_pop (TV_JIT_REPLAY);
1986 if (!errors_occurred ())
1988 int i;
1989 function *func;
1991 /* No GC can happen yet; process the cached source locations. */
1992 handle_locations ();
1994 /* We've now created tree nodes for the stmts in the various blocks
1995 in each function, but we haven't built each function's single stmt
1996 list yet. Do so now. */
1997 FOR_EACH_VEC_ELT (m_functions, i, func)
1998 func->build_stmt_list ();
2000 /* No GC can have happened yet. */
2002 /* Postprocess the functions. This could trigger GC. */
2003 FOR_EACH_VEC_ELT (m_functions, i, func)
2005 gcc_assert (func);
2006 func->postprocess ();
2011 /* Dump the generated .s file to stderr. */
2013 void
2014 playback::context::
2015 dump_generated_code ()
2017 JIT_LOG_SCOPE (get_logger ());
2018 char buf[4096];
2019 size_t sz;
2020 FILE *f_in = fopen (get_path_s_file (), "r");
2021 if (!f_in)
2022 return;
2024 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2025 fwrite (buf, 1, sz, stderr);
2027 fclose (f_in);
2030 /* Get the supposed path of the notional "fake.c" file within the
2031 tempdir. This file doesn't exist, but the rest of the compiler
2032 needs a name. */
2034 const char *
2035 playback::context::
2036 get_path_c_file () const
2038 return m_tempdir->get_path_c_file ();
2041 /* Get the path of the assembler output file "fake.s" file within the
2042 tempdir. */
2044 const char *
2045 playback::context::
2046 get_path_s_file () const
2048 return m_tempdir->get_path_s_file ();
2051 /* Get the path of the DSO object file "fake.so" file within the
2052 tempdir. */
2054 const char *
2055 playback::context::
2056 get_path_so_file () const
2058 return m_tempdir->get_path_so_file ();
2061 /* qsort comparator for comparing pairs of playback::source_line *,
2062 ordering them by line number. */
2064 static int
2065 line_comparator (const void *lhs, const void *rhs)
2067 const playback::source_line *line_lhs = \
2068 *static_cast<const playback::source_line * const*> (lhs);
2069 const playback::source_line *line_rhs = \
2070 *static_cast<const playback::source_line * const*> (rhs);
2071 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2074 /* qsort comparator for comparing pairs of playback::location *,
2075 ordering them by column number. */
2077 static int
2078 location_comparator (const void *lhs, const void *rhs)
2080 const playback::location *loc_lhs = \
2081 *static_cast<const playback::location * const *> (lhs);
2082 const playback::location *loc_rhs = \
2083 *static_cast<const playback::location * const *> (rhs);
2084 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2087 /* Our API allows locations to be created in arbitrary orders, but the
2088 linemap API requires locations to be created in ascending order
2089 as if we were tokenizing files.
2091 This hook sorts all of the the locations that have been created, and
2092 calls into the linemap API, creating linemap entries in sorted order
2093 for our locations. */
2095 void
2096 playback::context::
2097 handle_locations ()
2099 /* Create the source code locations, following the ordering rules
2100 imposed by the linemap API.
2102 line_table is a global. */
2103 JIT_LOG_SCOPE (get_logger ());
2104 int i;
2105 source_file *file;
2107 FOR_EACH_VEC_ELT (m_source_files, i, file)
2109 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2111 /* Sort lines by ascending line numbers. */
2112 file->m_source_lines.qsort (&line_comparator);
2114 int j;
2115 source_line *line;
2116 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2118 int k;
2119 location *loc;
2121 /* Sort locations in line by ascending column numbers. */
2122 line->m_locations.qsort (&location_comparator);
2124 /* Determine maximum column within this line. */
2125 gcc_assert (line->m_locations.length () > 0);
2126 location *final_column =
2127 line->m_locations[line->m_locations.length () - 1];
2128 int max_col = final_column->get_column_num ();
2130 linemap_line_start (line_table, line->get_line_num (), max_col);
2131 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2133 loc->m_srcloc = \
2134 linemap_position_for_column (line_table, loc->get_column_num ());
2138 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2141 /* line_table should now be populated; every playback::location should
2142 now have an m_srcloc. */
2144 /* Now assign them to tree nodes as appropriate. */
2145 std::pair<tree, location *> *cached_location;
2147 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2149 tree t = cached_location->first;
2150 source_location srcloc = cached_location->second->m_srcloc;
2152 /* This covers expressions: */
2153 if (CAN_HAVE_LOCATION_P (t))
2154 SET_EXPR_LOCATION (t, srcloc);
2155 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2156 DECL_SOURCE_LOCATION (t) = srcloc;
2157 else
2159 /* Don't know how to set location on this node. */
2164 /* We handle errors on a playback::context by adding them to the
2165 corresponding recording::context. */
2167 void
2168 playback::context::
2169 add_error (location *loc, const char *fmt, ...)
2171 va_list ap;
2172 va_start (ap, fmt);
2173 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2174 fmt, ap);
2175 va_end (ap);
2178 /* We handle errors on a playback::context by adding them to the
2179 corresponding recording::context. */
2181 void
2182 playback::context::
2183 add_error_va (location *loc, const char *fmt, va_list ap)
2185 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2186 fmt, ap);
2189 /* Dealing with the linemap API. */
2191 /* Construct a playback::location for a recording::location, if it
2192 doesn't exist already. */
2194 playback::location *
2195 playback::context::
2196 new_location (recording::location *rloc,
2197 const char *filename,
2198 int line,
2199 int column)
2201 /* Get the source_file for filename, creating if necessary. */
2202 source_file *src_file = get_source_file (filename);
2203 /* Likewise for the line within the file. */
2204 source_line *src_line = src_file->get_source_line (line);
2205 /* Likewise for the column within the line. */
2206 location *loc = src_line->get_location (rloc, column);
2207 return loc;
2210 /* Deferred setting of the location for a given tree, by adding the
2211 (tree, playback::location) pair to a list of deferred associations.
2212 We will actually set the location on the tree later on once
2213 the source_location for the playback::location exists. */
2215 void
2216 playback::context::
2217 set_tree_location (tree t, location *loc)
2219 gcc_assert (loc);
2220 m_cached_locations.safe_push (std::make_pair (t, loc));
2224 /* Construct a playback::source_file for the given source
2225 filename, if it doesn't exist already. */
2227 playback::source_file *
2228 playback::context::
2229 get_source_file (const char *filename)
2231 /* Locate the file.
2232 For simplicitly, this is currently a linear search.
2233 Replace with a hash if this shows up in the profile. */
2234 int i;
2235 source_file *file;
2236 tree ident_filename = get_identifier (filename);
2238 FOR_EACH_VEC_ELT (m_source_files, i, file)
2239 if (file->filename_as_tree () == ident_filename)
2240 return file;
2242 /* Not found. */
2243 file = new source_file (ident_filename);
2244 m_source_files.safe_push (file);
2245 return file;
2248 /* Constructor for gcc::jit::playback::source_file. */
2250 playback::source_file::source_file (tree filename) :
2251 m_source_lines (),
2252 m_filename (filename)
2256 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2257 GC-ed. */
2259 void
2260 playback::source_file::finalizer ()
2262 m_source_lines.release ();
2265 /* Construct a playback::source_line for the given line
2266 within this source file, if one doesn't exist already. */
2268 playback::source_line *
2269 playback::source_file::
2270 get_source_line (int line_num)
2272 /* Locate the line.
2273 For simplicitly, this is currently a linear search.
2274 Replace with a hash if this shows up in the profile. */
2275 int i;
2276 source_line *line;
2278 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2279 if (line->get_line_num () == line_num)
2280 return line;
2282 /* Not found. */
2283 line = new source_line (this, line_num);
2284 m_source_lines.safe_push (line);
2285 return line;
2288 /* Constructor for gcc::jit::playback::source_line. */
2290 playback::source_line::source_line (source_file *file, int line_num) :
2291 m_locations (),
2292 m_source_file (file),
2293 m_line_num (line_num)
2297 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2298 GC-ed. */
2300 void
2301 playback::source_line::finalizer ()
2303 m_locations.release ();
2306 /* Construct a playback::location for the given column
2307 within this line of a specific source file, if one doesn't exist
2308 already. */
2310 playback::location *
2311 playback::source_line::
2312 get_location (recording::location *rloc, int column_num)
2314 int i;
2315 location *loc;
2317 /* Another linear search that probably should be a hash table. */
2318 FOR_EACH_VEC_ELT (m_locations, i, loc)
2319 if (loc->get_column_num () == column_num)
2320 return loc;
2322 /* Not found. */
2323 loc = new location (rloc, this, column_num);
2324 m_locations.safe_push (loc);
2325 return loc;
2328 /* Constructor for gcc::jit::playback::location. */
2330 playback::location::location (recording::location *loc,
2331 source_line *line,
2332 int column_num) :
2333 m_srcloc (UNKNOWN_LOCATION),
2334 m_recording_loc (loc),
2335 m_line (line),
2336 m_column_num(column_num)
2340 /* The active gcc::jit::playback::context instance. This is a singleton,
2341 guarded by jit_mutex. */
2343 playback::context *active_playback_ctxt;
2345 } // namespace gcc::jit
2347 } // namespace gcc