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