xref: /netbsd-src/external/gpl3/gcc/dist/gcc/jit/jit-playback.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11 
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20 
21 #include "config.h"
22 #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). */
66 extern tree convert (tree type, tree expr);
67 
68 tree
convert(tree dst_type,tree expr)69 convert (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 
92 namespace gcc {
93 namespace 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.  */
108 static tree
fold_const_var(tree node)109 fold_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 
139 static tree
build_string(const char * str)140 build_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 
context(recording::context * ctxt)150 playback::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 
~context()165 playback::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 
189 void
190 playback::context::
gt_ggc_mx()191 gt_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 
204 tree
205 playback::context::
get_tree_node_for_type(enum gcc_jit_types type_)206 get_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 
311 playback::type *
312 playback::context::
get_type(enum gcc_jit_types type_)313 get_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 
325 playback::type *
326 playback::context::
new_array_type(playback::location * loc,playback::type * element_type,int num_elements)327 new_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 
345 playback::field *
346 playback::context::
new_field(location * loc,type * type,const char * name)347 new_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 
366 playback::field *
367 playback::context::
new_bitfield(location * loc,type * type,int width,const char * name)368 new_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 
406 playback::compound_type *
407 playback::context::
new_compound_type(location * loc,const char * name,bool is_struct)408 new_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 
426 void
set_fields(const auto_vec<playback::field * > * fields)427 playback::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 
455 playback::type *
456 playback::context::
new_function_type(type * return_type,const auto_vec<type * > * param_types,int is_variadic)457 new_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 
486 playback::param *
487 playback::context::
new_param(location * loc,type * type,const char * name)488 new_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 
504 playback::function *
505 playback::context::
new_function(location * loc,enum gcc_jit_function_kind kind,type * return_type,const char * name,const auto_vec<param * > * params,int is_variadic,enum built_in_function builtin_id)506 new_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 
604 tree
605 playback::context::
global_new_decl(location * loc,enum gcc_jit_global_kind kind,type * type,const char * name,enum global_var_flags flags)606 global_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 
660 playback::lvalue *
661 playback::context::
global_finalize_lvalue(tree inner)662 global_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 
671 playback::lvalue *
672 playback::context::
new_global(location * loc,enum gcc_jit_global_kind kind,type * type,const char * name,enum global_var_flags flags)673 new_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 
685 void
686 playback::context::
global_set_init_rvalue(lvalue * variable,rvalue * init)687 global_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 
718 playback::rvalue *
719 playback::context::
new_ctor(location * loc,type * type,const auto_vec<field * > * fields,const auto_vec<rvalue * > * rvalues)720 new_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 
795 template<typename T>
796 static void
load_blob_in_ctor(vec<constructor_elt,va_gc> * & constructor_elements,size_t num_elem,const void * initializer)797 load_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 
816 playback::lvalue *
817 playback::context::
new_global_initialized(location * loc,enum gcc_jit_global_kind kind,type * type,size_t element_size,size_t initializer_num_elem,const void * initializer,const char * name,enum global_var_flags flags)818 new_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 
873 namespace playback
874 {
875 
876 /* Specialization of making an rvalue from a const, for host <int>.  */
877 
878 template <>
879 rvalue *
880 context::
new_rvalue_from_const(type * type,int value)881 new_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 
902 template <>
903 rvalue *
904 context::
new_rvalue_from_const(type * type,long value)905 new_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 
926 template <>
927 rvalue *
928 context::
new_rvalue_from_const(type * type,double value)929 new_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 
957 template <>
958 rvalue *
959 context::
new_rvalue_from_const(type * type,void * value)960 new_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 
977 playback::rvalue *
978 playback::context::
new_string_literal(const char * value)979 new_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 
1001 playback::rvalue *
new_rvalue_from_vector(location *,type * type,const auto_vec<rvalue * > & elements)1002 playback::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 
1016 tree
1017 playback::context::
as_truth_value(tree expr,location * loc)1018 as_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 
1040 void
add_top_level_asm(const char * asm_stmts)1041 playback::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 
1050 playback::rvalue *
1051 playback::context::
new_unary_op(location * loc,enum gcc_jit_unary_op op,type * result_type,rvalue * a)1052 new_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 
1110 playback::rvalue *
1111 playback::context::
new_binary_op(location * loc,enum gcc_jit_binary_op op,type * result_type,rvalue * a,rvalue * b)1112 new_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 
1211 playback::rvalue *
1212 playback::context::
new_comparison(location * loc,enum gcc_jit_comparison op,rvalue * a,rvalue * b)1213 new_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 
1270 playback::rvalue *
1271 playback::context::
build_call(location * loc,tree fn_ptr,const auto_vec<rvalue * > * args,bool require_tail_call)1272 build_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 
1311 playback::rvalue *
1312 playback::context::
new_call(location * loc,function * func,const auto_vec<rvalue * > * args,bool require_tail_call)1313 new_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 
1334 playback::rvalue *
1335 playback::context::
new_call_through_ptr(location * loc,rvalue * fn_ptr,const auto_vec<rvalue * > * args,bool require_tail_call)1336 new_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 
1349 tree
build_cast(playback::location * loc,playback::rvalue * expr,playback::type * type_)1350 playback::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 
1411 playback::rvalue *
1412 playback::context::
new_cast(playback::location * loc,playback::rvalue * expr,playback::type * type_)1413 new_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 
1427 playback::rvalue *
1428 playback::context::
new_bitcast(location * loc,rvalue * expr,type * type_)1429 new_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 
1457 playback::lvalue *
1458 playback::context::
new_array_access(location * loc,rvalue * ptr,rvalue * index)1459 new_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 
1514 tree
1515 playback::context::
new_field_access(location * loc,tree datum,field * field)1516 new_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 
1539 tree
1540 playback::context::
new_dereference(tree ptr,location * loc)1541 new_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 
1556 playback::type *
1557 playback::type::
get_aligned(size_t alignment_in_bytes) const1558 get_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 
1571 playback::type *
1572 playback::type::
get_vector(size_t num_units) const1573 get_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 
1582 playback::lvalue *
1583 playback::lvalue::
access_field(location * loc,field * field)1584 access_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 
1597 playback::rvalue *
1598 playback::rvalue::
access_field(location * loc,field * field)1599 access_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 
1612 playback::lvalue *
1613 playback::rvalue::
dereference_field(location * loc,field * field)1614 dereference_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 
1630 playback::lvalue *
1631 playback::rvalue::
dereference(location * loc)1632 dereference (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 
1645 bool
1646 playback::lvalue::
mark_addressable(location * loc)1647 mark_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 
1694 playback::rvalue *
1695 playback::lvalue::
get_address(location * loc)1696 get_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 
1715 static void
wrapper_finalizer(void * ptr)1716 wrapper_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 
1725 void *
1726 playback::wrapper::
operator new(size_t sz)1727 operator 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 
1735 playback::function::
function(context * ctxt,tree fndecl,enum gcc_jit_function_kind kind)1736 function (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 
1763 void
1764 playback::function::
gt_ggc_mx()1765 gt_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 
1776 void
finalizer()1777 playback::function::finalizer ()
1778 {
1779   m_blocks.release ();
1780 }
1781 
1782 /* Get the return type of a playback function, in tree form.  */
1783 
1784 tree
1785 playback::function::
get_return_type_as_tree() const1786 get_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 
1793 playback::lvalue *
1794 playback::function::
new_local(location * loc,type * type,const char * name)1795 new_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 
1817 playback::block *
1818 playback::function::
new_block(const char * name)1819 new_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 
1831 playback::rvalue *
get_address(location * loc)1832 playback::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 
1846 void
1847 playback::function::
build_stmt_list()1848 build_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 
1876 void
1877 playback::function::
postprocess()1878 postprocess ()
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 
1937 void
finalizer()1938 playback::block::finalizer ()
1939 {
1940   m_stmts.release ();
1941 }
1942 
1943 /* Add an eval of the rvalue to the function's statement list.  */
1944 
1945 void
1946 playback::block::
add_eval(location * loc,rvalue * rvalue)1947 add_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 
1960 void
1961 playback::block::
add_assignment(location * loc,lvalue * lvalue,rvalue * rvalue)1962 add_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 
1991 void
1992 playback::block::
add_comment(location * loc,const char * text)1993 add_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 
2020 void
2021 playback::block::
add_conditional(location * loc,rvalue * boolval,block * on_true,block * on_false)2022 add_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 
2054 void
2055 playback::block::
add_jump(location * loc,block * target)2056 add_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:
2074 tree
2075 c_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 
2093 void
2094 playback::block::
add_return(location * loc,rvalue * rvalue)2095 add_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 
2125 static void
add_case(tree * ptr_t_switch_body,tree t_low_value,tree t_high_value,playback::block * dest_block)2126 add_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 
2148 void
2149 playback::block::
add_switch(location * loc,rvalue * expr,block * default_block,const auto_vec<case_> * cases)2150 add_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 
2188 static tree
build_operand_chain(const auto_vec<playback::asm_operand> * operands)2189 build_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 
2210 static tree
build_clobbers(const auto_vec<const char * > * clobbers)2211 build_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 
2228 static tree
build_goto_operands(const auto_vec<playback::block * > * blocks)2229 build_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 
2249 void
add_extended_asm(location * loc,const char * asm_template,bool is_volatile,bool is_inline,const auto_vec<asm_operand> * outputs,const auto_vec<asm_operand> * inputs,const auto_vec<const char * > * clobbers,const auto_vec<block * > * goto_blocks)2250 playback::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 
2284 playback::block::
block(function * func,const char * name)2285 block (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 
2325 void
2326 playback::context::
compile()2327 compile ()
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 
compile_to_memory(recording::context * ctxt)2414 playback::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 
2427 void
postprocess(const char * ctxt_progname)2428 playback::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 
compile_to_file(recording::context * ctxt,enum gcc_jit_output_kind output_kind,const char * output_path)2442 playback::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 
2459 void
postprocess(const char * ctxt_progname)2460 playback::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 
2551 void
copy_file(const char * src_path,const char * dst_path)2552 playback::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 
2664 static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2665 
2666 /* Acquire jit_mutex and set "this" as the active playback ctxt.  */
2667 
2668 void
acquire_mutex()2669 playback::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 
2682 void
release_mutex()2683 playback::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 
2696 static void
append_arg_from_driver(const char * option,void * user_data)2697 append_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 
2708 void
2709 playback::context::
make_fake_args(vec<char * > * argvec,const char * ctxt_progname,vec<recording::requested_dump> * requested_dumps)2710 make_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 
2855 void
2856 playback::context::
extract_any_requested_dumps(vec<recording::requested_dump> * requested_dumps)2857 extract_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 
2892 char *
read_dump_file(const char * path)2893 playback::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 
2943 void
2944 playback::context::
convert_to_dso(const char * ctxt_progname)2945 convert_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 
2957 static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2958 
2959 void
2960 playback::context::
invoke_driver(const char * ctxt_progname,const char * input_file,const char * output_file,timevar_id_t tv_id,bool shared,bool run_linker)2961 invoke_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 
3033 void
3034 playback::context::
invoke_embedded_driver(const vec<char * > * argvec)3035 invoke_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 
3047 void
3048 playback::context::
invoke_external_driver(const char * ctxt_progname,vec<char * > * argvec)3049 invoke_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 
3099 static 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 
3108 void
3109 playback::context::
add_multilib_driver_arguments(vec<char * > * argvec)3110 add_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 
3125 result *
3126 playback::context::
dlopen_built_dso()3127 dlopen_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 
3198 void
3199 playback::context::
replay()3200 replay ()
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 
3264 void
3265 playback::context::
dump_generated_code()3266 dump_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 
3285 const char *
3286 playback::context::
get_path_c_file() const3287 get_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 
3295 const char *
3296 playback::context::
get_path_s_file() const3297 get_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 
3305 const char *
3306 playback::context::
get_path_so_file() const3307 get_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 
3315 static int
line_comparator(const void * lhs,const void * rhs)3316 line_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 
3328 static int
location_comparator(const void * lhs,const void * rhs)3329 location_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. */
3340 void
3341 playback::context::
init_types()3342 init_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) \
3347 if (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 
3390 void
3391 playback::context::
handle_locations()3392 handle_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 
3462 void
3463 playback::context::
add_error(location * loc,const char * fmt,...)3464 add_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 
3476 void
3477 playback::context::
add_error_va(location * loc,const char * fmt,va_list ap)3478 add_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 
3489 void
3490 playback::context::
add_diagnostic(struct diagnostic_context * diag_context,struct diagnostic_info * diagnostic)3491 add_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 
3526 playback::location *
3527 playback::context::
new_location(recording::location * rloc,const char * filename,int line,int column)3528 new_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 
3547 void
3548 playback::context::
set_tree_location(tree t,location * loc)3549 set_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 
3559 playback::source_file *
3560 playback::context::
get_source_file(const char * filename)3561 get_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 
source_file(tree filename)3582 playback::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 
3591 void
finalizer()3592 playback::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 
3600 playback::source_line *
3601 playback::source_file::
get_source_line(int line_num)3602 get_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 
source_line(source_file * file,int line_num)3622 playback::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 
3632 void
finalizer()3633 playback::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 
3642 playback::location *
3643 playback::source_line::
get_location(recording::location * rloc,int column_num)3644 get_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 
location(recording::location * loc,source_line * line,int column_num)3662 playback::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 
3675 playback::context *active_playback_ctxt;
3676 
3677 } // namespace gcc::jit
3678 
3679 } // namespace gcc
3680