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