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