]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/jit/jit-playback.c
decl.c (grokdeclarator): Use %qT instead of %<%T%> in
[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
1098/* Construct a playback::lvalue instance (wrapping a tree) for a
1099 field access. */
1100
1101playback::lvalue *
1102playback::lvalue::
1103access_field (location *loc,
1104 field *field)
1105{
1106 tree datum = as_tree ();
1107 tree ref = get_context ()->new_field_access (loc, datum, field);
1108 if (!ref)
1109 return NULL;
1110 return new lvalue (get_context (), ref);
1111}
1112
1113/* Construct a playback::rvalue instance (wrapping a tree) for a
1114 field access. */
1115
1116playback::rvalue *
1117playback::rvalue::
1118access_field (location *loc,
1119 field *field)
1120{
1121 tree datum = as_tree ();
1122 tree ref = get_context ()->new_field_access (loc, datum, field);
1123 if (!ref)
1124 return NULL;
1125 return new rvalue (get_context (), ref);
1126}
1127
1128/* Construct a playback::lvalue instance (wrapping a tree) for a
1129 dereferenced field access. */
1130
1131playback::lvalue *
1132playback::rvalue::
1133dereference_field (location *loc,
1134 field *field)
1135{
1136 tree ptr = as_tree ();
1137 tree datum = get_context ()->new_dereference (ptr, loc);
1138 if (!datum)
1139 return NULL;
1140 tree ref = get_context ()->new_field_access (loc, datum, field);
1141 if (!ref)
1142 return NULL;
1143 return new lvalue (get_context (), ref);
1144}
1145
1146/* Construct a playback::lvalue instance (wrapping a tree) for a
1147 dereference. */
1148
1149playback::lvalue *
1150playback::rvalue::
1151dereference (location *loc)
1152{
1153 tree ptr = as_tree ();
1154 tree datum = get_context ()->new_dereference (ptr, loc);
1155 return new lvalue (get_context (), datum);
1156}
1157
e09abfa4
DM
1158/* Mark EXP saying that we need to be able to take the
1159 address of it; it should not be allocated in a register.
1160 Compare with e.g. c/c-typeck.c: c_mark_addressable. */
1161
1162static void
1163jit_mark_addressable (tree exp)
1164{
1165 tree x = exp;
1166
1167 while (1)
1168 switch (TREE_CODE (x))
1169 {
1170 case COMPONENT_REF:
1171 /* (we don't yet support bitfields) */
1172 /* fallthrough */
1173 case ADDR_EXPR:
1174 case ARRAY_REF:
1175 case REALPART_EXPR:
1176 case IMAGPART_EXPR:
1177 x = TREE_OPERAND (x, 0);
1178 break;
1179
1180 case COMPOUND_LITERAL_EXPR:
1181 case CONSTRUCTOR:
1182 TREE_ADDRESSABLE (x) = 1;
1183 return;
1184
1185 case VAR_DECL:
1186 case CONST_DECL:
1187 case PARM_DECL:
1188 case RESULT_DECL:
1189 /* (we don't have a concept of a "register" declaration) */
1190 /* fallthrough */
1191 case FUNCTION_DECL:
1192 TREE_ADDRESSABLE (x) = 1;
1193 /* fallthrough */
1194 default:
1195 return;
1196 }
1197}
1198
35485da9
DM
1199/* Construct a playback::rvalue instance (wrapping a tree) for an
1200 address-lookup. */
1201
1202playback::rvalue *
1203playback::lvalue::
1204get_address (location *loc)
1205{
1206 tree t_lvalue = as_tree ();
1207 tree t_thistype = TREE_TYPE (t_lvalue);
1208 tree t_ptrtype = build_pointer_type (t_thistype);
1209 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1210 if (loc)
1211 get_context ()->set_tree_location (ptr, loc);
e09abfa4 1212 jit_mark_addressable (t_lvalue);
35485da9
DM
1213 return new rvalue (get_context (), ptr);
1214}
1215
b957b2e0
DM
1216/* The wrapper subclasses are GC-managed, but can own non-GC memory.
1217 Provide this finalization hook for calling then they are collected,
1218 which calls the finalizer vfunc. This allows them to call "release"
1219 on any vec<> within them. */
1220
1221static void
1222wrapper_finalizer (void *ptr)
1223{
1224 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1225 wrapper->finalizer ();
1226}
1227
35485da9
DM
1228/* gcc::jit::playback::wrapper subclasses are GC-managed:
1229 allocate them using ggc_internal_cleared_alloc. */
1230
1231void *
1232playback::wrapper::
1233operator new (size_t sz)
1234{
b957b2e0
DM
1235 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1236
35485da9
DM
1237}
1238
1239/* Constructor for gcc:jit::playback::function. */
1240
1241playback::function::
1242function (context *ctxt,
1243 tree fndecl,
1244 enum gcc_jit_function_kind kind)
1245: m_ctxt(ctxt),
1246 m_inner_fndecl (fndecl),
1247 m_inner_bind_expr (NULL),
1248 m_kind (kind)
1249{
1250 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1251 {
1252 /* Create a BIND_EXPR, and within it, a statement list. */
1253 m_stmt_list = alloc_stmt_list ();
1254 m_stmt_iter = tsi_start (m_stmt_list);
1255 m_inner_block = make_node (BLOCK);
1256 m_inner_bind_expr =
1257 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1258 }
1259 else
1260 {
1261 m_inner_block = NULL;
1262 m_stmt_list = NULL;
1263 }
1264}
1265
1266/* Hand-written GC-marking hook for playback functions. */
1267
1268void
1269playback::function::
1270gt_ggc_mx ()
1271{
1272 gt_ggc_m_9tree_node (m_inner_fndecl);
1273 gt_ggc_m_9tree_node (m_inner_bind_expr);
1274 gt_ggc_m_9tree_node (m_stmt_list);
1275 gt_ggc_m_9tree_node (m_inner_block);
1276}
1277
b957b2e0
DM
1278/* Don't leak vec's internal buffer (in non-GC heap) when we are
1279 GC-ed. */
1280
1281void
1282playback::function::finalizer ()
1283{
1284 m_blocks.release ();
1285}
1286
35485da9
DM
1287/* Get the return type of a playback function, in tree form. */
1288
1289tree
1290playback::function::
1291get_return_type_as_tree () const
1292{
1293 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1294}
1295
1296/* Construct a new local within this playback::function. */
1297
1298playback::lvalue *
1299playback::function::
1300new_local (location *loc,
1301 type *type,
1302 const char *name)
1303{
1304 gcc_assert (type);
1305 gcc_assert (name);
1306 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1307 get_identifier (name),
1308 type->as_tree ());
1309 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1310
1311 /* Prepend to BIND_EXPR_VARS: */
1312 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1313 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1314
1315 if (loc)
1316 set_tree_location (inner, loc);
1317 return new lvalue (m_ctxt, inner);
1318}
1319
1320/* Construct a new block within this playback::function. */
1321
1322playback::block *
1323playback::function::
1324new_block (const char *name)
1325{
1326 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1327
1328 block *result = new playback::block (this, name);
1329 m_blocks.safe_push (result);
1330 return result;
1331}
1332
1333/* Build a statement list for the function as a whole out of the
1334 lists of statements for the individual blocks, building labels
1335 for each block. */
1336
1337void
1338playback::function::
1339build_stmt_list ()
1340{
1341 int i;
1342 block *b;
1343
eb4c16eb
DM
1344 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1345
35485da9
DM
1346 FOR_EACH_VEC_ELT (m_blocks, i, b)
1347 {
1348 int j;
1349 tree stmt;
1350
1351 b->m_label_expr = build1 (LABEL_EXPR,
1352 void_type_node,
1353 b->as_label_decl ());
1354 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1355
1356 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1357 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1358 }
1359}
1360
1361/* Finish compiling the given function, potentially running the
1362 garbage-collector.
1363 The function will have a statement list by now.
1364 Amongst other things, this gimplifies the statement list,
1365 and calls cgraph_node::finalize_function on the function. */
1366
1367void
1368playback::function::
1369postprocess ()
1370{
eb4c16eb
DM
1371 JIT_LOG_SCOPE (m_ctxt->get_logger ());
1372
35485da9
DM
1373 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1374 debug_tree (m_stmt_list);
1375
1376 /* Do we need this to force cgraphunit.c to output the function? */
1377 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1378 {
1379 DECL_EXTERNAL (m_inner_fndecl) = 0;
1380 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1381 }
1382
1383 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1384 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1385 {
1386 DECL_EXTERNAL (m_inner_fndecl) = 0;
1387 TREE_PUBLIC (m_inner_fndecl) = 0;
1388 }
1389
1390 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1391 {
1392 /* Seem to need this in gimple-low.c: */
1393 gcc_assert (m_inner_block);
1394 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1395
1396 /* how to add to function? the following appears to be how to
1397 set the body of a m_inner_fndecl: */
1398 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1399
1400 /* Ensure that locals appear in the debuginfo. */
1401 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1402
1403 //debug_tree (m_inner_fndecl);
1404
1405 /* Convert to gimple: */
1406 //printf("about to gimplify_function_tree\n");
1407 gimplify_function_tree (m_inner_fndecl);
1408 //printf("finished gimplify_function_tree\n");
1409
1410 current_function_decl = m_inner_fndecl;
1411 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1412 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1413 //debug_tree (m_inner_fndecl);
1414
1415 //printf("about to add to cgraph\n");
1416 /* Add to cgraph: */
1417 cgraph_node::finalize_function (m_inner_fndecl, false);
1418 /* This can trigger a collection, so we need to have all of
1419 the funcs as roots. */
1420
1421 current_function_decl = NULL;
1422 }
1423}
1424
b957b2e0
DM
1425/* Don't leak vec's internal buffer (in non-GC heap) when we are
1426 GC-ed. */
1427
1428void
1429playback::block::finalizer ()
1430{
1431 m_stmts.release ();
1432}
1433
35485da9
DM
1434/* Add an eval of the rvalue to the function's statement list. */
1435
1436void
1437playback::block::
1438add_eval (location *loc,
1439 rvalue *rvalue)
1440{
1441 gcc_assert (rvalue);
1442
1443 if (loc)
1444 set_tree_location (rvalue->as_tree (), loc);
1445
1446 add_stmt (rvalue->as_tree ());
1447}
1448
1449/* Add an assignment to the function's statement list. */
1450
1451void
1452playback::block::
1453add_assignment (location *loc,
1454 lvalue *lvalue,
1455 rvalue *rvalue)
1456{
1457 gcc_assert (lvalue);
1458 gcc_assert (rvalue);
1459
1460 tree t_lvalue = lvalue->as_tree ();
1461 tree t_rvalue = rvalue->as_tree ();
1462 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1463 {
1464 t_rvalue = build1 (CONVERT_EXPR,
c168eab9
UD
1465 TREE_TYPE (t_lvalue),
1466 t_rvalue);
35485da9
DM
1467 if (loc)
1468 set_tree_location (t_rvalue, loc);
1469 }
1470
1471 tree stmt =
1472 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1473 t_lvalue, t_rvalue);
1474 if (loc)
1475 set_tree_location (stmt, loc);
1476 add_stmt (stmt);
1477}
1478
1479/* Add a comment to the function's statement list.
1480 For now this is done by adding a dummy label. */
1481
1482void
1483playback::block::
1484add_comment (location *loc,
1485 const char *text)
1486{
1487 /* Wrap the text in C-style comment delimiters. */
1488 size_t sz =
1489 (3 /* opening delim */
1490 + strlen (text)
1491 + 3 /* closing delim */
1492 + 1 /* terminator */);
1493 char *wrapped = (char *)ggc_internal_alloc (sz);
1494 snprintf (wrapped, sz, "/* %s */", text);
1495
1496 /* For now we simply implement this by adding a dummy label with a name
1497 containing the given text. */
1498 tree identifier = get_identifier (wrapped);
1499 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1500 identifier, void_type_node);
1501 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1502
1503 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1504 if (loc)
1505 set_tree_location (label_expr, loc);
1506 add_stmt (label_expr);
1507}
1508
1509/* Add a conditional jump statement to the function's statement list. */
1510
1511void
1512playback::block::
1513add_conditional (location *loc,
1514 rvalue *boolval,
1515 block *on_true,
1516 block *on_false)
1517{
1518 gcc_assert (boolval);
1519 gcc_assert (on_true);
1520 gcc_assert (on_false);
1521
1522 /* COND_EXPR wants statement lists for the true/false operands, but we
1523 want labels.
1524 Shim it by creating jumps to the labels */
1525 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1526 on_true->as_label_decl ());
1527 if (loc)
1528 set_tree_location (true_jump, loc);
1529
1530 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1531 on_false->as_label_decl ());
1532 if (loc)
1533 set_tree_location (false_jump, loc);
1534
1535 tree stmt =
1536 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1537 true_jump, false_jump);
1538 if (loc)
1539 set_tree_location (stmt, loc);
1540 add_stmt (stmt);
1541}
1542
1543/* Add an unconditional jump statement to the function's statement list. */
1544
1545void
1546playback::block::
1547add_jump (location *loc,
1548 block *target)
1549{
1550 gcc_assert (target);
1551
1552 // see c_finish_loop
1553 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1554 //add_stmt (top);
1555
1556 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1557 TREE_USED (target->as_label_decl ()) = 1;
1558 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1559 if (loc)
1560 set_tree_location (stmt, loc);
1561 add_stmt (stmt);
1562
1563 /*
1564 from c-typeck.c:
1565tree
1566c_finish_goto_label (location_t loc, tree label)
1567{
1568 tree decl = lookup_label_for_goto (loc, label);
1569 if (!decl)
1570 return NULL_TREE;
1571 TREE_USED (decl) = 1;
1572 {
1573 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1574 SET_EXPR_LOCATION (t, loc);
1575 return add_stmt (t);
1576 }
1577}
1578 */
1579
1580}
1581
1582/* Add a return statement to the function's statement list. */
1583
1584void
1585playback::block::
1586add_return (location *loc,
1587 rvalue *rvalue)
1588{
1589 tree modify_retval = NULL;
1590 tree return_type = m_func->get_return_type_as_tree ();
1591 if (rvalue)
1592 {
1593 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1594 tree t_rvalue = rvalue->as_tree ();
1595 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1596 t_rvalue = build1 (CONVERT_EXPR,
1597 TREE_TYPE (t_lvalue),
1598 t_rvalue);
1599 modify_retval = build2 (MODIFY_EXPR, return_type,
1600 t_lvalue, t_rvalue);
1601 if (loc)
1602 set_tree_location (modify_retval, loc);
1603 }
1604 tree return_stmt = build1 (RETURN_EXPR, return_type,
1605 modify_retval);
1606 if (loc)
1607 set_tree_location (return_stmt, loc);
1608
1609 add_stmt (return_stmt);
1610}
1611
ec5d0088
DM
1612/* Helper function for playback::block::add_switch.
1613 Construct a case label for the given range, followed by a goto stmt
1614 to the given block, appending them to stmt list *ptr_t_switch_body. */
1615
1616static void
1617add_case (tree *ptr_t_switch_body,
1618 tree t_low_value,
1619 tree t_high_value,
1620 playback::block *dest_block)
1621{
1622 tree t_label = create_artificial_label (UNKNOWN_LOCATION);
1623 DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
1624
1625 tree t_case_label =
1626 build_case_label (t_low_value, t_high_value, t_label);
1627 append_to_statement_list (t_case_label, ptr_t_switch_body);
1628
1629 tree t_goto_stmt =
1630 build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
1631 append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
1632}
1633
1634/* Add a switch statement to the function's statement list.
1635
1636 My initial attempt at implementing this constructed a TREE_VEC
1637 of the cases and set it as SWITCH_LABELS (switch_expr). However,
1638 gimplify.c:gimplify_switch_expr is set up to deal with SWITCH_BODY, and
1639 doesn't have any logic for gimplifying SWITCH_LABELS.
1640
1641 Hence we create a switch body, and populate it with case labels, each
1642 followed by a goto to the desired block. */
1643
1644void
1645playback::block::
1646add_switch (location *loc,
1647 rvalue *expr,
1648 block *default_block,
1649 const auto_vec <case_> *cases)
1650{
1651 /* Compare with:
1652 - c/c-typeck.c: c_start_case
1653 - c-family/c-common.c:c_add_case_label
1654 - java/expr.c:expand_java_switch and expand_java_add_case
1655 We've already rejected overlaps and duplicates in
1656 libgccjit.c:case_range_validator::validate. */
1657
1658 tree t_expr = expr->as_tree ();
1659 tree t_type = TREE_TYPE (t_expr);
1660
1661 tree t_switch_body = alloc_stmt_list ();
1662
1663 int i;
1664 case_ *c;
1665 FOR_EACH_VEC_ELT (*cases, i, c)
1666 {
1667 tree t_low_value = c->m_min_value->as_tree ();
1668 tree t_high_value = c->m_max_value->as_tree ();
1669 add_case (&t_switch_body,
1670 t_low_value,
1671 t_high_value,
1672 c->m_dest_block);
1673 }
1674 /* Default label. */
1675 add_case (&t_switch_body,
1676 NULL_TREE, NULL_TREE,
1677 default_block);
1678
1679 tree switch_stmt = build3 (SWITCH_EXPR, t_type, t_expr,
1680 t_switch_body, NULL_TREE);
1681 if (loc)
1682 set_tree_location (switch_stmt, loc);
1683 add_stmt (switch_stmt);
1684}
1685
35485da9
DM
1686/* Constructor for gcc::jit::playback::block. */
1687
1688playback::block::
1689block (function *func,
1690 const char *name)
1691: m_func (func),
1692 m_stmts ()
1693{
1694 tree identifier;
1695
1696 gcc_assert (func);
1697 // name can be NULL
1698 if (name)
1699 identifier = get_identifier (name);
1700 else
1701 identifier = NULL;
1702 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1703 identifier, void_type_node);
1704 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1705 m_label_expr = NULL;
1706}
1707
463366a0
DM
1708/* A subclass of auto_vec <char *> that frees all of its elements on
1709 deletion. */
1710
1711class auto_argvec : public auto_vec <char *>
1712{
1713 public:
1714 ~auto_argvec ();
1715};
1716
1717/* auto_argvec's dtor, freeing all contained strings, automatically
1718 chaining up to ~auto_vec <char *>, which frees the internal buffer. */
1719
1720auto_argvec::~auto_argvec ()
1721{
1722 int i;
1723 char *str;
1724 FOR_EACH_VEC_ELT (*this, i, str)
1725 free (str);
1726}
1727
35485da9
DM
1728/* Compile a playback::context:
1729
1730 - Use the context's options to cconstruct command-line options, and
1731 call into the rest of GCC (toplev::main).
fdce7209
DM
1732 - Assuming it succeeds, we have a .s file.
1733 - We then run the "postprocess" vfunc:
35485da9 1734
fdce7209
DM
1735 (A) In-memory compile ("gcc_jit_context_compile")
1736
1737 For an in-memory compile we have the playback::compile_to_memory
1738 subclass; "postprocess" will convert the .s file to a .so DSO,
1739 and load it in memory (via dlopen), wrapping the result up as
1740 a jit::result and returning it.
1741
1742 (B) Compile to file ("gcc_jit_context_compile_to_file")
1743
1744 When compiling to a file, we have the playback::compile_to_file
1745 subclass; "postprocess" will either copy the .s file to the
1746 destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
1747 the driver to convert it as necessary, copying the result. */
1748
1749void
35485da9
DM
1750playback::context::
1751compile ()
1752{
eb4c16eb
DM
1753 JIT_LOG_SCOPE (get_logger ());
1754
35485da9 1755 const char *ctxt_progname;
35485da9 1756
d1e5f2c7
DM
1757 int keep_intermediates =
1758 get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
35485da9 1759
d2286af3 1760 m_tempdir = new tempdir (get_logger (), keep_intermediates);
d1e5f2c7 1761 if (!m_tempdir->create ())
fdce7209 1762 return;
35485da9
DM
1763
1764 /* Call into the rest of gcc.
1765 For now, we have to assemble command-line options to pass into
1766 toplev::main, so that they can be parsed. */
1767
1768 /* Pass in user-provided program name as argv0, if any, so that it
1769 makes it into GCC's "progname" global, used in various diagnostics. */
1770 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
35485da9 1771
c985705a
DM
1772 if (!ctxt_progname)
1773 ctxt_progname = "libgccjit.so";
1774
463366a0
DM
1775 auto_vec <recording::requested_dump> requested_dumps;
1776 m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
1777
2cb844ce
DM
1778 /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
1779 acquire_mutex ();
1780
463366a0
DM
1781 auto_argvec fake_args;
1782 make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
8f50ee3c 1783 if (errors_occurred ())
2cb844ce
DM
1784 {
1785 release_mutex ();
1786 return;
1787 }
38771e4e 1788
463366a0 1789 /* This runs the compiler. */
afed3459 1790 toplev toplev (get_timer (), /* external_timer */
6fc2d0f3 1791 false); /* init_signals */
eb4c16eb
DM
1792 enter_scope ("toplev::main");
1793 if (get_logger ())
1794 for (unsigned i = 0; i < fake_args.length (); i++)
1795 get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
8f50ee3c
DM
1796 toplev.main (fake_args.length (),
1797 const_cast <char **> (fake_args.address ()));
eb4c16eb 1798 exit_scope ("toplev::main");
463366a0
DM
1799
1800 /* Extracting dumps makes use of the gcc::dump_manager, hence we
1801 need to do it between toplev::main (which creates the dump manager)
1802 and toplev::finalize (which deletes it). */
1803 extract_any_requested_dumps (&requested_dumps);
1804
1805 /* Clean up the compiler. */
eb4c16eb 1806 enter_scope ("toplev::finalize");
35485da9 1807 toplev.finalize ();
eb4c16eb 1808 exit_scope ("toplev::finalize");
35485da9 1809
38771e4e
DM
1810 /* Ideally we would release the jit mutex here, but we can't yet since
1811 followup activities use timevars, which are global state. */
35485da9
DM
1812
1813 if (errors_occurred ())
38771e4e
DM
1814 {
1815 release_mutex ();
fdce7209 1816 return;
38771e4e 1817 }
35485da9
DM
1818
1819 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
c6760a13 1820 dump_generated_code ();
35485da9 1821
fdce7209
DM
1822 /* We now have a .s file.
1823
1824 Run any postprocessing steps. This will either convert the .s file to
1825 a .so DSO, and load it in memory (playback::compile_to_memory), or
1826 convert the .s file to the requested output format, and copy it to a
1827 given file (playback::compile_to_file). */
1828 postprocess (ctxt_progname);
1829
1830 release_mutex ();
1831}
1832
1833/* Implementation of class gcc::jit::playback::compile_to_memory,
1834 a subclass of gcc::jit::playback::context. */
1835
1836/* playback::compile_to_memory's trivial constructor. */
1837
1838playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
1839 playback::context (ctxt),
1840 m_result (NULL)
1841{
1842 JIT_LOG_SCOPE (get_logger ());
1843}
1844
1845/* Implementation of the playback::context::process vfunc for compiling
1846 to memory.
1847
1848 Convert the .s file to a .so DSO, and load it in memory (via dlopen),
1849 wrapping the result up as a jit::result and returning it. */
1850
1851void
1852playback::compile_to_memory::postprocess (const char *ctxt_progname)
1853{
1854 JIT_LOG_SCOPE (get_logger ());
c6760a13
DM
1855 convert_to_dso (ctxt_progname);
1856 if (errors_occurred ())
fdce7209
DM
1857 return;
1858 m_result = dlopen_built_dso ();
1859}
1860
1861/* Implementation of class gcc::jit::playback::compile_to_file,
1862 a subclass of gcc::jit::playback::context. */
1863
1864/* playback::compile_to_file's trivial constructor. */
1865
1866playback::compile_to_file::compile_to_file (recording::context *ctxt,
1867 enum gcc_jit_output_kind output_kind,
1868 const char *output_path) :
1869 playback::context (ctxt),
1870 m_output_kind (output_kind),
1871 m_output_path (output_path)
1872{
1873 JIT_LOG_SCOPE (get_logger ());
1874}
1875
1876/* Implementation of the playback::context::process vfunc for compiling
1877 to a file.
1878
1879 Either copy the .s file to the given destination (for
1880 GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
1881 as necessary, copying the result. */
1882
1883void
1884playback::compile_to_file::postprocess (const char *ctxt_progname)
1885{
1886 JIT_LOG_SCOPE (get_logger ());
1887
1888 /* The driver takes different actions based on the filename, so
1889 we provide a filename with an appropriate suffix for the
1890 output kind, and then copy it up to the user-provided path,
1891 rather than directly compiling it to the requested output path. */
1892
1893 switch (m_output_kind)
38771e4e 1894 {
fdce7209
DM
1895 default:
1896 gcc_unreachable ();
1897
1898 case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
1899 copy_file (get_tempdir ()->get_path_s_file (),
1900 m_output_path);
199501ea 1901 /* The .s file is automatically unlinked by tempdir::~tempdir. */
fdce7209
DM
1902 break;
1903
1904 case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
1905 {
1906 char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
1907 "/fake.o",
1908 NULL);
1909 invoke_driver (ctxt_progname,
1910 get_tempdir ()->get_path_s_file (),
1911 tmp_o_path,
1912 TV_ASSEMBLE,
1913 false, /* bool shared, */
1914 false);/* bool run_linker */
1915 if (!errors_occurred ())
199501ea
DM
1916 {
1917 copy_file (tmp_o_path,
1918 m_output_path);
1919 get_tempdir ()->add_temp_file (tmp_o_path);
1920 }
1921 else
1922 free (tmp_o_path);
fdce7209
DM
1923 }
1924 break;
1925
1926 case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
1927 invoke_driver (ctxt_progname,
1928 get_tempdir ()->get_path_s_file (),
1929 get_tempdir ()->get_path_so_file (),
1930 TV_ASSEMBLE,
1931 true, /* bool shared, */
1932 true);/* bool run_linker */
1933 if (!errors_occurred ())
1934 copy_file (get_tempdir ()->get_path_so_file (),
1935 m_output_path);
199501ea 1936 /* The .so file is automatically unlinked by tempdir::~tempdir. */
fdce7209
DM
1937 break;
1938
1939 case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
1940 {
1941 char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
1942 "/fake.exe",
1943 NULL);
1944 invoke_driver (ctxt_progname,
1945 get_tempdir ()->get_path_s_file (),
1946 tmp_exe_path,
1947 TV_ASSEMBLE,
1948 false, /* bool shared, */
1949 true);/* bool run_linker */
1950 if (!errors_occurred ())
199501ea
DM
1951 {
1952 copy_file (tmp_exe_path,
1953 m_output_path);
1954 get_tempdir ()->add_temp_file (tmp_exe_path);
1955 }
1956 else
1957 free (tmp_exe_path);
fdce7209
DM
1958 }
1959 break;
1960
38771e4e 1961 }
35485da9 1962
fdce7209 1963}
35485da9 1964
fdce7209
DM
1965/* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
1966 the "executable" bits).
1967
1968 Any errors that occur are reported on the context and hence count as
1969 a failure of the compile.
1970
1971 We can't in general hardlink or use "rename" from the tempdir since
1972 it might be on a different filesystem to the destination. For example,
1973 I get EXDEV: "Invalid cross-device link". */
1974
1975void
1976playback::compile_to_file::copy_file (const char *src_path,
1977 const char *dst_path)
1978{
1979 JIT_LOG_SCOPE (get_logger ());
1980 if (get_logger ())
1981 {
1982 get_logger ()->log ("src_path: %s", src_path);
1983 get_logger ()->log ("dst_path: %s", dst_path);
1984 }
1985
1986 FILE *f_in = NULL;
1987 FILE *f_out = NULL;
1988 size_t total_sz_in = 0;
1989 size_t total_sz_out = 0;
1990 char buf[4096];
1991 size_t sz_in;
1992 struct stat stat_buf;
1993
1994 f_in = fopen (src_path, "rb");
1995 if (!f_in)
1996 {
1997 add_error (NULL,
1998 "unable to open %s for reading: %s",
1999 src_path,
2000 xstrerror (errno));
2001 return;
2002 }
38771e4e 2003
fdce7209
DM
2004 /* Use stat on the filedescriptor to get the mode,
2005 so that we can copy it over (in particular, the
2006 "executable" bits). */
2007 if (-1 == fstat (fileno (f_in), &stat_buf))
2008 {
2009 add_error (NULL,
2010 "unable to fstat %s: %s",
2011 src_path,
2012 xstrerror (errno));
2013 fclose (f_in);
2014 return;
2015 }
2016
2017 f_out = fopen (dst_path, "wb");
2018 if (!f_out)
2019 {
2020 add_error (NULL,
2021 "unable to open %s for writing: %s",
2022 dst_path,
2023 xstrerror (errno));
2024 fclose (f_in);
2025 return;
2026 }
2027
2028 while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
2029 {
2030 total_sz_in += sz_in;
2031 size_t sz_out_remaining = sz_in;
2032 size_t sz_out_so_far = 0;
2033 while (sz_out_remaining)
2034 {
2035 size_t sz_out = fwrite (buf + sz_out_so_far,
2036 1,
2037 sz_out_remaining,
2038 f_out);
2039 gcc_assert (sz_out <= sz_out_remaining);
2040 if (!sz_out)
2041 {
2042 add_error (NULL,
2043 "error writing to %s: %s",
2044 dst_path,
2045 xstrerror (errno));
2046 fclose (f_in);
2047 fclose (f_out);
2048 return;
2049 }
2050 total_sz_out += sz_out;
2051 sz_out_so_far += sz_out;
2052 sz_out_remaining -= sz_out;
2053 }
2054 gcc_assert (sz_out_so_far == sz_in);
2055 }
2056
2057 if (!feof (f_in))
2058 add_error (NULL,
2059 "error reading from %s: %s",
2060 src_path,
2061 xstrerror (errno));
2062
2063 fclose (f_in);
2064
2065 gcc_assert (total_sz_in == total_sz_out);
2066 if (get_logger ())
2067 get_logger ()->log ("total bytes copied: %ld", total_sz_out);
2068
2069 /* Set the permissions of the copy to those of the original file,
2070 in particular the "executable" bits. */
2071 if (-1 == fchmod (fileno (f_out), stat_buf.st_mode))
2072 add_error (NULL,
2073 "error setting mode of %s: %s",
2074 dst_path,
2075 xstrerror (errno));
2076
2077 fclose (f_out);
35485da9
DM
2078}
2079
8f50ee3c
DM
2080/* Helper functions for gcc::jit::playback::context::compile. */
2081
38771e4e
DM
2082/* This mutex guards gcc::jit::recording::context::compile, so that only
2083 one thread can be accessing the bulk of GCC's state at once. */
2084
2085static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
2086
2087/* Acquire jit_mutex and set "this" as the active playback ctxt. */
2088
2089void
2090playback::context::acquire_mutex ()
2091{
afed3459
DM
2092 auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
2093
38771e4e 2094 /* Acquire the big GCC mutex. */
eb4c16eb 2095 JIT_LOG_SCOPE (get_logger ());
38771e4e
DM
2096 pthread_mutex_lock (&jit_mutex);
2097 gcc_assert (NULL == active_playback_ctxt);
2098 active_playback_ctxt = this;
2099}
2100
2101/* Release jit_mutex and clear the active playback ctxt. */
2102
2103void
2104playback::context::release_mutex ()
2105{
2106 /* Release the big GCC mutex. */
eb4c16eb 2107 JIT_LOG_SCOPE (get_logger ());
38771e4e
DM
2108 gcc_assert (active_playback_ctxt == this);
2109 active_playback_ctxt = NULL;
2110 pthread_mutex_unlock (&jit_mutex);
2111}
2112
2cb844ce
DM
2113/* Callback used by gcc::jit::playback::context::make_fake_args when
2114 invoking driver_get_configure_time_options.
2115 Populate a vec <char * > with the configure-time options. */
2116
2117static void
2118append_arg_from_driver (const char *option, void *user_data)
2119{
2120 gcc_assert (option);
2121 gcc_assert (user_data);
2122 vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
2123 argvec->safe_push (concat ("-", option, NULL));
2124}
2125
8f50ee3c
DM
2126/* Build a fake argv for toplev::main from the options set
2127 by the user on the context . */
2128
2129void
2130playback::context::
463366a0
DM
2131make_fake_args (vec <char *> *argvec,
2132 const char *ctxt_progname,
2133 vec <recording::requested_dump> *requested_dumps)
8f50ee3c 2134{
eb4c16eb
DM
2135 JIT_LOG_SCOPE (get_logger ());
2136
463366a0
DM
2137#define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
2138#define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
8f50ee3c
DM
2139
2140 ADD_ARG (ctxt_progname);
d1e5f2c7 2141 ADD_ARG (get_path_c_file ());
8f50ee3c
DM
2142 ADD_ARG ("-fPIC");
2143
2144 /* Handle int options: */
2145 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
2146 {
2147 default:
2148 add_error (NULL,
2149 "unrecognized optimization level: %i",
2150 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
2151 return;
2152
2153 case 0:
2154 ADD_ARG ("-O0");
2155 break;
2156
2157 case 1:
2158 ADD_ARG ("-O1");
2159 break;
2160
2161 case 2:
2162 ADD_ARG ("-O2");
2163 break;
2164
2165 case 3:
2166 ADD_ARG ("-O3");
2167 break;
2168 }
2169 /* What about -Os? */
2170
2171 /* Handle bool options: */
2172 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2173 ADD_ARG ("-g");
2174
2175 /* Suppress timing (and other) info. */
2176 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
2177 {
2178 ADD_ARG ("-quiet");
2179 quiet_flag = 1;
2180 }
2181
2182 /* Aggressively garbage-collect, to shake out bugs: */
2183 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
2184 {
2185 ADD_ARG ("--param");
2186 ADD_ARG ("ggc-min-expand=0");
2187 ADD_ARG ("--param");
2188 ADD_ARG ("ggc-min-heapsize=0");
2189 }
2190
2191 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
2192 {
2193 ADD_ARG ("-fdump-tree-all");
2194 ADD_ARG ("-fdump-rtl-all");
2195 ADD_ARG ("-fdump-ipa-all");
2196 }
463366a0
DM
2197
2198 /* Add "-fdump-" options for any calls to
2199 gcc_jit_context_enable_dump. */
2200 {
2201 int i;
2202 recording::requested_dump *d;
2203 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2204 {
2205 char *arg = concat ("-fdump-", d->m_dumpname, NULL);
2206 ADD_ARG_TAKE_OWNERSHIP (arg);
2207 }
2208 }
2209
2cb844ce
DM
2210 /* PR jit/64810: Add any target-specific default options
2211 from OPTION_DEFAULT_SPECS, normally provided by the driver
2212 in the non-jit case.
2213
2214 The target-specific code can define OPTION_DEFAULT_SPECS:
2215 default command options in the form of spec macros for the
2216 driver to expand ().
2217
2218 For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
2219 if not overriden, injects the defaults as extra arguments to
2220 cc1 etc.
2221 For the jit case, we need to add these arguments here. The
2222 input format (using the specs language) means that we have to run
2223 part of the driver code here (driver_get_configure_time_options).
2224
2225 To avoid running the spec-expansion code every time, we just do
2226 it the first time (via a function-static flag), saving the result
2227 into a function-static vec.
2228 This flag and vec are global state (i.e. per-process).
2229 They are guarded by the jit mutex. */
2230 {
2231 static bool have_configure_time_options = false;
2232 static vec <char *> configure_time_options;
2233
2234 if (have_configure_time_options)
2235 log ("reusing cached configure-time options");
2236 else
2237 {
2238 have_configure_time_options = true;
2239 log ("getting configure-time options from driver");
2240 driver_get_configure_time_options (append_arg_from_driver,
2241 &configure_time_options);
2242 }
2243
2244 int i;
2245 char *opt;
2246
2247 if (get_logger ())
2248 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2249 log ("configure_time_options[%i]: %s", i, opt);
2250
2251 /* configure_time_options should now contain the expanded options
2252 from OPTION_DEFAULT_SPECS (if any). */
2253 FOR_EACH_VEC_ELT (configure_time_options, i, opt)
2254 {
2255 gcc_assert (opt);
2256 gcc_assert (opt[0] == '-');
2257 ADD_ARG (opt);
2258 }
2259 }
2260
afed3459
DM
2261 if (get_timer ())
2262 ADD_ARG ("-ftime-report");
2263
fa22c20d
DM
2264 /* Add any user-provided extra options, starting with any from
2265 parent contexts. */
2266 m_recording_ctxt->append_command_line_options (argvec);
2267
8f50ee3c 2268#undef ADD_ARG
463366a0
DM
2269#undef ADD_ARG_TAKE_OWNERSHIP
2270}
2271
2272/* The second half of the implementation of gcc_jit_context_enable_dump.
2273 Iterate through the requested dumps, reading the underlying files
2274 into heap-allocated buffers, writing pointers to the buffers into
2275 the char ** pointers provided by client code.
2276 Client code is responsible for calling free on the results. */
2277
2278void
2279playback::context::
2280extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
2281{
eb4c16eb
DM
2282 JIT_LOG_SCOPE (get_logger ());
2283
463366a0
DM
2284 int i;
2285 recording::requested_dump *d;
2286 FOR_EACH_VEC_ELT (*requested_dumps, i, d)
2287 {
2288 dump_file_info *dfi;
2289 char *filename;
2290 char *content;
2291
2292 dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
2293 if (!dfi)
2294 {
2295 add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
2296 continue;
2297 }
2298
2299 filename = g->get_dumps ()->get_dump_file_name (dfi);
2300 content = read_dump_file (filename);
2301 *(d->m_out_ptr) = content;
199501ea 2302 m_tempdir->add_temp_file (filename);
463366a0
DM
2303 }
2304}
2305
2306/* Helper function for playback::context::extract_any_requested_dumps
2307 (itself for use in implementation of gcc_jit_context_enable_dump).
2308
2309 Attempt to read the complete file at the given path, returning the
2310 bytes found there as a buffer.
2311 The caller is responsible for calling free on the result.
2312 Errors will be reported on the context, and lead to NULL being
2313 returned; an out-of-memory error will terminate the process. */
2314
2315char *
2316playback::context::read_dump_file (const char *path)
2317{
2318 char *result = NULL;
2319 size_t total_sz = 0;
2320 char buf[4096];
2321 size_t sz;
2322 FILE *f_in;
2323
2324 f_in = fopen (path, "r");
2325 if (!f_in)
2326 {
2327 add_error (NULL, "unable to open %s for reading", path);
2328 return NULL;
2329 }
2330
2331 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2332 {
2333 size_t old_total_sz = total_sz;
2334 total_sz += sz;
2335 result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
2336 memcpy (result + old_total_sz, buf, sz);
2337 }
2338
2339 if (!feof (f_in))
2340 {
2341 add_error (NULL, "error reading from %s", path);
2342 free (result);
1c35cc2c 2343 fclose (f_in);
463366a0
DM
2344 return NULL;
2345 }
2346
2347 fclose (f_in);
2348
2349 if (result)
2350 {
2351 result[total_sz] = '\0';
2352 return result;
2353 }
2354 else
2355 return xstrdup ("");
8f50ee3c
DM
2356}
2357
c6760a13
DM
2358/* Part of playback::context::compile ().
2359
2360 We have a .s file; we want a .so file.
2361 We could reuse parts of gcc/gcc.c to do this.
2362 For now, just use the driver binary from the install, as
2363 named in gcc-driver-name.h
2364 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
2365
2366void
2367playback::context::
2368convert_to_dso (const char *ctxt_progname)
fdce7209
DM
2369{
2370 JIT_LOG_SCOPE (get_logger ());
2371
2372 invoke_driver (ctxt_progname,
2373 m_tempdir->get_path_s_file (),
2374 m_tempdir->get_path_so_file (),
2375 TV_ASSEMBLE,
2376 true, /* bool shared, */
2377 true);/* bool run_linker */
2378}
2379
9376dd63
DM
2380static const char * const gcc_driver_name = GCC_DRIVER_NAME;
2381
fdce7209
DM
2382void
2383playback::context::
2384invoke_driver (const char *ctxt_progname,
2385 const char *input_file,
2386 const char *output_file,
2387 timevar_id_t tv_id,
2388 bool shared,
2389 bool run_linker)
c6760a13 2390{
eb4c16eb 2391 JIT_LOG_SCOPE (get_logger ());
9376dd63
DM
2392
2393 bool embedded_driver
2394 = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
2395
c6760a13
DM
2396 /* Currently this lumps together both assembling and linking into
2397 TV_ASSEMBLE. */
afed3459 2398 auto_timevar assemble_timevar (get_timer (), tv_id);
eb3982c1
DM
2399 auto_argvec argvec;
2400#define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
c6760a13 2401
c168eab9 2402 ADD_ARG (gcc_driver_name);
fdce7209 2403
eb3982c1
DM
2404 add_multilib_driver_arguments (&argvec);
2405
fdce7209
DM
2406 if (shared)
2407 ADD_ARG ("-shared");
2408
2409 if (!run_linker)
2410 ADD_ARG ("-c");
2411
2412 ADD_ARG (input_file);
c168eab9 2413 ADD_ARG ("-o");
fdce7209 2414 ADD_ARG (output_file);
c6760a13
DM
2415
2416 /* Don't use the linker plugin.
2417 If running with just a "make" and not a "make install", then we'd
2418 run into
2419 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
2420 libto_plugin is a .la at build time, with it becoming installed with
2421 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
2422 time. */
c168eab9 2423 ADD_ARG ("-fno-use-linker-plugin");
c6760a13 2424
baf3fbad
DM
2425#if defined (DARWIN_X86) || defined (DARWIN_PPC)
2426 /* OS X's linker defaults to treating undefined symbols as errors.
2427 If the context has any imported functions or globals they will be
2428 undefined until the .so is dynamically-linked into the process.
2429 Ensure that the driver passes in "-undefined dynamic_lookup" to the
2430 linker. */
2431 ADD_ARG ("-Wl,-undefined,dynamic_lookup");
2432#endif
2433
9376dd63
DM
2434 if (0)
2435 ADD_ARG ("-v");
2436
2437#undef ADD_ARG
c6760a13
DM
2438
2439 /* pex_one's error-handling requires pname to be non-NULL. */
2440 gcc_assert (ctxt_progname);
2441
eb4c16eb
DM
2442 if (get_logger ())
2443 for (unsigned i = 0; i < argvec.length (); i++)
2444 get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
2445
9376dd63
DM
2446 if (embedded_driver)
2447 invoke_embedded_driver (&argvec);
2448 else
2449 invoke_external_driver (ctxt_progname, &argvec);
2450}
2451
2452void
2453playback::context::
2454invoke_embedded_driver (const vec <char *> *argvec)
2455{
2456 JIT_LOG_SCOPE (get_logger ());
2457 driver d (true, /* can_finalize */
2458 false); /* debug */
2459 int result = d.main (argvec->length (),
2460 const_cast <char **> (argvec->address ()));
2461 d.finalize ();
2462 if (result)
2463 add_error (NULL, "error invoking gcc driver");
2464}
2465
2466void
2467playback::context::
2468invoke_external_driver (const char *ctxt_progname,
2469 vec <char *> *argvec)
2470{
2471 JIT_LOG_SCOPE (get_logger ());
2472 const char *errmsg;
2473 int exit_status = 0;
2474 int err = 0;
2475
2476 /* pex argv arrays are NULL-terminated. */
2477 argvec->safe_push (NULL);
2478
c6760a13
DM
2479 errmsg = pex_one (PEX_SEARCH, /* int flags, */
2480 gcc_driver_name,
9376dd63 2481 const_cast <char *const *> (argvec->address ()),
c6760a13
DM
2482 ctxt_progname, /* const char *pname */
2483 NULL, /* const char *outname */
2484 NULL, /* const char *errname */
2485 &exit_status, /* int *status */
2486 &err); /* int *err*/
2487 if (errmsg)
2488 {
2489 add_error (NULL, "error invoking gcc driver: %s", errmsg);
2490 return;
2491 }
2492
2493 /* pex_one can return a NULL errmsg when the executable wasn't
2494 found (or doesn't exist), so trap these cases also. */
2495 if (exit_status || err)
2496 {
2497 add_error (NULL,
2498 "error invoking gcc driver: exit_status: %i err: %i",
2499 exit_status, err);
2500 add_error (NULL,
2501 "whilst attempting to run a driver named: %s",
2502 gcc_driver_name);
2503 add_error (NULL,
2504 "PATH was: %s",
2505 getenv ("PATH"));
2506 return;
2507 }
2508}
2509
eb3982c1
DM
2510/* Extract the target-specific MULTILIB_DEFAULTS to
2511 multilib_defaults_raw for use by
2512 playback::context::add_multilib_driver_arguments (). */
2513
2514#ifndef MULTILIB_DEFAULTS
2515#define MULTILIB_DEFAULTS { "" }
2516#endif
2517
2518static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
2519
2520/* Helper function for playback::context::invoke_driver ().
2521
2522 32-bit and 64-bit multilib peer builds of libgccjit.so may share
2523 a driver binary. We need to pass in options to the shared driver
2524 to get the appropriate assembler/linker options for this multilib
2525 peer. */
2526
2527void
2528playback::context::
2529add_multilib_driver_arguments (vec <char *> *argvec)
2530{
2531 JIT_LOG_SCOPE (get_logger ());
2532
2533 /* Add copies of the arguments in multilib_defaults_raw to argvec,
2534 prepending each with a "-". */
2535 for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
2536 if (multilib_defaults_raw[i][0])
2537 argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
2538}
2539
38f4f641
DM
2540/* Dynamically-link the built DSO file into this process, using dlopen.
2541 Wrap it up within a jit::result *, and return that.
2542 Return NULL if any errors occur, reporting them on this context. */
2543
2544result *
2545playback::context::
2546dlopen_built_dso ()
2547{
eb4c16eb 2548 JIT_LOG_SCOPE (get_logger ());
afed3459 2549 auto_timevar load_timevar (get_timer (), TV_LOAD);
38f4f641
DM
2550 void *handle = NULL;
2551 const char *error = NULL;
2552 result *result_obj = NULL;
2553
2554 /* Clear any existing error. */
2555 dlerror ();
2556
d1e5f2c7
DM
2557 handle = dlopen (m_tempdir->get_path_so_file (),
2558 RTLD_NOW | RTLD_LOCAL);
38f4f641
DM
2559 if ((error = dlerror()) != NULL) {
2560 add_error (NULL, "%s", error);
2561 }
2562 if (handle)
d2286af3
DM
2563 {
2564 /* We've successfully dlopened the result; create a
2565 jit::result object to wrap it.
2566
2567 We're done with the tempdir for now, but if the user
2568 has requested debugging, the user's debugger might not
2569 be capable of dealing with the .so file being unlinked
2570 immediately, so keep it around until after the result
2571 is released. We do this by handing over ownership of
2572 the jit::tempdir to the result. See PR jit/64206. */
2573 tempdir *handover_tempdir;
2574 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
2575 {
2576 handover_tempdir = m_tempdir;
2577 m_tempdir = NULL;
2578 /* The tempdir will eventually be cleaned up in the
2579 jit::result's dtor. */
2580 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
2581 " handing over tempdir to jit::result");
2582 }
2583 else
2584 {
2585 handover_tempdir = NULL;
2586 /* ... and retain ownership of m_tempdir so we clean it
2587 up it the playback::context's dtor. */
2588 log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
2589 " retaining ownership of tempdir");
2590 }
2591
2592 result_obj = new result (get_logger (), handle, handover_tempdir);
2593 }
38f4f641
DM
2594 else
2595 result_obj = NULL;
2596
2597 return result_obj;
2598}
2599
35485da9
DM
2600/* Top-level hook for playing back a recording context.
2601
2602 This plays back m_recording_ctxt, and, if no errors
2603 occurred builds statement lists for and then postprocesses
2604 every function in the result. */
2605
2606void
2607playback::context::
2608replay ()
2609{
eb4c16eb 2610 JIT_LOG_SCOPE (get_logger ());
35485da9
DM
2611 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
2612 tree array_domain_type = build_index_type (size_int (200));
2613 m_char_array_type_node
2614 = build_array_type (char_type_node, array_domain_type);
2615
2616 m_const_char_ptr
2617 = build_pointer_type (build_qualified_type (char_type_node,
2618 TYPE_QUAL_CONST));
2619
2620 /* Replay the recorded events: */
2621 timevar_push (TV_JIT_REPLAY);
2622
2623 m_recording_ctxt->replay_into (this);
2624
2625 /* Clean away the temporary references from recording objects
2626 to playback objects. We have to do this now since the
2627 latter are GC-allocated, but the former don't mark these
2628 refs. Hence we must stop using them before the GC can run. */
2629 m_recording_ctxt->disassociate_from_playback ();
2630
eeafb319
DM
2631 /* The builtins_manager, if any, is associated with the recording::context
2632 and might be reused for future compiles on other playback::contexts,
2633 but its m_attributes array is not GTY-labeled and hence will become
2634 nonsense if the GC runs. Purge this state. */
2635 builtins_manager *bm = get_builtins_manager ();
2636 if (bm)
2637 bm->finish_playback ();
2638
35485da9
DM
2639 timevar_pop (TV_JIT_REPLAY);
2640
2641 if (!errors_occurred ())
2642 {
2643 int i;
2644 function *func;
2645
2646 /* No GC can happen yet; process the cached source locations. */
2647 handle_locations ();
2648
2649 /* We've now created tree nodes for the stmts in the various blocks
2650 in each function, but we haven't built each function's single stmt
2651 list yet. Do so now. */
2652 FOR_EACH_VEC_ELT (m_functions, i, func)
2653 func->build_stmt_list ();
2654
2655 /* No GC can have happened yet. */
2656
2657 /* Postprocess the functions. This could trigger GC. */
2658 FOR_EACH_VEC_ELT (m_functions, i, func)
2659 {
2660 gcc_assert (func);
2661 func->postprocess ();
2662 }
2663 }
2664}
2665
2666/* Dump the generated .s file to stderr. */
2667
2668void
2669playback::context::
2670dump_generated_code ()
2671{
eb4c16eb 2672 JIT_LOG_SCOPE (get_logger ());
35485da9
DM
2673 char buf[4096];
2674 size_t sz;
d1e5f2c7 2675 FILE *f_in = fopen (get_path_s_file (), "r");
35485da9
DM
2676 if (!f_in)
2677 return;
2678
2679 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
2680 fwrite (buf, 1, sz, stderr);
2681
2682 fclose (f_in);
2683}
2684
d1e5f2c7
DM
2685/* Get the supposed path of the notional "fake.c" file within the
2686 tempdir. This file doesn't exist, but the rest of the compiler
2687 needs a name. */
2688
2689const char *
2690playback::context::
2691get_path_c_file () const
2692{
2693 return m_tempdir->get_path_c_file ();
2694}
2695
2696/* Get the path of the assembler output file "fake.s" file within the
2697 tempdir. */
2698
2699const char *
2700playback::context::
2701get_path_s_file () const
2702{
2703 return m_tempdir->get_path_s_file ();
2704}
2705
2706/* Get the path of the DSO object file "fake.so" file within the
2707 tempdir. */
2708
2709const char *
2710playback::context::
2711get_path_so_file () const
2712{
2713 return m_tempdir->get_path_so_file ();
2714}
2715
35485da9
DM
2716/* qsort comparator for comparing pairs of playback::source_line *,
2717 ordering them by line number. */
2718
2719static int
2720line_comparator (const void *lhs, const void *rhs)
2721{
2722 const playback::source_line *line_lhs = \
2723 *static_cast<const playback::source_line * const*> (lhs);
2724 const playback::source_line *line_rhs = \
2725 *static_cast<const playback::source_line * const*> (rhs);
2726 return line_lhs->get_line_num () - line_rhs->get_line_num ();
2727}
2728
2729/* qsort comparator for comparing pairs of playback::location *,
2730 ordering them by column number. */
2731
2732static int
2733location_comparator (const void *lhs, const void *rhs)
2734{
2735 const playback::location *loc_lhs = \
2736 *static_cast<const playback::location * const *> (lhs);
2737 const playback::location *loc_rhs = \
2738 *static_cast<const playback::location * const *> (rhs);
2739 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
2740}
2741
2742/* Our API allows locations to be created in arbitrary orders, but the
2743 linemap API requires locations to be created in ascending order
2744 as if we were tokenizing files.
2745
026c3cfd 2746 This hook sorts all of the locations that have been created, and
35485da9
DM
2747 calls into the linemap API, creating linemap entries in sorted order
2748 for our locations. */
2749
2750void
2751playback::context::
2752handle_locations ()
2753{
2754 /* Create the source code locations, following the ordering rules
2755 imposed by the linemap API.
2756
2757 line_table is a global. */
eb4c16eb 2758 JIT_LOG_SCOPE (get_logger ());
35485da9
DM
2759 int i;
2760 source_file *file;
2761
2762 FOR_EACH_VEC_ELT (m_source_files, i, file)
2763 {
2764 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
2765
2766 /* Sort lines by ascending line numbers. */
2767 file->m_source_lines.qsort (&line_comparator);
2768
2769 int j;
2770 source_line *line;
2771 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
2772 {
2773 int k;
2774 location *loc;
2775
2776 /* Sort locations in line by ascending column numbers. */
2777 line->m_locations.qsort (&location_comparator);
2778
2779 /* Determine maximum column within this line. */
2780 gcc_assert (line->m_locations.length () > 0);
2781 location *final_column =
2782 line->m_locations[line->m_locations.length () - 1];
2783 int max_col = final_column->get_column_num ();
2784
2785 linemap_line_start (line_table, line->get_line_num (), max_col);
2786 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
2787 {
2788 loc->m_srcloc = \
2789 linemap_position_for_column (line_table, loc->get_column_num ());
2790 }
2791 }
2792
2793 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2794 }
2795
2796 /* line_table should now be populated; every playback::location should
2797 now have an m_srcloc. */
2798
2799 /* Now assign them to tree nodes as appropriate. */
2800 std::pair<tree, location *> *cached_location;
2801
2802 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
2803 {
2804 tree t = cached_location->first;
2805 source_location srcloc = cached_location->second->m_srcloc;
2806
2807 /* This covers expressions: */
2808 if (CAN_HAVE_LOCATION_P (t))
2809 SET_EXPR_LOCATION (t, srcloc);
2810 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
2811 DECL_SOURCE_LOCATION (t) = srcloc;
2812 else
2813 {
2814 /* Don't know how to set location on this node. */
2815 }
2816 }
2817}
2818
2819/* We handle errors on a playback::context by adding them to the
2820 corresponding recording::context. */
2821
2822void
2823playback::context::
2824add_error (location *loc, const char *fmt, ...)
2825{
2826 va_list ap;
2827 va_start (ap, fmt);
2828 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2829 fmt, ap);
2830 va_end (ap);
2831}
2832
2833/* We handle errors on a playback::context by adding them to the
2834 corresponding recording::context. */
2835
2836void
2837playback::context::
2838add_error_va (location *loc, const char *fmt, va_list ap)
2839{
2840 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
2841 fmt, ap);
2842}
2843
6b5423a5
DM
2844/* Report a diagnostic up to the jit context as an error,
2845 so that the compilation is treated as a failure.
2846 For now, any kind of diagnostic is treated as an error by the jit
2847 API. */
2848
2849void
2850playback::context::
2851add_diagnostic (struct diagnostic_context *diag_context,
2852 struct diagnostic_info *diagnostic)
2853{
2854 /* At this point the text has been formatted into the pretty-printer's
2855 output buffer. */
2856 pretty_printer *pp = diag_context->printer;
2857 const char *text = pp_formatted_text (pp);
2858
2859 /* Get location information (if any) from the diagnostic.
2860 The recording::context::add_error[_va] methods require a
2861 recording::location. We can't lookup the playback::location
2862 from the file/line/column since any playback location instances
2863 may have been garbage-collected away by now, so instead we create
2864 another recording::location directly. */
2865 location_t gcc_loc = diagnostic_location (diagnostic);
2866 recording::location *rec_loc = NULL;
2867 if (gcc_loc)
2868 {
2869 expanded_location exploc = expand_location (gcc_loc);
2870 if (exploc.file)
2871 rec_loc = m_recording_ctxt->new_location (exploc.file,
2872 exploc.line,
2873 exploc.column,
2874 false);
2875 }
2876
2877 m_recording_ctxt->add_error (rec_loc, "%s", text);
2878 pp_clear_output_area (pp);
2879}
2880
35485da9
DM
2881/* Dealing with the linemap API. */
2882
2883/* Construct a playback::location for a recording::location, if it
2884 doesn't exist already. */
2885
2886playback::location *
2887playback::context::
2888new_location (recording::location *rloc,
2889 const char *filename,
2890 int line,
2891 int column)
2892{
2893 /* Get the source_file for filename, creating if necessary. */
2894 source_file *src_file = get_source_file (filename);
2895 /* Likewise for the line within the file. */
2896 source_line *src_line = src_file->get_source_line (line);
2897 /* Likewise for the column within the line. */
2898 location *loc = src_line->get_location (rloc, column);
2899 return loc;
2900}
2901
2902/* Deferred setting of the location for a given tree, by adding the
2903 (tree, playback::location) pair to a list of deferred associations.
2904 We will actually set the location on the tree later on once
2905 the source_location for the playback::location exists. */
2906
2907void
2908playback::context::
2909set_tree_location (tree t, location *loc)
2910{
2911 gcc_assert (loc);
2912 m_cached_locations.safe_push (std::make_pair (t, loc));
2913}
2914
2915
2916/* Construct a playback::source_file for the given source
2917 filename, if it doesn't exist already. */
2918
2919playback::source_file *
2920playback::context::
2921get_source_file (const char *filename)
2922{
2923 /* Locate the file.
2924 For simplicitly, this is currently a linear search.
2925 Replace with a hash if this shows up in the profile. */
2926 int i;
2927 source_file *file;
2928 tree ident_filename = get_identifier (filename);
2929
2930 FOR_EACH_VEC_ELT (m_source_files, i, file)
2931 if (file->filename_as_tree () == ident_filename)
2932 return file;
2933
2934 /* Not found. */
2935 file = new source_file (ident_filename);
2936 m_source_files.safe_push (file);
2937 return file;
2938}
2939
2940/* Constructor for gcc::jit::playback::source_file. */
2941
2942playback::source_file::source_file (tree filename) :
2943 m_source_lines (),
2944 m_filename (filename)
2945{
2946}
2947
b957b2e0
DM
2948/* Don't leak vec's internal buffer (in non-GC heap) when we are
2949 GC-ed. */
2950
2951void
2952playback::source_file::finalizer ()
2953{
2954 m_source_lines.release ();
2955}
2956
35485da9
DM
2957/* Construct a playback::source_line for the given line
2958 within this source file, if one doesn't exist already. */
2959
2960playback::source_line *
2961playback::source_file::
2962get_source_line (int line_num)
2963{
2964 /* Locate the line.
2965 For simplicitly, this is currently a linear search.
2966 Replace with a hash if this shows up in the profile. */
2967 int i;
2968 source_line *line;
2969
2970 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2971 if (line->get_line_num () == line_num)
2972 return line;
2973
2974 /* Not found. */
2975 line = new source_line (this, line_num);
2976 m_source_lines.safe_push (line);
2977 return line;
2978}
2979
2980/* Constructor for gcc::jit::playback::source_line. */
2981
2982playback::source_line::source_line (source_file *file, int line_num) :
2983 m_locations (),
2984 m_source_file (file),
2985 m_line_num (line_num)
2986{
2987}
b957b2e0
DM
2988
2989/* Don't leak vec's internal buffer (in non-GC heap) when we are
2990 GC-ed. */
2991
2992void
2993playback::source_line::finalizer ()
2994{
2995 m_locations.release ();
2996}
35485da9
DM
2997
2998/* Construct a playback::location for the given column
2999 within this line of a specific source file, if one doesn't exist
3000 already. */
3001
3002playback::location *
3003playback::source_line::
3004get_location (recording::location *rloc, int column_num)
3005{
3006 int i;
3007 location *loc;
3008
3009 /* Another linear search that probably should be a hash table. */
3010 FOR_EACH_VEC_ELT (m_locations, i, loc)
3011 if (loc->get_column_num () == column_num)
3012 return loc;
3013
3014 /* Not found. */
3015 loc = new location (rloc, this, column_num);
3016 m_locations.safe_push (loc);
3017 return loc;
3018}
3019
3020/* Constructor for gcc::jit::playback::location. */
3021
3022playback::location::location (recording::location *loc,
3023 source_line *line,
3024 int column_num) :
3025 m_srcloc (UNKNOWN_LOCATION),
3026 m_recording_loc (loc),
3027 m_line (line),
3028 m_column_num(column_num)
3029{
3030}
3031
3032/* The active gcc::jit::playback::context instance. This is a singleton,
3033 guarded by jit_mutex. */
3034
3035playback::context *active_playback_ctxt;
3036
3037} // namespace gcc::jit
3038
3039} // namespace gcc