ipa-cp.c (ipcp_cloning_candidate_p): Use opt_for_fn.
[gcc.git] / gcc / jit / jit-playback.c
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
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "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. */
60 extern tree convert (tree type, tree expr);
61
62 tree
63 convert (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
74 namespace gcc {
75 namespace jit {
76
77 /**********************************************************************
78 Playback.
79 **********************************************************************/
80
81 /* The constructor for gcc::jit::playback::context. */
82
83 playback::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
95 playback::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
125 void
126 playback::context::
127 gt_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
140 static tree
141 get_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
208 playback::type *
209 playback::context::
210 get_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
226 playback::type *
227 playback::context::
228 new_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
246 playback::field *
247 playback::context::
248 new_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
267 playback::compound_type *
268 playback::context::
269 new_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
287 void
288 playback::compound_type::set_fields (const vec<playback::field *> &fields)
289 {
290 /* Compare with c/c-decl.c: finish_struct. */
291 tree t = as_tree ();
292
293 tree fieldlist = NULL;
294 for (unsigned i = 0; i < fields.length (); i++)
295 {
296 field *f = fields[i];
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
309 playback::type *
310 playback::context::
311 new_function_type (type *return_type,
312 vec<type *> *param_types,
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
340 playback::param *
341 playback::context::
342 new_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
358 playback::function *
359 playback::context::
360 new_function (location *loc,
361 enum gcc_jit_function_kind kind,
362 type *return_type,
363 const char *name,
364 vec<param *> *params,
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
447 playback::lvalue *
448 playback::context::
449 new_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
470 playback::rvalue *
471 playback::context::
472 new_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
493 playback::rvalue *
494 playback::context::
495 new_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
523 playback::rvalue *
524 playback::context::
525 new_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
536 playback::rvalue *
537 playback::context::
538 new_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
554 tree
555 playback::context::
556 as_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
575 playback::rvalue *
576 playback::context::
577 new_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
625 playback::rvalue *
626 playback::context::
627 new_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
719 playback::rvalue *
720 playback::context::
721 new_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
769 playback::rvalue *
770 playback::context::
771 build_call (location *loc,
772 tree fn_ptr,
773 vec<rvalue *> args)
774 {
775 vec<tree, va_gc> *tree_args;
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 ());
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
805 playback::rvalue *
806 playback::context::
807 new_call (location *loc,
808 function *func,
809 vec<rvalue *> args)
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
827 playback::rvalue *
828 playback::context::
829 new_call_through_ptr (location *loc,
830 rvalue *fn_ptr,
831 vec<rvalue *> args)
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
841 tree
842 playback::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
900 playback::rvalue *
901 playback::context::
902 new_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
916 playback::lvalue *
917 playback::context::
918 new_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
967 tree
968 playback::context::
969 new_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
992 tree
993 playback::context::
994 new_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
1009 playback::lvalue *
1010 playback::lvalue::
1011 access_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
1024 playback::rvalue *
1025 playback::rvalue::
1026 access_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
1039 playback::lvalue *
1040 playback::rvalue::
1041 dereference_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
1057 playback::lvalue *
1058 playback::rvalue::
1059 dereference (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
1069 playback::rvalue *
1070 playback::lvalue::
1071 get_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
1082 /* gcc::jit::playback::wrapper subclasses are GC-managed:
1083 allocate them using ggc_internal_cleared_alloc. */
1084
1085 void *
1086 playback::wrapper::
1087 operator new (size_t sz)
1088 {
1089 return ggc_internal_cleared_alloc (sz MEM_STAT_INFO);
1090 }
1091
1092 /* Constructor for gcc:jit::playback::function. */
1093
1094 playback::function::
1095 function (context *ctxt,
1096 tree fndecl,
1097 enum gcc_jit_function_kind kind)
1098 : m_ctxt(ctxt),
1099 m_inner_fndecl (fndecl),
1100 m_inner_bind_expr (NULL),
1101 m_kind (kind)
1102 {
1103 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1104 {
1105 /* Create a BIND_EXPR, and within it, a statement list. */
1106 m_stmt_list = alloc_stmt_list ();
1107 m_stmt_iter = tsi_start (m_stmt_list);
1108 m_inner_block = make_node (BLOCK);
1109 m_inner_bind_expr =
1110 build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
1111 }
1112 else
1113 {
1114 m_inner_block = NULL;
1115 m_stmt_list = NULL;
1116 }
1117 }
1118
1119 /* Hand-written GC-marking hook for playback functions. */
1120
1121 void
1122 playback::function::
1123 gt_ggc_mx ()
1124 {
1125 gt_ggc_m_9tree_node (m_inner_fndecl);
1126 gt_ggc_m_9tree_node (m_inner_bind_expr);
1127 gt_ggc_m_9tree_node (m_stmt_list);
1128 gt_ggc_m_9tree_node (m_inner_block);
1129 }
1130
1131 /* Get the return type of a playback function, in tree form. */
1132
1133 tree
1134 playback::function::
1135 get_return_type_as_tree () const
1136 {
1137 return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
1138 }
1139
1140 /* Construct a new local within this playback::function. */
1141
1142 playback::lvalue *
1143 playback::function::
1144 new_local (location *loc,
1145 type *type,
1146 const char *name)
1147 {
1148 gcc_assert (type);
1149 gcc_assert (name);
1150 tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1151 get_identifier (name),
1152 type->as_tree ());
1153 DECL_CONTEXT (inner) = this->m_inner_fndecl;
1154
1155 /* Prepend to BIND_EXPR_VARS: */
1156 DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
1157 BIND_EXPR_VARS (m_inner_bind_expr) = inner;
1158
1159 if (loc)
1160 set_tree_location (inner, loc);
1161 return new lvalue (m_ctxt, inner);
1162 }
1163
1164 /* Construct a new block within this playback::function. */
1165
1166 playback::block *
1167 playback::function::
1168 new_block (const char *name)
1169 {
1170 gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
1171
1172 block *result = new playback::block (this, name);
1173 m_blocks.safe_push (result);
1174 return result;
1175 }
1176
1177 /* Build a statement list for the function as a whole out of the
1178 lists of statements for the individual blocks, building labels
1179 for each block. */
1180
1181 void
1182 playback::function::
1183 build_stmt_list ()
1184 {
1185 int i;
1186 block *b;
1187
1188 FOR_EACH_VEC_ELT (m_blocks, i, b)
1189 {
1190 int j;
1191 tree stmt;
1192
1193 b->m_label_expr = build1 (LABEL_EXPR,
1194 void_type_node,
1195 b->as_label_decl ());
1196 tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
1197
1198 FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
1199 tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
1200 }
1201 }
1202
1203 /* Finish compiling the given function, potentially running the
1204 garbage-collector.
1205 The function will have a statement list by now.
1206 Amongst other things, this gimplifies the statement list,
1207 and calls cgraph_node::finalize_function on the function. */
1208
1209 void
1210 playback::function::
1211 postprocess ()
1212 {
1213 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
1214 debug_tree (m_stmt_list);
1215
1216 /* Do we need this to force cgraphunit.c to output the function? */
1217 if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
1218 {
1219 DECL_EXTERNAL (m_inner_fndecl) = 0;
1220 DECL_PRESERVE_P (m_inner_fndecl) = 1;
1221 }
1222
1223 if (m_kind == GCC_JIT_FUNCTION_INTERNAL
1224 ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
1225 {
1226 DECL_EXTERNAL (m_inner_fndecl) = 0;
1227 TREE_PUBLIC (m_inner_fndecl) = 0;
1228 }
1229
1230 if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
1231 {
1232 /* Seem to need this in gimple-low.c: */
1233 gcc_assert (m_inner_block);
1234 DECL_INITIAL (m_inner_fndecl) = m_inner_block;
1235
1236 /* how to add to function? the following appears to be how to
1237 set the body of a m_inner_fndecl: */
1238 DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
1239
1240 /* Ensure that locals appear in the debuginfo. */
1241 BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
1242
1243 //debug_tree (m_inner_fndecl);
1244
1245 /* Convert to gimple: */
1246 //printf("about to gimplify_function_tree\n");
1247 gimplify_function_tree (m_inner_fndecl);
1248 //printf("finished gimplify_function_tree\n");
1249
1250 current_function_decl = m_inner_fndecl;
1251 if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
1252 dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
1253 //debug_tree (m_inner_fndecl);
1254
1255 //printf("about to add to cgraph\n");
1256 /* Add to cgraph: */
1257 cgraph_node::finalize_function (m_inner_fndecl, false);
1258 /* This can trigger a collection, so we need to have all of
1259 the funcs as roots. */
1260
1261 current_function_decl = NULL;
1262 }
1263 }
1264
1265 /* Add an eval of the rvalue to the function's statement list. */
1266
1267 void
1268 playback::block::
1269 add_eval (location *loc,
1270 rvalue *rvalue)
1271 {
1272 gcc_assert (rvalue);
1273
1274 if (loc)
1275 set_tree_location (rvalue->as_tree (), loc);
1276
1277 add_stmt (rvalue->as_tree ());
1278 }
1279
1280 /* Add an assignment to the function's statement list. */
1281
1282 void
1283 playback::block::
1284 add_assignment (location *loc,
1285 lvalue *lvalue,
1286 rvalue *rvalue)
1287 {
1288 gcc_assert (lvalue);
1289 gcc_assert (rvalue);
1290
1291 tree t_lvalue = lvalue->as_tree ();
1292 tree t_rvalue = rvalue->as_tree ();
1293 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1294 {
1295 t_rvalue = build1 (CONVERT_EXPR,
1296 TREE_TYPE (t_lvalue),
1297 t_rvalue);
1298 if (loc)
1299 set_tree_location (t_rvalue, loc);
1300 }
1301
1302 tree stmt =
1303 build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
1304 t_lvalue, t_rvalue);
1305 if (loc)
1306 set_tree_location (stmt, loc);
1307 add_stmt (stmt);
1308 }
1309
1310 /* Add a comment to the function's statement list.
1311 For now this is done by adding a dummy label. */
1312
1313 void
1314 playback::block::
1315 add_comment (location *loc,
1316 const char *text)
1317 {
1318 /* Wrap the text in C-style comment delimiters. */
1319 size_t sz =
1320 (3 /* opening delim */
1321 + strlen (text)
1322 + 3 /* closing delim */
1323 + 1 /* terminator */);
1324 char *wrapped = (char *)ggc_internal_alloc (sz);
1325 snprintf (wrapped, sz, "/* %s */", text);
1326
1327 /* For now we simply implement this by adding a dummy label with a name
1328 containing the given text. */
1329 tree identifier = get_identifier (wrapped);
1330 tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1331 identifier, void_type_node);
1332 DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
1333
1334 tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
1335 if (loc)
1336 set_tree_location (label_expr, loc);
1337 add_stmt (label_expr);
1338 }
1339
1340 /* Add a conditional jump statement to the function's statement list. */
1341
1342 void
1343 playback::block::
1344 add_conditional (location *loc,
1345 rvalue *boolval,
1346 block *on_true,
1347 block *on_false)
1348 {
1349 gcc_assert (boolval);
1350 gcc_assert (on_true);
1351 gcc_assert (on_false);
1352
1353 /* COND_EXPR wants statement lists for the true/false operands, but we
1354 want labels.
1355 Shim it by creating jumps to the labels */
1356 tree true_jump = build1 (GOTO_EXPR, void_type_node,
1357 on_true->as_label_decl ());
1358 if (loc)
1359 set_tree_location (true_jump, loc);
1360
1361 tree false_jump = build1 (GOTO_EXPR, void_type_node,
1362 on_false->as_label_decl ());
1363 if (loc)
1364 set_tree_location (false_jump, loc);
1365
1366 tree stmt =
1367 build3 (COND_EXPR, void_type_node, boolval->as_tree (),
1368 true_jump, false_jump);
1369 if (loc)
1370 set_tree_location (stmt, loc);
1371 add_stmt (stmt);
1372 }
1373
1374 /* Add an unconditional jump statement to the function's statement list. */
1375
1376 void
1377 playback::block::
1378 add_jump (location *loc,
1379 block *target)
1380 {
1381 gcc_assert (target);
1382
1383 // see c_finish_loop
1384 //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
1385 //add_stmt (top);
1386
1387 //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
1388 TREE_USED (target->as_label_decl ()) = 1;
1389 tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
1390 if (loc)
1391 set_tree_location (stmt, loc);
1392 add_stmt (stmt);
1393
1394 /*
1395 from c-typeck.c:
1396 tree
1397 c_finish_goto_label (location_t loc, tree label)
1398 {
1399 tree decl = lookup_label_for_goto (loc, label);
1400 if (!decl)
1401 return NULL_TREE;
1402 TREE_USED (decl) = 1;
1403 {
1404 tree t = build1 (GOTO_EXPR, void_type_node, decl);
1405 SET_EXPR_LOCATION (t, loc);
1406 return add_stmt (t);
1407 }
1408 }
1409 */
1410
1411 }
1412
1413 /* Add a return statement to the function's statement list. */
1414
1415 void
1416 playback::block::
1417 add_return (location *loc,
1418 rvalue *rvalue)
1419 {
1420 tree modify_retval = NULL;
1421 tree return_type = m_func->get_return_type_as_tree ();
1422 if (rvalue)
1423 {
1424 tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
1425 tree t_rvalue = rvalue->as_tree ();
1426 if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
1427 t_rvalue = build1 (CONVERT_EXPR,
1428 TREE_TYPE (t_lvalue),
1429 t_rvalue);
1430 modify_retval = build2 (MODIFY_EXPR, return_type,
1431 t_lvalue, t_rvalue);
1432 if (loc)
1433 set_tree_location (modify_retval, loc);
1434 }
1435 tree return_stmt = build1 (RETURN_EXPR, return_type,
1436 modify_retval);
1437 if (loc)
1438 set_tree_location (return_stmt, loc);
1439
1440 add_stmt (return_stmt);
1441 }
1442
1443 /* Constructor for gcc::jit::playback::block. */
1444
1445 playback::block::
1446 block (function *func,
1447 const char *name)
1448 : m_func (func),
1449 m_stmts ()
1450 {
1451 tree identifier;
1452
1453 gcc_assert (func);
1454 // name can be NULL
1455 if (name)
1456 identifier = get_identifier (name);
1457 else
1458 identifier = NULL;
1459 m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
1460 identifier, void_type_node);
1461 DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
1462 m_label_expr = NULL;
1463 }
1464
1465 /* Construct a tempdir path template suitable for use by mkdtemp
1466 e.g. "/tmp/libgccjit-XXXXXX", but respecting the rules in
1467 libiberty's choose_tempdir rather than hardcoding "/tmp/".
1468
1469 The memory is allocated using malloc and must be freed.
1470 Aborts the process if allocation fails. */
1471
1472 static char *
1473 make_tempdir_path_template ()
1474 {
1475 const char *tmpdir_buf;
1476 size_t tmpdir_len;
1477 const char *file_template_buf;
1478 size_t file_template_len;
1479 char *result;
1480
1481 /* The result of choose_tmpdir is a cached buffer within libiberty, so
1482 we must *not* free it. */
1483 tmpdir_buf = choose_tmpdir ();
1484
1485 /* choose_tmpdir aborts on malloc failure. */
1486 gcc_assert (tmpdir_buf);
1487
1488 tmpdir_len = strlen (tmpdir_buf);
1489 /* tmpdir_buf should now have a dir separator as the final byte. */
1490 gcc_assert (tmpdir_len > 0);
1491 gcc_assert (tmpdir_buf[tmpdir_len - 1] == DIR_SEPARATOR);
1492
1493 file_template_buf = "libgccjit-XXXXXX";
1494 file_template_len = strlen (file_template_buf);
1495
1496 result = XNEWVEC (char, tmpdir_len + file_template_len + 1);
1497 strcpy (result, tmpdir_buf);
1498 strcpy (result + tmpdir_len, file_template_buf);
1499
1500 return result;
1501 }
1502
1503 /* Compile a playback::context:
1504
1505 - Use the context's options to cconstruct command-line options, and
1506 call into the rest of GCC (toplev::main).
1507 - Assuming it succeeds, we have a .s file; we want a .so file.
1508 Invoke another gcc to convert the .s file to a .so file.
1509 - dlopen the .so file
1510 - Wrap the result up as a playback::result and return it. */
1511
1512 result *
1513 playback::context::
1514 compile ()
1515 {
1516 void *handle = NULL;
1517 const char *ctxt_progname;
1518 result *result_obj = NULL;
1519 const char *fake_args[20];
1520 unsigned int num_args;
1521
1522 m_path_template = make_tempdir_path_template ();
1523 if (!m_path_template)
1524 return NULL;
1525
1526 /* Create tempdir using mkdtemp. This is created with 0700 perms and
1527 is unique. Hence no other (non-root) users should have access to
1528 the paths within it. */
1529 m_path_tempdir = mkdtemp (m_path_template);
1530 if (!m_path_tempdir)
1531 return NULL;
1532 m_path_c_file = concat (m_path_tempdir, "/fake.c", NULL);
1533 m_path_s_file = concat (m_path_tempdir, "/fake.s", NULL);
1534 m_path_so_file = concat (m_path_tempdir, "/fake.so", NULL);
1535
1536 /* Call into the rest of gcc.
1537 For now, we have to assemble command-line options to pass into
1538 toplev::main, so that they can be parsed. */
1539
1540 /* Pass in user-provided program name as argv0, if any, so that it
1541 makes it into GCC's "progname" global, used in various diagnostics. */
1542 ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
1543 fake_args[0] =
1544 (ctxt_progname ? ctxt_progname : "libgccjit.so");
1545
1546 fake_args[1] = m_path_c_file;
1547 num_args = 2;
1548
1549 #define ADD_ARG(arg) \
1550 do \
1551 { \
1552 gcc_assert(num_args < sizeof(fake_args)/sizeof(char*)); \
1553 fake_args[num_args++] = arg; \
1554 } \
1555 while (0)
1556
1557 ADD_ARG ("-fPIC");
1558
1559 /* Handle int options: */
1560 switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
1561 {
1562 default:
1563 add_error (NULL,
1564 "unrecognized optimization level: %i",
1565 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
1566 return NULL;
1567
1568 case 0:
1569 ADD_ARG ("-O0");
1570 break;
1571
1572 case 1:
1573 ADD_ARG ("-O1");
1574 break;
1575
1576 case 2:
1577 ADD_ARG ("-O2");
1578 break;
1579
1580 case 3:
1581 ADD_ARG ("-O3");
1582 break;
1583 }
1584 /* What about -Os? */
1585
1586 /* Handle bool options: */
1587 if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
1588 ADD_ARG ("-g");
1589
1590 /* Suppress timing (and other) info. */
1591 if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
1592 {
1593 ADD_ARG ("-quiet");
1594 quiet_flag = 1;
1595 }
1596
1597 /* Aggressively garbage-collect, to shake out bugs: */
1598 if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
1599 {
1600 ADD_ARG ("--param");
1601 ADD_ARG ("ggc-min-expand=0");
1602 ADD_ARG ("--param");
1603 ADD_ARG ("ggc-min-heapsize=0");
1604 }
1605
1606 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
1607 {
1608 ADD_ARG ("-fdump-tree-all");
1609 ADD_ARG ("-fdump-rtl-all");
1610 ADD_ARG ("-fdump-ipa-all");
1611 }
1612
1613 toplev toplev (false);
1614
1615 toplev.main (num_args, const_cast <char **> (fake_args));
1616 toplev.finalize ();
1617
1618 active_playback_ctxt = NULL;
1619
1620 if (errors_occurred ())
1621 return NULL;
1622
1623 if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
1624 dump_generated_code ();
1625
1626 /* Gross hacks follow:
1627 We have a .s file; we want a .so file.
1628 We could reuse parts of gcc/gcc.c to do this.
1629 For now, just use the driver binary from the install, as
1630 named in gcc-driver-name.h
1631 e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0".
1632 */
1633 {
1634 auto_timevar assemble_timevar (TV_ASSEMBLE);
1635 const char *errmsg;
1636 const char *argv[7];
1637 int exit_status = 0;
1638 int err = 0;
1639 const char *gcc_driver_name = GCC_DRIVER_NAME;
1640
1641 argv[0] = gcc_driver_name;
1642 argv[1] = "-shared";
1643 /* The input: assembler. */
1644 argv[2] = m_path_s_file;
1645 /* The output: shared library. */
1646 argv[3] = "-o";
1647 argv[4] = m_path_so_file;
1648
1649 /* Don't use the linker plugin.
1650 If running with just a "make" and not a "make install", then we'd
1651 run into
1652 "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
1653 libto_plugin is a .la at build time, with it becoming installed with
1654 ".so" suffix: i.e. it doesn't exist with a .so suffix until install
1655 time. */
1656 argv[5] = "-fno-use-linker-plugin";
1657
1658 /* pex argv arrays are NULL-terminated. */
1659 argv[6] = NULL;
1660
1661 errmsg = pex_one (PEX_SEARCH, /* int flags, */
1662 gcc_driver_name,
1663 const_cast<char * const *> (argv),
1664 ctxt_progname, /* const char *pname */
1665 NULL, /* const char *outname */
1666 NULL, /* const char *errname */
1667 &exit_status, /* int *status */
1668 &err); /* int *err*/
1669 if (errmsg)
1670 {
1671 add_error (NULL, "error invoking gcc driver: %s", errmsg);
1672 return NULL;
1673 }
1674
1675 /* pex_one can return a NULL errmsg when the executable wasn't
1676 found (or doesn't exist), so trap these cases also. */
1677 if (exit_status || err)
1678 {
1679 add_error (NULL,
1680 "error invoking gcc driver: exit_status: %i err: %i",
1681 exit_status, err);
1682 add_error (NULL,
1683 "whilst attempting to run a driver named: %s",
1684 gcc_driver_name);
1685 add_error (NULL,
1686 "PATH was: %s",
1687 getenv ("PATH"));
1688 return NULL;
1689 }
1690 }
1691
1692 // TODO: split out assembles vs linker
1693
1694 /* dlopen the .so file. */
1695 {
1696 auto_timevar load_timevar (TV_LOAD);
1697
1698 const char *error;
1699
1700 /* Clear any existing error. */
1701 dlerror ();
1702
1703 handle = dlopen (m_path_so_file, RTLD_NOW | RTLD_LOCAL);
1704 if ((error = dlerror()) != NULL) {
1705 add_error (NULL, "%s", error);
1706 }
1707 if (handle)
1708 result_obj = new result (handle);
1709 else
1710 result_obj = NULL;
1711 }
1712
1713 return result_obj;
1714 }
1715
1716 /* Top-level hook for playing back a recording context.
1717
1718 This plays back m_recording_ctxt, and, if no errors
1719 occurred builds statement lists for and then postprocesses
1720 every function in the result. */
1721
1722 void
1723 playback::context::
1724 replay ()
1725 {
1726 /* Adapted from c-common.c:c_common_nodes_and_builtins. */
1727 tree array_domain_type = build_index_type (size_int (200));
1728 m_char_array_type_node
1729 = build_array_type (char_type_node, array_domain_type);
1730
1731 m_const_char_ptr
1732 = build_pointer_type (build_qualified_type (char_type_node,
1733 TYPE_QUAL_CONST));
1734
1735 /* Replay the recorded events: */
1736 timevar_push (TV_JIT_REPLAY);
1737
1738 m_recording_ctxt->replay_into (this);
1739
1740 /* Clean away the temporary references from recording objects
1741 to playback objects. We have to do this now since the
1742 latter are GC-allocated, but the former don't mark these
1743 refs. Hence we must stop using them before the GC can run. */
1744 m_recording_ctxt->disassociate_from_playback ();
1745
1746 timevar_pop (TV_JIT_REPLAY);
1747
1748 if (!errors_occurred ())
1749 {
1750 int i;
1751 function *func;
1752
1753 /* No GC can happen yet; process the cached source locations. */
1754 handle_locations ();
1755
1756 /* We've now created tree nodes for the stmts in the various blocks
1757 in each function, but we haven't built each function's single stmt
1758 list yet. Do so now. */
1759 FOR_EACH_VEC_ELT (m_functions, i, func)
1760 func->build_stmt_list ();
1761
1762 /* No GC can have happened yet. */
1763
1764 /* Postprocess the functions. This could trigger GC. */
1765 FOR_EACH_VEC_ELT (m_functions, i, func)
1766 {
1767 gcc_assert (func);
1768 func->postprocess ();
1769 }
1770 }
1771 }
1772
1773 /* Dump the generated .s file to stderr. */
1774
1775 void
1776 playback::context::
1777 dump_generated_code ()
1778 {
1779 char buf[4096];
1780 size_t sz;
1781 FILE *f_in = fopen (m_path_s_file, "r");
1782 if (!f_in)
1783 return;
1784
1785 while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
1786 fwrite (buf, 1, sz, stderr);
1787
1788 fclose (f_in);
1789 }
1790
1791 /* qsort comparator for comparing pairs of playback::source_line *,
1792 ordering them by line number. */
1793
1794 static int
1795 line_comparator (const void *lhs, const void *rhs)
1796 {
1797 const playback::source_line *line_lhs = \
1798 *static_cast<const playback::source_line * const*> (lhs);
1799 const playback::source_line *line_rhs = \
1800 *static_cast<const playback::source_line * const*> (rhs);
1801 return line_lhs->get_line_num () - line_rhs->get_line_num ();
1802 }
1803
1804 /* qsort comparator for comparing pairs of playback::location *,
1805 ordering them by column number. */
1806
1807 static int
1808 location_comparator (const void *lhs, const void *rhs)
1809 {
1810 const playback::location *loc_lhs = \
1811 *static_cast<const playback::location * const *> (lhs);
1812 const playback::location *loc_rhs = \
1813 *static_cast<const playback::location * const *> (rhs);
1814 return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
1815 }
1816
1817 /* Our API allows locations to be created in arbitrary orders, but the
1818 linemap API requires locations to be created in ascending order
1819 as if we were tokenizing files.
1820
1821 This hook sorts all of the the locations that have been created, and
1822 calls into the linemap API, creating linemap entries in sorted order
1823 for our locations. */
1824
1825 void
1826 playback::context::
1827 handle_locations ()
1828 {
1829 /* Create the source code locations, following the ordering rules
1830 imposed by the linemap API.
1831
1832 line_table is a global. */
1833 int i;
1834 source_file *file;
1835
1836 FOR_EACH_VEC_ELT (m_source_files, i, file)
1837 {
1838 linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
1839
1840 /* Sort lines by ascending line numbers. */
1841 file->m_source_lines.qsort (&line_comparator);
1842
1843 int j;
1844 source_line *line;
1845 FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
1846 {
1847 int k;
1848 location *loc;
1849
1850 /* Sort locations in line by ascending column numbers. */
1851 line->m_locations.qsort (&location_comparator);
1852
1853 /* Determine maximum column within this line. */
1854 gcc_assert (line->m_locations.length () > 0);
1855 location *final_column =
1856 line->m_locations[line->m_locations.length () - 1];
1857 int max_col = final_column->get_column_num ();
1858
1859 linemap_line_start (line_table, line->get_line_num (), max_col);
1860 FOR_EACH_VEC_ELT (line->m_locations, k, loc)
1861 {
1862 loc->m_srcloc = \
1863 linemap_position_for_column (line_table, loc->get_column_num ());
1864 }
1865 }
1866
1867 linemap_add (line_table, LC_LEAVE, false, NULL, 0);
1868 }
1869
1870 /* line_table should now be populated; every playback::location should
1871 now have an m_srcloc. */
1872
1873 /* Now assign them to tree nodes as appropriate. */
1874 std::pair<tree, location *> *cached_location;
1875
1876 FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
1877 {
1878 tree t = cached_location->first;
1879 source_location srcloc = cached_location->second->m_srcloc;
1880
1881 /* This covers expressions: */
1882 if (CAN_HAVE_LOCATION_P (t))
1883 SET_EXPR_LOCATION (t, srcloc);
1884 else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
1885 DECL_SOURCE_LOCATION (t) = srcloc;
1886 else
1887 {
1888 /* Don't know how to set location on this node. */
1889 }
1890 }
1891 }
1892
1893 /* We handle errors on a playback::context by adding them to the
1894 corresponding recording::context. */
1895
1896 void
1897 playback::context::
1898 add_error (location *loc, const char *fmt, ...)
1899 {
1900 va_list ap;
1901 va_start (ap, fmt);
1902 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
1903 fmt, ap);
1904 va_end (ap);
1905 }
1906
1907 /* We handle errors on a playback::context by adding them to the
1908 corresponding recording::context. */
1909
1910 void
1911 playback::context::
1912 add_error_va (location *loc, const char *fmt, va_list ap)
1913 {
1914 m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
1915 fmt, ap);
1916 }
1917
1918 /* Constructor for gcc::jit::playback::result. */
1919
1920 result::
1921 result(void *dso_handle)
1922 : m_dso_handle(dso_handle)
1923 {
1924 }
1925
1926 /* gcc::jit::playback::result's destructor.
1927
1928 Called implicitly by gcc_jit_result_release. */
1929
1930 result::~result()
1931 {
1932 dlclose (m_dso_handle);
1933 }
1934
1935 /* Attempt to locate the given function by name within the
1936 playback::result, using dlsym.
1937
1938 Implements the post-error-checking part of
1939 gcc_jit_result_get_code. */
1940
1941 void *
1942 result::
1943 get_code (const char *funcname)
1944 {
1945 void *code;
1946 const char *error;
1947
1948 /* Clear any existing error. */
1949 dlerror ();
1950
1951 code = dlsym (m_dso_handle, funcname);
1952
1953 if ((error = dlerror()) != NULL) {
1954 fprintf(stderr, "%s\n", error);
1955 }
1956
1957 return code;
1958 }
1959
1960 /* Dealing with the linemap API. */
1961
1962 /* Construct a playback::location for a recording::location, if it
1963 doesn't exist already. */
1964
1965 playback::location *
1966 playback::context::
1967 new_location (recording::location *rloc,
1968 const char *filename,
1969 int line,
1970 int column)
1971 {
1972 /* Get the source_file for filename, creating if necessary. */
1973 source_file *src_file = get_source_file (filename);
1974 /* Likewise for the line within the file. */
1975 source_line *src_line = src_file->get_source_line (line);
1976 /* Likewise for the column within the line. */
1977 location *loc = src_line->get_location (rloc, column);
1978 return loc;
1979 }
1980
1981 /* Deferred setting of the location for a given tree, by adding the
1982 (tree, playback::location) pair to a list of deferred associations.
1983 We will actually set the location on the tree later on once
1984 the source_location for the playback::location exists. */
1985
1986 void
1987 playback::context::
1988 set_tree_location (tree t, location *loc)
1989 {
1990 gcc_assert (loc);
1991 m_cached_locations.safe_push (std::make_pair (t, loc));
1992 }
1993
1994
1995 /* Construct a playback::source_file for the given source
1996 filename, if it doesn't exist already. */
1997
1998 playback::source_file *
1999 playback::context::
2000 get_source_file (const char *filename)
2001 {
2002 /* Locate the file.
2003 For simplicitly, this is currently a linear search.
2004 Replace with a hash if this shows up in the profile. */
2005 int i;
2006 source_file *file;
2007 tree ident_filename = get_identifier (filename);
2008
2009 FOR_EACH_VEC_ELT (m_source_files, i, file)
2010 if (file->filename_as_tree () == ident_filename)
2011 return file;
2012
2013 /* Not found. */
2014 file = new source_file (ident_filename);
2015 m_source_files.safe_push (file);
2016 return file;
2017 }
2018
2019 /* Constructor for gcc::jit::playback::source_file. */
2020
2021 playback::source_file::source_file (tree filename) :
2022 m_source_lines (),
2023 m_filename (filename)
2024 {
2025 }
2026
2027 /* Construct a playback::source_line for the given line
2028 within this source file, if one doesn't exist already. */
2029
2030 playback::source_line *
2031 playback::source_file::
2032 get_source_line (int line_num)
2033 {
2034 /* Locate the line.
2035 For simplicitly, this is currently a linear search.
2036 Replace with a hash if this shows up in the profile. */
2037 int i;
2038 source_line *line;
2039
2040 FOR_EACH_VEC_ELT (m_source_lines, i, line)
2041 if (line->get_line_num () == line_num)
2042 return line;
2043
2044 /* Not found. */
2045 line = new source_line (this, line_num);
2046 m_source_lines.safe_push (line);
2047 return line;
2048 }
2049
2050 /* Constructor for gcc::jit::playback::source_line. */
2051
2052 playback::source_line::source_line (source_file *file, int line_num) :
2053 m_locations (),
2054 m_source_file (file),
2055 m_line_num (line_num)
2056 {
2057 }
2058
2059 /* Construct a playback::location for the given column
2060 within this line of a specific source file, if one doesn't exist
2061 already. */
2062
2063 playback::location *
2064 playback::source_line::
2065 get_location (recording::location *rloc, int column_num)
2066 {
2067 int i;
2068 location *loc;
2069
2070 /* Another linear search that probably should be a hash table. */
2071 FOR_EACH_VEC_ELT (m_locations, i, loc)
2072 if (loc->get_column_num () == column_num)
2073 return loc;
2074
2075 /* Not found. */
2076 loc = new location (rloc, this, column_num);
2077 m_locations.safe_push (loc);
2078 return loc;
2079 }
2080
2081 /* Constructor for gcc::jit::playback::location. */
2082
2083 playback::location::location (recording::location *loc,
2084 source_line *line,
2085 int column_num) :
2086 m_srcloc (UNKNOWN_LOCATION),
2087 m_recording_loc (loc),
2088 m_line (line),
2089 m_column_num(column_num)
2090 {
2091 }
2092
2093 /* The active gcc::jit::playback::context instance. This is a singleton,
2094 guarded by jit_mutex. */
2095
2096 playback::context *active_playback_ctxt;
2097
2098 } // namespace gcc::jit
2099
2100 } // namespace gcc