]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/jit/jit-playback.c
c++: Tuple of self-dependent classes [PR96926]
[thirdparty/gcc.git] / gcc / jit / jit-playback.c
CommitLineData
35485da9 1/* Internals of libgccjit: classes for playing back recorded API calls.
99dee823 2 Copyright (C) 2013-2021 Free Software Foundation, Inc.
35485da9
DM
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
2adfab87 24#include "target.h"
2adfab87 25#include "tree.h"
2adfab87
AM
26#include "stringpool.h"
27#include "cgraph.h"
35485da9 28#include "dumpfile.h"
35485da9 29#include "toplev.h"
35485da9 30#include "tree-cfg.h"
35485da9 31#include "convert.h"
35485da9
DM
32#include "stor-layout.h"
33#include "print-tree.h"
34#include "gimplify.h"
35#include "gcc-driver-name.h"
eeafb319 36#include "attribs.h"
463366a0 37#include "context.h"
860e981c 38#include "fold-const.h"
98086b2b 39#include "opt-suggestions.h"
2cb844ce 40#include "gcc.h"
6b5423a5 41#include "diagnostic.h"
421d0d0f 42#include "stmt.h"
35485da9 43
1c652ccb
IB
44#include <pthread.h>
45
35485da9 46#include "jit-playback.h"
56dea35f 47#include "jit-result.h"
eeafb319 48#include "jit-builtins.h"
d1e5f2c7 49#include "jit-tempdir.h"
35485da9 50
c83027f3
NB
51#ifdef _WIN32
52#include "jit-w32.h"
53#endif
54
ee118c14
AC
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)
35485da9
DM
62
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.
66
67 Hence we provide this dummy one, with the requirement that any casts
68 are handled before reaching this. */
69extern tree convert (tree type, tree expr);
70
71tree
72convert (tree dst_type, tree expr)
73{
74 gcc_assert (gcc::jit::active_playback_ctxt);
75 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
76 fprintf (stderr, "input expression:\n");
77 debug_tree (expr);
78 fprintf (stderr, "requested type:\n");
79 debug_tree (dst_type);
80 return error_mark_node;
81}
82
83namespace gcc {
84namespace jit {
85
86/**********************************************************************
87 Playback.
88 **********************************************************************/
89
421d0d0f
DM
90/* Build a STRING_CST tree for STR, or return NULL if it is NULL.
91 The TREE_TYPE is not initialized. */
92
93static tree
94build_string (const char *str)
95{
96 if (str)
97 return ::build_string (strlen (str), str);
98 else
99 return NULL_TREE;
100}
101
35485da9
DM
102/* The constructor for gcc::jit::playback::context. */
103
104playback::context::context (recording::context *ctxt)
eb4c16eb
DM
105 : log_user (ctxt->get_logger ()),
106 m_recording_ctxt (ctxt),
d1e5f2c7 107 m_tempdir (NULL),
35485da9
DM
108 m_const_char_ptr (NULL)
109{
eb4c16eb 110 JIT_LOG_SCOPE (get_logger ());
35485da9 111 m_functions.create (0);
791cfef8 112 m_globals.create (0);
35485da9
DM
113 m_source_files.create (0);
114 m_cached_locations.create (0);
115}
116
117/* The destructor for gcc::jit::playback::context. */
118
119playback::context::~context ()
120{
eb4c16eb 121 JIT_LOG_SCOPE (get_logger ());
d2286af3
DM
122
123 /* Normally the playback::context is responsible for cleaning up the
124 tempdir (including "fake.so" within the filesystem).
125
126 In the normal case, clean it up now.
127
128 However m_tempdir can be NULL if the context has handed over
129 responsibility for the tempdir cleanup to the jit::result object, so
130 that the cleanup can be delayed (see PR jit/64206). If that's the
131 case this "delete NULL;" is a no-op. */
132 delete m_tempdir;
133
35485da9
DM
134 m_functions.release ();
135}
136
137/* A playback::context can reference GC-managed pointers. Mark them
138 ("by hand", rather than by gengtype).
139
140 This is called on the active playback context (if any) by the
141 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
142
143void
144playback::context::
145gt_ggc_mx ()
146{
147 int i;
148 function *func;
149 FOR_EACH_VEC_ELT (m_functions, i, func)
150 {
151 if (ggc_test_and_set_mark (func))
152 func->gt_ggc_mx ();
153 }
154}
155
156/* Given an enum gcc_jit_types value, get a "tree" type. */
157
158static tree
159get_tree_node_for_type (enum gcc_jit_types type_)
160{
161 switch (type_)
162 {
163 case GCC_JIT_TYPE_VOID:
164 return void_type_node;
165
166 case GCC_JIT_TYPE_VOID_PTR:
167 return ptr_type_node;
168
169 case GCC_JIT_TYPE_BOOL:
170 return boolean_type_node;
171
172 case GCC_JIT_TYPE_CHAR:
173 return char_type_node;
174 case GCC_JIT_TYPE_SIGNED_CHAR:
175 return signed_char_type_node;
176 case GCC_JIT_TYPE_UNSIGNED_CHAR:
177 return unsigned_char_type_node;
178
179 case GCC_JIT_TYPE_SHORT:
180 return short_integer_type_node;
181 case GCC_JIT_TYPE_UNSIGNED_SHORT:
182 return short_unsigned_type_node;
183
184 case GCC_JIT_TYPE_CONST_CHAR_PTR:
185 {
186 tree const_char = build_qualified_type (char_type_node,
187 TYPE_QUAL_CONST);
188 return build_pointer_type (const_char);
189 }
190
191 case GCC_JIT_TYPE_INT:
192 return integer_type_node;
193 case GCC_JIT_TYPE_UNSIGNED_INT:
194 return unsigned_type_node;
195
196 case GCC_JIT_TYPE_LONG:
197 return long_integer_type_node;
198 case GCC_JIT_TYPE_UNSIGNED_LONG:
199 return long_unsigned_type_node;
200
201 case GCC_JIT_TYPE_LONG_LONG:
202 return long_long_integer_type_node;
203 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
204 return long_long_unsigned_type_node;
205
206 case GCC_JIT_TYPE_FLOAT:
207 return float_type_node;
208 case GCC_JIT_TYPE_DOUBLE:
209 return double_type_node;
210 case GCC_JIT_TYPE_LONG_DOUBLE:
211 return long_double_type_node;
212
213 case GCC_JIT_TYPE_SIZE_T:
214 return size_type_node;
215
216 case GCC_JIT_TYPE_FILE_PTR:
217 return fileptr_type_node;
eeafb319
DM
218
219 case GCC_JIT_TYPE_COMPLEX_FLOAT:
220 return complex_float_type_node;
221 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
222 return complex_double_type_node;
223 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
224 return complex_long_double_type_node;
35485da9
DM
225 }
226
227 return NULL;
228}
229
230/* Construct a playback::type instance (wrapping a tree) for the given
231 enum value. */
232
233playback::type *
234playback::context::
235get_type (enum gcc_jit_types type_)
236{
237 tree type_node = get_tree_node_for_type (type_);
01512446 238 if (type_node == NULL)
35485da9 239 {
01512446 240 add_error (NULL, "unrecognized (enum gcc_jit_types) value: %i", type_);
35485da9
DM
241 return NULL;
242 }
243
244 return new type (type_node);
245}
246
247/* Construct a playback::type instance (wrapping a tree) for the given
248 array type. */
249
250playback::type *
251playback::context::
252new_array_type (playback::location *loc,
253 playback::type *element_type,
254 int num_elements)
255{
256 gcc_assert (element_type);
257
258 tree t = build_array_type_nelts (element_type->as_tree (),
259 num_elements);
260 layout_type (t);
261
262 if (loc)
263 set_tree_location (t, loc);
264
265 return new type (t);
266}
267
268/* Construct a playback::field instance (wrapping a tree). */
269
270playback::field *
271playback::context::
272new_field (location *loc,
273 type *type,
274 const char *name)
275{
276 gcc_assert (type);
277 gcc_assert (name);
278
279 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
280 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
281 get_identifier (name), type->as_tree ());
282
283 if (loc)
284 set_tree_location (decl, loc);
285
286 return new field (decl);
287}
288
ee118c14
AC
289/* Construct a playback::bitfield instance (wrapping a tree). */
290
291playback::field *
292playback::context::
293new_bitfield (location *loc,
294 type *type,
295 int width,
296 const char *name)
297{
298 gcc_assert (type);
299 gcc_assert (name);
300 gcc_assert (width);
301
302 /* compare with c/c-decl.c:grokfield, grokdeclarator and
303 check_bitfield_type_and_width. */
304
305 tree tree_type = type->as_tree ();
306 gcc_assert (INTEGRAL_TYPE_P (tree_type));
307 tree tree_width = build_int_cst (integer_type_node, width);
308 if (compare_tree_int (tree_width, TYPE_PRECISION (tree_type)) > 0)
309 {
310 add_error (
311 loc,
312 "width of bit-field %s (width: %i) is wider than its type (width: %i)",
313 name, width, TYPE_PRECISION (tree_type));
314 return NULL;
315 }
316
317 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
318 get_identifier (name), type->as_tree ());
319 DECL_NONADDRESSABLE_P (decl) = true;
320 DECL_INITIAL (decl) = tree_width;
321 SET_DECL_JIT_BIT_FIELD (decl);
322
323 if (loc)
324 set_tree_location (decl, loc);
325
326 return new field (decl);
327}
328
35485da9
DM
329/* Construct a playback::compound_type instance (wrapping a tree). */
330
331playback::compound_type *
332playback::context::
333new_compound_type (location *loc,
334 const char *name,
335 bool is_struct) /* else is union */
336{
337 gcc_assert (name);
338
339 /* Compare with c/c-decl.c: start_struct. */
340
341 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
342 TYPE_NAME (t) = get_identifier (name);
343 TYPE_SIZE (t) = 0;
344
345 if (loc)
346 set_tree_location (t, loc);
347
348 return new compound_type (t);
349}
350
351void
b957b2e0 352playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
35485da9
DM
353{
354 /* Compare with c/c-decl.c: finish_struct. */
355 tree t = as_tree ();
356
357 tree fieldlist = NULL;
b957b2e0 358 for (unsigned i = 0; i < fields->length (); i++)
35485da9 359 {
b957b2e0 360 field *f = (*fields)[i];
ee118c14
AC
361 tree x = f->as_tree ();
362 DECL_CONTEXT (x) = t;
363 if (DECL_JIT_BIT_FIELD (x))
364 {
365 unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (x));
366 DECL_SIZE (x) = bitsize_int (width);
367 DECL_BIT_FIELD (x) = 1;
368 }
369 fieldlist = chainon (x, fieldlist);
35485da9
DM
370 }
371 fieldlist = nreverse (fieldlist);
372 TYPE_FIELDS (t) = fieldlist;
373
374 layout_type (t);
375}
376
377/* Construct a playback::type instance (wrapping a tree) for a function
378 type. */
379
380playback::type *
381playback::context::
382new_function_type (type *return_type,
b957b2e0 383 const auto_vec<type *> *param_types,
35485da9
DM
384 int is_variadic)
385{
386 int i;
387 type *param_type;
388
389 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
390
391 FOR_EACH_VEC_ELT (*param_types, i, param_type)
392 arg_types[i] = param_type->as_tree ();
393
394 tree fn_type;
395 if (is_variadic)
396 fn_type =
397 build_varargs_function_type_array (return_type->as_tree (),
398 param_types->length (),
399 arg_types);
400 else
401 fn_type = build_function_type_array (return_type->as_tree (),
402 param_types->length (),
403 arg_types);
404 free (arg_types);
405
406 return new type (fn_type);
407}
408
409/* Construct a playback::param instance (wrapping a tree). */
410
411playback::param *
412playback::context::
413new_param (location *loc,
414 type *type,
415 const char *name)
416{
417 gcc_assert (type);
418 gcc_assert (name);
419 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
420 get_identifier (name), type->as_tree ());
421 if (loc)
422 set_tree_location (inner, loc);
423
424 return new param (this, inner);
425}
426
427/* Construct a playback::function instance. */
428
429playback::function *
430playback::context::
431new_function (location *loc,
432 enum gcc_jit_function_kind kind,
433 type *return_type,
434 const char *name,
b957b2e0 435 const auto_vec<param *> *params,
35485da9
DM
436 int is_variadic,
437 enum built_in_function builtin_id)
438{
439 int i;
440 param *param;
441
442 //can return_type be NULL?
443 gcc_assert (name);
444
445 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
446 FOR_EACH_VEC_ELT (*params, i, param)
447 arg_types[i] = TREE_TYPE (param->as_tree ());
448
449 tree fn_type;
450 if (is_variadic)
451 fn_type = build_varargs_function_type_array (return_type->as_tree (),
452 params->length (), arg_types);
453 else
454 fn_type = build_function_type_array (return_type->as_tree (),
455 params->length (), arg_types);
456 free (arg_types);
457
458 /* FIXME: this uses input_location: */
459 tree fndecl = build_fn_decl (name, fn_type);
460
461 if (loc)
462 set_tree_location (fndecl, loc);
463
464 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
465 NULL_TREE, return_type->as_tree ());
466 DECL_ARTIFICIAL (resdecl) = 1;
467 DECL_IGNORED_P (resdecl) = 1;
468 DECL_RESULT (fndecl) = resdecl;
469
470 if (builtin_id)
471 {
35485da9
DM
472 gcc_assert (loc == NULL);
473 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
eeafb319 474
4d732405
RS
475 built_in_class fclass = builtins_manager::get_class (builtin_id);
476 set_decl_built_in_function (fndecl, fclass, builtin_id);
eeafb319
DM
477 set_builtin_decl (builtin_id, fndecl,
478 builtins_manager::implicit_p (builtin_id));
479
480 builtins_manager *bm = get_builtins_manager ();
481 tree attrs = bm->get_attrs_tree (builtin_id);
482 if (attrs)
483 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
484 else
485 decl_attributes (&fndecl, NULL_TREE, 0);
35485da9
DM
486 }
487
488 if (kind != GCC_JIT_FUNCTION_IMPORTED)
489 {
490 tree param_decl_list = NULL;
491 FOR_EACH_VEC_ELT (*params, i, param)
492 {
493 param_decl_list = chainon (param->as_tree (), param_decl_list);
494 }
495
496 /* The param list was created in reverse order; fix it: */
497 param_decl_list = nreverse (param_decl_list);
498
499 tree t;
500 for (t = param_decl_list; t; t = DECL_CHAIN (t))
501 {
502 DECL_CONTEXT (t) = fndecl;
503 DECL_ARG_TYPE (t) = TREE_TYPE (t);
504 }
505
506 /* Set it up on DECL_ARGUMENTS */
507 DECL_ARGUMENTS(fndecl) = param_decl_list;
508 }
509
510 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
511 {
512 DECL_DECLARED_INLINE_P (fndecl) = 1;
513
514 /* Add attribute "always_inline": */
515 DECL_ATTRIBUTES (fndecl) =
516 tree_cons (get_identifier ("always_inline"),
517 NULL,
518 DECL_ATTRIBUTES (fndecl));
519 }
520
521 function *func = new function (this, fndecl, kind);
522 m_functions.safe_push (func);
523 return func;
524}
525
4ecc0061 526/* In use by new_global and new_global_initialized. */
35485da9 527
4ecc0061 528tree
35485da9 529playback::context::
4ecc0061
AC
530global_new_decl (location *loc,
531 enum gcc_jit_global_kind kind,
532 type *type,
533 const char *name)
35485da9
DM
534{
535 gcc_assert (type);
536 gcc_assert (name);
537 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
538 get_identifier (name),
539 type->as_tree ());
791cfef8 540 TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
35485da9 541 DECL_COMMON (inner) = 1;
791cfef8
DM
542 switch (kind)
543 {
544 default:
545 gcc_unreachable ();
546
547 case GCC_JIT_GLOBAL_EXPORTED:
548 TREE_STATIC (inner) = 1;
549 break;
550
551 case GCC_JIT_GLOBAL_INTERNAL:
552 TREE_STATIC (inner) = 1;
553 break;
554
555 case GCC_JIT_GLOBAL_IMPORTED:
556 DECL_EXTERNAL (inner) = 1;
557 break;
558 }
35485da9
DM
559
560 if (loc)
561 set_tree_location (inner, loc);
562
4ecc0061
AC
563 return inner;
564}
565
566/* In use by new_global and new_global_initialized. */
567
568playback::lvalue *
569playback::context::
570global_finalize_lvalue (tree inner)
571{
791cfef8
DM
572 varpool_node::get_create (inner);
573
e4753451
DM
574 varpool_node::finalize_decl (inner);
575
791cfef8
DM
576 m_globals.safe_push (inner);
577
35485da9
DM
578 return new lvalue (this, inner);
579}
580
4ecc0061
AC
581/* Construct a playback::lvalue instance (wrapping a tree). */
582
583playback::lvalue *
584playback::context::
585new_global (location *loc,
586 enum gcc_jit_global_kind kind,
587 type *type,
588 const char *name)
589{
590 tree inner = global_new_decl (loc, kind, type, name);
591
592 return global_finalize_lvalue (inner);
593}
594
595/* Fill 'constructor_elements' with the memory content of
596 'initializer'. Each element of the initializer is of the size of
597 type T. In use by new_global_initialized.*/
598
599template<typename T>
600static void
601load_blob_in_ctor (vec<constructor_elt, va_gc> *&constructor_elements,
602 size_t num_elem,
603 const void *initializer)
604{
605 /* Loosely based on 'output_init_element' c-typeck.c:9691. */
606 const T *p = (const T *)initializer;
607 tree node = make_unsigned_type (BITS_PER_UNIT * sizeof (T));
608 for (size_t i = 0; i < num_elem; i++)
609 {
610 constructor_elt celt =
611 { build_int_cst (long_unsigned_type_node, i),
612 build_int_cst (node, p[i]) };
613 vec_safe_push (constructor_elements, celt);
614 }
615}
616
617/* Construct an initialized playback::lvalue instance (wrapping a
618 tree). */
619
620playback::lvalue *
621playback::context::
622new_global_initialized (location *loc,
623 enum gcc_jit_global_kind kind,
624 type *type,
625 size_t element_size,
626 size_t initializer_num_elem,
627 const void *initializer,
628 const char *name)
629{
630 tree inner = global_new_decl (loc, kind, type, name);
631
632 vec<constructor_elt, va_gc> *constructor_elements = NULL;
633
634 switch (element_size)
635 {
636 case 1:
637 load_blob_in_ctor<uint8_t> (constructor_elements, initializer_num_elem,
638 initializer);
639 break;
640 case 2:
641 load_blob_in_ctor<uint16_t> (constructor_elements, initializer_num_elem,
642 initializer);
643 break;
644 case 4:
645 load_blob_in_ctor<uint32_t> (constructor_elements, initializer_num_elem,
646 initializer);
647 break;
648 case 8:
649 load_blob_in_ctor<uint64_t> (constructor_elements, initializer_num_elem,
650 initializer);
651 break;
652 default:
653 /* This function is serving on sizes returned by 'get_size',
654 these are all covered by the previous cases. */
655 gcc_unreachable ();
656 }
657 /* Compare with 'pop_init_level' c-typeck.c:8780. */
658 tree ctor = build_constructor (type->as_tree (), constructor_elements);
659 constructor_elements = NULL;
660
661 /* Compare with 'store_init_value' c-typeck.c:7555. */
662 DECL_INITIAL (inner) = ctor;
663
664 return global_finalize_lvalue (inner);
665}
666
ccce3b2a
DM
667/* Implementation of the various
668 gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
669 methods.
670 Each of these constructs a playback::rvalue instance (wrapping a tree).
35485da9 671
ccce3b2a
DM
672 These specializations are required to be in the same namespace
673 as the template, hence we now have to enter the gcc::jit::playback
674 namespace. */
675
676namespace playback
677{
678
679/* Specialization of making an rvalue from a const, for host <int>. */
680
681template <>
682rvalue *
683context::
684new_rvalue_from_const <int> (type *type,
685 int value)
35485da9
DM
686{
687 // FIXME: type-checking, or coercion?
688 tree inner_type = type->as_tree ();
689 if (INTEGRAL_TYPE_P (inner_type))
690 {
691 tree inner = build_int_cst (inner_type, value);
692 return new rvalue (this, inner);
693 }
694 else
695 {
696 REAL_VALUE_TYPE real_value;
697 real_from_integer (&real_value, VOIDmode, value, SIGNED);
698 tree inner = build_real (inner_type, real_value);
699 return new rvalue (this, inner);
700 }
701}
702
ccce3b2a 703/* Specialization of making an rvalue from a const, for host <long>. */
35485da9 704
ccce3b2a
DM
705template <>
706rvalue *
707context::
708new_rvalue_from_const <long> (type *type,
709 long value)
710{
711 // FIXME: type-checking, or coercion?
712 tree inner_type = type->as_tree ();
713 if (INTEGRAL_TYPE_P (inner_type))
714 {
715 tree inner = build_int_cst (inner_type, value);
716 return new rvalue (this, inner);
717 }
718 else
719 {
720 REAL_VALUE_TYPE real_value;
721 real_from_integer (&real_value, VOIDmode, value, SIGNED);
722 tree inner = build_real (inner_type, real_value);
723 return new rvalue (this, inner);
724 }
725}
726
727/* Specialization of making an rvalue from a const, for host <double>. */
728
729template <>
730rvalue *
731context::
732new_rvalue_from_const <double> (type *type,
733 double value)
35485da9
DM
734{
735 // FIXME: type-checking, or coercion?
736 tree inner_type = type->as_tree ();
737
738 /* We have a "double", we want a REAL_VALUE_TYPE.
739
740 real.c:real_from_target appears to require the representation to be
741 split into 32-bit values, and then sent as an pair of host long
742 ints. */
743 REAL_VALUE_TYPE real_value;
744 union
745 {
746 double as_double;
747 uint32_t as_uint32s[2];
748 } u;
749 u.as_double = value;
750 long int as_long_ints[2];
751 as_long_ints[0] = u.as_uint32s[0];
752 as_long_ints[1] = u.as_uint32s[1];
753 real_from_target (&real_value, as_long_ints, DFmode);
754 tree inner = build_real (inner_type, real_value);
755 return new rvalue (this, inner);
756}
757
ccce3b2a 758/* Specialization of making an rvalue from a const, for host <void *>. */
35485da9 759
ccce3b2a
DM
760template <>
761rvalue *
762context::
763new_rvalue_from_const <void *> (type *type,
764 void *value)
35485da9
DM
765{
766 tree inner_type = type->as_tree ();
767 /* FIXME: how to ensure we have a wide enough type? */
768 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
769 return new rvalue (this, inner);
770}
771
ccce3b2a
DM
772/* We're done implementing the specializations of
773 gcc::jit::playback::context::new_rvalue_from_const <T>
774 so we can exit the gcc::jit::playback namespace. */
775
776} // namespace playback
777
35485da9
DM
778/* Construct a playback::rvalue instance (wrapping a tree). */
779
780playback::rvalue *
781playback::context::
782new_string_literal (const char *value)
783{
0cd55f9d
A
784 /* Compare with c-family/c-common.c: fix_string_type. */
785 size_t len = strlen (value);
786 tree i_type = build_index_type (size_int (len));
787 tree a_type = build_array_type (char_type_node, i_type);
788 /* build_string len parameter must include NUL terminator when
789 building C strings. */
421d0d0f 790 tree t_str = ::build_string (len + 1, value);
0cd55f9d 791 TREE_TYPE (t_str) = a_type;
35485da9
DM
792
793 /* Convert to (const char*), loosely based on
794 c/c-typeck.c: array_to_pointer_conversion,
795 by taking address of start of string. */
796 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
797
798 return new rvalue (this, t_addr);
799}
800
6069fe72
DM
801/* Construct a playback::rvalue instance (wrapping a tree) for a
802 vector. */
803
804playback::rvalue *
805playback::context::new_rvalue_from_vector (location *,
806 type *type,
807 const auto_vec<rvalue *> &elements)
808{
809 vec<constructor_elt, va_gc> *v;
810 vec_alloc (v, elements.length ());
811 for (unsigned i = 0; i < elements.length (); ++i)
812 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
813 tree t_ctor = build_constructor (type->as_tree (), v);
814 return new rvalue (this, t_ctor);
815}
816
35485da9
DM
817/* Coerce a tree expression into a boolean tree expression. */
818
819tree
820playback::context::
821as_truth_value (tree expr, location *loc)
822{
823 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
824 tree typed_zero = fold_build1 (CONVERT_EXPR,
825 TREE_TYPE (expr),
826 integer_zero_node);
827 if (loc)
828 set_tree_location (typed_zero, loc);
829
830 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
831 if (loc)
832 set_tree_location (expr, loc);
833
834 return expr;
835}
836
421d0d0f
DM
837/* Add a "top-level" basic asm statement (i.e. one outside of any functions)
838 containing ASM_STMTS.
839
840 Compare with c_parser_asm_definition. */
841
842void
843playback::context::add_top_level_asm (const char *asm_stmts)
844{
845 tree asm_str = build_string (asm_stmts);
846 symtab->finalize_toplevel_asm (asm_str);
847}
848
35485da9
DM
849/* Construct a playback::rvalue instance (wrapping a tree) for a
850 unary op. */
851
852playback::rvalue *
853playback::context::
854new_unary_op (location *loc,
855 enum gcc_jit_unary_op op,
856 type *result_type,
857 rvalue *a)
858{
859 // FIXME: type-checking, or coercion?
860 enum tree_code inner_op;
861
862 gcc_assert (result_type);
863 gcc_assert (a);
864
865 tree node = a->as_tree ();
866 tree inner_result = NULL;
867
868 switch (op)
869 {
870 default:
871 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
872 return NULL;
873
874 case GCC_JIT_UNARY_OP_MINUS:
875 inner_op = NEGATE_EXPR;
876 break;
877
878 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
879 inner_op = BIT_NOT_EXPR;
880 break;
881
882 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
883 node = as_truth_value (node, loc);
884 inner_result = invert_truthvalue (node);
885 if (loc)
886 set_tree_location (inner_result, loc);
887 return new rvalue (this, inner_result);
18146f45
DM
888
889 case GCC_JIT_UNARY_OP_ABS:
890 inner_op = ABS_EXPR;
891 break;
35485da9
DM
892 }
893
894 inner_result = build1 (inner_op,
895 result_type->as_tree (),
896 node);
897 if (loc)
898 set_tree_location (inner_result, loc);
899
900 return new rvalue (this, inner_result);
901}
902
903/* Construct a playback::rvalue instance (wrapping a tree) for a
904 binary op. */
905
906playback::rvalue *
907playback::context::
908new_binary_op (location *loc,
909 enum gcc_jit_binary_op op,
910 type *result_type,
911 rvalue *a, rvalue *b)
912{
913 // FIXME: type-checking, or coercion?
914 enum tree_code inner_op;
915
916 gcc_assert (result_type);
917 gcc_assert (a);
918 gcc_assert (b);
919
920 tree node_a = a->as_tree ();
921 tree node_b = b->as_tree ();
922
923 switch (op)
924 {
925 default:
926 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
927 return NULL;
928
929 case GCC_JIT_BINARY_OP_PLUS:
930 inner_op = PLUS_EXPR;
931 break;
932
933 case GCC_JIT_BINARY_OP_MINUS:
934 inner_op = MINUS_EXPR;
935 break;
936
937 case GCC_JIT_BINARY_OP_MULT:
938 inner_op = MULT_EXPR;
939 break;
940
941 case GCC_JIT_BINARY_OP_DIVIDE:
942 if (FLOAT_TYPE_P (result_type->as_tree ()))
943 /* Floating-point division: */
944 inner_op = RDIV_EXPR;
945 else
946 /* Truncating to zero: */
947 inner_op = TRUNC_DIV_EXPR;
948 break;
949
950 case GCC_JIT_BINARY_OP_MODULO:
951 inner_op = TRUNC_MOD_EXPR;
952 break;
953
954 case GCC_JIT_BINARY_OP_BITWISE_AND:
955 inner_op = BIT_AND_EXPR;
956 break;
957
958 case GCC_JIT_BINARY_OP_BITWISE_XOR:
959 inner_op = BIT_XOR_EXPR;
960 break;
961
962 case GCC_JIT_BINARY_OP_BITWISE_OR:
963 inner_op = BIT_IOR_EXPR;
964 break;
965
966 case GCC_JIT_BINARY_OP_LOGICAL_AND:
967 node_a = as_truth_value (node_a, loc);
968 node_b = as_truth_value (node_b, loc);
969 inner_op = TRUTH_ANDIF_EXPR;
970 break;
971
972 case GCC_JIT_BINARY_OP_LOGICAL_OR:
973 node_a = as_truth_value (node_a, loc);
974 node_b = as_truth_value (node_b, loc);
975 inner_op = TRUTH_ORIF_EXPR;
976 break;
977
978 case GCC_JIT_BINARY_OP_LSHIFT:
979 inner_op = LSHIFT_EXPR;
980 break;
981
982 case GCC_JIT_BINARY_OP_RSHIFT:
983 inner_op = RSHIFT_EXPR;
984 break;
985 }
986
987 tree inner_expr = build2 (inner_op,
988 result_type->as_tree (),
989 node_a,
990 node_b);
991 if (loc)
992 set_tree_location (inner_expr, loc);
993
994 return new rvalue (this, inner_expr);
995}
996
997/* Construct a playback::rvalue instance (wrapping a tree) for a
998 comparison. */
999
1000playback::rvalue *
1001playback::context::
1002new_comparison (location *loc,
1003 enum gcc_jit_comparison op,
1004 rvalue *a, rvalue *b)
1005{
1006 // FIXME: type-checking, or coercion?
1007 enum tree_code inner_op;
1008
1009 gcc_assert (a);
1010 gcc_assert (b);
1011
1012 switch (op)
1013 {
1014 default:
1015 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
1016 return NULL;
1017
1018 case GCC_JIT_COMPARISON_EQ:
1019 inner_op = EQ_EXPR;
1020 break;
1021 case GCC_JIT_COMPARISON_NE:
1022 inner_op = NE_EXPR;
1023 break;
1024 case GCC_JIT_COMPARISON_LT:
1025 inner_op = LT_EXPR;
1026 break;
1027 case GCC_JIT_COMPARISON_LE:
1028 inner_op = LE_EXPR;
1029 break;
1030 case GCC_JIT_COMPARISON_GT:
1031 inner_op = GT_EXPR;
1032 break;
1033 case GCC_JIT_COMPARISON_GE:
1034 inner_op = GE_EXPR;
1035 break;
1036 }
1037
1038 tree inner_expr = build2 (inner_op,
1039 boolean_type_node,
1040 a->as_tree (),
1041 b->as_tree ());
1042 if (loc)
1043 set_tree_location (inner_expr, loc);
1044 return new rvalue (this, inner_expr);
1045}
1046
1047/* Construct a playback::rvalue instance (wrapping a tree) for a
1048 function call. */
1049
1050playback::rvalue *
1051playback::context::
1052build_call (location *loc,
1053 tree fn_ptr,
15c671a7
DM
1054 const auto_vec<rvalue *> *args,
1055 bool require_tail_call)
35485da9
DM
1056{
1057 vec<tree, va_gc> *tree_args;
b957b2e0
DM
1058 vec_alloc (tree_args, args->length ());
1059 for (unsigned i = 0; i < args->length (); i++)
1060 tree_args->quick_push ((*args)[i]->as_tree ());
35485da9
DM
1061
1062 if (loc)
1063 set_tree_location (fn_ptr, loc);
1064
1065 tree fn = TREE_TYPE (fn_ptr);
1066 tree fn_type = TREE_TYPE (fn);
1067 tree return_type = TREE_TYPE (fn_type);
1068
15c671a7
DM
1069 tree call = build_call_vec (return_type,
1070 fn_ptr, tree_args);
1071
1072 if (require_tail_call)
1073 CALL_EXPR_MUST_TAIL_CALL (call) = 1;
1074
1075 return new rvalue (this, call);
35485da9
DM
1076
1077 /* see c-typeck.c: build_function_call
1078 which calls build_function_call_vec
1079
1080 which does lots of checking, then:
1081 result = build_call_array_loc (loc, TREE_TYPE (fntype),
1082 function, nargs, argarray);
1083 which is in tree.c
1084 (see also build_call_vec)
1085 */
1086}
1087
1088/* Construct a playback::rvalue instance (wrapping a tree) for a
1089 call to a specific function. */
1090
1091playback::rvalue *
1092playback::context::
1093new_call (location *loc,
1094 function *func,
15c671a7
DM
1095 const auto_vec<rvalue *> *args,
1096 bool require_tail_call)
35485da9
DM
1097{
1098 tree fndecl;
1099
1100 gcc_assert (func);
1101
1102 fndecl = func->as_fndecl ();
1103
1104 tree fntype = TREE_TYPE (fndecl);
1105
1106 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
1107
15c671a7 1108 return build_call (loc, fn, args, require_tail_call);
35485da9
DM
1109}
1110
1111/* Construct a playback::rvalue instance (wrapping a tree) for a
1112 call through a function pointer. */
1113
1114playback::rvalue *
1115playback::context::
1116new_call_through_ptr (location *loc,
1117 rvalue *fn_ptr,
15c671a7
DM
1118 const auto_vec<rvalue *> *args,
1119 bool require_tail_call)
35485da9
DM
1120{
1121 gcc_assert (fn_ptr);
1122 tree t_fn_ptr = fn_ptr->as_tree ();
1123
15c671a7 1124 return build_call (loc, t_fn_ptr, args, require_tail_call);
35485da9
DM
1125}
1126
1127/* Construct a tree for a cast. */
1128
1129tree
1130playback::context::build_cast (playback::location *loc,
1131 playback::rvalue *expr,
1132 playback::type *type_)
1133{
1134 /* For comparison, see:
1135 - c/c-typeck.c:build_c_cast
1136 - c/c-convert.c: convert
1137 - convert.h
1138
1139 Only some kinds of cast are currently supported here. */
1140 tree t_expr = expr->as_tree ();
1141 tree t_dst_type = type_->as_tree ();
1142 tree t_ret = NULL;
1143 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
1144 if (t_ret)
1145 return t_ret;
1146 enum tree_code dst_code = TREE_CODE (t_dst_type);
1147 switch (dst_code)
1148 {
1149 case INTEGER_TYPE:
1150 case ENUMERAL_TYPE:
1151 t_ret = convert_to_integer (t_dst_type, t_expr);
1152 goto maybe_fold;
1153
1154 case BOOLEAN_TYPE:
1155 /* Compare with c_objc_common_truthvalue_conversion and
1156 c_common_truthvalue_conversion. */
1157 /* For now, convert to: (t_expr != 0) */
1158 t_ret = build2 (NE_EXPR, t_dst_type,
e8af59bc
DM
1159 t_expr,
1160 build_int_cst (TREE_TYPE (t_expr), 0));
35485da9
DM
1161 goto maybe_fold;
1162
1163 case REAL_TYPE:
1164 t_ret = convert_to_real (t_dst_type, t_expr);
1165 goto maybe_fold;
1166
1167 case POINTER_TYPE:
1168 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
1169 goto maybe_fold;
1170
1171 default:
1172 add_error (loc, "couldn't handle cast during playback");
1173 fprintf (stderr, "input expression:\n");
1174 debug_tree (t_expr);
1175 fprintf (stderr, "requested type:\n");
1176 debug_tree (t_dst_type);
1177 return error_mark_node;
1178
1179 maybe_fold:
1180 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
1181 t_ret = fold (t_ret);
1182 return t_ret;
1183 }
1184}
1185
1186/* Construct a playback::rvalue instance (wrapping a tree) for a
1187 cast. */
1188
1189playback::rvalue *
1190playback::context::
1191new_cast (playback::location *loc,
1192 playback::rvalue *expr,
1193 playback::type *type_)
1194{
1195
1196 tree t_cast = build_cast (loc, expr, type_);
1197 if (loc)
1198 set_tree_location (t_cast, loc);
1199 return new rvalue (this, t_cast);
1200}
1201
1202/* Construct a playback::lvalue instance (wrapping a tree) for an
1203 array access. */
1204
1205playback::lvalue *
1206playback::context::
1207new_array_access (location *loc,
1208 rvalue *ptr,
1209 rvalue *index)
1210{
1211 gcc_assert (ptr);
1212 gcc_assert (index);
1213
1214 /* For comparison, see:
1215 c/c-typeck.c: build_array_ref
1216 c-family/c-common.c: pointer_int_sum
1217 */
1218 tree t_ptr = ptr->as_tree ();
1219 tree t_index = index->as_tree ();
1220 tree t_type_ptr = TREE_TYPE (t_ptr);
1221 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1222
1223 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1224 {
1225 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1226 NULL_TREE, NULL_TREE);
1227 if (loc)
c168eab9 1228 set_tree_location (t_result, loc);
35485da9
DM
1229 return new lvalue (this, t_result);
1230 }
1231 else
1232 {
1233 /* Convert index to an offset in bytes. */
1234 tree t_sizeof = size_in_bytes (t_type_star_ptr);
1235 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1236 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
1237
1238 /* Locate (ptr + offset). */
1239 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1240
1241 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1242 if (loc)
c168eab9
UD
1243 {
1244 set_tree_location (t_sizeof, loc);
1245 set_tree_location (t_offset, loc);
1246 set_tree_location (t_address, loc);
1247 set_tree_location (t_indirection, loc);
1248 }
35485da9
DM
1249
1250 return new lvalue (this, t_indirection);
1251 }
1252}
1253
1254/* Construct a tree for a field access. */
1255
1256tree
1257playback::context::
1258new_field_access (location *loc,
1259 tree datum,
1260 field *field)
1261{
1262 gcc_assert (datum);
1263 gcc_assert (field);
1264
1265 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
1266 build_component_ref. */
1267 tree type = TREE_TYPE (datum);
1268 gcc_assert (type);
1269 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1270
1271 tree t_field = field->as_tree ();
1272 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1273 t_field, NULL_TREE);
1274 if (loc)
1275 set_tree_location (ref, loc);
1276 return ref;
1277}
1278
1279/* Construct a tree for a dereference. */
1280
1281tree
1282playback::context::
1283new_dereference (tree ptr,
1284 location *loc)
1285{
1286 gcc_assert (ptr);
1287
1288 tree type = TREE_TYPE (TREE_TYPE(ptr));
1289 tree datum = build1 (INDIRECT_REF, type, ptr);
1290 if (loc)
1291 set_tree_location (datum, loc);
1292 return datum;
1293}
1294
0ebd1f00
DM
1295/* Construct a playback::type instance (wrapping a tree)
1296 with the given alignment. */
1297
1298playback::type *
1299playback::type::
1300get_aligned (size_t alignment_in_bytes) const
1301{
1302 tree t_new_type = build_variant_type_copy (m_inner);
1303
1304 SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT);
1305 TYPE_USER_ALIGN (t_new_type) = 1;
1306
1307 return new type (t_new_type);
1308}
1309
47ee1b7c
DM
1310/* Construct a playback::type instance (wrapping a tree)
1311 for the given vector type. */
1312
1313playback::type *
1314playback::type::
1315get_vector (size_t num_units) const
1316{
1317 tree t_new_type = build_vector_type (m_inner, num_units);
1318 return new type (t_new_type);
1319}
1320
35485da9
DM
1321/* Construct a playback::lvalue instance (wrapping a tree) for a
1322 field access. */
1323
1324playback::lvalue *
1325playback::lvalue::
1326access_field (location *loc,
1327 field *field)
1328{
1329 tree datum = as_tree ();
1330 tree ref = get_context ()->new_field_access (loc, datum, field);
1331 if (!ref)
1332 return NULL;
1333 return new lvalue (get_context (), ref);
1334}
1335
1336/* Construct a playback::rvalue instance (wrapping a tree) for a
1337 field access. */
1338
1339playback::rvalue *
1340playback::rvalue::
1341access_field (location *loc,
1342 field *field)
1343{
1344 tree datum = as_tree ();
1345 tree ref = get_context ()->new_field_access (loc, datum, field);
1346 if (!ref)
1347 return NULL;
1348 return new rvalue (get_context (), ref);
1349}
1350
1351/* Construct a playback::lvalue instance (wrapping a tree) for a
1352 dereferenced field access. */
1353
1354playback::lvalue *
1355playback::rvalue::
1356dereference_field (location *loc,
1357 field *field)
1358{
1359 tree ptr = as_tree ();
1360 tree datum = get_context ()->new_dereference (ptr, loc);
1361 if (!datum)
1362 return NULL;
1363 tree ref = get_context ()->new_field_access (loc, datum, field);
1364 if (!ref)
1365 return NULL;
1366 return new lvalue (get_context (), ref);
1367}
1368
1369/* Construct a playback::lvalue instance (wrapping a tree) for a
1370 dereference. */
1371
1372playback::lvalue *
1373playback::rvalue::
1374dereference (location *loc)
1375{
1376 tree ptr = as_tree ();
1377 tree datum = get_context ()->new_dereference (ptr, loc);
1378 return new lvalue (get_context (), datum);
1379}
1380
ee118c14 1381/* Mark the lvalue saying that we need to be able to take the
e09abfa4 1382 address of it; it should not be allocated in a register.
ee118c14
AC
1383 Compare with e.g. c/c-typeck.c: c_mark_addressable really_atomic_lvalue.
1384 Returns false if a failure occurred (an error will already have been
1385 added to the active context for this case). */
e09abfa4 1386
ee118c14
AC
1387bool
1388playback::lvalue::
1389mark_addressable (location *loc)
e09abfa4 1390{
ee118c14 1391 tree x = as_tree ();;
e09abfa4
DM
1392
1393 while (1)
1394 switch (TREE_CODE (x))
1395 {
1396 case COMPONENT_REF:
ee118c14
AC
1397 if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x, 1)))
1398 {
1399 gcc_assert (gcc::jit::active_playback_ctxt);
1400 gcc::jit::
1401 active_playback_ctxt->add_error (loc,
1402 "cannot take address of "
1403 "bit-field");
1404 return false;
1405 }
e09abfa4
DM
1406 /* fallthrough */
1407 case ADDR_EXPR:
1408 case ARRAY_REF:
1409 case REALPART_EXPR:
1410 case IMAGPART_EXPR:
1411 x = TREE_OPERAND (x, 0);
1412 break;
1413
1414 case COMPOUND_LITERAL_EXPR:
1415 case CONSTRUCTOR:
1416 TREE_ADDRESSABLE (x) = 1;
ee118c14 1417 return true;
e09abfa4
DM
1418
1419 case VAR_DECL:
1420 case CONST_DECL:
1421 case PARM_DECL:
1422 case RESULT_DECL:
1423 /* (we don't have a concept of a "register" declaration) */
1424 /* fallthrough */
1425 case FUNCTION_DECL:
1426 TREE_ADDRESSABLE (x) = 1;
1427 /* fallthrough */
1428 default:
ee118c14 1429 return true;
e09abfa4
DM
1430 }
1431}
1432
35485da9
DM
1433/* Construct a playback::rvalue instance (wrapping a tree) for an
1434 address-lookup. */
1435
1436playback::rvalue *
1437playback::lvalue::
1438get_address (location *loc)
1439{
1440 tree t_lvalue = as_tree ();
1441 tree t_thistype = TREE_TYPE (t_lvalue);
1442 tree t_ptrtype = build_pointer_type (t_thistype);
1443 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1444 if (loc)
1445 get_context ()->set_tree_location (ptr, loc);
ee118c14
AC
1446 if (mark_addressable (loc))
1447 return new rvalue (get_context (), ptr);
1448 else
1449 return NULL;
35485da9
DM
1450}
1451
b957b2e0
DM
1452/* The wrapper subclasses are GC-managed, but can own non-GC memory.
1453 Provide this finalization hook for calling then they are collected,
1454 which calls the finalizer vfunc. This allows them to call "release"
1455 on any vec<> within them. */
1456
1457static void
1458wrapper_finalizer (void *ptr)
1459{
1460 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1461 wrapper->finalizer ();
1462}
1463
35485da9
DM
1464/* gcc::jit::playback::wrapper subclasses are GC-managed:
1465 allocate them using ggc_internal_cleared_alloc. */
1466
1467void *
1468playback::wrapper::
1469operator new (size_t sz)
1470{
b957b2e0
DM
1471 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1472
35485da9
DM
1473}
1474
1475/* Constructor for gcc:jit::playback::function. */
1476
1477playback::function::
1478function (context *ctxt,
1479 tree fndecl,
1480 enum gcc_jit_function_kind kind)
1481: m_ctxt(ctxt),
1482 m_inner_fndecl (fndecl),
1483 m_inner_bind_expr (NULL),
1484 m_kind (kind)
1485{
1486 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1487 {
1488 /* Create a BIND_EXPR, and within it, a statement list. */
1489 m_stmt_list = alloc_stmt_list ();
1490 m_stmt_iter = tsi_start (m_stmt_list);
1491 m_inner_block = make_node (BLOCK);
1492 m_inner_bind_expr =
1493 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1494 }
1495 else
1496 {
1497 m_inner_block = NULL;
1498 m_stmt_list = NULL;
1499 }
1500}
1501
1502/* Hand-written GC-marking hook for playback functions. */
1503
1504void
1505playback::function::
1506gt_ggc_mx ()
1507{
1508 gt_ggc_m_9tree_node (m_inner_fndecl);
1509 gt_ggc_m_9tree_node (m_inner_bind_expr);
1510 gt_ggc_m_9tree_node (m_stmt_list);
1511 gt_ggc_m_9tree_node (m_inner_block);
1512}
1513
b957b2e0
DM
1514/* Don't leak vec's internal buffer (in non-GC heap) when we are
1515 GC-ed. */
1516
1517void
1518playback::function::finalizer ()
1519{
1520 m_blocks.release ();
1521}
1522
35485da9
DM
1523/* Get the return type of a playback function, in tree form. */
1524
1525tree
1526playback::function::
1527get_return_type_as_tree () const
1528{
1529 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1530}
1531
1532/* Construct a new local within this playback::function. */
1533
1534playback::lvalue *
1535playback::function::
1536new_local (location *loc,
1537 type *type,
1538 const char *name)
1539{
1540 gcc_assert (type);
1541 gcc_assert (name);
1542 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1543 get_identifier (name),
1544 type->as_tree ());
1545 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1546
1547 /* Prepend to BIND_EXPR_VARS: */
1548 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1549 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1550
1551 if (loc)
1552 set_tree_location (inner, loc);
1553 return new lvalue (m_ctxt, inner);
1554}
1555
1556/* Construct a new block within this playback::function. */
1557
1558playback::block *
1559playback::function::
1560new_block (const char *name)
1561{
1562 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1563
1564 block *result = new playback::block (this, name);
1565 m_blocks.safe_push (result);
1566 return result;
1567}
1568
15a65e63
DM
1569/* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1570 this playback::function. */
1571
1572playback::rvalue *
1573playback::function::get_address (location *loc)
1574{
1575 tree t_fndecl = as_fndecl ();
1576 tree t_fntype = TREE_TYPE (t_fndecl);
1577 tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
1578 if (loc)
1579 m_ctxt->set_tree_location (t_fnptr, loc);
1580 return new rvalue (m_ctxt, t_fnptr);
1581}
1582
35485da9
DM
1583/* Build a statement list for the function as a whole out of the
1584 lists of statements for the individual blocks, building labels
1585 for each block. */
1586
1587void
1588playback::function::
1589build_stmt_list ()
1590{
1591 int i;
1592 block *b;
1593
eb4c16eb
DM
1594 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1595
35485da9
DM
1596 FOR_EACH_VEC_ELT (m_blocks, i, b)
1597 {
1598 int j;
1599 tree stmt;
1600
1601 b->m_label_expr = build1 (LABEL_EXPR,
1602 void_type_node,
1603 b->as_label_decl ());
1604 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1605
1606 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1607 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1608 }
1609}
1610
1611/* Finish compiling the given function, potentially running the
1612 garbage-collector.
1613 The function will have a statement list by now.
1614 Amongst other things, this gimplifies the statement list,
1615 and calls cgraph_node::finalize_function on the function. */
1616
1617void
1618playback::function::
1619postprocess ()
1620{
eb4c16eb
DM
1621 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1622
35485da9
DM
1623 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1624 debug_tree (m_stmt_list);
1625
1626 /* Do we need this to force cgraphunit.c to output the function? */
1627 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1628 {
1629 DECL_EXTERNAL (m_inner_fndecl) = 0;
1630 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1631 }
1632
1633 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1634 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1635 {
1636 DECL_EXTERNAL (m_inner_fndecl) = 0;
1637 TREE_PUBLIC (m_inner_fndecl) = 0;
1638 }
1639
1640 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1641 {
1642 /* Seem to need this in gimple-low.c: */
1643 gcc_assert (m_inner_block);
1644 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1645
1646 /* how to add to function? the following appears to be how to
1647 set the body of a m_inner_fndecl: */
1648 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1649
1650 /* Ensure that locals appear in the debuginfo. */
1651 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1652
1653 //debug_tree (m_inner_fndecl);
1654
1655 /* Convert to gimple: */
1656 //printf("about to gimplify_function_tree\n");
1657 gimplify_function_tree (m_inner_fndecl);
1658 //printf("finished gimplify_function_tree\n");
1659
1660 current_function_decl = m_inner_fndecl;
1661 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1662 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1663 //debug_tree (m_inner_fndecl);
1664
1665 //printf("about to add to cgraph\n");
1666 /* Add to cgraph: */
1667 cgraph_node::finalize_function (m_inner_fndecl, false);
1668 /* This can trigger a collection, so we need to have all of
1669 the funcs as roots. */
1670
1671 current_function_decl = NULL;
1672 }
1673}
1674
b957b2e0
DM
1675/* Don't leak vec's internal buffer (in non-GC heap) when we are
1676 GC-ed. */
1677
1678void
1679playback::block::finalizer ()
1680{
1681 m_stmts.release ();
1682}
1683
35485da9
DM
1684/* Add an eval of the rvalue to the function's statement list. */
1685
1686void
1687playback::block::
1688add_eval (location *loc,
1689 rvalue *rvalue)
1690{
1691 gcc_assert (rvalue);
1692
1693 if (loc)
1694 set_tree_location (rvalue->as_tree (), loc);
1695
1696 add_stmt (rvalue->as_tree ());
1697}
1698
1699/* Add an assignment to the function's statement list. */
1700
1701void
1702playback::block::
1703add_assignment (location *loc,
1704 lvalue *lvalue,
1705 rvalue *rvalue)
1706{
1707 gcc_assert (lvalue);
1708 gcc_assert (rvalue);
1709
1710 tree t_lvalue = lvalue->as_tree ();
1711 tree t_rvalue = rvalue->as_tree ();
1712 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1713 {
1714 t_rvalue = build1 (CONVERT_EXPR,
c168eab9
UD
1715 TREE_TYPE (t_lvalue),
1716 t_rvalue);
35485da9
DM
1717 if (loc)
1718 set_tree_location (t_rvalue, loc);
1719 }
1720
1721 tree stmt =
1722 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1723 t_lvalue, t_rvalue);
1724 if (loc)
1725 set_tree_location (stmt, loc);
1726 add_stmt (stmt);
1727}
1728
1729/* Add a comment to the function's statement list.
1730 For now this is done by adding a dummy label. */
1731
1732void
1733playback::block::
1734add_comment (location *loc,
1735 const char *text)
1736{
1737 /* Wrap the text in C-style comment delimiters. */
1738 size_t sz =
1739 (3 /* opening delim */
1740 + strlen (text)
1741 + 3 /* closing delim */
1742 + 1 /* terminator */);
1743 char *wrapped = (char *)ggc_internal_alloc (sz);
1744 snprintf (wrapped, sz, "/* %s */", text);
1745
1746 /* For now we simply implement this by adding a dummy label with a name
1747 containing the given text. */
1748 tree identifier = get_identifier (wrapped);
1749 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1750 identifier, void_type_node);
1751 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1752
1753 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1754 if (loc)
1755 set_tree_location (label_expr, loc);
1756 add_stmt (label_expr);
1757}
1758
1759/* Add a conditional jump statement to the function's statement list. */
1760
1761void
1762playback::block::
1763add_conditional (location *loc,
1764 rvalue *boolval,
1765 block *on_true,
1766 block *on_false)
1767{
1768 gcc_assert (boolval);
1769 gcc_assert (on_true);
1770 gcc_assert (on_false);
1771
1772 /* COND_EXPR wants statement lists for the true/false operands, but we
1773 want labels.
1774 Shim it by creating jumps to the labels */
1775 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1776 on_true->as_label_decl ());
1777 if (loc)
1778 set_tree_location (true_jump, loc);
1779
1780 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1781 on_false->as_label_decl ());
1782 if (loc)
1783 set_tree_location (false_jump, loc);
1784
1785 tree stmt =
1786 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1787 true_jump, false_jump);
1788 if (loc)
1789 set_tree_location (stmt, loc);
1790 add_stmt (stmt);
1791}
1792
1793/* Add an unconditional jump statement to the function's statement list. */
1794
1795void
1796playback::block::
1797add_jump (location *loc,
1798 block *target)
1799{
1800 gcc_assert (target);
1801
1802 // see c_finish_loop
1803 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1804 //add_stmt (top);
1805
1806 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1807 TREE_USED (target->as_label_decl ()) = 1;
1808 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1809 if (loc)
1810 set_tree_location (stmt, loc);
1811 add_stmt (stmt);
1812
1813 /*
1814 from c-typeck.c:
1815tree
1816c_finish_goto_label (location_t loc, tree label)
1817{
1818 tree decl = lookup_label_for_goto (loc, label);
1819 if (!decl)
1820 return NULL_TREE;
1821 TREE_USED (decl) = 1;
1822 {
1823 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1824 SET_EXPR_LOCATION (t, loc);
1825 return add_stmt (t);
1826 }
1827}
1828 */
1829
1830}
1831
1832/* Add a return statement to the function's statement list. */
1833
1834void
1835playback::block::
1836add_return (location *loc,
1837 rvalue *rvalue)
1838{
1839 tree modify_retval = NULL;
1840 tree return_type = m_func->get_return_type_as_tree ();
1841 if (rvalue)
1842 {
1843 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1844 tree t_rvalue = rvalue->as_tree ();
1845 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1846 t_rvalue = build1 (CONVERT_EXPR,
1847 TREE_TYPE (t_lvalue),
1848 t_rvalue);
1849 modify_retval = build2 (MODIFY_EXPR, return_type,
1850 t_lvalue, t_rvalue);
1851 if (loc)
1852 set_tree_location (modify_retval, loc);
1853 }
1854 tree return_stmt = build1 (RETURN_EXPR, return_type,
1855 modify_retval);
1856 if (loc)
1857 set_tree_location (return_stmt, loc);
1858
1859 add_stmt (return_stmt);
1860}
1861
ec5d0088
DM
1862/* Helper function for playback::block::add_switch.
1863 Construct a case label for the given range, followed by a goto stmt
1864 to the given block, appending them to stmt list *ptr_t_switch_body. */
1865
1866static void
1867add_case (tree *ptr_t_switch_body,
1868 tree t_low_value,
1869 tree t_high_value,
1870 playback::block *dest_block)
1871{
1872 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
1873 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
1874
1875 tree t_case_label =
1876 build_case_label (t_low_value, t_high_value, t_label);
1877 append_to_statement_list (t_case_label, ptr_t_switch_body);
1878
1879 tree t_goto_stmt =
1880 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
1881 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
1882}
1883
1884/* Add a switch statement to the function's statement list.
1885
9e851845 1886 We create a switch body, and populate it with case labels, each
ec5d0088
DM
1887 followed by a goto to the desired block. */
1888
1889void
1890playback::block::
1891add_switch (location *loc,
1892 rvalue *expr,
1893 block *default_block,
1894 const auto_vec <case_> *cases)
1895{
1896 /* Compare with:
1897 - c/c-typeck.c: c_start_case
1898 - c-family/c-common.c:c_add_case_label
1899 - java/expr.c:expand_java_switch and expand_java_add_case
1900 We've already rejected overlaps and duplicates in
1901 libgccjit.c:case_range_validator::validate. */
1902
1903 tree t_expr = expr->as_tree ();
1904 tree t_type = TREE_TYPE (t_expr);
1905
1906 tree t_switch_body = alloc_stmt_list ();
1907
1908 int i;
1909 case_ *c;
1910 FOR_EACH_VEC_ELT (*cases, i, c)
1911 {
1912 tree t_low_value = c->m_min_value->as_tree ();
1913 tree t_high_value = c->m_max_value->as_tree ();
9e851845 1914 add_case (&t_switch_body, t_low_value, t_high_value, c->m_dest_block);
ec5d0088
DM
1915 }
1916 /* Default label. */
9e851845 1917 add_case (&t_switch_body, NULL_TREE, NULL_TREE, default_block);
ec5d0088 1918
9e851845 1919 tree switch_stmt = build2 (SWITCH_EXPR, t_type, t_expr, t_switch_body);
ec5d0088
DM
1920 if (loc)
1921 set_tree_location (switch_stmt, loc);
1922 add_stmt (switch_stmt);
1923}
1924
421d0d0f
DM
1925/* Convert OPERANDS to a tree-based chain suitable for creating an
1926 extended asm stmt.
1927 Compare with c_parser_asm_operands. */
1928
1929static tree
1930build_operand_chain (const auto_vec <playback::asm_operand> *operands)
1931{
1932 tree result = NULL_TREE;
1933 unsigned i;
1934 playback::asm_operand *asm_op;
1935 FOR_EACH_VEC_ELT (*operands, i, asm_op)
1936 {
1937 tree name = build_string (asm_op->m_asm_symbolic_name);
1938 tree str = build_string (asm_op->m_constraint);
1939 tree value = asm_op->m_expr;
1940 result = chainon (result,
1941 build_tree_list (build_tree_list (name, str),
1942 value));
1943 }
1944 return result;
1945}
1946
1947/* Convert CLOBBERS to a tree-based list suitable for creating an
1948 extended asm stmt.
1949 Compare with c_parser_asm_clobbers. */
1950
1951static tree
1952build_clobbers (const auto_vec <const char *> *clobbers)
1953{
1954 tree list = NULL_TREE;
1955 unsigned i;
1956 const char *clobber;
1957 FOR_EACH_VEC_ELT (*clobbers, i, clobber)
1958 {
1959 tree str = build_string (clobber);
1960 list = tree_cons (NULL_TREE, str, list);
1961 }
1962 return list;
1963}
1964
1965/* Convert BLOCKS to a tree-based list suitable for creating an
1966 extended asm stmt.
1967 Compare with c_parser_asm_goto_operands. */
1968
1969static tree
1970build_goto_operands (const auto_vec <playback::block *> *blocks)
1971{
1972 tree list = NULL_TREE;
1973 unsigned i;
1974 playback::block *b;
1975 FOR_EACH_VEC_ELT (*blocks, i, b)
1976 {
1977 tree label = b->as_label_decl ();
1978 tree name = build_string (IDENTIFIER_POINTER (DECL_NAME (label)));
1979 TREE_USED (label) = 1;
1980 list = tree_cons (name, label, list);
1981 }
1982 return nreverse (list);
1983}
1984
1985/* Add an extended asm statement to this block.
1986
1987 Compare with c_parser_asm_statement (in c/c-parser.c)
1988 and build_asm_expr (in c/c-typeck.c). */
1989
1990void
1991playback::block::add_extended_asm (location *loc,
1992 const char *asm_template,
1993 bool is_volatile,
1994 bool is_inline,
1995 const auto_vec <asm_operand> *outputs,
1996 const auto_vec <asm_operand> *inputs,
1997 const auto_vec <const char *> *clobbers,
1998 const auto_vec <block *> *goto_blocks)
1999{
2000 tree t_string = build_string (asm_template);
2001 tree t_outputs = build_operand_chain (outputs);
2002 tree t_inputs = build_operand_chain (inputs);
2003 tree t_clobbers = build_clobbers (clobbers);
2004 tree t_labels = build_goto_operands (goto_blocks);
2005 t_string
2006 = resolve_asm_operand_names (t_string, t_outputs, t_inputs, t_labels);
2007 tree asm_stmt
2008 = build5 (ASM_EXPR, void_type_node,
2009 t_string, t_outputs, t_inputs, t_clobbers, t_labels);
2010
2011 /* asm statements without outputs, including simple ones, are treated
2012 as volatile. */
2013 ASM_VOLATILE_P (asm_stmt) = (outputs->length () == 0);
2014 ASM_INPUT_P (asm_stmt) = 0; /* extended asm stmts are not "simple". */
2015 ASM_INLINE_P (asm_stmt) = is_inline;
2016 if (is_volatile)
2017 ASM_VOLATILE_P (asm_stmt) = 1;
2018 if (loc)
2019 set_tree_location (asm_stmt, loc);
2020 add_stmt (asm_stmt);
2021}
2022
35485da9
DM
2023/* Constructor for gcc::jit::playback::block. */
2024
2025playback::block::
2026block (function *func,
2027 const char *name)
2028: m_func (func),
2029 m_stmts ()
2030{
2031 tree identifier;
2032
2033 gcc_assert (func);
2034 // name can be NULL
2035 if (name)
2036 identifier = get_identifier (name);
2037 else
2038 identifier = NULL;
2039 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
2040 identifier, void_type_node);
2041 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
2042 m_label_expr = NULL;
2043}
2044
35485da9
DM
2045/* Compile a playback::context:
2046
2047 - Use the context's options to cconstruct command-line options, and
2048 call into the rest of GCC (toplev::main).
fdce7209
DM
2049 - Assuming it succeeds, we have a .s file.
2050 - We then run the "postprocess" vfunc:
35485da9 2051
fdce7209
DM
2052 (A) In-memory compile ("gcc_jit_context_compile")
2053
2054 For an in-memory compile we have the playback::compile_to_memory
2055 subclass; "postprocess" will convert the .s file to a .so DSO,
2056 and load it in memory (via dlopen), wrapping the result up as
2057 a jit::result and returning it.
2058
2059 (B) Compile to file ("gcc_jit_context_compile_to_file")
2060
2061 When compiling to a file, we have the playback::compile_to_file
2062 subclass; "postprocess" will either copy the .s file to the
2063 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
2064 the driver to convert it as necessary, copying the result. */
2065
2066void
35485da9
DM
2067playback::context::
2068compile ()
2069{
eb4c16eb
DM
2070 JIT_LOG_SCOPE (get_logger ());
2071
35485da9 2072 const char *ctxt_progname;
35485da9 2073
d1e5f2c7
DM
2074 int keep_intermediates =
2075 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
35485da9 2076
d2286af3 2077 m_tempdir = new tempdir (get_logger (), keep_intermediates);
d1e5f2c7 2078 if (!m_tempdir->create ())
fdce7209 2079 return;
35485da9
DM
2080
2081 /* Call into the rest of gcc.
2082 For now, we have to assemble command-line options to pass into
2083 toplev::main, so that they can be parsed. */
2084
2085 /* Pass in user-provided program name as argv0, if any, so that it
2086 makes it into GCC's "progname" global, used in various diagnostics. */
2087 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
35485da9 2088
c985705a
DM
2089 if (!ctxt_progname)
2090 ctxt_progname = "libgccjit.so";
2091
463366a0
DM
2092 auto_vec <recording::requested_dump> requested_dumps;
2093 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
2094
2cb844ce
DM
2095 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
2096 acquire_mutex ();
2097
3de37a5d 2098 auto_string_vec fake_args;
463366a0 2099 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
8f50ee3c 2100 if (errors_occurred ())
2cb844ce
DM
2101 {
2102 release_mutex ();
2103 return;
2104 }
38771e4e 2105
463366a0 2106 /* This runs the compiler. */
afed3459 2107 toplev toplev (get_timer (), /* external_timer */
6fc2d0f3 2108 false); /* init_signals */
eb4c16eb
DM
2109 enter_scope ("toplev::main");
2110 if (get_logger ())
2111 for (unsigned i = 0; i < fake_args.length (); i++)
2112 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
8f50ee3c
DM
2113 toplev.main (fake_args.length (),
2114 const_cast <char **> (fake_args.address ()));
eb4c16eb 2115 exit_scope ("toplev::main");
463366a0
DM
2116
2117 /* Extracting dumps makes use of the gcc::dump_manager, hence we
2118 need to do it between toplev::main (which creates the dump manager)
2119 and toplev::finalize (which deletes it). */
2120 extract_any_requested_dumps (&requested_dumps);
2121
2122 /* Clean up the compiler. */
eb4c16eb 2123 enter_scope ("toplev::finalize");
35485da9 2124 toplev.finalize ();
eb4c16eb 2125 exit_scope ("toplev::finalize");
35485da9 2126
38771e4e
DM
2127 /* Ideally we would release the jit mutex here, but we can't yet since
2128 followup activities use timevars, which are global state. */
35485da9
DM
2129
2130 if (errors_occurred ())
38771e4e
DM
2131 {
2132 release_mutex ();
fdce7209 2133 return;
38771e4e 2134 }
35485da9
DM
2135
2136 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
c6760a13 2137 dump_generated_code ();
35485da9 2138
fdce7209
DM
2139 /* We now have a .s file.
2140
2141 Run any postprocessing steps. This will either convert the .s file to
2142 a .so DSO, and load it in memory (playback::compile_to_memory), or
2143 convert the .s file to the requested output format, and copy it to a
2144 given file (playback::compile_to_file). */
2145 postprocess (ctxt_progname);
2146
2147 release_mutex ();
2148}
2149
2150/* Implementation of class gcc::jit::playback::compile_to_memory,
2151 a subclass of gcc::jit::playback::context. */
2152
2153/* playback::compile_to_memory's trivial constructor. */
2154
2155playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
2156 playback::context (ctxt),
2157 m_result (NULL)
2158{
2159 JIT_LOG_SCOPE (get_logger ());
2160}
2161
2162/* Implementation of the playback::context::process vfunc for compiling
2163 to memory.
2164
2165 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
2166 wrapping the result up as a jit::result and returning it. */
2167
2168void
2169playback::compile_to_memory::postprocess (const char *ctxt_progname)
2170{
2171 JIT_LOG_SCOPE (get_logger ());
c6760a13
DM
2172 convert_to_dso (ctxt_progname);
2173 if (errors_occurred ())
fdce7209
DM
2174 return;
2175 m_result = dlopen_built_dso ();
2176}
2177
2178/* Implementation of class gcc::jit::playback::compile_to_file,
2179 a subclass of gcc::jit::playback::context. */
2180
2181/* playback::compile_to_file's trivial constructor. */
2182
2183playback::compile_to_file::compile_to_file (recording::context *ctxt,
2184 enum gcc_jit_output_kind output_kind,
2185 const char *output_path) :
2186 playback::context (ctxt),
2187 m_output_kind (output_kind),
2188 m_output_path (output_path)
2189{
2190 JIT_LOG_SCOPE (get_logger ());
2191}
2192
2193/* Implementation of the playback::context::process vfunc for compiling
2194 to a file.
2195
2196 Either copy the .s file to the given destination (for
2197 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
2198 as necessary, copying the result. */
2199
2200void
2201playback::compile_to_file::postprocess (const char *ctxt_progname)
2202{
2203 JIT_LOG_SCOPE (get_logger ());
2204
2205 /* The driver takes different actions based on the filename, so
2206 we provide a filename with an appropriate suffix for the
2207 output kind, and then copy it up to the user-provided path,
2208 rather than directly compiling it to the requested output path. */
2209
2210 switch (m_output_kind)
38771e4e 2211 {
fdce7209
DM
2212 default:
2213 gcc_unreachable ();
2214
2215 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
2216 copy_file (get_tempdir ()->get_path_s_file (),
2217 m_output_path);
199501ea 2218 /* The .s file is automatically unlinked by tempdir::~tempdir. */
fdce7209
DM
2219 break;
2220
2221 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
2222 {
2223 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
2224 "/fake.o",
2225 NULL);
2226 invoke_driver (ctxt_progname,
2227 get_tempdir ()->get_path_s_file (),
2228 tmp_o_path,
2229 TV_ASSEMBLE,
2230 false, /* bool shared, */
2231 false);/* bool run_linker */
2232 if (!errors_occurred ())
199501ea
DM
2233 {
2234 copy_file (tmp_o_path,
2235 m_output_path);
2236 get_tempdir ()->add_temp_file (tmp_o_path);
2237 }
2238 else
2239 free (tmp_o_path);
fdce7209
DM
2240 }
2241 break;
2242
2243 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
2244 invoke_driver (ctxt_progname,
2245 get_tempdir ()->get_path_s_file (),
2246 get_tempdir ()->get_path_so_file (),
2247 TV_ASSEMBLE,
2248 true, /* bool shared, */
2249 true);/* bool run_linker */
2250 if (!errors_occurred ())
2251 copy_file (get_tempdir ()->get_path_so_file (),
2252 m_output_path);
199501ea 2253 /* The .so file is automatically unlinked by tempdir::~tempdir. */
fdce7209
DM
2254 break;
2255
2256 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
2257 {
2258 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
2259 "/fake.exe",
2260 NULL);
2261 invoke_driver (ctxt_progname,
2262 get_tempdir ()->get_path_s_file (),
2263 tmp_exe_path,
2264 TV_ASSEMBLE,
2265 false, /* bool shared, */
2266 true);/* bool run_linker */
2267 if (!errors_occurred ())
199501ea
DM
2268 {
2269 copy_file (tmp_exe_path,
2270 m_output_path);
2271 get_tempdir ()->add_temp_file (tmp_exe_path);
2272 }
2273 else
2274 free (tmp_exe_path);
fdce7209
DM
2275 }
2276 break;
2277
38771e4e 2278 }
35485da9 2279
fdce7209 2280}
35485da9 2281
fdce7209
DM
2282/* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2283 the "executable" bits).
2284
2285 Any errors that occur are reported on the context and hence count as
2286 a failure of the compile.
2287
2288 We can't in general hardlink or use "rename" from the tempdir since
2289 it might be on a different filesystem to the destination. For example,
2290 I get EXDEV: "Invalid cross-device link". */
2291
2292void
2293playback::compile_to_file::copy_file (const char *src_path,
2294 const char *dst_path)
2295{
2296 JIT_LOG_SCOPE (get_logger ());
2297 if (get_logger ())
2298 {
2299 get_logger ()->log ("src_path: %s", src_path);
2300 get_logger ()->log ("dst_path: %s", dst_path);
2301 }
2302
2303 FILE *f_in = NULL;
2304 FILE *f_out = NULL;
2305 size_t total_sz_in = 0;
2306 size_t total_sz_out = 0;
2307 char buf[4096];
2308 size_t sz_in;
2309 struct stat stat_buf;
2310
2311 f_in = fopen (src_path, "rb");
2312 if (!f_in)
2313 {
2314 add_error (NULL,
2315 "unable to open %s for reading: %s",
2316 src_path,
2317 xstrerror (errno));
2318 return;
2319 }
38771e4e 2320
fdce7209
DM
2321 /* Use stat on the filedescriptor to get the mode,
2322 so that we can copy it over (in particular, the
2323 "executable" bits). */
01512446 2324 if (fstat (fileno (f_in), &stat_buf) == -1)
fdce7209
DM
2325 {
2326 add_error (NULL,
2327 "unable to fstat %s: %s",
2328 src_path,
2329 xstrerror (errno));
2330 fclose (f_in);
2331 return;
2332 }
2333
2334 f_out = fopen (dst_path, "wb");
2335 if (!f_out)
2336 {
2337 add_error (NULL,
2338 "unable to open %s for writing: %s",
2339 dst_path,
2340 xstrerror (errno));
2341 fclose (f_in);
2342 return;
2343 }
2344
2345 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2346 {
2347 total_sz_in += sz_in;
2348 size_t sz_out_remaining = sz_in;
2349 size_t sz_out_so_far = 0;
2350 while (sz_out_remaining)
2351 {
2352 size_t sz_out = fwrite (buf + sz_out_so_far,
2353 1,
2354 sz_out_remaining,
2355 f_out);
2356 gcc_assert (sz_out <= sz_out_remaining);
2357 if (!sz_out)
2358 {
2359 add_error (NULL,
2360 "error writing to %s: %s",
2361 dst_path,
2362 xstrerror (errno));
2363 fclose (f_in);
2364 fclose (f_out);
2365 return;
2366 }
2367 total_sz_out += sz_out;
2368 sz_out_so_far += sz_out;
2369 sz_out_remaining -= sz_out;
2370 }
2371 gcc_assert (sz_out_so_far == sz_in);
2372 }
2373
2374 if (!feof (f_in))
2375 add_error (NULL,
2376 "error reading from %s: %s",
2377 src_path,
2378 xstrerror (errno));
2379
2380 fclose (f_in);
2381
2382 gcc_assert (total_sz_in == total_sz_out);
2383 if (get_logger ())
c83027f3 2384 get_logger ()->log ("total bytes copied: %zu", total_sz_out);
fdce7209 2385
c83027f3
NB
2386 /* fchmod does not exist in Windows. */
2387#ifndef _WIN32
fdce7209
DM
2388 /* Set the permissions of the copy to those of the original file,
2389 in particular the "executable" bits. */
01512446 2390 if (fchmod (fileno (f_out), stat_buf.st_mode) == -1)
fdce7209
DM
2391 add_error (NULL,
2392 "error setting mode of %s: %s",
2393 dst_path,
2394 xstrerror (errno));
c83027f3 2395#endif
fdce7209
DM
2396
2397 fclose (f_out);
35485da9
DM
2398}
2399
8f50ee3c
DM
2400/* Helper functions for gcc::jit::playback::context::compile. */
2401
38771e4e
DM
2402/* This mutex guards gcc::jit::recording::context::compile, so that only
2403 one thread can be accessing the bulk of GCC's state at once. */
2404
2405static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2406
2407/* Acquire jit_mutex and set "this" as the active playback ctxt. */
2408
2409void
2410playback::context::acquire_mutex ()
2411{
afed3459
DM
2412 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2413
38771e4e 2414 /* Acquire the big GCC mutex. */
eb4c16eb 2415 JIT_LOG_SCOPE (get_logger ());
38771e4e 2416 pthread_mutex_lock (&jit_mutex);
01512446 2417 gcc_assert (active_playback_ctxt == NULL);
38771e4e
DM
2418 active_playback_ctxt = this;
2419}
2420
2421/* Release jit_mutex and clear the active playback ctxt. */
2422
2423void
2424playback::context::release_mutex ()
2425{
2426 /* Release the big GCC mutex. */
eb4c16eb 2427 JIT_LOG_SCOPE (get_logger ());
38771e4e
DM
2428 gcc_assert (active_playback_ctxt == this);
2429 active_playback_ctxt = NULL;
2430 pthread_mutex_unlock (&jit_mutex);
2431}
2432
2cb844ce
DM
2433/* Callback used by gcc::jit::playback::context::make_fake_args when
2434 invoking driver_get_configure_time_options.
2435 Populate a vec <char * > with the configure-time options. */
2436
2437static void
2438append_arg_from_driver (const char *option, void *user_data)
2439{
2440 gcc_assert (option);
2441 gcc_assert (user_data);
2442 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2443 argvec->safe_push (concat ("-", option, NULL));
2444}
2445
8f50ee3c
DM
2446/* Build a fake argv for toplev::main from the options set
2447 by the user on the context . */
2448
2449void
2450playback::context::
463366a0
DM
2451make_fake_args (vec <char *> *argvec,
2452 const char *ctxt_progname,
2453 vec <recording::requested_dump> *requested_dumps)
8f50ee3c 2454{
eb4c16eb
DM
2455 JIT_LOG_SCOPE (get_logger ());
2456
463366a0
DM
2457#define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2458#define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
8f50ee3c
DM
2459
2460 ADD_ARG (ctxt_progname);
d1e5f2c7 2461 ADD_ARG (get_path_c_file ());
8f50ee3c
DM
2462 ADD_ARG ("-fPIC");
2463
2464 /* Handle int options: */
2465 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2466 {
2467 default:
2468 add_error (NULL,
2469 "unrecognized optimization level: %i",
2470 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2471 return;
2472
2473 case 0:
2474 ADD_ARG ("-O0");
2475 break;
2476
2477 case 1:
2478 ADD_ARG ("-O1");
2479 break;
2480
2481 case 2:
2482 ADD_ARG ("-O2");
2483 break;
2484
2485 case 3:
2486 ADD_ARG ("-O3");
2487 break;
2488 }
2489 /* What about -Os? */
2490
2491 /* Handle bool options: */
2492 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2493 ADD_ARG ("-g");
2494
2495 /* Suppress timing (and other) info. */
2496 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2497 {
2498 ADD_ARG ("-quiet");
2499 quiet_flag = 1;
2500 }
2501
2502 /* Aggressively garbage-collect, to shake out bugs: */
2503 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2504 {
56e04525
DM
2505 ADD_ARG ("--param=ggc-min-expand=0");
2506 ADD_ARG ("--param=ggc-min-heapsize=0");
8f50ee3c
DM
2507 }
2508
2509 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2510 {
2511 ADD_ARG ("-fdump-tree-all");
2512 ADD_ARG ("-fdump-rtl-all");
2513 ADD_ARG ("-fdump-ipa-all");
2514 }
463366a0
DM
2515
2516 /* Add "-fdump-" options for any calls to
2517 gcc_jit_context_enable_dump. */
2518 {
2519 int i;
2520 recording::requested_dump *d;
2521 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2522 {
2523 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2524 ADD_ARG_TAKE_OWNERSHIP (arg);
2525 }
2526 }
2527
2cb844ce
DM
2528 /* PR jit/64810: Add any target-specific default options
2529 from OPTION_DEFAULT_SPECS, normally provided by the driver
2530 in the non-jit case.
2531
2532 The target-specific code can define OPTION_DEFAULT_SPECS:
2533 default command options in the form of spec macros for the
2534 driver to expand ().
2535
2536 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2537 if not overriden, injects the defaults as extra arguments to
2538 cc1 etc.
2539 For the jit case, we need to add these arguments here. The
2540 input format (using the specs language) means that we have to run
2541 part of the driver code here (driver_get_configure_time_options).
2542
2543 To avoid running the spec-expansion code every time, we just do
2544 it the first time (via a function-static flag), saving the result
2545 into a function-static vec.
2546 This flag and vec are global state (i.e. per-process).
2547 They are guarded by the jit mutex. */
2548 {
2549 static bool have_configure_time_options = false;
2550 static vec <char *> configure_time_options;
2551
2552 if (have_configure_time_options)
2553 log ("reusing cached configure-time options");
2554 else
2555 {
2556 have_configure_time_options = true;
2557 log ("getting configure-time options from driver");
2558 driver_get_configure_time_options (append_arg_from_driver,
2559 &configure_time_options);
2560 }
2561
2562 int i;
2563 char *opt;
2564
2565 if (get_logger ())
2566 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2567 log ("configure_time_options[%i]: %s", i, opt);
2568
2569 /* configure_time_options should now contain the expanded options
2570 from OPTION_DEFAULT_SPECS (if any). */
2571 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2572 {
2573 gcc_assert (opt);
2574 gcc_assert (opt[0] == '-');
2575 ADD_ARG (opt);
2576 }
2577 }
2578
afed3459
DM
2579 if (get_timer ())
2580 ADD_ARG ("-ftime-report");
2581
fa22c20d
DM
2582 /* Add any user-provided extra options, starting with any from
2583 parent contexts. */
2584 m_recording_ctxt->append_command_line_options (argvec);
2585
8f50ee3c 2586#undef ADD_ARG
463366a0
DM
2587#undef ADD_ARG_TAKE_OWNERSHIP
2588}
2589
2590/* The second half of the implementation of gcc_jit_context_enable_dump.
2591 Iterate through the requested dumps, reading the underlying files
2592 into heap-allocated buffers, writing pointers to the buffers into
2593 the char ** pointers provided by client code.
2594 Client code is responsible for calling free on the results. */
2595
2596void
2597playback::context::
2598extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2599{
eb4c16eb
DM
2600 JIT_LOG_SCOPE (get_logger ());
2601
463366a0
DM
2602 int i;
2603 recording::requested_dump *d;
2604 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2605 {
2606 dump_file_info *dfi;
2607 char *filename;
2608 char *content;
2609
2610 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2611 if (!dfi)
2612 {
2613 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2614 continue;
2615 }
2616
2617 filename = g->get_dumps ()->get_dump_file_name (dfi);
2618 content = read_dump_file (filename);
2619 *(d->m_out_ptr) = content;
199501ea 2620 m_tempdir->add_temp_file (filename);
463366a0
DM
2621 }
2622}
2623
2624/* Helper function for playback::context::extract_any_requested_dumps
2625 (itself for use in implementation of gcc_jit_context_enable_dump).
2626
2627 Attempt to read the complete file at the given path, returning the
2628 bytes found there as a buffer.
2629 The caller is responsible for calling free on the result.
2630 Errors will be reported on the context, and lead to NULL being
2631 returned; an out-of-memory error will terminate the process. */
2632
2633char *
2634playback::context::read_dump_file (const char *path)
2635{
2636 char *result = NULL;
2637 size_t total_sz = 0;
2638 char buf[4096];
2639 size_t sz;
2640 FILE *f_in;
2641
2642 f_in = fopen (path, "r");
2643 if (!f_in)
2644 {
2645 add_error (NULL, "unable to open %s for reading", path);
2646 return NULL;
2647 }
2648
2649 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2650 {
2651 size_t old_total_sz = total_sz;
2652 total_sz += sz;
2653 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2654 memcpy (result + old_total_sz, buf, sz);
2655 }
2656
2657 if (!feof (f_in))
2658 {
2659 add_error (NULL, "error reading from %s", path);
2660 free (result);
1c35cc2c 2661 fclose (f_in);
463366a0
DM
2662 return NULL;
2663 }
2664
2665 fclose (f_in);
2666
2667 if (result)
2668 {
2669 result[total_sz] = '\0';
2670 return result;
2671 }
2672 else
2673 return xstrdup ("");
8f50ee3c
DM
2674}
2675
c6760a13
DM
2676/* Part of playback::context::compile ().
2677
2678 We have a .s file; we want a .so file.
2679 We could reuse parts of gcc/gcc.c to do this.
2680 For now, just use the driver binary from the install, as
2681 named in gcc-driver-name.h
2682 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2683
2684void
2685playback::context::
2686convert_to_dso (const char *ctxt_progname)
fdce7209
DM
2687{
2688 JIT_LOG_SCOPE (get_logger ());
2689
2690 invoke_driver (ctxt_progname,
2691 m_tempdir->get_path_s_file (),
2692 m_tempdir->get_path_so_file (),
2693 TV_ASSEMBLE,
2694 true, /* bool shared, */
2695 true);/* bool run_linker */
2696}
2697
9376dd63
DM
2698static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2699
fdce7209
DM
2700void
2701playback::context::
2702invoke_driver (const char *ctxt_progname,
2703 const char *input_file,
2704 const char *output_file,
2705 timevar_id_t tv_id,
2706 bool shared,
2707 bool run_linker)
c6760a13 2708{
eb4c16eb 2709 JIT_LOG_SCOPE (get_logger ());
9376dd63
DM
2710
2711 bool embedded_driver
2712 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
2713
c6760a13
DM
2714 /* Currently this lumps together both assembling and linking into
2715 TV_ASSEMBLE. */
afed3459 2716 auto_timevar assemble_timevar (get_timer (), tv_id);
3de37a5d 2717 auto_string_vec argvec;
eb3982c1 2718#define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
c6760a13 2719
c168eab9 2720 ADD_ARG (gcc_driver_name);
fdce7209 2721
eb3982c1
DM
2722 add_multilib_driver_arguments (&argvec);
2723
fdce7209
DM
2724 if (shared)
2725 ADD_ARG ("-shared");
2726
2727 if (!run_linker)
2728 ADD_ARG ("-c");
2729
2730 ADD_ARG (input_file);
c168eab9 2731 ADD_ARG ("-o");
fdce7209 2732 ADD_ARG (output_file);
c6760a13
DM
2733
2734 /* Don't use the linker plugin.
2735 If running with just a "make" and not a "make install", then we'd
2736 run into
2737 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2738 libto_plugin is a .la at build time, with it becoming installed with
2739 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2740 time. */
c168eab9 2741 ADD_ARG ("-fno-use-linker-plugin");
c6760a13 2742
baf3fbad
DM
2743#if defined (DARWIN_X86) || defined (DARWIN_PPC)
2744 /* OS X's linker defaults to treating undefined symbols as errors.
2745 If the context has any imported functions or globals they will be
2746 undefined until the .so is dynamically-linked into the process.
2747 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2748 linker. */
2749 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2750#endif
2751
9376dd63
DM
2752 if (0)
2753 ADD_ARG ("-v");
2754
216090cc
AC
2755 /* Add any user-provided driver extra options. */
2756
2757 m_recording_ctxt->append_driver_options (&argvec);
2758
9376dd63 2759#undef ADD_ARG
c6760a13
DM
2760
2761 /* pex_one's error-handling requires pname to be non-NULL. */
2762 gcc_assert (ctxt_progname);
2763
eb4c16eb
DM
2764 if (get_logger ())
2765 for (unsigned i = 0; i < argvec.length (); i++)
2766 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2767
9376dd63
DM
2768 if (embedded_driver)
2769 invoke_embedded_driver (&argvec);
2770 else
2771 invoke_external_driver (ctxt_progname, &argvec);
2772}
2773
2774void
2775playback::context::
2776invoke_embedded_driver (const vec <char *> *argvec)
2777{
2778 JIT_LOG_SCOPE (get_logger ());
2779 driver d (true, /* can_finalize */
2780 false); /* debug */
2781 int result = d.main (argvec->length (),
2782 const_cast <char **> (argvec->address ()));
2783 d.finalize ();
2784 if (result)
2785 add_error (NULL, "error invoking gcc driver");
2786}
2787
2788void
2789playback::context::
2790invoke_external_driver (const char *ctxt_progname,
2791 vec <char *> *argvec)
2792{
2793 JIT_LOG_SCOPE (get_logger ());
2794 const char *errmsg;
2795 int exit_status = 0;
2796 int err = 0;
2797
2798 /* pex argv arrays are NULL-terminated. */
2799 argvec->safe_push (NULL);
2800
c6760a13
DM
2801 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2802 gcc_driver_name,
9376dd63 2803 const_cast <char *const *> (argvec->address ()),
c6760a13
DM
2804 ctxt_progname, /* const char *pname */
2805 NULL, /* const char *outname */
2806 NULL, /* const char *errname */
2807 &exit_status, /* int *status */
2808 &err); /* int *err*/
2809 if (errmsg)
2810 {
2811 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2812 return;
2813 }
2814
2815 /* pex_one can return a NULL errmsg when the executable wasn't
2816 found (or doesn't exist), so trap these cases also. */
2817 if (exit_status || err)
2818 {
2819 add_error (NULL,
2820 "error invoking gcc driver: exit_status: %i err: %i",
2821 exit_status, err);
2822 add_error (NULL,
2823 "whilst attempting to run a driver named: %s",
2824 gcc_driver_name);
2825 add_error (NULL,
2826 "PATH was: %s",
2827 getenv ("PATH"));
2828 return;
2829 }
2830}
2831
eb3982c1
DM
2832/* Extract the target-specific MULTILIB_DEFAULTS to
2833 multilib_defaults_raw for use by
2834 playback::context::add_multilib_driver_arguments (). */
2835
2836#ifndef MULTILIB_DEFAULTS
2837#define MULTILIB_DEFAULTS { "" }
2838#endif
2839
2840static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
2841
2842/* Helper function for playback::context::invoke_driver ().
2843
2844 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2845 a driver binary. We need to pass in options to the shared driver
2846 to get the appropriate assembler/linker options for this multilib
2847 peer. */
2848
2849void
2850playback::context::
2851add_multilib_driver_arguments (vec <char *> *argvec)
2852{
2853 JIT_LOG_SCOPE (get_logger ());
2854
2855 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2856 prepending each with a "-". */
2857 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
2858 if (multilib_defaults_raw[i][0])
2859 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
2860}
2861
38f4f641
DM
2862/* Dynamically-link the built DSO file into this process, using dlopen.
2863 Wrap it up within a jit::result *, and return that.
2864 Return NULL if any errors occur, reporting them on this context. */
2865
2866result *
2867playback::context::
2868dlopen_built_dso ()
2869{
eb4c16eb 2870 JIT_LOG_SCOPE (get_logger ());
afed3459 2871 auto_timevar load_timevar (get_timer (), TV_LOAD);
c83027f3 2872 result::handle handle = NULL;
38f4f641
DM
2873 result *result_obj = NULL;
2874
c83027f3
NB
2875#ifdef _WIN32
2876 /* Clear any existing error. */
2877 SetLastError(0);
2878
2879 handle = LoadLibrary(m_tempdir->get_path_so_file ());
2880 if (GetLastError() != 0) {
2881 print_last_error();
2882 }
2883#else
2884 const char *error = NULL;
38f4f641
DM
2885 /* Clear any existing error. */
2886 dlerror ();
2887
d1e5f2c7
DM
2888 handle = dlopen (m_tempdir->get_path_so_file (),
2889 RTLD_NOW | RTLD_LOCAL);
38f4f641
DM
2890 if ((error = dlerror()) != NULL) {
2891 add_error (NULL, "%s", error);
2892 }
c83027f3
NB
2893#endif
2894
38f4f641 2895 if (handle)
d2286af3
DM
2896 {
2897 /* We've successfully dlopened the result; create a
2898 jit::result object to wrap it.
2899
2900 We're done with the tempdir for now, but if the user
2901 has requested debugging, the user's debugger might not
2902 be capable of dealing with the .so file being unlinked
2903 immediately, so keep it around until after the result
2904 is released. We do this by handing over ownership of
2905 the jit::tempdir to the result. See PR jit/64206. */
2906 tempdir *handover_tempdir;
2907 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2908 {
2909 handover_tempdir = m_tempdir;
2910 m_tempdir = NULL;
2911 /* The tempdir will eventually be cleaned up in the
2912 jit::result's dtor. */
2913 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2914 " handing over tempdir to jit::result");
2915 }
2916 else
2917 {
2918 handover_tempdir = NULL;
2919 /* ... and retain ownership of m_tempdir so we clean it
2920 up it the playback::context's dtor. */
2921 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2922 " retaining ownership of tempdir");
2923 }
2924
2925 result_obj = new result (get_logger (), handle, handover_tempdir);
2926 }
38f4f641
DM
2927 else
2928 result_obj = NULL;
2929
2930 return result_obj;
2931}
2932
35485da9
DM
2933/* Top-level hook for playing back a recording context.
2934
2935 This plays back m_recording_ctxt, and, if no errors
2936 occurred builds statement lists for and then postprocesses
2937 every function in the result. */
2938
2939void
2940playback::context::
2941replay ()
2942{
eb4c16eb 2943 JIT_LOG_SCOPE (get_logger ());
35485da9
DM
2944
2945 m_const_char_ptr
2946 = build_pointer_type (build_qualified_type (char_type_node,
2947 TYPE_QUAL_CONST));
2948
2949 /* Replay the recorded events: */
2950 timevar_push (TV_JIT_REPLAY);
2951
2952 m_recording_ctxt->replay_into (this);
2953
2954 /* Clean away the temporary references from recording objects
2955 to playback objects. We have to do this now since the
2956 latter are GC-allocated, but the former don't mark these
2957 refs. Hence we must stop using them before the GC can run. */
2958 m_recording_ctxt->disassociate_from_playback ();
2959
eeafb319
DM
2960 /* The builtins_manager, if any, is associated with the recording::context
2961 and might be reused for future compiles on other playback::contexts,
2962 but its m_attributes array is not GTY-labeled and hence will become
2963 nonsense if the GC runs. Purge this state. */
2964 builtins_manager *bm = get_builtins_manager ();
2965 if (bm)
2966 bm->finish_playback ();
2967
35485da9
DM
2968 timevar_pop (TV_JIT_REPLAY);
2969
2970 if (!errors_occurred ())
2971 {
2972 int i;
2973 function *func;
2974
2975 /* No GC can happen yet; process the cached source locations. */
2976 handle_locations ();
2977
2978 /* We've now created tree nodes for the stmts in the various blocks
2979 in each function, but we haven't built each function's single stmt
2980 list yet. Do so now. */
2981 FOR_EACH_VEC_ELT (m_functions, i, func)
2982 func->build_stmt_list ();
2983
2984 /* No GC can have happened yet. */
2985
2986 /* Postprocess the functions. This could trigger GC. */
2987 FOR_EACH_VEC_ELT (m_functions, i, func)
2988 {
2989 gcc_assert (func);
2990 func->postprocess ();
2991 }
2992 }
2993}
2994
2995/* Dump the generated .s file to stderr. */
2996
2997void
2998playback::context::
2999dump_generated_code ()
3000{
eb4c16eb 3001 JIT_LOG_SCOPE (get_logger ());
35485da9
DM
3002 char buf[4096];
3003 size_t sz;
d1e5f2c7 3004 FILE *f_in = fopen (get_path_s_file (), "r");
35485da9
DM
3005 if (!f_in)
3006 return;
3007
3008 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
3009 fwrite (buf, 1, sz, stderr);
3010
3011 fclose (f_in);
3012}
3013
d1e5f2c7
DM
3014/* Get the supposed path of the notional "fake.c" file within the
3015 tempdir. This file doesn't exist, but the rest of the compiler
3016 needs a name. */
3017
3018const char *
3019playback::context::
3020get_path_c_file () const
3021{
3022 return m_tempdir->get_path_c_file ();
3023}
3024
3025/* Get the path of the assembler output file "fake.s" file within the
3026 tempdir. */
3027
3028const char *
3029playback::context::
3030get_path_s_file () const
3031{
3032 return m_tempdir->get_path_s_file ();
3033}
3034
3035/* Get the path of the DSO object file "fake.so" file within the
3036 tempdir. */
3037
3038const char *
3039playback::context::
3040get_path_so_file () const
3041{
3042 return m_tempdir->get_path_so_file ();
3043}
3044
35485da9
DM
3045/* qsort comparator for comparing pairs of playback::source_line *,
3046 ordering them by line number. */
3047
3048static int
3049line_comparator (const void *lhs, const void *rhs)
3050{
3051 const playback::source_line *line_lhs = \
3052 *static_cast<const playback::source_line * const*> (lhs);
3053 const playback::source_line *line_rhs = \
3054 *static_cast<const playback::source_line * const*> (rhs);
3055 return line_lhs->get_line_num () - line_rhs->get_line_num ();
3056}
3057
3058/* qsort comparator for comparing pairs of playback::location *,
3059 ordering them by column number. */
3060
3061static int
3062location_comparator (const void *lhs, const void *rhs)
3063{
3064 const playback::location *loc_lhs = \
3065 *static_cast<const playback::location * const *> (lhs);
3066 const playback::location *loc_rhs = \
3067 *static_cast<const playback::location * const *> (rhs);
3068 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
3069}
3070
3071/* Our API allows locations to be created in arbitrary orders, but the
3072 linemap API requires locations to be created in ascending order
3073 as if we were tokenizing files.
3074
026c3cfd 3075 This hook sorts all of the locations that have been created, and
35485da9
DM
3076 calls into the linemap API, creating linemap entries in sorted order
3077 for our locations. */
3078
3079void
3080playback::context::
3081handle_locations ()
3082{
3083 /* Create the source code locations, following the ordering rules
3084 imposed by the linemap API.
3085
3086 line_table is a global. */
eb4c16eb 3087 JIT_LOG_SCOPE (get_logger ());
35485da9
DM
3088 int i;
3089 source_file *file;
3090
3091 FOR_EACH_VEC_ELT (m_source_files, i, file)
3092 {
3093 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
3094
3095 /* Sort lines by ascending line numbers. */
3096 file->m_source_lines.qsort (&line_comparator);
3097
3098 int j;
3099 source_line *line;
3100 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
3101 {
3102 int k;
3103 location *loc;
3104
3105 /* Sort locations in line by ascending column numbers. */
3106 line->m_locations.qsort (&location_comparator);
3107
3108 /* Determine maximum column within this line. */
3109 gcc_assert (line->m_locations.length () > 0);
3110 location *final_column =
3111 line->m_locations[line->m_locations.length () - 1];
3112 int max_col = final_column->get_column_num ();
3113
3114 linemap_line_start (line_table, line->get_line_num (), max_col);
3115 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
3116 {
3117 loc->m_srcloc = \
3118 linemap_position_for_column (line_table, loc->get_column_num ());
3119 }
3120 }
3121
3122 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
3123 }
3124
3125 /* line_table should now be populated; every playback::location should
3126 now have an m_srcloc. */
3127
3128 /* Now assign them to tree nodes as appropriate. */
3129 std::pair<tree, location *> *cached_location;
3130
3131 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
3132 {
3133 tree t = cached_location->first;
620e594b 3134 location_t srcloc = cached_location->second->m_srcloc;
35485da9
DM
3135
3136 /* This covers expressions: */
3137 if (CAN_HAVE_LOCATION_P (t))
3138 SET_EXPR_LOCATION (t, srcloc);
3139 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
3140 DECL_SOURCE_LOCATION (t) = srcloc;
3141 else
3142 {
3143 /* Don't know how to set location on this node. */
3144 }
3145 }
3146}
3147
3148/* We handle errors on a playback::context by adding them to the
3149 corresponding recording::context. */
3150
3151void
3152playback::context::
3153add_error (location *loc, const char *fmt, ...)
3154{
3155 va_list ap;
3156 va_start (ap, fmt);
3157 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
3158 fmt, ap);
3159 va_end (ap);
3160}
3161
3162/* We handle errors on a playback::context by adding them to the
3163 corresponding recording::context. */
3164
3165void
3166playback::context::
3167add_error_va (location *loc, const char *fmt, va_list ap)
3168{
3169 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
3170 fmt, ap);
3171}
3172
6b5423a5
DM
3173/* Report a diagnostic up to the jit context as an error,
3174 so that the compilation is treated as a failure.
3175 For now, any kind of diagnostic is treated as an error by the jit
3176 API. */
3177
3178void
3179playback::context::
3180add_diagnostic (struct diagnostic_context *diag_context,
3181 struct diagnostic_info *diagnostic)
3182{
3183 /* At this point the text has been formatted into the pretty-printer's
3184 output buffer. */
3185 pretty_printer *pp = diag_context->printer;
3186 const char *text = pp_formatted_text (pp);
3187
3188 /* Get location information (if any) from the diagnostic.
3189 The recording::context::add_error[_va] methods require a
3190 recording::location. We can't lookup the playback::location
3191 from the file/line/column since any playback location instances
3192 may have been garbage-collected away by now, so instead we create
3193 another recording::location directly. */
3194 location_t gcc_loc = diagnostic_location (diagnostic);
3195 recording::location *rec_loc = NULL;
3196 if (gcc_loc)
3197 {
3198 expanded_location exploc = expand_location (gcc_loc);
3199 if (exploc.file)
3200 rec_loc = m_recording_ctxt->new_location (exploc.file,
3201 exploc.line,
3202 exploc.column,
3203 false);
3204 }
3205
3206 m_recording_ctxt->add_error (rec_loc, "%s", text);
3207 pp_clear_output_area (pp);
3208}
3209
35485da9
DM
3210/* Dealing with the linemap API. */
3211
3212/* Construct a playback::location for a recording::location, if it
3213 doesn't exist already. */
3214
3215playback::location *
3216playback::context::
3217new_location (recording::location *rloc,
3218 const char *filename,
3219 int line,
3220 int column)
3221{
3222 /* Get the source_file for filename, creating if necessary. */
3223 source_file *src_file = get_source_file (filename);
3224 /* Likewise for the line within the file. */
3225 source_line *src_line = src_file->get_source_line (line);
3226 /* Likewise for the column within the line. */
3227 location *loc = src_line->get_location (rloc, column);
3228 return loc;
3229}
3230
3231/* Deferred setting of the location for a given tree, by adding the
3232 (tree, playback::location) pair to a list of deferred associations.
3233 We will actually set the location on the tree later on once
620e594b 3234 the location_t for the playback::location exists. */
35485da9
DM
3235
3236void
3237playback::context::
3238set_tree_location (tree t, location *loc)
3239{
3240 gcc_assert (loc);
3241 m_cached_locations.safe_push (std::make_pair (t, loc));
3242}
3243
3244
3245/* Construct a playback::source_file for the given source
3246 filename, if it doesn't exist already. */
3247
3248playback::source_file *
3249playback::context::
3250get_source_file (const char *filename)
3251{
3252 /* Locate the file.
3253 For simplicitly, this is currently a linear search.
3254 Replace with a hash if this shows up in the profile. */
3255 int i;
3256 source_file *file;
3257 tree ident_filename = get_identifier (filename);
3258
3259 FOR_EACH_VEC_ELT (m_source_files, i, file)
3260 if (file->filename_as_tree () == ident_filename)
3261 return file;
3262
3263 /* Not found. */
3264 file = new source_file (ident_filename);
3265 m_source_files.safe_push (file);
3266 return file;
3267}
3268
3269/* Constructor for gcc::jit::playback::source_file. */
3270
3271playback::source_file::source_file (tree filename) :
3272 m_source_lines (),
3273 m_filename (filename)
3274{
3275}
3276
b957b2e0
DM
3277/* Don't leak vec's internal buffer (in non-GC heap) when we are
3278 GC-ed. */
3279
3280void
3281playback::source_file::finalizer ()
3282{
3283 m_source_lines.release ();
3284}
3285
35485da9
DM
3286/* Construct a playback::source_line for the given line
3287 within this source file, if one doesn't exist already. */
3288
3289playback::source_line *
3290playback::source_file::
3291get_source_line (int line_num)
3292{
3293 /* Locate the line.
3294 For simplicitly, this is currently a linear search.
3295 Replace with a hash if this shows up in the profile. */
3296 int i;
3297 source_line *line;
3298
3299 FOR_EACH_VEC_ELT (m_source_lines, i, line)
3300 if (line->get_line_num () == line_num)
3301 return line;
3302
3303 /* Not found. */
3304 line = new source_line (this, line_num);
3305 m_source_lines.safe_push (line);
3306 return line;
3307}
3308
3309/* Constructor for gcc::jit::playback::source_line. */
3310
3311playback::source_line::source_line (source_file *file, int line_num) :
3312 m_locations (),
3313 m_source_file (file),
3314 m_line_num (line_num)
3315{
3316}
b957b2e0
DM
3317
3318/* Don't leak vec's internal buffer (in non-GC heap) when we are
3319 GC-ed. */
3320
3321void
3322playback::source_line::finalizer ()
3323{
3324 m_locations.release ();
3325}
35485da9
DM
3326
3327/* Construct a playback::location for the given column
3328 within this line of a specific source file, if one doesn't exist
3329 already. */
3330
3331playback::location *
3332playback::source_line::
3333get_location (recording::location *rloc, int column_num)
3334{
3335 int i;
3336 location *loc;
3337
3338 /* Another linear search that probably should be a hash table. */
3339 FOR_EACH_VEC_ELT (m_locations, i, loc)
3340 if (loc->get_column_num () == column_num)
3341 return loc;
3342
3343 /* Not found. */
3344 loc = new location (rloc, this, column_num);
3345 m_locations.safe_push (loc);
3346 return loc;
3347}
3348
3349/* Constructor for gcc::jit::playback::location. */
3350
3351playback::location::location (recording::location *loc,
3352 source_line *line,
3353 int column_num) :
3354 m_srcloc (UNKNOWN_LOCATION),
3355 m_recording_loc (loc),
3356 m_line (line),
3357 m_column_num(column_num)
3358{
3359}
3360
3361/* The active gcc::jit::playback::context instance. This is a singleton,
3362 guarded by jit_mutex. */
3363
3364playback::context *active_playback_ctxt;
3365
3366} // namespace gcc::jit
3367
3368} // namespace gcc