PR jit/64020: Fixes to handling of builtins
[official-gcc.git] / gcc / jit / jit-playback.c
blobecdae80553c754c179998ef0792259cdb3c2d3db
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"
51 #include "jit-common.h"
52 #include "jit-playback.h"
53 #include "jit-result.h"
54 #include "jit-builtins.h"
57 /* gcc::jit::playback::context::build_cast uses the convert.h API,
58 which in turn requires the frontend to provide a "convert"
59 function, apparently as a fallback.
61 Hence we provide this dummy one, with the requirement that any casts
62 are handled before reaching this. */
63 extern tree convert (tree type, tree expr);
65 tree
66 convert (tree dst_type, tree expr)
68 gcc_assert (gcc::jit::active_playback_ctxt);
69 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
70 fprintf (stderr, "input expression:\n");
71 debug_tree (expr);
72 fprintf (stderr, "requested type:\n");
73 debug_tree (dst_type);
74 return error_mark_node;
77 namespace gcc {
78 namespace jit {
80 /**********************************************************************
81 Playback.
82 **********************************************************************/
84 /* The constructor for gcc::jit::playback::context. */
86 playback::context::context (recording::context *ctxt)
87 : m_recording_ctxt (ctxt),
88 m_char_array_type_node (NULL),
89 m_const_char_ptr (NULL)
91 m_functions.create (0);
92 m_source_files.create (0);
93 m_cached_locations.create (0);
96 /* The destructor for gcc::jit::playback::context. */
98 playback::context::~context ()
100 if (get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES))
101 fprintf (stderr, "intermediate files written to %s\n", m_path_tempdir);
102 else
104 /* Clean up .s/.so and tempdir. */
105 if (m_path_s_file)
106 unlink (m_path_s_file);
107 if (m_path_so_file)
108 unlink (m_path_so_file);
109 if (m_path_tempdir)
110 rmdir (m_path_tempdir);
113 free (m_path_template);
114 /* m_path_tempdir aliases m_path_template, or is NULL, so don't
115 attempt to free it . */
116 free (m_path_c_file);
117 free (m_path_s_file);
118 free (m_path_so_file);
119 m_functions.release ();
122 /* A playback::context can reference GC-managed pointers. Mark them
123 ("by hand", rather than by gengtype).
125 This is called on the active playback context (if any) by the
126 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
128 void
129 playback::context::
130 gt_ggc_mx ()
132 int i;
133 function *func;
134 FOR_EACH_VEC_ELT (m_functions, i, func)
136 if (ggc_test_and_set_mark (func))
137 func->gt_ggc_mx ();
141 /* Given an enum gcc_jit_types value, get a "tree" type. */
143 static tree
144 get_tree_node_for_type (enum gcc_jit_types type_)
146 switch (type_)
148 case GCC_JIT_TYPE_VOID:
149 return void_type_node;
151 case GCC_JIT_TYPE_VOID_PTR:
152 return ptr_type_node;
154 case GCC_JIT_TYPE_BOOL:
155 return boolean_type_node;
157 case GCC_JIT_TYPE_CHAR:
158 return char_type_node;
159 case GCC_JIT_TYPE_SIGNED_CHAR:
160 return signed_char_type_node;
161 case GCC_JIT_TYPE_UNSIGNED_CHAR:
162 return unsigned_char_type_node;
164 case GCC_JIT_TYPE_SHORT:
165 return short_integer_type_node;
166 case GCC_JIT_TYPE_UNSIGNED_SHORT:
167 return short_unsigned_type_node;
169 case GCC_JIT_TYPE_CONST_CHAR_PTR:
171 tree const_char = build_qualified_type (char_type_node,
172 TYPE_QUAL_CONST);
173 return build_pointer_type (const_char);
176 case GCC_JIT_TYPE_INT:
177 return integer_type_node;
178 case GCC_JIT_TYPE_UNSIGNED_INT:
179 return unsigned_type_node;
181 case GCC_JIT_TYPE_LONG:
182 return long_integer_type_node;
183 case GCC_JIT_TYPE_UNSIGNED_LONG:
184 return long_unsigned_type_node;
186 case GCC_JIT_TYPE_LONG_LONG:
187 return long_long_integer_type_node;
188 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
189 return long_long_unsigned_type_node;
191 case GCC_JIT_TYPE_FLOAT:
192 return float_type_node;
193 case GCC_JIT_TYPE_DOUBLE:
194 return double_type_node;
195 case GCC_JIT_TYPE_LONG_DOUBLE:
196 return long_double_type_node;
198 case GCC_JIT_TYPE_SIZE_T:
199 return size_type_node;
201 case GCC_JIT_TYPE_FILE_PTR:
202 return fileptr_type_node;
204 case GCC_JIT_TYPE_COMPLEX_FLOAT:
205 return complex_float_type_node;
206 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
207 return complex_double_type_node;
208 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
209 return complex_long_double_type_node;
212 return NULL;
215 /* Construct a playback::type instance (wrapping a tree) for the given
216 enum value. */
218 playback::type *
219 playback::context::
220 get_type (enum gcc_jit_types type_)
222 tree type_node = get_tree_node_for_type (type_);
223 if (NULL == type_node)
225 add_error (NULL,
226 "unrecognized (enum gcc_jit_types) value: %i", type_);
227 return NULL;
230 return new type (type_node);
233 /* Construct a playback::type instance (wrapping a tree) for the given
234 array type. */
236 playback::type *
237 playback::context::
238 new_array_type (playback::location *loc,
239 playback::type *element_type,
240 int num_elements)
242 gcc_assert (element_type);
244 tree t = build_array_type_nelts (element_type->as_tree (),
245 num_elements);
246 layout_type (t);
248 if (loc)
249 set_tree_location (t, loc);
251 return new type (t);
254 /* Construct a playback::field instance (wrapping a tree). */
256 playback::field *
257 playback::context::
258 new_field (location *loc,
259 type *type,
260 const char *name)
262 gcc_assert (type);
263 gcc_assert (name);
265 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
266 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
267 get_identifier (name), type->as_tree ());
269 if (loc)
270 set_tree_location (decl, loc);
272 return new field (decl);
275 /* Construct a playback::compound_type instance (wrapping a tree). */
277 playback::compound_type *
278 playback::context::
279 new_compound_type (location *loc,
280 const char *name,
281 bool is_struct) /* else is union */
283 gcc_assert (name);
285 /* Compare with c/c-decl.c: start_struct. */
287 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
288 TYPE_NAME (t) = get_identifier (name);
289 TYPE_SIZE (t) = 0;
291 if (loc)
292 set_tree_location (t, loc);
294 return new compound_type (t);
297 void
298 playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
300 /* Compare with c/c-decl.c: finish_struct. */
301 tree t = as_tree ();
303 tree fieldlist = NULL;
304 for (unsigned i = 0; i < fields->length (); i++)
306 field *f = (*fields)[i];
307 DECL_CONTEXT (f->as_tree ()) = t;
308 fieldlist = chainon (f->as_tree (), fieldlist);
310 fieldlist = nreverse (fieldlist);
311 TYPE_FIELDS (t) = fieldlist;
313 layout_type (t);
316 /* Construct a playback::type instance (wrapping a tree) for a function
317 type. */
319 playback::type *
320 playback::context::
321 new_function_type (type *return_type,
322 const auto_vec<type *> *param_types,
323 int is_variadic)
325 int i;
326 type *param_type;
328 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
330 FOR_EACH_VEC_ELT (*param_types, i, param_type)
331 arg_types[i] = param_type->as_tree ();
333 tree fn_type;
334 if (is_variadic)
335 fn_type =
336 build_varargs_function_type_array (return_type->as_tree (),
337 param_types->length (),
338 arg_types);
339 else
340 fn_type = build_function_type_array (return_type->as_tree (),
341 param_types->length (),
342 arg_types);
343 free (arg_types);
345 return new type (fn_type);
348 /* Construct a playback::param instance (wrapping a tree). */
350 playback::param *
351 playback::context::
352 new_param (location *loc,
353 type *type,
354 const char *name)
356 gcc_assert (type);
357 gcc_assert (name);
358 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
359 get_identifier (name), type->as_tree ());
360 if (loc)
361 set_tree_location (inner, loc);
363 return new param (this, inner);
366 /* Construct a playback::function instance. */
368 playback::function *
369 playback::context::
370 new_function (location *loc,
371 enum gcc_jit_function_kind kind,
372 type *return_type,
373 const char *name,
374 const auto_vec<param *> *params,
375 int is_variadic,
376 enum built_in_function builtin_id)
378 int i;
379 param *param;
381 //can return_type be NULL?
382 gcc_assert (name);
384 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
385 FOR_EACH_VEC_ELT (*params, i, param)
386 arg_types[i] = TREE_TYPE (param->as_tree ());
388 tree fn_type;
389 if (is_variadic)
390 fn_type = build_varargs_function_type_array (return_type->as_tree (),
391 params->length (), arg_types);
392 else
393 fn_type = build_function_type_array (return_type->as_tree (),
394 params->length (), arg_types);
395 free (arg_types);
397 /* FIXME: this uses input_location: */
398 tree fndecl = build_fn_decl (name, fn_type);
400 if (loc)
401 set_tree_location (fndecl, loc);
403 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
404 NULL_TREE, return_type->as_tree ());
405 DECL_ARTIFICIAL (resdecl) = 1;
406 DECL_IGNORED_P (resdecl) = 1;
407 DECL_RESULT (fndecl) = resdecl;
409 if (builtin_id)
411 DECL_FUNCTION_CODE (fndecl) = builtin_id;
412 gcc_assert (loc == NULL);
413 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
415 DECL_BUILT_IN_CLASS (fndecl) =
416 builtins_manager::get_class (builtin_id);
417 set_builtin_decl (builtin_id, fndecl,
418 builtins_manager::implicit_p (builtin_id));
420 builtins_manager *bm = get_builtins_manager ();
421 tree attrs = bm->get_attrs_tree (builtin_id);
422 if (attrs)
423 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
424 else
425 decl_attributes (&fndecl, NULL_TREE, 0);
428 if (kind != GCC_JIT_FUNCTION_IMPORTED)
430 tree param_decl_list = NULL;
431 FOR_EACH_VEC_ELT (*params, i, param)
433 param_decl_list = chainon (param->as_tree (), param_decl_list);
436 /* The param list was created in reverse order; fix it: */
437 param_decl_list = nreverse (param_decl_list);
439 tree t;
440 for (t = param_decl_list; t; t = DECL_CHAIN (t))
442 DECL_CONTEXT (t) = fndecl;
443 DECL_ARG_TYPE (t) = TREE_TYPE (t);
446 /* Set it up on DECL_ARGUMENTS */
447 DECL_ARGUMENTS(fndecl) = param_decl_list;
450 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
452 DECL_DECLARED_INLINE_P (fndecl) = 1;
454 /* Add attribute "always_inline": */
455 DECL_ATTRIBUTES (fndecl) =
456 tree_cons (get_identifier ("always_inline"),
457 NULL,
458 DECL_ATTRIBUTES (fndecl));
461 function *func = new function (this, fndecl, kind);
462 m_functions.safe_push (func);
463 return func;
466 /* Construct a playback::lvalue instance (wrapping a tree). */
468 playback::lvalue *
469 playback::context::
470 new_global (location *loc,
471 type *type,
472 const char *name)
474 gcc_assert (type);
475 gcc_assert (name);
476 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
477 get_identifier (name),
478 type->as_tree ());
479 TREE_PUBLIC (inner) = 1;
480 DECL_COMMON (inner) = 1;
481 DECL_EXTERNAL (inner) = 1;
483 if (loc)
484 set_tree_location (inner, loc);
486 return new lvalue (this, inner);
489 /* Construct a playback::rvalue instance (wrapping a tree). */
491 playback::rvalue *
492 playback::context::
493 new_rvalue_from_int (type *type,
494 int value)
496 // FIXME: type-checking, or coercion?
497 tree inner_type = type->as_tree ();
498 if (INTEGRAL_TYPE_P (inner_type))
500 tree inner = build_int_cst (inner_type, value);
501 return new rvalue (this, inner);
503 else
505 REAL_VALUE_TYPE real_value;
506 real_from_integer (&real_value, VOIDmode, value, SIGNED);
507 tree inner = build_real (inner_type, real_value);
508 return new rvalue (this, inner);
512 /* Construct a playback::rvalue instance (wrapping a tree). */
514 playback::rvalue *
515 playback::context::
516 new_rvalue_from_double (type *type,
517 double value)
519 // FIXME: type-checking, or coercion?
520 tree inner_type = type->as_tree ();
522 /* We have a "double", we want a REAL_VALUE_TYPE.
524 real.c:real_from_target appears to require the representation to be
525 split into 32-bit values, and then sent as an pair of host long
526 ints. */
527 REAL_VALUE_TYPE real_value;
528 union
530 double as_double;
531 uint32_t as_uint32s[2];
532 } u;
533 u.as_double = value;
534 long int as_long_ints[2];
535 as_long_ints[0] = u.as_uint32s[0];
536 as_long_ints[1] = u.as_uint32s[1];
537 real_from_target (&real_value, as_long_ints, DFmode);
538 tree inner = build_real (inner_type, real_value);
539 return new rvalue (this, inner);
542 /* Construct a playback::rvalue instance (wrapping a tree). */
544 playback::rvalue *
545 playback::context::
546 new_rvalue_from_ptr (type *type,
547 void *value)
549 tree inner_type = type->as_tree ();
550 /* FIXME: how to ensure we have a wide enough type? */
551 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
552 return new rvalue (this, inner);
555 /* Construct a playback::rvalue instance (wrapping a tree). */
557 playback::rvalue *
558 playback::context::
559 new_string_literal (const char *value)
561 tree t_str = build_string (strlen (value), value);
562 gcc_assert (m_char_array_type_node);
563 TREE_TYPE (t_str) = m_char_array_type_node;
565 /* Convert to (const char*), loosely based on
566 c/c-typeck.c: array_to_pointer_conversion,
567 by taking address of start of string. */
568 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
570 return new rvalue (this, t_addr);
573 /* Coerce a tree expression into a boolean tree expression. */
575 tree
576 playback::context::
577 as_truth_value (tree expr, location *loc)
579 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
580 tree typed_zero = fold_build1 (CONVERT_EXPR,
581 TREE_TYPE (expr),
582 integer_zero_node);
583 if (loc)
584 set_tree_location (typed_zero, loc);
586 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
587 if (loc)
588 set_tree_location (expr, loc);
590 return expr;
593 /* Construct a playback::rvalue instance (wrapping a tree) for a
594 unary op. */
596 playback::rvalue *
597 playback::context::
598 new_unary_op (location *loc,
599 enum gcc_jit_unary_op op,
600 type *result_type,
601 rvalue *a)
603 // FIXME: type-checking, or coercion?
604 enum tree_code inner_op;
606 gcc_assert (result_type);
607 gcc_assert (a);
609 tree node = a->as_tree ();
610 tree inner_result = NULL;
612 switch (op)
614 default:
615 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
616 return NULL;
618 case GCC_JIT_UNARY_OP_MINUS:
619 inner_op = NEGATE_EXPR;
620 break;
622 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
623 inner_op = BIT_NOT_EXPR;
624 break;
626 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
627 node = as_truth_value (node, loc);
628 inner_result = invert_truthvalue (node);
629 if (loc)
630 set_tree_location (inner_result, loc);
631 return new rvalue (this, inner_result);
634 inner_result = build1 (inner_op,
635 result_type->as_tree (),
636 node);
637 if (loc)
638 set_tree_location (inner_result, loc);
640 return new rvalue (this, inner_result);
643 /* Construct a playback::rvalue instance (wrapping a tree) for a
644 binary op. */
646 playback::rvalue *
647 playback::context::
648 new_binary_op (location *loc,
649 enum gcc_jit_binary_op op,
650 type *result_type,
651 rvalue *a, rvalue *b)
653 // FIXME: type-checking, or coercion?
654 enum tree_code inner_op;
656 gcc_assert (result_type);
657 gcc_assert (a);
658 gcc_assert (b);
660 tree node_a = a->as_tree ();
661 tree node_b = b->as_tree ();
663 switch (op)
665 default:
666 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
667 return NULL;
669 case GCC_JIT_BINARY_OP_PLUS:
670 inner_op = PLUS_EXPR;
671 break;
673 case GCC_JIT_BINARY_OP_MINUS:
674 inner_op = MINUS_EXPR;
675 break;
677 case GCC_JIT_BINARY_OP_MULT:
678 inner_op = MULT_EXPR;
679 break;
681 case GCC_JIT_BINARY_OP_DIVIDE:
682 if (FLOAT_TYPE_P (result_type->as_tree ()))
683 /* Floating-point division: */
684 inner_op = RDIV_EXPR;
685 else
686 /* Truncating to zero: */
687 inner_op = TRUNC_DIV_EXPR;
688 break;
690 case GCC_JIT_BINARY_OP_MODULO:
691 inner_op = TRUNC_MOD_EXPR;
692 break;
694 case GCC_JIT_BINARY_OP_BITWISE_AND:
695 inner_op = BIT_AND_EXPR;
696 break;
698 case GCC_JIT_BINARY_OP_BITWISE_XOR:
699 inner_op = BIT_XOR_EXPR;
700 break;
702 case GCC_JIT_BINARY_OP_BITWISE_OR:
703 inner_op = BIT_IOR_EXPR;
704 break;
706 case GCC_JIT_BINARY_OP_LOGICAL_AND:
707 node_a = as_truth_value (node_a, loc);
708 node_b = as_truth_value (node_b, loc);
709 inner_op = TRUTH_ANDIF_EXPR;
710 break;
712 case GCC_JIT_BINARY_OP_LOGICAL_OR:
713 node_a = as_truth_value (node_a, loc);
714 node_b = as_truth_value (node_b, loc);
715 inner_op = TRUTH_ORIF_EXPR;
716 break;
718 case GCC_JIT_BINARY_OP_LSHIFT:
719 inner_op = LSHIFT_EXPR;
720 break;
722 case GCC_JIT_BINARY_OP_RSHIFT:
723 inner_op = RSHIFT_EXPR;
724 break;
727 tree inner_expr = build2 (inner_op,
728 result_type->as_tree (),
729 node_a,
730 node_b);
731 if (loc)
732 set_tree_location (inner_expr, loc);
734 return new rvalue (this, inner_expr);
737 /* Construct a playback::rvalue instance (wrapping a tree) for a
738 comparison. */
740 playback::rvalue *
741 playback::context::
742 new_comparison (location *loc,
743 enum gcc_jit_comparison op,
744 rvalue *a, rvalue *b)
746 // FIXME: type-checking, or coercion?
747 enum tree_code inner_op;
749 gcc_assert (a);
750 gcc_assert (b);
752 switch (op)
754 default:
755 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
756 return NULL;
758 case GCC_JIT_COMPARISON_EQ:
759 inner_op = EQ_EXPR;
760 break;
761 case GCC_JIT_COMPARISON_NE:
762 inner_op = NE_EXPR;
763 break;
764 case GCC_JIT_COMPARISON_LT:
765 inner_op = LT_EXPR;
766 break;
767 case GCC_JIT_COMPARISON_LE:
768 inner_op = LE_EXPR;
769 break;
770 case GCC_JIT_COMPARISON_GT:
771 inner_op = GT_EXPR;
772 break;
773 case GCC_JIT_COMPARISON_GE:
774 inner_op = GE_EXPR;
775 break;
778 tree inner_expr = build2 (inner_op,
779 boolean_type_node,
780 a->as_tree (),
781 b->as_tree ());
782 if (loc)
783 set_tree_location (inner_expr, loc);
784 return new rvalue (this, inner_expr);
787 /* Construct a playback::rvalue instance (wrapping a tree) for a
788 function call. */
790 playback::rvalue *
791 playback::context::
792 build_call (location *loc,
793 tree fn_ptr,
794 const auto_vec<rvalue *> *args)
796 vec<tree, va_gc> *tree_args;
797 vec_alloc (tree_args, args->length ());
798 for (unsigned i = 0; i < args->length (); i++)
799 tree_args->quick_push ((*args)[i]->as_tree ());
801 if (loc)
802 set_tree_location (fn_ptr, loc);
804 tree fn = TREE_TYPE (fn_ptr);
805 tree fn_type = TREE_TYPE (fn);
806 tree return_type = TREE_TYPE (fn_type);
808 return new rvalue (this,
809 build_call_vec (return_type,
810 fn_ptr, tree_args));
812 /* see c-typeck.c: build_function_call
813 which calls build_function_call_vec
815 which does lots of checking, then:
816 result = build_call_array_loc (loc, TREE_TYPE (fntype),
817 function, nargs, argarray);
818 which is in tree.c
819 (see also build_call_vec)
823 /* Construct a playback::rvalue instance (wrapping a tree) for a
824 call to a specific function. */
826 playback::rvalue *
827 playback::context::
828 new_call (location *loc,
829 function *func,
830 const auto_vec<rvalue *> *args)
832 tree fndecl;
834 gcc_assert (func);
836 fndecl = func->as_fndecl ();
838 tree fntype = TREE_TYPE (fndecl);
840 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
842 return build_call (loc, fn, args);
845 /* Construct a playback::rvalue instance (wrapping a tree) for a
846 call through a function pointer. */
848 playback::rvalue *
849 playback::context::
850 new_call_through_ptr (location *loc,
851 rvalue *fn_ptr,
852 const auto_vec<rvalue *> *args)
854 gcc_assert (fn_ptr);
855 tree t_fn_ptr = fn_ptr->as_tree ();
857 return build_call (loc, t_fn_ptr, args);
860 /* Construct a tree for a cast. */
862 tree
863 playback::context::build_cast (playback::location *loc,
864 playback::rvalue *expr,
865 playback::type *type_)
867 /* For comparison, see:
868 - c/c-typeck.c:build_c_cast
869 - c/c-convert.c: convert
870 - convert.h
872 Only some kinds of cast are currently supported here. */
873 tree t_expr = expr->as_tree ();
874 tree t_dst_type = type_->as_tree ();
875 tree t_ret = NULL;
876 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
877 if (t_ret)
878 return t_ret;
879 enum tree_code dst_code = TREE_CODE (t_dst_type);
880 switch (dst_code)
882 case INTEGER_TYPE:
883 case ENUMERAL_TYPE:
884 t_ret = convert_to_integer (t_dst_type, t_expr);
885 goto maybe_fold;
887 case BOOLEAN_TYPE:
888 /* Compare with c_objc_common_truthvalue_conversion and
889 c_common_truthvalue_conversion. */
890 /* For now, convert to: (t_expr != 0) */
891 t_ret = build2 (NE_EXPR, t_dst_type,
892 t_expr, integer_zero_node);
893 goto maybe_fold;
895 case REAL_TYPE:
896 t_ret = convert_to_real (t_dst_type, t_expr);
897 goto maybe_fold;
899 case POINTER_TYPE:
900 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
901 goto maybe_fold;
903 default:
904 add_error (loc, "couldn't handle cast during playback");
905 fprintf (stderr, "input expression:\n");
906 debug_tree (t_expr);
907 fprintf (stderr, "requested type:\n");
908 debug_tree (t_dst_type);
909 return error_mark_node;
911 maybe_fold:
912 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
913 t_ret = fold (t_ret);
914 return t_ret;
918 /* Construct a playback::rvalue instance (wrapping a tree) for a
919 cast. */
921 playback::rvalue *
922 playback::context::
923 new_cast (playback::location *loc,
924 playback::rvalue *expr,
925 playback::type *type_)
928 tree t_cast = build_cast (loc, expr, type_);
929 if (loc)
930 set_tree_location (t_cast, loc);
931 return new rvalue (this, t_cast);
934 /* Construct a playback::lvalue instance (wrapping a tree) for an
935 array access. */
937 playback::lvalue *
938 playback::context::
939 new_array_access (location *loc,
940 rvalue *ptr,
941 rvalue *index)
943 gcc_assert (ptr);
944 gcc_assert (index);
946 /* For comparison, see:
947 c/c-typeck.c: build_array_ref
948 c-family/c-common.c: pointer_int_sum
950 tree t_ptr = ptr->as_tree ();
951 tree t_index = index->as_tree ();
952 tree t_type_ptr = TREE_TYPE (t_ptr);
953 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
955 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
957 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
958 NULL_TREE, NULL_TREE);
959 if (loc)
960 set_tree_location (t_result, loc);
961 return new lvalue (this, t_result);
963 else
965 /* Convert index to an offset in bytes. */
966 tree t_sizeof = size_in_bytes (t_type_star_ptr);
967 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
968 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
970 /* Locate (ptr + offset). */
971 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
973 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
974 if (loc)
976 set_tree_location (t_sizeof, loc);
977 set_tree_location (t_offset, loc);
978 set_tree_location (t_address, loc);
979 set_tree_location (t_indirection, loc);
982 return new lvalue (this, t_indirection);
986 /* Construct a tree for a field access. */
988 tree
989 playback::context::
990 new_field_access (location *loc,
991 tree datum,
992 field *field)
994 gcc_assert (datum);
995 gcc_assert (field);
997 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
998 build_component_ref. */
999 tree type = TREE_TYPE (datum);
1000 gcc_assert (type);
1001 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1003 tree t_field = field->as_tree ();
1004 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1005 t_field, NULL_TREE);
1006 if (loc)
1007 set_tree_location (ref, loc);
1008 return ref;
1011 /* Construct a tree for a dereference. */
1013 tree
1014 playback::context::
1015 new_dereference (tree ptr,
1016 location *loc)
1018 gcc_assert (ptr);
1020 tree type = TREE_TYPE (TREE_TYPE(ptr));
1021 tree datum = build1 (INDIRECT_REF, type, ptr);
1022 if (loc)
1023 set_tree_location (datum, loc);
1024 return datum;
1027 /* Construct a playback::lvalue instance (wrapping a tree) for a
1028 field access. */
1030 playback::lvalue *
1031 playback::lvalue::
1032 access_field (location *loc,
1033 field *field)
1035 tree datum = as_tree ();
1036 tree ref = get_context ()->new_field_access (loc, datum, field);
1037 if (!ref)
1038 return NULL;
1039 return new lvalue (get_context (), ref);
1042 /* Construct a playback::rvalue instance (wrapping a tree) for a
1043 field access. */
1045 playback::rvalue *
1046 playback::rvalue::
1047 access_field (location *loc,
1048 field *field)
1050 tree datum = as_tree ();
1051 tree ref = get_context ()->new_field_access (loc, datum, field);
1052 if (!ref)
1053 return NULL;
1054 return new rvalue (get_context (), ref);
1057 /* Construct a playback::lvalue instance (wrapping a tree) for a
1058 dereferenced field access. */
1060 playback::lvalue *
1061 playback::rvalue::
1062 dereference_field (location *loc,
1063 field *field)
1065 tree ptr = as_tree ();
1066 tree datum = get_context ()->new_dereference (ptr, loc);
1067 if (!datum)
1068 return NULL;
1069 tree ref = get_context ()->new_field_access (loc, datum, field);
1070 if (!ref)
1071 return NULL;
1072 return new lvalue (get_context (), ref);
1075 /* Construct a playback::lvalue instance (wrapping a tree) for a
1076 dereference. */
1078 playback::lvalue *
1079 playback::rvalue::
1080 dereference (location *loc)
1082 tree ptr = as_tree ();
1083 tree datum = get_context ()->new_dereference (ptr, loc);
1084 return new lvalue (get_context (), datum);
1087 /* Construct a playback::rvalue instance (wrapping a tree) for an
1088 address-lookup. */
1090 playback::rvalue *
1091 playback::lvalue::
1092 get_address (location *loc)
1094 tree t_lvalue = as_tree ();
1095 tree t_thistype = TREE_TYPE (t_lvalue);
1096 tree t_ptrtype = build_pointer_type (t_thistype);
1097 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1098 if (loc)
1099 get_context ()->set_tree_location (ptr, loc);
1100 return new rvalue (get_context (), ptr);
1103 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1104 Provide this finalization hook for calling then they are collected,
1105 which calls the finalizer vfunc. This allows them to call "release"
1106 on any vec<> within them. */
1108 static void
1109 wrapper_finalizer (void *ptr)
1111 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1112 wrapper->finalizer ();
1115 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1116 allocate them using ggc_internal_cleared_alloc. */
1118 void *
1119 playback::wrapper::
1120 operator new (size_t sz)
1122 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1126 /* Constructor for gcc:jit::playback::function. */
1128 playback::function::
1129 function (context *ctxt,
1130 tree fndecl,
1131 enum gcc_jit_function_kind kind)
1132 : m_ctxt(ctxt),
1133 m_inner_fndecl (fndecl),
1134 m_inner_bind_expr (NULL),
1135 m_kind (kind)
1137 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1139 /* Create a BIND_EXPR, and within it, a statement list. */
1140 m_stmt_list = alloc_stmt_list ();
1141 m_stmt_iter = tsi_start (m_stmt_list);
1142 m_inner_block = make_node (BLOCK);
1143 m_inner_bind_expr =
1144 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1146 else
1148 m_inner_block = NULL;
1149 m_stmt_list = NULL;
1153 /* Hand-written GC-marking hook for playback functions. */
1155 void
1156 playback::function::
1157 gt_ggc_mx ()
1159 gt_ggc_m_9tree_node (m_inner_fndecl);
1160 gt_ggc_m_9tree_node (m_inner_bind_expr);
1161 gt_ggc_m_9tree_node (m_stmt_list);
1162 gt_ggc_m_9tree_node (m_inner_block);
1165 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1166 GC-ed. */
1168 void
1169 playback::function::finalizer ()
1171 m_blocks.release ();
1174 /* Get the return type of a playback function, in tree form. */
1176 tree
1177 playback::function::
1178 get_return_type_as_tree () const
1180 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1183 /* Construct a new local within this playback::function. */
1185 playback::lvalue *
1186 playback::function::
1187 new_local (location *loc,
1188 type *type,
1189 const char *name)
1191 gcc_assert (type);
1192 gcc_assert (name);
1193 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1194 get_identifier (name),
1195 type->as_tree ());
1196 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1198 /* Prepend to BIND_EXPR_VARS: */
1199 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1200 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1202 if (loc)
1203 set_tree_location (inner, loc);
1204 return new lvalue (m_ctxt, inner);
1207 /* Construct a new block within this playback::function. */
1209 playback::block *
1210 playback::function::
1211 new_block (const char *name)
1213 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1215 block *result = new playback::block (this, name);
1216 m_blocks.safe_push (result);
1217 return result;
1220 /* Build a statement list for the function as a whole out of the
1221 lists of statements for the individual blocks, building labels
1222 for each block. */
1224 void
1225 playback::function::
1226 build_stmt_list ()
1228 int i;
1229 block *b;
1231 FOR_EACH_VEC_ELT (m_blocks, i, b)
1233 int j;
1234 tree stmt;
1236 b->m_label_expr = build1 (LABEL_EXPR,
1237 void_type_node,
1238 b->as_label_decl ());
1239 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1241 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1242 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1246 /* Finish compiling the given function, potentially running the
1247 garbage-collector.
1248 The function will have a statement list by now.
1249 Amongst other things, this gimplifies the statement list,
1250 and calls cgraph_node::finalize_function on the function. */
1252 void
1253 playback::function::
1254 postprocess ()
1256 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1257 debug_tree (m_stmt_list);
1259 /* Do we need this to force cgraphunit.c to output the function? */
1260 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1262 DECL_EXTERNAL (m_inner_fndecl) = 0;
1263 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1266 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1267 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1269 DECL_EXTERNAL (m_inner_fndecl) = 0;
1270 TREE_PUBLIC (m_inner_fndecl) = 0;
1273 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1275 /* Seem to need this in gimple-low.c: */
1276 gcc_assert (m_inner_block);
1277 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1279 /* how to add to function? the following appears to be how to
1280 set the body of a m_inner_fndecl: */
1281 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1283 /* Ensure that locals appear in the debuginfo. */
1284 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1286 //debug_tree (m_inner_fndecl);
1288 /* Convert to gimple: */
1289 //printf("about to gimplify_function_tree\n");
1290 gimplify_function_tree (m_inner_fndecl);
1291 //printf("finished gimplify_function_tree\n");
1293 current_function_decl = m_inner_fndecl;
1294 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1295 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1296 //debug_tree (m_inner_fndecl);
1298 //printf("about to add to cgraph\n");
1299 /* Add to cgraph: */
1300 cgraph_node::finalize_function (m_inner_fndecl, false);
1301 /* This can trigger a collection, so we need to have all of
1302 the funcs as roots. */
1304 current_function_decl = NULL;
1308 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1309 GC-ed. */
1311 void
1312 playback::block::finalizer ()
1314 m_stmts.release ();
1317 /* Add an eval of the rvalue to the function's statement list. */
1319 void
1320 playback::block::
1321 add_eval (location *loc,
1322 rvalue *rvalue)
1324 gcc_assert (rvalue);
1326 if (loc)
1327 set_tree_location (rvalue->as_tree (), loc);
1329 add_stmt (rvalue->as_tree ());
1332 /* Add an assignment to the function's statement list. */
1334 void
1335 playback::block::
1336 add_assignment (location *loc,
1337 lvalue *lvalue,
1338 rvalue *rvalue)
1340 gcc_assert (lvalue);
1341 gcc_assert (rvalue);
1343 tree t_lvalue = lvalue->as_tree ();
1344 tree t_rvalue = rvalue->as_tree ();
1345 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1347 t_rvalue = build1 (CONVERT_EXPR,
1348 TREE_TYPE (t_lvalue),
1349 t_rvalue);
1350 if (loc)
1351 set_tree_location (t_rvalue, loc);
1354 tree stmt =
1355 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1356 t_lvalue, t_rvalue);
1357 if (loc)
1358 set_tree_location (stmt, loc);
1359 add_stmt (stmt);
1362 /* Add a comment to the function's statement list.
1363 For now this is done by adding a dummy label. */
1365 void
1366 playback::block::
1367 add_comment (location *loc,
1368 const char *text)
1370 /* Wrap the text in C-style comment delimiters. */
1371 size_t sz =
1372 (3 /* opening delim */
1373 + strlen (text)
1374 + 3 /* closing delim */
1375 + 1 /* terminator */);
1376 char *wrapped = (char *)ggc_internal_alloc (sz);
1377 snprintf (wrapped, sz, "/* %s */", text);
1379 /* For now we simply implement this by adding a dummy label with a name
1380 containing the given text. */
1381 tree identifier = get_identifier (wrapped);
1382 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1383 identifier, void_type_node);
1384 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1386 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1387 if (loc)
1388 set_tree_location (label_expr, loc);
1389 add_stmt (label_expr);
1392 /* Add a conditional jump statement to the function's statement list. */
1394 void
1395 playback::block::
1396 add_conditional (location *loc,
1397 rvalue *boolval,
1398 block *on_true,
1399 block *on_false)
1401 gcc_assert (boolval);
1402 gcc_assert (on_true);
1403 gcc_assert (on_false);
1405 /* COND_EXPR wants statement lists for the true/false operands, but we
1406 want labels.
1407 Shim it by creating jumps to the labels */
1408 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1409 on_true->as_label_decl ());
1410 if (loc)
1411 set_tree_location (true_jump, loc);
1413 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1414 on_false->as_label_decl ());
1415 if (loc)
1416 set_tree_location (false_jump, loc);
1418 tree stmt =
1419 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1420 true_jump, false_jump);
1421 if (loc)
1422 set_tree_location (stmt, loc);
1423 add_stmt (stmt);
1426 /* Add an unconditional jump statement to the function's statement list. */
1428 void
1429 playback::block::
1430 add_jump (location *loc,
1431 block *target)
1433 gcc_assert (target);
1435 // see c_finish_loop
1436 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1437 //add_stmt (top);
1439 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1440 TREE_USED (target->as_label_decl ()) = 1;
1441 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1442 if (loc)
1443 set_tree_location (stmt, loc);
1444 add_stmt (stmt);
1447 from c-typeck.c:
1448 tree
1449 c_finish_goto_label (location_t loc, tree label)
1451 tree decl = lookup_label_for_goto (loc, label);
1452 if (!decl)
1453 return NULL_TREE;
1454 TREE_USED (decl) = 1;
1456 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1457 SET_EXPR_LOCATION (t, loc);
1458 return add_stmt (t);
1465 /* Add a return statement to the function's statement list. */
1467 void
1468 playback::block::
1469 add_return (location *loc,
1470 rvalue *rvalue)
1472 tree modify_retval = NULL;
1473 tree return_type = m_func->get_return_type_as_tree ();
1474 if (rvalue)
1476 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1477 tree t_rvalue = rvalue->as_tree ();
1478 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1479 t_rvalue = build1 (CONVERT_EXPR,
1480 TREE_TYPE (t_lvalue),
1481 t_rvalue);
1482 modify_retval = build2 (MODIFY_EXPR, return_type,
1483 t_lvalue, t_rvalue);
1484 if (loc)
1485 set_tree_location (modify_retval, loc);
1487 tree return_stmt = build1 (RETURN_EXPR, return_type,
1488 modify_retval);
1489 if (loc)
1490 set_tree_location (return_stmt, loc);
1492 add_stmt (return_stmt);
1495 /* Constructor for gcc::jit::playback::block. */
1497 playback::block::
1498 block (function *func,
1499 const char *name)
1500 : m_func (func),
1501 m_stmts ()
1503 tree identifier;
1505 gcc_assert (func);
1506 // name can be NULL
1507 if (name)
1508 identifier = get_identifier (name);
1509 else
1510 identifier = NULL;
1511 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1512 identifier, void_type_node);
1513 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1514 m_label_expr = NULL;
1517 /* Construct a tempdir path template suitable for use by mkdtemp
1518 e.g. "/tmp/libgccjit-XXXXXX", but respecting the rules in
1519 libiberty's choose_tempdir rather than hardcoding "/tmp/".
1521 The memory is allocated using malloc and must be freed.
1522 Aborts the process if allocation fails. */
1524 static char *
1525 make_tempdir_path_template ()
1527 const char *tmpdir_buf;
1528 size_t tmpdir_len;
1529 const char *file_template_buf;
1530 size_t file_template_len;
1531 char *result;
1533 /* The result of choose_tmpdir is a cached buffer within libiberty, so
1534 we must *not* free it. */
1535 tmpdir_buf = choose_tmpdir ();
1537 /* choose_tmpdir aborts on malloc failure. */
1538 gcc_assert (tmpdir_buf);
1540 tmpdir_len = strlen (tmpdir_buf);
1541 /* tmpdir_buf should now have a dir separator as the final byte. */
1542 gcc_assert (tmpdir_len > 0);
1543 gcc_assert (tmpdir_buf[tmpdir_len - 1] == DIR_SEPARATOR);
1545 file_template_buf = "libgccjit-XXXXXX";
1546 file_template_len = strlen (file_template_buf);
1548 result = XNEWVEC (char, tmpdir_len + file_template_len + 1);
1549 strcpy (result, tmpdir_buf);
1550 strcpy (result + tmpdir_len, file_template_buf);
1552 return result;
1555 /* Compile a playback::context:
1557 - Use the context's options to cconstruct command-line options, and
1558 call into the rest of GCC (toplev::main).
1559 - Assuming it succeeds, we have a .s file; we want a .so file.
1560 Invoke another gcc to convert the .s file to a .so file.
1561 - dlopen the .so file
1562 - Wrap the result up as a playback::result and return it. */
1564 result *
1565 playback::context::
1566 compile ()
1568 void *handle = NULL;
1569 const char *ctxt_progname;
1570 result *result_obj = NULL;
1572 m_path_template = make_tempdir_path_template ();
1573 if (!m_path_template)
1574 return NULL;
1576 /* Create tempdir using mkdtemp. This is created with 0700 perms and
1577 is unique. Hence no other (non-root) users should have access to
1578 the paths within it. */
1579 m_path_tempdir = mkdtemp (m_path_template);
1580 if (!m_path_tempdir)
1581 return NULL;
1582 m_path_c_file = concat (m_path_tempdir, "/fake.c", NULL);
1583 m_path_s_file = concat (m_path_tempdir, "/fake.s", NULL);
1584 m_path_so_file = concat (m_path_tempdir, "/fake.so", NULL);
1586 /* Call into the rest of gcc.
1587 For now, we have to assemble command-line options to pass into
1588 toplev::main, so that they can be parsed. */
1590 /* Pass in user-provided program name as argv0, if any, so that it
1591 makes it into GCC's "progname" global, used in various diagnostics. */
1592 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1594 if (!ctxt_progname)
1595 ctxt_progname = "libgccjit.so";
1597 auto_vec <const char *> fake_args;
1598 make_fake_args (&fake_args, ctxt_progname);
1599 if (errors_occurred ())
1600 return NULL;
1602 toplev toplev (false);
1603 toplev.main (fake_args.length (),
1604 const_cast <char **> (fake_args.address ()));
1605 toplev.finalize ();
1607 active_playback_ctxt = NULL;
1609 if (errors_occurred ())
1610 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 ())
1617 return NULL;
1619 /* dlopen the .so file. */
1621 auto_timevar load_timevar (TV_LOAD);
1623 const char *error;
1625 /* Clear any existing error. */
1626 dlerror ();
1628 handle = dlopen (m_path_so_file, RTLD_NOW | RTLD_LOCAL);
1629 if ((error = dlerror()) != NULL) {
1630 add_error (NULL, "%s", error);
1632 if (handle)
1633 result_obj = new result (handle);
1634 else
1635 result_obj = NULL;
1638 return result_obj;
1641 /* Helper functions for gcc::jit::playback::context::compile. */
1643 /* Build a fake argv for toplev::main from the options set
1644 by the user on the context . */
1646 void
1647 playback::context::
1648 make_fake_args (auto_vec <const char *> *argvec,
1649 const char *ctxt_progname)
1651 #define ADD_ARG(arg) argvec->safe_push (arg)
1653 ADD_ARG (ctxt_progname);
1654 ADD_ARG (m_path_c_file);
1655 ADD_ARG ("-fPIC");
1657 /* Handle int options: */
1658 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
1660 default:
1661 add_error (NULL,
1662 "unrecognized optimization level: %i",
1663 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
1664 return;
1666 case 0:
1667 ADD_ARG ("-O0");
1668 break;
1670 case 1:
1671 ADD_ARG ("-O1");
1672 break;
1674 case 2:
1675 ADD_ARG ("-O2");
1676 break;
1678 case 3:
1679 ADD_ARG ("-O3");
1680 break;
1682 /* What about -Os? */
1684 /* Handle bool options: */
1685 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
1686 ADD_ARG ("-g");
1688 /* Suppress timing (and other) info. */
1689 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
1691 ADD_ARG ("-quiet");
1692 quiet_flag = 1;
1695 /* Aggressively garbage-collect, to shake out bugs: */
1696 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
1698 ADD_ARG ("--param");
1699 ADD_ARG ("ggc-min-expand=0");
1700 ADD_ARG ("--param");
1701 ADD_ARG ("ggc-min-heapsize=0");
1704 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
1706 ADD_ARG ("-fdump-tree-all");
1707 ADD_ARG ("-fdump-rtl-all");
1708 ADD_ARG ("-fdump-ipa-all");
1710 #undef ADD_ARG
1713 /* Part of playback::context::compile ().
1715 We have a .s file; we want a .so file.
1716 We could reuse parts of gcc/gcc.c to do this.
1717 For now, just use the driver binary from the install, as
1718 named in gcc-driver-name.h
1719 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
1721 void
1722 playback::context::
1723 convert_to_dso (const char *ctxt_progname)
1725 /* Currently this lumps together both assembling and linking into
1726 TV_ASSEMBLE. */
1727 auto_timevar assemble_timevar (TV_ASSEMBLE);
1728 const char *errmsg;
1729 const char *argv[7];
1730 int exit_status = 0;
1731 int err = 0;
1732 const char *gcc_driver_name = GCC_DRIVER_NAME;
1734 argv[0] = gcc_driver_name;
1735 argv[1] = "-shared";
1736 /* The input: assembler. */
1737 argv[2] = m_path_s_file;
1738 /* The output: shared library. */
1739 argv[3] = "-o";
1740 argv[4] = m_path_so_file;
1742 /* Don't use the linker plugin.
1743 If running with just a "make" and not a "make install", then we'd
1744 run into
1745 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
1746 libto_plugin is a .la at build time, with it becoming installed with
1747 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
1748 time. */
1749 argv[5] = "-fno-use-linker-plugin";
1751 /* pex argv arrays are NULL-terminated. */
1752 argv[6] = NULL;
1754 /* pex_one's error-handling requires pname to be non-NULL. */
1755 gcc_assert (ctxt_progname);
1757 errmsg = pex_one (PEX_SEARCH, /* int flags, */
1758 gcc_driver_name,
1759 const_cast<char * const *> (argv),
1760 ctxt_progname, /* const char *pname */
1761 NULL, /* const char *outname */
1762 NULL, /* const char *errname */
1763 &exit_status, /* int *status */
1764 &err); /* int *err*/
1765 if (errmsg)
1767 add_error (NULL, "error invoking gcc driver: %s", errmsg);
1768 return;
1771 /* pex_one can return a NULL errmsg when the executable wasn't
1772 found (or doesn't exist), so trap these cases also. */
1773 if (exit_status || err)
1775 add_error (NULL,
1776 "error invoking gcc driver: exit_status: %i err: %i",
1777 exit_status, err);
1778 add_error (NULL,
1779 "whilst attempting to run a driver named: %s",
1780 gcc_driver_name);
1781 add_error (NULL,
1782 "PATH was: %s",
1783 getenv ("PATH"));
1784 return;
1788 /* Top-level hook for playing back a recording context.
1790 This plays back m_recording_ctxt, and, if no errors
1791 occurred builds statement lists for and then postprocesses
1792 every function in the result. */
1794 void
1795 playback::context::
1796 replay ()
1798 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
1799 tree array_domain_type = build_index_type (size_int (200));
1800 m_char_array_type_node
1801 = build_array_type (char_type_node, array_domain_type);
1803 m_const_char_ptr
1804 = build_pointer_type (build_qualified_type (char_type_node,
1805 TYPE_QUAL_CONST));
1807 /* Replay the recorded events: */
1808 timevar_push (TV_JIT_REPLAY);
1810 m_recording_ctxt->replay_into (this);
1812 /* Clean away the temporary references from recording objects
1813 to playback objects. We have to do this now since the
1814 latter are GC-allocated, but the former don't mark these
1815 refs. Hence we must stop using them before the GC can run. */
1816 m_recording_ctxt->disassociate_from_playback ();
1818 /* The builtins_manager, if any, is associated with the recording::context
1819 and might be reused for future compiles on other playback::contexts,
1820 but its m_attributes array is not GTY-labeled and hence will become
1821 nonsense if the GC runs. Purge this state. */
1822 builtins_manager *bm = get_builtins_manager ();
1823 if (bm)
1824 bm->finish_playback ();
1826 timevar_pop (TV_JIT_REPLAY);
1828 if (!errors_occurred ())
1830 int i;
1831 function *func;
1833 /* No GC can happen yet; process the cached source locations. */
1834 handle_locations ();
1836 /* We've now created tree nodes for the stmts in the various blocks
1837 in each function, but we haven't built each function's single stmt
1838 list yet. Do so now. */
1839 FOR_EACH_VEC_ELT (m_functions, i, func)
1840 func->build_stmt_list ();
1842 /* No GC can have happened yet. */
1844 /* Postprocess the functions. This could trigger GC. */
1845 FOR_EACH_VEC_ELT (m_functions, i, func)
1847 gcc_assert (func);
1848 func->postprocess ();
1853 /* Dump the generated .s file to stderr. */
1855 void
1856 playback::context::
1857 dump_generated_code ()
1859 char buf[4096];
1860 size_t sz;
1861 FILE *f_in = fopen (m_path_s_file, "r");
1862 if (!f_in)
1863 return;
1865 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
1866 fwrite (buf, 1, sz, stderr);
1868 fclose (f_in);
1871 /* qsort comparator for comparing pairs of playback::source_line *,
1872 ordering them by line number. */
1874 static int
1875 line_comparator (const void *lhs, const void *rhs)
1877 const playback::source_line *line_lhs = \
1878 *static_cast<const playback::source_line * const*> (lhs);
1879 const playback::source_line *line_rhs = \
1880 *static_cast<const playback::source_line * const*> (rhs);
1881 return line_lhs->get_line_num () - line_rhs->get_line_num ();
1884 /* qsort comparator for comparing pairs of playback::location *,
1885 ordering them by column number. */
1887 static int
1888 location_comparator (const void *lhs, const void *rhs)
1890 const playback::location *loc_lhs = \
1891 *static_cast<const playback::location * const *> (lhs);
1892 const playback::location *loc_rhs = \
1893 *static_cast<const playback::location * const *> (rhs);
1894 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
1897 /* Our API allows locations to be created in arbitrary orders, but the
1898 linemap API requires locations to be created in ascending order
1899 as if we were tokenizing files.
1901 This hook sorts all of the the locations that have been created, and
1902 calls into the linemap API, creating linemap entries in sorted order
1903 for our locations. */
1905 void
1906 playback::context::
1907 handle_locations ()
1909 /* Create the source code locations, following the ordering rules
1910 imposed by the linemap API.
1912 line_table is a global. */
1913 int i;
1914 source_file *file;
1916 FOR_EACH_VEC_ELT (m_source_files, i, file)
1918 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
1920 /* Sort lines by ascending line numbers. */
1921 file->m_source_lines.qsort (&line_comparator);
1923 int j;
1924 source_line *line;
1925 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
1927 int k;
1928 location *loc;
1930 /* Sort locations in line by ascending column numbers. */
1931 line->m_locations.qsort (&location_comparator);
1933 /* Determine maximum column within this line. */
1934 gcc_assert (line->m_locations.length () > 0);
1935 location *final_column =
1936 line->m_locations[line->m_locations.length () - 1];
1937 int max_col = final_column->get_column_num ();
1939 linemap_line_start (line_table, line->get_line_num (), max_col);
1940 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
1942 loc->m_srcloc = \
1943 linemap_position_for_column (line_table, loc->get_column_num ());
1947 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
1950 /* line_table should now be populated; every playback::location should
1951 now have an m_srcloc. */
1953 /* Now assign them to tree nodes as appropriate. */
1954 std::pair<tree, location *> *cached_location;
1956 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
1958 tree t = cached_location->first;
1959 source_location srcloc = cached_location->second->m_srcloc;
1961 /* This covers expressions: */
1962 if (CAN_HAVE_LOCATION_P (t))
1963 SET_EXPR_LOCATION (t, srcloc);
1964 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
1965 DECL_SOURCE_LOCATION (t) = srcloc;
1966 else
1968 /* Don't know how to set location on this node. */
1973 /* We handle errors on a playback::context by adding them to the
1974 corresponding recording::context. */
1976 void
1977 playback::context::
1978 add_error (location *loc, const char *fmt, ...)
1980 va_list ap;
1981 va_start (ap, fmt);
1982 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
1983 fmt, ap);
1984 va_end (ap);
1987 /* We handle errors on a playback::context by adding them to the
1988 corresponding recording::context. */
1990 void
1991 playback::context::
1992 add_error_va (location *loc, const char *fmt, va_list ap)
1994 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
1995 fmt, ap);
1998 /* Dealing with the linemap API. */
2000 /* Construct a playback::location for a recording::location, if it
2001 doesn't exist already. */
2003 playback::location *
2004 playback::context::
2005 new_location (recording::location *rloc,
2006 const char *filename,
2007 int line,
2008 int column)
2010 /* Get the source_file for filename, creating if necessary. */
2011 source_file *src_file = get_source_file (filename);
2012 /* Likewise for the line within the file. */
2013 source_line *src_line = src_file->get_source_line (line);
2014 /* Likewise for the column within the line. */
2015 location *loc = src_line->get_location (rloc, column);
2016 return loc;
2019 /* Deferred setting of the location for a given tree, by adding the
2020 (tree, playback::location) pair to a list of deferred associations.
2021 We will actually set the location on the tree later on once
2022 the source_location for the playback::location exists. */
2024 void
2025 playback::context::
2026 set_tree_location (tree t, location *loc)
2028 gcc_assert (loc);
2029 m_cached_locations.safe_push (std::make_pair (t, loc));
2033 /* Construct a playback::source_file for the given source
2034 filename, if it doesn't exist already. */
2036 playback::source_file *
2037 playback::context::
2038 get_source_file (const char *filename)
2040 /* Locate the file.
2041 For simplicitly, this is currently a linear search.
2042 Replace with a hash if this shows up in the profile. */
2043 int i;
2044 source_file *file;
2045 tree ident_filename = get_identifier (filename);
2047 FOR_EACH_VEC_ELT (m_source_files, i, file)
2048 if (file->filename_as_tree () == ident_filename)
2049 return file;
2051 /* Not found. */
2052 file = new source_file (ident_filename);
2053 m_source_files.safe_push (file);
2054 return file;
2057 /* Constructor for gcc::jit::playback::source_file. */
2059 playback::source_file::source_file (tree filename) :
2060 m_source_lines (),
2061 m_filename (filename)
2065 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2066 GC-ed. */
2068 void
2069 playback::source_file::finalizer ()
2071 m_source_lines.release ();
2074 /* Construct a playback::source_line for the given line
2075 within this source file, if one doesn't exist already. */
2077 playback::source_line *
2078 playback::source_file::
2079 get_source_line (int line_num)
2081 /* Locate the line.
2082 For simplicitly, this is currently a linear search.
2083 Replace with a hash if this shows up in the profile. */
2084 int i;
2085 source_line *line;
2087 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2088 if (line->get_line_num () == line_num)
2089 return line;
2091 /* Not found. */
2092 line = new source_line (this, line_num);
2093 m_source_lines.safe_push (line);
2094 return line;
2097 /* Constructor for gcc::jit::playback::source_line. */
2099 playback::source_line::source_line (source_file *file, int line_num) :
2100 m_locations (),
2101 m_source_file (file),
2102 m_line_num (line_num)
2106 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2107 GC-ed. */
2109 void
2110 playback::source_line::finalizer ()
2112 m_locations.release ();
2115 /* Construct a playback::location for the given column
2116 within this line of a specific source file, if one doesn't exist
2117 already. */
2119 playback::location *
2120 playback::source_line::
2121 get_location (recording::location *rloc, int column_num)
2123 int i;
2124 location *loc;
2126 /* Another linear search that probably should be a hash table. */
2127 FOR_EACH_VEC_ELT (m_locations, i, loc)
2128 if (loc->get_column_num () == column_num)
2129 return loc;
2131 /* Not found. */
2132 loc = new location (rloc, this, column_num);
2133 m_locations.safe_push (loc);
2134 return loc;
2137 /* Constructor for gcc::jit::playback::location. */
2139 playback::location::location (recording::location *loc,
2140 source_line *line,
2141 int column_num) :
2142 m_srcloc (UNKNOWN_LOCATION),
2143 m_recording_loc (loc),
2144 m_line (line),
2145 m_column_num(column_num)
2149 /* The active gcc::jit::playback::context instance. This is a singleton,
2150 guarded by jit_mutex. */
2152 playback::context *active_playback_ctxt;
2154 } // namespace gcc::jit
2156 } // namespace gcc