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