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