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