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