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