xfail scan-tree-dump-not throw in g++.dg/pr99966.C on hppa*64*-*-*
[official-gcc.git] / gcc / jit / jit-playback.cc
blob84df6c100e6d22234e708f454d87d541c31fb7c1
1 /* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2024 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 #define INCLUDE_MUTEX
23 #include "libgccjit.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "target.h"
27 #include "tree.h"
28 #include "stringpool.h"
29 #include "cgraph.h"
30 #include "dumpfile.h"
31 #include "toplev.h"
32 #include "tree-cfg.h"
33 #include "convert.h"
34 #include "stor-layout.h"
35 #include "print-tree.h"
36 #include "gimplify.h"
37 #include "gcc-driver-name.h"
38 #include "attribs.h"
39 #include "context.h"
40 #include "fold-const.h"
41 #include "opt-suggestions.h"
42 #include "gcc.h"
43 #include "diagnostic.h"
44 #include "stmt.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 /* Fold a readonly non-volatile variable with an initial constant value,
101 to that value.
103 Otherwise return the argument unchanged.
105 This fold is needed for setting a variable's DECL_INITIAL to the value
106 of a const variable. The c-frontend does this in its own special
107 fold (), so we lift this part out and do it explicitly where there is a
108 potential for variables to be used as rvalues. */
109 static tree
110 fold_const_var (tree node)
112 /* See c_fully_fold_internal in c-fold.cc and decl_constant_value_1
113 in c-typeck.cc. */
114 if (VAR_P (node)
115 && TREE_READONLY (node)
116 && !TREE_THIS_VOLATILE (node)
117 && DECL_INITIAL (node) != NULL_TREE
118 /* "This is invalid if initial value is not constant.
119 If it has either a function call, a memory reference,
120 or a variable, then re-evaluating it could give different
121 results." */
122 && TREE_CONSTANT (DECL_INITIAL (node)))
124 tree ret = DECL_INITIAL (node);
125 /* "Avoid unwanted tree sharing between the initializer and current
126 function's body where the tree can be modified e.g. by the
127 gimplifier." */
128 if (TREE_STATIC (node))
129 ret = unshare_expr (ret);
131 return ret;
134 return node;
137 /* Build a STRING_CST tree for STR, or return NULL if it is NULL.
138 The TREE_TYPE is not initialized. */
140 static tree
141 build_string (const char *str)
143 if (str)
144 return ::build_string (strlen (str), str);
145 else
146 return NULL_TREE;
149 /* The constructor for gcc::jit::playback::context. */
151 playback::context::context (recording::context *ctxt)
152 : log_user (ctxt->get_logger ()),
153 m_recording_ctxt (ctxt),
154 m_tempdir (NULL),
155 m_const_char_ptr (NULL)
157 JIT_LOG_SCOPE (get_logger ());
158 m_functions.create (0);
159 m_globals.create (0);
160 m_source_files.create (0);
161 m_cached_locations.create (0);
164 /* The destructor for gcc::jit::playback::context. */
166 playback::context::~context ()
168 JIT_LOG_SCOPE (get_logger ());
170 /* Normally the playback::context is responsible for cleaning up the
171 tempdir (including "fake.so" within the filesystem).
173 In the normal case, clean it up now.
175 However m_tempdir can be NULL if the context has handed over
176 responsibility for the tempdir cleanup to the jit::result object, so
177 that the cleanup can be delayed (see PR jit/64206). If that's the
178 case this "delete NULL;" is a no-op. */
179 delete m_tempdir;
181 m_functions.release ();
184 /* A playback::context can reference GC-managed pointers. Mark them
185 ("by hand", rather than by gengtype).
187 This is called on the active playback context (if any) by the
188 my_ggc_walker hook in the jit_root_table in dummy-frontend.cc. */
190 void
191 playback::context::
192 gt_ggc_mx ()
194 int i;
195 function *func;
196 FOR_EACH_VEC_ELT (m_functions, i, func)
198 if (ggc_test_and_set_mark (func))
199 func->gt_ggc_mx ();
203 /* Given an enum gcc_jit_types value, get a "tree" type. */
205 tree
206 playback::context::
207 get_tree_node_for_type (enum gcc_jit_types type_)
209 switch (type_)
211 case GCC_JIT_TYPE_VOID:
212 return void_type_node;
214 case GCC_JIT_TYPE_VOID_PTR:
215 return ptr_type_node;
217 case GCC_JIT_TYPE_BOOL:
218 return boolean_type_node;
220 case GCC_JIT_TYPE_CHAR:
221 return char_type_node;
222 case GCC_JIT_TYPE_SIGNED_CHAR:
223 return signed_char_type_node;
224 case GCC_JIT_TYPE_UNSIGNED_CHAR:
225 return unsigned_char_type_node;
227 case GCC_JIT_TYPE_SHORT:
228 return short_integer_type_node;
229 case GCC_JIT_TYPE_UNSIGNED_SHORT:
230 return short_unsigned_type_node;
232 case GCC_JIT_TYPE_CONST_CHAR_PTR:
233 return m_const_char_ptr;
235 case GCC_JIT_TYPE_INT:
236 return integer_type_node;
237 case GCC_JIT_TYPE_UNSIGNED_INT:
238 return unsigned_type_node;
240 case GCC_JIT_TYPE_UINT8_T:
241 return unsigned_intQI_type_node;
242 case GCC_JIT_TYPE_UINT16_T:
243 return uint16_type_node;
244 case GCC_JIT_TYPE_UINT32_T:
245 return uint32_type_node;
246 case GCC_JIT_TYPE_UINT64_T:
247 return uint64_type_node;
248 case GCC_JIT_TYPE_UINT128_T:
249 if (targetm.scalar_mode_supported_p (TImode))
250 return uint128_type_node;
252 add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
253 type_);
254 return NULL;
256 case GCC_JIT_TYPE_INT8_T:
257 return intQI_type_node;
258 case GCC_JIT_TYPE_INT16_T:
259 return intHI_type_node;
260 case GCC_JIT_TYPE_INT32_T:
261 return intSI_type_node;
262 case GCC_JIT_TYPE_INT64_T:
263 return intDI_type_node;
264 case GCC_JIT_TYPE_INT128_T:
265 if (targetm.scalar_mode_supported_p (TImode))
266 return intTI_type_node;
268 add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
269 type_);
270 return NULL;
272 case GCC_JIT_TYPE_LONG:
273 return long_integer_type_node;
274 case GCC_JIT_TYPE_UNSIGNED_LONG:
275 return long_unsigned_type_node;
277 case GCC_JIT_TYPE_LONG_LONG:
278 return long_long_integer_type_node;
279 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
280 return long_long_unsigned_type_node;
282 case GCC_JIT_TYPE_FLOAT:
283 return float_type_node;
284 case GCC_JIT_TYPE_DOUBLE:
285 return double_type_node;
286 case GCC_JIT_TYPE_LONG_DOUBLE:
287 return long_double_type_node;
289 case GCC_JIT_TYPE_SIZE_T:
290 return size_type_node;
292 case GCC_JIT_TYPE_FILE_PTR:
293 return fileptr_type_node;
295 case GCC_JIT_TYPE_COMPLEX_FLOAT:
296 return complex_float_type_node;
297 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
298 return complex_double_type_node;
299 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
300 return complex_long_double_type_node;
303 add_error (NULL, "unrecognized (enum gcc_jit_types) value: %i",
304 type_);
306 return NULL;
309 /* Construct a playback::type instance (wrapping a tree) for the given
310 enum value. */
312 playback::type *
313 playback::context::
314 get_type (enum gcc_jit_types type_)
316 tree type_node = get_tree_node_for_type (type_);
317 if (type_node == NULL)
318 return NULL;
320 return new type (type_node);
323 /* Construct a playback::type instance (wrapping a tree) for the given
324 array type. */
326 playback::type *
327 playback::context::
328 new_array_type (playback::location *loc,
329 playback::type *element_type,
330 int num_elements)
332 gcc_assert (element_type);
334 tree t = build_array_type_nelts (element_type->as_tree (),
335 num_elements);
336 layout_type (t);
338 if (loc)
339 set_tree_location (t, loc);
341 return new type (t);
344 /* Construct a playback::field instance (wrapping a tree). */
346 playback::field *
347 playback::context::
348 new_field (location *loc,
349 type *type,
350 const char *name)
352 gcc_assert (type);
353 gcc_assert (name);
355 /* compare with c/c-decl.cc:grokfield and grokdeclarator. */
356 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
357 get_identifier (name), type->as_tree ());
359 if (loc)
360 set_tree_location (decl, loc);
362 return new field (decl);
365 /* Construct a playback::bitfield instance (wrapping a tree). */
367 playback::field *
368 playback::context::
369 new_bitfield (location *loc,
370 type *type,
371 int width,
372 const char *name)
374 gcc_assert (type);
375 gcc_assert (name);
376 gcc_assert (width);
378 /* compare with c/c-decl.cc:grokfield, grokdeclarator and
379 check_bitfield_type_and_width. */
381 tree tree_type = type->as_tree ();
382 gcc_assert (INTEGRAL_TYPE_P (tree_type));
383 tree tree_width = build_int_cst (integer_type_node, width);
384 if (compare_tree_int (tree_width, TYPE_PRECISION (tree_type)) > 0)
386 add_error (
387 loc,
388 "width of bit-field %s (width: %i) is wider than its type (width: %i)",
389 name, width, TYPE_PRECISION (tree_type));
390 return NULL;
393 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
394 get_identifier (name), type->as_tree ());
395 DECL_NONADDRESSABLE_P (decl) = true;
396 DECL_INITIAL (decl) = tree_width;
397 SET_DECL_JIT_BIT_FIELD (decl);
399 if (loc)
400 set_tree_location (decl, loc);
402 return new field (decl);
405 /* Construct a playback::compound_type instance (wrapping a tree). */
407 playback::compound_type *
408 playback::context::
409 new_compound_type (location *loc,
410 const char *name,
411 bool is_struct) /* else is union */
413 gcc_assert (name);
415 /* Compare with c/c-decl.cc: start_struct. */
417 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
418 TYPE_NAME (t) = get_identifier (name);
419 TYPE_SIZE (t) = 0;
421 if (loc)
422 set_tree_location (t, loc);
424 return new compound_type (t);
427 void
428 playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
430 /* Compare with c/c-decl.cc: finish_struct. */
431 tree t = as_tree ();
433 tree fieldlist = NULL;
434 for (unsigned i = 0; i < fields->length (); i++)
436 field *f = (*fields)[i];
437 tree x = f->as_tree ();
438 DECL_CONTEXT (x) = t;
439 if (DECL_JIT_BIT_FIELD (x))
441 unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (x));
442 DECL_SIZE (x) = bitsize_int (width);
443 DECL_BIT_FIELD (x) = 1;
445 fieldlist = chainon (x, fieldlist);
447 fieldlist = nreverse (fieldlist);
448 TYPE_FIELDS (t) = fieldlist;
450 layout_type (t);
453 /* Construct a playback::type instance (wrapping a tree) for a function
454 type. */
456 playback::type *
457 playback::context::
458 new_function_type (type *return_type,
459 const auto_vec<type *> *param_types,
460 int is_variadic)
462 int i;
463 type *param_type;
465 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
467 FOR_EACH_VEC_ELT (*param_types, i, param_type)
468 arg_types[i] = param_type->as_tree ();
470 tree fn_type;
471 if (is_variadic)
472 fn_type =
473 build_varargs_function_type_array (return_type->as_tree (),
474 param_types->length (),
475 arg_types);
476 else
477 fn_type = build_function_type_array (return_type->as_tree (),
478 param_types->length (),
479 arg_types);
480 free (arg_types);
482 return new type (fn_type);
485 /* Construct a playback::param instance (wrapping a tree). */
487 playback::param *
488 playback::context::
489 new_param (location *loc,
490 type *type,
491 const char *name)
493 gcc_assert (type);
494 gcc_assert (name);
495 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
496 get_identifier (name), type->as_tree ());
497 if (loc)
498 set_tree_location (inner, loc);
500 return new param (this, inner);
503 const char* fn_attribute_to_string (gcc_jit_fn_attribute attr)
505 switch (attr)
507 case GCC_JIT_FN_ATTRIBUTE_ALIAS:
508 return "alias";
509 case GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE:
510 return "always_inline";
511 case GCC_JIT_FN_ATTRIBUTE_INLINE:
512 return NULL;
513 case GCC_JIT_FN_ATTRIBUTE_NOINLINE:
514 return "noinline";
515 case GCC_JIT_FN_ATTRIBUTE_TARGET:
516 return "target";
517 case GCC_JIT_FN_ATTRIBUTE_USED:
518 return "used";
519 case GCC_JIT_FN_ATTRIBUTE_VISIBILITY:
520 return "visibility";
521 case GCC_JIT_FN_ATTRIBUTE_COLD:
522 return "cold";
523 case GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE:
524 return "returns_twice";
525 case GCC_JIT_FN_ATTRIBUTE_PURE:
526 return "pure";
527 case GCC_JIT_FN_ATTRIBUTE_CONST:
528 return "const";
529 case GCC_JIT_FN_ATTRIBUTE_WEAK:
530 return "weak";
531 case GCC_JIT_FN_ATTRIBUTE_NONNULL:
532 return "nonnull";
533 case GCC_JIT_FN_ATTRIBUTE_MAX:
534 return NULL;
536 return NULL;
539 const char* variable_attribute_to_string (gcc_jit_variable_attribute attr)
541 switch (attr)
543 case GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY:
544 return "visibility";
545 case GCC_JIT_VARIABLE_ATTRIBUTE_MAX:
546 return NULL;
548 return NULL;
551 /* Construct a playback::function instance. */
553 playback::function *
554 playback::context::
555 new_function (location *loc,
556 enum gcc_jit_function_kind kind,
557 type *return_type,
558 const char *name,
559 const auto_vec<param *> *params,
560 int is_variadic,
561 enum built_in_function builtin_id,
562 const std::vector<gcc_jit_fn_attribute> &attributes,
563 const std::vector<std::pair<gcc_jit_fn_attribute,
564 std::string>> &string_attributes,
565 const std::vector<std::pair<gcc_jit_fn_attribute,
566 std::vector<int>>>
567 &int_array_attributes)
569 int i;
570 param *param;
572 //can return_type be NULL?
573 gcc_assert (name);
575 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
576 FOR_EACH_VEC_ELT (*params, i, param)
577 arg_types[i] = TREE_TYPE (param->as_tree ());
579 tree fn_type;
580 if (is_variadic)
581 fn_type = build_varargs_function_type_array (return_type->as_tree (),
582 params->length (), arg_types);
583 else
584 fn_type = build_function_type_array (return_type->as_tree (),
585 params->length (), arg_types);
586 free (arg_types);
588 /* FIXME: this uses input_location: */
589 tree fndecl = build_fn_decl (name, fn_type);
591 if (loc)
592 set_tree_location (fndecl, loc);
594 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
595 NULL_TREE, return_type->as_tree ());
596 DECL_ARTIFICIAL (resdecl) = 1;
597 DECL_IGNORED_P (resdecl) = 1;
598 DECL_RESULT (fndecl) = resdecl;
599 DECL_CONTEXT (resdecl) = fndecl;
601 tree fn_attributes = NULL_TREE;
603 if (builtin_id)
605 gcc_assert (loc == NULL);
606 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
608 built_in_class fclass = builtins_manager::get_class (builtin_id);
609 set_decl_built_in_function (fndecl, fclass, builtin_id);
610 set_builtin_decl (builtin_id, fndecl,
611 builtins_manager::implicit_p (builtin_id));
613 builtins_manager *bm = get_builtins_manager ();
614 tree attrs = bm->get_attrs_tree (builtin_id);
615 if (attrs)
616 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
617 else
618 decl_attributes (&fndecl, NULL_TREE, 0);
621 if (kind != GCC_JIT_FUNCTION_IMPORTED)
623 tree param_decl_list = NULL;
624 FOR_EACH_VEC_ELT (*params, i, param)
626 param_decl_list = chainon (param->as_tree (), param_decl_list);
629 /* The param list was created in reverse order; fix it: */
630 param_decl_list = nreverse (param_decl_list);
632 tree t;
633 for (t = param_decl_list; t; t = DECL_CHAIN (t))
635 DECL_CONTEXT (t) = fndecl;
636 DECL_ARG_TYPE (t) = TREE_TYPE (t);
639 /* Set it up on DECL_ARGUMENTS */
640 DECL_ARGUMENTS(fndecl) = param_decl_list;
643 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
645 DECL_DECLARED_INLINE_P (fndecl) = 1;
647 /* Add attribute "always_inline": */
648 fn_attributes = tree_cons (get_identifier ("always_inline"),
649 NULL,
650 fn_attributes);
653 /* All attributes need to be declared in `dummy-frontend.cc` and more
654 specifically in `jit_attribute_table`. */
655 for (auto attr: attributes)
657 if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE)
658 DECL_DECLARED_INLINE_P (fndecl) = 1;
660 const char* attribute = fn_attribute_to_string (attr);
661 if (attribute)
663 tree ident = get_identifier (attribute);
664 fn_attributes = tree_cons (ident, NULL_TREE, fn_attributes);
668 for (auto attr: string_attributes)
670 gcc_jit_fn_attribute& name = std::get<0>(attr);
671 std::string& value = std::get<1>(attr);
672 tree attribute_value = build_tree_list (NULL_TREE,
673 ::build_string (value.length () + 1, value.c_str ()));
674 const char* attribute = fn_attribute_to_string (name);
675 tree ident = attribute ? get_identifier (attribute) : NULL;
677 if (ident)
678 fn_attributes = tree_cons (ident, attribute_value, fn_attributes);
681 for (auto attr: int_array_attributes)
683 gcc_jit_fn_attribute& name = std::get<0>(attr);
684 std::vector<int>& values = std::get<1>(attr);
686 const char* attribute = fn_attribute_to_string (name);
687 tree ident = attribute ? get_identifier (attribute) : NULL;
689 if (!ident)
690 continue;
692 tree tree_list = NULL_TREE;
693 tree *p_tree_list = &tree_list;
694 for (auto value : values)
696 tree int_value = build_int_cst (integer_type_node, value);
697 *p_tree_list = build_tree_list (NULL, int_value);
698 p_tree_list = &TREE_CHAIN (*p_tree_list);
700 fn_attributes = tree_cons (ident, tree_list, fn_attributes);
703 decl_attributes (&fndecl, fn_attributes, 0);
704 function *func = new function (this, fndecl, kind);
705 m_functions.safe_push (func);
706 return func;
709 /* In use by new_global and new_global_initialized. */
711 tree
712 playback::context::
713 global_new_decl (location *loc,
714 enum gcc_jit_global_kind kind,
715 type *type,
716 const char *name,
717 enum global_var_flags flags,
718 const std::vector<std::pair<gcc_jit_variable_attribute,
719 std::string>> &attributes)
721 gcc_assert (type);
722 gcc_assert (name);
724 tree type_tree = type->as_tree ();
726 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
727 get_identifier (name),
728 type_tree);
730 TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
733 int will_be_init = flags & (GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT |
734 GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT);
736 /* A VAR_DECL with DECL_INITIAL will not end up in .common section. */
737 if (!will_be_init)
738 DECL_COMMON (inner) = 1;
740 switch (kind)
742 default:
743 gcc_unreachable ();
745 case GCC_JIT_GLOBAL_EXPORTED:
746 TREE_STATIC (inner) = 1;
747 break;
749 case GCC_JIT_GLOBAL_INTERNAL:
750 TREE_STATIC (inner) = 1;
751 break;
753 case GCC_JIT_GLOBAL_IMPORTED:
754 DECL_EXTERNAL (inner) = 1;
755 break;
758 if (TYPE_READONLY (type_tree))
759 TREE_READONLY (inner) = 1;
761 if (loc)
762 set_tree_location (inner, loc);
764 set_variable_string_attribute (attributes, inner);
766 return inner;
769 void
770 playback::
771 set_variable_string_attribute (
772 const std::vector<std::pair<gcc_jit_variable_attribute,
773 std::string>> &string_attributes,
774 tree decl)
776 tree var_attributes = NULL_TREE;
777 for (auto attr: string_attributes)
779 gcc_jit_variable_attribute& name = std::get<0>(attr);
780 std::string& value = std::get<1>(attr);
781 tree attribute_value = build_tree_list (NULL_TREE,
782 ::build_string (value.length () + 1, value.c_str ()));
783 tree ident = get_identifier (variable_attribute_to_string (name));
784 if (ident)
785 var_attributes = tree_cons (ident, attribute_value, var_attributes);
787 decl_attributes (&decl, var_attributes, 0);
790 /* In use by new_global and new_global_initialized. */
792 playback::lvalue *
793 playback::context::
794 global_finalize_lvalue (tree inner)
796 m_globals.safe_push (inner);
798 return new lvalue (this, inner);
801 /* Construct a playback::lvalue instance (wrapping a tree). */
803 playback::lvalue *
804 playback::context::
805 new_global (location *loc,
806 enum gcc_jit_global_kind kind,
807 type *type,
808 const char *name,
809 enum global_var_flags flags,
810 const std::vector<std::pair<gcc_jit_variable_attribute,
811 std::string>> &attributes)
813 tree inner =
814 global_new_decl (loc, kind, type, name, flags, attributes);
816 return global_finalize_lvalue (inner);
819 void
820 playback::context::
821 global_set_init_rvalue (lvalue* variable,
822 rvalue* init)
824 tree inner = variable->as_tree ();
826 /* We need to fold all expressions as much as possible. The code
827 for a DECL_INITIAL only handles some operations,
828 etc addition, minus, 'address of'. See output_addressed_constants ()
829 in varasm.cc. */
830 tree init_tree = init->as_tree ();
831 tree folded = fold_const_var (init_tree);
833 if (!TREE_CONSTANT (folded))
835 tree name = DECL_NAME (inner);
837 if (name != NULL_TREE)
838 add_error (NULL,
839 "unable to convert initial value for the global variable %s"
840 " to a compile-time constant",
841 IDENTIFIER_POINTER (name));
842 else
843 add_error (NULL,
844 "unable to convert initial value for global variable"
845 " to a compile-time constant");
846 return;
849 DECL_INITIAL (inner) = folded;
852 playback::rvalue *
853 playback::context::
854 new_ctor (location *loc,
855 type *type,
856 const auto_vec<field*> *fields,
857 const auto_vec<rvalue*> *rvalues)
859 tree type_tree = type->as_tree ();
861 /* Handle empty ctors first. I.e. set everything to 0. */
862 if (rvalues->length () == 0)
863 return new rvalue (this, build_constructor (type_tree, NULL));
865 /* Handle arrays (and return). */
866 if (TREE_CODE (type_tree) == ARRAY_TYPE)
868 int n = rvalues->length ();
869 /* The vec for the constructor node. */
870 vec<constructor_elt, va_gc> *v = NULL;
871 vec_alloc (v, n);
873 for (int i = 0; i < n; i++)
875 rvalue *rv = (*rvalues)[i];
876 /* null rvalues indicate that the element should be zeroed. */
877 if (rv)
878 CONSTRUCTOR_APPEND_ELT (v,
879 build_int_cst (size_type_node, i),
880 rv->as_tree ());
881 else
882 CONSTRUCTOR_APPEND_ELT (v,
883 build_int_cst (size_type_node, i),
884 build_zero_cst (TREE_TYPE (type_tree)));
887 tree ctor = build_constructor (type_tree, v);
889 if (loc)
890 set_tree_location (ctor, loc);
892 return new rvalue (this, ctor);
895 /* Handle structs and unions. */
896 int n = fields->length ();
898 /* The vec for the constructor node. */
899 vec<constructor_elt, va_gc> *v = NULL;
900 vec_alloc (v, n);
902 /* Iterate over the fields, building initializations. */
903 for (int i = 0;i < n; i++)
905 tree field = (*fields)[i]->as_tree ();
906 rvalue *rv = (*rvalues)[i];
907 /* If the value is NULL, it means we should zero the field. */
908 if (rv)
909 CONSTRUCTOR_APPEND_ELT (v, field, rv->as_tree ());
910 else
912 tree zero_cst = build_zero_cst (TREE_TYPE (field));
913 CONSTRUCTOR_APPEND_ELT (v, field, zero_cst);
917 tree ctor = build_constructor (type_tree, v);
919 if (loc)
920 set_tree_location (ctor, loc);
922 return new rvalue (this, build_constructor (type_tree, v));
925 /* Fill 'constructor_elements' with the memory content of
926 'initializer'. Each element of the initializer is of the size of
927 type T. In use by new_global_initialized.*/
929 template<typename T>
930 static void
931 load_blob_in_ctor (vec<constructor_elt, va_gc> *&constructor_elements,
932 size_t num_elem,
933 const void *initializer)
935 /* Loosely based on 'output_init_element' c-typeck.cc:9691. */
936 const T *p = (const T *)initializer;
937 tree node = make_unsigned_type (BITS_PER_UNIT * sizeof (T));
938 for (size_t i = 0; i < num_elem; i++)
940 constructor_elt celt =
941 { build_int_cst (long_unsigned_type_node, i),
942 build_int_cst (node, p[i]) };
943 vec_safe_push (constructor_elements, celt);
947 /* Construct an initialized playback::lvalue instance (wrapping a
948 tree). */
950 playback::lvalue *
951 playback::context::
952 new_global_initialized (location *loc,
953 enum gcc_jit_global_kind kind,
954 type *type,
955 size_t element_size,
956 size_t initializer_num_elem,
957 const void *initializer,
958 const char *name,
959 enum global_var_flags flags,
960 const std::vector<std::pair<gcc_jit_variable_attribute,
961 std::string>> &attributes)
963 tree inner = global_new_decl (loc, kind, type, name, flags, attributes);
965 vec<constructor_elt, va_gc> *constructor_elements = NULL;
967 switch (element_size)
969 case 1:
970 load_blob_in_ctor<uint8_t> (constructor_elements, initializer_num_elem,
971 initializer);
972 break;
973 case 2:
974 load_blob_in_ctor<uint16_t> (constructor_elements, initializer_num_elem,
975 initializer);
976 break;
977 case 4:
978 load_blob_in_ctor<uint32_t> (constructor_elements, initializer_num_elem,
979 initializer);
980 break;
981 case 8:
982 load_blob_in_ctor<uint64_t> (constructor_elements, initializer_num_elem,
983 initializer);
984 break;
985 default:
986 /* This function is serving on sizes returned by 'get_size',
987 these are all covered by the previous cases. */
988 gcc_unreachable ();
990 /* Compare with 'pop_init_level' c-typeck.cc:8780. */
991 tree ctor = build_constructor (type->as_tree (), constructor_elements);
992 constructor_elements = NULL;
994 /* Compare with 'store_init_value' c-typeck.cc:7555. */
995 DECL_INITIAL (inner) = ctor;
997 return global_finalize_lvalue (inner);
1000 /* Implementation of the various
1001 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
1002 methods.
1003 Each of these constructs a playback::rvalue instance (wrapping a tree).
1005 These specializations are required to be in the same namespace
1006 as the template, hence we now have to enter the gcc::jit::playback
1007 namespace. */
1009 namespace playback
1012 /* Specialization of making an rvalue from a const, for host <int>. */
1014 template <>
1015 rvalue *
1016 context::
1017 new_rvalue_from_const <int> (type *type,
1018 int value)
1020 // FIXME: type-checking, or coercion?
1021 tree inner_type = type->as_tree ();
1022 if (INTEGRAL_TYPE_P (inner_type))
1024 tree inner = build_int_cst (inner_type, value);
1025 return new rvalue (this, inner);
1027 else
1029 REAL_VALUE_TYPE real_value;
1030 real_from_integer (&real_value, VOIDmode, value, SIGNED);
1031 tree inner = build_real (inner_type, real_value);
1032 return new rvalue (this, inner);
1036 /* Specialization of making an rvalue from a const, for host <long>. */
1038 template <>
1039 rvalue *
1040 context::
1041 new_rvalue_from_const <long> (type *type,
1042 long value)
1044 // FIXME: type-checking, or coercion?
1045 tree inner_type = type->as_tree ();
1046 if (INTEGRAL_TYPE_P (inner_type))
1048 tree inner = build_int_cst (inner_type, value);
1049 return new rvalue (this, inner);
1051 else
1053 REAL_VALUE_TYPE real_value;
1054 real_from_integer (&real_value, VOIDmode, value, SIGNED);
1055 tree inner = build_real (inner_type, real_value);
1056 return new rvalue (this, inner);
1060 /* Specialization of making an rvalue from a const, for host <double>. */
1062 template <>
1063 rvalue *
1064 context::
1065 new_rvalue_from_const <double> (type *type,
1066 double value)
1068 // FIXME: type-checking, or coercion?
1069 tree inner_type = type->as_tree ();
1071 /* We have a "double", we want a REAL_VALUE_TYPE.
1073 real.cc:real_from_target appears to require the representation to be
1074 split into 32-bit values, and then sent as an pair of host long
1075 ints. */
1076 REAL_VALUE_TYPE real_value;
1077 union
1079 double as_double;
1080 uint32_t as_uint32s[2];
1081 } u;
1082 u.as_double = value;
1083 long int as_long_ints[2];
1084 as_long_ints[0] = u.as_uint32s[0];
1085 as_long_ints[1] = u.as_uint32s[1];
1086 real_from_target (&real_value, as_long_ints, DFmode);
1087 tree inner = build_real (inner_type, real_value);
1088 return new rvalue (this, inner);
1091 /* Specialization of making an rvalue from a const, for host <void *>. */
1093 template <>
1094 rvalue *
1095 context::
1096 new_rvalue_from_const <void *> (type *type,
1097 void *value)
1099 tree inner_type = type->as_tree ();
1100 /* FIXME: how to ensure we have a wide enough type? */
1101 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
1102 return new rvalue (this, inner);
1105 /* We're done implementing the specializations of
1106 gcc::jit::playback::context::new_rvalue_from_const <T>
1107 so we can exit the gcc::jit::playback namespace. */
1109 } // namespace playback
1111 /* Construct a playback::rvalue instance (wrapping a tree). */
1113 playback::rvalue *
1114 playback::context::
1115 new_string_literal (const char *value)
1117 /* Compare with c-family/c-common.cc: fix_string_type. */
1118 size_t len = strlen (value);
1119 tree i_type = build_index_type (size_int (len));
1120 tree a_type = build_array_type (char_type_node, i_type);
1121 /* build_string len parameter must include NUL terminator when
1122 building C strings. */
1123 tree t_str = ::build_string (len + 1, value);
1124 TREE_TYPE (t_str) = a_type;
1126 /* Convert to (const char*), loosely based on
1127 c/c-typeck.cc: array_to_pointer_conversion,
1128 by taking address of start of string. */
1129 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
1131 return new rvalue (this, t_addr);
1134 /* Construct a playback::rvalue instance (wrapping a tree) for a
1135 vector. */
1137 playback::rvalue *
1138 playback::context::new_rvalue_from_vector (location *,
1139 type *type,
1140 const auto_vec<rvalue *> &elements)
1142 vec<constructor_elt, va_gc> *v;
1143 vec_alloc (v, elements.length ());
1144 for (unsigned i = 0; i < elements.length (); ++i)
1145 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
1146 tree t_ctor = build_constructor (type->as_tree (), v);
1147 return new rvalue (this, t_ctor);
1150 /* Coerce a tree expression into a boolean tree expression. */
1152 tree
1153 playback::context::
1154 as_truth_value (tree expr, location *loc)
1156 /* Compare to c-typeck.cc:c_objc_common_truthvalue_conversion */
1157 tree typed_zero = fold_build1 (CONVERT_EXPR,
1158 TREE_TYPE (expr),
1159 integer_zero_node);
1160 if (loc)
1161 set_tree_location (typed_zero, loc);
1163 tree type = TREE_TYPE (expr);
1164 expr = fold_build2_loc (UNKNOWN_LOCATION,
1165 NE_EXPR, type, expr, typed_zero);
1166 if (loc)
1167 set_tree_location (expr, loc);
1169 return expr;
1172 /* Add a "top-level" basic asm statement (i.e. one outside of any functions)
1173 containing ASM_STMTS.
1175 Compare with c_parser_asm_definition. */
1177 void
1178 playback::context::add_top_level_asm (const char *asm_stmts)
1180 tree asm_str = build_string (asm_stmts);
1181 symtab->finalize_toplevel_asm (asm_str);
1184 /* Construct a playback::rvalue instance (wrapping a tree) for a
1185 unary op. */
1187 playback::rvalue *
1188 playback::context::
1189 new_unary_op (location *loc,
1190 enum gcc_jit_unary_op op,
1191 type *result_type,
1192 rvalue *a)
1194 // FIXME: type-checking, or coercion?
1195 enum tree_code inner_op;
1197 gcc_assert (result_type);
1198 gcc_assert (a);
1200 tree node = a->as_tree ();
1201 node = fold_const_var (node);
1203 tree inner_result = NULL;
1205 switch (op)
1207 default:
1208 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
1209 return NULL;
1211 case GCC_JIT_UNARY_OP_MINUS:
1212 inner_op = NEGATE_EXPR;
1213 break;
1215 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
1216 inner_op = BIT_NOT_EXPR;
1217 break;
1219 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
1220 node = as_truth_value (node, loc);
1221 inner_result = invert_truthvalue (node);
1222 if (loc)
1223 set_tree_location (inner_result, loc);
1224 return new rvalue (this, inner_result);
1226 case GCC_JIT_UNARY_OP_ABS:
1227 inner_op = ABS_EXPR;
1228 break;
1231 inner_result = build1 (inner_op,
1232 result_type->as_tree (),
1233 node);
1235 /* Try to fold. */
1236 inner_result = fold (inner_result);
1238 if (loc)
1239 set_tree_location (inner_result, loc);
1241 return new rvalue (this, inner_result);
1244 /* Construct a playback::rvalue instance (wrapping a tree) for a
1245 binary op. */
1247 playback::rvalue *
1248 playback::context::
1249 new_binary_op (location *loc,
1250 enum gcc_jit_binary_op op,
1251 type *result_type,
1252 rvalue *a, rvalue *b)
1254 // FIXME: type-checking, or coercion?
1255 enum tree_code inner_op;
1257 gcc_assert (result_type);
1258 gcc_assert (a);
1259 gcc_assert (b);
1261 tree node_a = a->as_tree ();
1262 node_a = fold_const_var (node_a);
1264 tree node_b = b->as_tree ();
1265 node_b = fold_const_var (node_b);
1267 switch (op)
1269 default:
1270 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
1271 return NULL;
1273 case GCC_JIT_BINARY_OP_PLUS:
1274 inner_op = PLUS_EXPR;
1275 break;
1277 case GCC_JIT_BINARY_OP_MINUS:
1278 inner_op = MINUS_EXPR;
1279 break;
1281 case GCC_JIT_BINARY_OP_MULT:
1282 inner_op = MULT_EXPR;
1283 break;
1285 case GCC_JIT_BINARY_OP_DIVIDE:
1286 if (FLOAT_TYPE_P (result_type->as_tree ()))
1287 /* Floating-point division: */
1288 inner_op = RDIV_EXPR;
1289 else
1290 /* Truncating to zero: */
1291 inner_op = TRUNC_DIV_EXPR;
1292 break;
1294 case GCC_JIT_BINARY_OP_MODULO:
1295 inner_op = TRUNC_MOD_EXPR;
1296 break;
1298 case GCC_JIT_BINARY_OP_BITWISE_AND:
1299 inner_op = BIT_AND_EXPR;
1300 break;
1302 case GCC_JIT_BINARY_OP_BITWISE_XOR:
1303 inner_op = BIT_XOR_EXPR;
1304 break;
1306 case GCC_JIT_BINARY_OP_BITWISE_OR:
1307 inner_op = BIT_IOR_EXPR;
1308 break;
1310 case GCC_JIT_BINARY_OP_LOGICAL_AND:
1311 node_a = as_truth_value (node_a, loc);
1312 node_b = as_truth_value (node_b, loc);
1313 inner_op = TRUTH_ANDIF_EXPR;
1314 break;
1316 case GCC_JIT_BINARY_OP_LOGICAL_OR:
1317 node_a = as_truth_value (node_a, loc);
1318 node_b = as_truth_value (node_b, loc);
1319 inner_op = TRUTH_ORIF_EXPR;
1320 break;
1322 case GCC_JIT_BINARY_OP_LSHIFT:
1323 inner_op = LSHIFT_EXPR;
1324 break;
1326 case GCC_JIT_BINARY_OP_RSHIFT:
1327 inner_op = RSHIFT_EXPR;
1328 break;
1331 tree inner_expr = build2 (inner_op,
1332 result_type->as_tree (),
1333 node_a,
1334 node_b);
1336 /* Try to fold the expression. */
1337 inner_expr = fold (inner_expr);
1339 if (loc)
1340 set_tree_location (inner_expr, loc);
1342 return new rvalue (this, inner_expr);
1345 /* Construct a playback::rvalue instance (wrapping a tree) for a
1346 comparison. */
1348 playback::rvalue *
1349 playback::context::
1350 new_comparison (location *loc,
1351 enum gcc_jit_comparison op,
1352 rvalue *a, rvalue *b, type *vec_result_type)
1354 // FIXME: type-checking, or coercion?
1355 enum tree_code inner_op;
1357 gcc_assert (a);
1358 gcc_assert (b);
1360 switch (op)
1362 default:
1363 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
1364 return NULL;
1366 case GCC_JIT_COMPARISON_EQ:
1367 inner_op = EQ_EXPR;
1368 break;
1369 case GCC_JIT_COMPARISON_NE:
1370 inner_op = NE_EXPR;
1371 break;
1372 case GCC_JIT_COMPARISON_LT:
1373 inner_op = LT_EXPR;
1374 break;
1375 case GCC_JIT_COMPARISON_LE:
1376 inner_op = LE_EXPR;
1377 break;
1378 case GCC_JIT_COMPARISON_GT:
1379 inner_op = GT_EXPR;
1380 break;
1381 case GCC_JIT_COMPARISON_GE:
1382 inner_op = GE_EXPR;
1383 break;
1386 tree node_a = a->as_tree ();
1387 node_a = fold_const_var (node_a);
1388 tree node_b = b->as_tree ();
1389 node_b = fold_const_var (node_b);
1391 tree inner_expr;
1392 tree a_type = TREE_TYPE (node_a);
1393 if (VECTOR_TYPE_P (a_type))
1395 /* Build a vector comparison. See build_vec_cmp in c-typeck.cc for
1396 reference. */
1397 tree t_vec_result_type = vec_result_type->as_tree ();
1398 tree zero_vec = build_zero_cst (t_vec_result_type);
1399 tree minus_one_vec = build_minus_one_cst (t_vec_result_type);
1400 tree cmp_type = truth_type_for (a_type);
1401 tree cmp = build2 (inner_op, cmp_type, node_a, node_b);
1402 inner_expr = build3 (VEC_COND_EXPR, t_vec_result_type, cmp, minus_one_vec,
1403 zero_vec);
1405 else
1407 inner_expr = build2 (inner_op,
1408 boolean_type_node,
1409 node_a,
1410 node_b);
1413 /* Try to fold. */
1414 inner_expr = fold (inner_expr);
1416 if (loc)
1417 set_tree_location (inner_expr, loc);
1418 return new rvalue (this, inner_expr);
1421 /* Construct a playback::rvalue instance (wrapping a tree) for a
1422 function call. */
1424 playback::rvalue *
1425 playback::context::
1426 build_call (location *loc,
1427 tree fn_ptr,
1428 const auto_vec<rvalue *> *args,
1429 bool require_tail_call)
1431 vec<tree, va_gc> *tree_args;
1432 vec_alloc (tree_args, args->length ());
1433 for (unsigned i = 0; i < args->length (); i++)
1434 tree_args->quick_push ((*args)[i]->as_tree ());
1436 if (loc)
1437 set_tree_location (fn_ptr, loc);
1439 tree fn = TREE_TYPE (fn_ptr);
1440 tree fn_type = TREE_TYPE (fn);
1441 tree return_type = TREE_TYPE (fn_type);
1443 tree call = build_call_vec (return_type,
1444 fn_ptr, tree_args);
1446 if (require_tail_call)
1447 CALL_EXPR_MUST_TAIL_CALL (call) = 1;
1449 return new rvalue (this, call);
1451 /* see c-typeck.cc: build_function_call
1452 which calls build_function_call_vec
1454 which does lots of checking, then:
1455 result = build_call_array_loc (loc, TREE_TYPE (fntype),
1456 function, nargs, argarray);
1457 which is in tree.cc
1458 (see also build_call_vec)
1462 /* Construct a playback::rvalue instance (wrapping a tree) for a
1463 call to a specific function. */
1465 playback::rvalue *
1466 playback::context::
1467 new_call (location *loc,
1468 function *func,
1469 const auto_vec<rvalue *> *args,
1470 bool require_tail_call)
1472 tree fndecl;
1474 gcc_assert (func);
1476 fndecl = func->as_fndecl ();
1478 tree fntype = TREE_TYPE (fndecl);
1480 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
1482 return build_call (loc, fn, args, require_tail_call);
1485 /* Construct a playback::rvalue instance (wrapping a tree) for a
1486 call through a function pointer. */
1488 playback::rvalue *
1489 playback::context::
1490 new_call_through_ptr (location *loc,
1491 rvalue *fn_ptr,
1492 const auto_vec<rvalue *> *args,
1493 bool require_tail_call)
1495 gcc_assert (fn_ptr);
1496 tree t_fn_ptr = fn_ptr->as_tree ();
1498 return build_call (loc, t_fn_ptr, args, require_tail_call);
1501 /* Construct a tree for a cast. */
1503 tree
1504 playback::context::build_cast (playback::location *loc,
1505 playback::rvalue *expr,
1506 playback::type *type_)
1508 /* For comparison, see:
1509 - c/c-typeck.cc:build_c_cast
1510 - c/c-convert.cc: convert
1511 - convert.h
1513 Only some kinds of cast are currently supported here. */
1514 tree t_expr = expr->as_tree ();
1515 t_expr = fold_const_var (t_expr);
1517 tree t_dst_type = type_->as_tree ();
1518 tree t_ret = NULL;
1519 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
1520 if (t_ret)
1521 return t_ret;
1522 enum tree_code dst_code = TREE_CODE (t_dst_type);
1523 switch (dst_code)
1525 case INTEGER_TYPE:
1526 case ENUMERAL_TYPE:
1527 t_ret = convert_to_integer (t_dst_type, t_expr);
1528 goto maybe_fold;
1530 case BOOLEAN_TYPE:
1531 /* Compare with c_objc_common_truthvalue_conversion and
1532 c_common_truthvalue_conversion. */
1533 /* For now, convert to: (t_expr != 0) */
1534 t_ret = build2 (NE_EXPR, t_dst_type,
1535 t_expr,
1536 build_int_cst (TREE_TYPE (t_expr), 0));
1537 goto maybe_fold;
1539 case REAL_TYPE:
1540 t_ret = convert_to_real (t_dst_type, t_expr);
1541 goto maybe_fold;
1543 case POINTER_TYPE:
1544 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
1545 goto maybe_fold;
1547 default:
1548 add_error (loc, "couldn't handle cast during playback");
1549 fprintf (stderr, "input expression:\n");
1550 debug_tree (t_expr);
1551 fprintf (stderr, "requested type:\n");
1552 debug_tree (t_dst_type);
1553 return error_mark_node;
1555 maybe_fold:
1556 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
1557 t_ret = fold (t_ret);
1558 return t_ret;
1562 /* Construct a playback::rvalue instance (wrapping a tree) for a
1563 cast. */
1565 playback::rvalue *
1566 playback::context::
1567 new_cast (playback::location *loc,
1568 playback::rvalue *expr,
1569 playback::type *type_)
1572 tree t_cast = build_cast (loc, expr, type_);
1573 if (loc)
1574 set_tree_location (t_cast, loc);
1575 return new rvalue (this, t_cast);
1578 /* Construct a playback::rvalue instance (wrapping a tree) for a
1579 bitcast. */
1581 playback::rvalue *
1582 playback::context::
1583 new_bitcast (location *loc,
1584 rvalue *expr,
1585 type *type_)
1587 tree expr_size = TYPE_SIZE (expr->get_type ()->as_tree ());
1588 tree type_size = TYPE_SIZE (type_->as_tree ());
1589 tree t_expr = expr->as_tree ();
1590 tree t_dst_type = type_->as_tree ();
1591 if (expr_size != type_size)
1593 active_playback_ctxt->add_error (loc,
1594 "bitcast with types of different sizes");
1595 fprintf (stderr, "input expression (size: %ld):\n",
1596 (long) tree_to_uhwi (expr_size));
1597 debug_tree (t_expr);
1598 fprintf (stderr, "requested type (size: %ld):\n",
1599 (long) tree_to_uhwi (type_size));
1600 debug_tree (t_dst_type);
1602 tree t_bitcast = build1 (VIEW_CONVERT_EXPR, t_dst_type, t_expr);
1603 if (loc)
1604 set_tree_location (t_bitcast, loc);
1605 return new rvalue (this, t_bitcast);
1608 /* Construct a playback::lvalue instance (wrapping a tree) for an
1609 array access. */
1611 playback::lvalue *
1612 playback::context::
1613 new_array_access (location *loc,
1614 rvalue *ptr,
1615 rvalue *index)
1617 gcc_assert (ptr);
1618 gcc_assert (index);
1620 /* For comparison, see:
1621 c/c-typeck.cc: build_array_ref
1622 c-family/c-common.cc: pointer_int_sum
1624 tree t_ptr = ptr->as_tree ();
1625 t_ptr = fold_const_var (t_ptr);
1626 tree t_index = index->as_tree ();
1627 t_index = fold_const_var (t_index);
1629 tree t_type_ptr = TREE_TYPE (t_ptr);
1630 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1632 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1634 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1635 NULL_TREE, NULL_TREE);
1636 t_result = fold (t_result);
1637 if (loc)
1638 set_tree_location (t_result, loc);
1639 return new lvalue (this, t_result);
1641 else
1643 /* Convert index to an offset in bytes. */
1644 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1645 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1646 tree t_offset = fold_build2_loc (UNKNOWN_LOCATION,
1647 MULT_EXPR, sizetype, t_index, t_sizeof);
1649 /* Locate (ptr + offset). */
1650 tree t_address = fold_build2_loc (UNKNOWN_LOCATION,
1651 POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1653 tree t_indirection = fold_build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1654 if (loc)
1656 set_tree_location (t_sizeof, loc);
1657 set_tree_location (t_offset, loc);
1658 set_tree_location (t_address, loc);
1659 set_tree_location (t_indirection, loc);
1662 return new lvalue (this, t_indirection);
1666 /* Construct a tree for a field access. */
1668 tree
1669 playback::context::
1670 new_field_access (location *loc,
1671 tree datum,
1672 field *field)
1674 gcc_assert (datum);
1675 gcc_assert (field);
1677 /* Compare with c/c-typeck.cc:lookup_field, build_indirect_ref, and
1678 build_component_ref. */
1679 tree type = TREE_TYPE (datum);
1680 gcc_assert (type);
1681 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1683 tree t_field = field->as_tree ();
1684 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1685 t_field, NULL_TREE);
1686 if (loc)
1687 set_tree_location (ref, loc);
1688 return ref;
1691 /* Construct a tree for a dereference. */
1693 tree
1694 playback::context::
1695 new_dereference (tree ptr,
1696 location *loc)
1698 gcc_assert (ptr);
1700 tree type = TREE_TYPE (TREE_TYPE(ptr));
1701 tree datum = fold_build1 (INDIRECT_REF, type, ptr);
1702 if (loc)
1703 set_tree_location (datum, loc);
1704 return datum;
1707 /* Construct a playback::type instance (wrapping a tree)
1708 with the given alignment. */
1710 playback::type *
1711 playback::type::
1712 get_aligned (size_t alignment_in_bytes) const
1714 tree t_new_type = build_variant_type_copy (m_inner);
1716 SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT);
1717 TYPE_USER_ALIGN (t_new_type) = 1;
1719 return new type (t_new_type);
1722 /* Construct a playback::type instance (wrapping a tree)
1723 for the given vector type. */
1725 playback::type *
1726 playback::type::
1727 get_vector (size_t num_units) const
1729 tree t_new_type = build_vector_type (m_inner, num_units);
1730 return new type (t_new_type);
1733 /* Construct a playback::lvalue instance (wrapping a tree) for a
1734 field access. */
1736 playback::lvalue *
1737 playback::lvalue::
1738 access_field (location *loc,
1739 field *field)
1741 tree datum = as_tree ();
1742 tree ref = get_context ()->new_field_access (loc, datum, field);
1743 if (!ref)
1744 return NULL;
1745 return new lvalue (get_context (), ref);
1748 /* Construct a playback::rvalue instance (wrapping a tree) for a
1749 field access. */
1751 playback::rvalue *
1752 playback::rvalue::
1753 access_field (location *loc,
1754 field *field)
1756 tree datum = as_tree ();
1757 tree ref = get_context ()->new_field_access (loc, datum, field);
1758 if (!ref)
1759 return NULL;
1760 return new rvalue (get_context (), ref);
1763 /* Construct a playback::lvalue instance (wrapping a tree) for a
1764 dereferenced field access. */
1766 playback::lvalue *
1767 playback::rvalue::
1768 dereference_field (location *loc,
1769 field *field)
1771 tree ptr = as_tree ();
1772 tree datum = get_context ()->new_dereference (ptr, loc);
1773 if (!datum)
1774 return NULL;
1775 tree ref = get_context ()->new_field_access (loc, datum, field);
1776 if (!ref)
1777 return NULL;
1778 return new lvalue (get_context (), ref);
1781 /* Construct a playback::lvalue instance (wrapping a tree) for a
1782 dereference. */
1784 playback::lvalue *
1785 playback::rvalue::
1786 dereference (location *loc)
1788 tree ptr = as_tree ();
1789 tree datum = get_context ()->new_dereference (ptr, loc);
1790 return new lvalue (get_context (), datum);
1793 /* Mark the lvalue saying that we need to be able to take the
1794 address of it; it should not be allocated in a register.
1795 Compare with e.g. c/c-typeck.cc: c_mark_addressable really_atomic_lvalue.
1796 Returns false if a failure occurred (an error will already have been
1797 added to the active context for this case). */
1799 bool
1800 playback::lvalue::
1801 mark_addressable (location *loc)
1803 tree x = as_tree ();
1805 while (1)
1806 switch (TREE_CODE (x))
1808 case COMPONENT_REF:
1809 if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x, 1)))
1811 gcc_assert (gcc::jit::active_playback_ctxt);
1812 gcc::jit::
1813 active_playback_ctxt->add_error (loc,
1814 "cannot take address of "
1815 "bit-field");
1816 return false;
1818 /* fallthrough */
1819 case ADDR_EXPR:
1820 case ARRAY_REF:
1821 case REALPART_EXPR:
1822 case IMAGPART_EXPR:
1823 x = TREE_OPERAND (x, 0);
1824 break;
1826 case COMPOUND_LITERAL_EXPR:
1827 case CONSTRUCTOR:
1828 TREE_ADDRESSABLE (x) = 1;
1829 return true;
1831 case VAR_DECL:
1832 case CONST_DECL:
1833 case PARM_DECL:
1834 case RESULT_DECL:
1835 /* (we don't have a concept of a "register" declaration) */
1836 /* fallthrough */
1837 case FUNCTION_DECL:
1838 TREE_ADDRESSABLE (x) = 1;
1839 /* fallthrough */
1840 default:
1841 return true;
1845 /* Construct a playback::rvalue instance (wrapping a tree) for an
1846 address-lookup. */
1848 playback::rvalue *
1849 playback::lvalue::
1850 get_address (location *loc)
1852 tree t_lvalue = as_tree ();
1853 tree t_thistype = TREE_TYPE (t_lvalue);
1854 tree t_ptrtype = build_pointer_type (t_thistype);
1855 tree ptr = fold_build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1856 if (loc)
1857 get_context ()->set_tree_location (ptr, loc);
1858 if (mark_addressable (loc))
1859 return new rvalue (get_context (), ptr);
1860 else
1861 return NULL;
1864 /* The wrapper subclasses are GC-managed, but can own non-GC memory.
1865 Provide this finalization hook for calling then they are collected,
1866 which calls the finalizer vfunc. This allows them to call "release"
1867 on any vec<> within them. */
1869 static void
1870 wrapper_finalizer (void *ptr)
1872 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1873 wrapper->finalizer ();
1876 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1877 allocate them using ggc_internal_cleared_alloc. */
1879 void *
1880 playback::wrapper::
1881 operator new (size_t sz)
1883 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1887 /* Constructor for gcc:jit::playback::function. */
1889 playback::function::
1890 function (context *ctxt,
1891 tree fndecl,
1892 enum gcc_jit_function_kind kind)
1893 : m_ctxt(ctxt),
1894 m_inner_fndecl (fndecl),
1895 m_inner_bind_expr (NULL),
1896 m_kind (kind),
1897 m_blocks ()
1899 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1901 /* Create a BIND_EXPR, and within it, a statement list. */
1902 m_stmt_list = alloc_stmt_list ();
1903 m_stmt_iter = tsi_start (m_stmt_list);
1904 m_inner_block = make_node (BLOCK);
1905 m_inner_bind_expr =
1906 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1908 else
1910 m_inner_block = NULL;
1911 m_stmt_list = NULL;
1915 /* Hand-written GC-marking hook for playback functions. */
1917 void
1918 playback::function::
1919 gt_ggc_mx ()
1921 gt_ggc_m_9tree_node (m_inner_fndecl);
1922 gt_ggc_m_9tree_node (m_inner_bind_expr);
1923 gt_ggc_m_9tree_node (m_stmt_list);
1924 gt_ggc_m_9tree_node (m_inner_block);
1927 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1928 GC-ed. */
1930 void
1931 playback::function::finalizer ()
1933 m_blocks.release ();
1936 /* Get the return type of a playback function, in tree form. */
1938 tree
1939 playback::function::
1940 get_return_type_as_tree () const
1942 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1945 /* Construct a new local within this playback::function. */
1947 playback::lvalue *
1948 playback::function::
1949 new_local (location *loc,
1950 type *type,
1951 const char *name,
1952 const std::vector<std::pair<gcc_jit_variable_attribute,
1953 std::string>> &attributes)
1955 gcc_assert (type);
1956 gcc_assert (name);
1957 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1958 get_identifier (name),
1959 type->as_tree ());
1960 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1962 /* Prepend to BIND_EXPR_VARS: */
1963 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1964 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1966 set_variable_string_attribute (attributes, inner);
1968 if (loc)
1969 set_tree_location (inner, loc);
1970 return new lvalue (m_ctxt, inner);
1973 /* Construct a new block within this playback::function. */
1975 playback::block *
1976 playback::function::
1977 new_block (const char *name)
1979 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1981 block *result = new playback::block (this, name);
1982 m_blocks.safe_push (result);
1983 return result;
1986 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1987 this playback::function. */
1989 playback::rvalue *
1990 playback::function::get_address (location *loc)
1992 tree t_fndecl = as_fndecl ();
1993 tree t_fntype = TREE_TYPE (t_fndecl);
1994 tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
1995 if (loc)
1996 m_ctxt->set_tree_location (t_fnptr, loc);
1997 return new rvalue (m_ctxt, t_fnptr);
2000 /* Build a statement list for the function as a whole out of the
2001 lists of statements for the individual blocks, building labels
2002 for each block. */
2004 void
2005 playback::function::
2006 build_stmt_list ()
2008 int i;
2009 block *b;
2011 JIT_LOG_SCOPE (m_ctxt->get_logger ());
2013 FOR_EACH_VEC_ELT (m_blocks, i, b)
2015 int j;
2016 tree stmt;
2018 b->m_label_expr = build1 (LABEL_EXPR,
2019 void_type_node,
2020 b->as_label_decl ());
2021 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
2023 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
2024 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
2028 /* Finish compiling the given function, potentially running the
2029 garbage-collector.
2030 The function will have a statement list by now.
2031 Amongst other things, this gimplifies the statement list,
2032 and calls cgraph_node::finalize_function on the function. */
2034 void
2035 playback::function::
2036 postprocess ()
2038 JIT_LOG_SCOPE (m_ctxt->get_logger ());
2040 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
2041 debug_tree (m_stmt_list);
2043 /* Do we need this to force cgraphunit.cc to output the function? */
2044 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
2046 DECL_EXTERNAL (m_inner_fndecl) = 0;
2047 DECL_PRESERVE_P (m_inner_fndecl) = 1;
2050 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
2051 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
2053 DECL_EXTERNAL (m_inner_fndecl) = 0;
2054 TREE_PUBLIC (m_inner_fndecl) = 0;
2057 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
2059 /* Seem to need this in gimple-low.cc: */
2060 gcc_assert (m_inner_block);
2061 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
2063 /* how to add to function? the following appears to be how to
2064 set the body of a m_inner_fndecl: */
2065 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
2067 /* Ensure that locals appear in the debuginfo. */
2068 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
2070 //debug_tree (m_inner_fndecl);
2072 /* Convert to gimple: */
2073 //printf("about to gimplify_function_tree\n");
2074 gimplify_function_tree (m_inner_fndecl);
2075 //printf("finished gimplify_function_tree\n");
2077 current_function_decl = m_inner_fndecl;
2078 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
2079 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
2080 //debug_tree (m_inner_fndecl);
2082 //printf("about to add to cgraph\n");
2083 /* Add to cgraph: */
2084 cgraph_node::finalize_function (m_inner_fndecl, false);
2085 /* This can trigger a collection, so we need to have all of
2086 the funcs as roots. */
2088 current_function_decl = NULL;
2090 else
2091 /* Add to cgraph to output aliases: */
2092 rest_of_decl_compilation (m_inner_fndecl, true, 0);
2095 /* Don't leak vec's internal buffer (in non-GC heap) when we are
2096 GC-ed. */
2098 void
2099 playback::block::finalizer ()
2101 m_stmts.release ();
2104 /* Add an eval of the rvalue to the function's statement list. */
2106 void
2107 playback::block::
2108 add_eval (location *loc,
2109 rvalue *rvalue)
2111 gcc_assert (rvalue);
2113 if (loc)
2114 set_tree_location (rvalue->as_tree (), loc);
2116 add_stmt (rvalue->as_tree ());
2119 /* Add an assignment to the function's statement list. */
2121 void
2122 playback::block::
2123 add_assignment (location *loc,
2124 lvalue *lvalue,
2125 rvalue *rvalue)
2127 gcc_assert (lvalue);
2128 gcc_assert (rvalue);
2130 tree t_lvalue = lvalue->as_tree ();
2131 tree t_rvalue = rvalue->as_tree ();
2132 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
2134 t_rvalue = build1 (CONVERT_EXPR,
2135 TREE_TYPE (t_lvalue),
2136 t_rvalue);
2137 if (loc)
2138 set_tree_location (t_rvalue, loc);
2141 tree stmt =
2142 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
2143 t_lvalue, t_rvalue);
2144 if (loc)
2145 set_tree_location (stmt, loc);
2146 add_stmt (stmt);
2149 /* Add a comment to the function's statement list.
2150 For now this is done by adding a dummy label. */
2152 void
2153 playback::block::
2154 add_comment (location *loc,
2155 const char *text)
2157 /* Wrap the text in C-style comment delimiters. */
2158 size_t sz =
2159 (3 /* opening delim */
2160 + strlen (text)
2161 + 3 /* closing delim */
2162 + 1 /* terminator */);
2163 char *wrapped = (char *)ggc_internal_alloc (sz);
2164 snprintf (wrapped, sz, "/* %s */", text);
2166 /* For now we simply implement this by adding a dummy label with a name
2167 containing the given text. */
2168 tree identifier = get_identifier (wrapped);
2169 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
2170 identifier, void_type_node);
2171 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
2173 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
2174 if (loc)
2175 set_tree_location (label_expr, loc);
2176 add_stmt (label_expr);
2179 /* Add a conditional jump statement to the function's statement list. */
2181 void
2182 playback::block::
2183 add_conditional (location *loc,
2184 rvalue *boolval,
2185 block *on_true,
2186 block *on_false)
2188 gcc_assert (boolval);
2189 gcc_assert (on_true);
2190 gcc_assert (on_false);
2192 /* COND_EXPR wants statement lists for the true/false operands, but we
2193 want labels.
2194 Shim it by creating jumps to the labels */
2195 tree true_jump = build1 (GOTO_EXPR, void_type_node,
2196 on_true->as_label_decl ());
2197 if (loc)
2198 set_tree_location (true_jump, loc);
2200 tree false_jump = build1 (GOTO_EXPR, void_type_node,
2201 on_false->as_label_decl ());
2202 if (loc)
2203 set_tree_location (false_jump, loc);
2205 tree stmt =
2206 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
2207 true_jump, false_jump);
2208 if (loc)
2209 set_tree_location (stmt, loc);
2210 add_stmt (stmt);
2213 /* Add an unconditional jump statement to the function's statement list. */
2215 void
2216 playback::block::
2217 add_jump (location *loc,
2218 block *target)
2220 gcc_assert (target);
2222 // see c_finish_loop
2223 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
2224 //add_stmt (top);
2226 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
2227 TREE_USED (target->as_label_decl ()) = 1;
2228 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
2229 if (loc)
2230 set_tree_location (stmt, loc);
2231 add_stmt (stmt);
2234 from c-typeck.cc:
2235 tree
2236 c_finish_goto_label (location_t loc, tree label)
2238 tree decl = lookup_label_for_goto (loc, label);
2239 if (!decl)
2240 return NULL_TREE;
2241 TREE_USED (decl) = 1;
2243 tree t = build1 (GOTO_EXPR, void_type_node, decl);
2244 SET_EXPR_LOCATION (t, loc);
2245 return add_stmt (t);
2252 /* Add a return statement to the function's statement list. */
2254 void
2255 playback::block::
2256 add_return (location *loc,
2257 rvalue *rvalue)
2259 tree modify_retval = NULL;
2260 tree return_type = m_func->get_return_type_as_tree ();
2261 if (rvalue)
2263 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
2264 tree t_rvalue = rvalue->as_tree ();
2265 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
2266 t_rvalue = build1 (CONVERT_EXPR,
2267 TREE_TYPE (t_lvalue),
2268 t_rvalue);
2269 modify_retval = build2 (MODIFY_EXPR, return_type,
2270 t_lvalue, t_rvalue);
2271 if (loc)
2272 set_tree_location (modify_retval, loc);
2274 tree return_stmt = build1 (RETURN_EXPR, return_type,
2275 modify_retval);
2276 if (loc)
2277 set_tree_location (return_stmt, loc);
2279 add_stmt (return_stmt);
2282 /* Helper function for playback::block::add_switch.
2283 Construct a case label for the given range, followed by a goto stmt
2284 to the given block, appending them to stmt list *ptr_t_switch_body. */
2286 static void
2287 add_case (tree *ptr_t_switch_body,
2288 tree t_low_value,
2289 tree t_high_value,
2290 playback::block *dest_block)
2292 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
2293 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
2295 tree t_case_label =
2296 build_case_label (t_low_value, t_high_value, t_label);
2297 append_to_statement_list (t_case_label, ptr_t_switch_body);
2299 tree t_goto_stmt =
2300 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
2301 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
2304 /* Add a switch statement to the function's statement list.
2306 We create a switch body, and populate it with case labels, each
2307 followed by a goto to the desired block. */
2309 void
2310 playback::block::
2311 add_switch (location *loc,
2312 rvalue *expr,
2313 block *default_block,
2314 const auto_vec <case_> *cases)
2316 /* Compare with:
2317 - c/c-typeck.cc: c_start_case
2318 - c-family/c-common.cc:c_add_case_label
2319 - java/expr.cc:expand_java_switch and expand_java_add_case
2320 We've already rejected overlaps and duplicates in
2321 libgccjit.cc:case_range_validator::validate. */
2323 tree t_expr = expr->as_tree ();
2324 tree t_type = TREE_TYPE (t_expr);
2326 tree t_switch_body = alloc_stmt_list ();
2328 int i;
2329 case_ *c;
2330 FOR_EACH_VEC_ELT (*cases, i, c)
2332 tree t_low_value = c->m_min_value->as_tree ();
2333 tree t_high_value = c->m_max_value->as_tree ();
2334 add_case (&t_switch_body, t_low_value, t_high_value, c->m_dest_block);
2336 /* Default label. */
2337 add_case (&t_switch_body, NULL_TREE, NULL_TREE, default_block);
2339 tree switch_stmt = build2 (SWITCH_EXPR, t_type, t_expr, t_switch_body);
2340 if (loc)
2341 set_tree_location (switch_stmt, loc);
2342 add_stmt (switch_stmt);
2345 /* Convert OPERANDS to a tree-based chain suitable for creating an
2346 extended asm stmt.
2347 Compare with c_parser_asm_operands. */
2349 static tree
2350 build_operand_chain (const auto_vec <playback::asm_operand> *operands)
2352 tree result = NULL_TREE;
2353 unsigned i;
2354 playback::asm_operand *asm_op;
2355 FOR_EACH_VEC_ELT (*operands, i, asm_op)
2357 tree name = build_string (asm_op->m_asm_symbolic_name);
2358 tree str = build_string (asm_op->m_constraint);
2359 tree value = asm_op->m_expr;
2360 result = chainon (result,
2361 build_tree_list (build_tree_list (name, str),
2362 value));
2364 return result;
2367 /* Convert CLOBBERS to a tree-based list suitable for creating an
2368 extended asm stmt.
2369 Compare with c_parser_asm_clobbers. */
2371 static tree
2372 build_clobbers (const auto_vec <const char *> *clobbers)
2374 tree list = NULL_TREE;
2375 unsigned i;
2376 const char *clobber;
2377 FOR_EACH_VEC_ELT (*clobbers, i, clobber)
2379 tree str = build_string (clobber);
2380 list = tree_cons (NULL_TREE, str, list);
2382 return list;
2385 /* Convert BLOCKS to a tree-based list suitable for creating an
2386 extended asm stmt.
2387 Compare with c_parser_asm_goto_operands. */
2389 static tree
2390 build_goto_operands (const auto_vec <playback::block *> *blocks)
2392 tree list = NULL_TREE;
2393 unsigned i;
2394 playback::block *b;
2395 FOR_EACH_VEC_ELT (*blocks, i, b)
2397 tree label = b->as_label_decl ();
2398 tree name = build_string (IDENTIFIER_POINTER (DECL_NAME (label)));
2399 TREE_USED (label) = 1;
2400 list = tree_cons (name, label, list);
2402 return nreverse (list);
2405 /* Add an extended asm statement to this block.
2407 Compare with c_parser_asm_statement (in c/c-parser.cc)
2408 and build_asm_expr (in c/c-typeck.cc). */
2410 void
2411 playback::block::add_extended_asm (location *loc,
2412 const char *asm_template,
2413 bool is_volatile,
2414 bool is_inline,
2415 const auto_vec <asm_operand> *outputs,
2416 const auto_vec <asm_operand> *inputs,
2417 const auto_vec <const char *> *clobbers,
2418 const auto_vec <block *> *goto_blocks)
2420 tree t_string = build_string (asm_template);
2421 tree t_outputs = build_operand_chain (outputs);
2422 tree t_inputs = build_operand_chain (inputs);
2423 tree t_clobbers = build_clobbers (clobbers);
2424 tree t_labels = build_goto_operands (goto_blocks);
2425 t_string
2426 = resolve_asm_operand_names (t_string, t_outputs, t_inputs, t_labels);
2427 tree asm_stmt
2428 = build5 (ASM_EXPR, void_type_node,
2429 t_string, t_outputs, t_inputs, t_clobbers, t_labels);
2431 /* asm statements without outputs, including simple ones, are treated
2432 as volatile. */
2433 ASM_VOLATILE_P (asm_stmt) = (outputs->length () == 0);
2434 ASM_INPUT_P (asm_stmt) = 0; /* extended asm stmts are not "simple". */
2435 ASM_INLINE_P (asm_stmt) = is_inline;
2436 if (is_volatile)
2437 ASM_VOLATILE_P (asm_stmt) = 1;
2438 if (loc)
2439 set_tree_location (asm_stmt, loc);
2440 add_stmt (asm_stmt);
2443 /* Constructor for gcc::jit::playback::block. */
2445 playback::block::
2446 block (function *func,
2447 const char *name)
2448 : m_func (func),
2449 m_stmts ()
2451 tree identifier;
2453 gcc_assert (func);
2454 // name can be NULL
2455 if (name)
2456 identifier = get_identifier (name);
2457 else
2458 identifier = NULL;
2459 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
2460 identifier, void_type_node);
2461 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
2462 m_label_expr = NULL;
2465 // This is basically std::lock_guard but it can call the private lock/unlock
2466 // members of playback::context.
2467 struct playback::context::scoped_lock
2469 scoped_lock (context &ctx) : m_ctx (&ctx) { m_ctx->lock (); }
2470 ~scoped_lock () { m_ctx->unlock (); }
2472 context *m_ctx;
2474 // Not movable or copyable.
2475 scoped_lock (scoped_lock &&) = delete;
2476 scoped_lock &operator= (scoped_lock &&) = delete;
2479 /* Compile a playback::context:
2481 - Use the context's options to cconstruct command-line options, and
2482 call into the rest of GCC (toplev::main).
2483 - Assuming it succeeds, we have a .s file.
2484 - We then run the "postprocess" vfunc:
2486 (A) In-memory compile ("gcc_jit_context_compile")
2488 For an in-memory compile we have the playback::compile_to_memory
2489 subclass; "postprocess" will convert the .s file to a .so DSO,
2490 and load it in memory (via dlopen), wrapping the result up as
2491 a jit::result and returning it.
2493 (B) Compile to file ("gcc_jit_context_compile_to_file")
2495 When compiling to a file, we have the playback::compile_to_file
2496 subclass; "postprocess" will either copy the .s file to the
2497 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
2498 the driver to convert it as necessary, copying the result. */
2500 void
2501 playback::context::
2502 compile ()
2504 JIT_LOG_SCOPE (get_logger ());
2506 const char *ctxt_progname;
2508 int keep_intermediates =
2509 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
2511 m_tempdir = new tempdir (get_logger (), keep_intermediates);
2512 if (!m_tempdir->create ())
2513 return;
2515 /* Call into the rest of gcc.
2516 For now, we have to assemble command-line options to pass into
2517 toplev::main, so that they can be parsed. */
2519 /* Pass in user-provided program name as argv0, if any, so that it
2520 makes it into GCC's "progname" global, used in various diagnostics. */
2521 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
2523 if (!ctxt_progname)
2524 ctxt_progname = "libgccjit.so";
2526 auto_vec <recording::requested_dump> requested_dumps;
2527 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
2529 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
2530 scoped_lock lock(*this);
2532 auto_string_vec fake_args;
2533 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
2534 if (errors_occurred ())
2535 return;
2537 /* This runs the compiler. */
2538 toplev toplev (get_timer (), /* external_timer */
2539 false); /* init_signals */
2540 enter_scope ("toplev::main");
2541 if (get_logger ())
2542 for (unsigned i = 0; i < fake_args.length (); i++)
2543 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
2544 toplev.main (fake_args.length (),
2545 const_cast <char **> (fake_args.address ()));
2546 exit_scope ("toplev::main");
2548 /* Extracting dumps makes use of the gcc::dump_manager, hence we
2549 need to do it between toplev::main (which creates the dump manager)
2550 and toplev::finalize (which deletes it). */
2551 extract_any_requested_dumps (&requested_dumps);
2553 /* Clean up the compiler. */
2554 enter_scope ("toplev::finalize");
2555 toplev.finalize ();
2556 exit_scope ("toplev::finalize");
2558 /* Ideally we would release the jit mutex here, but we can't yet since
2559 followup activities use timevars, which are global state. */
2561 if (errors_occurred ())
2562 return;
2564 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
2565 dump_generated_code ();
2567 /* We now have a .s file.
2569 Run any postprocessing steps. This will either convert the .s file to
2570 a .so DSO, and load it in memory (playback::compile_to_memory), or
2571 convert the .s file to the requested output format, and copy it to a
2572 given file (playback::compile_to_file). */
2573 postprocess (ctxt_progname);
2576 /* Implementation of class gcc::jit::playback::compile_to_memory,
2577 a subclass of gcc::jit::playback::context. */
2579 /* playback::compile_to_memory's trivial constructor. */
2581 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
2582 playback::context (ctxt),
2583 m_result (NULL)
2585 JIT_LOG_SCOPE (get_logger ());
2588 /* Implementation of the playback::context::process vfunc for compiling
2589 to memory.
2591 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
2592 wrapping the result up as a jit::result and returning it. */
2594 void
2595 playback::compile_to_memory::postprocess (const char *ctxt_progname)
2597 JIT_LOG_SCOPE (get_logger ());
2598 convert_to_dso (ctxt_progname);
2599 if (errors_occurred ())
2600 return;
2601 m_result = dlopen_built_dso ();
2604 /* Implementation of class gcc::jit::playback::compile_to_file,
2605 a subclass of gcc::jit::playback::context. */
2607 /* playback::compile_to_file's trivial constructor. */
2609 playback::compile_to_file::compile_to_file (recording::context *ctxt,
2610 enum gcc_jit_output_kind output_kind,
2611 const char *output_path) :
2612 playback::context (ctxt),
2613 m_output_kind (output_kind),
2614 m_output_path (output_path)
2616 JIT_LOG_SCOPE (get_logger ());
2619 /* Implementation of the playback::context::process vfunc for compiling
2620 to a file.
2622 Either copy the .s file to the given destination (for
2623 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
2624 as necessary, copying the result. */
2626 void
2627 playback::compile_to_file::postprocess (const char *ctxt_progname)
2629 JIT_LOG_SCOPE (get_logger ());
2631 /* The driver takes different actions based on the filename, so
2632 we provide a filename with an appropriate suffix for the
2633 output kind, and then copy it up to the user-provided path,
2634 rather than directly compiling it to the requested output path. */
2636 switch (m_output_kind)
2638 default:
2639 gcc_unreachable ();
2641 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
2642 copy_file (get_tempdir ()->get_path_s_file (),
2643 m_output_path);
2644 /* The .s file is automatically unlinked by tempdir::~tempdir. */
2645 break;
2647 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
2649 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
2650 "/fake.o",
2651 NULL);
2652 invoke_driver (ctxt_progname,
2653 get_tempdir ()->get_path_s_file (),
2654 tmp_o_path,
2655 TV_ASSEMBLE,
2656 false, /* bool shared, */
2657 false);/* bool run_linker */
2658 if (!errors_occurred ())
2660 copy_file (tmp_o_path,
2661 m_output_path);
2662 get_tempdir ()->add_temp_file (tmp_o_path);
2664 else
2665 free (tmp_o_path);
2667 break;
2669 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
2670 invoke_driver (ctxt_progname,
2671 get_tempdir ()->get_path_s_file (),
2672 get_tempdir ()->get_path_so_file (),
2673 TV_ASSEMBLE,
2674 true, /* bool shared, */
2675 true);/* bool run_linker */
2676 if (!errors_occurred ())
2677 copy_file (get_tempdir ()->get_path_so_file (),
2678 m_output_path);
2679 /* The .so file is automatically unlinked by tempdir::~tempdir. */
2680 break;
2682 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
2684 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
2685 "/fake.exe",
2686 NULL);
2687 invoke_driver (ctxt_progname,
2688 get_tempdir ()->get_path_s_file (),
2689 tmp_exe_path,
2690 TV_ASSEMBLE,
2691 false, /* bool shared, */
2692 true);/* bool run_linker */
2693 if (!errors_occurred ())
2695 copy_file (tmp_exe_path,
2696 m_output_path);
2697 get_tempdir ()->add_temp_file (tmp_exe_path);
2699 else
2700 free (tmp_exe_path);
2702 break;
2708 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2709 the "executable" bits).
2711 Any errors that occur are reported on the context and hence count as
2712 a failure of the compile.
2714 We can't in general hardlink or use "rename" from the tempdir since
2715 it might be on a different filesystem to the destination. For example,
2716 I get EXDEV: "Invalid cross-device link". */
2718 void
2719 playback::compile_to_file::copy_file (const char *src_path,
2720 const char *dst_path)
2722 JIT_LOG_SCOPE (get_logger ());
2723 if (get_logger ())
2725 get_logger ()->log ("src_path: %s", src_path);
2726 get_logger ()->log ("dst_path: %s", dst_path);
2729 FILE *f_in = NULL;
2730 FILE *f_out = NULL;
2731 size_t total_sz_in = 0;
2732 size_t total_sz_out = 0;
2733 char buf[4096];
2734 size_t sz_in;
2735 struct stat stat_buf;
2737 f_in = fopen (src_path, "rb");
2738 if (!f_in)
2740 add_error (NULL,
2741 "unable to open %s for reading: %s",
2742 src_path,
2743 xstrerror (errno));
2744 return;
2747 /* Use stat on the filedescriptor to get the mode,
2748 so that we can copy it over (in particular, the
2749 "executable" bits). */
2750 if (fstat (fileno (f_in), &stat_buf) == -1)
2752 add_error (NULL,
2753 "unable to fstat %s: %s",
2754 src_path,
2755 xstrerror (errno));
2756 fclose (f_in);
2757 return;
2760 f_out = fopen (dst_path, "wb");
2761 if (!f_out)
2763 add_error (NULL,
2764 "unable to open %s for writing: %s",
2765 dst_path,
2766 xstrerror (errno));
2767 fclose (f_in);
2768 return;
2771 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2773 total_sz_in += sz_in;
2774 size_t sz_out_remaining = sz_in;
2775 size_t sz_out_so_far = 0;
2776 while (sz_out_remaining)
2778 size_t sz_out = fwrite (buf + sz_out_so_far,
2780 sz_out_remaining,
2781 f_out);
2782 gcc_assert (sz_out <= sz_out_remaining);
2783 if (!sz_out)
2785 add_error (NULL,
2786 "error writing to %s: %s",
2787 dst_path,
2788 xstrerror (errno));
2789 fclose (f_in);
2790 fclose (f_out);
2791 return;
2793 total_sz_out += sz_out;
2794 sz_out_so_far += sz_out;
2795 sz_out_remaining -= sz_out;
2797 gcc_assert (sz_out_so_far == sz_in);
2800 if (!feof (f_in))
2801 add_error (NULL,
2802 "error reading from %s: %s",
2803 src_path,
2804 xstrerror (errno));
2806 fclose (f_in);
2808 gcc_assert (total_sz_in == total_sz_out);
2809 if (get_logger ())
2810 get_logger ()->log ("total bytes copied: %zu", total_sz_out);
2812 /* fchmod does not exist in Windows. */
2813 #ifndef _WIN32
2814 /* Set the permissions of the copy to those of the original file,
2815 in particular the "executable" bits. */
2816 if (fchmod (fileno (f_out), stat_buf.st_mode) == -1)
2817 add_error (NULL,
2818 "error setting mode of %s: %s",
2819 dst_path,
2820 xstrerror (errno));
2821 #endif
2823 fclose (f_out);
2826 /* Helper functions for gcc::jit::playback::context::compile. */
2828 /* This mutex guards gcc::jit::recording::context::compile, so that only
2829 one thread can be accessing the bulk of GCC's state at once. */
2831 static std::mutex jit_mutex;
2833 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2835 void
2836 playback::context::lock ()
2838 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2840 /* Acquire the big GCC mutex. */
2841 JIT_LOG_SCOPE (get_logger ());
2842 jit_mutex.lock ();
2843 gcc_assert (active_playback_ctxt == NULL);
2844 active_playback_ctxt = this;
2847 /* Release jit_mutex and clear the active playback ctxt. */
2849 void
2850 playback::context::unlock ()
2852 /* Release the big GCC mutex. */
2853 JIT_LOG_SCOPE (get_logger ());
2854 gcc_assert (active_playback_ctxt == this);
2855 active_playback_ctxt = NULL;
2856 jit_mutex.unlock ();
2859 /* Callback used by gcc::jit::playback::context::make_fake_args when
2860 invoking driver_get_configure_time_options.
2861 Populate a vec <char * > with the configure-time options. */
2863 static void
2864 append_arg_from_driver (const char *option, void *user_data)
2866 gcc_assert (option);
2867 gcc_assert (user_data);
2868 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2869 argvec->safe_push (concat ("-", option, NULL));
2872 /* Build a fake argv for toplev::main from the options set
2873 by the user on the context . */
2875 void
2876 playback::context::
2877 make_fake_args (vec <char *> *argvec,
2878 const char *ctxt_progname,
2879 vec <recording::requested_dump> *requested_dumps)
2881 JIT_LOG_SCOPE (get_logger ());
2883 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2884 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2886 ADD_ARG (ctxt_progname);
2887 ADD_ARG (get_path_c_file ());
2888 ADD_ARG ("-fPIC");
2890 /* Handle int options: */
2891 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2893 default:
2894 add_error (NULL,
2895 "unrecognized optimization level: %i",
2896 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2897 return;
2899 case 0:
2900 ADD_ARG ("-O0");
2901 break;
2903 case 1:
2904 ADD_ARG ("-O1");
2905 break;
2907 case 2:
2908 ADD_ARG ("-O2");
2909 break;
2911 case 3:
2912 ADD_ARG ("-O3");
2913 break;
2915 /* What about -Os? */
2917 /* Handle bool options: */
2918 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2919 ADD_ARG ("-g");
2921 /* Suppress timing (and other) info. */
2922 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2924 ADD_ARG ("-quiet");
2925 quiet_flag = 1;
2928 /* Aggressively garbage-collect, to shake out bugs: */
2929 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2931 ADD_ARG ("--param=ggc-min-expand=0");
2932 ADD_ARG ("--param=ggc-min-heapsize=0");
2935 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2937 ADD_ARG ("-fdump-tree-all");
2938 ADD_ARG ("-fdump-rtl-all");
2939 ADD_ARG ("-fdump-ipa-all");
2942 /* Add "-fdump-" options for any calls to
2943 gcc_jit_context_enable_dump. */
2945 int i;
2946 recording::requested_dump *d;
2947 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2949 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2950 ADD_ARG_TAKE_OWNERSHIP (arg);
2954 /* PR jit/64810: Add any target-specific default options
2955 from OPTION_DEFAULT_SPECS, normally provided by the driver
2956 in the non-jit case.
2958 The target-specific code can define OPTION_DEFAULT_SPECS:
2959 default command options in the form of spec macros for the
2960 driver to expand ().
2962 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2963 if not overriden, injects the defaults as extra arguments to
2964 cc1 etc.
2965 For the jit case, we need to add these arguments here. The
2966 input format (using the specs language) means that we have to run
2967 part of the driver code here (driver_get_configure_time_options).
2969 To avoid running the spec-expansion code every time, we just do
2970 it the first time (via a function-static flag), saving the result
2971 into a function-static vec.
2972 This flag and vec are global state (i.e. per-process).
2973 They are guarded by the jit mutex. */
2975 static bool have_configure_time_options = false;
2976 static vec <char *> configure_time_options;
2978 if (have_configure_time_options)
2979 log ("reusing cached configure-time options");
2980 else
2982 have_configure_time_options = true;
2983 log ("getting configure-time options from driver");
2984 driver_get_configure_time_options (append_arg_from_driver,
2985 &configure_time_options);
2988 int i;
2989 char *opt;
2991 if (get_logger ())
2992 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2993 log ("configure_time_options[%i]: %s", i, opt);
2995 /* configure_time_options should now contain the expanded options
2996 from OPTION_DEFAULT_SPECS (if any). */
2997 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2999 gcc_assert (opt);
3000 gcc_assert (opt[0] == '-');
3001 ADD_ARG (opt);
3005 if (get_timer ())
3006 ADD_ARG ("-ftime-report");
3008 /* Add any user-provided extra options, starting with any from
3009 parent contexts. */
3010 m_recording_ctxt->append_command_line_options (argvec);
3012 #undef ADD_ARG
3013 #undef ADD_ARG_TAKE_OWNERSHIP
3016 /* The second half of the implementation of gcc_jit_context_enable_dump.
3017 Iterate through the requested dumps, reading the underlying files
3018 into heap-allocated buffers, writing pointers to the buffers into
3019 the char ** pointers provided by client code.
3020 Client code is responsible for calling free on the results. */
3022 void
3023 playback::context::
3024 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
3026 JIT_LOG_SCOPE (get_logger ());
3028 int i;
3029 recording::requested_dump *d;
3030 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
3032 dump_file_info *dfi;
3033 char *filename;
3034 char *content;
3036 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
3037 if (!dfi)
3039 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
3040 continue;
3043 filename = g->get_dumps ()->get_dump_file_name (dfi);
3044 content = read_dump_file (filename);
3045 *(d->m_out_ptr) = content;
3046 m_tempdir->add_temp_file (filename);
3050 /* Helper function for playback::context::extract_any_requested_dumps
3051 (itself for use in implementation of gcc_jit_context_enable_dump).
3053 Attempt to read the complete file at the given path, returning the
3054 bytes found there as a buffer.
3055 The caller is responsible for calling free on the result.
3056 Errors will be reported on the context, and lead to NULL being
3057 returned; an out-of-memory error will terminate the process. */
3059 char *
3060 playback::context::read_dump_file (const char *path)
3062 char *result = NULL;
3063 size_t total_sz = 0;
3064 char buf[4096];
3065 size_t sz;
3066 FILE *f_in;
3068 f_in = fopen (path, "r");
3069 if (!f_in)
3071 add_error (NULL, "unable to open %s for reading", path);
3072 return NULL;
3075 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
3077 size_t old_total_sz = total_sz;
3078 total_sz += sz;
3079 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
3080 memcpy (result + old_total_sz, buf, sz);
3083 if (!feof (f_in))
3085 add_error (NULL, "error reading from %s", path);
3086 free (result);
3087 fclose (f_in);
3088 return NULL;
3091 fclose (f_in);
3093 if (result)
3095 result[total_sz] = '\0';
3096 return result;
3098 else
3099 return xstrdup ("");
3102 /* Part of playback::context::compile ().
3104 We have a .s file; we want a .so file.
3105 We could reuse parts of gcc/gcc.cc to do this.
3106 For now, just use the driver binary from the install, as
3107 named in gcc-driver-name.h
3108 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
3110 void
3111 playback::context::
3112 convert_to_dso (const char *ctxt_progname)
3114 JIT_LOG_SCOPE (get_logger ());
3116 invoke_driver (ctxt_progname,
3117 m_tempdir->get_path_s_file (),
3118 m_tempdir->get_path_so_file (),
3119 TV_ASSEMBLE,
3120 true, /* bool shared, */
3121 true);/* bool run_linker */
3124 static const char * const gcc_driver_name = GCC_DRIVER_NAME;
3126 void
3127 playback::context::
3128 invoke_driver (const char *ctxt_progname,
3129 const char *input_file,
3130 const char *output_file,
3131 timevar_id_t tv_id,
3132 bool shared,
3133 bool run_linker)
3135 JIT_LOG_SCOPE (get_logger ());
3137 bool embedded_driver
3138 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
3140 /* Currently this lumps together both assembling and linking into
3141 TV_ASSEMBLE. */
3142 auto_timevar assemble_timevar (get_timer (), tv_id);
3143 auto_string_vec argvec;
3144 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
3146 ADD_ARG (gcc_driver_name);
3148 add_multilib_driver_arguments (&argvec);
3150 if (shared)
3151 ADD_ARG ("-shared");
3153 if (!run_linker)
3154 ADD_ARG ("-c");
3156 ADD_ARG (input_file);
3157 ADD_ARG ("-o");
3158 ADD_ARG (output_file);
3160 /* Don't use the linker plugin.
3161 If running with just a "make" and not a "make install", then we'd
3162 run into
3163 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
3164 libto_plugin is a .la at build time, with it becoming installed with
3165 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
3166 time. */
3167 ADD_ARG ("-fno-use-linker-plugin");
3169 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
3170 /* macOS's linker defaults to treating undefined symbols as errors.
3171 If the context has any imported functions or globals they will be
3172 undefined until the .so is dynamically-linked into the process.
3173 Ensure that the driver passes in "-undefined dynamic_lookup" to the
3174 linker. */
3175 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
3176 #endif
3178 if (0)
3179 ADD_ARG ("-v");
3181 /* Add any user-provided driver extra options. */
3183 m_recording_ctxt->append_driver_options (&argvec);
3185 #undef ADD_ARG
3187 /* pex_one's error-handling requires pname to be non-NULL. */
3188 gcc_assert (ctxt_progname);
3190 if (get_logger ())
3191 for (unsigned i = 0; i < argvec.length (); i++)
3192 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
3194 if (embedded_driver)
3195 invoke_embedded_driver (&argvec);
3196 else
3197 invoke_external_driver (ctxt_progname, &argvec);
3200 void
3201 playback::context::
3202 invoke_embedded_driver (const vec <char *> *argvec)
3204 JIT_LOG_SCOPE (get_logger ());
3205 driver d (true, /* can_finalize */
3206 false); /* debug */
3207 int result = d.main (argvec->length (),
3208 const_cast <char **> (argvec->address ()));
3209 d.finalize ();
3210 if (result)
3211 add_error (NULL, "error invoking gcc driver");
3214 void
3215 playback::context::
3216 invoke_external_driver (const char *ctxt_progname,
3217 vec <char *> *argvec)
3219 JIT_LOG_SCOPE (get_logger ());
3220 const char *errmsg;
3221 int exit_status = 0;
3222 int err = 0;
3224 /* pex argv arrays are NULL-terminated. */
3225 argvec->safe_push (NULL);
3227 errmsg = pex_one (PEX_SEARCH, /* int flags, */
3228 gcc_driver_name,
3229 const_cast <char *const *> (argvec->address ()),
3230 ctxt_progname, /* const char *pname */
3231 NULL, /* const char *outname */
3232 NULL, /* const char *errname */
3233 &exit_status, /* int *status */
3234 &err); /* int *err*/
3235 if (errmsg)
3237 add_error (NULL, "error invoking gcc driver: %s", errmsg);
3238 return;
3241 /* pex_one can return a NULL errmsg when the executable wasn't
3242 found (or doesn't exist), so trap these cases also. */
3243 if (exit_status || err)
3245 add_error (NULL,
3246 "error invoking gcc driver: exit_status: %i err: %i",
3247 exit_status, err);
3248 add_error (NULL,
3249 "whilst attempting to run a driver named: %s",
3250 gcc_driver_name);
3251 add_error (NULL,
3252 "PATH was: %s",
3253 getenv ("PATH"));
3254 return;
3258 /* Extract the target-specific MULTILIB_DEFAULTS to
3259 multilib_defaults_raw for use by
3260 playback::context::add_multilib_driver_arguments (). */
3262 #ifndef MULTILIB_DEFAULTS
3263 #define MULTILIB_DEFAULTS { "" }
3264 #endif
3266 static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
3268 /* Helper function for playback::context::invoke_driver ().
3270 32-bit and 64-bit multilib peer builds of libgccjit.so may share
3271 a driver binary. We need to pass in options to the shared driver
3272 to get the appropriate assembler/linker options for this multilib
3273 peer. */
3275 void
3276 playback::context::
3277 add_multilib_driver_arguments (vec <char *> *argvec)
3279 JIT_LOG_SCOPE (get_logger ());
3281 /* Add copies of the arguments in multilib_defaults_raw to argvec,
3282 prepending each with a "-". */
3283 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
3284 if (multilib_defaults_raw[i][0])
3285 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
3288 /* Dynamically-link the built DSO file into this process, using dlopen.
3289 Wrap it up within a jit::result *, and return that.
3290 Return NULL if any errors occur, reporting them on this context. */
3292 result *
3293 playback::context::
3294 dlopen_built_dso ()
3296 JIT_LOG_SCOPE (get_logger ());
3297 auto_timevar load_timevar (get_timer (), TV_LOAD);
3298 result::handle handle = NULL;
3299 result *result_obj = NULL;
3301 #ifdef _WIN32
3302 /* Clear any existing error. */
3303 SetLastError(0);
3305 handle = LoadLibrary(m_tempdir->get_path_so_file ());
3306 if (GetLastError() != 0) {
3307 print_last_error();
3309 #else
3310 const char *error = NULL;
3311 /* Clear any existing error. */
3312 dlerror ();
3314 handle = dlopen (m_tempdir->get_path_so_file (),
3315 RTLD_NOW | RTLD_LOCAL);
3316 if ((error = dlerror()) != NULL) {
3317 add_error (NULL, "%s", error);
3319 #endif
3321 if (handle)
3323 /* We've successfully dlopened the result; create a
3324 jit::result object to wrap it.
3326 We're done with the tempdir for now, but if the user
3327 has requested debugging, the user's debugger might not
3328 be capable of dealing with the .so file being unlinked
3329 immediately, so keep it around until after the result
3330 is released. We do this by handing over ownership of
3331 the jit::tempdir to the result. See PR jit/64206. */
3332 tempdir *handover_tempdir;
3333 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
3335 handover_tempdir = m_tempdir;
3336 m_tempdir = NULL;
3337 /* The tempdir will eventually be cleaned up in the
3338 jit::result's dtor. */
3339 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
3340 " handing over tempdir to jit::result");
3342 else
3344 handover_tempdir = NULL;
3345 /* ... and retain ownership of m_tempdir so we clean it
3346 up it the playback::context's dtor. */
3347 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
3348 " retaining ownership of tempdir");
3351 result_obj = new result (get_logger (), handle, handover_tempdir);
3353 else
3354 result_obj = NULL;
3356 return result_obj;
3359 /* Top-level hook for playing back a recording context.
3361 This plays back m_recording_ctxt, and, if no errors
3362 occurred builds statement lists for and then postprocesses
3363 every function in the result. */
3365 void
3366 playback::context::
3367 replay ()
3369 JIT_LOG_SCOPE (get_logger ());
3371 init_types ();
3373 /* Replay the recorded events: */
3374 timevar_push (TV_JIT_REPLAY);
3376 /* Ensure that builtins that could be needed during optimization
3377 get created ahead of time. */
3378 builtins_manager *bm = m_recording_ctxt->get_builtins_manager ();
3379 bm->ensure_optimization_builtins_exist ();
3381 m_recording_ctxt->replay_into (this);
3383 /* Clean away the temporary references from recording objects
3384 to playback objects. We have to do this now since the
3385 latter are GC-allocated, but the former don't mark these
3386 refs. Hence we must stop using them before the GC can run. */
3387 m_recording_ctxt->disassociate_from_playback ();
3389 /* The builtins_manager is associated with the recording::context
3390 and might be reused for future compiles on other playback::contexts,
3391 but its m_attributes array is not GTY-labeled and hence will become
3392 nonsense if the GC runs. Purge this state. */
3393 bm->finish_playback ();
3395 timevar_pop (TV_JIT_REPLAY);
3397 if (!errors_occurred ())
3399 int i;
3400 function *func;
3401 tree global;
3402 /* No GC can happen yet; process the cached source locations. */
3403 handle_locations ();
3405 /* Finalize globals. See how FORTRAN 95 does it in gfc_be_parse_file()
3406 for a simple reference. */
3407 FOR_EACH_VEC_ELT (m_globals, i, global)
3408 rest_of_decl_compilation (global, true, true);
3410 wrapup_global_declarations (m_globals.address(), m_globals.length());
3412 /* We've now created tree nodes for the stmts in the various blocks
3413 in each function, but we haven't built each function's single stmt
3414 list yet. Do so now. */
3415 FOR_EACH_VEC_ELT (m_functions, i, func)
3416 func->build_stmt_list ();
3418 /* No GC can have happened yet. */
3420 /* Postprocess the functions. This could trigger GC. */
3421 FOR_EACH_VEC_ELT (m_functions, i, func)
3423 gcc_assert (func);
3424 func->postprocess ();
3429 /* Dump the generated .s file to stderr. */
3431 void
3432 playback::context::
3433 dump_generated_code ()
3435 JIT_LOG_SCOPE (get_logger ());
3436 char buf[4096];
3437 size_t sz;
3438 FILE *f_in = fopen (get_path_s_file (), "r");
3439 if (!f_in)
3440 return;
3442 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
3443 fwrite (buf, 1, sz, stderr);
3445 fclose (f_in);
3448 /* Get the supposed path of the notional "fake.c" file within the
3449 tempdir. This file doesn't exist, but the rest of the compiler
3450 needs a name. */
3452 const char *
3453 playback::context::
3454 get_path_c_file () const
3456 return m_tempdir->get_path_c_file ();
3459 /* Get the path of the assembler output file "fake.s" file within the
3460 tempdir. */
3462 const char *
3463 playback::context::
3464 get_path_s_file () const
3466 return m_tempdir->get_path_s_file ();
3469 /* Get the path of the DSO object file "fake.so" file within the
3470 tempdir. */
3472 const char *
3473 playback::context::
3474 get_path_so_file () const
3476 return m_tempdir->get_path_so_file ();
3479 /* qsort comparator for comparing pairs of playback::source_line *,
3480 ordering them by line number. */
3482 static int
3483 line_comparator (const void *lhs, const void *rhs)
3485 const playback::source_line *line_lhs = \
3486 *static_cast<const playback::source_line * const*> (lhs);
3487 const playback::source_line *line_rhs = \
3488 *static_cast<const playback::source_line * const*> (rhs);
3489 return line_lhs->get_line_num () - line_rhs->get_line_num ();
3492 /* qsort comparator for comparing pairs of playback::location *,
3493 ordering them by column number. */
3495 static int
3496 location_comparator (const void *lhs, const void *rhs)
3498 const playback::location *loc_lhs = \
3499 *static_cast<const playback::location * const *> (lhs);
3500 const playback::location *loc_rhs = \
3501 *static_cast<const playback::location * const *> (rhs);
3502 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
3505 /* Initialize the NAME_TYPE of the primitive types as well as some
3506 others. */
3507 void
3508 playback::context::
3509 init_types ()
3511 /* See lto_init () in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc
3512 for reference. If TYPE_NAME is not set, debug info will not contain types */
3513 #define NAME_TYPE(t,n) \
3514 if (t) \
3515 TYPE_NAME (t) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, \
3516 get_identifier (n), t)
3518 NAME_TYPE (integer_type_node, "int");
3519 NAME_TYPE (char_type_node, "char");
3520 NAME_TYPE (long_integer_type_node, "long int");
3521 NAME_TYPE (unsigned_type_node, "unsigned int");
3522 NAME_TYPE (long_unsigned_type_node, "long unsigned int");
3523 NAME_TYPE (long_long_integer_type_node, "long long int");
3524 NAME_TYPE (long_long_unsigned_type_node, "long long unsigned int");
3525 NAME_TYPE (short_integer_type_node, "short int");
3526 NAME_TYPE (short_unsigned_type_node, "short unsigned int");
3527 if (signed_char_type_node != char_type_node)
3528 NAME_TYPE (signed_char_type_node, "signed char");
3529 if (unsigned_char_type_node != char_type_node)
3530 NAME_TYPE (unsigned_char_type_node, "unsigned char");
3531 NAME_TYPE (float_type_node, "float");
3532 NAME_TYPE (double_type_node, "double");
3533 NAME_TYPE (long_double_type_node, "long double");
3534 NAME_TYPE (void_type_node, "void");
3535 NAME_TYPE (boolean_type_node, "bool");
3536 NAME_TYPE (complex_float_type_node, "complex float");
3537 NAME_TYPE (complex_double_type_node, "complex double");
3538 NAME_TYPE (complex_long_double_type_node, "complex long double");
3540 m_const_char_ptr = build_pointer_type(
3541 build_qualified_type (char_type_node, TYPE_QUAL_CONST));
3543 NAME_TYPE (m_const_char_ptr, "char");
3544 NAME_TYPE (size_type_node, "size_t");
3545 NAME_TYPE (fileptr_type_node, "FILE");
3546 #undef NAME_TYPE
3549 /* Our API allows locations to be created in arbitrary orders, but the
3550 linemap API requires locations to be created in ascending order
3551 as if we were tokenizing files.
3553 This hook sorts all of the locations that have been created, and
3554 calls into the linemap API, creating linemap entries in sorted order
3555 for our locations. */
3557 void
3558 playback::context::
3559 handle_locations ()
3561 /* Create the source code locations, following the ordering rules
3562 imposed by the linemap API.
3564 line_table is a global. */
3565 JIT_LOG_SCOPE (get_logger ());
3566 int i;
3567 source_file *file;
3569 FOR_EACH_VEC_ELT (m_source_files, i, file)
3571 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
3573 /* Sort lines by ascending line numbers. */
3574 file->m_source_lines.qsort (&line_comparator);
3576 int j;
3577 source_line *line;
3578 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
3580 int k;
3581 location *loc;
3583 /* Sort locations in line by ascending column numbers. */
3584 line->m_locations.qsort (&location_comparator);
3586 /* Determine maximum column within this line. */
3587 gcc_assert (line->m_locations.length () > 0);
3588 location *final_column =
3589 line->m_locations[line->m_locations.length () - 1];
3590 int max_col = final_column->get_column_num ();
3592 linemap_line_start (line_table, line->get_line_num (), max_col);
3593 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
3595 loc->m_srcloc = \
3596 linemap_position_for_column (line_table, loc->get_column_num ());
3600 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
3603 /* line_table should now be populated; every playback::location should
3604 now have an m_srcloc. */
3606 /* Now assign them to tree nodes as appropriate. */
3607 std::pair<tree, location *> *cached_location;
3609 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
3611 tree t = cached_location->first;
3612 location_t srcloc = cached_location->second->m_srcloc;
3614 /* This covers expressions: */
3615 if (CAN_HAVE_LOCATION_P (t))
3616 SET_EXPR_LOCATION (t, srcloc);
3617 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
3618 DECL_SOURCE_LOCATION (t) = srcloc;
3619 else
3621 /* Don't know how to set location on this node. */
3626 /* We handle errors on a playback::context by adding them to the
3627 corresponding recording::context. */
3629 void
3630 playback::context::
3631 add_error (location *loc, const char *fmt, ...)
3633 va_list ap;
3634 va_start (ap, fmt);
3635 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
3636 fmt, ap);
3637 va_end (ap);
3640 /* We handle errors on a playback::context by adding them to the
3641 corresponding recording::context. */
3643 void
3644 playback::context::
3645 add_error_va (location *loc, const char *fmt, va_list ap)
3647 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
3648 fmt, ap);
3651 /* Report a diagnostic up to the jit context as an error,
3652 so that the compilation is treated as a failure.
3653 For now, any kind of diagnostic is treated as an error by the jit
3654 API. */
3656 void
3657 playback::context::
3658 add_diagnostic (diagnostic_context *diag_context,
3659 const diagnostic_info &diagnostic)
3661 /* At this point the text has been formatted into the pretty-printer's
3662 output buffer. */
3663 pretty_printer *pp = diag_context->printer;
3664 const char *text = pp_formatted_text (pp);
3666 /* Get location information (if any) from the diagnostic.
3667 The recording::context::add_error[_va] methods require a
3668 recording::location. We can't lookup the playback::location
3669 from the file/line/column since any playback location instances
3670 may have been garbage-collected away by now, so instead we create
3671 another recording::location directly. */
3672 location_t gcc_loc = diagnostic_location (&diagnostic);
3673 recording::location *rec_loc = NULL;
3674 if (gcc_loc)
3676 expanded_location exploc = expand_location (gcc_loc);
3677 if (exploc.file)
3678 rec_loc = m_recording_ctxt->new_location (exploc.file,
3679 exploc.line,
3680 exploc.column,
3681 false);
3684 m_recording_ctxt->add_error (rec_loc, "%s", text);
3685 pp_clear_output_area (pp);
3688 /* Dealing with the linemap API. */
3690 /* Construct a playback::location for a recording::location, if it
3691 doesn't exist already. */
3693 playback::location *
3694 playback::context::
3695 new_location (recording::location *rloc,
3696 const char *filename,
3697 int line,
3698 int column)
3700 /* Get the source_file for filename, creating if necessary. */
3701 source_file *src_file = get_source_file (filename);
3702 /* Likewise for the line within the file. */
3703 source_line *src_line = src_file->get_source_line (line);
3704 /* Likewise for the column within the line. */
3705 location *loc = src_line->get_location (rloc, column);
3706 return loc;
3709 /* Deferred setting of the location for a given tree, by adding the
3710 (tree, playback::location) pair to a list of deferred associations.
3711 We will actually set the location on the tree later on once
3712 the location_t for the playback::location exists. */
3714 void
3715 playback::context::
3716 set_tree_location (tree t, location *loc)
3718 gcc_assert (loc);
3719 m_cached_locations.safe_push (std::make_pair (t, loc));
3723 /* Construct a playback::source_file for the given source
3724 filename, if it doesn't exist already. */
3726 playback::source_file *
3727 playback::context::
3728 get_source_file (const char *filename)
3730 /* Locate the file.
3731 For simplicitly, this is currently a linear search.
3732 Replace with a hash if this shows up in the profile. */
3733 int i;
3734 source_file *file;
3735 tree ident_filename = get_identifier (filename);
3737 FOR_EACH_VEC_ELT (m_source_files, i, file)
3738 if (file->filename_as_tree () == ident_filename)
3739 return file;
3741 /* Not found. */
3742 file = new source_file (ident_filename);
3743 m_source_files.safe_push (file);
3744 return file;
3747 /* Constructor for gcc::jit::playback::source_file. */
3749 playback::source_file::source_file (tree filename) :
3750 m_source_lines (),
3751 m_filename (filename)
3755 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3756 GC-ed. */
3758 void
3759 playback::source_file::finalizer ()
3761 m_source_lines.release ();
3764 /* Construct a playback::source_line for the given line
3765 within this source file, if one doesn't exist already. */
3767 playback::source_line *
3768 playback::source_file::
3769 get_source_line (int line_num)
3771 /* Locate the line.
3772 For simplicitly, this is currently a linear search.
3773 Replace with a hash if this shows up in the profile. */
3774 int i;
3775 source_line *line;
3777 FOR_EACH_VEC_ELT (m_source_lines, i, line)
3778 if (line->get_line_num () == line_num)
3779 return line;
3781 /* Not found. */
3782 line = new source_line (this, line_num);
3783 m_source_lines.safe_push (line);
3784 return line;
3787 /* Constructor for gcc::jit::playback::source_line. */
3789 playback::source_line::source_line (source_file *file, int line_num) :
3790 m_locations (),
3791 m_source_file (file),
3792 m_line_num (line_num)
3796 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3797 GC-ed. */
3799 void
3800 playback::source_line::finalizer ()
3802 m_locations.release ();
3805 /* Construct a playback::location for the given column
3806 within this line of a specific source file, if one doesn't exist
3807 already. */
3809 playback::location *
3810 playback::source_line::
3811 get_location (recording::location *rloc, int column_num)
3813 int i;
3814 location *loc;
3816 /* Another linear search that probably should be a hash table. */
3817 FOR_EACH_VEC_ELT (m_locations, i, loc)
3818 if (loc->get_column_num () == column_num)
3819 return loc;
3821 /* Not found. */
3822 loc = new location (rloc, this, column_num);
3823 m_locations.safe_push (loc);
3824 return loc;
3827 /* Constructor for gcc::jit::playback::location. */
3829 playback::location::location (recording::location *loc,
3830 source_line *line,
3831 int column_num) :
3832 m_srcloc (UNKNOWN_LOCATION),
3833 m_recording_loc (loc),
3834 m_line (line),
3835 m_column_num(column_num)
3839 /* The active gcc::jit::playback::context instance. This is a singleton,
3840 guarded by jit_mutex. */
3842 playback::context *active_playback_ctxt;
3844 } // namespace gcc::jit
3846 } // namespace gcc