Daily bump.
[official-gcc.git] / gcc / jit / jit-playback.c
blob84989005b446bc5d308d3734c436e656c00a2d24
1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2014 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-playback.h"
54 #include "jit-result.h"
55 #include "jit-builtins.h"
56 #include "jit-tempdir.h"
59 /* gcc::jit::playback::context::build_cast uses the convert.h API,
60 which in turn requires the frontend to provide a "convert"
61 function, apparently as a fallback.
63 Hence we provide this dummy one, with the requirement that any casts
64 are handled before reaching this. */
65 extern tree convert (tree type, tree expr);
67 tree
68 convert (tree dst_type, tree expr)
70 gcc_assert (gcc::jit::active_playback_ctxt);
71 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
72 fprintf (stderr, "input expression:\n");
73 debug_tree (expr);
74 fprintf (stderr, "requested type:\n");
75 debug_tree (dst_type);
76 return error_mark_node;
79 namespace gcc {
80 namespace jit {
82 /**********************************************************************
83 Playback.
84 **********************************************************************/
86 /* The constructor for gcc::jit::playback::context. */
88 playback::context::context (recording::context *ctxt)
89 : m_recording_ctxt (ctxt),
90 m_tempdir (NULL),
91 m_char_array_type_node (NULL),
92 m_const_char_ptr (NULL)
94 m_functions.create (0);
95 m_source_files.create (0);
96 m_cached_locations.create (0);
99 /* The destructor for gcc::jit::playback::context. */
101 playback::context::~context ()
103 if (m_tempdir)
104 delete m_tempdir;
105 m_functions.release ();
108 /* A playback::context can reference GC-managed pointers. Mark them
109 ("by hand", rather than by gengtype).
111 This is called on the active playback context (if any) by the
112 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
114 void
115 playback::context::
116 gt_ggc_mx ()
118 int i;
119 function *func;
120 FOR_EACH_VEC_ELT (m_functions, i, func)
122 if (ggc_test_and_set_mark (func))
123 func->gt_ggc_mx ();
127 /* Given an enum gcc_jit_types value, get a "tree" type. */
129 static tree
130 get_tree_node_for_type (enum gcc_jit_types type_)
132 switch (type_)
134 case GCC_JIT_TYPE_VOID:
135 return void_type_node;
137 case GCC_JIT_TYPE_VOID_PTR:
138 return ptr_type_node;
140 case GCC_JIT_TYPE_BOOL:
141 return boolean_type_node;
143 case GCC_JIT_TYPE_CHAR:
144 return char_type_node;
145 case GCC_JIT_TYPE_SIGNED_CHAR:
146 return signed_char_type_node;
147 case GCC_JIT_TYPE_UNSIGNED_CHAR:
148 return unsigned_char_type_node;
150 case GCC_JIT_TYPE_SHORT:
151 return short_integer_type_node;
152 case GCC_JIT_TYPE_UNSIGNED_SHORT:
153 return short_unsigned_type_node;
155 case GCC_JIT_TYPE_CONST_CHAR_PTR:
157 tree const_char = build_qualified_type (char_type_node,
158 TYPE_QUAL_CONST);
159 return build_pointer_type (const_char);
162 case GCC_JIT_TYPE_INT:
163 return integer_type_node;
164 case GCC_JIT_TYPE_UNSIGNED_INT:
165 return unsigned_type_node;
167 case GCC_JIT_TYPE_LONG:
168 return long_integer_type_node;
169 case GCC_JIT_TYPE_UNSIGNED_LONG:
170 return long_unsigned_type_node;
172 case GCC_JIT_TYPE_LONG_LONG:
173 return long_long_integer_type_node;
174 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
175 return long_long_unsigned_type_node;
177 case GCC_JIT_TYPE_FLOAT:
178 return float_type_node;
179 case GCC_JIT_TYPE_DOUBLE:
180 return double_type_node;
181 case GCC_JIT_TYPE_LONG_DOUBLE:
182 return long_double_type_node;
184 case GCC_JIT_TYPE_SIZE_T:
185 return size_type_node;
187 case GCC_JIT_TYPE_FILE_PTR:
188 return fileptr_type_node;
190 case GCC_JIT_TYPE_COMPLEX_FLOAT:
191 return complex_float_type_node;
192 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
193 return complex_double_type_node;
194 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
195 return complex_long_double_type_node;
198 return NULL;
201 /* Construct a playback::type instance (wrapping a tree) for the given
202 enum value. */
204 playback::type *
205 playback::context::
206 get_type (enum gcc_jit_types type_)
208 tree type_node = get_tree_node_for_type (type_);
209 if (NULL == type_node)
211 add_error (NULL,
212 "unrecognized (enum gcc_jit_types) value: %i", type_);
213 return NULL;
216 return new type (type_node);
219 /* Construct a playback::type instance (wrapping a tree) for the given
220 array type. */
222 playback::type *
223 playback::context::
224 new_array_type (playback::location *loc,
225 playback::type *element_type,
226 int num_elements)
228 gcc_assert (element_type);
230 tree t = build_array_type_nelts (element_type->as_tree (),
231 num_elements);
232 layout_type (t);
234 if (loc)
235 set_tree_location (t, loc);
237 return new type (t);
240 /* Construct a playback::field instance (wrapping a tree). */
242 playback::field *
243 playback::context::
244 new_field (location *loc,
245 type *type,
246 const char *name)
248 gcc_assert (type);
249 gcc_assert (name);
251 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
252 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
253 get_identifier (name), type->as_tree ());
255 if (loc)
256 set_tree_location (decl, loc);
258 return new field (decl);
261 /* Construct a playback::compound_type instance (wrapping a tree). */
263 playback::compound_type *
264 playback::context::
265 new_compound_type (location *loc,
266 const char *name,
267 bool is_struct) /* else is union */
269 gcc_assert (name);
271 /* Compare with c/c-decl.c: start_struct. */
273 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
274 TYPE_NAME (t) = get_identifier (name);
275 TYPE_SIZE (t) = 0;
277 if (loc)
278 set_tree_location (t, loc);
280 return new compound_type (t);
283 void
284 playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
286 /* Compare with c/c-decl.c: finish_struct. */
287 tree t = as_tree ();
289 tree fieldlist = NULL;
290 for (unsigned i = 0; i < fields->length (); i++)
292 field *f = (*fields)[i];
293 DECL_CONTEXT (f->as_tree ()) = t;
294 fieldlist = chainon (f->as_tree (), fieldlist);
296 fieldlist = nreverse (fieldlist);
297 TYPE_FIELDS (t) = fieldlist;
299 layout_type (t);
302 /* Construct a playback::type instance (wrapping a tree) for a function
303 type. */
305 playback::type *
306 playback::context::
307 new_function_type (type *return_type,
308 const auto_vec<type *> *param_types,
309 int is_variadic)
311 int i;
312 type *param_type;
314 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
316 FOR_EACH_VEC_ELT (*param_types, i, param_type)
317 arg_types[i] = param_type->as_tree ();
319 tree fn_type;
320 if (is_variadic)
321 fn_type =
322 build_varargs_function_type_array (return_type->as_tree (),
323 param_types->length (),
324 arg_types);
325 else
326 fn_type = build_function_type_array (return_type->as_tree (),
327 param_types->length (),
328 arg_types);
329 free (arg_types);
331 return new type (fn_type);
334 /* Construct a playback::param instance (wrapping a tree). */
336 playback::param *
337 playback::context::
338 new_param (location *loc,
339 type *type,
340 const char *name)
342 gcc_assert (type);
343 gcc_assert (name);
344 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
345 get_identifier (name), type->as_tree ());
346 if (loc)
347 set_tree_location (inner, loc);
349 return new param (this, inner);
352 /* Construct a playback::function instance. */
354 playback::function *
355 playback::context::
356 new_function (location *loc,
357 enum gcc_jit_function_kind kind,
358 type *return_type,
359 const char *name,
360 const auto_vec<param *> *params,
361 int is_variadic,
362 enum built_in_function builtin_id)
364 int i;
365 param *param;
367 //can return_type be NULL?
368 gcc_assert (name);
370 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
371 FOR_EACH_VEC_ELT (*params, i, param)
372 arg_types[i] = TREE_TYPE (param->as_tree ());
374 tree fn_type;
375 if (is_variadic)
376 fn_type = build_varargs_function_type_array (return_type->as_tree (),
377 params->length (), arg_types);
378 else
379 fn_type = build_function_type_array (return_type->as_tree (),
380 params->length (), arg_types);
381 free (arg_types);
383 /* FIXME: this uses input_location: */
384 tree fndecl = build_fn_decl (name, fn_type);
386 if (loc)
387 set_tree_location (fndecl, loc);
389 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
390 NULL_TREE, return_type->as_tree ());
391 DECL_ARTIFICIAL (resdecl) = 1;
392 DECL_IGNORED_P (resdecl) = 1;
393 DECL_RESULT (fndecl) = resdecl;
395 if (builtin_id)
397 DECL_FUNCTION_CODE (fndecl) = builtin_id;
398 gcc_assert (loc == NULL);
399 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
401 DECL_BUILT_IN_CLASS (fndecl) =
402 builtins_manager::get_class (builtin_id);
403 set_builtin_decl (builtin_id, fndecl,
404 builtins_manager::implicit_p (builtin_id));
406 builtins_manager *bm = get_builtins_manager ();
407 tree attrs = bm->get_attrs_tree (builtin_id);
408 if (attrs)
409 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
410 else
411 decl_attributes (&fndecl, NULL_TREE, 0);
414 if (kind != GCC_JIT_FUNCTION_IMPORTED)
416 tree param_decl_list = NULL;
417 FOR_EACH_VEC_ELT (*params, i, param)
419 param_decl_list = chainon (param->as_tree (), param_decl_list);
422 /* The param list was created in reverse order; fix it: */
423 param_decl_list = nreverse (param_decl_list);
425 tree t;
426 for (t = param_decl_list; t; t = DECL_CHAIN (t))
428 DECL_CONTEXT (t) = fndecl;
429 DECL_ARG_TYPE (t) = TREE_TYPE (t);
432 /* Set it up on DECL_ARGUMENTS */
433 DECL_ARGUMENTS(fndecl) = param_decl_list;
436 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
438 DECL_DECLARED_INLINE_P (fndecl) = 1;
440 /* Add attribute "always_inline": */
441 DECL_ATTRIBUTES (fndecl) =
442 tree_cons (get_identifier ("always_inline"),
443 NULL,
444 DECL_ATTRIBUTES (fndecl));
447 function *func = new function (this, fndecl, kind);
448 m_functions.safe_push (func);
449 return func;
452 /* Construct a playback::lvalue instance (wrapping a tree). */
454 playback::lvalue *
455 playback::context::
456 new_global (location *loc,
457 type *type,
458 const char *name)
460 gcc_assert (type);
461 gcc_assert (name);
462 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
463 get_identifier (name),
464 type->as_tree ());
465 TREE_PUBLIC (inner) = 1;
466 DECL_COMMON (inner) = 1;
467 DECL_EXTERNAL (inner) = 1;
469 if (loc)
470 set_tree_location (inner, loc);
472 return new lvalue (this, inner);
475 /* Construct a playback::rvalue instance (wrapping a tree). */
477 playback::rvalue *
478 playback::context::
479 new_rvalue_from_int (type *type,
480 int value)
482 // FIXME: type-checking, or coercion?
483 tree inner_type = type->as_tree ();
484 if (INTEGRAL_TYPE_P (inner_type))
486 tree inner = build_int_cst (inner_type, value);
487 return new rvalue (this, inner);
489 else
491 REAL_VALUE_TYPE real_value;
492 real_from_integer (&real_value, VOIDmode, value, SIGNED);
493 tree inner = build_real (inner_type, real_value);
494 return new rvalue (this, inner);
498 /* Construct a playback::rvalue instance (wrapping a tree). */
500 playback::rvalue *
501 playback::context::
502 new_rvalue_from_double (type *type,
503 double value)
505 // FIXME: type-checking, or coercion?
506 tree inner_type = type->as_tree ();
508 /* We have a "double", we want a REAL_VALUE_TYPE.
510 real.c:real_from_target appears to require the representation to be
511 split into 32-bit values, and then sent as an pair of host long
512 ints. */
513 REAL_VALUE_TYPE real_value;
514 union
516 double as_double;
517 uint32_t as_uint32s[2];
518 } u;
519 u.as_double = value;
520 long int as_long_ints[2];
521 as_long_ints[0] = u.as_uint32s[0];
522 as_long_ints[1] = u.as_uint32s[1];
523 real_from_target (&real_value, as_long_ints, DFmode);
524 tree inner = build_real (inner_type, real_value);
525 return new rvalue (this, inner);
528 /* Construct a playback::rvalue instance (wrapping a tree). */
530 playback::rvalue *
531 playback::context::
532 new_rvalue_from_ptr (type *type,
533 void *value)
535 tree inner_type = type->as_tree ();
536 /* FIXME: how to ensure we have a wide enough type? */
537 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
538 return new rvalue (this, inner);
541 /* Construct a playback::rvalue instance (wrapping a tree). */
543 playback::rvalue *
544 playback::context::
545 new_string_literal (const char *value)
547 tree t_str = build_string (strlen (value), value);
548 gcc_assert (m_char_array_type_node);
549 TREE_TYPE (t_str) = m_char_array_type_node;
551 /* Convert to (const char*), loosely based on
552 c/c-typeck.c: array_to_pointer_conversion,
553 by taking address of start of string. */
554 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
556 return new rvalue (this, t_addr);
559 /* Coerce a tree expression into a boolean tree expression. */
561 tree
562 playback::context::
563 as_truth_value (tree expr, location *loc)
565 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
566 tree typed_zero = fold_build1 (CONVERT_EXPR,
567 TREE_TYPE (expr),
568 integer_zero_node);
569 if (loc)
570 set_tree_location (typed_zero, loc);
572 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
573 if (loc)
574 set_tree_location (expr, loc);
576 return expr;
579 /* Construct a playback::rvalue instance (wrapping a tree) for a
580 unary op. */
582 playback::rvalue *
583 playback::context::
584 new_unary_op (location *loc,
585 enum gcc_jit_unary_op op,
586 type *result_type,
587 rvalue *a)
589 // FIXME: type-checking, or coercion?
590 enum tree_code inner_op;
592 gcc_assert (result_type);
593 gcc_assert (a);
595 tree node = a->as_tree ();
596 tree inner_result = NULL;
598 switch (op)
600 default:
601 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
602 return NULL;
604 case GCC_JIT_UNARY_OP_MINUS:
605 inner_op = NEGATE_EXPR;
606 break;
608 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
609 inner_op = BIT_NOT_EXPR;
610 break;
612 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
613 node = as_truth_value (node, loc);
614 inner_result = invert_truthvalue (node);
615 if (loc)
616 set_tree_location (inner_result, loc);
617 return new rvalue (this, inner_result);
620 inner_result = build1 (inner_op,
621 result_type->as_tree (),
622 node);
623 if (loc)
624 set_tree_location (inner_result, loc);
626 return new rvalue (this, inner_result);
629 /* Construct a playback::rvalue instance (wrapping a tree) for a
630 binary op. */
632 playback::rvalue *
633 playback::context::
634 new_binary_op (location *loc,
635 enum gcc_jit_binary_op op,
636 type *result_type,
637 rvalue *a, rvalue *b)
639 // FIXME: type-checking, or coercion?
640 enum tree_code inner_op;
642 gcc_assert (result_type);
643 gcc_assert (a);
644 gcc_assert (b);
646 tree node_a = a->as_tree ();
647 tree node_b = b->as_tree ();
649 switch (op)
651 default:
652 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
653 return NULL;
655 case GCC_JIT_BINARY_OP_PLUS:
656 inner_op = PLUS_EXPR;
657 break;
659 case GCC_JIT_BINARY_OP_MINUS:
660 inner_op = MINUS_EXPR;
661 break;
663 case GCC_JIT_BINARY_OP_MULT:
664 inner_op = MULT_EXPR;
665 break;
667 case GCC_JIT_BINARY_OP_DIVIDE:
668 if (FLOAT_TYPE_P (result_type->as_tree ()))
669 /* Floating-point division: */
670 inner_op = RDIV_EXPR;
671 else
672 /* Truncating to zero: */
673 inner_op = TRUNC_DIV_EXPR;
674 break;
676 case GCC_JIT_BINARY_OP_MODULO:
677 inner_op = TRUNC_MOD_EXPR;
678 break;
680 case GCC_JIT_BINARY_OP_BITWISE_AND:
681 inner_op = BIT_AND_EXPR;
682 break;
684 case GCC_JIT_BINARY_OP_BITWISE_XOR:
685 inner_op = BIT_XOR_EXPR;
686 break;
688 case GCC_JIT_BINARY_OP_BITWISE_OR:
689 inner_op = BIT_IOR_EXPR;
690 break;
692 case GCC_JIT_BINARY_OP_LOGICAL_AND:
693 node_a = as_truth_value (node_a, loc);
694 node_b = as_truth_value (node_b, loc);
695 inner_op = TRUTH_ANDIF_EXPR;
696 break;
698 case GCC_JIT_BINARY_OP_LOGICAL_OR:
699 node_a = as_truth_value (node_a, loc);
700 node_b = as_truth_value (node_b, loc);
701 inner_op = TRUTH_ORIF_EXPR;
702 break;
704 case GCC_JIT_BINARY_OP_LSHIFT:
705 inner_op = LSHIFT_EXPR;
706 break;
708 case GCC_JIT_BINARY_OP_RSHIFT:
709 inner_op = RSHIFT_EXPR;
710 break;
713 tree inner_expr = build2 (inner_op,
714 result_type->as_tree (),
715 node_a,
716 node_b);
717 if (loc)
718 set_tree_location (inner_expr, loc);
720 return new rvalue (this, inner_expr);
723 /* Construct a playback::rvalue instance (wrapping a tree) for a
724 comparison. */
726 playback::rvalue *
727 playback::context::
728 new_comparison (location *loc,
729 enum gcc_jit_comparison op,
730 rvalue *a, rvalue *b)
732 // FIXME: type-checking, or coercion?
733 enum tree_code inner_op;
735 gcc_assert (a);
736 gcc_assert (b);
738 switch (op)
740 default:
741 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
742 return NULL;
744 case GCC_JIT_COMPARISON_EQ:
745 inner_op = EQ_EXPR;
746 break;
747 case GCC_JIT_COMPARISON_NE:
748 inner_op = NE_EXPR;
749 break;
750 case GCC_JIT_COMPARISON_LT:
751 inner_op = LT_EXPR;
752 break;
753 case GCC_JIT_COMPARISON_LE:
754 inner_op = LE_EXPR;
755 break;
756 case GCC_JIT_COMPARISON_GT:
757 inner_op = GT_EXPR;
758 break;
759 case GCC_JIT_COMPARISON_GE:
760 inner_op = GE_EXPR;
761 break;
764 tree inner_expr = build2 (inner_op,
765 boolean_type_node,
766 a->as_tree (),
767 b->as_tree ());
768 if (loc)
769 set_tree_location (inner_expr, loc);
770 return new rvalue (this, inner_expr);
773 /* Construct a playback::rvalue instance (wrapping a tree) for a
774 function call. */
776 playback::rvalue *
777 playback::context::
778 build_call (location *loc,
779 tree fn_ptr,
780 const auto_vec<rvalue *> *args)
782 vec<tree, va_gc> *tree_args;
783 vec_alloc (tree_args, args->length ());
784 for (unsigned i = 0; i < args->length (); i++)
785 tree_args->quick_push ((*args)[i]->as_tree ());
787 if (loc)
788 set_tree_location (fn_ptr, loc);
790 tree fn = TREE_TYPE (fn_ptr);
791 tree fn_type = TREE_TYPE (fn);
792 tree return_type = TREE_TYPE (fn_type);
794 return new rvalue (this,
795 build_call_vec (return_type,
796 fn_ptr, tree_args));
798 /* see c-typeck.c: build_function_call
799 which calls build_function_call_vec
801 which does lots of checking, then:
802 result = build_call_array_loc (loc, TREE_TYPE (fntype),
803 function, nargs, argarray);
804 which is in tree.c
805 (see also build_call_vec)
809 /* Construct a playback::rvalue instance (wrapping a tree) for a
810 call to a specific function. */
812 playback::rvalue *
813 playback::context::
814 new_call (location *loc,
815 function *func,
816 const auto_vec<rvalue *> *args)
818 tree fndecl;
820 gcc_assert (func);
822 fndecl = func->as_fndecl ();
824 tree fntype = TREE_TYPE (fndecl);
826 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
828 return build_call (loc, fn, args);
831 /* Construct a playback::rvalue instance (wrapping a tree) for a
832 call through a function pointer. */
834 playback::rvalue *
835 playback::context::
836 new_call_through_ptr (location *loc,
837 rvalue *fn_ptr,
838 const auto_vec<rvalue *> *args)
840 gcc_assert (fn_ptr);
841 tree t_fn_ptr = fn_ptr->as_tree ();
843 return build_call (loc, t_fn_ptr, args);
846 /* Construct a tree for a cast. */
848 tree
849 playback::context::build_cast (playback::location *loc,
850 playback::rvalue *expr,
851 playback::type *type_)
853 /* For comparison, see:
854 - c/c-typeck.c:build_c_cast
855 - c/c-convert.c: convert
856 - convert.h
858 Only some kinds of cast are currently supported here. */
859 tree t_expr = expr->as_tree ();
860 tree t_dst_type = type_->as_tree ();
861 tree t_ret = NULL;
862 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
863 if (t_ret)
864 return t_ret;
865 enum tree_code dst_code = TREE_CODE (t_dst_type);
866 switch (dst_code)
868 case INTEGER_TYPE:
869 case ENUMERAL_TYPE:
870 t_ret = convert_to_integer (t_dst_type, t_expr);
871 goto maybe_fold;
873 case BOOLEAN_TYPE:
874 /* Compare with c_objc_common_truthvalue_conversion and
875 c_common_truthvalue_conversion. */
876 /* For now, convert to: (t_expr != 0) */
877 t_ret = build2 (NE_EXPR, t_dst_type,
878 t_expr, integer_zero_node);
879 goto maybe_fold;
881 case REAL_TYPE:
882 t_ret = convert_to_real (t_dst_type, t_expr);
883 goto maybe_fold;
885 case POINTER_TYPE:
886 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
887 goto maybe_fold;
889 default:
890 add_error (loc, "couldn't handle cast during playback");
891 fprintf (stderr, "input expression:\n");
892 debug_tree (t_expr);
893 fprintf (stderr, "requested type:\n");
894 debug_tree (t_dst_type);
895 return error_mark_node;
897 maybe_fold:
898 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
899 t_ret = fold (t_ret);
900 return t_ret;
904 /* Construct a playback::rvalue instance (wrapping a tree) for a
905 cast. */
907 playback::rvalue *
908 playback::context::
909 new_cast (playback::location *loc,
910 playback::rvalue *expr,
911 playback::type *type_)
914 tree t_cast = build_cast (loc, expr, type_);
915 if (loc)
916 set_tree_location (t_cast, loc);
917 return new rvalue (this, t_cast);
920 /* Construct a playback::lvalue instance (wrapping a tree) for an
921 array access. */
923 playback::lvalue *
924 playback::context::
925 new_array_access (location *loc,
926 rvalue *ptr,
927 rvalue *index)
929 gcc_assert (ptr);
930 gcc_assert (index);
932 /* For comparison, see:
933 c/c-typeck.c: build_array_ref
934 c-family/c-common.c: pointer_int_sum
936 tree t_ptr = ptr->as_tree ();
937 tree t_index = index->as_tree ();
938 tree t_type_ptr = TREE_TYPE (t_ptr);
939 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
941 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
943 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
944 NULL_TREE, NULL_TREE);
945 if (loc)
946 set_tree_location (t_result, loc);
947 return new lvalue (this, t_result);
949 else
951 /* Convert index to an offset in bytes. */
952 tree t_sizeof = size_in_bytes (t_type_star_ptr);
953 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
954 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
956 /* Locate (ptr + offset). */
957 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
959 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
960 if (loc)
962 set_tree_location (t_sizeof, loc);
963 set_tree_location (t_offset, loc);
964 set_tree_location (t_address, loc);
965 set_tree_location (t_indirection, loc);
968 return new lvalue (this, t_indirection);
972 /* Construct a tree for a field access. */
974 tree
975 playback::context::
976 new_field_access (location *loc,
977 tree datum,
978 field *field)
980 gcc_assert (datum);
981 gcc_assert (field);
983 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
984 build_component_ref. */
985 tree type = TREE_TYPE (datum);
986 gcc_assert (type);
987 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
989 tree t_field = field->as_tree ();
990 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
991 t_field, NULL_TREE);
992 if (loc)
993 set_tree_location (ref, loc);
994 return ref;
997 /* Construct a tree for a dereference. */
999 tree
1000 playback::context::
1001 new_dereference (tree ptr,
1002 location *loc)
1004 gcc_assert (ptr);
1006 tree type = TREE_TYPE (TREE_TYPE(ptr));
1007 tree datum = build1 (INDIRECT_REF, type, ptr);
1008 if (loc)
1009 set_tree_location (datum, loc);
1010 return datum;
1013 /* Construct a playback::lvalue instance (wrapping a tree) for a
1014 field access. */
1016 playback::lvalue *
1017 playback::lvalue::
1018 access_field (location *loc,
1019 field *field)
1021 tree datum = as_tree ();
1022 tree ref = get_context ()->new_field_access (loc, datum, field);
1023 if (!ref)
1024 return NULL;
1025 return new lvalue (get_context (), ref);
1028 /* Construct a playback::rvalue instance (wrapping a tree) for a
1029 field access. */
1031 playback::rvalue *
1032 playback::rvalue::
1033 access_field (location *loc,
1034 field *field)
1036 tree datum = as_tree ();
1037 tree ref = get_context ()->new_field_access (loc, datum, field);
1038 if (!ref)
1039 return NULL;
1040 return new rvalue (get_context (), ref);
1043 /* Construct a playback::lvalue instance (wrapping a tree) for a
1044 dereferenced field access. */
1046 playback::lvalue *
1047 playback::rvalue::
1048 dereference_field (location *loc,
1049 field *field)
1051 tree ptr = as_tree ();
1052 tree datum = get_context ()->new_dereference (ptr, loc);
1053 if (!datum)
1054 return NULL;
1055 tree ref = get_context ()->new_field_access (loc, datum, field);
1056 if (!ref)
1057 return NULL;
1058 return new lvalue (get_context (), ref);
1061 /* Construct a playback::lvalue instance (wrapping a tree) for a
1062 dereference. */
1064 playback::lvalue *
1065 playback::rvalue::
1066 dereference (location *loc)
1068 tree ptr = as_tree ();
1069 tree datum = get_context ()->new_dereference (ptr, loc);
1070 return new lvalue (get_context (), datum);
1073 /* Construct a playback::rvalue instance (wrapping a tree) for an
1074 address-lookup. */
1076 playback::rvalue *
1077 playback::lvalue::
1078 get_address (location *loc)
1080 tree t_lvalue = as_tree ();
1081 tree t_thistype = TREE_TYPE (t_lvalue);
1082 tree t_ptrtype = build_pointer_type (t_thistype);
1083 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1084 if (loc)
1085 get_context ()->set_tree_location (ptr, loc);
1086 return new rvalue (get_context (), ptr);
1089 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1090 Provide this finalization hook for calling then they are collected,
1091 which calls the finalizer vfunc. This allows them to call "release"
1092 on any vec<> within them. */
1094 static void
1095 wrapper_finalizer (void *ptr)
1097 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1098 wrapper->finalizer ();
1101 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1102 allocate them using ggc_internal_cleared_alloc. */
1104 void *
1105 playback::wrapper::
1106 operator new (size_t sz)
1108 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1112 /* Constructor for gcc:jit::playback::function. */
1114 playback::function::
1115 function (context *ctxt,
1116 tree fndecl,
1117 enum gcc_jit_function_kind kind)
1118 : m_ctxt(ctxt),
1119 m_inner_fndecl (fndecl),
1120 m_inner_bind_expr (NULL),
1121 m_kind (kind)
1123 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1125 /* Create a BIND_EXPR, and within it, a statement list. */
1126 m_stmt_list = alloc_stmt_list ();
1127 m_stmt_iter = tsi_start (m_stmt_list);
1128 m_inner_block = make_node (BLOCK);
1129 m_inner_bind_expr =
1130 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1132 else
1134 m_inner_block = NULL;
1135 m_stmt_list = NULL;
1139 /* Hand-written GC-marking hook for playback functions. */
1141 void
1142 playback::function::
1143 gt_ggc_mx ()
1145 gt_ggc_m_9tree_node (m_inner_fndecl);
1146 gt_ggc_m_9tree_node (m_inner_bind_expr);
1147 gt_ggc_m_9tree_node (m_stmt_list);
1148 gt_ggc_m_9tree_node (m_inner_block);
1151 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1152 GC-ed. */
1154 void
1155 playback::function::finalizer ()
1157 m_blocks.release ();
1160 /* Get the return type of a playback function, in tree form. */
1162 tree
1163 playback::function::
1164 get_return_type_as_tree () const
1166 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1169 /* Construct a new local within this playback::function. */
1171 playback::lvalue *
1172 playback::function::
1173 new_local (location *loc,
1174 type *type,
1175 const char *name)
1177 gcc_assert (type);
1178 gcc_assert (name);
1179 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1180 get_identifier (name),
1181 type->as_tree ());
1182 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1184 /* Prepend to BIND_EXPR_VARS: */
1185 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1186 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1188 if (loc)
1189 set_tree_location (inner, loc);
1190 return new lvalue (m_ctxt, inner);
1193 /* Construct a new block within this playback::function. */
1195 playback::block *
1196 playback::function::
1197 new_block (const char *name)
1199 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1201 block *result = new playback::block (this, name);
1202 m_blocks.safe_push (result);
1203 return result;
1206 /* Build a statement list for the function as a whole out of the
1207 lists of statements for the individual blocks, building labels
1208 for each block. */
1210 void
1211 playback::function::
1212 build_stmt_list ()
1214 int i;
1215 block *b;
1217 FOR_EACH_VEC_ELT (m_blocks, i, b)
1219 int j;
1220 tree stmt;
1222 b->m_label_expr = build1 (LABEL_EXPR,
1223 void_type_node,
1224 b->as_label_decl ());
1225 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1227 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1228 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1232 /* Finish compiling the given function, potentially running the
1233 garbage-collector.
1234 The function will have a statement list by now.
1235 Amongst other things, this gimplifies the statement list,
1236 and calls cgraph_node::finalize_function on the function. */
1238 void
1239 playback::function::
1240 postprocess ()
1242 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1243 debug_tree (m_stmt_list);
1245 /* Do we need this to force cgraphunit.c to output the function? */
1246 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1248 DECL_EXTERNAL (m_inner_fndecl) = 0;
1249 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1252 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1253 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1255 DECL_EXTERNAL (m_inner_fndecl) = 0;
1256 TREE_PUBLIC (m_inner_fndecl) = 0;
1259 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1261 /* Seem to need this in gimple-low.c: */
1262 gcc_assert (m_inner_block);
1263 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1265 /* how to add to function? the following appears to be how to
1266 set the body of a m_inner_fndecl: */
1267 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1269 /* Ensure that locals appear in the debuginfo. */
1270 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1272 //debug_tree (m_inner_fndecl);
1274 /* Convert to gimple: */
1275 //printf("about to gimplify_function_tree\n");
1276 gimplify_function_tree (m_inner_fndecl);
1277 //printf("finished gimplify_function_tree\n");
1279 current_function_decl = m_inner_fndecl;
1280 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1281 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1282 //debug_tree (m_inner_fndecl);
1284 //printf("about to add to cgraph\n");
1285 /* Add to cgraph: */
1286 cgraph_node::finalize_function (m_inner_fndecl, false);
1287 /* This can trigger a collection, so we need to have all of
1288 the funcs as roots. */
1290 current_function_decl = NULL;
1294 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1295 GC-ed. */
1297 void
1298 playback::block::finalizer ()
1300 m_stmts.release ();
1303 /* Add an eval of the rvalue to the function's statement list. */
1305 void
1306 playback::block::
1307 add_eval (location *loc,
1308 rvalue *rvalue)
1310 gcc_assert (rvalue);
1312 if (loc)
1313 set_tree_location (rvalue->as_tree (), loc);
1315 add_stmt (rvalue->as_tree ());
1318 /* Add an assignment to the function's statement list. */
1320 void
1321 playback::block::
1322 add_assignment (location *loc,
1323 lvalue *lvalue,
1324 rvalue *rvalue)
1326 gcc_assert (lvalue);
1327 gcc_assert (rvalue);
1329 tree t_lvalue = lvalue->as_tree ();
1330 tree t_rvalue = rvalue->as_tree ();
1331 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1333 t_rvalue = build1 (CONVERT_EXPR,
1334 TREE_TYPE (t_lvalue),
1335 t_rvalue);
1336 if (loc)
1337 set_tree_location (t_rvalue, loc);
1340 tree stmt =
1341 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1342 t_lvalue, t_rvalue);
1343 if (loc)
1344 set_tree_location (stmt, loc);
1345 add_stmt (stmt);
1348 /* Add a comment to the function's statement list.
1349 For now this is done by adding a dummy label. */
1351 void
1352 playback::block::
1353 add_comment (location *loc,
1354 const char *text)
1356 /* Wrap the text in C-style comment delimiters. */
1357 size_t sz =
1358 (3 /* opening delim */
1359 + strlen (text)
1360 + 3 /* closing delim */
1361 + 1 /* terminator */);
1362 char *wrapped = (char *)ggc_internal_alloc (sz);
1363 snprintf (wrapped, sz, "/* %s */", text);
1365 /* For now we simply implement this by adding a dummy label with a name
1366 containing the given text. */
1367 tree identifier = get_identifier (wrapped);
1368 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1369 identifier, void_type_node);
1370 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1372 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1373 if (loc)
1374 set_tree_location (label_expr, loc);
1375 add_stmt (label_expr);
1378 /* Add a conditional jump statement to the function's statement list. */
1380 void
1381 playback::block::
1382 add_conditional (location *loc,
1383 rvalue *boolval,
1384 block *on_true,
1385 block *on_false)
1387 gcc_assert (boolval);
1388 gcc_assert (on_true);
1389 gcc_assert (on_false);
1391 /* COND_EXPR wants statement lists for the true/false operands, but we
1392 want labels.
1393 Shim it by creating jumps to the labels */
1394 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1395 on_true->as_label_decl ());
1396 if (loc)
1397 set_tree_location (true_jump, loc);
1399 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1400 on_false->as_label_decl ());
1401 if (loc)
1402 set_tree_location (false_jump, loc);
1404 tree stmt =
1405 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1406 true_jump, false_jump);
1407 if (loc)
1408 set_tree_location (stmt, loc);
1409 add_stmt (stmt);
1412 /* Add an unconditional jump statement to the function's statement list. */
1414 void
1415 playback::block::
1416 add_jump (location *loc,
1417 block *target)
1419 gcc_assert (target);
1421 // see c_finish_loop
1422 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1423 //add_stmt (top);
1425 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1426 TREE_USED (target->as_label_decl ()) = 1;
1427 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1428 if (loc)
1429 set_tree_location (stmt, loc);
1430 add_stmt (stmt);
1433 from c-typeck.c:
1434 tree
1435 c_finish_goto_label (location_t loc, tree label)
1437 tree decl = lookup_label_for_goto (loc, label);
1438 if (!decl)
1439 return NULL_TREE;
1440 TREE_USED (decl) = 1;
1442 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1443 SET_EXPR_LOCATION (t, loc);
1444 return add_stmt (t);
1451 /* Add a return statement to the function's statement list. */
1453 void
1454 playback::block::
1455 add_return (location *loc,
1456 rvalue *rvalue)
1458 tree modify_retval = NULL;
1459 tree return_type = m_func->get_return_type_as_tree ();
1460 if (rvalue)
1462 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1463 tree t_rvalue = rvalue->as_tree ();
1464 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1465 t_rvalue = build1 (CONVERT_EXPR,
1466 TREE_TYPE (t_lvalue),
1467 t_rvalue);
1468 modify_retval = build2 (MODIFY_EXPR, return_type,
1469 t_lvalue, t_rvalue);
1470 if (loc)
1471 set_tree_location (modify_retval, loc);
1473 tree return_stmt = build1 (RETURN_EXPR, return_type,
1474 modify_retval);
1475 if (loc)
1476 set_tree_location (return_stmt, loc);
1478 add_stmt (return_stmt);
1481 /* Constructor for gcc::jit::playback::block. */
1483 playback::block::
1484 block (function *func,
1485 const char *name)
1486 : m_func (func),
1487 m_stmts ()
1489 tree identifier;
1491 gcc_assert (func);
1492 // name can be NULL
1493 if (name)
1494 identifier = get_identifier (name);
1495 else
1496 identifier = NULL;
1497 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1498 identifier, void_type_node);
1499 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1500 m_label_expr = NULL;
1503 /* A subclass of auto_vec <char *> that frees all of its elements on
1504 deletion. */
1506 class auto_argvec : public auto_vec <char *>
1508 public:
1509 ~auto_argvec ();
1512 /* auto_argvec's dtor, freeing all contained strings, automatically
1513 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1515 auto_argvec::~auto_argvec ()
1517 int i;
1518 char *str;
1519 FOR_EACH_VEC_ELT (*this, i, str)
1520 free (str);
1523 /* Compile a playback::context:
1525 - Use the context's options to cconstruct command-line options, and
1526 call into the rest of GCC (toplev::main).
1527 - Assuming it succeeds, we have a .s file; we want a .so file.
1528 Invoke another gcc to convert the .s file to a .so file.
1529 - dlopen the .so file
1530 - Wrap the result up as a playback::result and return it. */
1532 result *
1533 playback::context::
1534 compile ()
1536 const char *ctxt_progname;
1537 result *result_obj = NULL;
1539 int keep_intermediates =
1540 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
1542 m_tempdir = new tempdir (keep_intermediates);
1543 if (!m_tempdir->create ())
1544 return NULL;
1546 /* Call into the rest of gcc.
1547 For now, we have to assemble command-line options to pass into
1548 toplev::main, so that they can be parsed. */
1550 /* Pass in user-provided program name as argv0, if any, so that it
1551 makes it into GCC's "progname" global, used in various diagnostics. */
1552 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1554 if (!ctxt_progname)
1555 ctxt_progname = "libgccjit.so";
1557 auto_vec <recording::requested_dump> requested_dumps;
1558 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1560 auto_argvec fake_args;
1561 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
1562 if (errors_occurred ())
1563 return NULL;
1565 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1566 acquire_mutex ();
1568 /* This runs the compiler. */
1569 toplev toplev (false);
1570 toplev.main (fake_args.length (),
1571 const_cast <char **> (fake_args.address ()));
1573 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1574 need to do it between toplev::main (which creates the dump manager)
1575 and toplev::finalize (which deletes it). */
1576 extract_any_requested_dumps (&requested_dumps);
1578 /* Clean up the compiler. */
1579 toplev.finalize ();
1581 /* Ideally we would release the jit mutex here, but we can't yet since
1582 followup activities use timevars, which are global state. */
1584 if (errors_occurred ())
1586 release_mutex ();
1587 return NULL;
1590 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1591 dump_generated_code ();
1593 convert_to_dso (ctxt_progname);
1594 if (errors_occurred ())
1596 release_mutex ();
1597 return NULL;
1600 result_obj = dlopen_built_dso ();
1602 release_mutex ();
1604 return result_obj;
1607 /* Helper functions for gcc::jit::playback::context::compile. */
1609 /* This mutex guards gcc::jit::recording::context::compile, so that only
1610 one thread can be accessing the bulk of GCC's state at once. */
1612 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
1614 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
1616 void
1617 playback::context::acquire_mutex ()
1619 /* Acquire the big GCC mutex. */
1620 pthread_mutex_lock (&jit_mutex);
1621 gcc_assert (NULL == active_playback_ctxt);
1622 active_playback_ctxt = this;
1625 /* Release jit_mutex and clear the active playback ctxt. */
1627 void
1628 playback::context::release_mutex ()
1630 /* Release the big GCC mutex. */
1631 gcc_assert (active_playback_ctxt == this);
1632 active_playback_ctxt = NULL;
1633 pthread_mutex_unlock (&jit_mutex);
1636 /* Build a fake argv for toplev::main from the options set
1637 by the user on the context . */
1639 void
1640 playback::context::
1641 make_fake_args (vec <char *> *argvec,
1642 const char *ctxt_progname,
1643 vec <recording::requested_dump> *requested_dumps)
1645 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
1646 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
1648 ADD_ARG (ctxt_progname);
1649 ADD_ARG (get_path_c_file ());
1650 ADD_ARG ("-fPIC");
1652 /* Handle int options: */
1653 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
1655 default:
1656 add_error (NULL,
1657 "unrecognized optimization level: %i",
1658 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
1659 return;
1661 case 0:
1662 ADD_ARG ("-O0");
1663 break;
1665 case 1:
1666 ADD_ARG ("-O1");
1667 break;
1669 case 2:
1670 ADD_ARG ("-O2");
1671 break;
1673 case 3:
1674 ADD_ARG ("-O3");
1675 break;
1677 /* What about -Os? */
1679 /* Handle bool options: */
1680 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
1681 ADD_ARG ("-g");
1683 /* Suppress timing (and other) info. */
1684 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
1686 ADD_ARG ("-quiet");
1687 quiet_flag = 1;
1690 /* Aggressively garbage-collect, to shake out bugs: */
1691 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
1693 ADD_ARG ("--param");
1694 ADD_ARG ("ggc-min-expand=0");
1695 ADD_ARG ("--param");
1696 ADD_ARG ("ggc-min-heapsize=0");
1699 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
1701 ADD_ARG ("-fdump-tree-all");
1702 ADD_ARG ("-fdump-rtl-all");
1703 ADD_ARG ("-fdump-ipa-all");
1706 /* Add "-fdump-" options for any calls to
1707 gcc_jit_context_enable_dump. */
1709 int i;
1710 recording::requested_dump *d;
1711 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
1713 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
1714 ADD_ARG_TAKE_OWNERSHIP (arg);
1718 #undef ADD_ARG
1719 #undef ADD_ARG_TAKE_OWNERSHIP
1722 /* The second half of the implementation of gcc_jit_context_enable_dump.
1723 Iterate through the requested dumps, reading the underlying files
1724 into heap-allocated buffers, writing pointers to the buffers into
1725 the char ** pointers provided by client code.
1726 Client code is responsible for calling free on the results. */
1728 void
1729 playback::context::
1730 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
1732 int i;
1733 recording::requested_dump *d;
1734 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
1736 dump_file_info *dfi;
1737 char *filename;
1738 char *content;
1740 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
1741 if (!dfi)
1743 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
1744 continue;
1747 filename = g->get_dumps ()->get_dump_file_name (dfi);
1748 content = read_dump_file (filename);
1749 *(d->m_out_ptr) = content;
1750 free (filename);
1754 /* Helper function for playback::context::extract_any_requested_dumps
1755 (itself for use in implementation of gcc_jit_context_enable_dump).
1757 Attempt to read the complete file at the given path, returning the
1758 bytes found there as a buffer.
1759 The caller is responsible for calling free on the result.
1760 Errors will be reported on the context, and lead to NULL being
1761 returned; an out-of-memory error will terminate the process. */
1763 char *
1764 playback::context::read_dump_file (const char *path)
1766 char *result = NULL;
1767 size_t total_sz = 0;
1768 char buf[4096];
1769 size_t sz;
1770 FILE *f_in;
1772 f_in = fopen (path, "r");
1773 if (!f_in)
1775 add_error (NULL, "unable to open %s for reading", path);
1776 return NULL;
1779 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
1781 size_t old_total_sz = total_sz;
1782 total_sz += sz;
1783 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
1784 memcpy (result + old_total_sz, buf, sz);
1787 if (!feof (f_in))
1789 add_error (NULL, "error reading from %s", path);
1790 free (result);
1791 return NULL;
1794 fclose (f_in);
1796 if (result)
1798 result[total_sz] = '\0';
1799 return result;
1801 else
1802 return xstrdup ("");
1805 /* Part of playback::context::compile ().
1807 We have a .s file; we want a .so file.
1808 We could reuse parts of gcc/gcc.c to do this.
1809 For now, just use the driver binary from the install, as
1810 named in gcc-driver-name.h
1811 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
1813 void
1814 playback::context::
1815 convert_to_dso (const char *ctxt_progname)
1817 /* Currently this lumps together both assembling and linking into
1818 TV_ASSEMBLE. */
1819 auto_timevar assemble_timevar (TV_ASSEMBLE);
1820 const char *errmsg;
1821 const char *argv[7];
1822 int exit_status = 0;
1823 int err = 0;
1824 const char *gcc_driver_name = GCC_DRIVER_NAME;
1826 argv[0] = gcc_driver_name;
1827 argv[1] = "-shared";
1828 /* The input: assembler. */
1829 argv[2] = m_tempdir->get_path_s_file ();
1830 /* The output: shared library. */
1831 argv[3] = "-o";
1832 argv[4] = m_tempdir->get_path_so_file ();
1834 /* Don't use the linker plugin.
1835 If running with just a "make" and not a "make install", then we'd
1836 run into
1837 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
1838 libto_plugin is a .la at build time, with it becoming installed with
1839 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
1840 time. */
1841 argv[5] = "-fno-use-linker-plugin";
1843 /* pex argv arrays are NULL-terminated. */
1844 argv[6] = NULL;
1846 /* pex_one's error-handling requires pname to be non-NULL. */
1847 gcc_assert (ctxt_progname);
1849 errmsg = pex_one (PEX_SEARCH, /* int flags, */
1850 gcc_driver_name,
1851 const_cast<char * const *> (argv),
1852 ctxt_progname, /* const char *pname */
1853 NULL, /* const char *outname */
1854 NULL, /* const char *errname */
1855 &exit_status, /* int *status */
1856 &err); /* int *err*/
1857 if (errmsg)
1859 add_error (NULL, "error invoking gcc driver: %s", errmsg);
1860 return;
1863 /* pex_one can return a NULL errmsg when the executable wasn't
1864 found (or doesn't exist), so trap these cases also. */
1865 if (exit_status || err)
1867 add_error (NULL,
1868 "error invoking gcc driver: exit_status: %i err: %i",
1869 exit_status, err);
1870 add_error (NULL,
1871 "whilst attempting to run a driver named: %s",
1872 gcc_driver_name);
1873 add_error (NULL,
1874 "PATH was: %s",
1875 getenv ("PATH"));
1876 return;
1880 /* Dynamically-link the built DSO file into this process, using dlopen.
1881 Wrap it up within a jit::result *, and return that.
1882 Return NULL if any errors occur, reporting them on this context. */
1884 result *
1885 playback::context::
1886 dlopen_built_dso ()
1888 auto_timevar load_timevar (TV_LOAD);
1889 void *handle = NULL;
1890 const char *error = NULL;
1891 result *result_obj = NULL;
1893 /* Clear any existing error. */
1894 dlerror ();
1896 handle = dlopen (m_tempdir->get_path_so_file (),
1897 RTLD_NOW | RTLD_LOCAL);
1898 if ((error = dlerror()) != NULL) {
1899 add_error (NULL, "%s", error);
1901 if (handle)
1902 result_obj = new result (handle);
1903 else
1904 result_obj = NULL;
1906 return result_obj;
1909 /* Top-level hook for playing back a recording context.
1911 This plays back m_recording_ctxt, and, if no errors
1912 occurred builds statement lists for and then postprocesses
1913 every function in the result. */
1915 void
1916 playback::context::
1917 replay ()
1919 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
1920 tree array_domain_type = build_index_type (size_int (200));
1921 m_char_array_type_node
1922 = build_array_type (char_type_node, array_domain_type);
1924 m_const_char_ptr
1925 = build_pointer_type (build_qualified_type (char_type_node,
1926 TYPE_QUAL_CONST));
1928 /* Replay the recorded events: */
1929 timevar_push (TV_JIT_REPLAY);
1931 m_recording_ctxt->replay_into (this);
1933 /* Clean away the temporary references from recording objects
1934 to playback objects. We have to do this now since the
1935 latter are GC-allocated, but the former don't mark these
1936 refs. Hence we must stop using them before the GC can run. */
1937 m_recording_ctxt->disassociate_from_playback ();
1939 /* The builtins_manager, if any, is associated with the recording::context
1940 and might be reused for future compiles on other playback::contexts,
1941 but its m_attributes array is not GTY-labeled and hence will become
1942 nonsense if the GC runs. Purge this state. */
1943 builtins_manager *bm = get_builtins_manager ();
1944 if (bm)
1945 bm->finish_playback ();
1947 timevar_pop (TV_JIT_REPLAY);
1949 if (!errors_occurred ())
1951 int i;
1952 function *func;
1954 /* No GC can happen yet; process the cached source locations. */
1955 handle_locations ();
1957 /* We've now created tree nodes for the stmts in the various blocks
1958 in each function, but we haven't built each function's single stmt
1959 list yet. Do so now. */
1960 FOR_EACH_VEC_ELT (m_functions, i, func)
1961 func->build_stmt_list ();
1963 /* No GC can have happened yet. */
1965 /* Postprocess the functions. This could trigger GC. */
1966 FOR_EACH_VEC_ELT (m_functions, i, func)
1968 gcc_assert (func);
1969 func->postprocess ();
1974 /* Dump the generated .s file to stderr. */
1976 void
1977 playback::context::
1978 dump_generated_code ()
1980 char buf[4096];
1981 size_t sz;
1982 FILE *f_in = fopen (get_path_s_file (), "r");
1983 if (!f_in)
1984 return;
1986 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
1987 fwrite (buf, 1, sz, stderr);
1989 fclose (f_in);
1992 /* Get the supposed path of the notional "fake.c" file within the
1993 tempdir. This file doesn't exist, but the rest of the compiler
1994 needs a name. */
1996 const char *
1997 playback::context::
1998 get_path_c_file () const
2000 return m_tempdir->get_path_c_file ();
2003 /* Get the path of the assembler output file "fake.s" file within the
2004 tempdir. */
2006 const char *
2007 playback::context::
2008 get_path_s_file () const
2010 return m_tempdir->get_path_s_file ();
2013 /* Get the path of the DSO object file "fake.so" file within the
2014 tempdir. */
2016 const char *
2017 playback::context::
2018 get_path_so_file () const
2020 return m_tempdir->get_path_so_file ();
2023 /* qsort comparator for comparing pairs of playback::source_line *,
2024 ordering them by line number. */
2026 static int
2027 line_comparator (const void *lhs, const void *rhs)
2029 const playback::source_line *line_lhs = \
2030 *static_cast<const playback::source_line * const*> (lhs);
2031 const playback::source_line *line_rhs = \
2032 *static_cast<const playback::source_line * const*> (rhs);
2033 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2036 /* qsort comparator for comparing pairs of playback::location *,
2037 ordering them by column number. */
2039 static int
2040 location_comparator (const void *lhs, const void *rhs)
2042 const playback::location *loc_lhs = \
2043 *static_cast<const playback::location * const *> (lhs);
2044 const playback::location *loc_rhs = \
2045 *static_cast<const playback::location * const *> (rhs);
2046 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2049 /* Our API allows locations to be created in arbitrary orders, but the
2050 linemap API requires locations to be created in ascending order
2051 as if we were tokenizing files.
2053 This hook sorts all of the the locations that have been created, and
2054 calls into the linemap API, creating linemap entries in sorted order
2055 for our locations. */
2057 void
2058 playback::context::
2059 handle_locations ()
2061 /* Create the source code locations, following the ordering rules
2062 imposed by the linemap API.
2064 line_table is a global. */
2065 int i;
2066 source_file *file;
2068 FOR_EACH_VEC_ELT (m_source_files, i, file)
2070 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2072 /* Sort lines by ascending line numbers. */
2073 file->m_source_lines.qsort (&line_comparator);
2075 int j;
2076 source_line *line;
2077 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2079 int k;
2080 location *loc;
2082 /* Sort locations in line by ascending column numbers. */
2083 line->m_locations.qsort (&location_comparator);
2085 /* Determine maximum column within this line. */
2086 gcc_assert (line->m_locations.length () > 0);
2087 location *final_column =
2088 line->m_locations[line->m_locations.length () - 1];
2089 int max_col = final_column->get_column_num ();
2091 linemap_line_start (line_table, line->get_line_num (), max_col);
2092 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2094 loc->m_srcloc = \
2095 linemap_position_for_column (line_table, loc->get_column_num ());
2099 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2102 /* line_table should now be populated; every playback::location should
2103 now have an m_srcloc. */
2105 /* Now assign them to tree nodes as appropriate. */
2106 std::pair<tree, location *> *cached_location;
2108 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2110 tree t = cached_location->first;
2111 source_location srcloc = cached_location->second->m_srcloc;
2113 /* This covers expressions: */
2114 if (CAN_HAVE_LOCATION_P (t))
2115 SET_EXPR_LOCATION (t, srcloc);
2116 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2117 DECL_SOURCE_LOCATION (t) = srcloc;
2118 else
2120 /* Don't know how to set location on this node. */
2125 /* We handle errors on a playback::context by adding them to the
2126 corresponding recording::context. */
2128 void
2129 playback::context::
2130 add_error (location *loc, const char *fmt, ...)
2132 va_list ap;
2133 va_start (ap, fmt);
2134 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2135 fmt, ap);
2136 va_end (ap);
2139 /* We handle errors on a playback::context by adding them to the
2140 corresponding recording::context. */
2142 void
2143 playback::context::
2144 add_error_va (location *loc, const char *fmt, va_list ap)
2146 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2147 fmt, ap);
2150 /* Dealing with the linemap API. */
2152 /* Construct a playback::location for a recording::location, if it
2153 doesn't exist already. */
2155 playback::location *
2156 playback::context::
2157 new_location (recording::location *rloc,
2158 const char *filename,
2159 int line,
2160 int column)
2162 /* Get the source_file for filename, creating if necessary. */
2163 source_file *src_file = get_source_file (filename);
2164 /* Likewise for the line within the file. */
2165 source_line *src_line = src_file->get_source_line (line);
2166 /* Likewise for the column within the line. */
2167 location *loc = src_line->get_location (rloc, column);
2168 return loc;
2171 /* Deferred setting of the location for a given tree, by adding the
2172 (tree, playback::location) pair to a list of deferred associations.
2173 We will actually set the location on the tree later on once
2174 the source_location for the playback::location exists. */
2176 void
2177 playback::context::
2178 set_tree_location (tree t, location *loc)
2180 gcc_assert (loc);
2181 m_cached_locations.safe_push (std::make_pair (t, loc));
2185 /* Construct a playback::source_file for the given source
2186 filename, if it doesn't exist already. */
2188 playback::source_file *
2189 playback::context::
2190 get_source_file (const char *filename)
2192 /* Locate the file.
2193 For simplicitly, this is currently a linear search.
2194 Replace with a hash if this shows up in the profile. */
2195 int i;
2196 source_file *file;
2197 tree ident_filename = get_identifier (filename);
2199 FOR_EACH_VEC_ELT (m_source_files, i, file)
2200 if (file->filename_as_tree () == ident_filename)
2201 return file;
2203 /* Not found. */
2204 file = new source_file (ident_filename);
2205 m_source_files.safe_push (file);
2206 return file;
2209 /* Constructor for gcc::jit::playback::source_file. */
2211 playback::source_file::source_file (tree filename) :
2212 m_source_lines (),
2213 m_filename (filename)
2217 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2218 GC-ed. */
2220 void
2221 playback::source_file::finalizer ()
2223 m_source_lines.release ();
2226 /* Construct a playback::source_line for the given line
2227 within this source file, if one doesn't exist already. */
2229 playback::source_line *
2230 playback::source_file::
2231 get_source_line (int line_num)
2233 /* Locate the line.
2234 For simplicitly, this is currently a linear search.
2235 Replace with a hash if this shows up in the profile. */
2236 int i;
2237 source_line *line;
2239 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2240 if (line->get_line_num () == line_num)
2241 return line;
2243 /* Not found. */
2244 line = new source_line (this, line_num);
2245 m_source_lines.safe_push (line);
2246 return line;
2249 /* Constructor for gcc::jit::playback::source_line. */
2251 playback::source_line::source_line (source_file *file, int line_num) :
2252 m_locations (),
2253 m_source_file (file),
2254 m_line_num (line_num)
2258 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2259 GC-ed. */
2261 void
2262 playback::source_line::finalizer ()
2264 m_locations.release ();
2267 /* Construct a playback::location for the given column
2268 within this line of a specific source file, if one doesn't exist
2269 already. */
2271 playback::location *
2272 playback::source_line::
2273 get_location (recording::location *rloc, int column_num)
2275 int i;
2276 location *loc;
2278 /* Another linear search that probably should be a hash table. */
2279 FOR_EACH_VEC_ELT (m_locations, i, loc)
2280 if (loc->get_column_num () == column_num)
2281 return loc;
2283 /* Not found. */
2284 loc = new location (rloc, this, column_num);
2285 m_locations.safe_push (loc);
2286 return loc;
2289 /* Constructor for gcc::jit::playback::location. */
2291 playback::location::location (recording::location *loc,
2292 source_line *line,
2293 int column_num) :
2294 m_srcloc (UNKNOWN_LOCATION),
2295 m_recording_loc (loc),
2296 m_line (line),
2297 m_column_num(column_num)
2301 /* The active gcc::jit::playback::context instance. This is a singleton,
2302 guarded by jit_mutex. */
2304 playback::context *active_playback_ctxt;
2306 } // namespace gcc::jit
2308 } // namespace gcc