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