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