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