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