]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/jit/jit-playback.c
jit.exp: Avoid embedding full paths into test results
[thirdparty/gcc.git] / gcc / jit / jit-playback.c
CommitLineData
35485da9
DM
1/* Internals of libgccjit: classes for playing back recorded API calls.
2 Copyright (C) 2013-2014 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "opts.h"
25#include "tree.h"
26#include "hash-map.h"
27#include "is-a.h"
28#include "plugin-api.h"
29#include "vec.h"
30#include "hashtab.h"
31#include "hash-set.h"
32#include "machmode.h"
33#include "tm.h"
34#include "hard-reg-set.h"
35#include "function.h"
36#include "ipa-ref.h"
37#include "dumpfile.h"
38#include "cgraph.h"
39#include "toplev.h"
40#include "timevar.h"
41#include "tree-cfg.h"
42#include "target.h"
43#include "convert.h"
44#include "stringpool.h"
45#include "stor-layout.h"
46#include "print-tree.h"
47#include "gimplify.h"
48#include "gcc-driver-name.h"
49
50#include "jit-common.h"
51#include "jit-playback.h"
52
53
54/* gcc::jit::playback::context::build_cast uses the convert.h API,
55 which in turn requires the frontend to provide a "convert"
56 function, apparently as a fallback.
57
58 Hence we provide this dummy one, with the requirement that any casts
59 are handled before reaching this. */
60extern tree convert (tree type, tree expr);
61
62tree
63convert (tree dst_type, tree expr)
64{
65 gcc_assert (gcc::jit::active_playback_ctxt);
66 gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
67 fprintf (stderr, "input expression:\n");
68 debug_tree (expr);
69 fprintf (stderr, "requested type:\n");
70 debug_tree (dst_type);
71 return error_mark_node;
72}
73
74namespace gcc {
75namespace jit {
76
77/**********************************************************************
78 Playback.
79 **********************************************************************/
80
81/* The constructor for gcc::jit::playback::context. */
82
83playback::context::context (recording::context *ctxt)
84 : m_recording_ctxt (ctxt),
85 m_char_array_type_node (NULL),
86 m_const_char_ptr (NULL)
87{
88 m_functions.create (0);
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{
97 if (get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES))
98 fprintf (stderr, "intermediate files written to %s\n", m_path_tempdir);
99 else
100 {
101 /* Clean up .s/.so and tempdir. */
102 if (m_path_s_file)
103 unlink (m_path_s_file);
104 if (m_path_so_file)
105 unlink (m_path_so_file);
106 if (m_path_tempdir)
107 rmdir (m_path_tempdir);
108 }
109
110 free (m_path_template);
111 /* m_path_tempdir aliases m_path_template, or is NULL, so don't
112 attempt to free it . */
113 free (m_path_c_file);
114 free (m_path_s_file);
115 free (m_path_so_file);
116 m_functions.release ();
117}
118
119/* A playback::context can reference GC-managed pointers. Mark them
120 ("by hand", rather than by gengtype).
121
122 This is called on the active playback context (if any) by the
123 my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
124
125void
126playback::context::
127gt_ggc_mx ()
128{
129 int i;
130 function *func;
131 FOR_EACH_VEC_ELT (m_functions, i, func)
132 {
133 if (ggc_test_and_set_mark (func))
134 func->gt_ggc_mx ();
135 }
136}
137
138/* Given an enum gcc_jit_types value, get a "tree" type. */
139
140static tree
141get_tree_node_for_type (enum gcc_jit_types type_)
142{
143 switch (type_)
144 {
145 case GCC_JIT_TYPE_VOID:
146 return void_type_node;
147
148 case GCC_JIT_TYPE_VOID_PTR:
149 return ptr_type_node;
150
151 case GCC_JIT_TYPE_BOOL:
152 return boolean_type_node;
153
154 case GCC_JIT_TYPE_CHAR:
155 return char_type_node;
156 case GCC_JIT_TYPE_SIGNED_CHAR:
157 return signed_char_type_node;
158 case GCC_JIT_TYPE_UNSIGNED_CHAR:
159 return unsigned_char_type_node;
160
161 case GCC_JIT_TYPE_SHORT:
162 return short_integer_type_node;
163 case GCC_JIT_TYPE_UNSIGNED_SHORT:
164 return short_unsigned_type_node;
165
166 case GCC_JIT_TYPE_CONST_CHAR_PTR:
167 {
168 tree const_char = build_qualified_type (char_type_node,
169 TYPE_QUAL_CONST);
170 return build_pointer_type (const_char);
171 }
172
173 case GCC_JIT_TYPE_INT:
174 return integer_type_node;
175 case GCC_JIT_TYPE_UNSIGNED_INT:
176 return unsigned_type_node;
177
178 case GCC_JIT_TYPE_LONG:
179 return long_integer_type_node;
180 case GCC_JIT_TYPE_UNSIGNED_LONG:
181 return long_unsigned_type_node;
182
183 case GCC_JIT_TYPE_LONG_LONG:
184 return long_long_integer_type_node;
185 case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
186 return long_long_unsigned_type_node;
187
188 case GCC_JIT_TYPE_FLOAT:
189 return float_type_node;
190 case GCC_JIT_TYPE_DOUBLE:
191 return double_type_node;
192 case GCC_JIT_TYPE_LONG_DOUBLE:
193 return long_double_type_node;
194
195 case GCC_JIT_TYPE_SIZE_T:
196 return size_type_node;
197
198 case GCC_JIT_TYPE_FILE_PTR:
199 return fileptr_type_node;
200 }
201
202 return NULL;
203}
204
205/* Construct a playback::type instance (wrapping a tree) for the given
206 enum value. */
207
208playback::type *
209playback::context::
210get_type (enum gcc_jit_types type_)
211{
212 tree type_node = get_tree_node_for_type (type_);
213 if (NULL == type_node)
214 {
215 add_error (NULL,
216 "unrecognized (enum gcc_jit_types) value: %i", type_);
217 return NULL;
218 }
219
220 return new type (type_node);
221}
222
223/* Construct a playback::type instance (wrapping a tree) for the given
224 array type. */
225
226playback::type *
227playback::context::
228new_array_type (playback::location *loc,
229 playback::type *element_type,
230 int num_elements)
231{
232 gcc_assert (element_type);
233
234 tree t = build_array_type_nelts (element_type->as_tree (),
235 num_elements);
236 layout_type (t);
237
238 if (loc)
239 set_tree_location (t, loc);
240
241 return new type (t);
242}
243
244/* Construct a playback::field instance (wrapping a tree). */
245
246playback::field *
247playback::context::
248new_field (location *loc,
249 type *type,
250 const char *name)
251{
252 gcc_assert (type);
253 gcc_assert (name);
254
255 /* compare with c/c-decl.c:grokfield and grokdeclarator. */
256 tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
257 get_identifier (name), type->as_tree ());
258
259 if (loc)
260 set_tree_location (decl, loc);
261
262 return new field (decl);
263}
264
265/* Construct a playback::compound_type instance (wrapping a tree). */
266
267playback::compound_type *
268playback::context::
269new_compound_type (location *loc,
270 const char *name,
271 bool is_struct) /* else is union */
272{
273 gcc_assert (name);
274
275 /* Compare with c/c-decl.c: start_struct. */
276
277 tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
278 TYPE_NAME (t) = get_identifier (name);
279 TYPE_SIZE (t) = 0;
280
281 if (loc)
282 set_tree_location (t, loc);
283
284 return new compound_type (t);
285}
286
287void
b957b2e0 288playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
35485da9
DM
289{
290 /* Compare with c/c-decl.c: finish_struct. */
291 tree t = as_tree ();
292
293 tree fieldlist = NULL;
b957b2e0 294 for (unsigned i = 0; i < fields->length (); i++)
35485da9 295 {
b957b2e0 296 field *f = (*fields)[i];
35485da9
DM
297 DECL_CONTEXT (f->as_tree ()) = t;
298 fieldlist = chainon (f->as_tree (), fieldlist);
299 }
300 fieldlist = nreverse (fieldlist);
301 TYPE_FIELDS (t) = fieldlist;
302
303 layout_type (t);
304}
305
306/* Construct a playback::type instance (wrapping a tree) for a function
307 type. */
308
309playback::type *
310playback::context::
311new_function_type (type *return_type,
b957b2e0 312 const auto_vec<type *> *param_types,
35485da9
DM
313 int is_variadic)
314{
315 int i;
316 type *param_type;
317
318 tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
319
320 FOR_EACH_VEC_ELT (*param_types, i, param_type)
321 arg_types[i] = param_type->as_tree ();
322
323 tree fn_type;
324 if (is_variadic)
325 fn_type =
326 build_varargs_function_type_array (return_type->as_tree (),
327 param_types->length (),
328 arg_types);
329 else
330 fn_type = build_function_type_array (return_type->as_tree (),
331 param_types->length (),
332 arg_types);
333 free (arg_types);
334
335 return new type (fn_type);
336}
337
338/* Construct a playback::param instance (wrapping a tree). */
339
340playback::param *
341playback::context::
342new_param (location *loc,
343 type *type,
344 const char *name)
345{
346 gcc_assert (type);
347 gcc_assert (name);
348 tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
349 get_identifier (name), type->as_tree ());
350 if (loc)
351 set_tree_location (inner, loc);
352
353 return new param (this, inner);
354}
355
356/* Construct a playback::function instance. */
357
358playback::function *
359playback::context::
360new_function (location *loc,
361 enum gcc_jit_function_kind kind,
362 type *return_type,
363 const char *name,
b957b2e0 364 const auto_vec<param *> *params,
35485da9
DM
365 int is_variadic,
366 enum built_in_function builtin_id)
367{
368 int i;
369 param *param;
370
371 //can return_type be NULL?
372 gcc_assert (name);
373
374 tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
375 FOR_EACH_VEC_ELT (*params, i, param)
376 arg_types[i] = TREE_TYPE (param->as_tree ());
377
378 tree fn_type;
379 if (is_variadic)
380 fn_type = build_varargs_function_type_array (return_type->as_tree (),
381 params->length (), arg_types);
382 else
383 fn_type = build_function_type_array (return_type->as_tree (),
384 params->length (), arg_types);
385 free (arg_types);
386
387 /* FIXME: this uses input_location: */
388 tree fndecl = build_fn_decl (name, fn_type);
389
390 if (loc)
391 set_tree_location (fndecl, loc);
392
393 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
394 NULL_TREE, return_type->as_tree ());
395 DECL_ARTIFICIAL (resdecl) = 1;
396 DECL_IGNORED_P (resdecl) = 1;
397 DECL_RESULT (fndecl) = resdecl;
398
399 if (builtin_id)
400 {
401 DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
402 DECL_FUNCTION_CODE (fndecl) = builtin_id;
403 gcc_assert (loc == NULL);
404 DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
405 }
406
407 if (kind != GCC_JIT_FUNCTION_IMPORTED)
408 {
409 tree param_decl_list = NULL;
410 FOR_EACH_VEC_ELT (*params, i, param)
411 {
412 param_decl_list = chainon (param->as_tree (), param_decl_list);
413 }
414
415 /* The param list was created in reverse order; fix it: */
416 param_decl_list = nreverse (param_decl_list);
417
418 tree t;
419 for (t = param_decl_list; t; t = DECL_CHAIN (t))
420 {
421 DECL_CONTEXT (t) = fndecl;
422 DECL_ARG_TYPE (t) = TREE_TYPE (t);
423 }
424
425 /* Set it up on DECL_ARGUMENTS */
426 DECL_ARGUMENTS(fndecl) = param_decl_list;
427 }
428
429 if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
430 {
431 DECL_DECLARED_INLINE_P (fndecl) = 1;
432
433 /* Add attribute "always_inline": */
434 DECL_ATTRIBUTES (fndecl) =
435 tree_cons (get_identifier ("always_inline"),
436 NULL,
437 DECL_ATTRIBUTES (fndecl));
438 }
439
440 function *func = new function (this, fndecl, kind);
441 m_functions.safe_push (func);
442 return func;
443}
444
445/* Construct a playback::lvalue instance (wrapping a tree). */
446
447playback::lvalue *
448playback::context::
449new_global (location *loc,
450 type *type,
451 const char *name)
452{
453 gcc_assert (type);
454 gcc_assert (name);
455 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
456 get_identifier (name),
457 type->as_tree ());
458 TREE_PUBLIC (inner) = 1;
459 DECL_COMMON (inner) = 1;
460 DECL_EXTERNAL (inner) = 1;
461
462 if (loc)
463 set_tree_location (inner, loc);
464
465 return new lvalue (this, inner);
466}
467
468/* Construct a playback::rvalue instance (wrapping a tree). */
469
470playback::rvalue *
471playback::context::
472new_rvalue_from_int (type *type,
473 int value)
474{
475 // FIXME: type-checking, or coercion?
476 tree inner_type = type->as_tree ();
477 if (INTEGRAL_TYPE_P (inner_type))
478 {
479 tree inner = build_int_cst (inner_type, value);
480 return new rvalue (this, inner);
481 }
482 else
483 {
484 REAL_VALUE_TYPE real_value;
485 real_from_integer (&real_value, VOIDmode, value, SIGNED);
486 tree inner = build_real (inner_type, real_value);
487 return new rvalue (this, inner);
488 }
489}
490
491/* Construct a playback::rvalue instance (wrapping a tree). */
492
493playback::rvalue *
494playback::context::
495new_rvalue_from_double (type *type,
496 double value)
497{
498 // FIXME: type-checking, or coercion?
499 tree inner_type = type->as_tree ();
500
501 /* We have a "double", we want a REAL_VALUE_TYPE.
502
503 real.c:real_from_target appears to require the representation to be
504 split into 32-bit values, and then sent as an pair of host long
505 ints. */
506 REAL_VALUE_TYPE real_value;
507 union
508 {
509 double as_double;
510 uint32_t as_uint32s[2];
511 } u;
512 u.as_double = value;
513 long int as_long_ints[2];
514 as_long_ints[0] = u.as_uint32s[0];
515 as_long_ints[1] = u.as_uint32s[1];
516 real_from_target (&real_value, as_long_ints, DFmode);
517 tree inner = build_real (inner_type, real_value);
518 return new rvalue (this, inner);
519}
520
521/* Construct a playback::rvalue instance (wrapping a tree). */
522
523playback::rvalue *
524playback::context::
525new_rvalue_from_ptr (type *type,
526 void *value)
527{
528 tree inner_type = type->as_tree ();
529 /* FIXME: how to ensure we have a wide enough type? */
530 tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
531 return new rvalue (this, inner);
532}
533
534/* Construct a playback::rvalue instance (wrapping a tree). */
535
536playback::rvalue *
537playback::context::
538new_string_literal (const char *value)
539{
540 tree t_str = build_string (strlen (value), value);
541 gcc_assert (m_char_array_type_node);
542 TREE_TYPE (t_str) = m_char_array_type_node;
543
544 /* Convert to (const char*), loosely based on
545 c/c-typeck.c: array_to_pointer_conversion,
546 by taking address of start of string. */
547 tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
548
549 return new rvalue (this, t_addr);
550}
551
552/* Coerce a tree expression into a boolean tree expression. */
553
554tree
555playback::context::
556as_truth_value (tree expr, location *loc)
557{
558 /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
559 tree typed_zero = fold_build1 (CONVERT_EXPR,
560 TREE_TYPE (expr),
561 integer_zero_node);
562 if (loc)
563 set_tree_location (typed_zero, loc);
564
565 expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
566 if (loc)
567 set_tree_location (expr, loc);
568
569 return expr;
570}
571
572/* Construct a playback::rvalue instance (wrapping a tree) for a
573 unary op. */
574
575playback::rvalue *
576playback::context::
577new_unary_op (location *loc,
578 enum gcc_jit_unary_op op,
579 type *result_type,
580 rvalue *a)
581{
582 // FIXME: type-checking, or coercion?
583 enum tree_code inner_op;
584
585 gcc_assert (result_type);
586 gcc_assert (a);
587
588 tree node = a->as_tree ();
589 tree inner_result = NULL;
590
591 switch (op)
592 {
593 default:
594 add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
595 return NULL;
596
597 case GCC_JIT_UNARY_OP_MINUS:
598 inner_op = NEGATE_EXPR;
599 break;
600
601 case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
602 inner_op = BIT_NOT_EXPR;
603 break;
604
605 case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
606 node = as_truth_value (node, loc);
607 inner_result = invert_truthvalue (node);
608 if (loc)
609 set_tree_location (inner_result, loc);
610 return new rvalue (this, inner_result);
611 }
612
613 inner_result = build1 (inner_op,
614 result_type->as_tree (),
615 node);
616 if (loc)
617 set_tree_location (inner_result, loc);
618
619 return new rvalue (this, inner_result);
620}
621
622/* Construct a playback::rvalue instance (wrapping a tree) for a
623 binary op. */
624
625playback::rvalue *
626playback::context::
627new_binary_op (location *loc,
628 enum gcc_jit_binary_op op,
629 type *result_type,
630 rvalue *a, rvalue *b)
631{
632 // FIXME: type-checking, or coercion?
633 enum tree_code inner_op;
634
635 gcc_assert (result_type);
636 gcc_assert (a);
637 gcc_assert (b);
638
639 tree node_a = a->as_tree ();
640 tree node_b = b->as_tree ();
641
642 switch (op)
643 {
644 default:
645 add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
646 return NULL;
647
648 case GCC_JIT_BINARY_OP_PLUS:
649 inner_op = PLUS_EXPR;
650 break;
651
652 case GCC_JIT_BINARY_OP_MINUS:
653 inner_op = MINUS_EXPR;
654 break;
655
656 case GCC_JIT_BINARY_OP_MULT:
657 inner_op = MULT_EXPR;
658 break;
659
660 case GCC_JIT_BINARY_OP_DIVIDE:
661 if (FLOAT_TYPE_P (result_type->as_tree ()))
662 /* Floating-point division: */
663 inner_op = RDIV_EXPR;
664 else
665 /* Truncating to zero: */
666 inner_op = TRUNC_DIV_EXPR;
667 break;
668
669 case GCC_JIT_BINARY_OP_MODULO:
670 inner_op = TRUNC_MOD_EXPR;
671 break;
672
673 case GCC_JIT_BINARY_OP_BITWISE_AND:
674 inner_op = BIT_AND_EXPR;
675 break;
676
677 case GCC_JIT_BINARY_OP_BITWISE_XOR:
678 inner_op = BIT_XOR_EXPR;
679 break;
680
681 case GCC_JIT_BINARY_OP_BITWISE_OR:
682 inner_op = BIT_IOR_EXPR;
683 break;
684
685 case GCC_JIT_BINARY_OP_LOGICAL_AND:
686 node_a = as_truth_value (node_a, loc);
687 node_b = as_truth_value (node_b, loc);
688 inner_op = TRUTH_ANDIF_EXPR;
689 break;
690
691 case GCC_JIT_BINARY_OP_LOGICAL_OR:
692 node_a = as_truth_value (node_a, loc);
693 node_b = as_truth_value (node_b, loc);
694 inner_op = TRUTH_ORIF_EXPR;
695 break;
696
697 case GCC_JIT_BINARY_OP_LSHIFT:
698 inner_op = LSHIFT_EXPR;
699 break;
700
701 case GCC_JIT_BINARY_OP_RSHIFT:
702 inner_op = RSHIFT_EXPR;
703 break;
704 }
705
706 tree inner_expr = build2 (inner_op,
707 result_type->as_tree (),
708 node_a,
709 node_b);
710 if (loc)
711 set_tree_location (inner_expr, loc);
712
713 return new rvalue (this, inner_expr);
714}
715
716/* Construct a playback::rvalue instance (wrapping a tree) for a
717 comparison. */
718
719playback::rvalue *
720playback::context::
721new_comparison (location *loc,
722 enum gcc_jit_comparison op,
723 rvalue *a, rvalue *b)
724{
725 // FIXME: type-checking, or coercion?
726 enum tree_code inner_op;
727
728 gcc_assert (a);
729 gcc_assert (b);
730
731 switch (op)
732 {
733 default:
734 add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
735 return NULL;
736
737 case GCC_JIT_COMPARISON_EQ:
738 inner_op = EQ_EXPR;
739 break;
740 case GCC_JIT_COMPARISON_NE:
741 inner_op = NE_EXPR;
742 break;
743 case GCC_JIT_COMPARISON_LT:
744 inner_op = LT_EXPR;
745 break;
746 case GCC_JIT_COMPARISON_LE:
747 inner_op = LE_EXPR;
748 break;
749 case GCC_JIT_COMPARISON_GT:
750 inner_op = GT_EXPR;
751 break;
752 case GCC_JIT_COMPARISON_GE:
753 inner_op = GE_EXPR;
754 break;
755 }
756
757 tree inner_expr = build2 (inner_op,
758 boolean_type_node,
759 a->as_tree (),
760 b->as_tree ());
761 if (loc)
762 set_tree_location (inner_expr, loc);
763 return new rvalue (this, inner_expr);
764}
765
766/* Construct a playback::rvalue instance (wrapping a tree) for a
767 function call. */
768
769playback::rvalue *
770playback::context::
771build_call (location *loc,
772 tree fn_ptr,
b957b2e0 773 const auto_vec<rvalue *> *args)
35485da9
DM
774{
775 vec<tree, va_gc> *tree_args;
b957b2e0
DM
776 vec_alloc (tree_args, args->length ());
777 for (unsigned i = 0; i < args->length (); i++)
778 tree_args->quick_push ((*args)[i]->as_tree ());
35485da9
DM
779
780 if (loc)
781 set_tree_location (fn_ptr, loc);
782
783 tree fn = TREE_TYPE (fn_ptr);
784 tree fn_type = TREE_TYPE (fn);
785 tree return_type = TREE_TYPE (fn_type);
786
787 return new rvalue (this,
788 build_call_vec (return_type,
789 fn_ptr, tree_args));
790
791 /* see c-typeck.c: build_function_call
792 which calls build_function_call_vec
793
794 which does lots of checking, then:
795 result = build_call_array_loc (loc, TREE_TYPE (fntype),
796 function, nargs, argarray);
797 which is in tree.c
798 (see also build_call_vec)
799 */
800}
801
802/* Construct a playback::rvalue instance (wrapping a tree) for a
803 call to a specific function. */
804
805playback::rvalue *
806playback::context::
807new_call (location *loc,
808 function *func,
b957b2e0 809 const auto_vec<rvalue *> *args)
35485da9
DM
810{
811 tree fndecl;
812
813 gcc_assert (func);
814
815 fndecl = func->as_fndecl ();
816
817 tree fntype = TREE_TYPE (fndecl);
818
819 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
820
821 return build_call (loc, fn, args);
822}
823
824/* Construct a playback::rvalue instance (wrapping a tree) for a
825 call through a function pointer. */
826
827playback::rvalue *
828playback::context::
829new_call_through_ptr (location *loc,
830 rvalue *fn_ptr,
b957b2e0 831 const auto_vec<rvalue *> *args)
35485da9
DM
832{
833 gcc_assert (fn_ptr);
834 tree t_fn_ptr = fn_ptr->as_tree ();
835
836 return build_call (loc, t_fn_ptr, args);
837}
838
839/* Construct a tree for a cast. */
840
841tree
842playback::context::build_cast (playback::location *loc,
843 playback::rvalue *expr,
844 playback::type *type_)
845{
846 /* For comparison, see:
847 - c/c-typeck.c:build_c_cast
848 - c/c-convert.c: convert
849 - convert.h
850
851 Only some kinds of cast are currently supported here. */
852 tree t_expr = expr->as_tree ();
853 tree t_dst_type = type_->as_tree ();
854 tree t_ret = NULL;
855 t_ret = targetm.convert_to_type (t_dst_type, t_expr);
856 if (t_ret)
857 return t_ret;
858 enum tree_code dst_code = TREE_CODE (t_dst_type);
859 switch (dst_code)
860 {
861 case INTEGER_TYPE:
862 case ENUMERAL_TYPE:
863 t_ret = convert_to_integer (t_dst_type, t_expr);
864 goto maybe_fold;
865
866 case BOOLEAN_TYPE:
867 /* Compare with c_objc_common_truthvalue_conversion and
868 c_common_truthvalue_conversion. */
869 /* For now, convert to: (t_expr != 0) */
870 t_ret = build2 (NE_EXPR, t_dst_type,
871 t_expr, integer_zero_node);
872 goto maybe_fold;
873
874 case REAL_TYPE:
875 t_ret = convert_to_real (t_dst_type, t_expr);
876 goto maybe_fold;
877
878 case POINTER_TYPE:
879 t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
880 goto maybe_fold;
881
882 default:
883 add_error (loc, "couldn't handle cast during playback");
884 fprintf (stderr, "input expression:\n");
885 debug_tree (t_expr);
886 fprintf (stderr, "requested type:\n");
887 debug_tree (t_dst_type);
888 return error_mark_node;
889
890 maybe_fold:
891 if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
892 t_ret = fold (t_ret);
893 return t_ret;
894 }
895}
896
897/* Construct a playback::rvalue instance (wrapping a tree) for a
898 cast. */
899
900playback::rvalue *
901playback::context::
902new_cast (playback::location *loc,
903 playback::rvalue *expr,
904 playback::type *type_)
905{
906
907 tree t_cast = build_cast (loc, expr, type_);
908 if (loc)
909 set_tree_location (t_cast, loc);
910 return new rvalue (this, t_cast);
911}
912
913/* Construct a playback::lvalue instance (wrapping a tree) for an
914 array access. */
915
916playback::lvalue *
917playback::context::
918new_array_access (location *loc,
919 rvalue *ptr,
920 rvalue *index)
921{
922 gcc_assert (ptr);
923 gcc_assert (index);
924
925 /* For comparison, see:
926 c/c-typeck.c: build_array_ref
927 c-family/c-common.c: pointer_int_sum
928 */
929 tree t_ptr = ptr->as_tree ();
930 tree t_index = index->as_tree ();
931 tree t_type_ptr = TREE_TYPE (t_ptr);
932 tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
933
934 if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
935 {
936 tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
937 NULL_TREE, NULL_TREE);
938 if (loc)
939 set_tree_location (t_result, loc);
940 return new lvalue (this, t_result);
941 }
942 else
943 {
944 /* Convert index to an offset in bytes. */
945 tree t_sizeof = size_in_bytes (t_type_star_ptr);
946 t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
947 tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
948
949 /* Locate (ptr + offset). */
950 tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
951
952 tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
953 if (loc)
954 {
955 set_tree_location (t_sizeof, loc);
956 set_tree_location (t_offset, loc);
957 set_tree_location (t_address, loc);
958 set_tree_location (t_indirection, loc);
959 }
960
961 return new lvalue (this, t_indirection);
962 }
963}
964
965/* Construct a tree for a field access. */
966
967tree
968playback::context::
969new_field_access (location *loc,
970 tree datum,
971 field *field)
972{
973 gcc_assert (datum);
974 gcc_assert (field);
975
976 /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
977 build_component_ref. */
978 tree type = TREE_TYPE (datum);
979 gcc_assert (type);
980 gcc_assert (TREE_CODE (type) != POINTER_TYPE);
981
982 tree t_field = field->as_tree ();
983 tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
984 t_field, NULL_TREE);
985 if (loc)
986 set_tree_location (ref, loc);
987 return ref;
988}
989
990/* Construct a tree for a dereference. */
991
992tree
993playback::context::
994new_dereference (tree ptr,
995 location *loc)
996{
997 gcc_assert (ptr);
998
999 tree type = TREE_TYPE (TREE_TYPE(ptr));
1000 tree datum = build1 (INDIRECT_REF, type, ptr);
1001 if (loc)
1002 set_tree_location (datum, loc);
1003 return datum;
1004}
1005
1006/* Construct a playback::lvalue instance (wrapping a tree) for a
1007 field access. */
1008
1009playback::lvalue *
1010playback::lvalue::
1011access_field (location *loc,
1012 field *field)
1013{
1014 tree datum = as_tree ();
1015 tree ref = get_context ()->new_field_access (loc, datum, field);
1016 if (!ref)
1017 return NULL;
1018 return new lvalue (get_context (), ref);
1019}
1020
1021/* Construct a playback::rvalue instance (wrapping a tree) for a
1022 field access. */
1023
1024playback::rvalue *
1025playback::rvalue::
1026access_field (location *loc,
1027 field *field)
1028{
1029 tree datum = as_tree ();
1030 tree ref = get_context ()->new_field_access (loc, datum, field);
1031 if (!ref)
1032 return NULL;
1033 return new rvalue (get_context (), ref);
1034}
1035
1036/* Construct a playback::lvalue instance (wrapping a tree) for a
1037 dereferenced field access. */
1038
1039playback::lvalue *
1040playback::rvalue::
1041dereference_field (location *loc,
1042 field *field)
1043{
1044 tree ptr = as_tree ();
1045 tree datum = get_context ()->new_dereference (ptr, loc);
1046 if (!datum)
1047 return NULL;
1048 tree ref = get_context ()->new_field_access (loc, datum, field);
1049 if (!ref)
1050 return NULL;
1051 return new lvalue (get_context (), ref);
1052}
1053
1054/* Construct a playback::lvalue instance (wrapping a tree) for a
1055 dereference. */
1056
1057playback::lvalue *
1058playback::rvalue::
1059dereference (location *loc)
1060{
1061 tree ptr = as_tree ();
1062 tree datum = get_context ()->new_dereference (ptr, loc);
1063 return new lvalue (get_context (), datum);
1064}
1065
1066/* Construct a playback::rvalue instance (wrapping a tree) for an
1067 address-lookup. */
1068
1069playback::rvalue *
1070playback::lvalue::
1071get_address (location *loc)
1072{
1073 tree t_lvalue = as_tree ();
1074 tree t_thistype = TREE_TYPE (t_lvalue);
1075 tree t_ptrtype = build_pointer_type (t_thistype);
1076 tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
1077 if (loc)
1078 get_context ()->set_tree_location (ptr, loc);
1079 return new rvalue (get_context (), ptr);
1080}
1081
b957b2e0
DM
1082/* The wrapper subclasses are GC-managed, but can own non-GC memory.
1083 Provide this finalization hook for calling then they are collected,
1084 which calls the finalizer vfunc. This allows them to call "release"
1085 on any vec<> within them. */
1086
1087static void
1088wrapper_finalizer (void *ptr)
1089{
1090 playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
1091 wrapper->finalizer ();
1092}
1093
35485da9
DM
1094/* gcc::jit::playback::wrapper subclasses are GC-managed:
1095 allocate them using ggc_internal_cleared_alloc. */
1096
1097void *
1098playback::wrapper::
1099operator new (size_t sz)
1100{
b957b2e0
DM
1101 return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
1102
35485da9
DM
1103}
1104
1105/* Constructor for gcc:jit::playback::function. */
1106
1107playback::function::
1108function (context *ctxt,
1109 tree fndecl,
1110 enum gcc_jit_function_kind kind)
1111: m_ctxt(ctxt),
1112 m_inner_fndecl (fndecl),
1113 m_inner_bind_expr (NULL),
1114 m_kind (kind)
1115{
1116 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1117 {
1118 /* Create a BIND_EXPR, and within it, a statement list. */
1119 m_stmt_list = alloc_stmt_list ();
1120 m_stmt_iter = tsi_start (m_stmt_list);
1121 m_inner_block = make_node (BLOCK);
1122 m_inner_bind_expr =
1123 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1124 }
1125 else
1126 {
1127 m_inner_block = NULL;
1128 m_stmt_list = NULL;
1129 }
1130}
1131
1132/* Hand-written GC-marking hook for playback functions. */
1133
1134void
1135playback::function::
1136gt_ggc_mx ()
1137{
1138 gt_ggc_m_9tree_node (m_inner_fndecl);
1139 gt_ggc_m_9tree_node (m_inner_bind_expr);
1140 gt_ggc_m_9tree_node (m_stmt_list);
1141 gt_ggc_m_9tree_node (m_inner_block);
1142}
1143
b957b2e0
DM
1144/* Don't leak vec's internal buffer (in non-GC heap) when we are
1145 GC-ed. */
1146
1147void
1148playback::function::finalizer ()
1149{
1150 m_blocks.release ();
1151}
1152
35485da9
DM
1153/* Get the return type of a playback function, in tree form. */
1154
1155tree
1156playback::function::
1157get_return_type_as_tree () const
1158{
1159 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1160}
1161
1162/* Construct a new local within this playback::function. */
1163
1164playback::lvalue *
1165playback::function::
1166new_local (location *loc,
1167 type *type,
1168 const char *name)
1169{
1170 gcc_assert (type);
1171 gcc_assert (name);
1172 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1173 get_identifier (name),
1174 type->as_tree ());
1175 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1176
1177 /* Prepend to BIND_EXPR_VARS: */
1178 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1179 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1180
1181 if (loc)
1182 set_tree_location (inner, loc);
1183 return new lvalue (m_ctxt, inner);
1184}
1185
1186/* Construct a new block within this playback::function. */
1187
1188playback::block *
1189playback::function::
1190new_block (const char *name)
1191{
1192 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1193
1194 block *result = new playback::block (this, name);
1195 m_blocks.safe_push (result);
1196 return result;
1197}
1198
1199/* Build a statement list for the function as a whole out of the
1200 lists of statements for the individual blocks, building labels
1201 for each block. */
1202
1203void
1204playback::function::
1205build_stmt_list ()
1206{
1207 int i;
1208 block *b;
1209
1210 FOR_EACH_VEC_ELT (m_blocks, i, b)
1211 {
1212 int j;
1213 tree stmt;
1214
1215 b->m_label_expr = build1 (LABEL_EXPR,
1216 void_type_node,
1217 b->as_label_decl ());
1218 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1219
1220 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1221 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1222 }
1223}
1224
1225/* Finish compiling the given function, potentially running the
1226 garbage-collector.
1227 The function will have a statement list by now.
1228 Amongst other things, this gimplifies the statement list,
1229 and calls cgraph_node::finalize_function on the function. */
1230
1231void
1232playback::function::
1233postprocess ()
1234{
1235 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1236 debug_tree (m_stmt_list);
1237
1238 /* Do we need this to force cgraphunit.c to output the function? */
1239 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1240 {
1241 DECL_EXTERNAL (m_inner_fndecl) = 0;
1242 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1243 }
1244
1245 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1246 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1247 {
1248 DECL_EXTERNAL (m_inner_fndecl) = 0;
1249 TREE_PUBLIC (m_inner_fndecl) = 0;
1250 }
1251
1252 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1253 {
1254 /* Seem to need this in gimple-low.c: */
1255 gcc_assert (m_inner_block);
1256 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1257
1258 /* how to add to function? the following appears to be how to
1259 set the body of a m_inner_fndecl: */
1260 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1261
1262 /* Ensure that locals appear in the debuginfo. */
1263 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1264
1265 //debug_tree (m_inner_fndecl);
1266
1267 /* Convert to gimple: */
1268 //printf("about to gimplify_function_tree\n");
1269 gimplify_function_tree (m_inner_fndecl);
1270 //printf("finished gimplify_function_tree\n");
1271
1272 current_function_decl = m_inner_fndecl;
1273 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1274 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1275 //debug_tree (m_inner_fndecl);
1276
1277 //printf("about to add to cgraph\n");
1278 /* Add to cgraph: */
1279 cgraph_node::finalize_function (m_inner_fndecl, false);
1280 /* This can trigger a collection, so we need to have all of
1281 the funcs as roots. */
1282
1283 current_function_decl = NULL;
1284 }
1285}
1286
b957b2e0
DM
1287/* Don't leak vec's internal buffer (in non-GC heap) when we are
1288 GC-ed. */
1289
1290void
1291playback::block::finalizer ()
1292{
1293 m_stmts.release ();
1294}
1295
35485da9
DM
1296/* Add an eval of the rvalue to the function's statement list. */
1297
1298void
1299playback::block::
1300add_eval (location *loc,
1301 rvalue *rvalue)
1302{
1303 gcc_assert (rvalue);
1304
1305 if (loc)
1306 set_tree_location (rvalue->as_tree (), loc);
1307
1308 add_stmt (rvalue->as_tree ());
1309}
1310
1311/* Add an assignment to the function's statement list. */
1312
1313void
1314playback::block::
1315add_assignment (location *loc,
1316 lvalue *lvalue,
1317 rvalue *rvalue)
1318{
1319 gcc_assert (lvalue);
1320 gcc_assert (rvalue);
1321
1322 tree t_lvalue = lvalue->as_tree ();
1323 tree t_rvalue = rvalue->as_tree ();
1324 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1325 {
1326 t_rvalue = build1 (CONVERT_EXPR,
1327 TREE_TYPE (t_lvalue),
1328 t_rvalue);
1329 if (loc)
1330 set_tree_location (t_rvalue, loc);
1331 }
1332
1333 tree stmt =
1334 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1335 t_lvalue, t_rvalue);
1336 if (loc)
1337 set_tree_location (stmt, loc);
1338 add_stmt (stmt);
1339}
1340
1341/* Add a comment to the function's statement list.
1342 For now this is done by adding a dummy label. */
1343
1344void
1345playback::block::
1346add_comment (location *loc,
1347 const char *text)
1348{
1349 /* Wrap the text in C-style comment delimiters. */
1350 size_t sz =
1351 (3 /* opening delim */
1352 + strlen (text)
1353 + 3 /* closing delim */
1354 + 1 /* terminator */);
1355 char *wrapped = (char *)ggc_internal_alloc (sz);
1356 snprintf (wrapped, sz, "/* %s */", text);
1357
1358 /* For now we simply implement this by adding a dummy label with a name
1359 containing the given text. */
1360 tree identifier = get_identifier (wrapped);
1361 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1362 identifier, void_type_node);
1363 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1364
1365 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1366 if (loc)
1367 set_tree_location (label_expr, loc);
1368 add_stmt (label_expr);
1369}
1370
1371/* Add a conditional jump statement to the function's statement list. */
1372
1373void
1374playback::block::
1375add_conditional (location *loc,
1376 rvalue *boolval,
1377 block *on_true,
1378 block *on_false)
1379{
1380 gcc_assert (boolval);
1381 gcc_assert (on_true);
1382 gcc_assert (on_false);
1383
1384 /* COND_EXPR wants statement lists for the true/false operands, but we
1385 want labels.
1386 Shim it by creating jumps to the labels */
1387 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1388 on_true->as_label_decl ());
1389 if (loc)
1390 set_tree_location (true_jump, loc);
1391
1392 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1393 on_false->as_label_decl ());
1394 if (loc)
1395 set_tree_location (false_jump, loc);
1396
1397 tree stmt =
1398 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1399 true_jump, false_jump);
1400 if (loc)
1401 set_tree_location (stmt, loc);
1402 add_stmt (stmt);
1403}
1404
1405/* Add an unconditional jump statement to the function's statement list. */
1406
1407void
1408playback::block::
1409add_jump (location *loc,
1410 block *target)
1411{
1412 gcc_assert (target);
1413
1414 // see c_finish_loop
1415 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1416 //add_stmt (top);
1417
1418 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1419 TREE_USED (target->as_label_decl ()) = 1;
1420 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1421 if (loc)
1422 set_tree_location (stmt, loc);
1423 add_stmt (stmt);
1424
1425 /*
1426 from c-typeck.c:
1427tree
1428c_finish_goto_label (location_t loc, tree label)
1429{
1430 tree decl = lookup_label_for_goto (loc, label);
1431 if (!decl)
1432 return NULL_TREE;
1433 TREE_USED (decl) = 1;
1434 {
1435 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1436 SET_EXPR_LOCATION (t, loc);
1437 return add_stmt (t);
1438 }
1439}
1440 */
1441
1442}
1443
1444/* Add a return statement to the function's statement list. */
1445
1446void
1447playback::block::
1448add_return (location *loc,
1449 rvalue *rvalue)
1450{
1451 tree modify_retval = NULL;
1452 tree return_type = m_func->get_return_type_as_tree ();
1453 if (rvalue)
1454 {
1455 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1456 tree t_rvalue = rvalue->as_tree ();
1457 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1458 t_rvalue = build1 (CONVERT_EXPR,
1459 TREE_TYPE (t_lvalue),
1460 t_rvalue);
1461 modify_retval = build2 (MODIFY_EXPR, return_type,
1462 t_lvalue, t_rvalue);
1463 if (loc)
1464 set_tree_location (modify_retval, loc);
1465 }
1466 tree return_stmt = build1 (RETURN_EXPR, return_type,
1467 modify_retval);
1468 if (loc)
1469 set_tree_location (return_stmt, loc);
1470
1471 add_stmt (return_stmt);
1472}
1473
1474/* Constructor for gcc::jit::playback::block. */
1475
1476playback::block::
1477block (function *func,
1478 const char *name)
1479: m_func (func),
1480 m_stmts ()
1481{
1482 tree identifier;
1483
1484 gcc_assert (func);
1485 // name can be NULL
1486 if (name)
1487 identifier = get_identifier (name);
1488 else
1489 identifier = NULL;
1490 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1491 identifier, void_type_node);
1492 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1493 m_label_expr = NULL;
1494}
1495
1496/* Construct a tempdir path template suitable for use by mkdtemp
1497 e.g. "/tmp/libgccjit-XXXXXX", but respecting the rules in
1498 libiberty's choose_tempdir rather than hardcoding "/tmp/".
1499
1500 The memory is allocated using malloc and must be freed.
1501 Aborts the process if allocation fails. */
1502
1503static char *
1504make_tempdir_path_template ()
1505{
1506 const char *tmpdir_buf;
1507 size_t tmpdir_len;
1508 const char *file_template_buf;
1509 size_t file_template_len;
1510 char *result;
1511
1512 /* The result of choose_tmpdir is a cached buffer within libiberty, so
1513 we must *not* free it. */
1514 tmpdir_buf = choose_tmpdir ();
1515
1516 /* choose_tmpdir aborts on malloc failure. */
1517 gcc_assert (tmpdir_buf);
1518
1519 tmpdir_len = strlen (tmpdir_buf);
1520 /* tmpdir_buf should now have a dir separator as the final byte. */
1521 gcc_assert (tmpdir_len > 0);
1522 gcc_assert (tmpdir_buf[tmpdir_len - 1] == DIR_SEPARATOR);
1523
1524 file_template_buf = "libgccjit-XXXXXX";
1525 file_template_len = strlen (file_template_buf);
1526
1527 result = XNEWVEC (char, tmpdir_len + file_template_len + 1);
1528 strcpy (result, tmpdir_buf);
1529 strcpy (result + tmpdir_len, file_template_buf);
1530
1531 return result;
1532}
1533
1534/* Compile a playback::context:
1535
1536 - Use the context's options to cconstruct command-line options, and
1537 call into the rest of GCC (toplev::main).
1538 - Assuming it succeeds, we have a .s file; we want a .so file.
1539 Invoke another gcc to convert the .s file to a .so file.
1540 - dlopen the .so file
1541 - Wrap the result up as a playback::result and return it. */
1542
1543result *
1544playback::context::
1545compile ()
1546{
1547 void *handle = NULL;
1548 const char *ctxt_progname;
1549 result *result_obj = NULL;
1550 const char *fake_args[20];
1551 unsigned int num_args;
1552
1553 m_path_template = make_tempdir_path_template ();
1554 if (!m_path_template)
1555 return NULL;
1556
1557 /* Create tempdir using mkdtemp. This is created with 0700 perms and
1558 is unique. Hence no other (non-root) users should have access to
1559 the paths within it. */
1560 m_path_tempdir = mkdtemp (m_path_template);
1561 if (!m_path_tempdir)
1562 return NULL;
1563 m_path_c_file = concat (m_path_tempdir, "/fake.c", NULL);
1564 m_path_s_file = concat (m_path_tempdir, "/fake.s", NULL);
1565 m_path_so_file = concat (m_path_tempdir, "/fake.so", NULL);
1566
1567 /* Call into the rest of gcc.
1568 For now, we have to assemble command-line options to pass into
1569 toplev::main, so that they can be parsed. */
1570
1571 /* Pass in user-provided program name as argv0, if any, so that it
1572 makes it into GCC's "progname" global, used in various diagnostics. */
1573 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1574 fake_args[0] =
1575 (ctxt_progname ? ctxt_progname : "libgccjit.so");
1576
1577 fake_args[1] = m_path_c_file;
1578 num_args = 2;
1579
1580#define ADD_ARG(arg) \
1581 do \
1582 { \
1583 gcc_assert(num_args < sizeof(fake_args)/sizeof(char*)); \
1584 fake_args[num_args++] = arg; \
1585 } \
1586 while (0)
1587
1588 ADD_ARG ("-fPIC");
1589
1590 /* Handle int options: */
1591 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
1592 {
1593 default:
1594 add_error (NULL,
1595 "unrecognized optimization level: %i",
1596 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
1597 return NULL;
1598
1599 case 0:
1600 ADD_ARG ("-O0");
1601 break;
1602
1603 case 1:
1604 ADD_ARG ("-O1");
1605 break;
1606
1607 case 2:
1608 ADD_ARG ("-O2");
1609 break;
1610
1611 case 3:
1612 ADD_ARG ("-O3");
1613 break;
1614 }
1615 /* What about -Os? */
1616
1617 /* Handle bool options: */
1618 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
1619 ADD_ARG ("-g");
1620
1621 /* Suppress timing (and other) info. */
1622 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
1623 {
1624 ADD_ARG ("-quiet");
1625 quiet_flag = 1;
1626 }
1627
1628 /* Aggressively garbage-collect, to shake out bugs: */
1629 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
1630 {
1631 ADD_ARG ("--param");
1632 ADD_ARG ("ggc-min-expand=0");
1633 ADD_ARG ("--param");
1634 ADD_ARG ("ggc-min-heapsize=0");
1635 }
1636
1637 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
1638 {
1639 ADD_ARG ("-fdump-tree-all");
1640 ADD_ARG ("-fdump-rtl-all");
1641 ADD_ARG ("-fdump-ipa-all");
1642 }
1643
1644 toplev toplev (false);
1645
1646 toplev.main (num_args, const_cast <char **> (fake_args));
1647 toplev.finalize ();
1648
1649 active_playback_ctxt = NULL;
1650
1651 if (errors_occurred ())
1652 return NULL;
1653
1654 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1655 dump_generated_code ();
1656
1657 /* Gross hacks follow:
1658 We have a .s file; we want a .so file.
1659 We could reuse parts of gcc/gcc.c to do this.
1660 For now, just use the driver binary from the install, as
1661 named in gcc-driver-name.h
1662 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0".
1663 */
1664 {
1665 auto_timevar assemble_timevar (TV_ASSEMBLE);
1666 const char *errmsg;
1667 const char *argv[7];
1668 int exit_status = 0;
1669 int err = 0;
1670 const char *gcc_driver_name = GCC_DRIVER_NAME;
1671
1672 argv[0] = gcc_driver_name;
1673 argv[1] = "-shared";
1674 /* The input: assembler. */
1675 argv[2] = m_path_s_file;
1676 /* The output: shared library. */
1677 argv[3] = "-o";
1678 argv[4] = m_path_so_file;
1679
1680 /* Don't use the linker plugin.
1681 If running with just a "make" and not a "make install", then we'd
1682 run into
1683 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
1684 libto_plugin is a .la at build time, with it becoming installed with
1685 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
1686 time. */
1687 argv[5] = "-fno-use-linker-plugin";
1688
1689 /* pex argv arrays are NULL-terminated. */
1690 argv[6] = NULL;
1691
1692 errmsg = pex_one (PEX_SEARCH, /* int flags, */
1693 gcc_driver_name,
1694 const_cast<char * const *> (argv),
1695 ctxt_progname, /* const char *pname */
1696 NULL, /* const char *outname */
1697 NULL, /* const char *errname */
1698 &exit_status, /* int *status */
1699 &err); /* int *err*/
1700 if (errmsg)
1701 {
1702 add_error (NULL, "error invoking gcc driver: %s", errmsg);
1703 return NULL;
1704 }
1705
1706 /* pex_one can return a NULL errmsg when the executable wasn't
1707 found (or doesn't exist), so trap these cases also. */
1708 if (exit_status || err)
1709 {
1710 add_error (NULL,
1711 "error invoking gcc driver: exit_status: %i err: %i",
1712 exit_status, err);
1713 add_error (NULL,
1714 "whilst attempting to run a driver named: %s",
1715 gcc_driver_name);
1716 add_error (NULL,
1717 "PATH was: %s",
1718 getenv ("PATH"));
1719 return NULL;
1720 }
1721 }
1722
1723 // TODO: split out assembles vs linker
1724
1725 /* dlopen the .so file. */
1726 {
1727 auto_timevar load_timevar (TV_LOAD);
1728
1729 const char *error;
1730
1731 /* Clear any existing error. */
1732 dlerror ();
1733
1734 handle = dlopen (m_path_so_file, RTLD_NOW | RTLD_LOCAL);
1735 if ((error = dlerror()) != NULL) {
1736 add_error (NULL, "%s", error);
1737 }
1738 if (handle)
1739 result_obj = new result (handle);
1740 else
1741 result_obj = NULL;
1742 }
1743
1744 return result_obj;
1745}
1746
1747/* Top-level hook for playing back a recording context.
1748
1749 This plays back m_recording_ctxt, and, if no errors
1750 occurred builds statement lists for and then postprocesses
1751 every function in the result. */
1752
1753void
1754playback::context::
1755replay ()
1756{
1757 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
1758 tree array_domain_type = build_index_type (size_int (200));
1759 m_char_array_type_node
1760 = build_array_type (char_type_node, array_domain_type);
1761
1762 m_const_char_ptr
1763 = build_pointer_type (build_qualified_type (char_type_node,
1764 TYPE_QUAL_CONST));
1765
1766 /* Replay the recorded events: */
1767 timevar_push (TV_JIT_REPLAY);
1768
1769 m_recording_ctxt->replay_into (this);
1770
1771 /* Clean away the temporary references from recording objects
1772 to playback objects. We have to do this now since the
1773 latter are GC-allocated, but the former don't mark these
1774 refs. Hence we must stop using them before the GC can run. */
1775 m_recording_ctxt->disassociate_from_playback ();
1776
1777 timevar_pop (TV_JIT_REPLAY);
1778
1779 if (!errors_occurred ())
1780 {
1781 int i;
1782 function *func;
1783
1784 /* No GC can happen yet; process the cached source locations. */
1785 handle_locations ();
1786
1787 /* We've now created tree nodes for the stmts in the various blocks
1788 in each function, but we haven't built each function's single stmt
1789 list yet. Do so now. */
1790 FOR_EACH_VEC_ELT (m_functions, i, func)
1791 func->build_stmt_list ();
1792
1793 /* No GC can have happened yet. */
1794
1795 /* Postprocess the functions. This could trigger GC. */
1796 FOR_EACH_VEC_ELT (m_functions, i, func)
1797 {
1798 gcc_assert (func);
1799 func->postprocess ();
1800 }
1801 }
1802}
1803
1804/* Dump the generated .s file to stderr. */
1805
1806void
1807playback::context::
1808dump_generated_code ()
1809{
1810 char buf[4096];
1811 size_t sz;
1812 FILE *f_in = fopen (m_path_s_file, "r");
1813 if (!f_in)
1814 return;
1815
1816 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
1817 fwrite (buf, 1, sz, stderr);
1818
1819 fclose (f_in);
1820}
1821
1822/* qsort comparator for comparing pairs of playback::source_line *,
1823 ordering them by line number. */
1824
1825static int
1826line_comparator (const void *lhs, const void *rhs)
1827{
1828 const playback::source_line *line_lhs = \
1829 *static_cast<const playback::source_line * const*> (lhs);
1830 const playback::source_line *line_rhs = \
1831 *static_cast<const playback::source_line * const*> (rhs);
1832 return line_lhs->get_line_num () - line_rhs->get_line_num ();
1833}
1834
1835/* qsort comparator for comparing pairs of playback::location *,
1836 ordering them by column number. */
1837
1838static int
1839location_comparator (const void *lhs, const void *rhs)
1840{
1841 const playback::location *loc_lhs = \
1842 *static_cast<const playback::location * const *> (lhs);
1843 const playback::location *loc_rhs = \
1844 *static_cast<const playback::location * const *> (rhs);
1845 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
1846}
1847
1848/* Our API allows locations to be created in arbitrary orders, but the
1849 linemap API requires locations to be created in ascending order
1850 as if we were tokenizing files.
1851
1852 This hook sorts all of the the locations that have been created, and
1853 calls into the linemap API, creating linemap entries in sorted order
1854 for our locations. */
1855
1856void
1857playback::context::
1858handle_locations ()
1859{
1860 /* Create the source code locations, following the ordering rules
1861 imposed by the linemap API.
1862
1863 line_table is a global. */
1864 int i;
1865 source_file *file;
1866
1867 FOR_EACH_VEC_ELT (m_source_files, i, file)
1868 {
1869 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
1870
1871 /* Sort lines by ascending line numbers. */
1872 file->m_source_lines.qsort (&line_comparator);
1873
1874 int j;
1875 source_line *line;
1876 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
1877 {
1878 int k;
1879 location *loc;
1880
1881 /* Sort locations in line by ascending column numbers. */
1882 line->m_locations.qsort (&location_comparator);
1883
1884 /* Determine maximum column within this line. */
1885 gcc_assert (line->m_locations.length () > 0);
1886 location *final_column =
1887 line->m_locations[line->m_locations.length () - 1];
1888 int max_col = final_column->get_column_num ();
1889
1890 linemap_line_start (line_table, line->get_line_num (), max_col);
1891 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
1892 {
1893 loc->m_srcloc = \
1894 linemap_position_for_column (line_table, loc->get_column_num ());
1895 }
1896 }
1897
1898 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
1899 }
1900
1901 /* line_table should now be populated; every playback::location should
1902 now have an m_srcloc. */
1903
1904 /* Now assign them to tree nodes as appropriate. */
1905 std::pair<tree, location *> *cached_location;
1906
1907 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
1908 {
1909 tree t = cached_location->first;
1910 source_location srcloc = cached_location->second->m_srcloc;
1911
1912 /* This covers expressions: */
1913 if (CAN_HAVE_LOCATION_P (t))
1914 SET_EXPR_LOCATION (t, srcloc);
1915 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
1916 DECL_SOURCE_LOCATION (t) = srcloc;
1917 else
1918 {
1919 /* Don't know how to set location on this node. */
1920 }
1921 }
1922}
1923
1924/* We handle errors on a playback::context by adding them to the
1925 corresponding recording::context. */
1926
1927void
1928playback::context::
1929add_error (location *loc, const char *fmt, ...)
1930{
1931 va_list ap;
1932 va_start (ap, fmt);
1933 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
1934 fmt, ap);
1935 va_end (ap);
1936}
1937
1938/* We handle errors on a playback::context by adding them to the
1939 corresponding recording::context. */
1940
1941void
1942playback::context::
1943add_error_va (location *loc, const char *fmt, va_list ap)
1944{
1945 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
1946 fmt, ap);
1947}
1948
1949/* Constructor for gcc::jit::playback::result. */
1950
1951result::
1952result(void *dso_handle)
1953 : m_dso_handle(dso_handle)
1954{
1955}
1956
1957/* gcc::jit::playback::result's destructor.
1958
1959 Called implicitly by gcc_jit_result_release. */
1960
1961result::~result()
1962{
1963 dlclose (m_dso_handle);
1964}
1965
1966/* Attempt to locate the given function by name within the
1967 playback::result, using dlsym.
1968
1969 Implements the post-error-checking part of
1970 gcc_jit_result_get_code. */
1971
1972void *
1973result::
1974get_code (const char *funcname)
1975{
1976 void *code;
1977 const char *error;
1978
1979 /* Clear any existing error. */
1980 dlerror ();
1981
1982 code = dlsym (m_dso_handle, funcname);
1983
1984 if ((error = dlerror()) != NULL) {
1985 fprintf(stderr, "%s\n", error);
1986 }
1987
1988 return code;
1989}
1990
1991/* Dealing with the linemap API. */
1992
1993/* Construct a playback::location for a recording::location, if it
1994 doesn't exist already. */
1995
1996playback::location *
1997playback::context::
1998new_location (recording::location *rloc,
1999 const char *filename,
2000 int line,
2001 int column)
2002{
2003 /* Get the source_file for filename, creating if necessary. */
2004 source_file *src_file = get_source_file (filename);
2005 /* Likewise for the line within the file. */
2006 source_line *src_line = src_file->get_source_line (line);
2007 /* Likewise for the column within the line. */
2008 location *loc = src_line->get_location (rloc, column);
2009 return loc;
2010}
2011
2012/* Deferred setting of the location for a given tree, by adding the
2013 (tree, playback::location) pair to a list of deferred associations.
2014 We will actually set the location on the tree later on once
2015 the source_location for the playback::location exists. */
2016
2017void
2018playback::context::
2019set_tree_location (tree t, location *loc)
2020{
2021 gcc_assert (loc);
2022 m_cached_locations.safe_push (std::make_pair (t, loc));
2023}
2024
2025
2026/* Construct a playback::source_file for the given source
2027 filename, if it doesn't exist already. */
2028
2029playback::source_file *
2030playback::context::
2031get_source_file (const char *filename)
2032{
2033 /* Locate the file.
2034 For simplicitly, this is currently a linear search.
2035 Replace with a hash if this shows up in the profile. */
2036 int i;
2037 source_file *file;
2038 tree ident_filename = get_identifier (filename);
2039
2040 FOR_EACH_VEC_ELT (m_source_files, i, file)
2041 if (file->filename_as_tree () == ident_filename)
2042 return file;
2043
2044 /* Not found. */
2045 file = new source_file (ident_filename);
2046 m_source_files.safe_push (file);
2047 return file;
2048}
2049
2050/* Constructor for gcc::jit::playback::source_file. */
2051
2052playback::source_file::source_file (tree filename) :
2053 m_source_lines (),
2054 m_filename (filename)
2055{
2056}
2057
b957b2e0
DM
2058/* Don't leak vec's internal buffer (in non-GC heap) when we are
2059 GC-ed. */
2060
2061void
2062playback::source_file::finalizer ()
2063{
2064 m_source_lines.release ();
2065}
2066
35485da9
DM
2067/* Construct a playback::source_line for the given line
2068 within this source file, if one doesn't exist already. */
2069
2070playback::source_line *
2071playback::source_file::
2072get_source_line (int line_num)
2073{
2074 /* Locate the line.
2075 For simplicitly, this is currently a linear search.
2076 Replace with a hash if this shows up in the profile. */
2077 int i;
2078 source_line *line;
2079
2080 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2081 if (line->get_line_num () == line_num)
2082 return line;
2083
2084 /* Not found. */
2085 line = new source_line (this, line_num);
2086 m_source_lines.safe_push (line);
2087 return line;
2088}
2089
2090/* Constructor for gcc::jit::playback::source_line. */
2091
2092playback::source_line::source_line (source_file *file, int line_num) :
2093 m_locations (),
2094 m_source_file (file),
2095 m_line_num (line_num)
2096{
2097}
b957b2e0
DM
2098
2099/* Don't leak vec's internal buffer (in non-GC heap) when we are
2100 GC-ed. */
2101
2102void
2103playback::source_line::finalizer ()
2104{
2105 m_locations.release ();
2106}
35485da9
DM
2107
2108/* Construct a playback::location for the given column
2109 within this line of a specific source file, if one doesn't exist
2110 already. */
2111
2112playback::location *
2113playback::source_line::
2114get_location (recording::location *rloc, int column_num)
2115{
2116 int i;
2117 location *loc;
2118
2119 /* Another linear search that probably should be a hash table. */
2120 FOR_EACH_VEC_ELT (m_locations, i, loc)
2121 if (loc->get_column_num () == column_num)
2122 return loc;
2123
2124 /* Not found. */
2125 loc = new location (rloc, this, column_num);
2126 m_locations.safe_push (loc);
2127 return loc;
2128}
2129
2130/* Constructor for gcc::jit::playback::location. */
2131
2132playback::location::location (recording::location *loc,
2133 source_line *line,
2134 int column_num) :
2135 m_srcloc (UNKNOWN_LOCATION),
2136 m_recording_loc (loc),
2137 m_line (line),
2138 m_column_num(column_num)
2139{
2140}
2141
2142/* The active gcc::jit::playback::context instance. This is a singleton,
2143 guarded by jit_mutex. */
2144
2145playback::context *active_playback_ctxt;
2146
2147} // namespace gcc::jit
2148
2149} // namespace gcc