]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/jit/jit-playback.c
[AArch64] Fix ICE on non-constant indices to __builtin_aarch64_im_lane_boundsi
[thirdparty/gcc.git] / gcc / jit / jit-playback.c
CommitLineData
35485da9
DM
1/* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2014 Free Software Foundation, Inc.
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"
25#include "tree.h"
26#include "hash-map.h"
27#include "is-a.h"
28#include "plugin-api.h"
29#include "vec.h"
30#include "hashtab.h"
31#include "hash-set.h"
32#include "machmode.h"
33#include "tm.h"
34#include "hard-reg-set.h"
35#include "function.h"
36#include "ipa-ref.h"
37#include "dumpfile.h"
38#include "cgraph.h"
39#include "toplev.h"
40#include "timevar.h"
41#include "tree-cfg.h"
42#include "target.h"
43#include "convert.h"
44#include "stringpool.h"
45#include "stor-layout.h"
46#include "print-tree.h"
47#include "gimplify.h"
48#include "gcc-driver-name.h"
eeafb319 49#include "attribs.h"
463366a0 50#include "context.h"
35485da9
DM
51
52#include "jit-common.h"
53#include "jit-playback.h"
56dea35f 54#include "jit-result.h"
eeafb319 55#include "jit-builtins.h"
35485da9
DM
56
57
58/* gcc::jit::playback::context::build_cast uses the convert.h API,
59 which in turn requires the frontend to provide a "convert"
60 function, apparently as a fallback.
61
62 Hence we provide this dummy one, with the requirement that any casts
63 are handled before reaching this. */
64extern tree convert (tree type, tree expr);
65
66tree
67convert (tree dst_type, tree expr)
68{
69 gcc_assert (gcc::jit::active_playback_ctxt);
70 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
71 fprintf (stderr, "input expression:\n");
72 debug_tree (expr);
73 fprintf (stderr, "requested type:\n");
74 debug_tree (dst_type);
75 return error_mark_node;
76}
77
78namespace gcc {
79namespace jit {
80
81/**********************************************************************
82 Playback.
83 **********************************************************************/
84
85/* The constructor for gcc::jit::playback::context. */
86
87playback::context::context (recording::context *ctxt)
88 : m_recording_ctxt (ctxt),
89 m_char_array_type_node (NULL),
90 m_const_char_ptr (NULL)
91{
92 m_functions.create (0);
93 m_source_files.create (0);
94 m_cached_locations.create (0);
95}
96
97/* The destructor for gcc::jit::playback::context. */
98
99playback::context::~context ()
100{
101 if (get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES))
102 fprintf (stderr, "intermediate files written to %s\n", m_path_tempdir);
103 else
104 {
105 /* Clean up .s/.so and tempdir. */
106 if (m_path_s_file)
107 unlink (m_path_s_file);
108 if (m_path_so_file)
109 unlink (m_path_so_file);
110 if (m_path_tempdir)
111 rmdir (m_path_tempdir);
112 }
113
114 free (m_path_template);
115 /* m_path_tempdir aliases m_path_template, or is NULL, so don't
116 attempt to free it . */
117 free (m_path_c_file);
118 free (m_path_s_file);
119 free (m_path_so_file);
120 m_functions.release ();
121}
122
123/* A playback::context can reference GC-managed pointers. Mark them
124 ("by hand", rather than by gengtype).
125
126 This is called on the active playback context (if any) by the
127 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
128
129void
130playback::context::
131gt_ggc_mx ()
132{
133 int i;
134 function *func;
135 FOR_EACH_VEC_ELT (m_functions, i, func)
136 {
137 if (ggc_test_and_set_mark (func))
138 func->gt_ggc_mx ();
139 }
140}
141
142/* Given an enum gcc_jit_types value, get a "tree" type. */
143
144static tree
145get_tree_node_for_type (enum gcc_jit_types type_)
146{
147 switch (type_)
148 {
149 case GCC_JIT_TYPE_VOID:
150 return void_type_node;
151
152 case GCC_JIT_TYPE_VOID_PTR:
153 return ptr_type_node;
154
155 case GCC_JIT_TYPE_BOOL:
156 return boolean_type_node;
157
158 case GCC_JIT_TYPE_CHAR:
159 return char_type_node;
160 case GCC_JIT_TYPE_SIGNED_CHAR:
161 return signed_char_type_node;
162 case GCC_JIT_TYPE_UNSIGNED_CHAR:
163 return unsigned_char_type_node;
164
165 case GCC_JIT_TYPE_SHORT:
166 return short_integer_type_node;
167 case GCC_JIT_TYPE_UNSIGNED_SHORT:
168 return short_unsigned_type_node;
169
170 case GCC_JIT_TYPE_CONST_CHAR_PTR:
171 {
172 tree const_char = build_qualified_type (char_type_node,
173 TYPE_QUAL_CONST);
174 return build_pointer_type (const_char);
175 }
176
177 case GCC_JIT_TYPE_INT:
178 return integer_type_node;
179 case GCC_JIT_TYPE_UNSIGNED_INT:
180 return unsigned_type_node;
181
182 case GCC_JIT_TYPE_LONG:
183 return long_integer_type_node;
184 case GCC_JIT_TYPE_UNSIGNED_LONG:
185 return long_unsigned_type_node;
186
187 case GCC_JIT_TYPE_LONG_LONG:
188 return long_long_integer_type_node;
189 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
190 return long_long_unsigned_type_node;
191
192 case GCC_JIT_TYPE_FLOAT:
193 return float_type_node;
194 case GCC_JIT_TYPE_DOUBLE:
195 return double_type_node;
196 case GCC_JIT_TYPE_LONG_DOUBLE:
197 return long_double_type_node;
198
199 case GCC_JIT_TYPE_SIZE_T:
200 return size_type_node;
201
202 case GCC_JIT_TYPE_FILE_PTR:
203 return fileptr_type_node;
eeafb319
DM
204
205 case GCC_JIT_TYPE_COMPLEX_FLOAT:
206 return complex_float_type_node;
207 case GCC_JIT_TYPE_COMPLEX_DOUBLE:
208 return complex_double_type_node;
209 case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
210 return complex_long_double_type_node;
35485da9
DM
211 }
212
213 return NULL;
214}
215
216/* Construct a playback::type instance (wrapping a tree) for the given
217 enum value. */
218
219playback::type *
220playback::context::
221get_type (enum gcc_jit_types type_)
222{
223 tree type_node = get_tree_node_for_type (type_);
224 if (NULL == type_node)
225 {
226 add_error (NULL,
227 "unrecognized (enum gcc_jit_types) value: %i", type_);
228 return NULL;
229 }
230
231 return new type (type_node);
232}
233
234/* Construct a playback::type instance (wrapping a tree) for the given
235 array type. */
236
237playback::type *
238playback::context::
239new_array_type (playback::location *loc,
240 playback::type *element_type,
241 int num_elements)
242{
243 gcc_assert (element_type);
244
245 tree t = build_array_type_nelts (element_type->as_tree (),
246 num_elements);
247 layout_type (t);
248
249 if (loc)
250 set_tree_location (t, loc);
251
252 return new type (t);
253}
254
255/* Construct a playback::field instance (wrapping a tree). */
256
257playback::field *
258playback::context::
259new_field (location *loc,
260 type *type,
261 const char *name)
262{
263 gcc_assert (type);
264 gcc_assert (name);
265
266 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
267 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
268 get_identifier (name), type->as_tree ());
269
270 if (loc)
271 set_tree_location (decl, loc);
272
273 return new field (decl);
274}
275
276/* Construct a playback::compound_type instance (wrapping a tree). */
277
278playback::compound_type *
279playback::context::
280new_compound_type (location *loc,
281 const char *name,
282 bool is_struct) /* else is union */
283{
284 gcc_assert (name);
285
286 /* Compare with c/c-decl.c: start_struct. */
287
288 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
289 TYPE_NAME (t) = get_identifier (name);
290 TYPE_SIZE (t) = 0;
291
292 if (loc)
293 set_tree_location (t, loc);
294
295 return new compound_type (t);
296}
297
298void
b957b2e0 299playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
35485da9
DM
300{
301 /* Compare with c/c-decl.c: finish_struct. */
302 tree t = as_tree ();
303
304 tree fieldlist = NULL;
b957b2e0 305 for (unsigned i = 0; i < fields->length (); i++)
35485da9 306 {
b957b2e0 307 field *f = (*fields)[i];
35485da9
DM
308 DECL_CONTEXT (f->as_tree ()) = t;
309 fieldlist = chainon (f->as_tree (), fieldlist);
310 }
311 fieldlist = nreverse (fieldlist);
312 TYPE_FIELDS (t) = fieldlist;
313
314 layout_type (t);
315}
316
317/* Construct a playback::type instance (wrapping a tree) for a function
318 type. */
319
320playback::type *
321playback::context::
322new_function_type (type *return_type,
b957b2e0 323 const auto_vec<type *> *param_types,
35485da9
DM
324 int is_variadic)
325{
326 int i;
327 type *param_type;
328
329 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
330
331 FOR_EACH_VEC_ELT (*param_types, i, param_type)
332 arg_types[i] = param_type->as_tree ();
333
334 tree fn_type;
335 if (is_variadic)
336 fn_type =
337 build_varargs_function_type_array (return_type->as_tree (),
338 param_types->length (),
339 arg_types);
340 else
341 fn_type = build_function_type_array (return_type->as_tree (),
342 param_types->length (),
343 arg_types);
344 free (arg_types);
345
346 return new type (fn_type);
347}
348
349/* Construct a playback::param instance (wrapping a tree). */
350
351playback::param *
352playback::context::
353new_param (location *loc,
354 type *type,
355 const char *name)
356{
357 gcc_assert (type);
358 gcc_assert (name);
359 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
360 get_identifier (name), type->as_tree ());
361 if (loc)
362 set_tree_location (inner, loc);
363
364 return new param (this, inner);
365}
366
367/* Construct a playback::function instance. */
368
369playback::function *
370playback::context::
371new_function (location *loc,
372 enum gcc_jit_function_kind kind,
373 type *return_type,
374 const char *name,
b957b2e0 375 const auto_vec<param *> *params,
35485da9
DM
376 int is_variadic,
377 enum built_in_function builtin_id)
378{
379 int i;
380 param *param;
381
382 //can return_type be NULL?
383 gcc_assert (name);
384
385 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
386 FOR_EACH_VEC_ELT (*params, i, param)
387 arg_types[i] = TREE_TYPE (param->as_tree ());
388
389 tree fn_type;
390 if (is_variadic)
391 fn_type = build_varargs_function_type_array (return_type->as_tree (),
392 params->length (), arg_types);
393 else
394 fn_type = build_function_type_array (return_type->as_tree (),
395 params->length (), arg_types);
396 free (arg_types);
397
398 /* FIXME: this uses input_location: */
399 tree fndecl = build_fn_decl (name, fn_type);
400
401 if (loc)
402 set_tree_location (fndecl, loc);
403
404 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
405 NULL_TREE, return_type->as_tree ());
406 DECL_ARTIFICIAL (resdecl) = 1;
407 DECL_IGNORED_P (resdecl) = 1;
408 DECL_RESULT (fndecl) = resdecl;
409
410 if (builtin_id)
411 {
35485da9
DM
412 DECL_FUNCTION_CODE (fndecl) = builtin_id;
413 gcc_assert (loc == NULL);
414 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
eeafb319
DM
415
416 DECL_BUILT_IN_CLASS (fndecl) =
417 builtins_manager::get_class (builtin_id);
418 set_builtin_decl (builtin_id, fndecl,
419 builtins_manager::implicit_p (builtin_id));
420
421 builtins_manager *bm = get_builtins_manager ();
422 tree attrs = bm->get_attrs_tree (builtin_id);
423 if (attrs)
424 decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
425 else
426 decl_attributes (&fndecl, NULL_TREE, 0);
35485da9
DM
427 }
428
429 if (kind != GCC_JIT_FUNCTION_IMPORTED)
430 {
431 tree param_decl_list = NULL;
432 FOR_EACH_VEC_ELT (*params, i, param)
433 {
434 param_decl_list = chainon (param->as_tree (), param_decl_list);
435 }
436
437 /* The param list was created in reverse order; fix it: */
438 param_decl_list = nreverse (param_decl_list);
439
440 tree t;
441 for (t = param_decl_list; t; t = DECL_CHAIN (t))
442 {
443 DECL_CONTEXT (t) = fndecl;
444 DECL_ARG_TYPE (t) = TREE_TYPE (t);
445 }
446
447 /* Set it up on DECL_ARGUMENTS */
448 DECL_ARGUMENTS(fndecl) = param_decl_list;
449 }
450
451 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
452 {
453 DECL_DECLARED_INLINE_P (fndecl) = 1;
454
455 /* Add attribute "always_inline": */
456 DECL_ATTRIBUTES (fndecl) =
457 tree_cons (get_identifier ("always_inline"),
458 NULL,
459 DECL_ATTRIBUTES (fndecl));
460 }
461
462 function *func = new function (this, fndecl, kind);
463 m_functions.safe_push (func);
464 return func;
465}
466
467/* Construct a playback::lvalue instance (wrapping a tree). */
468
469playback::lvalue *
470playback::context::
471new_global (location *loc,
472 type *type,
473 const char *name)
474{
475 gcc_assert (type);
476 gcc_assert (name);
477 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
478 get_identifier (name),
479 type->as_tree ());
480 TREE_PUBLIC (inner) = 1;
481 DECL_COMMON (inner) = 1;
482 DECL_EXTERNAL (inner) = 1;
483
484 if (loc)
485 set_tree_location (inner, loc);
486
487 return new lvalue (this, inner);
488}
489
490/* Construct a playback::rvalue instance (wrapping a tree). */
491
492playback::rvalue *
493playback::context::
494new_rvalue_from_int (type *type,
495 int value)
496{
497 // FIXME: type-checking, or coercion?
498 tree inner_type = type->as_tree ();
499 if (INTEGRAL_TYPE_P (inner_type))
500 {
501 tree inner = build_int_cst (inner_type, value);
502 return new rvalue (this, inner);
503 }
504 else
505 {
506 REAL_VALUE_TYPE real_value;
507 real_from_integer (&real_value, VOIDmode, value, SIGNED);
508 tree inner = build_real (inner_type, real_value);
509 return new rvalue (this, inner);
510 }
511}
512
513/* Construct a playback::rvalue instance (wrapping a tree). */
514
515playback::rvalue *
516playback::context::
517new_rvalue_from_double (type *type,
518 double value)
519{
520 // FIXME: type-checking, or coercion?
521 tree inner_type = type->as_tree ();
522
523 /* We have a "double", we want a REAL_VALUE_TYPE.
524
525 real.c:real_from_target appears to require the representation to be
526 split into 32-bit values, and then sent as an pair of host long
527 ints. */
528 REAL_VALUE_TYPE real_value;
529 union
530 {
531 double as_double;
532 uint32_t as_uint32s[2];
533 } u;
534 u.as_double = value;
535 long int as_long_ints[2];
536 as_long_ints[0] = u.as_uint32s[0];
537 as_long_ints[1] = u.as_uint32s[1];
538 real_from_target (&real_value, as_long_ints, DFmode);
539 tree inner = build_real (inner_type, real_value);
540 return new rvalue (this, inner);
541}
542
543/* Construct a playback::rvalue instance (wrapping a tree). */
544
545playback::rvalue *
546playback::context::
547new_rvalue_from_ptr (type *type,
548 void *value)
549{
550 tree inner_type = type->as_tree ();
551 /* FIXME: how to ensure we have a wide enough type? */
552 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
553 return new rvalue (this, inner);
554}
555
556/* Construct a playback::rvalue instance (wrapping a tree). */
557
558playback::rvalue *
559playback::context::
560new_string_literal (const char *value)
561{
562 tree t_str = build_string (strlen (value), value);
563 gcc_assert (m_char_array_type_node);
564 TREE_TYPE (t_str) = m_char_array_type_node;
565
566 /* Convert to (const char*), loosely based on
567 c/c-typeck.c: array_to_pointer_conversion,
568 by taking address of start of string. */
569 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
570
571 return new rvalue (this, t_addr);
572}
573
574/* Coerce a tree expression into a boolean tree expression. */
575
576tree
577playback::context::
578as_truth_value (tree expr, location *loc)
579{
580 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
581 tree typed_zero = fold_build1 (CONVERT_EXPR,
582 TREE_TYPE (expr),
583 integer_zero_node);
584 if (loc)
585 set_tree_location (typed_zero, loc);
586
587 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
588 if (loc)
589 set_tree_location (expr, loc);
590
591 return expr;
592}
593
594/* Construct a playback::rvalue instance (wrapping a tree) for a
595 unary op. */
596
597playback::rvalue *
598playback::context::
599new_unary_op (location *loc,
600 enum gcc_jit_unary_op op,
601 type *result_type,
602 rvalue *a)
603{
604 // FIXME: type-checking, or coercion?
605 enum tree_code inner_op;
606
607 gcc_assert (result_type);
608 gcc_assert (a);
609
610 tree node = a->as_tree ();
611 tree inner_result = NULL;
612
613 switch (op)
614 {
615 default:
616 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
617 return NULL;
618
619 case GCC_JIT_UNARY_OP_MINUS:
620 inner_op = NEGATE_EXPR;
621 break;
622
623 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
624 inner_op = BIT_NOT_EXPR;
625 break;
626
627 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
628 node = as_truth_value (node, loc);
629 inner_result = invert_truthvalue (node);
630 if (loc)
631 set_tree_location (inner_result, loc);
632 return new rvalue (this, inner_result);
633 }
634
635 inner_result = build1 (inner_op,
636 result_type->as_tree (),
637 node);
638 if (loc)
639 set_tree_location (inner_result, loc);
640
641 return new rvalue (this, inner_result);
642}
643
644/* Construct a playback::rvalue instance (wrapping a tree) for a
645 binary op. */
646
647playback::rvalue *
648playback::context::
649new_binary_op (location *loc,
650 enum gcc_jit_binary_op op,
651 type *result_type,
652 rvalue *a, rvalue *b)
653{
654 // FIXME: type-checking, or coercion?
655 enum tree_code inner_op;
656
657 gcc_assert (result_type);
658 gcc_assert (a);
659 gcc_assert (b);
660
661 tree node_a = a->as_tree ();
662 tree node_b = b->as_tree ();
663
664 switch (op)
665 {
666 default:
667 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
668 return NULL;
669
670 case GCC_JIT_BINARY_OP_PLUS:
671 inner_op = PLUS_EXPR;
672 break;
673
674 case GCC_JIT_BINARY_OP_MINUS:
675 inner_op = MINUS_EXPR;
676 break;
677
678 case GCC_JIT_BINARY_OP_MULT:
679 inner_op = MULT_EXPR;
680 break;
681
682 case GCC_JIT_BINARY_OP_DIVIDE:
683 if (FLOAT_TYPE_P (result_type->as_tree ()))
684 /* Floating-point division: */
685 inner_op = RDIV_EXPR;
686 else
687 /* Truncating to zero: */
688 inner_op = TRUNC_DIV_EXPR;
689 break;
690
691 case GCC_JIT_BINARY_OP_MODULO:
692 inner_op = TRUNC_MOD_EXPR;
693 break;
694
695 case GCC_JIT_BINARY_OP_BITWISE_AND:
696 inner_op = BIT_AND_EXPR;
697 break;
698
699 case GCC_JIT_BINARY_OP_BITWISE_XOR:
700 inner_op = BIT_XOR_EXPR;
701 break;
702
703 case GCC_JIT_BINARY_OP_BITWISE_OR:
704 inner_op = BIT_IOR_EXPR;
705 break;
706
707 case GCC_JIT_BINARY_OP_LOGICAL_AND:
708 node_a = as_truth_value (node_a, loc);
709 node_b = as_truth_value (node_b, loc);
710 inner_op = TRUTH_ANDIF_EXPR;
711 break;
712
713 case GCC_JIT_BINARY_OP_LOGICAL_OR:
714 node_a = as_truth_value (node_a, loc);
715 node_b = as_truth_value (node_b, loc);
716 inner_op = TRUTH_ORIF_EXPR;
717 break;
718
719 case GCC_JIT_BINARY_OP_LSHIFT:
720 inner_op = LSHIFT_EXPR;
721 break;
722
723 case GCC_JIT_BINARY_OP_RSHIFT:
724 inner_op = RSHIFT_EXPR;
725 break;
726 }
727
728 tree inner_expr = build2 (inner_op,
729 result_type->as_tree (),
730 node_a,
731 node_b);
732 if (loc)
733 set_tree_location (inner_expr, loc);
734
735 return new rvalue (this, inner_expr);
736}
737
738/* Construct a playback::rvalue instance (wrapping a tree) for a
739 comparison. */
740
741playback::rvalue *
742playback::context::
743new_comparison (location *loc,
744 enum gcc_jit_comparison op,
745 rvalue *a, rvalue *b)
746{
747 // FIXME: type-checking, or coercion?
748 enum tree_code inner_op;
749
750 gcc_assert (a);
751 gcc_assert (b);
752
753 switch (op)
754 {
755 default:
756 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
757 return NULL;
758
759 case GCC_JIT_COMPARISON_EQ:
760 inner_op = EQ_EXPR;
761 break;
762 case GCC_JIT_COMPARISON_NE:
763 inner_op = NE_EXPR;
764 break;
765 case GCC_JIT_COMPARISON_LT:
766 inner_op = LT_EXPR;
767 break;
768 case GCC_JIT_COMPARISON_LE:
769 inner_op = LE_EXPR;
770 break;
771 case GCC_JIT_COMPARISON_GT:
772 inner_op = GT_EXPR;
773 break;
774 case GCC_JIT_COMPARISON_GE:
775 inner_op = GE_EXPR;
776 break;
777 }
778
779 tree inner_expr = build2 (inner_op,
780 boolean_type_node,
781 a->as_tree (),
782 b->as_tree ());
783 if (loc)
784 set_tree_location (inner_expr, loc);
785 return new rvalue (this, inner_expr);
786}
787
788/* Construct a playback::rvalue instance (wrapping a tree) for a
789 function call. */
790
791playback::rvalue *
792playback::context::
793build_call (location *loc,
794 tree fn_ptr,
b957b2e0 795 const auto_vec<rvalue *> *args)
35485da9
DM
796{
797 vec<tree, va_gc> *tree_args;
b957b2e0
DM
798 vec_alloc (tree_args, args->length ());
799 for (unsigned i = 0; i < args->length (); i++)
800 tree_args->quick_push ((*args)[i]->as_tree ());
35485da9
DM
801
802 if (loc)
803 set_tree_location (fn_ptr, loc);
804
805 tree fn = TREE_TYPE (fn_ptr);
806 tree fn_type = TREE_TYPE (fn);
807 tree return_type = TREE_TYPE (fn_type);
808
809 return new rvalue (this,
810 build_call_vec (return_type,
811 fn_ptr, tree_args));
812
813 /* see c-typeck.c: build_function_call
814 which calls build_function_call_vec
815
816 which does lots of checking, then:
817 result = build_call_array_loc (loc, TREE_TYPE (fntype),
818 function, nargs, argarray);
819 which is in tree.c
820 (see also build_call_vec)
821 */
822}
823
824/* Construct a playback::rvalue instance (wrapping a tree) for a
825 call to a specific function. */
826
827playback::rvalue *
828playback::context::
829new_call (location *loc,
830 function *func,
b957b2e0 831 const auto_vec<rvalue *> *args)
35485da9
DM
832{
833 tree fndecl;
834
835 gcc_assert (func);
836
837 fndecl = func->as_fndecl ();
838
839 tree fntype = TREE_TYPE (fndecl);
840
841 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
842
843 return build_call (loc, fn, args);
844}
845
846/* Construct a playback::rvalue instance (wrapping a tree) for a
847 call through a function pointer. */
848
849playback::rvalue *
850playback::context::
851new_call_through_ptr (location *loc,
852 rvalue *fn_ptr,
b957b2e0 853 const auto_vec<rvalue *> *args)
35485da9
DM
854{
855 gcc_assert (fn_ptr);
856 tree t_fn_ptr = fn_ptr->as_tree ();
857
858 return build_call (loc, t_fn_ptr, args);
859}
860
861/* Construct a tree for a cast. */
862
863tree
864playback::context::build_cast (playback::location *loc,
865 playback::rvalue *expr,
866 playback::type *type_)
867{
868 /* For comparison, see:
869 - c/c-typeck.c:build_c_cast
870 - c/c-convert.c: convert
871 - convert.h
872
873 Only some kinds of cast are currently supported here. */
874 tree t_expr = expr->as_tree ();
875 tree t_dst_type = type_->as_tree ();
876 tree t_ret = NULL;
877 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
878 if (t_ret)
879 return t_ret;
880 enum tree_code dst_code = TREE_CODE (t_dst_type);
881 switch (dst_code)
882 {
883 case INTEGER_TYPE:
884 case ENUMERAL_TYPE:
885 t_ret = convert_to_integer (t_dst_type, t_expr);
886 goto maybe_fold;
887
888 case BOOLEAN_TYPE:
889 /* Compare with c_objc_common_truthvalue_conversion and
890 c_common_truthvalue_conversion. */
891 /* For now, convert to: (t_expr != 0) */
892 t_ret = build2 (NE_EXPR, t_dst_type,
893 t_expr, integer_zero_node);
894 goto maybe_fold;
895
896 case REAL_TYPE:
897 t_ret = convert_to_real (t_dst_type, t_expr);
898 goto maybe_fold;
899
900 case POINTER_TYPE:
901 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
902 goto maybe_fold;
903
904 default:
905 add_error (loc, "couldn't handle cast during playback");
906 fprintf (stderr, "input expression:\n");
907 debug_tree (t_expr);
908 fprintf (stderr, "requested type:\n");
909 debug_tree (t_dst_type);
910 return error_mark_node;
911
912 maybe_fold:
913 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
914 t_ret = fold (t_ret);
915 return t_ret;
916 }
917}
918
919/* Construct a playback::rvalue instance (wrapping a tree) for a
920 cast. */
921
922playback::rvalue *
923playback::context::
924new_cast (playback::location *loc,
925 playback::rvalue *expr,
926 playback::type *type_)
927{
928
929 tree t_cast = build_cast (loc, expr, type_);
930 if (loc)
931 set_tree_location (t_cast, loc);
932 return new rvalue (this, t_cast);
933}
934
935/* Construct a playback::lvalue instance (wrapping a tree) for an
936 array access. */
937
938playback::lvalue *
939playback::context::
940new_array_access (location *loc,
941 rvalue *ptr,
942 rvalue *index)
943{
944 gcc_assert (ptr);
945 gcc_assert (index);
946
947 /* For comparison, see:
948 c/c-typeck.c: build_array_ref
949 c-family/c-common.c: pointer_int_sum
950 */
951 tree t_ptr = ptr->as_tree ();
952 tree t_index = index->as_tree ();
953 tree t_type_ptr = TREE_TYPE (t_ptr);
954 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
955
956 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
957 {
958 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
959 NULL_TREE, NULL_TREE);
960 if (loc)
961 set_tree_location (t_result, loc);
962 return new lvalue (this, t_result);
963 }
964 else
965 {
966 /* Convert index to an offset in bytes. */
967 tree t_sizeof = size_in_bytes (t_type_star_ptr);
968 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
969 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
970
971 /* Locate (ptr + offset). */
972 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
973
974 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
975 if (loc)
976 {
977 set_tree_location (t_sizeof, loc);
978 set_tree_location (t_offset, loc);
979 set_tree_location (t_address, loc);
980 set_tree_location (t_indirection, loc);
981 }
982
983 return new lvalue (this, t_indirection);
984 }
985}
986
987/* Construct a tree for a field access. */
988
989tree
990playback::context::
991new_field_access (location *loc,
992 tree datum,
993 field *field)
994{
995 gcc_assert (datum);
996 gcc_assert (field);
997
998 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
999 build_component_ref. */
1000 tree type = TREE_TYPE (datum);
1001 gcc_assert (type);
1002 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1003
1004 tree t_field = field->as_tree ();
1005 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1006 t_field, NULL_TREE);
1007 if (loc)
1008 set_tree_location (ref, loc);
1009 return ref;
1010}
1011
1012/* Construct a tree for a dereference. */
1013
1014tree
1015playback::context::
1016new_dereference (tree ptr,
1017 location *loc)
1018{
1019 gcc_assert (ptr);
1020
1021 tree type = TREE_TYPE (TREE_TYPE(ptr));
1022 tree datum = build1 (INDIRECT_REF, type, ptr);
1023 if (loc)
1024 set_tree_location (datum, loc);
1025 return datum;
1026}
1027
1028/* Construct a playback::lvalue instance (wrapping a tree) for a
1029 field access. */
1030
1031playback::lvalue *
1032playback::lvalue::
1033access_field (location *loc,
1034 field *field)
1035{
1036 tree datum = as_tree ();
1037 tree ref = get_context ()->new_field_access (loc, datum, field);
1038 if (!ref)
1039 return NULL;
1040 return new lvalue (get_context (), ref);
1041}
1042
1043/* Construct a playback::rvalue instance (wrapping a tree) for a
1044 field access. */
1045
1046playback::rvalue *
1047playback::rvalue::
1048access_field (location *loc,
1049 field *field)
1050{
1051 tree datum = as_tree ();
1052 tree ref = get_context ()->new_field_access (loc, datum, field);
1053 if (!ref)
1054 return NULL;
1055 return new rvalue (get_context (), ref);
1056}
1057
1058/* Construct a playback::lvalue instance (wrapping a tree) for a
1059 dereferenced field access. */
1060
1061playback::lvalue *
1062playback::rvalue::
1063dereference_field (location *loc,
1064 field *field)
1065{
1066 tree ptr = as_tree ();
1067 tree datum = get_context ()->new_dereference (ptr, loc);
1068 if (!datum)
1069 return NULL;
1070 tree ref = get_context ()->new_field_access (loc, datum, field);
1071 if (!ref)
1072 return NULL;
1073 return new lvalue (get_context (), ref);
1074}
1075
1076/* Construct a playback::lvalue instance (wrapping a tree) for a
1077 dereference. */
1078
1079playback::lvalue *
1080playback::rvalue::
1081dereference (location *loc)
1082{
1083 tree ptr = as_tree ();
1084 tree datum = get_context ()->new_dereference (ptr, loc);
1085 return new lvalue (get_context (), datum);
1086}
1087
1088/* Construct a playback::rvalue instance (wrapping a tree) for an
1089 address-lookup. */
1090
1091playback::rvalue *
1092playback::lvalue::
1093get_address (location *loc)
1094{
1095 tree t_lvalue = as_tree ();
1096 tree t_thistype = TREE_TYPE (t_lvalue);
1097 tree t_ptrtype = build_pointer_type (t_thistype);
1098 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1099 if (loc)
1100 get_context ()->set_tree_location (ptr, loc);
1101 return new rvalue (get_context (), ptr);
1102}
1103
b957b2e0
DM
1104/* The wrapper subclasses are GC-managed, but can own non-GC memory.
1105 Provide this finalization hook for calling then they are collected,
1106 which calls the finalizer vfunc. This allows them to call "release"
1107 on any vec<> within them. */
1108
1109static void
1110wrapper_finalizer (void *ptr)
1111{
1112 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1113 wrapper->finalizer ();
1114}
1115
35485da9
DM
1116/* gcc::jit::playback::wrapper subclasses are GC-managed:
1117 allocate them using ggc_internal_cleared_alloc. */
1118
1119void *
1120playback::wrapper::
1121operator new (size_t sz)
1122{
b957b2e0
DM
1123 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1124
35485da9
DM
1125}
1126
1127/* Constructor for gcc:jit::playback::function. */
1128
1129playback::function::
1130function (context *ctxt,
1131 tree fndecl,
1132 enum gcc_jit_function_kind kind)
1133: m_ctxt(ctxt),
1134 m_inner_fndecl (fndecl),
1135 m_inner_bind_expr (NULL),
1136 m_kind (kind)
1137{
1138 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1139 {
1140 /* Create a BIND_EXPR, and within it, a statement list. */
1141 m_stmt_list = alloc_stmt_list ();
1142 m_stmt_iter = tsi_start (m_stmt_list);
1143 m_inner_block = make_node (BLOCK);
1144 m_inner_bind_expr =
1145 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1146 }
1147 else
1148 {
1149 m_inner_block = NULL;
1150 m_stmt_list = NULL;
1151 }
1152}
1153
1154/* Hand-written GC-marking hook for playback functions. */
1155
1156void
1157playback::function::
1158gt_ggc_mx ()
1159{
1160 gt_ggc_m_9tree_node (m_inner_fndecl);
1161 gt_ggc_m_9tree_node (m_inner_bind_expr);
1162 gt_ggc_m_9tree_node (m_stmt_list);
1163 gt_ggc_m_9tree_node (m_inner_block);
1164}
1165
b957b2e0
DM
1166/* Don't leak vec's internal buffer (in non-GC heap) when we are
1167 GC-ed. */
1168
1169void
1170playback::function::finalizer ()
1171{
1172 m_blocks.release ();
1173}
1174
35485da9
DM
1175/* Get the return type of a playback function, in tree form. */
1176
1177tree
1178playback::function::
1179get_return_type_as_tree () const
1180{
1181 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1182}
1183
1184/* Construct a new local within this playback::function. */
1185
1186playback::lvalue *
1187playback::function::
1188new_local (location *loc,
1189 type *type,
1190 const char *name)
1191{
1192 gcc_assert (type);
1193 gcc_assert (name);
1194 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1195 get_identifier (name),
1196 type->as_tree ());
1197 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1198
1199 /* Prepend to BIND_EXPR_VARS: */
1200 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1201 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1202
1203 if (loc)
1204 set_tree_location (inner, loc);
1205 return new lvalue (m_ctxt, inner);
1206}
1207
1208/* Construct a new block within this playback::function. */
1209
1210playback::block *
1211playback::function::
1212new_block (const char *name)
1213{
1214 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1215
1216 block *result = new playback::block (this, name);
1217 m_blocks.safe_push (result);
1218 return result;
1219}
1220
1221/* Build a statement list for the function as a whole out of the
1222 lists of statements for the individual blocks, building labels
1223 for each block. */
1224
1225void
1226playback::function::
1227build_stmt_list ()
1228{
1229 int i;
1230 block *b;
1231
1232 FOR_EACH_VEC_ELT (m_blocks, i, b)
1233 {
1234 int j;
1235 tree stmt;
1236
1237 b->m_label_expr = build1 (LABEL_EXPR,
1238 void_type_node,
1239 b->as_label_decl ());
1240 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1241
1242 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1243 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1244 }
1245}
1246
1247/* Finish compiling the given function, potentially running the
1248 garbage-collector.
1249 The function will have a statement list by now.
1250 Amongst other things, this gimplifies the statement list,
1251 and calls cgraph_node::finalize_function on the function. */
1252
1253void
1254playback::function::
1255postprocess ()
1256{
1257 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1258 debug_tree (m_stmt_list);
1259
1260 /* Do we need this to force cgraphunit.c to output the function? */
1261 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1262 {
1263 DECL_EXTERNAL (m_inner_fndecl) = 0;
1264 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1265 }
1266
1267 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1268 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1269 {
1270 DECL_EXTERNAL (m_inner_fndecl) = 0;
1271 TREE_PUBLIC (m_inner_fndecl) = 0;
1272 }
1273
1274 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1275 {
1276 /* Seem to need this in gimple-low.c: */
1277 gcc_assert (m_inner_block);
1278 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1279
1280 /* how to add to function? the following appears to be how to
1281 set the body of a m_inner_fndecl: */
1282 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1283
1284 /* Ensure that locals appear in the debuginfo. */
1285 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1286
1287 //debug_tree (m_inner_fndecl);
1288
1289 /* Convert to gimple: */
1290 //printf("about to gimplify_function_tree\n");
1291 gimplify_function_tree (m_inner_fndecl);
1292 //printf("finished gimplify_function_tree\n");
1293
1294 current_function_decl = m_inner_fndecl;
1295 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1296 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1297 //debug_tree (m_inner_fndecl);
1298
1299 //printf("about to add to cgraph\n");
1300 /* Add to cgraph: */
1301 cgraph_node::finalize_function (m_inner_fndecl, false);
1302 /* This can trigger a collection, so we need to have all of
1303 the funcs as roots. */
1304
1305 current_function_decl = NULL;
1306 }
1307}
1308
b957b2e0
DM
1309/* Don't leak vec's internal buffer (in non-GC heap) when we are
1310 GC-ed. */
1311
1312void
1313playback::block::finalizer ()
1314{
1315 m_stmts.release ();
1316}
1317
35485da9
DM
1318/* Add an eval of the rvalue to the function's statement list. */
1319
1320void
1321playback::block::
1322add_eval (location *loc,
1323 rvalue *rvalue)
1324{
1325 gcc_assert (rvalue);
1326
1327 if (loc)
1328 set_tree_location (rvalue->as_tree (), loc);
1329
1330 add_stmt (rvalue->as_tree ());
1331}
1332
1333/* Add an assignment to the function's statement list. */
1334
1335void
1336playback::block::
1337add_assignment (location *loc,
1338 lvalue *lvalue,
1339 rvalue *rvalue)
1340{
1341 gcc_assert (lvalue);
1342 gcc_assert (rvalue);
1343
1344 tree t_lvalue = lvalue->as_tree ();
1345 tree t_rvalue = rvalue->as_tree ();
1346 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1347 {
1348 t_rvalue = build1 (CONVERT_EXPR,
1349 TREE_TYPE (t_lvalue),
1350 t_rvalue);
1351 if (loc)
1352 set_tree_location (t_rvalue, loc);
1353 }
1354
1355 tree stmt =
1356 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1357 t_lvalue, t_rvalue);
1358 if (loc)
1359 set_tree_location (stmt, loc);
1360 add_stmt (stmt);
1361}
1362
1363/* Add a comment to the function's statement list.
1364 For now this is done by adding a dummy label. */
1365
1366void
1367playback::block::
1368add_comment (location *loc,
1369 const char *text)
1370{
1371 /* Wrap the text in C-style comment delimiters. */
1372 size_t sz =
1373 (3 /* opening delim */
1374 + strlen (text)
1375 + 3 /* closing delim */
1376 + 1 /* terminator */);
1377 char *wrapped = (char *)ggc_internal_alloc (sz);
1378 snprintf (wrapped, sz, "/* %s */", text);
1379
1380 /* For now we simply implement this by adding a dummy label with a name
1381 containing the given text. */
1382 tree identifier = get_identifier (wrapped);
1383 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1384 identifier, void_type_node);
1385 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1386
1387 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1388 if (loc)
1389 set_tree_location (label_expr, loc);
1390 add_stmt (label_expr);
1391}
1392
1393/* Add a conditional jump statement to the function's statement list. */
1394
1395void
1396playback::block::
1397add_conditional (location *loc,
1398 rvalue *boolval,
1399 block *on_true,
1400 block *on_false)
1401{
1402 gcc_assert (boolval);
1403 gcc_assert (on_true);
1404 gcc_assert (on_false);
1405
1406 /* COND_EXPR wants statement lists for the true/false operands, but we
1407 want labels.
1408 Shim it by creating jumps to the labels */
1409 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1410 on_true->as_label_decl ());
1411 if (loc)
1412 set_tree_location (true_jump, loc);
1413
1414 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1415 on_false->as_label_decl ());
1416 if (loc)
1417 set_tree_location (false_jump, loc);
1418
1419 tree stmt =
1420 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1421 true_jump, false_jump);
1422 if (loc)
1423 set_tree_location (stmt, loc);
1424 add_stmt (stmt);
1425}
1426
1427/* Add an unconditional jump statement to the function's statement list. */
1428
1429void
1430playback::block::
1431add_jump (location *loc,
1432 block *target)
1433{
1434 gcc_assert (target);
1435
1436 // see c_finish_loop
1437 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1438 //add_stmt (top);
1439
1440 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1441 TREE_USED (target->as_label_decl ()) = 1;
1442 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1443 if (loc)
1444 set_tree_location (stmt, loc);
1445 add_stmt (stmt);
1446
1447 /*
1448 from c-typeck.c:
1449tree
1450c_finish_goto_label (location_t loc, tree label)
1451{
1452 tree decl = lookup_label_for_goto (loc, label);
1453 if (!decl)
1454 return NULL_TREE;
1455 TREE_USED (decl) = 1;
1456 {
1457 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1458 SET_EXPR_LOCATION (t, loc);
1459 return add_stmt (t);
1460 }
1461}
1462 */
1463
1464}
1465
1466/* Add a return statement to the function's statement list. */
1467
1468void
1469playback::block::
1470add_return (location *loc,
1471 rvalue *rvalue)
1472{
1473 tree modify_retval = NULL;
1474 tree return_type = m_func->get_return_type_as_tree ();
1475 if (rvalue)
1476 {
1477 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1478 tree t_rvalue = rvalue->as_tree ();
1479 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1480 t_rvalue = build1 (CONVERT_EXPR,
1481 TREE_TYPE (t_lvalue),
1482 t_rvalue);
1483 modify_retval = build2 (MODIFY_EXPR, return_type,
1484 t_lvalue, t_rvalue);
1485 if (loc)
1486 set_tree_location (modify_retval, loc);
1487 }
1488 tree return_stmt = build1 (RETURN_EXPR, return_type,
1489 modify_retval);
1490 if (loc)
1491 set_tree_location (return_stmt, loc);
1492
1493 add_stmt (return_stmt);
1494}
1495
1496/* Constructor for gcc::jit::playback::block. */
1497
1498playback::block::
1499block (function *func,
1500 const char *name)
1501: m_func (func),
1502 m_stmts ()
1503{
1504 tree identifier;
1505
1506 gcc_assert (func);
1507 // name can be NULL
1508 if (name)
1509 identifier = get_identifier (name);
1510 else
1511 identifier = NULL;
1512 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1513 identifier, void_type_node);
1514 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1515 m_label_expr = NULL;
1516}
1517
1518/* Construct a tempdir path template suitable for use by mkdtemp
1519 e.g. "/tmp/libgccjit-XXXXXX", but respecting the rules in
1520 libiberty's choose_tempdir rather than hardcoding "/tmp/".
1521
1522 The memory is allocated using malloc and must be freed.
1523 Aborts the process if allocation fails. */
1524
1525static char *
1526make_tempdir_path_template ()
1527{
1528 const char *tmpdir_buf;
1529 size_t tmpdir_len;
1530 const char *file_template_buf;
1531 size_t file_template_len;
1532 char *result;
1533
1534 /* The result of choose_tmpdir is a cached buffer within libiberty, so
1535 we must *not* free it. */
1536 tmpdir_buf = choose_tmpdir ();
1537
1538 /* choose_tmpdir aborts on malloc failure. */
1539 gcc_assert (tmpdir_buf);
1540
1541 tmpdir_len = strlen (tmpdir_buf);
1542 /* tmpdir_buf should now have a dir separator as the final byte. */
1543 gcc_assert (tmpdir_len > 0);
1544 gcc_assert (tmpdir_buf[tmpdir_len - 1] == DIR_SEPARATOR);
1545
1546 file_template_buf = "libgccjit-XXXXXX";
1547 file_template_len = strlen (file_template_buf);
1548
1549 result = XNEWVEC (char, tmpdir_len + file_template_len + 1);
1550 strcpy (result, tmpdir_buf);
1551 strcpy (result + tmpdir_len, file_template_buf);
1552
1553 return result;
1554}
1555
463366a0
DM
1556/* A subclass of auto_vec <char *> that frees all of its elements on
1557 deletion. */
1558
1559class auto_argvec : public auto_vec <char *>
1560{
1561 public:
1562 ~auto_argvec ();
1563};
1564
1565/* auto_argvec's dtor, freeing all contained strings, automatically
1566 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1567
1568auto_argvec::~auto_argvec ()
1569{
1570 int i;
1571 char *str;
1572 FOR_EACH_VEC_ELT (*this, i, str)
1573 free (str);
1574}
1575
35485da9
DM
1576/* Compile a playback::context:
1577
1578 - Use the context's options to cconstruct command-line options, and
1579 call into the rest of GCC (toplev::main).
1580 - Assuming it succeeds, we have a .s file; we want a .so file.
1581 Invoke another gcc to convert the .s file to a .so file.
1582 - dlopen the .so file
1583 - Wrap the result up as a playback::result and return it. */
1584
1585result *
1586playback::context::
1587compile ()
1588{
35485da9
DM
1589 const char *ctxt_progname;
1590 result *result_obj = NULL;
35485da9
DM
1591
1592 m_path_template = make_tempdir_path_template ();
1593 if (!m_path_template)
1594 return NULL;
1595
1596 /* Create tempdir using mkdtemp. This is created with 0700 perms and
1597 is unique. Hence no other (non-root) users should have access to
1598 the paths within it. */
1599 m_path_tempdir = mkdtemp (m_path_template);
1600 if (!m_path_tempdir)
1601 return NULL;
1602 m_path_c_file = concat (m_path_tempdir, "/fake.c", NULL);
1603 m_path_s_file = concat (m_path_tempdir, "/fake.s", NULL);
1604 m_path_so_file = concat (m_path_tempdir, "/fake.so", NULL);
1605
1606 /* Call into the rest of gcc.
1607 For now, we have to assemble command-line options to pass into
1608 toplev::main, so that they can be parsed. */
1609
1610 /* Pass in user-provided program name as argv0, if any, so that it
1611 makes it into GCC's "progname" global, used in various diagnostics. */
1612 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
35485da9 1613
c985705a
DM
1614 if (!ctxt_progname)
1615 ctxt_progname = "libgccjit.so";
1616
463366a0
DM
1617 auto_vec <recording::requested_dump> requested_dumps;
1618 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1619
1620 auto_argvec fake_args;
1621 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
8f50ee3c
DM
1622 if (errors_occurred ())
1623 return NULL;
35485da9 1624
38771e4e
DM
1625 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1626 acquire_mutex ();
1627
463366a0 1628 /* This runs the compiler. */
35485da9 1629 toplev toplev (false);
8f50ee3c
DM
1630 toplev.main (fake_args.length (),
1631 const_cast <char **> (fake_args.address ()));
463366a0
DM
1632
1633 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1634 need to do it between toplev::main (which creates the dump manager)
1635 and toplev::finalize (which deletes it). */
1636 extract_any_requested_dumps (&requested_dumps);
1637
1638 /* Clean up the compiler. */
35485da9
DM
1639 toplev.finalize ();
1640
38771e4e
DM
1641 /* Ideally we would release the jit mutex here, but we can't yet since
1642 followup activities use timevars, which are global state. */
35485da9
DM
1643
1644 if (errors_occurred ())
38771e4e
DM
1645 {
1646 release_mutex ();
1647 return NULL;
1648 }
35485da9
DM
1649
1650 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
c6760a13 1651 dump_generated_code ();
35485da9 1652
c6760a13
DM
1653 convert_to_dso (ctxt_progname);
1654 if (errors_occurred ())
38771e4e
DM
1655 {
1656 release_mutex ();
1657 return NULL;
1658 }
35485da9 1659
38f4f641 1660 result_obj = dlopen_built_dso ();
35485da9 1661
38771e4e
DM
1662 release_mutex ();
1663
35485da9
DM
1664 return result_obj;
1665}
1666
8f50ee3c
DM
1667/* Helper functions for gcc::jit::playback::context::compile. */
1668
38771e4e
DM
1669/* This mutex guards gcc::jit::recording::context::compile, so that only
1670 one thread can be accessing the bulk of GCC's state at once. */
1671
1672static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
1673
1674/* Acquire jit_mutex and set "this" as the active playback ctxt. */
1675
1676void
1677playback::context::acquire_mutex ()
1678{
1679 /* Acquire the big GCC mutex. */
1680 pthread_mutex_lock (&jit_mutex);
1681 gcc_assert (NULL == active_playback_ctxt);
1682 active_playback_ctxt = this;
1683}
1684
1685/* Release jit_mutex and clear the active playback ctxt. */
1686
1687void
1688playback::context::release_mutex ()
1689{
1690 /* Release the big GCC mutex. */
1691 gcc_assert (active_playback_ctxt == this);
1692 active_playback_ctxt = NULL;
1693 pthread_mutex_unlock (&jit_mutex);
1694}
1695
8f50ee3c
DM
1696/* Build a fake argv for toplev::main from the options set
1697 by the user on the context . */
1698
1699void
1700playback::context::
463366a0
DM
1701make_fake_args (vec <char *> *argvec,
1702 const char *ctxt_progname,
1703 vec <recording::requested_dump> *requested_dumps)
8f50ee3c 1704{
463366a0
DM
1705#define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
1706#define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
8f50ee3c
DM
1707
1708 ADD_ARG (ctxt_progname);
1709 ADD_ARG (m_path_c_file);
1710 ADD_ARG ("-fPIC");
1711
1712 /* Handle int options: */
1713 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
1714 {
1715 default:
1716 add_error (NULL,
1717 "unrecognized optimization level: %i",
1718 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
1719 return;
1720
1721 case 0:
1722 ADD_ARG ("-O0");
1723 break;
1724
1725 case 1:
1726 ADD_ARG ("-O1");
1727 break;
1728
1729 case 2:
1730 ADD_ARG ("-O2");
1731 break;
1732
1733 case 3:
1734 ADD_ARG ("-O3");
1735 break;
1736 }
1737 /* What about -Os? */
1738
1739 /* Handle bool options: */
1740 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
1741 ADD_ARG ("-g");
1742
1743 /* Suppress timing (and other) info. */
1744 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
1745 {
1746 ADD_ARG ("-quiet");
1747 quiet_flag = 1;
1748 }
1749
1750 /* Aggressively garbage-collect, to shake out bugs: */
1751 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
1752 {
1753 ADD_ARG ("--param");
1754 ADD_ARG ("ggc-min-expand=0");
1755 ADD_ARG ("--param");
1756 ADD_ARG ("ggc-min-heapsize=0");
1757 }
1758
1759 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
1760 {
1761 ADD_ARG ("-fdump-tree-all");
1762 ADD_ARG ("-fdump-rtl-all");
1763 ADD_ARG ("-fdump-ipa-all");
1764 }
463366a0
DM
1765
1766 /* Add "-fdump-" options for any calls to
1767 gcc_jit_context_enable_dump. */
1768 {
1769 int i;
1770 recording::requested_dump *d;
1771 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
1772 {
1773 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
1774 ADD_ARG_TAKE_OWNERSHIP (arg);
1775 }
1776 }
1777
8f50ee3c 1778#undef ADD_ARG
463366a0
DM
1779#undef ADD_ARG_TAKE_OWNERSHIP
1780}
1781
1782/* The second half of the implementation of gcc_jit_context_enable_dump.
1783 Iterate through the requested dumps, reading the underlying files
1784 into heap-allocated buffers, writing pointers to the buffers into
1785 the char ** pointers provided by client code.
1786 Client code is responsible for calling free on the results. */
1787
1788void
1789playback::context::
1790extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
1791{
1792 int i;
1793 recording::requested_dump *d;
1794 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
1795 {
1796 dump_file_info *dfi;
1797 char *filename;
1798 char *content;
1799
1800 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
1801 if (!dfi)
1802 {
1803 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
1804 continue;
1805 }
1806
1807 filename = g->get_dumps ()->get_dump_file_name (dfi);
1808 content = read_dump_file (filename);
1809 *(d->m_out_ptr) = content;
1810 free (filename);
1811 }
1812}
1813
1814/* Helper function for playback::context::extract_any_requested_dumps
1815 (itself for use in implementation of gcc_jit_context_enable_dump).
1816
1817 Attempt to read the complete file at the given path, returning the
1818 bytes found there as a buffer.
1819 The caller is responsible for calling free on the result.
1820 Errors will be reported on the context, and lead to NULL being
1821 returned; an out-of-memory error will terminate the process. */
1822
1823char *
1824playback::context::read_dump_file (const char *path)
1825{
1826 char *result = NULL;
1827 size_t total_sz = 0;
1828 char buf[4096];
1829 size_t sz;
1830 FILE *f_in;
1831
1832 f_in = fopen (path, "r");
1833 if (!f_in)
1834 {
1835 add_error (NULL, "unable to open %s for reading", path);
1836 return NULL;
1837 }
1838
1839 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
1840 {
1841 size_t old_total_sz = total_sz;
1842 total_sz += sz;
1843 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
1844 memcpy (result + old_total_sz, buf, sz);
1845 }
1846
1847 if (!feof (f_in))
1848 {
1849 add_error (NULL, "error reading from %s", path);
1850 free (result);
1851 return NULL;
1852 }
1853
1854 fclose (f_in);
1855
1856 if (result)
1857 {
1858 result[total_sz] = '\0';
1859 return result;
1860 }
1861 else
1862 return xstrdup ("");
8f50ee3c
DM
1863}
1864
c6760a13
DM
1865/* Part of playback::context::compile ().
1866
1867 We have a .s file; we want a .so file.
1868 We could reuse parts of gcc/gcc.c to do this.
1869 For now, just use the driver binary from the install, as
1870 named in gcc-driver-name.h
1871 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
1872
1873void
1874playback::context::
1875convert_to_dso (const char *ctxt_progname)
1876{
1877 /* Currently this lumps together both assembling and linking into
1878 TV_ASSEMBLE. */
1879 auto_timevar assemble_timevar (TV_ASSEMBLE);
1880 const char *errmsg;
1881 const char *argv[7];
1882 int exit_status = 0;
1883 int err = 0;
1884 const char *gcc_driver_name = GCC_DRIVER_NAME;
1885
1886 argv[0] = gcc_driver_name;
1887 argv[1] = "-shared";
1888 /* The input: assembler. */
1889 argv[2] = m_path_s_file;
1890 /* The output: shared library. */
1891 argv[3] = "-o";
1892 argv[4] = m_path_so_file;
1893
1894 /* Don't use the linker plugin.
1895 If running with just a "make" and not a "make install", then we'd
1896 run into
1897 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
1898 libto_plugin is a .la at build time, with it becoming installed with
1899 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
1900 time. */
1901 argv[5] = "-fno-use-linker-plugin";
1902
1903 /* pex argv arrays are NULL-terminated. */
1904 argv[6] = NULL;
1905
1906 /* pex_one's error-handling requires pname to be non-NULL. */
1907 gcc_assert (ctxt_progname);
1908
1909 errmsg = pex_one (PEX_SEARCH, /* int flags, */
1910 gcc_driver_name,
1911 const_cast<char * const *> (argv),
1912 ctxt_progname, /* const char *pname */
1913 NULL, /* const char *outname */
1914 NULL, /* const char *errname */
1915 &exit_status, /* int *status */
1916 &err); /* int *err*/
1917 if (errmsg)
1918 {
1919 add_error (NULL, "error invoking gcc driver: %s", errmsg);
1920 return;
1921 }
1922
1923 /* pex_one can return a NULL errmsg when the executable wasn't
1924 found (or doesn't exist), so trap these cases also. */
1925 if (exit_status || err)
1926 {
1927 add_error (NULL,
1928 "error invoking gcc driver: exit_status: %i err: %i",
1929 exit_status, err);
1930 add_error (NULL,
1931 "whilst attempting to run a driver named: %s",
1932 gcc_driver_name);
1933 add_error (NULL,
1934 "PATH was: %s",
1935 getenv ("PATH"));
1936 return;
1937 }
1938}
1939
38f4f641
DM
1940/* Dynamically-link the built DSO file into this process, using dlopen.
1941 Wrap it up within a jit::result *, and return that.
1942 Return NULL if any errors occur, reporting them on this context. */
1943
1944result *
1945playback::context::
1946dlopen_built_dso ()
1947{
1948 auto_timevar load_timevar (TV_LOAD);
1949 void *handle = NULL;
1950 const char *error = NULL;
1951 result *result_obj = NULL;
1952
1953 /* Clear any existing error. */
1954 dlerror ();
1955
1956 handle = dlopen (m_path_so_file, RTLD_NOW | RTLD_LOCAL);
1957 if ((error = dlerror()) != NULL) {
1958 add_error (NULL, "%s", error);
1959 }
1960 if (handle)
1961 result_obj = new result (handle);
1962 else
1963 result_obj = NULL;
1964
1965 return result_obj;
1966}
1967
35485da9
DM
1968/* Top-level hook for playing back a recording context.
1969
1970 This plays back m_recording_ctxt, and, if no errors
1971 occurred builds statement lists for and then postprocesses
1972 every function in the result. */
1973
1974void
1975playback::context::
1976replay ()
1977{
1978 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
1979 tree array_domain_type = build_index_type (size_int (200));
1980 m_char_array_type_node
1981 = build_array_type (char_type_node, array_domain_type);
1982
1983 m_const_char_ptr
1984 = build_pointer_type (build_qualified_type (char_type_node,
1985 TYPE_QUAL_CONST));
1986
1987 /* Replay the recorded events: */
1988 timevar_push (TV_JIT_REPLAY);
1989
1990 m_recording_ctxt->replay_into (this);
1991
1992 /* Clean away the temporary references from recording objects
1993 to playback objects. We have to do this now since the
1994 latter are GC-allocated, but the former don't mark these
1995 refs. Hence we must stop using them before the GC can run. */
1996 m_recording_ctxt->disassociate_from_playback ();
1997
eeafb319
DM
1998 /* The builtins_manager, if any, is associated with the recording::context
1999 and might be reused for future compiles on other playback::contexts,
2000 but its m_attributes array is not GTY-labeled and hence will become
2001 nonsense if the GC runs. Purge this state. */
2002 builtins_manager *bm = get_builtins_manager ();
2003 if (bm)
2004 bm->finish_playback ();
2005
35485da9
DM
2006 timevar_pop (TV_JIT_REPLAY);
2007
2008 if (!errors_occurred ())
2009 {
2010 int i;
2011 function *func;
2012
2013 /* No GC can happen yet; process the cached source locations. */
2014 handle_locations ();
2015
2016 /* We've now created tree nodes for the stmts in the various blocks
2017 in each function, but we haven't built each function's single stmt
2018 list yet. Do so now. */
2019 FOR_EACH_VEC_ELT (m_functions, i, func)
2020 func->build_stmt_list ();
2021
2022 /* No GC can have happened yet. */
2023
2024 /* Postprocess the functions. This could trigger GC. */
2025 FOR_EACH_VEC_ELT (m_functions, i, func)
2026 {
2027 gcc_assert (func);
2028 func->postprocess ();
2029 }
2030 }
2031}
2032
2033/* Dump the generated .s file to stderr. */
2034
2035void
2036playback::context::
2037dump_generated_code ()
2038{
2039 char buf[4096];
2040 size_t sz;
2041 FILE *f_in = fopen (m_path_s_file, "r");
2042 if (!f_in)
2043 return;
2044
2045 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2046 fwrite (buf, 1, sz, stderr);
2047
2048 fclose (f_in);
2049}
2050
2051/* qsort comparator for comparing pairs of playback::source_line *,
2052 ordering them by line number. */
2053
2054static int
2055line_comparator (const void *lhs, const void *rhs)
2056{
2057 const playback::source_line *line_lhs = \
2058 *static_cast<const playback::source_line * const*> (lhs);
2059 const playback::source_line *line_rhs = \
2060 *static_cast<const playback::source_line * const*> (rhs);
2061 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2062}
2063
2064/* qsort comparator for comparing pairs of playback::location *,
2065 ordering them by column number. */
2066
2067static int
2068location_comparator (const void *lhs, const void *rhs)
2069{
2070 const playback::location *loc_lhs = \
2071 *static_cast<const playback::location * const *> (lhs);
2072 const playback::location *loc_rhs = \
2073 *static_cast<const playback::location * const *> (rhs);
2074 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2075}
2076
2077/* Our API allows locations to be created in arbitrary orders, but the
2078 linemap API requires locations to be created in ascending order
2079 as if we were tokenizing files.
2080
2081 This hook sorts all of the the locations that have been created, and
2082 calls into the linemap API, creating linemap entries in sorted order
2083 for our locations. */
2084
2085void
2086playback::context::
2087handle_locations ()
2088{
2089 /* Create the source code locations, following the ordering rules
2090 imposed by the linemap API.
2091
2092 line_table is a global. */
2093 int i;
2094 source_file *file;
2095
2096 FOR_EACH_VEC_ELT (m_source_files, i, file)
2097 {
2098 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2099
2100 /* Sort lines by ascending line numbers. */
2101 file->m_source_lines.qsort (&line_comparator);
2102
2103 int j;
2104 source_line *line;
2105 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2106 {
2107 int k;
2108 location *loc;
2109
2110 /* Sort locations in line by ascending column numbers. */
2111 line->m_locations.qsort (&location_comparator);
2112
2113 /* Determine maximum column within this line. */
2114 gcc_assert (line->m_locations.length () > 0);
2115 location *final_column =
2116 line->m_locations[line->m_locations.length () - 1];
2117 int max_col = final_column->get_column_num ();
2118
2119 linemap_line_start (line_table, line->get_line_num (), max_col);
2120 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2121 {
2122 loc->m_srcloc = \
2123 linemap_position_for_column (line_table, loc->get_column_num ());
2124 }
2125 }
2126
2127 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2128 }
2129
2130 /* line_table should now be populated; every playback::location should
2131 now have an m_srcloc. */
2132
2133 /* Now assign them to tree nodes as appropriate. */
2134 std::pair<tree, location *> *cached_location;
2135
2136 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2137 {
2138 tree t = cached_location->first;
2139 source_location srcloc = cached_location->second->m_srcloc;
2140
2141 /* This covers expressions: */
2142 if (CAN_HAVE_LOCATION_P (t))
2143 SET_EXPR_LOCATION (t, srcloc);
2144 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2145 DECL_SOURCE_LOCATION (t) = srcloc;
2146 else
2147 {
2148 /* Don't know how to set location on this node. */
2149 }
2150 }
2151}
2152
2153/* We handle errors on a playback::context by adding them to the
2154 corresponding recording::context. */
2155
2156void
2157playback::context::
2158add_error (location *loc, const char *fmt, ...)
2159{
2160 va_list ap;
2161 va_start (ap, fmt);
2162 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2163 fmt, ap);
2164 va_end (ap);
2165}
2166
2167/* We handle errors on a playback::context by adding them to the
2168 corresponding recording::context. */
2169
2170void
2171playback::context::
2172add_error_va (location *loc, const char *fmt, va_list ap)
2173{
2174 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2175 fmt, ap);
2176}
2177
35485da9
DM
2178/* Dealing with the linemap API. */
2179
2180/* Construct a playback::location for a recording::location, if it
2181 doesn't exist already. */
2182
2183playback::location *
2184playback::context::
2185new_location (recording::location *rloc,
2186 const char *filename,
2187 int line,
2188 int column)
2189{
2190 /* Get the source_file for filename, creating if necessary. */
2191 source_file *src_file = get_source_file (filename);
2192 /* Likewise for the line within the file. */
2193 source_line *src_line = src_file->get_source_line (line);
2194 /* Likewise for the column within the line. */
2195 location *loc = src_line->get_location (rloc, column);
2196 return loc;
2197}
2198
2199/* Deferred setting of the location for a given tree, by adding the
2200 (tree, playback::location) pair to a list of deferred associations.
2201 We will actually set the location on the tree later on once
2202 the source_location for the playback::location exists. */
2203
2204void
2205playback::context::
2206set_tree_location (tree t, location *loc)
2207{
2208 gcc_assert (loc);
2209 m_cached_locations.safe_push (std::make_pair (t, loc));
2210}
2211
2212
2213/* Construct a playback::source_file for the given source
2214 filename, if it doesn't exist already. */
2215
2216playback::source_file *
2217playback::context::
2218get_source_file (const char *filename)
2219{
2220 /* Locate the file.
2221 For simplicitly, this is currently a linear search.
2222 Replace with a hash if this shows up in the profile. */
2223 int i;
2224 source_file *file;
2225 tree ident_filename = get_identifier (filename);
2226
2227 FOR_EACH_VEC_ELT (m_source_files, i, file)
2228 if (file->filename_as_tree () == ident_filename)
2229 return file;
2230
2231 /* Not found. */
2232 file = new source_file (ident_filename);
2233 m_source_files.safe_push (file);
2234 return file;
2235}
2236
2237/* Constructor for gcc::jit::playback::source_file. */
2238
2239playback::source_file::source_file (tree filename) :
2240 m_source_lines (),
2241 m_filename (filename)
2242{
2243}
2244
b957b2e0
DM
2245/* Don't leak vec's internal buffer (in non-GC heap) when we are
2246 GC-ed. */
2247
2248void
2249playback::source_file::finalizer ()
2250{
2251 m_source_lines.release ();
2252}
2253
35485da9
DM
2254/* Construct a playback::source_line for the given line
2255 within this source file, if one doesn't exist already. */
2256
2257playback::source_line *
2258playback::source_file::
2259get_source_line (int line_num)
2260{
2261 /* Locate the line.
2262 For simplicitly, this is currently a linear search.
2263 Replace with a hash if this shows up in the profile. */
2264 int i;
2265 source_line *line;
2266
2267 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2268 if (line->get_line_num () == line_num)
2269 return line;
2270
2271 /* Not found. */
2272 line = new source_line (this, line_num);
2273 m_source_lines.safe_push (line);
2274 return line;
2275}
2276
2277/* Constructor for gcc::jit::playback::source_line. */
2278
2279playback::source_line::source_line (source_file *file, int line_num) :
2280 m_locations (),
2281 m_source_file (file),
2282 m_line_num (line_num)
2283{
2284}
b957b2e0
DM
2285
2286/* Don't leak vec's internal buffer (in non-GC heap) when we are
2287 GC-ed. */
2288
2289void
2290playback::source_line::finalizer ()
2291{
2292 m_locations.release ();
2293}
35485da9
DM
2294
2295/* Construct a playback::location for the given column
2296 within this line of a specific source file, if one doesn't exist
2297 already. */
2298
2299playback::location *
2300playback::source_line::
2301get_location (recording::location *rloc, int column_num)
2302{
2303 int i;
2304 location *loc;
2305
2306 /* Another linear search that probably should be a hash table. */
2307 FOR_EACH_VEC_ELT (m_locations, i, loc)
2308 if (loc->get_column_num () == column_num)
2309 return loc;
2310
2311 /* Not found. */
2312 loc = new location (rloc, this, column_num);
2313 m_locations.safe_push (loc);
2314 return loc;
2315}
2316
2317/* Constructor for gcc::jit::playback::location. */
2318
2319playback::location::location (recording::location *loc,
2320 source_line *line,
2321 int column_num) :
2322 m_srcloc (UNKNOWN_LOCATION),
2323 m_recording_loc (loc),
2324 m_line (line),
2325 m_column_num(column_num)
2326{
2327}
2328
2329/* The active gcc::jit::playback::context instance. This is a singleton,
2330 guarded by jit_mutex. */
2331
2332playback::context *active_playback_ctxt;
2333
2334} // namespace gcc::jit
2335
2336} // namespace gcc