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