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