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