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