]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/jit/jit-playback.c
[AArch64] Add TARGET_SCHED_REASSOCIATION_WIDTH
[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{
1589 void *handle = NULL;
1590 const char *ctxt_progname;
1591 result *result_obj = NULL;
35485da9
DM
1592
1593 m_path_template = make_tempdir_path_template ();
1594 if (!m_path_template)
1595 return NULL;
1596
1597 /* Create tempdir using mkdtemp. This is created with 0700 perms and
1598 is unique. Hence no other (non-root) users should have access to
1599 the paths within it. */
1600 m_path_tempdir = mkdtemp (m_path_template);
1601 if (!m_path_tempdir)
1602 return NULL;
1603 m_path_c_file = concat (m_path_tempdir, "/fake.c", NULL);
1604 m_path_s_file = concat (m_path_tempdir, "/fake.s", NULL);
1605 m_path_so_file = concat (m_path_tempdir, "/fake.so", NULL);
1606
1607 /* Call into the rest of gcc.
1608 For now, we have to assemble command-line options to pass into
1609 toplev::main, so that they can be parsed. */
1610
1611 /* Pass in user-provided program name as argv0, if any, so that it
1612 makes it into GCC's "progname" global, used in various diagnostics. */
1613 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
35485da9 1614
c985705a
DM
1615 if (!ctxt_progname)
1616 ctxt_progname = "libgccjit.so";
1617
463366a0
DM
1618 auto_vec <recording::requested_dump> requested_dumps;
1619 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1620
1621 auto_argvec fake_args;
1622 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
8f50ee3c
DM
1623 if (errors_occurred ())
1624 return NULL;
35485da9 1625
463366a0 1626 /* This runs the compiler. */
35485da9 1627 toplev toplev (false);
8f50ee3c
DM
1628 toplev.main (fake_args.length (),
1629 const_cast <char **> (fake_args.address ()));
463366a0
DM
1630
1631 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1632 need to do it between toplev::main (which creates the dump manager)
1633 and toplev::finalize (which deletes it). */
1634 extract_any_requested_dumps (&requested_dumps);
1635
1636 /* Clean up the compiler. */
35485da9
DM
1637 toplev.finalize ();
1638
1639 active_playback_ctxt = NULL;
1640
1641 if (errors_occurred ())
1642 return NULL;
1643
1644 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
c6760a13 1645 dump_generated_code ();
35485da9 1646
c6760a13
DM
1647 convert_to_dso (ctxt_progname);
1648 if (errors_occurred ())
1649 return NULL;
35485da9
DM
1650
1651 /* dlopen the .so file. */
1652 {
1653 auto_timevar load_timevar (TV_LOAD);
1654
1655 const char *error;
1656
1657 /* Clear any existing error. */
1658 dlerror ();
1659
1660 handle = dlopen (m_path_so_file, RTLD_NOW | RTLD_LOCAL);
1661 if ((error = dlerror()) != NULL) {
1662 add_error (NULL, "%s", error);
1663 }
1664 if (handle)
1665 result_obj = new result (handle);
1666 else
1667 result_obj = NULL;
1668 }
1669
1670 return result_obj;
1671}
1672
8f50ee3c
DM
1673/* Helper functions for gcc::jit::playback::context::compile. */
1674
1675/* Build a fake argv for toplev::main from the options set
1676 by the user on the context . */
1677
1678void
1679playback::context::
463366a0
DM
1680make_fake_args (vec <char *> *argvec,
1681 const char *ctxt_progname,
1682 vec <recording::requested_dump> *requested_dumps)
8f50ee3c 1683{
463366a0
DM
1684#define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
1685#define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
8f50ee3c
DM
1686
1687 ADD_ARG (ctxt_progname);
1688 ADD_ARG (m_path_c_file);
1689 ADD_ARG ("-fPIC");
1690
1691 /* Handle int options: */
1692 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
1693 {
1694 default:
1695 add_error (NULL,
1696 "unrecognized optimization level: %i",
1697 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
1698 return;
1699
1700 case 0:
1701 ADD_ARG ("-O0");
1702 break;
1703
1704 case 1:
1705 ADD_ARG ("-O1");
1706 break;
1707
1708 case 2:
1709 ADD_ARG ("-O2");
1710 break;
1711
1712 case 3:
1713 ADD_ARG ("-O3");
1714 break;
1715 }
1716 /* What about -Os? */
1717
1718 /* Handle bool options: */
1719 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
1720 ADD_ARG ("-g");
1721
1722 /* Suppress timing (and other) info. */
1723 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
1724 {
1725 ADD_ARG ("-quiet");
1726 quiet_flag = 1;
1727 }
1728
1729 /* Aggressively garbage-collect, to shake out bugs: */
1730 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
1731 {
1732 ADD_ARG ("--param");
1733 ADD_ARG ("ggc-min-expand=0");
1734 ADD_ARG ("--param");
1735 ADD_ARG ("ggc-min-heapsize=0");
1736 }
1737
1738 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
1739 {
1740 ADD_ARG ("-fdump-tree-all");
1741 ADD_ARG ("-fdump-rtl-all");
1742 ADD_ARG ("-fdump-ipa-all");
1743 }
463366a0
DM
1744
1745 /* Add "-fdump-" options for any calls to
1746 gcc_jit_context_enable_dump. */
1747 {
1748 int i;
1749 recording::requested_dump *d;
1750 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
1751 {
1752 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
1753 ADD_ARG_TAKE_OWNERSHIP (arg);
1754 }
1755 }
1756
8f50ee3c 1757#undef ADD_ARG
463366a0
DM
1758#undef ADD_ARG_TAKE_OWNERSHIP
1759}
1760
1761/* The second half of the implementation of gcc_jit_context_enable_dump.
1762 Iterate through the requested dumps, reading the underlying files
1763 into heap-allocated buffers, writing pointers to the buffers into
1764 the char ** pointers provided by client code.
1765 Client code is responsible for calling free on the results. */
1766
1767void
1768playback::context::
1769extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
1770{
1771 int i;
1772 recording::requested_dump *d;
1773 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
1774 {
1775 dump_file_info *dfi;
1776 char *filename;
1777 char *content;
1778
1779 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
1780 if (!dfi)
1781 {
1782 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
1783 continue;
1784 }
1785
1786 filename = g->get_dumps ()->get_dump_file_name (dfi);
1787 content = read_dump_file (filename);
1788 *(d->m_out_ptr) = content;
1789 free (filename);
1790 }
1791}
1792
1793/* Helper function for playback::context::extract_any_requested_dumps
1794 (itself for use in implementation of gcc_jit_context_enable_dump).
1795
1796 Attempt to read the complete file at the given path, returning the
1797 bytes found there as a buffer.
1798 The caller is responsible for calling free on the result.
1799 Errors will be reported on the context, and lead to NULL being
1800 returned; an out-of-memory error will terminate the process. */
1801
1802char *
1803playback::context::read_dump_file (const char *path)
1804{
1805 char *result = NULL;
1806 size_t total_sz = 0;
1807 char buf[4096];
1808 size_t sz;
1809 FILE *f_in;
1810
1811 f_in = fopen (path, "r");
1812 if (!f_in)
1813 {
1814 add_error (NULL, "unable to open %s for reading", path);
1815 return NULL;
1816 }
1817
1818 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
1819 {
1820 size_t old_total_sz = total_sz;
1821 total_sz += sz;
1822 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
1823 memcpy (result + old_total_sz, buf, sz);
1824 }
1825
1826 if (!feof (f_in))
1827 {
1828 add_error (NULL, "error reading from %s", path);
1829 free (result);
1830 return NULL;
1831 }
1832
1833 fclose (f_in);
1834
1835 if (result)
1836 {
1837 result[total_sz] = '\0';
1838 return result;
1839 }
1840 else
1841 return xstrdup ("");
8f50ee3c
DM
1842}
1843
c6760a13
DM
1844/* Part of playback::context::compile ().
1845
1846 We have a .s file; we want a .so file.
1847 We could reuse parts of gcc/gcc.c to do this.
1848 For now, just use the driver binary from the install, as
1849 named in gcc-driver-name.h
1850 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
1851
1852void
1853playback::context::
1854convert_to_dso (const char *ctxt_progname)
1855{
1856 /* Currently this lumps together both assembling and linking into
1857 TV_ASSEMBLE. */
1858 auto_timevar assemble_timevar (TV_ASSEMBLE);
1859 const char *errmsg;
1860 const char *argv[7];
1861 int exit_status = 0;
1862 int err = 0;
1863 const char *gcc_driver_name = GCC_DRIVER_NAME;
1864
1865 argv[0] = gcc_driver_name;
1866 argv[1] = "-shared";
1867 /* The input: assembler. */
1868 argv[2] = m_path_s_file;
1869 /* The output: shared library. */
1870 argv[3] = "-o";
1871 argv[4] = m_path_so_file;
1872
1873 /* Don't use the linker plugin.
1874 If running with just a "make" and not a "make install", then we'd
1875 run into
1876 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
1877 libto_plugin is a .la at build time, with it becoming installed with
1878 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
1879 time. */
1880 argv[5] = "-fno-use-linker-plugin";
1881
1882 /* pex argv arrays are NULL-terminated. */
1883 argv[6] = NULL;
1884
1885 /* pex_one's error-handling requires pname to be non-NULL. */
1886 gcc_assert (ctxt_progname);
1887
1888 errmsg = pex_one (PEX_SEARCH, /* int flags, */
1889 gcc_driver_name,
1890 const_cast<char * const *> (argv),
1891 ctxt_progname, /* const char *pname */
1892 NULL, /* const char *outname */
1893 NULL, /* const char *errname */
1894 &exit_status, /* int *status */
1895 &err); /* int *err*/
1896 if (errmsg)
1897 {
1898 add_error (NULL, "error invoking gcc driver: %s", errmsg);
1899 return;
1900 }
1901
1902 /* pex_one can return a NULL errmsg when the executable wasn't
1903 found (or doesn't exist), so trap these cases also. */
1904 if (exit_status || err)
1905 {
1906 add_error (NULL,
1907 "error invoking gcc driver: exit_status: %i err: %i",
1908 exit_status, err);
1909 add_error (NULL,
1910 "whilst attempting to run a driver named: %s",
1911 gcc_driver_name);
1912 add_error (NULL,
1913 "PATH was: %s",
1914 getenv ("PATH"));
1915 return;
1916 }
1917}
1918
35485da9
DM
1919/* Top-level hook for playing back a recording context.
1920
1921 This plays back m_recording_ctxt, and, if no errors
1922 occurred builds statement lists for and then postprocesses
1923 every function in the result. */
1924
1925void
1926playback::context::
1927replay ()
1928{
1929 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
1930 tree array_domain_type = build_index_type (size_int (200));
1931 m_char_array_type_node
1932 = build_array_type (char_type_node, array_domain_type);
1933
1934 m_const_char_ptr
1935 = build_pointer_type (build_qualified_type (char_type_node,
1936 TYPE_QUAL_CONST));
1937
1938 /* Replay the recorded events: */
1939 timevar_push (TV_JIT_REPLAY);
1940
1941 m_recording_ctxt->replay_into (this);
1942
1943 /* Clean away the temporary references from recording objects
1944 to playback objects. We have to do this now since the
1945 latter are GC-allocated, but the former don't mark these
1946 refs. Hence we must stop using them before the GC can run. */
1947 m_recording_ctxt->disassociate_from_playback ();
1948
eeafb319
DM
1949 /* The builtins_manager, if any, is associated with the recording::context
1950 and might be reused for future compiles on other playback::contexts,
1951 but its m_attributes array is not GTY-labeled and hence will become
1952 nonsense if the GC runs. Purge this state. */
1953 builtins_manager *bm = get_builtins_manager ();
1954 if (bm)
1955 bm->finish_playback ();
1956
35485da9
DM
1957 timevar_pop (TV_JIT_REPLAY);
1958
1959 if (!errors_occurred ())
1960 {
1961 int i;
1962 function *func;
1963
1964 /* No GC can happen yet; process the cached source locations. */
1965 handle_locations ();
1966
1967 /* We've now created tree nodes for the stmts in the various blocks
1968 in each function, but we haven't built each function's single stmt
1969 list yet. Do so now. */
1970 FOR_EACH_VEC_ELT (m_functions, i, func)
1971 func->build_stmt_list ();
1972
1973 /* No GC can have happened yet. */
1974
1975 /* Postprocess the functions. This could trigger GC. */
1976 FOR_EACH_VEC_ELT (m_functions, i, func)
1977 {
1978 gcc_assert (func);
1979 func->postprocess ();
1980 }
1981 }
1982}
1983
1984/* Dump the generated .s file to stderr. */
1985
1986void
1987playback::context::
1988dump_generated_code ()
1989{
1990 char buf[4096];
1991 size_t sz;
1992 FILE *f_in = fopen (m_path_s_file, "r");
1993 if (!f_in)
1994 return;
1995
1996 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
1997 fwrite (buf, 1, sz, stderr);
1998
1999 fclose (f_in);
2000}
2001
2002/* qsort comparator for comparing pairs of playback::source_line *,
2003 ordering them by line number. */
2004
2005static int
2006line_comparator (const void *lhs, const void *rhs)
2007{
2008 const playback::source_line *line_lhs = \
2009 *static_cast<const playback::source_line * const*> (lhs);
2010 const playback::source_line *line_rhs = \
2011 *static_cast<const playback::source_line * const*> (rhs);
2012 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2013}
2014
2015/* qsort comparator for comparing pairs of playback::location *,
2016 ordering them by column number. */
2017
2018static int
2019location_comparator (const void *lhs, const void *rhs)
2020{
2021 const playback::location *loc_lhs = \
2022 *static_cast<const playback::location * const *> (lhs);
2023 const playback::location *loc_rhs = \
2024 *static_cast<const playback::location * const *> (rhs);
2025 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2026}
2027
2028/* Our API allows locations to be created in arbitrary orders, but the
2029 linemap API requires locations to be created in ascending order
2030 as if we were tokenizing files.
2031
2032 This hook sorts all of the the locations that have been created, and
2033 calls into the linemap API, creating linemap entries in sorted order
2034 for our locations. */
2035
2036void
2037playback::context::
2038handle_locations ()
2039{
2040 /* Create the source code locations, following the ordering rules
2041 imposed by the linemap API.
2042
2043 line_table is a global. */
2044 int i;
2045 source_file *file;
2046
2047 FOR_EACH_VEC_ELT (m_source_files, i, file)
2048 {
2049 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2050
2051 /* Sort lines by ascending line numbers. */
2052 file->m_source_lines.qsort (&line_comparator);
2053
2054 int j;
2055 source_line *line;
2056 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2057 {
2058 int k;
2059 location *loc;
2060
2061 /* Sort locations in line by ascending column numbers. */
2062 line->m_locations.qsort (&location_comparator);
2063
2064 /* Determine maximum column within this line. */
2065 gcc_assert (line->m_locations.length () > 0);
2066 location *final_column =
2067 line->m_locations[line->m_locations.length () - 1];
2068 int max_col = final_column->get_column_num ();
2069
2070 linemap_line_start (line_table, line->get_line_num (), max_col);
2071 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2072 {
2073 loc->m_srcloc = \
2074 linemap_position_for_column (line_table, loc->get_column_num ());
2075 }
2076 }
2077
2078 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2079 }
2080
2081 /* line_table should now be populated; every playback::location should
2082 now have an m_srcloc. */
2083
2084 /* Now assign them to tree nodes as appropriate. */
2085 std::pair<tree, location *> *cached_location;
2086
2087 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2088 {
2089 tree t = cached_location->first;
2090 source_location srcloc = cached_location->second->m_srcloc;
2091
2092 /* This covers expressions: */
2093 if (CAN_HAVE_LOCATION_P (t))
2094 SET_EXPR_LOCATION (t, srcloc);
2095 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2096 DECL_SOURCE_LOCATION (t) = srcloc;
2097 else
2098 {
2099 /* Don't know how to set location on this node. */
2100 }
2101 }
2102}
2103
2104/* We handle errors on a playback::context by adding them to the
2105 corresponding recording::context. */
2106
2107void
2108playback::context::
2109add_error (location *loc, const char *fmt, ...)
2110{
2111 va_list ap;
2112 va_start (ap, fmt);
2113 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2114 fmt, ap);
2115 va_end (ap);
2116}
2117
2118/* We handle errors on a playback::context by adding them to the
2119 corresponding recording::context. */
2120
2121void
2122playback::context::
2123add_error_va (location *loc, const char *fmt, va_list ap)
2124{
2125 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2126 fmt, ap);
2127}
2128
35485da9
DM
2129/* Dealing with the linemap API. */
2130
2131/* Construct a playback::location for a recording::location, if it
2132 doesn't exist already. */
2133
2134playback::location *
2135playback::context::
2136new_location (recording::location *rloc,
2137 const char *filename,
2138 int line,
2139 int column)
2140{
2141 /* Get the source_file for filename, creating if necessary. */
2142 source_file *src_file = get_source_file (filename);
2143 /* Likewise for the line within the file. */
2144 source_line *src_line = src_file->get_source_line (line);
2145 /* Likewise for the column within the line. */
2146 location *loc = src_line->get_location (rloc, column);
2147 return loc;
2148}
2149
2150/* Deferred setting of the location for a given tree, by adding the
2151 (tree, playback::location) pair to a list of deferred associations.
2152 We will actually set the location on the tree later on once
2153 the source_location for the playback::location exists. */
2154
2155void
2156playback::context::
2157set_tree_location (tree t, location *loc)
2158{
2159 gcc_assert (loc);
2160 m_cached_locations.safe_push (std::make_pair (t, loc));
2161}
2162
2163
2164/* Construct a playback::source_file for the given source
2165 filename, if it doesn't exist already. */
2166
2167playback::source_file *
2168playback::context::
2169get_source_file (const char *filename)
2170{
2171 /* Locate the file.
2172 For simplicitly, this is currently a linear search.
2173 Replace with a hash if this shows up in the profile. */
2174 int i;
2175 source_file *file;
2176 tree ident_filename = get_identifier (filename);
2177
2178 FOR_EACH_VEC_ELT (m_source_files, i, file)
2179 if (file->filename_as_tree () == ident_filename)
2180 return file;
2181
2182 /* Not found. */
2183 file = new source_file (ident_filename);
2184 m_source_files.safe_push (file);
2185 return file;
2186}
2187
2188/* Constructor for gcc::jit::playback::source_file. */
2189
2190playback::source_file::source_file (tree filename) :
2191 m_source_lines (),
2192 m_filename (filename)
2193{
2194}
2195
b957b2e0
DM
2196/* Don't leak vec's internal buffer (in non-GC heap) when we are
2197 GC-ed. */
2198
2199void
2200playback::source_file::finalizer ()
2201{
2202 m_source_lines.release ();
2203}
2204
35485da9
DM
2205/* Construct a playback::source_line for the given line
2206 within this source file, if one doesn't exist already. */
2207
2208playback::source_line *
2209playback::source_file::
2210get_source_line (int line_num)
2211{
2212 /* Locate the line.
2213 For simplicitly, this is currently a linear search.
2214 Replace with a hash if this shows up in the profile. */
2215 int i;
2216 source_line *line;
2217
2218 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2219 if (line->get_line_num () == line_num)
2220 return line;
2221
2222 /* Not found. */
2223 line = new source_line (this, line_num);
2224 m_source_lines.safe_push (line);
2225 return line;
2226}
2227
2228/* Constructor for gcc::jit::playback::source_line. */
2229
2230playback::source_line::source_line (source_file *file, int line_num) :
2231 m_locations (),
2232 m_source_file (file),
2233 m_line_num (line_num)
2234{
2235}
b957b2e0
DM
2236
2237/* Don't leak vec's internal buffer (in non-GC heap) when we are
2238 GC-ed. */
2239
2240void
2241playback::source_line::finalizer ()
2242{
2243 m_locations.release ();
2244}
35485da9
DM
2245
2246/* Construct a playback::location for the given column
2247 within this line of a specific source file, if one doesn't exist
2248 already. */
2249
2250playback::location *
2251playback::source_line::
2252get_location (recording::location *rloc, int column_num)
2253{
2254 int i;
2255 location *loc;
2256
2257 /* Another linear search that probably should be a hash table. */
2258 FOR_EACH_VEC_ELT (m_locations, i, loc)
2259 if (loc->get_column_num () == column_num)
2260 return loc;
2261
2262 /* Not found. */
2263 loc = new location (rloc, this, column_num);
2264 m_locations.safe_push (loc);
2265 return loc;
2266}
2267
2268/* Constructor for gcc::jit::playback::location. */
2269
2270playback::location::location (recording::location *loc,
2271 source_line *line,
2272 int column_num) :
2273 m_srcloc (UNKNOWN_LOCATION),
2274 m_recording_loc (loc),
2275 m_line (line),
2276 m_column_num(column_num)
2277{
2278}
2279
2280/* The active gcc::jit::playback::context instance. This is a singleton,
2281 guarded by jit_mutex. */
2282
2283playback::context *active_playback_ctxt;
2284
2285} // namespace gcc::jit
2286
2287} // namespace gcc