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