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