Daily bump.
[official-gcc.git] / gcc / jit / jit-playback.c
blob59399dee251c9e546501e5edefa54a42d3379c71
1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2021 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "target.h"
25 #include "tree.h"
26 #include "stringpool.h"
27 #include "cgraph.h"
28 #include "dumpfile.h"
29 #include "toplev.h"
30 #include "tree-cfg.h"
31 #include "convert.h"
32 #include "stor-layout.h"
33 #include "print-tree.h"
34 #include "gimplify.h"
35 #include "gcc-driver-name.h"
36 #include "attribs.h"
37 #include "context.h"
38 #include "fold-const.h"
39 #include "opt-suggestions.h"
40 #include "gcc.h"
41 #include "diagnostic.h"
42 #include "stmt.h"
44 #include <pthread.h>
46 #include "jit-playback.h"
47 #include "jit-result.h"
48 #include "jit-builtins.h"
49 #include "jit-tempdir.h"
51 #ifdef _WIN32
52 #include "jit-w32.h"
53 #endif
55 /* Compare with gcc/c-family/c-common.h: DECL_C_BIT_FIELD,
56 SET_DECL_C_BIT_FIELD.
57 These are redefined here to avoid depending from the C frontend. */
58 #define DECL_JIT_BIT_FIELD(NODE) \
59 (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1)
60 #define SET_DECL_JIT_BIT_FIELD(NODE) \
61 (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1)
63 /* gcc::jit::playback::context::build_cast uses the convert.h API,
64 which in turn requires the frontend to provide a "convert"
65 function, apparently as a fallback for casts that can be simplified
66 (truncation, extension). */
67 extern tree convert (tree type, tree expr);
69 tree
70 convert (tree dst_type, tree expr)
72 tree t_ret = NULL;
73 t_ret = targetm.convert_to_type (dst_type, expr);
74 if (t_ret)
75 return t_ret;
76 switch (TREE_CODE (dst_type))
78 case INTEGER_TYPE:
79 case ENUMERAL_TYPE:
80 return fold (convert_to_integer (dst_type, expr));
82 default:
83 gcc_assert (gcc::jit::active_playback_ctxt);
84 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
85 fprintf (stderr, "input expression:\n");
86 debug_tree (expr);
87 fprintf (stderr, "requested type:\n");
88 debug_tree (dst_type);
89 return error_mark_node;
93 namespace gcc {
94 namespace jit {
96 /**********************************************************************
97 Playback.
98 **********************************************************************/
100 /* Build a STRING_CST tree for STR, or return NULL if it is NULL.
101 The TREE_TYPE is not initialized. */
103 static tree
104 build_string (const char *str)
106 if (str)
107 return ::build_string (strlen (str), str);
108 else
109 return NULL_TREE;
112 /* The constructor for gcc::jit::playback::context. */
114 playback::context::context (recording::context *ctxt)
115 : log_user (ctxt->get_logger ()),
116 m_recording_ctxt (ctxt),
117 m_tempdir (NULL),
118 m_const_char_ptr (NULL)
120 JIT_LOG_SCOPE (get_logger ());
121 m_functions.create (0);
122 m_globals.create (0);
123 m_source_files.create (0);
124 m_cached_locations.create (0);
127 /* The destructor for gcc::jit::playback::context. */
129 playback::context::~context ()
131 JIT_LOG_SCOPE (get_logger ());
133 /* Normally the playback::context is responsible for cleaning up the
134 tempdir (including "fake.so" within the filesystem).
136 In the normal case, clean it up now.
138 However m_tempdir can be NULL if the context has handed over
139 responsibility for the tempdir cleanup to the jit::result object, so
140 that the cleanup can be delayed (see PR jit/64206). If that's the
141 case this "delete NULL;" is a no-op. */
142 delete m_tempdir;
144 m_functions.release ();
147 /* A playback::context can reference GC-managed pointers. Mark them
148 ("by hand", rather than by gengtype).
150 This is called on the active playback context (if any) by the
151 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
153 void
154 playback::context::
155 gt_ggc_mx ()
157 int i;
158 function *func;
159 FOR_EACH_VEC_ELT (m_functions, i, func)
161 if (ggc_test_and_set_mark (func))
162 func->gt_ggc_mx ();
166 /* Given an enum gcc_jit_types value, get a "tree" type. */
168 tree
169 playback::context::
170 get_tree_node_for_type (enum gcc_jit_types type_)
172 switch (type_)
174 case GCC_JIT_TYPE_VOID:
175 return void_type_node;
177 case GCC_JIT_TYPE_VOID_PTR:
178 return ptr_type_node;
180 case GCC_JIT_TYPE_BOOL:
181 return boolean_type_node;
183 case GCC_JIT_TYPE_CHAR:
184 return char_type_node;
185 case GCC_JIT_TYPE_SIGNED_CHAR:
186 return signed_char_type_node;
187 case GCC_JIT_TYPE_UNSIGNED_CHAR:
188 return unsigned_char_type_node;
190 case GCC_JIT_TYPE_SHORT:
191 return short_integer_type_node;
192 case GCC_JIT_TYPE_UNSIGNED_SHORT:
193 return short_unsigned_type_node;
195 case GCC_JIT_TYPE_CONST_CHAR_PTR:
196 return m_const_char_ptr;
198 case GCC_JIT_TYPE_INT:
199 return integer_type_node;
200 case GCC_JIT_TYPE_UNSIGNED_INT:
201 return unsigned_type_node;
203 case GCC_JIT_TYPE_LONG:
204 return long_integer_type_node;
205 case GCC_JIT_TYPE_UNSIGNED_LONG:
206 return long_unsigned_type_node;
208 case GCC_JIT_TYPE_LONG_LONG:
209 return long_long_integer_type_node;
210 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
211 return long_long_unsigned_type_node;
213 case GCC_JIT_TYPE_FLOAT:
214 return float_type_node;
215 case GCC_JIT_TYPE_DOUBLE:
216 return double_type_node;
217 case GCC_JIT_TYPE_LONG_DOUBLE:
218 return long_double_type_node;
220 case GCC_JIT_TYPE_SIZE_T:
221 return size_type_node;
223 case GCC_JIT_TYPE_FILE_PTR:
224 return fileptr_type_node;
226 case GCC_JIT_TYPE_COMPLEX_FLOAT:
227 return complex_float_type_node;
228 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
229 return complex_double_type_node;
230 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
231 return complex_long_double_type_node;
234 return NULL;
237 /* Construct a playback::type instance (wrapping a tree) for the given
238 enum value. */
240 playback::type *
241 playback::context::
242 get_type (enum gcc_jit_types type_)
244 tree type_node = get_tree_node_for_type (type_);
245 if (type_node == NULL)
247 add_error (NULL, "unrecognized (enum gcc_jit_types) value: %i", type_);
248 return NULL;
251 return new type (type_node);
254 /* Construct a playback::type instance (wrapping a tree) for the given
255 array type. */
257 playback::type *
258 playback::context::
259 new_array_type (playback::location *loc,
260 playback::type *element_type,
261 int num_elements)
263 gcc_assert (element_type);
265 tree t = build_array_type_nelts (element_type->as_tree (),
266 num_elements);
267 layout_type (t);
269 if (loc)
270 set_tree_location (t, loc);
272 return new type (t);
275 /* Construct a playback::field instance (wrapping a tree). */
277 playback::field *
278 playback::context::
279 new_field (location *loc,
280 type *type,
281 const char *name)
283 gcc_assert (type);
284 gcc_assert (name);
286 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
287 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
288 get_identifier (name), type->as_tree ());
290 if (loc)
291 set_tree_location (decl, loc);
293 return new field (decl);
296 /* Construct a playback::bitfield instance (wrapping a tree). */
298 playback::field *
299 playback::context::
300 new_bitfield (location *loc,
301 type *type,
302 int width,
303 const char *name)
305 gcc_assert (type);
306 gcc_assert (name);
307 gcc_assert (width);
309 /* compare with c/c-decl.c:grokfield, grokdeclarator and
310 check_bitfield_type_and_width. */
312 tree tree_type = type->as_tree ();
313 gcc_assert (INTEGRAL_TYPE_P (tree_type));
314 tree tree_width = build_int_cst (integer_type_node, width);
315 if (compare_tree_int (tree_width, TYPE_PRECISION (tree_type)) > 0)
317 add_error (
318 loc,
319 "width of bit-field %s (width: %i) is wider than its type (width: %i)",
320 name, width, TYPE_PRECISION (tree_type));
321 return NULL;
324 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
325 get_identifier (name), type->as_tree ());
326 DECL_NONADDRESSABLE_P (decl) = true;
327 DECL_INITIAL (decl) = tree_width;
328 SET_DECL_JIT_BIT_FIELD (decl);
330 if (loc)
331 set_tree_location (decl, loc);
333 return new field (decl);
336 /* Construct a playback::compound_type instance (wrapping a tree). */
338 playback::compound_type *
339 playback::context::
340 new_compound_type (location *loc,
341 const char *name,
342 bool is_struct) /* else is union */
344 gcc_assert (name);
346 /* Compare with c/c-decl.c: start_struct. */
348 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
349 TYPE_NAME (t) = get_identifier (name);
350 TYPE_SIZE (t) = 0;
352 if (loc)
353 set_tree_location (t, loc);
355 return new compound_type (t);
358 void
359 playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
361 /* Compare with c/c-decl.c: finish_struct. */
362 tree t = as_tree ();
364 tree fieldlist = NULL;
365 for (unsigned i = 0; i < fields->length (); i++)
367 field *f = (*fields)[i];
368 tree x = f->as_tree ();
369 DECL_CONTEXT (x) = t;
370 if (DECL_JIT_BIT_FIELD (x))
372 unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (x));
373 DECL_SIZE (x) = bitsize_int (width);
374 DECL_BIT_FIELD (x) = 1;
376 fieldlist = chainon (x, fieldlist);
378 fieldlist = nreverse (fieldlist);
379 TYPE_FIELDS (t) = fieldlist;
381 layout_type (t);
384 /* Construct a playback::type instance (wrapping a tree) for a function
385 type. */
387 playback::type *
388 playback::context::
389 new_function_type (type *return_type,
390 const auto_vec<type *> *param_types,
391 int is_variadic)
393 int i;
394 type *param_type;
396 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
398 FOR_EACH_VEC_ELT (*param_types, i, param_type)
399 arg_types[i] = param_type->as_tree ();
401 tree fn_type;
402 if (is_variadic)
403 fn_type =
404 build_varargs_function_type_array (return_type->as_tree (),
405 param_types->length (),
406 arg_types);
407 else
408 fn_type = build_function_type_array (return_type->as_tree (),
409 param_types->length (),
410 arg_types);
411 free (arg_types);
413 return new type (fn_type);
416 /* Construct a playback::param instance (wrapping a tree). */
418 playback::param *
419 playback::context::
420 new_param (location *loc,
421 type *type,
422 const char *name)
424 gcc_assert (type);
425 gcc_assert (name);
426 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
427 get_identifier (name), type->as_tree ());
428 if (loc)
429 set_tree_location (inner, loc);
431 return new param (this, inner);
434 /* Construct a playback::function instance. */
436 playback::function *
437 playback::context::
438 new_function (location *loc,
439 enum gcc_jit_function_kind kind,
440 type *return_type,
441 const char *name,
442 const auto_vec<param *> *params,
443 int is_variadic,
444 enum built_in_function builtin_id)
446 int i;
447 param *param;
449 //can return_type be NULL?
450 gcc_assert (name);
452 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
453 FOR_EACH_VEC_ELT (*params, i, param)
454 arg_types[i] = TREE_TYPE (param->as_tree ());
456 tree fn_type;
457 if (is_variadic)
458 fn_type = build_varargs_function_type_array (return_type->as_tree (),
459 params->length (), arg_types);
460 else
461 fn_type = build_function_type_array (return_type->as_tree (),
462 params->length (), arg_types);
463 free (arg_types);
465 /* FIXME: this uses input_location: */
466 tree fndecl = build_fn_decl (name, fn_type);
468 if (loc)
469 set_tree_location (fndecl, loc);
471 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
472 NULL_TREE, return_type->as_tree ());
473 DECL_ARTIFICIAL (resdecl) = 1;
474 DECL_IGNORED_P (resdecl) = 1;
475 DECL_RESULT (fndecl) = resdecl;
477 if (builtin_id)
479 gcc_assert (loc == NULL);
480 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
482 built_in_class fclass = builtins_manager::get_class (builtin_id);
483 set_decl_built_in_function (fndecl, fclass, builtin_id);
484 set_builtin_decl (builtin_id, fndecl,
485 builtins_manager::implicit_p (builtin_id));
487 builtins_manager *bm = get_builtins_manager ();
488 tree attrs = bm->get_attrs_tree (builtin_id);
489 if (attrs)
490 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
491 else
492 decl_attributes (&fndecl, NULL_TREE, 0);
495 if (kind != GCC_JIT_FUNCTION_IMPORTED)
497 tree param_decl_list = NULL;
498 FOR_EACH_VEC_ELT (*params, i, param)
500 param_decl_list = chainon (param->as_tree (), param_decl_list);
503 /* The param list was created in reverse order; fix it: */
504 param_decl_list = nreverse (param_decl_list);
506 tree t;
507 for (t = param_decl_list; t; t = DECL_CHAIN (t))
509 DECL_CONTEXT (t) = fndecl;
510 DECL_ARG_TYPE (t) = TREE_TYPE (t);
513 /* Set it up on DECL_ARGUMENTS */
514 DECL_ARGUMENTS(fndecl) = param_decl_list;
517 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
519 DECL_DECLARED_INLINE_P (fndecl) = 1;
521 /* Add attribute "always_inline": */
522 DECL_ATTRIBUTES (fndecl) =
523 tree_cons (get_identifier ("always_inline"),
524 NULL,
525 DECL_ATTRIBUTES (fndecl));
528 function *func = new function (this, fndecl, kind);
529 m_functions.safe_push (func);
530 return func;
533 /* In use by new_global and new_global_initialized. */
535 tree
536 playback::context::
537 global_new_decl (location *loc,
538 enum gcc_jit_global_kind kind,
539 type *type,
540 const char *name)
542 gcc_assert (type);
543 gcc_assert (name);
544 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
545 get_identifier (name),
546 type->as_tree ());
547 TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
548 DECL_COMMON (inner) = 1;
549 switch (kind)
551 default:
552 gcc_unreachable ();
554 case GCC_JIT_GLOBAL_EXPORTED:
555 TREE_STATIC (inner) = 1;
556 break;
558 case GCC_JIT_GLOBAL_INTERNAL:
559 TREE_STATIC (inner) = 1;
560 break;
562 case GCC_JIT_GLOBAL_IMPORTED:
563 DECL_EXTERNAL (inner) = 1;
564 break;
567 if (loc)
568 set_tree_location (inner, loc);
570 return inner;
573 /* In use by new_global and new_global_initialized. */
575 playback::lvalue *
576 playback::context::
577 global_finalize_lvalue (tree inner)
579 m_globals.safe_push (inner);
581 return new lvalue (this, inner);
584 /* Construct a playback::lvalue instance (wrapping a tree). */
586 playback::lvalue *
587 playback::context::
588 new_global (location *loc,
589 enum gcc_jit_global_kind kind,
590 type *type,
591 const char *name)
593 tree inner = global_new_decl (loc, kind, type, name);
595 return global_finalize_lvalue (inner);
598 /* Fill 'constructor_elements' with the memory content of
599 'initializer'. Each element of the initializer is of the size of
600 type T. In use by new_global_initialized.*/
602 template<typename T>
603 static void
604 load_blob_in_ctor (vec<constructor_elt, va_gc> *&constructor_elements,
605 size_t num_elem,
606 const void *initializer)
608 /* Loosely based on 'output_init_element' c-typeck.c:9691. */
609 const T *p = (const T *)initializer;
610 tree node = make_unsigned_type (BITS_PER_UNIT * sizeof (T));
611 for (size_t i = 0; i < num_elem; i++)
613 constructor_elt celt =
614 { build_int_cst (long_unsigned_type_node, i),
615 build_int_cst (node, p[i]) };
616 vec_safe_push (constructor_elements, celt);
620 /* Construct an initialized playback::lvalue instance (wrapping a
621 tree). */
623 playback::lvalue *
624 playback::context::
625 new_global_initialized (location *loc,
626 enum gcc_jit_global_kind kind,
627 type *type,
628 size_t element_size,
629 size_t initializer_num_elem,
630 const void *initializer,
631 const char *name)
633 tree inner = global_new_decl (loc, kind, type, name);
635 vec<constructor_elt, va_gc> *constructor_elements = NULL;
637 switch (element_size)
639 case 1:
640 load_blob_in_ctor<uint8_t> (constructor_elements, initializer_num_elem,
641 initializer);
642 break;
643 case 2:
644 load_blob_in_ctor<uint16_t> (constructor_elements, initializer_num_elem,
645 initializer);
646 break;
647 case 4:
648 load_blob_in_ctor<uint32_t> (constructor_elements, initializer_num_elem,
649 initializer);
650 break;
651 case 8:
652 load_blob_in_ctor<uint64_t> (constructor_elements, initializer_num_elem,
653 initializer);
654 break;
655 default:
656 /* This function is serving on sizes returned by 'get_size',
657 these are all covered by the previous cases. */
658 gcc_unreachable ();
660 /* Compare with 'pop_init_level' c-typeck.c:8780. */
661 tree ctor = build_constructor (type->as_tree (), constructor_elements);
662 constructor_elements = NULL;
664 /* Compare with 'store_init_value' c-typeck.c:7555. */
665 DECL_INITIAL (inner) = ctor;
667 return global_finalize_lvalue (inner);
670 /* Implementation of the various
671 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
672 methods.
673 Each of these constructs a playback::rvalue instance (wrapping a tree).
675 These specializations are required to be in the same namespace
676 as the template, hence we now have to enter the gcc::jit::playback
677 namespace. */
679 namespace playback
682 /* Specialization of making an rvalue from a const, for host <int>. */
684 template <>
685 rvalue *
686 context::
687 new_rvalue_from_const <int> (type *type,
688 int value)
690 // FIXME: type-checking, or coercion?
691 tree inner_type = type->as_tree ();
692 if (INTEGRAL_TYPE_P (inner_type))
694 tree inner = build_int_cst (inner_type, value);
695 return new rvalue (this, inner);
697 else
699 REAL_VALUE_TYPE real_value;
700 real_from_integer (&real_value, VOIDmode, value, SIGNED);
701 tree inner = build_real (inner_type, real_value);
702 return new rvalue (this, inner);
706 /* Specialization of making an rvalue from a const, for host <long>. */
708 template <>
709 rvalue *
710 context::
711 new_rvalue_from_const <long> (type *type,
712 long value)
714 // FIXME: type-checking, or coercion?
715 tree inner_type = type->as_tree ();
716 if (INTEGRAL_TYPE_P (inner_type))
718 tree inner = build_int_cst (inner_type, value);
719 return new rvalue (this, inner);
721 else
723 REAL_VALUE_TYPE real_value;
724 real_from_integer (&real_value, VOIDmode, value, SIGNED);
725 tree inner = build_real (inner_type, real_value);
726 return new rvalue (this, inner);
730 /* Specialization of making an rvalue from a const, for host <double>. */
732 template <>
733 rvalue *
734 context::
735 new_rvalue_from_const <double> (type *type,
736 double value)
738 // FIXME: type-checking, or coercion?
739 tree inner_type = type->as_tree ();
741 /* We have a "double", we want a REAL_VALUE_TYPE.
743 real.c:real_from_target appears to require the representation to be
744 split into 32-bit values, and then sent as an pair of host long
745 ints. */
746 REAL_VALUE_TYPE real_value;
747 union
749 double as_double;
750 uint32_t as_uint32s[2];
751 } u;
752 u.as_double = value;
753 long int as_long_ints[2];
754 as_long_ints[0] = u.as_uint32s[0];
755 as_long_ints[1] = u.as_uint32s[1];
756 real_from_target (&real_value, as_long_ints, DFmode);
757 tree inner = build_real (inner_type, real_value);
758 return new rvalue (this, inner);
761 /* Specialization of making an rvalue from a const, for host <void *>. */
763 template <>
764 rvalue *
765 context::
766 new_rvalue_from_const <void *> (type *type,
767 void *value)
769 tree inner_type = type->as_tree ();
770 /* FIXME: how to ensure we have a wide enough type? */
771 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
772 return new rvalue (this, inner);
775 /* We're done implementing the specializations of
776 gcc::jit::playback::context::new_rvalue_from_const <T>
777 so we can exit the gcc::jit::playback namespace. */
779 } // namespace playback
781 /* Construct a playback::rvalue instance (wrapping a tree). */
783 playback::rvalue *
784 playback::context::
785 new_string_literal (const char *value)
787 /* Compare with c-family/c-common.c: fix_string_type. */
788 size_t len = strlen (value);
789 tree i_type = build_index_type (size_int (len));
790 tree a_type = build_array_type (char_type_node, i_type);
791 /* build_string len parameter must include NUL terminator when
792 building C strings. */
793 tree t_str = ::build_string (len + 1, value);
794 TREE_TYPE (t_str) = a_type;
796 /* Convert to (const char*), loosely based on
797 c/c-typeck.c: array_to_pointer_conversion,
798 by taking address of start of string. */
799 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
801 return new rvalue (this, t_addr);
804 /* Construct a playback::rvalue instance (wrapping a tree) for a
805 vector. */
807 playback::rvalue *
808 playback::context::new_rvalue_from_vector (location *,
809 type *type,
810 const auto_vec<rvalue *> &elements)
812 vec<constructor_elt, va_gc> *v;
813 vec_alloc (v, elements.length ());
814 for (unsigned i = 0; i < elements.length (); ++i)
815 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
816 tree t_ctor = build_constructor (type->as_tree (), v);
817 return new rvalue (this, t_ctor);
820 /* Coerce a tree expression into a boolean tree expression. */
822 tree
823 playback::context::
824 as_truth_value (tree expr, location *loc)
826 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
827 tree typed_zero = fold_build1 (CONVERT_EXPR,
828 TREE_TYPE (expr),
829 integer_zero_node);
830 if (loc)
831 set_tree_location (typed_zero, loc);
833 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
834 if (loc)
835 set_tree_location (expr, loc);
837 return expr;
840 /* Add a "top-level" basic asm statement (i.e. one outside of any functions)
841 containing ASM_STMTS.
843 Compare with c_parser_asm_definition. */
845 void
846 playback::context::add_top_level_asm (const char *asm_stmts)
848 tree asm_str = build_string (asm_stmts);
849 symtab->finalize_toplevel_asm (asm_str);
852 /* Construct a playback::rvalue instance (wrapping a tree) for a
853 unary op. */
855 playback::rvalue *
856 playback::context::
857 new_unary_op (location *loc,
858 enum gcc_jit_unary_op op,
859 type *result_type,
860 rvalue *a)
862 // FIXME: type-checking, or coercion?
863 enum tree_code inner_op;
865 gcc_assert (result_type);
866 gcc_assert (a);
868 tree node = a->as_tree ();
869 tree inner_result = NULL;
871 switch (op)
873 default:
874 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
875 return NULL;
877 case GCC_JIT_UNARY_OP_MINUS:
878 inner_op = NEGATE_EXPR;
879 break;
881 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
882 inner_op = BIT_NOT_EXPR;
883 break;
885 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
886 node = as_truth_value (node, loc);
887 inner_result = invert_truthvalue (node);
888 if (loc)
889 set_tree_location (inner_result, loc);
890 return new rvalue (this, inner_result);
892 case GCC_JIT_UNARY_OP_ABS:
893 inner_op = ABS_EXPR;
894 break;
897 inner_result = build1 (inner_op,
898 result_type->as_tree (),
899 node);
900 if (loc)
901 set_tree_location (inner_result, loc);
903 return new rvalue (this, inner_result);
906 /* Construct a playback::rvalue instance (wrapping a tree) for a
907 binary op. */
909 playback::rvalue *
910 playback::context::
911 new_binary_op (location *loc,
912 enum gcc_jit_binary_op op,
913 type *result_type,
914 rvalue *a, rvalue *b)
916 // FIXME: type-checking, or coercion?
917 enum tree_code inner_op;
919 gcc_assert (result_type);
920 gcc_assert (a);
921 gcc_assert (b);
923 tree node_a = a->as_tree ();
924 tree node_b = b->as_tree ();
926 switch (op)
928 default:
929 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
930 return NULL;
932 case GCC_JIT_BINARY_OP_PLUS:
933 inner_op = PLUS_EXPR;
934 break;
936 case GCC_JIT_BINARY_OP_MINUS:
937 inner_op = MINUS_EXPR;
938 break;
940 case GCC_JIT_BINARY_OP_MULT:
941 inner_op = MULT_EXPR;
942 break;
944 case GCC_JIT_BINARY_OP_DIVIDE:
945 if (FLOAT_TYPE_P (result_type->as_tree ()))
946 /* Floating-point division: */
947 inner_op = RDIV_EXPR;
948 else
949 /* Truncating to zero: */
950 inner_op = TRUNC_DIV_EXPR;
951 break;
953 case GCC_JIT_BINARY_OP_MODULO:
954 inner_op = TRUNC_MOD_EXPR;
955 break;
957 case GCC_JIT_BINARY_OP_BITWISE_AND:
958 inner_op = BIT_AND_EXPR;
959 break;
961 case GCC_JIT_BINARY_OP_BITWISE_XOR:
962 inner_op = BIT_XOR_EXPR;
963 break;
965 case GCC_JIT_BINARY_OP_BITWISE_OR:
966 inner_op = BIT_IOR_EXPR;
967 break;
969 case GCC_JIT_BINARY_OP_LOGICAL_AND:
970 node_a = as_truth_value (node_a, loc);
971 node_b = as_truth_value (node_b, loc);
972 inner_op = TRUTH_ANDIF_EXPR;
973 break;
975 case GCC_JIT_BINARY_OP_LOGICAL_OR:
976 node_a = as_truth_value (node_a, loc);
977 node_b = as_truth_value (node_b, loc);
978 inner_op = TRUTH_ORIF_EXPR;
979 break;
981 case GCC_JIT_BINARY_OP_LSHIFT:
982 inner_op = LSHIFT_EXPR;
983 break;
985 case GCC_JIT_BINARY_OP_RSHIFT:
986 inner_op = RSHIFT_EXPR;
987 break;
990 tree inner_expr = build2 (inner_op,
991 result_type->as_tree (),
992 node_a,
993 node_b);
994 if (loc)
995 set_tree_location (inner_expr, loc);
997 return new rvalue (this, inner_expr);
1000 /* Construct a playback::rvalue instance (wrapping a tree) for a
1001 comparison. */
1003 playback::rvalue *
1004 playback::context::
1005 new_comparison (location *loc,
1006 enum gcc_jit_comparison op,
1007 rvalue *a, rvalue *b)
1009 // FIXME: type-checking, or coercion?
1010 enum tree_code inner_op;
1012 gcc_assert (a);
1013 gcc_assert (b);
1015 switch (op)
1017 default:
1018 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
1019 return NULL;
1021 case GCC_JIT_COMPARISON_EQ:
1022 inner_op = EQ_EXPR;
1023 break;
1024 case GCC_JIT_COMPARISON_NE:
1025 inner_op = NE_EXPR;
1026 break;
1027 case GCC_JIT_COMPARISON_LT:
1028 inner_op = LT_EXPR;
1029 break;
1030 case GCC_JIT_COMPARISON_LE:
1031 inner_op = LE_EXPR;
1032 break;
1033 case GCC_JIT_COMPARISON_GT:
1034 inner_op = GT_EXPR;
1035 break;
1036 case GCC_JIT_COMPARISON_GE:
1037 inner_op = GE_EXPR;
1038 break;
1041 tree inner_expr = build2 (inner_op,
1042 boolean_type_node,
1043 a->as_tree (),
1044 b->as_tree ());
1045 if (loc)
1046 set_tree_location (inner_expr, loc);
1047 return new rvalue (this, inner_expr);
1050 /* Construct a playback::rvalue instance (wrapping a tree) for a
1051 function call. */
1053 playback::rvalue *
1054 playback::context::
1055 build_call (location *loc,
1056 tree fn_ptr,
1057 const auto_vec<rvalue *> *args,
1058 bool require_tail_call)
1060 vec<tree, va_gc> *tree_args;
1061 vec_alloc (tree_args, args->length ());
1062 for (unsigned i = 0; i < args->length (); i++)
1063 tree_args->quick_push ((*args)[i]->as_tree ());
1065 if (loc)
1066 set_tree_location (fn_ptr, loc);
1068 tree fn = TREE_TYPE (fn_ptr);
1069 tree fn_type = TREE_TYPE (fn);
1070 tree return_type = TREE_TYPE (fn_type);
1072 tree call = build_call_vec (return_type,
1073 fn_ptr, tree_args);
1075 if (require_tail_call)
1076 CALL_EXPR_MUST_TAIL_CALL (call) = 1;
1078 return new rvalue (this, call);
1080 /* see c-typeck.c: build_function_call
1081 which calls build_function_call_vec
1083 which does lots of checking, then:
1084 result = build_call_array_loc (loc, TREE_TYPE (fntype),
1085 function, nargs, argarray);
1086 which is in tree.c
1087 (see also build_call_vec)
1091 /* Construct a playback::rvalue instance (wrapping a tree) for a
1092 call to a specific function. */
1094 playback::rvalue *
1095 playback::context::
1096 new_call (location *loc,
1097 function *func,
1098 const auto_vec<rvalue *> *args,
1099 bool require_tail_call)
1101 tree fndecl;
1103 gcc_assert (func);
1105 fndecl = func->as_fndecl ();
1107 tree fntype = TREE_TYPE (fndecl);
1109 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
1111 return build_call (loc, fn, args, require_tail_call);
1114 /* Construct a playback::rvalue instance (wrapping a tree) for a
1115 call through a function pointer. */
1117 playback::rvalue *
1118 playback::context::
1119 new_call_through_ptr (location *loc,
1120 rvalue *fn_ptr,
1121 const auto_vec<rvalue *> *args,
1122 bool require_tail_call)
1124 gcc_assert (fn_ptr);
1125 tree t_fn_ptr = fn_ptr->as_tree ();
1127 return build_call (loc, t_fn_ptr, args, require_tail_call);
1130 /* Construct a tree for a cast. */
1132 tree
1133 playback::context::build_cast (playback::location *loc,
1134 playback::rvalue *expr,
1135 playback::type *type_)
1137 /* For comparison, see:
1138 - c/c-typeck.c:build_c_cast
1139 - c/c-convert.c: convert
1140 - convert.h
1142 Only some kinds of cast are currently supported here. */
1143 tree t_expr = expr->as_tree ();
1144 tree t_dst_type = type_->as_tree ();
1145 tree t_ret = NULL;
1146 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
1147 if (t_ret)
1148 return t_ret;
1149 enum tree_code dst_code = TREE_CODE (t_dst_type);
1150 switch (dst_code)
1152 case INTEGER_TYPE:
1153 case ENUMERAL_TYPE:
1154 t_ret = convert_to_integer (t_dst_type, t_expr);
1155 goto maybe_fold;
1157 case BOOLEAN_TYPE:
1158 /* Compare with c_objc_common_truthvalue_conversion and
1159 c_common_truthvalue_conversion. */
1160 /* For now, convert to: (t_expr != 0) */
1161 t_ret = build2 (NE_EXPR, t_dst_type,
1162 t_expr,
1163 build_int_cst (TREE_TYPE (t_expr), 0));
1164 goto maybe_fold;
1166 case REAL_TYPE:
1167 t_ret = convert_to_real (t_dst_type, t_expr);
1168 goto maybe_fold;
1170 case POINTER_TYPE:
1171 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
1172 goto maybe_fold;
1174 default:
1175 add_error (loc, "couldn't handle cast during playback");
1176 fprintf (stderr, "input expression:\n");
1177 debug_tree (t_expr);
1178 fprintf (stderr, "requested type:\n");
1179 debug_tree (t_dst_type);
1180 return error_mark_node;
1182 maybe_fold:
1183 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
1184 t_ret = fold (t_ret);
1185 return t_ret;
1189 /* Construct a playback::rvalue instance (wrapping a tree) for a
1190 cast. */
1192 playback::rvalue *
1193 playback::context::
1194 new_cast (playback::location *loc,
1195 playback::rvalue *expr,
1196 playback::type *type_)
1199 tree t_cast = build_cast (loc, expr, type_);
1200 if (loc)
1201 set_tree_location (t_cast, loc);
1202 return new rvalue (this, t_cast);
1205 /* Construct a playback::lvalue instance (wrapping a tree) for an
1206 array access. */
1208 playback::lvalue *
1209 playback::context::
1210 new_array_access (location *loc,
1211 rvalue *ptr,
1212 rvalue *index)
1214 gcc_assert (ptr);
1215 gcc_assert (index);
1217 /* For comparison, see:
1218 c/c-typeck.c: build_array_ref
1219 c-family/c-common.c: pointer_int_sum
1221 tree t_ptr = ptr->as_tree ();
1222 tree t_index = index->as_tree ();
1223 tree t_type_ptr = TREE_TYPE (t_ptr);
1224 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1226 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1228 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1229 NULL_TREE, NULL_TREE);
1230 if (loc)
1231 set_tree_location (t_result, loc);
1232 return new lvalue (this, t_result);
1234 else
1236 /* Convert index to an offset in bytes. */
1237 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1238 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1239 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
1241 /* Locate (ptr + offset). */
1242 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1244 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1245 if (loc)
1247 set_tree_location (t_sizeof, loc);
1248 set_tree_location (t_offset, loc);
1249 set_tree_location (t_address, loc);
1250 set_tree_location (t_indirection, loc);
1253 return new lvalue (this, t_indirection);
1257 /* Construct a tree for a field access. */
1259 tree
1260 playback::context::
1261 new_field_access (location *loc,
1262 tree datum,
1263 field *field)
1265 gcc_assert (datum);
1266 gcc_assert (field);
1268 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1269 build_component_ref. */
1270 tree type = TREE_TYPE (datum);
1271 gcc_assert (type);
1272 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1274 tree t_field = field->as_tree ();
1275 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1276 t_field, NULL_TREE);
1277 if (loc)
1278 set_tree_location (ref, loc);
1279 return ref;
1282 /* Construct a tree for a dereference. */
1284 tree
1285 playback::context::
1286 new_dereference (tree ptr,
1287 location *loc)
1289 gcc_assert (ptr);
1291 tree type = TREE_TYPE (TREE_TYPE(ptr));
1292 tree datum = build1 (INDIRECT_REF, type, ptr);
1293 if (loc)
1294 set_tree_location (datum, loc);
1295 return datum;
1298 /* Construct a playback::type instance (wrapping a tree)
1299 with the given alignment. */
1301 playback::type *
1302 playback::type::
1303 get_aligned (size_t alignment_in_bytes) const
1305 tree t_new_type = build_variant_type_copy (m_inner);
1307 SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT);
1308 TYPE_USER_ALIGN (t_new_type) = 1;
1310 return new type (t_new_type);
1313 /* Construct a playback::type instance (wrapping a tree)
1314 for the given vector type. */
1316 playback::type *
1317 playback::type::
1318 get_vector (size_t num_units) const
1320 tree t_new_type = build_vector_type (m_inner, num_units);
1321 return new type (t_new_type);
1324 /* Construct a playback::lvalue instance (wrapping a tree) for a
1325 field access. */
1327 playback::lvalue *
1328 playback::lvalue::
1329 access_field (location *loc,
1330 field *field)
1332 tree datum = as_tree ();
1333 tree ref = get_context ()->new_field_access (loc, datum, field);
1334 if (!ref)
1335 return NULL;
1336 return new lvalue (get_context (), ref);
1339 /* Construct a playback::rvalue instance (wrapping a tree) for a
1340 field access. */
1342 playback::rvalue *
1343 playback::rvalue::
1344 access_field (location *loc,
1345 field *field)
1347 tree datum = as_tree ();
1348 tree ref = get_context ()->new_field_access (loc, datum, field);
1349 if (!ref)
1350 return NULL;
1351 return new rvalue (get_context (), ref);
1354 /* Construct a playback::lvalue instance (wrapping a tree) for a
1355 dereferenced field access. */
1357 playback::lvalue *
1358 playback::rvalue::
1359 dereference_field (location *loc,
1360 field *field)
1362 tree ptr = as_tree ();
1363 tree datum = get_context ()->new_dereference (ptr, loc);
1364 if (!datum)
1365 return NULL;
1366 tree ref = get_context ()->new_field_access (loc, datum, field);
1367 if (!ref)
1368 return NULL;
1369 return new lvalue (get_context (), ref);
1372 /* Construct a playback::lvalue instance (wrapping a tree) for a
1373 dereference. */
1375 playback::lvalue *
1376 playback::rvalue::
1377 dereference (location *loc)
1379 tree ptr = as_tree ();
1380 tree datum = get_context ()->new_dereference (ptr, loc);
1381 return new lvalue (get_context (), datum);
1384 /* Mark the lvalue saying that we need to be able to take the
1385 address of it; it should not be allocated in a register.
1386 Compare with e.g. c/c-typeck.c: c_mark_addressable really_atomic_lvalue.
1387 Returns false if a failure occurred (an error will already have been
1388 added to the active context for this case). */
1390 bool
1391 playback::lvalue::
1392 mark_addressable (location *loc)
1394 tree x = as_tree ();;
1396 while (1)
1397 switch (TREE_CODE (x))
1399 case COMPONENT_REF:
1400 if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x, 1)))
1402 gcc_assert (gcc::jit::active_playback_ctxt);
1403 gcc::jit::
1404 active_playback_ctxt->add_error (loc,
1405 "cannot take address of "
1406 "bit-field");
1407 return false;
1409 /* fallthrough */
1410 case ADDR_EXPR:
1411 case ARRAY_REF:
1412 case REALPART_EXPR:
1413 case IMAGPART_EXPR:
1414 x = TREE_OPERAND (x, 0);
1415 break;
1417 case COMPOUND_LITERAL_EXPR:
1418 case CONSTRUCTOR:
1419 TREE_ADDRESSABLE (x) = 1;
1420 return true;
1422 case VAR_DECL:
1423 case CONST_DECL:
1424 case PARM_DECL:
1425 case RESULT_DECL:
1426 /* (we don't have a concept of a "register" declaration) */
1427 /* fallthrough */
1428 case FUNCTION_DECL:
1429 TREE_ADDRESSABLE (x) = 1;
1430 /* fallthrough */
1431 default:
1432 return true;
1436 /* Construct a playback::rvalue instance (wrapping a tree) for an
1437 address-lookup. */
1439 playback::rvalue *
1440 playback::lvalue::
1441 get_address (location *loc)
1443 tree t_lvalue = as_tree ();
1444 tree t_thistype = TREE_TYPE (t_lvalue);
1445 tree t_ptrtype = build_pointer_type (t_thistype);
1446 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1447 if (loc)
1448 get_context ()->set_tree_location (ptr, loc);
1449 if (mark_addressable (loc))
1450 return new rvalue (get_context (), ptr);
1451 else
1452 return NULL;
1455 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1456 Provide this finalization hook for calling then they are collected,
1457 which calls the finalizer vfunc. This allows them to call "release"
1458 on any vec<> within them. */
1460 static void
1461 wrapper_finalizer (void *ptr)
1463 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1464 wrapper->finalizer ();
1467 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1468 allocate them using ggc_internal_cleared_alloc. */
1470 void *
1471 playback::wrapper::
1472 operator new (size_t sz)
1474 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1478 /* Constructor for gcc:jit::playback::function. */
1480 playback::function::
1481 function (context *ctxt,
1482 tree fndecl,
1483 enum gcc_jit_function_kind kind)
1484 : m_ctxt(ctxt),
1485 m_inner_fndecl (fndecl),
1486 m_inner_bind_expr (NULL),
1487 m_kind (kind)
1489 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1491 /* Create a BIND_EXPR, and within it, a statement list. */
1492 m_stmt_list = alloc_stmt_list ();
1493 m_stmt_iter = tsi_start (m_stmt_list);
1494 m_inner_block = make_node (BLOCK);
1495 m_inner_bind_expr =
1496 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1498 else
1500 m_inner_block = NULL;
1501 m_stmt_list = NULL;
1505 /* Hand-written GC-marking hook for playback functions. */
1507 void
1508 playback::function::
1509 gt_ggc_mx ()
1511 gt_ggc_m_9tree_node (m_inner_fndecl);
1512 gt_ggc_m_9tree_node (m_inner_bind_expr);
1513 gt_ggc_m_9tree_node (m_stmt_list);
1514 gt_ggc_m_9tree_node (m_inner_block);
1517 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1518 GC-ed. */
1520 void
1521 playback::function::finalizer ()
1523 m_blocks.release ();
1526 /* Get the return type of a playback function, in tree form. */
1528 tree
1529 playback::function::
1530 get_return_type_as_tree () const
1532 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1535 /* Construct a new local within this playback::function. */
1537 playback::lvalue *
1538 playback::function::
1539 new_local (location *loc,
1540 type *type,
1541 const char *name)
1543 gcc_assert (type);
1544 gcc_assert (name);
1545 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1546 get_identifier (name),
1547 type->as_tree ());
1548 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1550 /* Prepend to BIND_EXPR_VARS: */
1551 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1552 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1554 if (loc)
1555 set_tree_location (inner, loc);
1556 return new lvalue (m_ctxt, inner);
1559 /* Construct a new block within this playback::function. */
1561 playback::block *
1562 playback::function::
1563 new_block (const char *name)
1565 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1567 block *result = new playback::block (this, name);
1568 m_blocks.safe_push (result);
1569 return result;
1572 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1573 this playback::function. */
1575 playback::rvalue *
1576 playback::function::get_address (location *loc)
1578 tree t_fndecl = as_fndecl ();
1579 tree t_fntype = TREE_TYPE (t_fndecl);
1580 tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
1581 if (loc)
1582 m_ctxt->set_tree_location (t_fnptr, loc);
1583 return new rvalue (m_ctxt, t_fnptr);
1586 /* Build a statement list for the function as a whole out of the
1587 lists of statements for the individual blocks, building labels
1588 for each block. */
1590 void
1591 playback::function::
1592 build_stmt_list ()
1594 int i;
1595 block *b;
1597 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1599 FOR_EACH_VEC_ELT (m_blocks, i, b)
1601 int j;
1602 tree stmt;
1604 b->m_label_expr = build1 (LABEL_EXPR,
1605 void_type_node,
1606 b->as_label_decl ());
1607 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1609 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1610 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1614 /* Finish compiling the given function, potentially running the
1615 garbage-collector.
1616 The function will have a statement list by now.
1617 Amongst other things, this gimplifies the statement list,
1618 and calls cgraph_node::finalize_function on the function. */
1620 void
1621 playback::function::
1622 postprocess ()
1624 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1626 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1627 debug_tree (m_stmt_list);
1629 /* Do we need this to force cgraphunit.c to output the function? */
1630 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1632 DECL_EXTERNAL (m_inner_fndecl) = 0;
1633 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1636 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1637 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1639 DECL_EXTERNAL (m_inner_fndecl) = 0;
1640 TREE_PUBLIC (m_inner_fndecl) = 0;
1643 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1645 /* Seem to need this in gimple-low.c: */
1646 gcc_assert (m_inner_block);
1647 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1649 /* how to add to function? the following appears to be how to
1650 set the body of a m_inner_fndecl: */
1651 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1653 /* Ensure that locals appear in the debuginfo. */
1654 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1656 //debug_tree (m_inner_fndecl);
1658 /* Convert to gimple: */
1659 //printf("about to gimplify_function_tree\n");
1660 gimplify_function_tree (m_inner_fndecl);
1661 //printf("finished gimplify_function_tree\n");
1663 current_function_decl = m_inner_fndecl;
1664 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1665 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1666 //debug_tree (m_inner_fndecl);
1668 //printf("about to add to cgraph\n");
1669 /* Add to cgraph: */
1670 cgraph_node::finalize_function (m_inner_fndecl, false);
1671 /* This can trigger a collection, so we need to have all of
1672 the funcs as roots. */
1674 current_function_decl = NULL;
1678 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1679 GC-ed. */
1681 void
1682 playback::block::finalizer ()
1684 m_stmts.release ();
1687 /* Add an eval of the rvalue to the function's statement list. */
1689 void
1690 playback::block::
1691 add_eval (location *loc,
1692 rvalue *rvalue)
1694 gcc_assert (rvalue);
1696 if (loc)
1697 set_tree_location (rvalue->as_tree (), loc);
1699 add_stmt (rvalue->as_tree ());
1702 /* Add an assignment to the function's statement list. */
1704 void
1705 playback::block::
1706 add_assignment (location *loc,
1707 lvalue *lvalue,
1708 rvalue *rvalue)
1710 gcc_assert (lvalue);
1711 gcc_assert (rvalue);
1713 tree t_lvalue = lvalue->as_tree ();
1714 tree t_rvalue = rvalue->as_tree ();
1715 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1717 t_rvalue = build1 (CONVERT_EXPR,
1718 TREE_TYPE (t_lvalue),
1719 t_rvalue);
1720 if (loc)
1721 set_tree_location (t_rvalue, loc);
1724 tree stmt =
1725 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1726 t_lvalue, t_rvalue);
1727 if (loc)
1728 set_tree_location (stmt, loc);
1729 add_stmt (stmt);
1732 /* Add a comment to the function's statement list.
1733 For now this is done by adding a dummy label. */
1735 void
1736 playback::block::
1737 add_comment (location *loc,
1738 const char *text)
1740 /* Wrap the text in C-style comment delimiters. */
1741 size_t sz =
1742 (3 /* opening delim */
1743 + strlen (text)
1744 + 3 /* closing delim */
1745 + 1 /* terminator */);
1746 char *wrapped = (char *)ggc_internal_alloc (sz);
1747 snprintf (wrapped, sz, "/* %s */", text);
1749 /* For now we simply implement this by adding a dummy label with a name
1750 containing the given text. */
1751 tree identifier = get_identifier (wrapped);
1752 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1753 identifier, void_type_node);
1754 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1756 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1757 if (loc)
1758 set_tree_location (label_expr, loc);
1759 add_stmt (label_expr);
1762 /* Add a conditional jump statement to the function's statement list. */
1764 void
1765 playback::block::
1766 add_conditional (location *loc,
1767 rvalue *boolval,
1768 block *on_true,
1769 block *on_false)
1771 gcc_assert (boolval);
1772 gcc_assert (on_true);
1773 gcc_assert (on_false);
1775 /* COND_EXPR wants statement lists for the true/false operands, but we
1776 want labels.
1777 Shim it by creating jumps to the labels */
1778 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1779 on_true->as_label_decl ());
1780 if (loc)
1781 set_tree_location (true_jump, loc);
1783 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1784 on_false->as_label_decl ());
1785 if (loc)
1786 set_tree_location (false_jump, loc);
1788 tree stmt =
1789 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1790 true_jump, false_jump);
1791 if (loc)
1792 set_tree_location (stmt, loc);
1793 add_stmt (stmt);
1796 /* Add an unconditional jump statement to the function's statement list. */
1798 void
1799 playback::block::
1800 add_jump (location *loc,
1801 block *target)
1803 gcc_assert (target);
1805 // see c_finish_loop
1806 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1807 //add_stmt (top);
1809 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1810 TREE_USED (target->as_label_decl ()) = 1;
1811 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1812 if (loc)
1813 set_tree_location (stmt, loc);
1814 add_stmt (stmt);
1817 from c-typeck.c:
1818 tree
1819 c_finish_goto_label (location_t loc, tree label)
1821 tree decl = lookup_label_for_goto (loc, label);
1822 if (!decl)
1823 return NULL_TREE;
1824 TREE_USED (decl) = 1;
1826 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1827 SET_EXPR_LOCATION (t, loc);
1828 return add_stmt (t);
1835 /* Add a return statement to the function's statement list. */
1837 void
1838 playback::block::
1839 add_return (location *loc,
1840 rvalue *rvalue)
1842 tree modify_retval = NULL;
1843 tree return_type = m_func->get_return_type_as_tree ();
1844 if (rvalue)
1846 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1847 tree t_rvalue = rvalue->as_tree ();
1848 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1849 t_rvalue = build1 (CONVERT_EXPR,
1850 TREE_TYPE (t_lvalue),
1851 t_rvalue);
1852 modify_retval = build2 (MODIFY_EXPR, return_type,
1853 t_lvalue, t_rvalue);
1854 if (loc)
1855 set_tree_location (modify_retval, loc);
1857 tree return_stmt = build1 (RETURN_EXPR, return_type,
1858 modify_retval);
1859 if (loc)
1860 set_tree_location (return_stmt, loc);
1862 add_stmt (return_stmt);
1865 /* Helper function for playback::block::add_switch.
1866 Construct a case label for the given range, followed by a goto stmt
1867 to the given block, appending them to stmt list *ptr_t_switch_body. */
1869 static void
1870 add_case (tree *ptr_t_switch_body,
1871 tree t_low_value,
1872 tree t_high_value,
1873 playback::block *dest_block)
1875 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
1876 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
1878 tree t_case_label =
1879 build_case_label (t_low_value, t_high_value, t_label);
1880 append_to_statement_list (t_case_label, ptr_t_switch_body);
1882 tree t_goto_stmt =
1883 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
1884 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
1887 /* Add a switch statement to the function's statement list.
1889 We create a switch body, and populate it with case labels, each
1890 followed by a goto to the desired block. */
1892 void
1893 playback::block::
1894 add_switch (location *loc,
1895 rvalue *expr,
1896 block *default_block,
1897 const auto_vec <case_> *cases)
1899 /* Compare with:
1900 - c/c-typeck.c: c_start_case
1901 - c-family/c-common.c:c_add_case_label
1902 - java/expr.c:expand_java_switch and expand_java_add_case
1903 We've already rejected overlaps and duplicates in
1904 libgccjit.c:case_range_validator::validate. */
1906 tree t_expr = expr->as_tree ();
1907 tree t_type = TREE_TYPE (t_expr);
1909 tree t_switch_body = alloc_stmt_list ();
1911 int i;
1912 case_ *c;
1913 FOR_EACH_VEC_ELT (*cases, i, c)
1915 tree t_low_value = c->m_min_value->as_tree ();
1916 tree t_high_value = c->m_max_value->as_tree ();
1917 add_case (&t_switch_body, t_low_value, t_high_value, c->m_dest_block);
1919 /* Default label. */
1920 add_case (&t_switch_body, NULL_TREE, NULL_TREE, default_block);
1922 tree switch_stmt = build2 (SWITCH_EXPR, t_type, t_expr, t_switch_body);
1923 if (loc)
1924 set_tree_location (switch_stmt, loc);
1925 add_stmt (switch_stmt);
1928 /* Convert OPERANDS to a tree-based chain suitable for creating an
1929 extended asm stmt.
1930 Compare with c_parser_asm_operands. */
1932 static tree
1933 build_operand_chain (const auto_vec <playback::asm_operand> *operands)
1935 tree result = NULL_TREE;
1936 unsigned i;
1937 playback::asm_operand *asm_op;
1938 FOR_EACH_VEC_ELT (*operands, i, asm_op)
1940 tree name = build_string (asm_op->m_asm_symbolic_name);
1941 tree str = build_string (asm_op->m_constraint);
1942 tree value = asm_op->m_expr;
1943 result = chainon (result,
1944 build_tree_list (build_tree_list (name, str),
1945 value));
1947 return result;
1950 /* Convert CLOBBERS to a tree-based list suitable for creating an
1951 extended asm stmt.
1952 Compare with c_parser_asm_clobbers. */
1954 static tree
1955 build_clobbers (const auto_vec <const char *> *clobbers)
1957 tree list = NULL_TREE;
1958 unsigned i;
1959 const char *clobber;
1960 FOR_EACH_VEC_ELT (*clobbers, i, clobber)
1962 tree str = build_string (clobber);
1963 list = tree_cons (NULL_TREE, str, list);
1965 return list;
1968 /* Convert BLOCKS to a tree-based list suitable for creating an
1969 extended asm stmt.
1970 Compare with c_parser_asm_goto_operands. */
1972 static tree
1973 build_goto_operands (const auto_vec <playback::block *> *blocks)
1975 tree list = NULL_TREE;
1976 unsigned i;
1977 playback::block *b;
1978 FOR_EACH_VEC_ELT (*blocks, i, b)
1980 tree label = b->as_label_decl ();
1981 tree name = build_string (IDENTIFIER_POINTER (DECL_NAME (label)));
1982 TREE_USED (label) = 1;
1983 list = tree_cons (name, label, list);
1985 return nreverse (list);
1988 /* Add an extended asm statement to this block.
1990 Compare with c_parser_asm_statement (in c/c-parser.c)
1991 and build_asm_expr (in c/c-typeck.c). */
1993 void
1994 playback::block::add_extended_asm (location *loc,
1995 const char *asm_template,
1996 bool is_volatile,
1997 bool is_inline,
1998 const auto_vec <asm_operand> *outputs,
1999 const auto_vec <asm_operand> *inputs,
2000 const auto_vec <const char *> *clobbers,
2001 const auto_vec <block *> *goto_blocks)
2003 tree t_string = build_string (asm_template);
2004 tree t_outputs = build_operand_chain (outputs);
2005 tree t_inputs = build_operand_chain (inputs);
2006 tree t_clobbers = build_clobbers (clobbers);
2007 tree t_labels = build_goto_operands (goto_blocks);
2008 t_string
2009 = resolve_asm_operand_names (t_string, t_outputs, t_inputs, t_labels);
2010 tree asm_stmt
2011 = build5 (ASM_EXPR, void_type_node,
2012 t_string, t_outputs, t_inputs, t_clobbers, t_labels);
2014 /* asm statements without outputs, including simple ones, are treated
2015 as volatile. */
2016 ASM_VOLATILE_P (asm_stmt) = (outputs->length () == 0);
2017 ASM_INPUT_P (asm_stmt) = 0; /* extended asm stmts are not "simple". */
2018 ASM_INLINE_P (asm_stmt) = is_inline;
2019 if (is_volatile)
2020 ASM_VOLATILE_P (asm_stmt) = 1;
2021 if (loc)
2022 set_tree_location (asm_stmt, loc);
2023 add_stmt (asm_stmt);
2026 /* Constructor for gcc::jit::playback::block. */
2028 playback::block::
2029 block (function *func,
2030 const char *name)
2031 : m_func (func),
2032 m_stmts ()
2034 tree identifier;
2036 gcc_assert (func);
2037 // name can be NULL
2038 if (name)
2039 identifier = get_identifier (name);
2040 else
2041 identifier = NULL;
2042 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
2043 identifier, void_type_node);
2044 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
2045 m_label_expr = NULL;
2048 /* Compile a playback::context:
2050 - Use the context's options to cconstruct command-line options, and
2051 call into the rest of GCC (toplev::main).
2052 - Assuming it succeeds, we have a .s file.
2053 - We then run the "postprocess" vfunc:
2055 (A) In-memory compile ("gcc_jit_context_compile")
2057 For an in-memory compile we have the playback::compile_to_memory
2058 subclass; "postprocess" will convert the .s file to a .so DSO,
2059 and load it in memory (via dlopen), wrapping the result up as
2060 a jit::result and returning it.
2062 (B) Compile to file ("gcc_jit_context_compile_to_file")
2064 When compiling to a file, we have the playback::compile_to_file
2065 subclass; "postprocess" will either copy the .s file to the
2066 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
2067 the driver to convert it as necessary, copying the result. */
2069 void
2070 playback::context::
2071 compile ()
2073 JIT_LOG_SCOPE (get_logger ());
2075 const char *ctxt_progname;
2077 int keep_intermediates =
2078 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
2080 m_tempdir = new tempdir (get_logger (), keep_intermediates);
2081 if (!m_tempdir->create ())
2082 return;
2084 /* Call into the rest of gcc.
2085 For now, we have to assemble command-line options to pass into
2086 toplev::main, so that they can be parsed. */
2088 /* Pass in user-provided program name as argv0, if any, so that it
2089 makes it into GCC's "progname" global, used in various diagnostics. */
2090 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
2092 if (!ctxt_progname)
2093 ctxt_progname = "libgccjit.so";
2095 auto_vec <recording::requested_dump> requested_dumps;
2096 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
2098 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
2099 acquire_mutex ();
2101 auto_string_vec fake_args;
2102 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
2103 if (errors_occurred ())
2105 release_mutex ();
2106 return;
2109 /* This runs the compiler. */
2110 toplev toplev (get_timer (), /* external_timer */
2111 false); /* init_signals */
2112 enter_scope ("toplev::main");
2113 if (get_logger ())
2114 for (unsigned i = 0; i < fake_args.length (); i++)
2115 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
2116 toplev.main (fake_args.length (),
2117 const_cast <char **> (fake_args.address ()));
2118 exit_scope ("toplev::main");
2120 /* Extracting dumps makes use of the gcc::dump_manager, hence we
2121 need to do it between toplev::main (which creates the dump manager)
2122 and toplev::finalize (which deletes it). */
2123 extract_any_requested_dumps (&requested_dumps);
2125 /* Clean up the compiler. */
2126 enter_scope ("toplev::finalize");
2127 toplev.finalize ();
2128 exit_scope ("toplev::finalize");
2130 /* Ideally we would release the jit mutex here, but we can't yet since
2131 followup activities use timevars, which are global state. */
2133 if (errors_occurred ())
2135 release_mutex ();
2136 return;
2139 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
2140 dump_generated_code ();
2142 /* We now have a .s file.
2144 Run any postprocessing steps. This will either convert the .s file to
2145 a .so DSO, and load it in memory (playback::compile_to_memory), or
2146 convert the .s file to the requested output format, and copy it to a
2147 given file (playback::compile_to_file). */
2148 postprocess (ctxt_progname);
2150 release_mutex ();
2153 /* Implementation of class gcc::jit::playback::compile_to_memory,
2154 a subclass of gcc::jit::playback::context. */
2156 /* playback::compile_to_memory's trivial constructor. */
2158 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
2159 playback::context (ctxt),
2160 m_result (NULL)
2162 JIT_LOG_SCOPE (get_logger ());
2165 /* Implementation of the playback::context::process vfunc for compiling
2166 to memory.
2168 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
2169 wrapping the result up as a jit::result and returning it. */
2171 void
2172 playback::compile_to_memory::postprocess (const char *ctxt_progname)
2174 JIT_LOG_SCOPE (get_logger ());
2175 convert_to_dso (ctxt_progname);
2176 if (errors_occurred ())
2177 return;
2178 m_result = dlopen_built_dso ();
2181 /* Implementation of class gcc::jit::playback::compile_to_file,
2182 a subclass of gcc::jit::playback::context. */
2184 /* playback::compile_to_file's trivial constructor. */
2186 playback::compile_to_file::compile_to_file (recording::context *ctxt,
2187 enum gcc_jit_output_kind output_kind,
2188 const char *output_path) :
2189 playback::context (ctxt),
2190 m_output_kind (output_kind),
2191 m_output_path (output_path)
2193 JIT_LOG_SCOPE (get_logger ());
2196 /* Implementation of the playback::context::process vfunc for compiling
2197 to a file.
2199 Either copy the .s file to the given destination (for
2200 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
2201 as necessary, copying the result. */
2203 void
2204 playback::compile_to_file::postprocess (const char *ctxt_progname)
2206 JIT_LOG_SCOPE (get_logger ());
2208 /* The driver takes different actions based on the filename, so
2209 we provide a filename with an appropriate suffix for the
2210 output kind, and then copy it up to the user-provided path,
2211 rather than directly compiling it to the requested output path. */
2213 switch (m_output_kind)
2215 default:
2216 gcc_unreachable ();
2218 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
2219 copy_file (get_tempdir ()->get_path_s_file (),
2220 m_output_path);
2221 /* The .s file is automatically unlinked by tempdir::~tempdir. */
2222 break;
2224 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
2226 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
2227 "/fake.o",
2228 NULL);
2229 invoke_driver (ctxt_progname,
2230 get_tempdir ()->get_path_s_file (),
2231 tmp_o_path,
2232 TV_ASSEMBLE,
2233 false, /* bool shared, */
2234 false);/* bool run_linker */
2235 if (!errors_occurred ())
2237 copy_file (tmp_o_path,
2238 m_output_path);
2239 get_tempdir ()->add_temp_file (tmp_o_path);
2241 else
2242 free (tmp_o_path);
2244 break;
2246 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
2247 invoke_driver (ctxt_progname,
2248 get_tempdir ()->get_path_s_file (),
2249 get_tempdir ()->get_path_so_file (),
2250 TV_ASSEMBLE,
2251 true, /* bool shared, */
2252 true);/* bool run_linker */
2253 if (!errors_occurred ())
2254 copy_file (get_tempdir ()->get_path_so_file (),
2255 m_output_path);
2256 /* The .so file is automatically unlinked by tempdir::~tempdir. */
2257 break;
2259 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
2261 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
2262 "/fake.exe",
2263 NULL);
2264 invoke_driver (ctxt_progname,
2265 get_tempdir ()->get_path_s_file (),
2266 tmp_exe_path,
2267 TV_ASSEMBLE,
2268 false, /* bool shared, */
2269 true);/* bool run_linker */
2270 if (!errors_occurred ())
2272 copy_file (tmp_exe_path,
2273 m_output_path);
2274 get_tempdir ()->add_temp_file (tmp_exe_path);
2276 else
2277 free (tmp_exe_path);
2279 break;
2285 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2286 the "executable" bits).
2288 Any errors that occur are reported on the context and hence count as
2289 a failure of the compile.
2291 We can't in general hardlink or use "rename" from the tempdir since
2292 it might be on a different filesystem to the destination. For example,
2293 I get EXDEV: "Invalid cross-device link". */
2295 void
2296 playback::compile_to_file::copy_file (const char *src_path,
2297 const char *dst_path)
2299 JIT_LOG_SCOPE (get_logger ());
2300 if (get_logger ())
2302 get_logger ()->log ("src_path: %s", src_path);
2303 get_logger ()->log ("dst_path: %s", dst_path);
2306 FILE *f_in = NULL;
2307 FILE *f_out = NULL;
2308 size_t total_sz_in = 0;
2309 size_t total_sz_out = 0;
2310 char buf[4096];
2311 size_t sz_in;
2312 struct stat stat_buf;
2314 f_in = fopen (src_path, "rb");
2315 if (!f_in)
2317 add_error (NULL,
2318 "unable to open %s for reading: %s",
2319 src_path,
2320 xstrerror (errno));
2321 return;
2324 /* Use stat on the filedescriptor to get the mode,
2325 so that we can copy it over (in particular, the
2326 "executable" bits). */
2327 if (fstat (fileno (f_in), &stat_buf) == -1)
2329 add_error (NULL,
2330 "unable to fstat %s: %s",
2331 src_path,
2332 xstrerror (errno));
2333 fclose (f_in);
2334 return;
2337 f_out = fopen (dst_path, "wb");
2338 if (!f_out)
2340 add_error (NULL,
2341 "unable to open %s for writing: %s",
2342 dst_path,
2343 xstrerror (errno));
2344 fclose (f_in);
2345 return;
2348 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2350 total_sz_in += sz_in;
2351 size_t sz_out_remaining = sz_in;
2352 size_t sz_out_so_far = 0;
2353 while (sz_out_remaining)
2355 size_t sz_out = fwrite (buf + sz_out_so_far,
2357 sz_out_remaining,
2358 f_out);
2359 gcc_assert (sz_out <= sz_out_remaining);
2360 if (!sz_out)
2362 add_error (NULL,
2363 "error writing to %s: %s",
2364 dst_path,
2365 xstrerror (errno));
2366 fclose (f_in);
2367 fclose (f_out);
2368 return;
2370 total_sz_out += sz_out;
2371 sz_out_so_far += sz_out;
2372 sz_out_remaining -= sz_out;
2374 gcc_assert (sz_out_so_far == sz_in);
2377 if (!feof (f_in))
2378 add_error (NULL,
2379 "error reading from %s: %s",
2380 src_path,
2381 xstrerror (errno));
2383 fclose (f_in);
2385 gcc_assert (total_sz_in == total_sz_out);
2386 if (get_logger ())
2387 get_logger ()->log ("total bytes copied: %zu", total_sz_out);
2389 /* fchmod does not exist in Windows. */
2390 #ifndef _WIN32
2391 /* Set the permissions of the copy to those of the original file,
2392 in particular the "executable" bits. */
2393 if (fchmod (fileno (f_out), stat_buf.st_mode) == -1)
2394 add_error (NULL,
2395 "error setting mode of %s: %s",
2396 dst_path,
2397 xstrerror (errno));
2398 #endif
2400 fclose (f_out);
2403 /* Helper functions for gcc::jit::playback::context::compile. */
2405 /* This mutex guards gcc::jit::recording::context::compile, so that only
2406 one thread can be accessing the bulk of GCC's state at once. */
2408 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2410 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2412 void
2413 playback::context::acquire_mutex ()
2415 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2417 /* Acquire the big GCC mutex. */
2418 JIT_LOG_SCOPE (get_logger ());
2419 pthread_mutex_lock (&jit_mutex);
2420 gcc_assert (active_playback_ctxt == NULL);
2421 active_playback_ctxt = this;
2424 /* Release jit_mutex and clear the active playback ctxt. */
2426 void
2427 playback::context::release_mutex ()
2429 /* Release the big GCC mutex. */
2430 JIT_LOG_SCOPE (get_logger ());
2431 gcc_assert (active_playback_ctxt == this);
2432 active_playback_ctxt = NULL;
2433 pthread_mutex_unlock (&jit_mutex);
2436 /* Callback used by gcc::jit::playback::context::make_fake_args when
2437 invoking driver_get_configure_time_options.
2438 Populate a vec <char * > with the configure-time options. */
2440 static void
2441 append_arg_from_driver (const char *option, void *user_data)
2443 gcc_assert (option);
2444 gcc_assert (user_data);
2445 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2446 argvec->safe_push (concat ("-", option, NULL));
2449 /* Build a fake argv for toplev::main from the options set
2450 by the user on the context . */
2452 void
2453 playback::context::
2454 make_fake_args (vec <char *> *argvec,
2455 const char *ctxt_progname,
2456 vec <recording::requested_dump> *requested_dumps)
2458 JIT_LOG_SCOPE (get_logger ());
2460 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2461 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2463 ADD_ARG (ctxt_progname);
2464 ADD_ARG (get_path_c_file ());
2465 ADD_ARG ("-fPIC");
2467 /* Handle int options: */
2468 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2470 default:
2471 add_error (NULL,
2472 "unrecognized optimization level: %i",
2473 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2474 return;
2476 case 0:
2477 ADD_ARG ("-O0");
2478 break;
2480 case 1:
2481 ADD_ARG ("-O1");
2482 break;
2484 case 2:
2485 ADD_ARG ("-O2");
2486 break;
2488 case 3:
2489 ADD_ARG ("-O3");
2490 break;
2492 /* What about -Os? */
2494 /* Handle bool options: */
2495 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2496 ADD_ARG ("-g");
2498 /* Suppress timing (and other) info. */
2499 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2501 ADD_ARG ("-quiet");
2502 quiet_flag = 1;
2505 /* Aggressively garbage-collect, to shake out bugs: */
2506 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2508 ADD_ARG ("--param=ggc-min-expand=0");
2509 ADD_ARG ("--param=ggc-min-heapsize=0");
2512 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2514 ADD_ARG ("-fdump-tree-all");
2515 ADD_ARG ("-fdump-rtl-all");
2516 ADD_ARG ("-fdump-ipa-all");
2519 /* Add "-fdump-" options for any calls to
2520 gcc_jit_context_enable_dump. */
2522 int i;
2523 recording::requested_dump *d;
2524 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2526 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2527 ADD_ARG_TAKE_OWNERSHIP (arg);
2531 /* PR jit/64810: Add any target-specific default options
2532 from OPTION_DEFAULT_SPECS, normally provided by the driver
2533 in the non-jit case.
2535 The target-specific code can define OPTION_DEFAULT_SPECS:
2536 default command options in the form of spec macros for the
2537 driver to expand ().
2539 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2540 if not overriden, injects the defaults as extra arguments to
2541 cc1 etc.
2542 For the jit case, we need to add these arguments here. The
2543 input format (using the specs language) means that we have to run
2544 part of the driver code here (driver_get_configure_time_options).
2546 To avoid running the spec-expansion code every time, we just do
2547 it the first time (via a function-static flag), saving the result
2548 into a function-static vec.
2549 This flag and vec are global state (i.e. per-process).
2550 They are guarded by the jit mutex. */
2552 static bool have_configure_time_options = false;
2553 static vec <char *> configure_time_options;
2555 if (have_configure_time_options)
2556 log ("reusing cached configure-time options");
2557 else
2559 have_configure_time_options = true;
2560 log ("getting configure-time options from driver");
2561 driver_get_configure_time_options (append_arg_from_driver,
2562 &configure_time_options);
2565 int i;
2566 char *opt;
2568 if (get_logger ())
2569 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2570 log ("configure_time_options[%i]: %s", i, opt);
2572 /* configure_time_options should now contain the expanded options
2573 from OPTION_DEFAULT_SPECS (if any). */
2574 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2576 gcc_assert (opt);
2577 gcc_assert (opt[0] == '-');
2578 ADD_ARG (opt);
2582 if (get_timer ())
2583 ADD_ARG ("-ftime-report");
2585 /* Add any user-provided extra options, starting with any from
2586 parent contexts. */
2587 m_recording_ctxt->append_command_line_options (argvec);
2589 #undef ADD_ARG
2590 #undef ADD_ARG_TAKE_OWNERSHIP
2593 /* The second half of the implementation of gcc_jit_context_enable_dump.
2594 Iterate through the requested dumps, reading the underlying files
2595 into heap-allocated buffers, writing pointers to the buffers into
2596 the char ** pointers provided by client code.
2597 Client code is responsible for calling free on the results. */
2599 void
2600 playback::context::
2601 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2603 JIT_LOG_SCOPE (get_logger ());
2605 int i;
2606 recording::requested_dump *d;
2607 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2609 dump_file_info *dfi;
2610 char *filename;
2611 char *content;
2613 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2614 if (!dfi)
2616 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2617 continue;
2620 filename = g->get_dumps ()->get_dump_file_name (dfi);
2621 content = read_dump_file (filename);
2622 *(d->m_out_ptr) = content;
2623 m_tempdir->add_temp_file (filename);
2627 /* Helper function for playback::context::extract_any_requested_dumps
2628 (itself for use in implementation of gcc_jit_context_enable_dump).
2630 Attempt to read the complete file at the given path, returning the
2631 bytes found there as a buffer.
2632 The caller is responsible for calling free on the result.
2633 Errors will be reported on the context, and lead to NULL being
2634 returned; an out-of-memory error will terminate the process. */
2636 char *
2637 playback::context::read_dump_file (const char *path)
2639 char *result = NULL;
2640 size_t total_sz = 0;
2641 char buf[4096];
2642 size_t sz;
2643 FILE *f_in;
2645 f_in = fopen (path, "r");
2646 if (!f_in)
2648 add_error (NULL, "unable to open %s for reading", path);
2649 return NULL;
2652 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2654 size_t old_total_sz = total_sz;
2655 total_sz += sz;
2656 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2657 memcpy (result + old_total_sz, buf, sz);
2660 if (!feof (f_in))
2662 add_error (NULL, "error reading from %s", path);
2663 free (result);
2664 fclose (f_in);
2665 return NULL;
2668 fclose (f_in);
2670 if (result)
2672 result[total_sz] = '\0';
2673 return result;
2675 else
2676 return xstrdup ("");
2679 /* Part of playback::context::compile ().
2681 We have a .s file; we want a .so file.
2682 We could reuse parts of gcc/gcc.c to do this.
2683 For now, just use the driver binary from the install, as
2684 named in gcc-driver-name.h
2685 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2687 void
2688 playback::context::
2689 convert_to_dso (const char *ctxt_progname)
2691 JIT_LOG_SCOPE (get_logger ());
2693 invoke_driver (ctxt_progname,
2694 m_tempdir->get_path_s_file (),
2695 m_tempdir->get_path_so_file (),
2696 TV_ASSEMBLE,
2697 true, /* bool shared, */
2698 true);/* bool run_linker */
2701 static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2703 void
2704 playback::context::
2705 invoke_driver (const char *ctxt_progname,
2706 const char *input_file,
2707 const char *output_file,
2708 timevar_id_t tv_id,
2709 bool shared,
2710 bool run_linker)
2712 JIT_LOG_SCOPE (get_logger ());
2714 bool embedded_driver
2715 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
2717 /* Currently this lumps together both assembling and linking into
2718 TV_ASSEMBLE. */
2719 auto_timevar assemble_timevar (get_timer (), tv_id);
2720 auto_string_vec argvec;
2721 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2723 ADD_ARG (gcc_driver_name);
2725 add_multilib_driver_arguments (&argvec);
2727 if (shared)
2728 ADD_ARG ("-shared");
2730 if (!run_linker)
2731 ADD_ARG ("-c");
2733 ADD_ARG (input_file);
2734 ADD_ARG ("-o");
2735 ADD_ARG (output_file);
2737 /* Don't use the linker plugin.
2738 If running with just a "make" and not a "make install", then we'd
2739 run into
2740 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2741 libto_plugin is a .la at build time, with it becoming installed with
2742 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2743 time. */
2744 ADD_ARG ("-fno-use-linker-plugin");
2746 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2747 /* OS X's linker defaults to treating undefined symbols as errors.
2748 If the context has any imported functions or globals they will be
2749 undefined until the .so is dynamically-linked into the process.
2750 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2751 linker. */
2752 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2753 #endif
2755 if (0)
2756 ADD_ARG ("-v");
2758 /* Add any user-provided driver extra options. */
2760 m_recording_ctxt->append_driver_options (&argvec);
2762 #undef ADD_ARG
2764 /* pex_one's error-handling requires pname to be non-NULL. */
2765 gcc_assert (ctxt_progname);
2767 if (get_logger ())
2768 for (unsigned i = 0; i < argvec.length (); i++)
2769 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2771 if (embedded_driver)
2772 invoke_embedded_driver (&argvec);
2773 else
2774 invoke_external_driver (ctxt_progname, &argvec);
2777 void
2778 playback::context::
2779 invoke_embedded_driver (const vec <char *> *argvec)
2781 JIT_LOG_SCOPE (get_logger ());
2782 driver d (true, /* can_finalize */
2783 false); /* debug */
2784 int result = d.main (argvec->length (),
2785 const_cast <char **> (argvec->address ()));
2786 d.finalize ();
2787 if (result)
2788 add_error (NULL, "error invoking gcc driver");
2791 void
2792 playback::context::
2793 invoke_external_driver (const char *ctxt_progname,
2794 vec <char *> *argvec)
2796 JIT_LOG_SCOPE (get_logger ());
2797 const char *errmsg;
2798 int exit_status = 0;
2799 int err = 0;
2801 /* pex argv arrays are NULL-terminated. */
2802 argvec->safe_push (NULL);
2804 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2805 gcc_driver_name,
2806 const_cast <char *const *> (argvec->address ()),
2807 ctxt_progname, /* const char *pname */
2808 NULL, /* const char *outname */
2809 NULL, /* const char *errname */
2810 &exit_status, /* int *status */
2811 &err); /* int *err*/
2812 if (errmsg)
2814 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2815 return;
2818 /* pex_one can return a NULL errmsg when the executable wasn't
2819 found (or doesn't exist), so trap these cases also. */
2820 if (exit_status || err)
2822 add_error (NULL,
2823 "error invoking gcc driver: exit_status: %i err: %i",
2824 exit_status, err);
2825 add_error (NULL,
2826 "whilst attempting to run a driver named: %s",
2827 gcc_driver_name);
2828 add_error (NULL,
2829 "PATH was: %s",
2830 getenv ("PATH"));
2831 return;
2835 /* Extract the target-specific MULTILIB_DEFAULTS to
2836 multilib_defaults_raw for use by
2837 playback::context::add_multilib_driver_arguments (). */
2839 #ifndef MULTILIB_DEFAULTS
2840 #define MULTILIB_DEFAULTS { "" }
2841 #endif
2843 static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
2845 /* Helper function for playback::context::invoke_driver ().
2847 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2848 a driver binary. We need to pass in options to the shared driver
2849 to get the appropriate assembler/linker options for this multilib
2850 peer. */
2852 void
2853 playback::context::
2854 add_multilib_driver_arguments (vec <char *> *argvec)
2856 JIT_LOG_SCOPE (get_logger ());
2858 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2859 prepending each with a "-". */
2860 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
2861 if (multilib_defaults_raw[i][0])
2862 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
2865 /* Dynamically-link the built DSO file into this process, using dlopen.
2866 Wrap it up within a jit::result *, and return that.
2867 Return NULL if any errors occur, reporting them on this context. */
2869 result *
2870 playback::context::
2871 dlopen_built_dso ()
2873 JIT_LOG_SCOPE (get_logger ());
2874 auto_timevar load_timevar (get_timer (), TV_LOAD);
2875 result::handle handle = NULL;
2876 result *result_obj = NULL;
2878 #ifdef _WIN32
2879 /* Clear any existing error. */
2880 SetLastError(0);
2882 handle = LoadLibrary(m_tempdir->get_path_so_file ());
2883 if (GetLastError() != 0) {
2884 print_last_error();
2886 #else
2887 const char *error = NULL;
2888 /* Clear any existing error. */
2889 dlerror ();
2891 handle = dlopen (m_tempdir->get_path_so_file (),
2892 RTLD_NOW | RTLD_LOCAL);
2893 if ((error = dlerror()) != NULL) {
2894 add_error (NULL, "%s", error);
2896 #endif
2898 if (handle)
2900 /* We've successfully dlopened the result; create a
2901 jit::result object to wrap it.
2903 We're done with the tempdir for now, but if the user
2904 has requested debugging, the user's debugger might not
2905 be capable of dealing with the .so file being unlinked
2906 immediately, so keep it around until after the result
2907 is released. We do this by handing over ownership of
2908 the jit::tempdir to the result. See PR jit/64206. */
2909 tempdir *handover_tempdir;
2910 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2912 handover_tempdir = m_tempdir;
2913 m_tempdir = NULL;
2914 /* The tempdir will eventually be cleaned up in the
2915 jit::result's dtor. */
2916 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2917 " handing over tempdir to jit::result");
2919 else
2921 handover_tempdir = NULL;
2922 /* ... and retain ownership of m_tempdir so we clean it
2923 up it the playback::context's dtor. */
2924 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2925 " retaining ownership of tempdir");
2928 result_obj = new result (get_logger (), handle, handover_tempdir);
2930 else
2931 result_obj = NULL;
2933 return result_obj;
2936 /* Top-level hook for playing back a recording context.
2938 This plays back m_recording_ctxt, and, if no errors
2939 occurred builds statement lists for and then postprocesses
2940 every function in the result. */
2942 void
2943 playback::context::
2944 replay ()
2946 JIT_LOG_SCOPE (get_logger ());
2948 init_types ();
2950 /* Replay the recorded events: */
2951 timevar_push (TV_JIT_REPLAY);
2953 /* Ensure that builtins that could be needed during optimization
2954 get created ahead of time. */
2955 builtins_manager *bm = m_recording_ctxt->get_builtins_manager ();
2956 bm->ensure_optimization_builtins_exist ();
2958 m_recording_ctxt->replay_into (this);
2960 /* Clean away the temporary references from recording objects
2961 to playback objects. We have to do this now since the
2962 latter are GC-allocated, but the former don't mark these
2963 refs. Hence we must stop using them before the GC can run. */
2964 m_recording_ctxt->disassociate_from_playback ();
2966 /* The builtins_manager is associated with the recording::context
2967 and might be reused for future compiles on other playback::contexts,
2968 but its m_attributes array is not GTY-labeled and hence will become
2969 nonsense if the GC runs. Purge this state. */
2970 bm->finish_playback ();
2972 timevar_pop (TV_JIT_REPLAY);
2974 if (!errors_occurred ())
2976 int i;
2977 function *func;
2978 tree global;
2979 /* No GC can happen yet; process the cached source locations. */
2980 handle_locations ();
2982 /* Finalize globals. See how FORTRAN 95 does it in gfc_be_parse_file()
2983 for a simple reference. */
2984 FOR_EACH_VEC_ELT (m_globals, i, global)
2985 rest_of_decl_compilation (global, true, true);
2987 wrapup_global_declarations (m_globals.address(), m_globals.length());
2989 /* We've now created tree nodes for the stmts in the various blocks
2990 in each function, but we haven't built each function's single stmt
2991 list yet. Do so now. */
2992 FOR_EACH_VEC_ELT (m_functions, i, func)
2993 func->build_stmt_list ();
2995 /* No GC can have happened yet. */
2997 /* Postprocess the functions. This could trigger GC. */
2998 FOR_EACH_VEC_ELT (m_functions, i, func)
3000 gcc_assert (func);
3001 func->postprocess ();
3006 /* Dump the generated .s file to stderr. */
3008 void
3009 playback::context::
3010 dump_generated_code ()
3012 JIT_LOG_SCOPE (get_logger ());
3013 char buf[4096];
3014 size_t sz;
3015 FILE *f_in = fopen (get_path_s_file (), "r");
3016 if (!f_in)
3017 return;
3019 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
3020 fwrite (buf, 1, sz, stderr);
3022 fclose (f_in);
3025 /* Get the supposed path of the notional "fake.c" file within the
3026 tempdir. This file doesn't exist, but the rest of the compiler
3027 needs a name. */
3029 const char *
3030 playback::context::
3031 get_path_c_file () const
3033 return m_tempdir->get_path_c_file ();
3036 /* Get the path of the assembler output file "fake.s" file within the
3037 tempdir. */
3039 const char *
3040 playback::context::
3041 get_path_s_file () const
3043 return m_tempdir->get_path_s_file ();
3046 /* Get the path of the DSO object file "fake.so" file within the
3047 tempdir. */
3049 const char *
3050 playback::context::
3051 get_path_so_file () const
3053 return m_tempdir->get_path_so_file ();
3056 /* qsort comparator for comparing pairs of playback::source_line *,
3057 ordering them by line number. */
3059 static int
3060 line_comparator (const void *lhs, const void *rhs)
3062 const playback::source_line *line_lhs = \
3063 *static_cast<const playback::source_line * const*> (lhs);
3064 const playback::source_line *line_rhs = \
3065 *static_cast<const playback::source_line * const*> (rhs);
3066 return line_lhs->get_line_num () - line_rhs->get_line_num ();
3069 /* qsort comparator for comparing pairs of playback::location *,
3070 ordering them by column number. */
3072 static int
3073 location_comparator (const void *lhs, const void *rhs)
3075 const playback::location *loc_lhs = \
3076 *static_cast<const playback::location * const *> (lhs);
3077 const playback::location *loc_rhs = \
3078 *static_cast<const playback::location * const *> (rhs);
3079 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
3082 /* Initialize the NAME_TYPE of the primitive types as well as some
3083 others. */
3084 void
3085 playback::context::
3086 init_types ()
3088 /* See lto_init() in lto-lang.c or void visit (TypeBasic *t) in D's types.cc
3089 for reference. If TYPE_NAME is not set, debug info will not contain types */
3090 #define NAME_TYPE(t,n) \
3091 if (t) \
3092 TYPE_NAME (t) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, \
3093 get_identifier (n), t)
3095 NAME_TYPE (integer_type_node, "int");
3096 NAME_TYPE (char_type_node, "char");
3097 NAME_TYPE (long_integer_type_node, "long int");
3098 NAME_TYPE (unsigned_type_node, "unsigned int");
3099 NAME_TYPE (long_unsigned_type_node, "long unsigned int");
3100 NAME_TYPE (long_long_integer_type_node, "long long int");
3101 NAME_TYPE (long_long_unsigned_type_node, "long long unsigned int");
3102 NAME_TYPE (short_integer_type_node, "short int");
3103 NAME_TYPE (short_unsigned_type_node, "short unsigned int");
3104 if (signed_char_type_node != char_type_node)
3105 NAME_TYPE (signed_char_type_node, "signed char");
3106 if (unsigned_char_type_node != char_type_node)
3107 NAME_TYPE (unsigned_char_type_node, "unsigned char");
3108 NAME_TYPE (float_type_node, "float");
3109 NAME_TYPE (double_type_node, "double");
3110 NAME_TYPE (long_double_type_node, "long double");
3111 NAME_TYPE (void_type_node, "void");
3112 NAME_TYPE (boolean_type_node, "bool");
3113 NAME_TYPE (complex_float_type_node, "complex float");
3114 NAME_TYPE (complex_double_type_node, "complex double");
3115 NAME_TYPE (complex_long_double_type_node, "complex long double");
3117 m_const_char_ptr = build_pointer_type(
3118 build_qualified_type (char_type_node, TYPE_QUAL_CONST));
3120 NAME_TYPE (m_const_char_ptr, "char");
3121 NAME_TYPE (size_type_node, "size_t");
3122 NAME_TYPE (fileptr_type_node, "FILE");
3123 #undef NAME_TYPE
3126 /* Our API allows locations to be created in arbitrary orders, but the
3127 linemap API requires locations to be created in ascending order
3128 as if we were tokenizing files.
3130 This hook sorts all of the locations that have been created, and
3131 calls into the linemap API, creating linemap entries in sorted order
3132 for our locations. */
3134 void
3135 playback::context::
3136 handle_locations ()
3138 /* Create the source code locations, following the ordering rules
3139 imposed by the linemap API.
3141 line_table is a global. */
3142 JIT_LOG_SCOPE (get_logger ());
3143 int i;
3144 source_file *file;
3146 FOR_EACH_VEC_ELT (m_source_files, i, file)
3148 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
3150 /* Sort lines by ascending line numbers. */
3151 file->m_source_lines.qsort (&line_comparator);
3153 int j;
3154 source_line *line;
3155 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
3157 int k;
3158 location *loc;
3160 /* Sort locations in line by ascending column numbers. */
3161 line->m_locations.qsort (&location_comparator);
3163 /* Determine maximum column within this line. */
3164 gcc_assert (line->m_locations.length () > 0);
3165 location *final_column =
3166 line->m_locations[line->m_locations.length () - 1];
3167 int max_col = final_column->get_column_num ();
3169 linemap_line_start (line_table, line->get_line_num (), max_col);
3170 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
3172 loc->m_srcloc = \
3173 linemap_position_for_column (line_table, loc->get_column_num ());
3177 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
3180 /* line_table should now be populated; every playback::location should
3181 now have an m_srcloc. */
3183 /* Now assign them to tree nodes as appropriate. */
3184 std::pair<tree, location *> *cached_location;
3186 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
3188 tree t = cached_location->first;
3189 location_t srcloc = cached_location->second->m_srcloc;
3191 /* This covers expressions: */
3192 if (CAN_HAVE_LOCATION_P (t))
3193 SET_EXPR_LOCATION (t, srcloc);
3194 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
3195 DECL_SOURCE_LOCATION (t) = srcloc;
3196 else
3198 /* Don't know how to set location on this node. */
3203 /* We handle errors on a playback::context by adding them to the
3204 corresponding recording::context. */
3206 void
3207 playback::context::
3208 add_error (location *loc, const char *fmt, ...)
3210 va_list ap;
3211 va_start (ap, fmt);
3212 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
3213 fmt, ap);
3214 va_end (ap);
3217 /* We handle errors on a playback::context by adding them to the
3218 corresponding recording::context. */
3220 void
3221 playback::context::
3222 add_error_va (location *loc, const char *fmt, va_list ap)
3224 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
3225 fmt, ap);
3228 /* Report a diagnostic up to the jit context as an error,
3229 so that the compilation is treated as a failure.
3230 For now, any kind of diagnostic is treated as an error by the jit
3231 API. */
3233 void
3234 playback::context::
3235 add_diagnostic (struct diagnostic_context *diag_context,
3236 struct diagnostic_info *diagnostic)
3238 /* At this point the text has been formatted into the pretty-printer's
3239 output buffer. */
3240 pretty_printer *pp = diag_context->printer;
3241 const char *text = pp_formatted_text (pp);
3243 /* Get location information (if any) from the diagnostic.
3244 The recording::context::add_error[_va] methods require a
3245 recording::location. We can't lookup the playback::location
3246 from the file/line/column since any playback location instances
3247 may have been garbage-collected away by now, so instead we create
3248 another recording::location directly. */
3249 location_t gcc_loc = diagnostic_location (diagnostic);
3250 recording::location *rec_loc = NULL;
3251 if (gcc_loc)
3253 expanded_location exploc = expand_location (gcc_loc);
3254 if (exploc.file)
3255 rec_loc = m_recording_ctxt->new_location (exploc.file,
3256 exploc.line,
3257 exploc.column,
3258 false);
3261 m_recording_ctxt->add_error (rec_loc, "%s", text);
3262 pp_clear_output_area (pp);
3265 /* Dealing with the linemap API. */
3267 /* Construct a playback::location for a recording::location, if it
3268 doesn't exist already. */
3270 playback::location *
3271 playback::context::
3272 new_location (recording::location *rloc,
3273 const char *filename,
3274 int line,
3275 int column)
3277 /* Get the source_file for filename, creating if necessary. */
3278 source_file *src_file = get_source_file (filename);
3279 /* Likewise for the line within the file. */
3280 source_line *src_line = src_file->get_source_line (line);
3281 /* Likewise for the column within the line. */
3282 location *loc = src_line->get_location (rloc, column);
3283 return loc;
3286 /* Deferred setting of the location for a given tree, by adding the
3287 (tree, playback::location) pair to a list of deferred associations.
3288 We will actually set the location on the tree later on once
3289 the location_t for the playback::location exists. */
3291 void
3292 playback::context::
3293 set_tree_location (tree t, location *loc)
3295 gcc_assert (loc);
3296 m_cached_locations.safe_push (std::make_pair (t, loc));
3300 /* Construct a playback::source_file for the given source
3301 filename, if it doesn't exist already. */
3303 playback::source_file *
3304 playback::context::
3305 get_source_file (const char *filename)
3307 /* Locate the file.
3308 For simplicitly, this is currently a linear search.
3309 Replace with a hash if this shows up in the profile. */
3310 int i;
3311 source_file *file;
3312 tree ident_filename = get_identifier (filename);
3314 FOR_EACH_VEC_ELT (m_source_files, i, file)
3315 if (file->filename_as_tree () == ident_filename)
3316 return file;
3318 /* Not found. */
3319 file = new source_file (ident_filename);
3320 m_source_files.safe_push (file);
3321 return file;
3324 /* Constructor for gcc::jit::playback::source_file. */
3326 playback::source_file::source_file (tree filename) :
3327 m_source_lines (),
3328 m_filename (filename)
3332 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3333 GC-ed. */
3335 void
3336 playback::source_file::finalizer ()
3338 m_source_lines.release ();
3341 /* Construct a playback::source_line for the given line
3342 within this source file, if one doesn't exist already. */
3344 playback::source_line *
3345 playback::source_file::
3346 get_source_line (int line_num)
3348 /* Locate the line.
3349 For simplicitly, this is currently a linear search.
3350 Replace with a hash if this shows up in the profile. */
3351 int i;
3352 source_line *line;
3354 FOR_EACH_VEC_ELT (m_source_lines, i, line)
3355 if (line->get_line_num () == line_num)
3356 return line;
3358 /* Not found. */
3359 line = new source_line (this, line_num);
3360 m_source_lines.safe_push (line);
3361 return line;
3364 /* Constructor for gcc::jit::playback::source_line. */
3366 playback::source_line::source_line (source_file *file, int line_num) :
3367 m_locations (),
3368 m_source_file (file),
3369 m_line_num (line_num)
3373 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3374 GC-ed. */
3376 void
3377 playback::source_line::finalizer ()
3379 m_locations.release ();
3382 /* Construct a playback::location for the given column
3383 within this line of a specific source file, if one doesn't exist
3384 already. */
3386 playback::location *
3387 playback::source_line::
3388 get_location (recording::location *rloc, int column_num)
3390 int i;
3391 location *loc;
3393 /* Another linear search that probably should be a hash table. */
3394 FOR_EACH_VEC_ELT (m_locations, i, loc)
3395 if (loc->get_column_num () == column_num)
3396 return loc;
3398 /* Not found. */
3399 loc = new location (rloc, this, column_num);
3400 m_locations.safe_push (loc);
3401 return loc;
3404 /* Constructor for gcc::jit::playback::location. */
3406 playback::location::location (recording::location *loc,
3407 source_line *line,
3408 int column_num) :
3409 m_srcloc (UNKNOWN_LOCATION),
3410 m_recording_loc (loc),
3411 m_line (line),
3412 m_column_num(column_num)
3416 /* The active gcc::jit::playback::context instance. This is a singleton,
3417 guarded by jit_mutex. */
3419 playback::context *active_playback_ctxt;
3421 } // namespace gcc::jit
3423 } // namespace gcc