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