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