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
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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.  */
82extern tree convert (tree type, tree expr);
83
84tree
85convert (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
96namespace gcc {
97namespace jit {
98
99/**********************************************************************
100 Playback.
101 **********************************************************************/
102
103/* The constructor for gcc::jit::playback::context.  */
104
105playback::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
121playback::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
145void
146playback::context::
147gt_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
160static tree
161get_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
235playback::type *
236playback::context::
237get_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
253playback::type *
254playback::context::
255new_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
273playback::field *
274playback::context::
275new_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
294playback::compound_type *
295playback::context::
296new_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
314void
315playback::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
336playback::type *
337playback::context::
338new_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
367playback::param *
368playback::context::
369new_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
385playback::function *
386playback::context::
387new_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
485playback::lvalue *
486playback::context::
487new_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
536namespace playback
537{
538
539/* Specialization of making an rvalue from a const, for host <int>.  */
540
541template <>
542rvalue *
543context::
544new_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
565template <>
566rvalue *
567context::
568new_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
589template <>
590rvalue *
591context::
592new_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
620template <>
621rvalue *
622context::
623new_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
640playback::rvalue *
641playback::context::
642new_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
658tree
659playback::context::
660as_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
679void
680playback::context::
681write_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
698void
699playback::context::
700write_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
718playback::rvalue *
719playback::context::
720new_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
772playback::rvalue *
773playback::context::
774new_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
866playback::rvalue *
867playback::context::
868new_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
916playback::rvalue *
917playback::context::
918build_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
952playback::rvalue *
953playback::context::
954new_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
974playback::rvalue *
975playback::context::
976new_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
988tree
989playback::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
1048playback::rvalue *
1049playback::context::
1050new_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
1064playback::lvalue *
1065playback::context::
1066new_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
1115tree
1116playback::context::
1117new_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
1140tree
1141playback::context::
1142new_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
1157playback::lvalue *
1158playback::lvalue::
1159access_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
1172playback::rvalue *
1173playback::rvalue::
1174access_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
1187playback::lvalue *
1188playback::rvalue::
1189dereference_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
1205playback::lvalue *
1206playback::rvalue::
1207dereference (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
1218static void
1219jit_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
1258playback::rvalue *
1259playback::lvalue::
1260get_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
1277static void
1278wrapper_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
1287void *
1288playback::wrapper::
1289operator 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
1297playback::function::
1298function (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
1324void
1325playback::function::
1326gt_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
1337void
1338playback::function::finalizer ()
1339{
1340  m_blocks.release ();
1341}
1342
1343/* Get the return type of a playback function, in tree form.  */
1344
1345tree
1346playback::function::
1347get_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
1354playback::lvalue *
1355playback::function::
1356new_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
1378playback::block *
1379playback::function::
1380new_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
1393void
1394playback::function::
1395build_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
1423void
1424playback::function::
1425postprocess ()
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
1484void
1485playback::block::finalizer ()
1486{
1487  m_stmts.release ();
1488}
1489
1490/* Add an eval of the rvalue to the function's statement list.  */
1491
1492void
1493playback::block::
1494add_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
1507void
1508playback::block::
1509add_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
1538void
1539playback::block::
1540add_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
1567void
1568playback::block::
1569add_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
1601void
1602playback::block::
1603add_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:
1621tree
1622c_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
1640void
1641playback::block::
1642add_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
1672static void
1673add_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
1700void
1701playback::block::
1702add_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
1744playback::block::
1745block (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
1767class 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
1776auto_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
1805void
1806playback::context::
1807compile ()
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
1894playback::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
1907void
1908playback::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
1922playback::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
1939void
1940playback::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
2021void
2022playback::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
2131static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2132
2133/* Acquire jit_mutex and set "this" as the active playback ctxt.  */
2134
2135void
2136playback::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
2147void
2148playback::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
2161static void
2162append_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
2173void
2174playback::context::
2175make_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
2319void
2320playback::context::
2321extract_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
2356char *
2357playback::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
2407void
2408playback::context::
2409convert_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
2421void
2422playback::context::
2423invoke_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
2523static 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
2532void
2533playback::context::
2534add_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
2549result *
2550playback::context::
2551dlopen_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
2611void
2612playback::context::
2613replay ()
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
2673void
2674playback::context::
2675dump_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
2694const char *
2695playback::context::
2696get_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
2704const char *
2705playback::context::
2706get_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
2714const char *
2715playback::context::
2716get_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
2724static int
2725line_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
2737static int
2738location_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
2755void
2756playback::context::
2757handle_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
2827void
2828playback::context::
2829add_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
2841void
2842playback::context::
2843add_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
2854playback::location *
2855playback::context::
2856new_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
2875void
2876playback::context::
2877set_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
2887playback::source_file *
2888playback::context::
2889get_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
2910playback::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
2919void
2920playback::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
2928playback::source_line *
2929playback::source_file::
2930get_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
2950playback::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
2960void
2961playback::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
2970playback::location *
2971playback::source_line::
2972get_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
2990playback::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
3003playback::context *active_playback_ctxt;
3004
3005} // namespace gcc::jit
3006
3007} // namespace gcc
3008