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