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 m_blocks ()
1362 {
1363 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1364 {
1365 /* Create a BIND_EXPR, and within it, a statement list. */
1366 m_stmt_list = alloc_stmt_list ();
1367 m_stmt_iter = tsi_start (m_stmt_list);
1368 m_inner_block = make_node (BLOCK);
1369 m_inner_bind_expr =
1370 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1371 }
1372 else
1373 {
1374 m_inner_block = NULL;
1375 m_stmt_list = NULL;
1376 }
1377 }
1378
1379 /* Hand-written GC-marking hook for playback functions. */
1380
1381 void
1382 playback::function::
gt_ggc_mx()1383 gt_ggc_mx ()
1384 {
1385 gt_ggc_m_9tree_node (m_inner_fndecl);
1386 gt_ggc_m_9tree_node (m_inner_bind_expr);
1387 gt_ggc_m_9tree_node (m_stmt_list);
1388 gt_ggc_m_9tree_node (m_inner_block);
1389 }
1390
1391 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1392 GC-ed. */
1393
1394 void
finalizer()1395 playback::function::finalizer ()
1396 {
1397 m_blocks.release ();
1398 }
1399
1400 /* Get the return type of a playback function, in tree form. */
1401
1402 tree
1403 playback::function::
get_return_type_as_tree()1404 get_return_type_as_tree () const
1405 {
1406 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1407 }
1408
1409 /* Construct a new local within this playback::function. */
1410
1411 playback::lvalue *
1412 playback::function::
new_local(location * loc,type * type,const char * name)1413 new_local (location *loc,
1414 type *type,
1415 const char *name)
1416 {
1417 gcc_assert (type);
1418 gcc_assert (name);
1419 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1420 get_identifier (name),
1421 type->as_tree ());
1422 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1423
1424 /* Prepend to BIND_EXPR_VARS: */
1425 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1426 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1427
1428 if (loc)
1429 set_tree_location (inner, loc);
1430 return new lvalue (m_ctxt, inner);
1431 }
1432
1433 /* Construct a new block within this playback::function. */
1434
1435 playback::block *
1436 playback::function::
new_block(const char * name)1437 new_block (const char *name)
1438 {
1439 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1440
1441 block *result = new playback::block (this, name);
1442 m_blocks.safe_push (result);
1443 return result;
1444 }
1445
1446 /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
1447 this playback::function. */
1448
1449 playback::rvalue *
get_address(location * loc)1450 playback::function::get_address (location *loc)
1451 {
1452 tree t_fndecl = as_fndecl ();
1453 tree t_fntype = TREE_TYPE (t_fndecl);
1454 tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
1455 if (loc)
1456 m_ctxt->set_tree_location (t_fnptr, loc);
1457 return new rvalue (m_ctxt, t_fnptr);
1458 }
1459
1460 /* Build a statement list for the function as a whole out of the
1461 lists of statements for the individual blocks, building labels
1462 for each block. */
1463
1464 void
1465 playback::function::
build_stmt_list()1466 build_stmt_list ()
1467 {
1468 int i;
1469 block *b;
1470
1471 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1472
1473 FOR_EACH_VEC_ELT (m_blocks, i, b)
1474 {
1475 int j;
1476 tree stmt;
1477
1478 b->m_label_expr = build1 (LABEL_EXPR,
1479 void_type_node,
1480 b->as_label_decl ());
1481 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1482
1483 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1484 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1485 }
1486 }
1487
1488 /* Finish compiling the given function, potentially running the
1489 garbage-collector.
1490 The function will have a statement list by now.
1491 Amongst other things, this gimplifies the statement list,
1492 and calls cgraph_node::finalize_function on the function. */
1493
1494 void
1495 playback::function::
postprocess()1496 postprocess ()
1497 {
1498 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1499
1500 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1501 debug_tree (m_stmt_list);
1502
1503 /* Do we need this to force cgraphunit.c to output the function? */
1504 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1505 {
1506 DECL_EXTERNAL (m_inner_fndecl) = 0;
1507 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1508 }
1509
1510 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1511 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1512 {
1513 DECL_EXTERNAL (m_inner_fndecl) = 0;
1514 TREE_PUBLIC (m_inner_fndecl) = 0;
1515 }
1516
1517 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1518 {
1519 /* Seem to need this in gimple-low.c: */
1520 gcc_assert (m_inner_block);
1521 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1522
1523 /* how to add to function? the following appears to be how to
1524 set the body of a m_inner_fndecl: */
1525 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1526
1527 /* Ensure that locals appear in the debuginfo. */
1528 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1529
1530 //debug_tree (m_inner_fndecl);
1531
1532 /* Convert to gimple: */
1533 //printf("about to gimplify_function_tree\n");
1534 gimplify_function_tree (m_inner_fndecl);
1535 //printf("finished gimplify_function_tree\n");
1536
1537 current_function_decl = m_inner_fndecl;
1538 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1539 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1540 //debug_tree (m_inner_fndecl);
1541
1542 //printf("about to add to cgraph\n");
1543 /* Add to cgraph: */
1544 cgraph_node::finalize_function (m_inner_fndecl, false);
1545 /* This can trigger a collection, so we need to have all of
1546 the funcs as roots. */
1547
1548 current_function_decl = NULL;
1549 }
1550 }
1551
1552 /* Don't leak vec's internal buffer (in non-GC heap) when we are
1553 GC-ed. */
1554
1555 void
finalizer()1556 playback::block::finalizer ()
1557 {
1558 m_stmts.release ();
1559 }
1560
1561 /* Add an eval of the rvalue to the function's statement list. */
1562
1563 void
1564 playback::block::
add_eval(location * loc,rvalue * rvalue)1565 add_eval (location *loc,
1566 rvalue *rvalue)
1567 {
1568 gcc_assert (rvalue);
1569
1570 if (loc)
1571 set_tree_location (rvalue->as_tree (), loc);
1572
1573 add_stmt (rvalue->as_tree ());
1574 }
1575
1576 /* Add an assignment to the function's statement list. */
1577
1578 void
1579 playback::block::
add_assignment(location * loc,lvalue * lvalue,rvalue * rvalue)1580 add_assignment (location *loc,
1581 lvalue *lvalue,
1582 rvalue *rvalue)
1583 {
1584 gcc_assert (lvalue);
1585 gcc_assert (rvalue);
1586
1587 tree t_lvalue = lvalue->as_tree ();
1588 tree t_rvalue = rvalue->as_tree ();
1589 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1590 {
1591 t_rvalue = build1 (CONVERT_EXPR,
1592 TREE_TYPE (t_lvalue),
1593 t_rvalue);
1594 if (loc)
1595 set_tree_location (t_rvalue, loc);
1596 }
1597
1598 tree stmt =
1599 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1600 t_lvalue, t_rvalue);
1601 if (loc)
1602 set_tree_location (stmt, loc);
1603 add_stmt (stmt);
1604 }
1605
1606 /* Add a comment to the function's statement list.
1607 For now this is done by adding a dummy label. */
1608
1609 void
1610 playback::block::
add_comment(location * loc,const char * text)1611 add_comment (location *loc,
1612 const char *text)
1613 {
1614 /* Wrap the text in C-style comment delimiters. */
1615 size_t sz =
1616 (3 /* opening delim */
1617 + strlen (text)
1618 + 3 /* closing delim */
1619 + 1 /* terminator */);
1620 char *wrapped = (char *)ggc_internal_alloc (sz);
1621 snprintf (wrapped, sz, "/* %s */", text);
1622
1623 /* For now we simply implement this by adding a dummy label with a name
1624 containing the given text. */
1625 tree identifier = get_identifier (wrapped);
1626 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1627 identifier, void_type_node);
1628 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1629
1630 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1631 if (loc)
1632 set_tree_location (label_expr, loc);
1633 add_stmt (label_expr);
1634 }
1635
1636 /* Add a conditional jump statement to the function's statement list. */
1637
1638 void
1639 playback::block::
add_conditional(location * loc,rvalue * boolval,block * on_true,block * on_false)1640 add_conditional (location *loc,
1641 rvalue *boolval,
1642 block *on_true,
1643 block *on_false)
1644 {
1645 gcc_assert (boolval);
1646 gcc_assert (on_true);
1647 gcc_assert (on_false);
1648
1649 /* COND_EXPR wants statement lists for the true/false operands, but we
1650 want labels.
1651 Shim it by creating jumps to the labels */
1652 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1653 on_true->as_label_decl ());
1654 if (loc)
1655 set_tree_location (true_jump, loc);
1656
1657 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1658 on_false->as_label_decl ());
1659 if (loc)
1660 set_tree_location (false_jump, loc);
1661
1662 tree stmt =
1663 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1664 true_jump, false_jump);
1665 if (loc)
1666 set_tree_location (stmt, loc);
1667 add_stmt (stmt);
1668 }
1669
1670 /* Add an unconditional jump statement to the function's statement list. */
1671
1672 void
1673 playback::block::
add_jump(location * loc,block * target)1674 add_jump (location *loc,
1675 block *target)
1676 {
1677 gcc_assert (target);
1678
1679 // see c_finish_loop
1680 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1681 //add_stmt (top);
1682
1683 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1684 TREE_USED (target->as_label_decl ()) = 1;
1685 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1686 if (loc)
1687 set_tree_location (stmt, loc);
1688 add_stmt (stmt);
1689
1690 /*
1691 from c-typeck.c:
1692 tree
1693 c_finish_goto_label (location_t loc, tree label)
1694 {
1695 tree decl = lookup_label_for_goto (loc, label);
1696 if (!decl)
1697 return NULL_TREE;
1698 TREE_USED (decl) = 1;
1699 {
1700 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1701 SET_EXPR_LOCATION (t, loc);
1702 return add_stmt (t);
1703 }
1704 }
1705 */
1706
1707 }
1708
1709 /* Add a return statement to the function's statement list. */
1710
1711 void
1712 playback::block::
add_return(location * loc,rvalue * rvalue)1713 add_return (location *loc,
1714 rvalue *rvalue)
1715 {
1716 tree modify_retval = NULL;
1717 tree return_type = m_func->get_return_type_as_tree ();
1718 if (rvalue)
1719 {
1720 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1721 tree t_rvalue = rvalue->as_tree ();
1722 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1723 t_rvalue = build1 (CONVERT_EXPR,
1724 TREE_TYPE (t_lvalue),
1725 t_rvalue);
1726 modify_retval = build2 (MODIFY_EXPR, return_type,
1727 t_lvalue, t_rvalue);
1728 if (loc)
1729 set_tree_location (modify_retval, loc);
1730 }
1731 tree return_stmt = build1 (RETURN_EXPR, return_type,
1732 modify_retval);
1733 if (loc)
1734 set_tree_location (return_stmt, loc);
1735
1736 add_stmt (return_stmt);
1737 }
1738
1739 /* Helper function for playback::block::add_switch.
1740 Construct a case label for the given range, followed by a goto stmt
1741 to the given block, appending them to stmt list *ptr_t_switch_body. */
1742
1743 static void
add_case(tree * ptr_t_switch_body,tree t_low_value,tree t_high_value,playback::block * dest_block)1744 add_case (tree *ptr_t_switch_body,
1745 tree t_low_value,
1746 tree t_high_value,
1747 playback::block *dest_block)
1748 {
1749 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
1750 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
1751
1752 tree t_case_label =
1753 build_case_label (t_low_value, t_high_value, t_label);
1754 append_to_statement_list (t_case_label, ptr_t_switch_body);
1755
1756 tree t_goto_stmt =
1757 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
1758 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
1759 }
1760
1761 /* Add a switch statement to the function's statement list.
1762
1763 We create a switch body, and populate it with case labels, each
1764 followed by a goto to the desired block. */
1765
1766 void
1767 playback::block::
add_switch(location * loc,rvalue * expr,block * default_block,const auto_vec<case_> * cases)1768 add_switch (location *loc,
1769 rvalue *expr,
1770 block *default_block,
1771 const auto_vec <case_> *cases)
1772 {
1773 /* Compare with:
1774 - c/c-typeck.c: c_start_case
1775 - c-family/c-common.c:c_add_case_label
1776 - java/expr.c:expand_java_switch and expand_java_add_case
1777 We've already rejected overlaps and duplicates in
1778 libgccjit.c:case_range_validator::validate. */
1779
1780 tree t_expr = expr->as_tree ();
1781 tree t_type = TREE_TYPE (t_expr);
1782
1783 tree t_switch_body = alloc_stmt_list ();
1784
1785 int i;
1786 case_ *c;
1787 FOR_EACH_VEC_ELT (*cases, i, c)
1788 {
1789 tree t_low_value = c->m_min_value->as_tree ();
1790 tree t_high_value = c->m_max_value->as_tree ();
1791 add_case (&t_switch_body, t_low_value, t_high_value, c->m_dest_block);
1792 }
1793 /* Default label. */
1794 add_case (&t_switch_body, NULL_TREE, NULL_TREE, default_block);
1795
1796 tree switch_stmt = build2 (SWITCH_EXPR, t_type, t_expr, t_switch_body);
1797 if (loc)
1798 set_tree_location (switch_stmt, loc);
1799 add_stmt (switch_stmt);
1800 }
1801
1802 /* Constructor for gcc::jit::playback::block. */
1803
1804 playback::block::
block(function * func,const char * name)1805 block (function *func,
1806 const char *name)
1807 : m_func (func),
1808 m_stmts ()
1809 {
1810 tree identifier;
1811
1812 gcc_assert (func);
1813 // name can be NULL
1814 if (name)
1815 identifier = get_identifier (name);
1816 else
1817 identifier = NULL;
1818 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1819 identifier, void_type_node);
1820 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1821 m_label_expr = NULL;
1822 }
1823
1824 /* Compile a playback::context:
1825
1826 - Use the context's options to cconstruct command-line options, and
1827 call into the rest of GCC (toplev::main).
1828 - Assuming it succeeds, we have a .s file.
1829 - We then run the "postprocess" vfunc:
1830
1831 (A) In-memory compile ("gcc_jit_context_compile")
1832
1833 For an in-memory compile we have the playback::compile_to_memory
1834 subclass; "postprocess" will convert the .s file to a .so DSO,
1835 and load it in memory (via dlopen), wrapping the result up as
1836 a jit::result and returning it.
1837
1838 (B) Compile to file ("gcc_jit_context_compile_to_file")
1839
1840 When compiling to a file, we have the playback::compile_to_file
1841 subclass; "postprocess" will either copy the .s file to the
1842 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1843 the driver to convert it as necessary, copying the result. */
1844
1845 void
1846 playback::context::
compile()1847 compile ()
1848 {
1849 JIT_LOG_SCOPE (get_logger ());
1850
1851 const char *ctxt_progname;
1852
1853 int keep_intermediates =
1854 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
1855
1856 m_tempdir = new tempdir (get_logger (), keep_intermediates);
1857 if (!m_tempdir->create ())
1858 return;
1859
1860 /* Call into the rest of gcc.
1861 For now, we have to assemble command-line options to pass into
1862 toplev::main, so that they can be parsed. */
1863
1864 /* Pass in user-provided program name as argv0, if any, so that it
1865 makes it into GCC's "progname" global, used in various diagnostics. */
1866 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1867
1868 if (!ctxt_progname)
1869 ctxt_progname = "libgccjit.so";
1870
1871 auto_vec <recording::requested_dump> requested_dumps;
1872 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1873
1874 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1875 acquire_mutex ();
1876
1877 auto_string_vec fake_args;
1878 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
1879 if (errors_occurred ())
1880 {
1881 release_mutex ();
1882 return;
1883 }
1884
1885 /* This runs the compiler. */
1886 toplev toplev (get_timer (), /* external_timer */
1887 false); /* init_signals */
1888 enter_scope ("toplev::main");
1889 if (get_logger ())
1890 for (unsigned i = 0; i < fake_args.length (); i++)
1891 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
1892 toplev.main (fake_args.length (),
1893 const_cast <char **> (fake_args.address ()));
1894 exit_scope ("toplev::main");
1895
1896 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1897 need to do it between toplev::main (which creates the dump manager)
1898 and toplev::finalize (which deletes it). */
1899 extract_any_requested_dumps (&requested_dumps);
1900
1901 /* Clean up the compiler. */
1902 enter_scope ("toplev::finalize");
1903 toplev.finalize ();
1904 exit_scope ("toplev::finalize");
1905
1906 /* Ideally we would release the jit mutex here, but we can't yet since
1907 followup activities use timevars, which are global state. */
1908
1909 if (errors_occurred ())
1910 {
1911 release_mutex ();
1912 return;
1913 }
1914
1915 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1916 dump_generated_code ();
1917
1918 /* We now have a .s file.
1919
1920 Run any postprocessing steps. This will either convert the .s file to
1921 a .so DSO, and load it in memory (playback::compile_to_memory), or
1922 convert the .s file to the requested output format, and copy it to a
1923 given file (playback::compile_to_file). */
1924 postprocess (ctxt_progname);
1925
1926 release_mutex ();
1927 }
1928
1929 /* Implementation of class gcc::jit::playback::compile_to_memory,
1930 a subclass of gcc::jit::playback::context. */
1931
1932 /* playback::compile_to_memory's trivial constructor. */
1933
compile_to_memory(recording::context * ctxt)1934 playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
1935 playback::context (ctxt),
1936 m_result (NULL)
1937 {
1938 JIT_LOG_SCOPE (get_logger ());
1939 }
1940
1941 /* Implementation of the playback::context::process vfunc for compiling
1942 to memory.
1943
1944 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1945 wrapping the result up as a jit::result and returning it. */
1946
1947 void
postprocess(const char * ctxt_progname)1948 playback::compile_to_memory::postprocess (const char *ctxt_progname)
1949 {
1950 JIT_LOG_SCOPE (get_logger ());
1951 convert_to_dso (ctxt_progname);
1952 if (errors_occurred ())
1953 return;
1954 m_result = dlopen_built_dso ();
1955 }
1956
1957 /* Implementation of class gcc::jit::playback::compile_to_file,
1958 a subclass of gcc::jit::playback::context. */
1959
1960 /* playback::compile_to_file's trivial constructor. */
1961
compile_to_file(recording::context * ctxt,enum gcc_jit_output_kind output_kind,const char * output_path)1962 playback::compile_to_file::compile_to_file (recording::context *ctxt,
1963 enum gcc_jit_output_kind output_kind,
1964 const char *output_path) :
1965 playback::context (ctxt),
1966 m_output_kind (output_kind),
1967 m_output_path (output_path)
1968 {
1969 JIT_LOG_SCOPE (get_logger ());
1970 }
1971
1972 /* Implementation of the playback::context::process vfunc for compiling
1973 to a file.
1974
1975 Either copy the .s file to the given destination (for
1976 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1977 as necessary, copying the result. */
1978
1979 void
postprocess(const char * ctxt_progname)1980 playback::compile_to_file::postprocess (const char *ctxt_progname)
1981 {
1982 JIT_LOG_SCOPE (get_logger ());
1983
1984 /* The driver takes different actions based on the filename, so
1985 we provide a filename with an appropriate suffix for the
1986 output kind, and then copy it up to the user-provided path,
1987 rather than directly compiling it to the requested output path. */
1988
1989 switch (m_output_kind)
1990 {
1991 default:
1992 gcc_unreachable ();
1993
1994 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
1995 copy_file (get_tempdir ()->get_path_s_file (),
1996 m_output_path);
1997 /* The .s file is automatically unlinked by tempdir::~tempdir. */
1998 break;
1999
2000 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
2001 {
2002 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
2003 "/fake.o",
2004 NULL);
2005 invoke_driver (ctxt_progname,
2006 get_tempdir ()->get_path_s_file (),
2007 tmp_o_path,
2008 TV_ASSEMBLE,
2009 false, /* bool shared, */
2010 false);/* bool run_linker */
2011 if (!errors_occurred ())
2012 {
2013 copy_file (tmp_o_path,
2014 m_output_path);
2015 get_tempdir ()->add_temp_file (tmp_o_path);
2016 }
2017 else
2018 free (tmp_o_path);
2019 }
2020 break;
2021
2022 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
2023 invoke_driver (ctxt_progname,
2024 get_tempdir ()->get_path_s_file (),
2025 get_tempdir ()->get_path_so_file (),
2026 TV_ASSEMBLE,
2027 true, /* bool shared, */
2028 true);/* bool run_linker */
2029 if (!errors_occurred ())
2030 copy_file (get_tempdir ()->get_path_so_file (),
2031 m_output_path);
2032 /* The .so file is automatically unlinked by tempdir::~tempdir. */
2033 break;
2034
2035 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
2036 {
2037 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
2038 "/fake.exe",
2039 NULL);
2040 invoke_driver (ctxt_progname,
2041 get_tempdir ()->get_path_s_file (),
2042 tmp_exe_path,
2043 TV_ASSEMBLE,
2044 false, /* bool shared, */
2045 true);/* bool run_linker */
2046 if (!errors_occurred ())
2047 {
2048 copy_file (tmp_exe_path,
2049 m_output_path);
2050 get_tempdir ()->add_temp_file (tmp_exe_path);
2051 }
2052 else
2053 free (tmp_exe_path);
2054 }
2055 break;
2056
2057 }
2058
2059 }
2060
2061 /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
2062 the "executable" bits).
2063
2064 Any errors that occur are reported on the context and hence count as
2065 a failure of the compile.
2066
2067 We can't in general hardlink or use "rename" from the tempdir since
2068 it might be on a different filesystem to the destination. For example,
2069 I get EXDEV: "Invalid cross-device link". */
2070
2071 void
copy_file(const char * src_path,const char * dst_path)2072 playback::compile_to_file::copy_file (const char *src_path,
2073 const char *dst_path)
2074 {
2075 JIT_LOG_SCOPE (get_logger ());
2076 if (get_logger ())
2077 {
2078 get_logger ()->log ("src_path: %s", src_path);
2079 get_logger ()->log ("dst_path: %s", dst_path);
2080 }
2081
2082 FILE *f_in = NULL;
2083 FILE *f_out = NULL;
2084 size_t total_sz_in = 0;
2085 size_t total_sz_out = 0;
2086 char buf[4096];
2087 size_t sz_in;
2088 struct stat stat_buf;
2089
2090 f_in = fopen (src_path, "rb");
2091 if (!f_in)
2092 {
2093 add_error (NULL,
2094 "unable to open %s for reading: %s",
2095 src_path,
2096 xstrerror (errno));
2097 return;
2098 }
2099
2100 /* Use stat on the filedescriptor to get the mode,
2101 so that we can copy it over (in particular, the
2102 "executable" bits). */
2103 if (fstat (fileno (f_in), &stat_buf) == -1)
2104 {
2105 add_error (NULL,
2106 "unable to fstat %s: %s",
2107 src_path,
2108 xstrerror (errno));
2109 fclose (f_in);
2110 return;
2111 }
2112
2113 f_out = fopen (dst_path, "wb");
2114 if (!f_out)
2115 {
2116 add_error (NULL,
2117 "unable to open %s for writing: %s",
2118 dst_path,
2119 xstrerror (errno));
2120 fclose (f_in);
2121 return;
2122 }
2123
2124 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2125 {
2126 total_sz_in += sz_in;
2127 size_t sz_out_remaining = sz_in;
2128 size_t sz_out_so_far = 0;
2129 while (sz_out_remaining)
2130 {
2131 size_t sz_out = fwrite (buf + sz_out_so_far,
2132 1,
2133 sz_out_remaining,
2134 f_out);
2135 gcc_assert (sz_out <= sz_out_remaining);
2136 if (!sz_out)
2137 {
2138 add_error (NULL,
2139 "error writing to %s: %s",
2140 dst_path,
2141 xstrerror (errno));
2142 fclose (f_in);
2143 fclose (f_out);
2144 return;
2145 }
2146 total_sz_out += sz_out;
2147 sz_out_so_far += sz_out;
2148 sz_out_remaining -= sz_out;
2149 }
2150 gcc_assert (sz_out_so_far == sz_in);
2151 }
2152
2153 if (!feof (f_in))
2154 add_error (NULL,
2155 "error reading from %s: %s",
2156 src_path,
2157 xstrerror (errno));
2158
2159 fclose (f_in);
2160
2161 gcc_assert (total_sz_in == total_sz_out);
2162 if (get_logger ())
2163 get_logger ()->log ("total bytes copied: %ld", total_sz_out);
2164
2165 /* Set the permissions of the copy to those of the original file,
2166 in particular the "executable" bits. */
2167 if (fchmod (fileno (f_out), stat_buf.st_mode) == -1)
2168 add_error (NULL,
2169 "error setting mode of %s: %s",
2170 dst_path,
2171 xstrerror (errno));
2172
2173 fclose (f_out);
2174 }
2175
2176 /* Helper functions for gcc::jit::playback::context::compile. */
2177
2178 /* This mutex guards gcc::jit::recording::context::compile, so that only
2179 one thread can be accessing the bulk of GCC's state at once. */
2180
2181 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2182
2183 /* Acquire jit_mutex and set "this" as the active playback ctxt. */
2184
2185 void
acquire_mutex()2186 playback::context::acquire_mutex ()
2187 {
2188 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2189
2190 /* Acquire the big GCC mutex. */
2191 JIT_LOG_SCOPE (get_logger ());
2192 pthread_mutex_lock (&jit_mutex);
2193 gcc_assert (active_playback_ctxt == NULL);
2194 active_playback_ctxt = this;
2195 }
2196
2197 /* Release jit_mutex and clear the active playback ctxt. */
2198
2199 void
release_mutex()2200 playback::context::release_mutex ()
2201 {
2202 /* Release the big GCC mutex. */
2203 JIT_LOG_SCOPE (get_logger ());
2204 gcc_assert (active_playback_ctxt == this);
2205 active_playback_ctxt = NULL;
2206 pthread_mutex_unlock (&jit_mutex);
2207 }
2208
2209 /* Callback used by gcc::jit::playback::context::make_fake_args when
2210 invoking driver_get_configure_time_options.
2211 Populate a vec <char * > with the configure-time options. */
2212
2213 static void
append_arg_from_driver(const char * option,void * user_data)2214 append_arg_from_driver (const char *option, void *user_data)
2215 {
2216 gcc_assert (option);
2217 gcc_assert (user_data);
2218 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2219 argvec->safe_push (concat ("-", option, NULL));
2220 }
2221
2222 /* Build a fake argv for toplev::main from the options set
2223 by the user on the context . */
2224
2225 void
2226 playback::context::
make_fake_args(vec<char * > * argvec,const char * ctxt_progname,vec<recording::requested_dump> * requested_dumps)2227 make_fake_args (vec <char *> *argvec,
2228 const char *ctxt_progname,
2229 vec <recording::requested_dump> *requested_dumps)
2230 {
2231 JIT_LOG_SCOPE (get_logger ());
2232
2233 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2234 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
2235
2236 ADD_ARG (ctxt_progname);
2237 ADD_ARG (get_path_c_file ());
2238 ADD_ARG ("-fPIC");
2239
2240 /* Handle int options: */
2241 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2242 {
2243 default:
2244 add_error (NULL,
2245 "unrecognized optimization level: %i",
2246 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2247 return;
2248
2249 case 0:
2250 ADD_ARG ("-O0");
2251 break;
2252
2253 case 1:
2254 ADD_ARG ("-O1");
2255 break;
2256
2257 case 2:
2258 ADD_ARG ("-O2");
2259 break;
2260
2261 case 3:
2262 ADD_ARG ("-O3");
2263 break;
2264 }
2265 /* What about -Os? */
2266
2267 /* Handle bool options: */
2268 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2269 ADD_ARG ("-g");
2270
2271 /* Suppress timing (and other) info. */
2272 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2273 {
2274 ADD_ARG ("-quiet");
2275 quiet_flag = 1;
2276 }
2277
2278 /* Aggressively garbage-collect, to shake out bugs: */
2279 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2280 {
2281 ADD_ARG ("--param=ggc-min-expand=0");
2282 ADD_ARG ("--param=ggc-min-heapsize=0");
2283 }
2284
2285 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2286 {
2287 ADD_ARG ("-fdump-tree-all");
2288 ADD_ARG ("-fdump-rtl-all");
2289 ADD_ARG ("-fdump-ipa-all");
2290 }
2291
2292 /* Add "-fdump-" options for any calls to
2293 gcc_jit_context_enable_dump. */
2294 {
2295 int i;
2296 recording::requested_dump *d;
2297 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2298 {
2299 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2300 ADD_ARG_TAKE_OWNERSHIP (arg);
2301 }
2302 }
2303
2304 /* PR jit/64810: Add any target-specific default options
2305 from OPTION_DEFAULT_SPECS, normally provided by the driver
2306 in the non-jit case.
2307
2308 The target-specific code can define OPTION_DEFAULT_SPECS:
2309 default command options in the form of spec macros for the
2310 driver to expand ().
2311
2312 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2313 if not overriden, injects the defaults as extra arguments to
2314 cc1 etc.
2315 For the jit case, we need to add these arguments here. The
2316 input format (using the specs language) means that we have to run
2317 part of the driver code here (driver_get_configure_time_options).
2318
2319 To avoid running the spec-expansion code every time, we just do
2320 it the first time (via a function-static flag), saving the result
2321 into a function-static vec.
2322 This flag and vec are global state (i.e. per-process).
2323 They are guarded by the jit mutex. */
2324 {
2325 static bool have_configure_time_options = false;
2326 static vec <char *> configure_time_options;
2327
2328 if (have_configure_time_options)
2329 log ("reusing cached configure-time options");
2330 else
2331 {
2332 have_configure_time_options = true;
2333 log ("getting configure-time options from driver");
2334 driver_get_configure_time_options (append_arg_from_driver,
2335 &configure_time_options);
2336 }
2337
2338 int i;
2339 char *opt;
2340
2341 if (get_logger ())
2342 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2343 log ("configure_time_options[%i]: %s", i, opt);
2344
2345 /* configure_time_options should now contain the expanded options
2346 from OPTION_DEFAULT_SPECS (if any). */
2347 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2348 {
2349 gcc_assert (opt);
2350 gcc_assert (opt[0] == '-');
2351 ADD_ARG (opt);
2352 }
2353 }
2354
2355 if (get_timer ())
2356 ADD_ARG ("-ftime-report");
2357
2358 /* Add any user-provided extra options, starting with any from
2359 parent contexts. */
2360 m_recording_ctxt->append_command_line_options (argvec);
2361
2362 #undef ADD_ARG
2363 #undef ADD_ARG_TAKE_OWNERSHIP
2364 }
2365
2366 /* The second half of the implementation of gcc_jit_context_enable_dump.
2367 Iterate through the requested dumps, reading the underlying files
2368 into heap-allocated buffers, writing pointers to the buffers into
2369 the char ** pointers provided by client code.
2370 Client code is responsible for calling free on the results. */
2371
2372 void
2373 playback::context::
extract_any_requested_dumps(vec<recording::requested_dump> * requested_dumps)2374 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2375 {
2376 JIT_LOG_SCOPE (get_logger ());
2377
2378 int i;
2379 recording::requested_dump *d;
2380 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2381 {
2382 dump_file_info *dfi;
2383 char *filename;
2384 char *content;
2385
2386 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2387 if (!dfi)
2388 {
2389 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2390 continue;
2391 }
2392
2393 filename = g->get_dumps ()->get_dump_file_name (dfi);
2394 content = read_dump_file (filename);
2395 *(d->m_out_ptr) = content;
2396 m_tempdir->add_temp_file (filename);
2397 }
2398 }
2399
2400 /* Helper function for playback::context::extract_any_requested_dumps
2401 (itself for use in implementation of gcc_jit_context_enable_dump).
2402
2403 Attempt to read the complete file at the given path, returning the
2404 bytes found there as a buffer.
2405 The caller is responsible for calling free on the result.
2406 Errors will be reported on the context, and lead to NULL being
2407 returned; an out-of-memory error will terminate the process. */
2408
2409 char *
read_dump_file(const char * path)2410 playback::context::read_dump_file (const char *path)
2411 {
2412 char *result = NULL;
2413 size_t total_sz = 0;
2414 char buf[4096];
2415 size_t sz;
2416 FILE *f_in;
2417
2418 f_in = fopen (path, "r");
2419 if (!f_in)
2420 {
2421 add_error (NULL, "unable to open %s for reading", path);
2422 return NULL;
2423 }
2424
2425 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2426 {
2427 size_t old_total_sz = total_sz;
2428 total_sz += sz;
2429 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2430 memcpy (result + old_total_sz, buf, sz);
2431 }
2432
2433 if (!feof (f_in))
2434 {
2435 add_error (NULL, "error reading from %s", path);
2436 free (result);
2437 fclose (f_in);
2438 return NULL;
2439 }
2440
2441 fclose (f_in);
2442
2443 if (result)
2444 {
2445 result[total_sz] = '\0';
2446 return result;
2447 }
2448 else
2449 return xstrdup ("");
2450 }
2451
2452 /* Part of playback::context::compile ().
2453
2454 We have a .s file; we want a .so file.
2455 We could reuse parts of gcc/gcc.c to do this.
2456 For now, just use the driver binary from the install, as
2457 named in gcc-driver-name.h
2458 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2459
2460 void
2461 playback::context::
convert_to_dso(const char * ctxt_progname)2462 convert_to_dso (const char *ctxt_progname)
2463 {
2464 JIT_LOG_SCOPE (get_logger ());
2465
2466 invoke_driver (ctxt_progname,
2467 m_tempdir->get_path_s_file (),
2468 m_tempdir->get_path_so_file (),
2469 TV_ASSEMBLE,
2470 true, /* bool shared, */
2471 true);/* bool run_linker */
2472 }
2473
2474 static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2475
2476 void
2477 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)2478 invoke_driver (const char *ctxt_progname,
2479 const char *input_file,
2480 const char *output_file,
2481 timevar_id_t tv_id,
2482 bool shared,
2483 bool run_linker)
2484 {
2485 JIT_LOG_SCOPE (get_logger ());
2486
2487 bool embedded_driver
2488 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
2489
2490 /* Currently this lumps together both assembling and linking into
2491 TV_ASSEMBLE. */
2492 auto_timevar assemble_timevar (get_timer (), tv_id);
2493 auto_string_vec argvec;
2494 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
2495
2496 ADD_ARG (gcc_driver_name);
2497
2498 add_multilib_driver_arguments (&argvec);
2499
2500 if (shared)
2501 ADD_ARG ("-shared");
2502
2503 if (!run_linker)
2504 ADD_ARG ("-c");
2505
2506 ADD_ARG (input_file);
2507 ADD_ARG ("-o");
2508 ADD_ARG (output_file);
2509
2510 /* Don't use the linker plugin.
2511 If running with just a "make" and not a "make install", then we'd
2512 run into
2513 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2514 libto_plugin is a .la at build time, with it becoming installed with
2515 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2516 time. */
2517 ADD_ARG ("-fno-use-linker-plugin");
2518
2519 #if defined (DARWIN_X86) || defined (DARWIN_PPC)
2520 /* OS X's linker defaults to treating undefined symbols as errors.
2521 If the context has any imported functions or globals they will be
2522 undefined until the .so is dynamically-linked into the process.
2523 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2524 linker. */
2525 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2526 #endif
2527
2528 if (0)
2529 ADD_ARG ("-v");
2530
2531 /* Add any user-provided driver extra options. */
2532
2533 m_recording_ctxt->append_driver_options (&argvec);
2534
2535 #undef ADD_ARG
2536
2537 /* pex_one's error-handling requires pname to be non-NULL. */
2538 gcc_assert (ctxt_progname);
2539
2540 if (get_logger ())
2541 for (unsigned i = 0; i < argvec.length (); i++)
2542 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2543
2544 if (embedded_driver)
2545 invoke_embedded_driver (&argvec);
2546 else
2547 invoke_external_driver (ctxt_progname, &argvec);
2548 }
2549
2550 void
2551 playback::context::
invoke_embedded_driver(const vec<char * > * argvec)2552 invoke_embedded_driver (const vec <char *> *argvec)
2553 {
2554 JIT_LOG_SCOPE (get_logger ());
2555 driver d (true, /* can_finalize */
2556 false); /* debug */
2557 int result = d.main (argvec->length (),
2558 const_cast <char **> (argvec->address ()));
2559 d.finalize ();
2560 if (result)
2561 add_error (NULL, "error invoking gcc driver");
2562 }
2563
2564 void
2565 playback::context::
invoke_external_driver(const char * ctxt_progname,vec<char * > * argvec)2566 invoke_external_driver (const char *ctxt_progname,
2567 vec <char *> *argvec)
2568 {
2569 JIT_LOG_SCOPE (get_logger ());
2570 const char *errmsg;
2571 int exit_status = 0;
2572 int err = 0;
2573
2574 /* pex argv arrays are NULL-terminated. */
2575 argvec->safe_push (NULL);
2576
2577 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2578 gcc_driver_name,
2579 const_cast <char *const *> (argvec->address ()),
2580 ctxt_progname, /* const char *pname */
2581 NULL, /* const char *outname */
2582 NULL, /* const char *errname */
2583 &exit_status, /* int *status */
2584 &err); /* int *err*/
2585 if (errmsg)
2586 {
2587 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2588 return;
2589 }
2590
2591 /* pex_one can return a NULL errmsg when the executable wasn't
2592 found (or doesn't exist), so trap these cases also. */
2593 if (exit_status || err)
2594 {
2595 add_error (NULL,
2596 "error invoking gcc driver: exit_status: %i err: %i",
2597 exit_status, err);
2598 add_error (NULL,
2599 "whilst attempting to run a driver named: %s",
2600 gcc_driver_name);
2601 add_error (NULL,
2602 "PATH was: %s",
2603 getenv ("PATH"));
2604 return;
2605 }
2606 }
2607
2608 /* Extract the target-specific MULTILIB_DEFAULTS to
2609 multilib_defaults_raw for use by
2610 playback::context::add_multilib_driver_arguments (). */
2611
2612 #ifndef MULTILIB_DEFAULTS
2613 #define MULTILIB_DEFAULTS { "" }
2614 #endif
2615
2616 static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
2617
2618 /* Helper function for playback::context::invoke_driver ().
2619
2620 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2621 a driver binary. We need to pass in options to the shared driver
2622 to get the appropriate assembler/linker options for this multilib
2623 peer. */
2624
2625 void
2626 playback::context::
add_multilib_driver_arguments(vec<char * > * argvec)2627 add_multilib_driver_arguments (vec <char *> *argvec)
2628 {
2629 JIT_LOG_SCOPE (get_logger ());
2630
2631 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2632 prepending each with a "-". */
2633 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
2634 if (multilib_defaults_raw[i][0])
2635 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
2636 }
2637
2638 /* Dynamically-link the built DSO file into this process, using dlopen.
2639 Wrap it up within a jit::result *, and return that.
2640 Return NULL if any errors occur, reporting them on this context. */
2641
2642 result *
2643 playback::context::
dlopen_built_dso()2644 dlopen_built_dso ()
2645 {
2646 JIT_LOG_SCOPE (get_logger ());
2647 auto_timevar load_timevar (get_timer (), TV_LOAD);
2648 void *handle = NULL;
2649 const char *error = NULL;
2650 result *result_obj = NULL;
2651
2652 /* Clear any existing error. */
2653 dlerror ();
2654
2655 handle = dlopen (m_tempdir->get_path_so_file (),
2656 RTLD_NOW | RTLD_LOCAL);
2657 if ((error = dlerror()) != NULL) {
2658 add_error (NULL, "%s", error);
2659 }
2660 if (handle)
2661 {
2662 /* We've successfully dlopened the result; create a
2663 jit::result object to wrap it.
2664
2665 We're done with the tempdir for now, but if the user
2666 has requested debugging, the user's debugger might not
2667 be capable of dealing with the .so file being unlinked
2668 immediately, so keep it around until after the result
2669 is released. We do this by handing over ownership of
2670 the jit::tempdir to the result. See PR jit/64206. */
2671 tempdir *handover_tempdir;
2672 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2673 {
2674 handover_tempdir = m_tempdir;
2675 m_tempdir = NULL;
2676 /* The tempdir will eventually be cleaned up in the
2677 jit::result's dtor. */
2678 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2679 " handing over tempdir to jit::result");
2680 }
2681 else
2682 {
2683 handover_tempdir = NULL;
2684 /* ... and retain ownership of m_tempdir so we clean it
2685 up it the playback::context's dtor. */
2686 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2687 " retaining ownership of tempdir");
2688 }
2689
2690 result_obj = new result (get_logger (), handle, handover_tempdir);
2691 }
2692 else
2693 result_obj = NULL;
2694
2695 return result_obj;
2696 }
2697
2698 /* Top-level hook for playing back a recording context.
2699
2700 This plays back m_recording_ctxt, and, if no errors
2701 occurred builds statement lists for and then postprocesses
2702 every function in the result. */
2703
2704 void
2705 playback::context::
replay()2706 replay ()
2707 {
2708 JIT_LOG_SCOPE (get_logger ());
2709
2710 m_const_char_ptr
2711 = build_pointer_type (build_qualified_type (char_type_node,
2712 TYPE_QUAL_CONST));
2713
2714 /* Replay the recorded events: */
2715 timevar_push (TV_JIT_REPLAY);
2716
2717 m_recording_ctxt->replay_into (this);
2718
2719 /* Clean away the temporary references from recording objects
2720 to playback objects. We have to do this now since the
2721 latter are GC-allocated, but the former don't mark these
2722 refs. Hence we must stop using them before the GC can run. */
2723 m_recording_ctxt->disassociate_from_playback ();
2724
2725 /* The builtins_manager, if any, is associated with the recording::context
2726 and might be reused for future compiles on other playback::contexts,
2727 but its m_attributes array is not GTY-labeled and hence will become
2728 nonsense if the GC runs. Purge this state. */
2729 builtins_manager *bm = get_builtins_manager ();
2730 if (bm)
2731 bm->finish_playback ();
2732
2733 timevar_pop (TV_JIT_REPLAY);
2734
2735 if (!errors_occurred ())
2736 {
2737 int i;
2738 function *func;
2739
2740 /* No GC can happen yet; process the cached source locations. */
2741 handle_locations ();
2742
2743 /* We've now created tree nodes for the stmts in the various blocks
2744 in each function, but we haven't built each function's single stmt
2745 list yet. Do so now. */
2746 FOR_EACH_VEC_ELT (m_functions, i, func)
2747 func->build_stmt_list ();
2748
2749 /* No GC can have happened yet. */
2750
2751 /* Postprocess the functions. This could trigger GC. */
2752 FOR_EACH_VEC_ELT (m_functions, i, func)
2753 {
2754 gcc_assert (func);
2755 func->postprocess ();
2756 }
2757 }
2758 }
2759
2760 /* Dump the generated .s file to stderr. */
2761
2762 void
2763 playback::context::
dump_generated_code()2764 dump_generated_code ()
2765 {
2766 JIT_LOG_SCOPE (get_logger ());
2767 char buf[4096];
2768 size_t sz;
2769 FILE *f_in = fopen (get_path_s_file (), "r");
2770 if (!f_in)
2771 return;
2772
2773 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2774 fwrite (buf, 1, sz, stderr);
2775
2776 fclose (f_in);
2777 }
2778
2779 /* Get the supposed path of the notional "fake.c" file within the
2780 tempdir. This file doesn't exist, but the rest of the compiler
2781 needs a name. */
2782
2783 const char *
2784 playback::context::
get_path_c_file()2785 get_path_c_file () const
2786 {
2787 return m_tempdir->get_path_c_file ();
2788 }
2789
2790 /* Get the path of the assembler output file "fake.s" file within the
2791 tempdir. */
2792
2793 const char *
2794 playback::context::
get_path_s_file()2795 get_path_s_file () const
2796 {
2797 return m_tempdir->get_path_s_file ();
2798 }
2799
2800 /* Get the path of the DSO object file "fake.so" file within the
2801 tempdir. */
2802
2803 const char *
2804 playback::context::
get_path_so_file()2805 get_path_so_file () const
2806 {
2807 return m_tempdir->get_path_so_file ();
2808 }
2809
2810 /* qsort comparator for comparing pairs of playback::source_line *,
2811 ordering them by line number. */
2812
2813 static int
line_comparator(const void * lhs,const void * rhs)2814 line_comparator (const void *lhs, const void *rhs)
2815 {
2816 const playback::source_line *line_lhs = \
2817 *static_cast<const playback::source_line * const*> (lhs);
2818 const playback::source_line *line_rhs = \
2819 *static_cast<const playback::source_line * const*> (rhs);
2820 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2821 }
2822
2823 /* qsort comparator for comparing pairs of playback::location *,
2824 ordering them by column number. */
2825
2826 static int
location_comparator(const void * lhs,const void * rhs)2827 location_comparator (const void *lhs, const void *rhs)
2828 {
2829 const playback::location *loc_lhs = \
2830 *static_cast<const playback::location * const *> (lhs);
2831 const playback::location *loc_rhs = \
2832 *static_cast<const playback::location * const *> (rhs);
2833 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2834 }
2835
2836 /* Our API allows locations to be created in arbitrary orders, but the
2837 linemap API requires locations to be created in ascending order
2838 as if we were tokenizing files.
2839
2840 This hook sorts all of the locations that have been created, and
2841 calls into the linemap API, creating linemap entries in sorted order
2842 for our locations. */
2843
2844 void
2845 playback::context::
handle_locations()2846 handle_locations ()
2847 {
2848 /* Create the source code locations, following the ordering rules
2849 imposed by the linemap API.
2850
2851 line_table is a global. */
2852 JIT_LOG_SCOPE (get_logger ());
2853 int i;
2854 source_file *file;
2855
2856 FOR_EACH_VEC_ELT (m_source_files, i, file)
2857 {
2858 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2859
2860 /* Sort lines by ascending line numbers. */
2861 file->m_source_lines.qsort (&line_comparator);
2862
2863 int j;
2864 source_line *line;
2865 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2866 {
2867 int k;
2868 location *loc;
2869
2870 /* Sort locations in line by ascending column numbers. */
2871 line->m_locations.qsort (&location_comparator);
2872
2873 /* Determine maximum column within this line. */
2874 gcc_assert (line->m_locations.length () > 0);
2875 location *final_column =
2876 line->m_locations[line->m_locations.length () - 1];
2877 int max_col = final_column->get_column_num ();
2878
2879 linemap_line_start (line_table, line->get_line_num (), max_col);
2880 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2881 {
2882 loc->m_srcloc = \
2883 linemap_position_for_column (line_table, loc->get_column_num ());
2884 }
2885 }
2886
2887 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2888 }
2889
2890 /* line_table should now be populated; every playback::location should
2891 now have an m_srcloc. */
2892
2893 /* Now assign them to tree nodes as appropriate. */
2894 std::pair<tree, location *> *cached_location;
2895
2896 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2897 {
2898 tree t = cached_location->first;
2899 location_t srcloc = cached_location->second->m_srcloc;
2900
2901 /* This covers expressions: */
2902 if (CAN_HAVE_LOCATION_P (t))
2903 SET_EXPR_LOCATION (t, srcloc);
2904 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2905 DECL_SOURCE_LOCATION (t) = srcloc;
2906 else
2907 {
2908 /* Don't know how to set location on this node. */
2909 }
2910 }
2911 }
2912
2913 /* We handle errors on a playback::context by adding them to the
2914 corresponding recording::context. */
2915
2916 void
2917 playback::context::
add_error(location * loc,const char * fmt,...)2918 add_error (location *loc, const char *fmt, ...)
2919 {
2920 va_list ap;
2921 va_start (ap, fmt);
2922 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2923 fmt, ap);
2924 va_end (ap);
2925 }
2926
2927 /* We handle errors on a playback::context by adding them to the
2928 corresponding recording::context. */
2929
2930 void
2931 playback::context::
add_error_va(location * loc,const char * fmt,va_list ap)2932 add_error_va (location *loc, const char *fmt, va_list ap)
2933 {
2934 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2935 fmt, ap);
2936 }
2937
2938 /* Report a diagnostic up to the jit context as an error,
2939 so that the compilation is treated as a failure.
2940 For now, any kind of diagnostic is treated as an error by the jit
2941 API. */
2942
2943 void
2944 playback::context::
add_diagnostic(struct diagnostic_context * diag_context,struct diagnostic_info * diagnostic)2945 add_diagnostic (struct diagnostic_context *diag_context,
2946 struct diagnostic_info *diagnostic)
2947 {
2948 /* At this point the text has been formatted into the pretty-printer's
2949 output buffer. */
2950 pretty_printer *pp = diag_context->printer;
2951 const char *text = pp_formatted_text (pp);
2952
2953 /* Get location information (if any) from the diagnostic.
2954 The recording::context::add_error[_va] methods require a
2955 recording::location. We can't lookup the playback::location
2956 from the file/line/column since any playback location instances
2957 may have been garbage-collected away by now, so instead we create
2958 another recording::location directly. */
2959 location_t gcc_loc = diagnostic_location (diagnostic);
2960 recording::location *rec_loc = NULL;
2961 if (gcc_loc)
2962 {
2963 expanded_location exploc = expand_location (gcc_loc);
2964 if (exploc.file)
2965 rec_loc = m_recording_ctxt->new_location (exploc.file,
2966 exploc.line,
2967 exploc.column,
2968 false);
2969 }
2970
2971 m_recording_ctxt->add_error (rec_loc, "%s", text);
2972 pp_clear_output_area (pp);
2973 }
2974
2975 /* Dealing with the linemap API. */
2976
2977 /* Construct a playback::location for a recording::location, if it
2978 doesn't exist already. */
2979
2980 playback::location *
2981 playback::context::
new_location(recording::location * rloc,const char * filename,int line,int column)2982 new_location (recording::location *rloc,
2983 const char *filename,
2984 int line,
2985 int column)
2986 {
2987 /* Get the source_file for filename, creating if necessary. */
2988 source_file *src_file = get_source_file (filename);
2989 /* Likewise for the line within the file. */
2990 source_line *src_line = src_file->get_source_line (line);
2991 /* Likewise for the column within the line. */
2992 location *loc = src_line->get_location (rloc, column);
2993 return loc;
2994 }
2995
2996 /* Deferred setting of the location for a given tree, by adding the
2997 (tree, playback::location) pair to a list of deferred associations.
2998 We will actually set the location on the tree later on once
2999 the location_t for the playback::location exists. */
3000
3001 void
3002 playback::context::
set_tree_location(tree t,location * loc)3003 set_tree_location (tree t, location *loc)
3004 {
3005 gcc_assert (loc);
3006 m_cached_locations.safe_push (std::make_pair (t, loc));
3007 }
3008
3009
3010 /* Construct a playback::source_file for the given source
3011 filename, if it doesn't exist already. */
3012
3013 playback::source_file *
3014 playback::context::
get_source_file(const char * filename)3015 get_source_file (const char *filename)
3016 {
3017 /* Locate the file.
3018 For simplicitly, this is currently a linear search.
3019 Replace with a hash if this shows up in the profile. */
3020 int i;
3021 source_file *file;
3022 tree ident_filename = get_identifier (filename);
3023
3024 FOR_EACH_VEC_ELT (m_source_files, i, file)
3025 if (file->filename_as_tree () == ident_filename)
3026 return file;
3027
3028 /* Not found. */
3029 file = new source_file (ident_filename);
3030 m_source_files.safe_push (file);
3031 return file;
3032 }
3033
3034 /* Constructor for gcc::jit::playback::source_file. */
3035
source_file(tree filename)3036 playback::source_file::source_file (tree filename) :
3037 m_source_lines (),
3038 m_filename (filename)
3039 {
3040 }
3041
3042 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3043 GC-ed. */
3044
3045 void
finalizer()3046 playback::source_file::finalizer ()
3047 {
3048 m_source_lines.release ();
3049 }
3050
3051 /* Construct a playback::source_line for the given line
3052 within this source file, if one doesn't exist already. */
3053
3054 playback::source_line *
3055 playback::source_file::
get_source_line(int line_num)3056 get_source_line (int line_num)
3057 {
3058 /* Locate the line.
3059 For simplicitly, this is currently a linear search.
3060 Replace with a hash if this shows up in the profile. */
3061 int i;
3062 source_line *line;
3063
3064 FOR_EACH_VEC_ELT (m_source_lines, i, line)
3065 if (line->get_line_num () == line_num)
3066 return line;
3067
3068 /* Not found. */
3069 line = new source_line (this, line_num);
3070 m_source_lines.safe_push (line);
3071 return line;
3072 }
3073
3074 /* Constructor for gcc::jit::playback::source_line. */
3075
source_line(source_file * file,int line_num)3076 playback::source_line::source_line (source_file *file, int line_num) :
3077 m_locations (),
3078 m_source_file (file),
3079 m_line_num (line_num)
3080 {
3081 }
3082
3083 /* Don't leak vec's internal buffer (in non-GC heap) when we are
3084 GC-ed. */
3085
3086 void
finalizer()3087 playback::source_line::finalizer ()
3088 {
3089 m_locations.release ();
3090 }
3091
3092 /* Construct a playback::location for the given column
3093 within this line of a specific source file, if one doesn't exist
3094 already. */
3095
3096 playback::location *
3097 playback::source_line::
get_location(recording::location * rloc,int column_num)3098 get_location (recording::location *rloc, int column_num)
3099 {
3100 int i;
3101 location *loc;
3102
3103 /* Another linear search that probably should be a hash table. */
3104 FOR_EACH_VEC_ELT (m_locations, i, loc)
3105 if (loc->get_column_num () == column_num)
3106 return loc;
3107
3108 /* Not found. */
3109 loc = new location (rloc, this, column_num);
3110 m_locations.safe_push (loc);
3111 return loc;
3112 }
3113
3114 /* Constructor for gcc::jit::playback::location. */
3115
location(recording::location * loc,source_line * line,int column_num)3116 playback::location::location (recording::location *loc,
3117 source_line *line,
3118 int column_num) :
3119 m_srcloc (UNKNOWN_LOCATION),
3120 m_recording_loc (loc),
3121 m_line (line),
3122 m_column_num(column_num)
3123 {
3124 }
3125
3126 /* The active gcc::jit::playback::context instance. This is a singleton,
3127 guarded by jit_mutex. */
3128
3129 playback::context *active_playback_ctxt;
3130
3131 } // namespace gcc::jit
3132
3133 } // namespace gcc
3134