Line data Source code
1 : /* Internals of libgccjit: classes for playing back recorded API calls.
2 : Copyright (C) 2013-2026 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 : #define INCLUDE_MUTEX
23 : #define INCLUDE_DLFCN_H
24 : #include "libgccjit.h"
25 : #include "system.h"
26 : #include "coretypes.h"
27 : #include "target.h"
28 : #include "tree.h"
29 : #include "stringpool.h"
30 : #include "cgraph.h"
31 : #include "dumpfile.h"
32 : #include "toplev.h"
33 : #include "tree-cfg.h"
34 : #include "convert.h"
35 : #include "gimple-expr.h"
36 : #include "stor-layout.h"
37 : #include "print-tree.h"
38 : #include "gimplify.h"
39 : #include "gcc-driver-name.h"
40 : #include "attribs.h"
41 : #include "context.h"
42 : #include "fold-const.h"
43 : #include "opt-suggestions.h"
44 : #include "gcc.h"
45 : #include "diagnostic.h"
46 : #include "stmt.h"
47 : #include "realmpfr.h"
48 :
49 : #include "jit-playback.h"
50 : #include "jit-result.h"
51 : #include "jit-builtins.h"
52 : #include "jit-tempdir.h"
53 : #include "jit-target.h"
54 :
55 : #ifdef _WIN32
56 : #include "jit-w32.h"
57 : #endif
58 :
59 : /* Compare with gcc/c-family/c-common.h: DECL_C_BIT_FIELD,
60 : SET_DECL_C_BIT_FIELD.
61 : These are redefined here to avoid depending from the C frontend. */
62 : #define DECL_JIT_BIT_FIELD(NODE) \
63 : (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1)
64 : #define SET_DECL_JIT_BIT_FIELD(NODE) \
65 : (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1)
66 :
67 : /* gcc::jit::playback::context::build_cast uses the convert.h API,
68 : which in turn requires the frontend to provide a "convert"
69 : function, apparently as a fallback for casts that can be simplified
70 : (truncation, extension). */
71 : extern tree convert (tree type, tree expr);
72 :
73 : tree
74 15 : convert (tree dst_type, tree expr)
75 : {
76 15 : tree t_ret = NULL;
77 15 : t_ret = targetm.convert_to_type (dst_type, expr);
78 15 : if (t_ret)
79 : return t_ret;
80 15 : switch (TREE_CODE (dst_type))
81 : {
82 15 : case INTEGER_TYPE:
83 15 : case ENUMERAL_TYPE:
84 15 : return fold (convert_to_integer (dst_type, expr));
85 :
86 0 : default:
87 0 : gcc_assert (gcc::jit::active_playback_ctxt);
88 0 : gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
89 0 : fprintf (stderr, "input expression:\n");
90 0 : debug_tree (expr);
91 0 : fprintf (stderr, "requested type:\n");
92 0 : debug_tree (dst_type);
93 0 : return error_mark_node;
94 : }
95 : }
96 :
97 : namespace gcc {
98 : namespace jit {
99 :
100 : /**********************************************************************
101 : Playback.
102 : **********************************************************************/
103 :
104 : /* Fold a readonly non-volatile variable with an initial constant value,
105 : to that value.
106 :
107 : Otherwise return the argument unchanged.
108 :
109 : This fold is needed for setting a variable's DECL_INITIAL to the value
110 : of a const variable. The c-frontend does this in its own special
111 : fold (), so we lift this part out and do it explicitly where there is a
112 : potential for variables to be used as rvalues. */
113 : static tree
114 13011 : fold_const_var (tree node)
115 : {
116 : /* See c_fully_fold_internal in c-fold.cc and decl_constant_value_1
117 : in c-typeck.cc. */
118 13011 : if (VAR_P (node)
119 4428 : && TREE_READONLY (node)
120 50 : && !TREE_THIS_VOLATILE (node)
121 50 : && DECL_INITIAL (node) != NULL_TREE
122 : /* "This is invalid if initial value is not constant.
123 : If it has either a function call, a memory reference,
124 : or a variable, then re-evaluating it could give different
125 : results." */
126 13056 : && TREE_CONSTANT (DECL_INITIAL (node)))
127 : {
128 45 : tree ret = DECL_INITIAL (node);
129 : /* "Avoid unwanted tree sharing between the initializer and current
130 : function's body where the tree can be modified e.g. by the
131 : gimplifier." */
132 45 : if (TREE_STATIC (node))
133 45 : ret = unshare_expr (ret);
134 :
135 45 : return ret;
136 : }
137 :
138 : return node;
139 : }
140 :
141 : /* Build a STRING_CST tree for STR, or return NULL if it is NULL.
142 : The TREE_TYPE is not initialized. */
143 :
144 : static tree
145 350 : build_string (const char *str)
146 : {
147 350 : if (str)
148 270 : return ::build_string (strlen (str), str);
149 : else
150 : return NULL_TREE;
151 : }
152 :
153 : /* The constructor for gcc::jit::playback::context. */
154 :
155 1331 : playback::context::context (recording::context *ctxt)
156 : : log_user (ctxt->get_logger ()),
157 1331 : m_recording_ctxt (ctxt),
158 1331 : m_tempdir (NULL),
159 1331 : m_const_char_ptr (NULL)
160 : {
161 1331 : JIT_LOG_SCOPE (get_logger ());
162 1331 : m_functions.create (0);
163 1331 : m_globals.create (0);
164 1331 : m_source_files.create (0);
165 1331 : m_cached_locations.create (0);
166 1331 : }
167 :
168 : /* The destructor for gcc::jit::playback::context. */
169 :
170 1331 : playback::context::~context ()
171 : {
172 1331 : JIT_LOG_SCOPE (get_logger ());
173 :
174 : /* Normally the playback::context is responsible for cleaning up the
175 : tempdir (including "fake.so" within the filesystem).
176 :
177 : In the normal case, clean it up now.
178 :
179 : However m_tempdir can be NULL if the context has handed over
180 : responsibility for the tempdir cleanup to the jit::result object, so
181 : that the cleanup can be delayed (see PR jit/64206). If that's the
182 : case this "delete NULL;" is a no-op. */
183 1331 : delete m_tempdir;
184 :
185 1331 : m_functions.release ();
186 1331 : }
187 :
188 : /* A playback::context can reference GC-managed pointers. Mark them
189 : ("by hand", rather than by gengtype).
190 :
191 : This is called on the active playback context (if any) by the
192 : my_ggc_walker hook in the jit_root_table in dummy-frontend.cc. */
193 :
194 : void
195 514851 : playback::context::
196 : gt_ggc_mx ()
197 : {
198 514851 : int i;
199 514851 : function *func;
200 36823970 : FOR_EACH_VEC_ELT (m_functions, i, func)
201 : {
202 36309119 : if (ggc_test_and_set_mark (func))
203 36309119 : func->gt_ggc_mx ();
204 : }
205 514851 : }
206 :
207 : /* Given an enum gcc_jit_types value, get a "tree" type. */
208 :
209 : tree
210 8289 : playback::context::
211 : get_tree_node_for_type (enum gcc_jit_types type_)
212 : {
213 8289 : switch (type_)
214 : {
215 1291 : case GCC_JIT_TYPE_VOID:
216 1291 : return void_type_node;
217 :
218 70 : case GCC_JIT_TYPE_VOID_PTR:
219 70 : return ptr_type_node;
220 :
221 662 : case GCC_JIT_TYPE_BOOL:
222 662 : return boolean_type_node;
223 :
224 141 : case GCC_JIT_TYPE_CHAR:
225 141 : return char_type_node;
226 30 : case GCC_JIT_TYPE_SIGNED_CHAR:
227 30 : return signed_char_type_node;
228 41 : case GCC_JIT_TYPE_UNSIGNED_CHAR:
229 41 : return unsigned_char_type_node;
230 :
231 40 : case GCC_JIT_TYPE_SHORT:
232 40 : return short_integer_type_node;
233 25 : case GCC_JIT_TYPE_UNSIGNED_SHORT:
234 25 : return short_unsigned_type_node;
235 :
236 117 : case GCC_JIT_TYPE_CONST_CHAR_PTR:
237 117 : return m_const_char_ptr;
238 :
239 1321 : case GCC_JIT_TYPE_INT:
240 1321 : return integer_type_node;
241 1291 : case GCC_JIT_TYPE_UNSIGNED_INT:
242 1291 : return unsigned_type_node;
243 :
244 15 : case GCC_JIT_TYPE_UINT8_T:
245 15 : return unsigned_intQI_type_node;
246 15 : case GCC_JIT_TYPE_UINT16_T:
247 15 : return uint16_type_node;
248 15 : case GCC_JIT_TYPE_UINT32_T:
249 15 : return uint32_type_node;
250 15 : case GCC_JIT_TYPE_UINT64_T:
251 15 : return uint64_type_node;
252 15 : case GCC_JIT_TYPE_UINT128_T:
253 15 : if (targetm.scalar_mode_supported_p (TImode))
254 15 : return uint128_type_node;
255 :
256 0 : add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
257 : type_);
258 0 : return NULL;
259 :
260 15 : case GCC_JIT_TYPE_INT8_T:
261 15 : return intQI_type_node;
262 15 : case GCC_JIT_TYPE_INT16_T:
263 15 : return intHI_type_node;
264 15 : case GCC_JIT_TYPE_INT32_T:
265 15 : return intSI_type_node;
266 15 : case GCC_JIT_TYPE_INT64_T:
267 15 : return intDI_type_node;
268 15 : case GCC_JIT_TYPE_INT128_T:
269 15 : if (targetm.scalar_mode_supported_p (TImode))
270 15 : return intTI_type_node;
271 :
272 0 : add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
273 : type_);
274 0 : return NULL;
275 :
276 78 : case GCC_JIT_TYPE_LONG:
277 78 : return long_integer_type_node;
278 1291 : case GCC_JIT_TYPE_UNSIGNED_LONG:
279 1291 : return long_unsigned_type_node;
280 :
281 28 : case GCC_JIT_TYPE_LONG_LONG:
282 28 : return long_long_integer_type_node;
283 1291 : case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
284 1291 : return long_long_unsigned_type_node;
285 :
286 105 : case GCC_JIT_TYPE_FLOAT:
287 105 : return float_type_node;
288 5 : case GCC_JIT_TYPE_BFLOAT16:
289 : #ifndef HAVE_BFmode
290 : add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
291 : type_);
292 : #endif
293 5 : return bfloat16_type_node;
294 132 : case GCC_JIT_TYPE_DOUBLE:
295 132 : return double_type_node;
296 15 : case GCC_JIT_TYPE_LONG_DOUBLE:
297 15 : return long_double_type_node;
298 15 : case GCC_JIT_TYPE_FLOAT16:
299 15 : if (float16_type_node == NULL || TYPE_PRECISION (float16_type_node) != 16)
300 : {
301 0 : add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
302 : type_);
303 0 : return NULL;
304 : }
305 : return float16_type_node;
306 15 : case GCC_JIT_TYPE_FLOAT32:
307 15 : if (float32_type_node == NULL || TYPE_PRECISION (float32_type_node) != 32)
308 : {
309 0 : add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
310 : type_);
311 0 : return NULL;
312 : }
313 : return float32_type_node;
314 15 : case GCC_JIT_TYPE_FLOAT64:
315 15 : if (float64_type_node == NULL || TYPE_PRECISION (float64_type_node) != 64)
316 : {
317 0 : add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
318 : type_);
319 0 : return NULL;
320 : }
321 : return float64_type_node;
322 15 : case GCC_JIT_TYPE_FLOAT128:
323 15 : if (float128_type_node == NULL
324 15 : || TYPE_PRECISION (float128_type_node) != 128)
325 : {
326 0 : add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
327 : type_);
328 0 : return NULL;
329 : }
330 : return float128_type_node;
331 :
332 75 : case GCC_JIT_TYPE_SIZE_T:
333 75 : return size_type_node;
334 :
335 15 : case GCC_JIT_TYPE_FILE_PTR:
336 15 : return fileptr_type_node;
337 :
338 0 : case GCC_JIT_TYPE_COMPLEX_FLOAT:
339 0 : return complex_float_type_node;
340 15 : case GCC_JIT_TYPE_COMPLEX_DOUBLE:
341 15 : return complex_double_type_node;
342 0 : case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
343 0 : return complex_long_double_type_node;
344 : }
345 :
346 0 : add_error (NULL, "unrecognized (enum gcc_jit_types) value: %i",
347 : type_);
348 :
349 0 : return NULL;
350 : }
351 :
352 : /* Construct a playback::type instance (wrapping a tree) for the given
353 : enum value. */
354 :
355 : playback::type *
356 8289 : playback::context::
357 : get_type (enum gcc_jit_types type_)
358 : {
359 8289 : tree type_node = get_tree_node_for_type (type_);
360 8289 : if (type_node == NULL)
361 : return NULL;
362 :
363 8289 : return new type (type_node);
364 : }
365 :
366 : void
367 5 : playback::context::
368 : set_output_ident (const char* ident)
369 : {
370 5 : targetm.asm_out.output_ident (ident);
371 5 : }
372 :
373 : /* Construct a playback::type instance (wrapping a tree) for the given
374 : array type. */
375 :
376 : playback::type *
377 330 : playback::context::
378 : new_array_type (playback::location *loc,
379 : playback::type *element_type,
380 : uint64_t num_elements)
381 : {
382 330 : gcc_assert (element_type);
383 :
384 330 : tree t = build_array_type_nelts (element_type->as_tree (),
385 330 : num_elements);
386 330 : layout_type (t);
387 :
388 330 : if (loc)
389 0 : set_tree_location (t, loc);
390 :
391 330 : return new type (t);
392 : }
393 :
394 : /* Construct a playback::field instance (wrapping a tree). */
395 :
396 : playback::field *
397 1718 : playback::context::
398 : new_field (location *loc,
399 : type *type,
400 : const char *name)
401 : {
402 1718 : gcc_assert (type);
403 1718 : gcc_assert (name);
404 :
405 : /* compare with c/c-decl.cc:grokfield and grokdeclarator. */
406 1718 : tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
407 : get_identifier (name), type->as_tree ());
408 :
409 1718 : if (loc)
410 0 : set_tree_location (decl, loc);
411 :
412 1718 : return new field (decl);
413 : }
414 :
415 : /* Construct a playback::bitfield instance (wrapping a tree). */
416 :
417 : playback::field *
418 95 : playback::context::
419 : new_bitfield (location *loc,
420 : type *type,
421 : int width,
422 : const char *name)
423 : {
424 95 : gcc_assert (type);
425 95 : gcc_assert (name);
426 95 : gcc_assert (width);
427 :
428 : /* compare with c/c-decl.cc:grokfield, grokdeclarator and
429 : check_bitfield_type_and_width. */
430 :
431 95 : tree tree_type = type->as_tree ();
432 95 : gcc_assert (INTEGRAL_TYPE_P (tree_type));
433 95 : tree tree_width = build_int_cst (integer_type_node, width);
434 95 : if (compare_tree_int (tree_width, TYPE_PRECISION (tree_type)) > 0)
435 : {
436 10 : add_error (
437 : loc,
438 : "width of bit-field %s (width: %i) is wider than its type (width: %i)",
439 5 : name, width, TYPE_PRECISION (tree_type));
440 5 : return NULL;
441 : }
442 :
443 90 : tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
444 : get_identifier (name), type->as_tree ());
445 90 : DECL_NONADDRESSABLE_P (decl) = true;
446 90 : DECL_INITIAL (decl) = tree_width;
447 90 : SET_DECL_JIT_BIT_FIELD (decl);
448 :
449 90 : if (loc)
450 0 : set_tree_location (decl, loc);
451 :
452 90 : return new field (decl);
453 : }
454 :
455 : /* Construct a playback::compound_type instance (wrapping a tree). */
456 :
457 : playback::compound_type *
458 602 : playback::context::
459 : new_compound_type (location *loc,
460 : const char *name,
461 : bool is_struct) /* else is union */
462 : {
463 602 : gcc_assert (name);
464 :
465 : /* Compare with c/c-decl.cc: start_struct. */
466 :
467 677 : tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
468 602 : TYPE_NAME (t) = get_identifier (name);
469 602 : TYPE_SIZE (t) = 0;
470 :
471 602 : if (loc)
472 0 : set_tree_location (t, loc);
473 :
474 602 : return new compound_type (t);
475 : }
476 :
477 : void
478 572 : playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
479 : {
480 : /* Compare with c/c-decl.cc: finish_struct. */
481 572 : tree t = as_tree ();
482 :
483 572 : tree fieldlist = NULL;
484 2375 : for (unsigned i = 0; i < fields->length (); i++)
485 : {
486 1803 : field *f = (*fields)[i];
487 1803 : tree x = f->as_tree ();
488 1803 : DECL_CONTEXT (x) = t;
489 1803 : if (DECL_JIT_BIT_FIELD (x))
490 : {
491 85 : unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (x));
492 85 : DECL_SIZE (x) = bitsize_int (width);
493 85 : DECL_BIT_FIELD (x) = 1;
494 : }
495 1803 : fieldlist = chainon (x, fieldlist);
496 : }
497 572 : fieldlist = nreverse (fieldlist);
498 572 : TYPE_FIELDS (t) = fieldlist;
499 :
500 572 : layout_type (t);
501 572 : }
502 :
503 : /* Construct a playback::type instance (wrapping a tree) for a function
504 : type. */
505 :
506 : playback::type *
507 5379 : playback::context::
508 : new_function_type (type *return_type,
509 : const auto_vec<type *> *param_types,
510 : int is_variadic)
511 : {
512 5379 : int i;
513 5379 : type *param_type;
514 :
515 5379 : tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
516 :
517 15076 : FOR_EACH_VEC_ELT (*param_types, i, param_type)
518 4318 : arg_types[i] = param_type->as_tree ();
519 :
520 5379 : tree fn_type;
521 5379 : if (is_variadic)
522 15 : fn_type =
523 15 : build_varargs_function_type_array (return_type->as_tree (),
524 15 : param_types->length (),
525 : arg_types);
526 : else
527 10728 : fn_type = build_function_type_array (return_type->as_tree (),
528 9437 : param_types->length (),
529 : arg_types);
530 5379 : free (arg_types);
531 :
532 5379 : return new type (fn_type);
533 : }
534 :
535 : /* Construct a playback::param instance (wrapping a tree). */
536 :
537 : playback::param *
538 16518 : playback::context::
539 : new_param (location *loc,
540 : type *type,
541 : const char *name)
542 : {
543 16518 : gcc_assert (type);
544 16518 : gcc_assert (name);
545 16518 : tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
546 : get_identifier (name), type->as_tree ());
547 16518 : if (loc)
548 29 : set_tree_location (inner, loc);
549 :
550 16518 : return new param (this, inner);
551 : }
552 :
553 55 : const char* fn_attribute_to_string (gcc_jit_fn_attribute attr)
554 : {
555 55 : switch (attr)
556 : {
557 : case GCC_JIT_FN_ATTRIBUTE_ALIAS:
558 : return "alias";
559 5 : case GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE:
560 5 : return "always_inline";
561 : case GCC_JIT_FN_ATTRIBUTE_INLINE:
562 : return NULL;
563 5 : case GCC_JIT_FN_ATTRIBUTE_NOINLINE:
564 5 : return "noinline";
565 0 : case GCC_JIT_FN_ATTRIBUTE_TARGET:
566 0 : return "target";
567 5 : case GCC_JIT_FN_ATTRIBUTE_USED:
568 5 : return "used";
569 0 : case GCC_JIT_FN_ATTRIBUTE_VISIBILITY:
570 0 : return "visibility";
571 5 : case GCC_JIT_FN_ATTRIBUTE_COLD:
572 5 : return "cold";
573 0 : case GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE:
574 0 : return "returns_twice";
575 5 : case GCC_JIT_FN_ATTRIBUTE_PURE:
576 5 : return "pure";
577 5 : case GCC_JIT_FN_ATTRIBUTE_CONST:
578 5 : return "const";
579 5 : case GCC_JIT_FN_ATTRIBUTE_WEAK:
580 5 : return "weak";
581 5 : case GCC_JIT_FN_ATTRIBUTE_NONNULL:
582 5 : return "nonnull";
583 0 : case GCC_JIT_FN_ATTRIBUTE_ARM_CMSE_NONSECURE_CALL:
584 0 : return "cmse_nonsecure_call";
585 0 : case GCC_JIT_FN_ATTRIBUTE_ARM_CMSE_NONSECURE_ENTRY:
586 0 : return "cmse_nonsecure_entry";
587 0 : case GCC_JIT_FN_ATTRIBUTE_ARM_PCS:
588 0 : return "pcs";
589 : case GCC_JIT_FN_ATTRIBUTE_AVR_INTERRUPT:
590 : return "interrupt";
591 0 : case GCC_JIT_FN_ATTRIBUTE_AVR_NOBLOCK:
592 0 : return "noblock";
593 0 : case GCC_JIT_FN_ATTRIBUTE_AVR_SIGNAL:
594 0 : return "signal";
595 0 : case GCC_JIT_FN_ATTRIBUTE_GCN_AMDGPU_HSA_KERNEL:
596 0 : return "amdgpu_hsa_kernel";
597 : case GCC_JIT_FN_ATTRIBUTE_MSP430_INTERRUPT:
598 : return "interrupt";
599 0 : case GCC_JIT_FN_ATTRIBUTE_NVPTX_KERNEL:
600 0 : return "kernel";
601 : case GCC_JIT_FN_ATTRIBUTE_RISCV_INTERRUPT:
602 : return "interrupt";
603 0 : case GCC_JIT_FN_ATTRIBUTE_X86_FAST_CALL:
604 0 : return "fastcall";
605 : case GCC_JIT_FN_ATTRIBUTE_X86_INTERRUPT:
606 : return "interrupt";
607 5 : case GCC_JIT_FN_ATTRIBUTE_X86_MS_ABI:
608 5 : return "ms_abi";
609 0 : case GCC_JIT_FN_ATTRIBUTE_X86_STDCALL:
610 0 : return "stdcall";
611 0 : case GCC_JIT_FN_ATTRIBUTE_X86_SYSV_ABI:
612 0 : return "sysv_abi";
613 0 : case GCC_JIT_FN_ATTRIBUTE_X86_THIS_CALL:
614 0 : return "thiscall";
615 : case GCC_JIT_FN_ATTRIBUTE_MAX:
616 : return NULL;
617 : }
618 : return NULL;
619 : }
620 :
621 5 : const char* variable_attribute_to_string (gcc_jit_variable_attribute attr)
622 : {
623 5 : switch (attr)
624 : {
625 : case GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY:
626 : return "visibility";
627 : case GCC_JIT_VARIABLE_ATTRIBUTE_MAX:
628 : return NULL;
629 : }
630 : return NULL;
631 : }
632 :
633 : /* Construct a playback::function instance. */
634 :
635 : playback::function *
636 16667 : playback::context::
637 : new_function (location *loc,
638 : enum gcc_jit_function_kind kind,
639 : type *return_type,
640 : const char *name,
641 : const auto_vec<param *> *params,
642 : int is_variadic,
643 : enum built_in_function builtin_id,
644 : const std::vector<gcc_jit_fn_attribute> &attributes,
645 : const std::vector<std::pair<gcc_jit_fn_attribute,
646 : std::string>> &string_attributes,
647 : const std::vector<std::pair<gcc_jit_fn_attribute,
648 : std::vector<int>>>
649 : &int_array_attributes,
650 : bool is_target_builtin)
651 : {
652 16667 : int i;
653 16667 : param *param;
654 :
655 : //can return_type be NULL?
656 16667 : gcc_assert (name);
657 :
658 16667 : tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
659 49852 : FOR_EACH_VEC_ELT (*params, i, param)
660 16518 : arg_types[i] = TREE_TYPE (param->as_tree ());
661 :
662 16667 : tree fn_type;
663 16667 : if (is_variadic)
664 204 : fn_type = build_varargs_function_type_array (return_type->as_tree (),
665 154 : params->length (), arg_types);
666 : else
667 33130 : fn_type = build_function_type_array (return_type->as_tree (),
668 30958 : params->length (), arg_types);
669 16667 : free (arg_types);
670 :
671 : /* FIXME: this uses input_location: */
672 16667 : tree fndecl = build_fn_decl (name, fn_type);
673 :
674 16667 : if (loc)
675 56 : set_tree_location (fndecl, loc);
676 :
677 16667 : tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
678 : NULL_TREE, return_type->as_tree ());
679 16667 : DECL_ARTIFICIAL (resdecl) = 1;
680 16667 : DECL_IGNORED_P (resdecl) = 1;
681 16667 : DECL_RESULT (fndecl) = resdecl;
682 16667 : DECL_CONTEXT (resdecl) = fndecl;
683 :
684 16667 : tree fn_attributes = NULL_TREE;
685 :
686 16667 : if (is_target_builtin)
687 : {
688 10 : tree *decl = target_builtins.get (name);
689 10 : if (decl != NULL)
690 10 : fndecl = *decl;
691 : else
692 0 : add_error (loc, "cannot find target builtin %s", name);
693 : }
694 :
695 16667 : if (builtin_id)
696 : {
697 13120 : gcc_assert (loc == NULL);
698 13120 : DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
699 :
700 13120 : built_in_class fclass = builtins_manager::get_class (builtin_id);
701 13120 : set_decl_built_in_function (fndecl, fclass, builtin_id);
702 13120 : set_builtin_decl (builtin_id, fndecl,
703 13120 : builtins_manager::implicit_p (builtin_id));
704 :
705 13120 : builtins_manager *bm = get_builtins_manager ();
706 13120 : tree attrs = bm->get_attrs_tree (builtin_id);
707 13120 : if (attrs)
708 13120 : decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
709 : else
710 0 : decl_attributes (&fndecl, NULL_TREE, 0);
711 : }
712 :
713 16667 : if (kind != GCC_JIT_FUNCTION_IMPORTED)
714 : {
715 : tree param_decl_list = NULL;
716 7590 : FOR_EACH_VEC_ELT (*params, i, param)
717 : {
718 4244 : param_decl_list = chainon (param->as_tree (), param_decl_list);
719 : }
720 :
721 : /* The param list was created in reverse order; fix it: */
722 3346 : param_decl_list = nreverse (param_decl_list);
723 :
724 3346 : tree t;
725 10936 : for (t = param_decl_list; t; t = DECL_CHAIN (t))
726 : {
727 4244 : DECL_CONTEXT (t) = fndecl;
728 4244 : DECL_ARG_TYPE (t) = TREE_TYPE (t);
729 : }
730 :
731 : /* Set it up on DECL_ARGUMENTS */
732 3346 : DECL_ARGUMENTS(fndecl) = param_decl_list;
733 : }
734 :
735 3346 : if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
736 : {
737 15 : DECL_DECLARED_INLINE_P (fndecl) = 1;
738 :
739 : /* Add attribute "always_inline": */
740 15 : fn_attributes = tree_cons (get_identifier ("always_inline"),
741 : NULL,
742 : fn_attributes);
743 : }
744 :
745 : /* All attributes need to be declared in `dummy-frontend.cc` and more
746 : specifically in `jit_attribute_table`. */
747 16712 : for (auto attr: attributes)
748 : {
749 45 : if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE)
750 5 : DECL_DECLARED_INLINE_P (fndecl) = 1;
751 :
752 45 : const char* attribute = fn_attribute_to_string (attr);
753 45 : if (attribute)
754 : {
755 40 : tree ident = get_identifier (attribute);
756 40 : fn_attributes = tree_cons (ident, NULL_TREE, fn_attributes);
757 : }
758 : }
759 :
760 16672 : for (auto attr: string_attributes)
761 : {
762 5 : gcc_jit_fn_attribute& name = std::get<0>(attr);
763 5 : std::string& value = std::get<1>(attr);
764 10 : tree attribute_value = build_tree_list (NULL_TREE,
765 5 : ::build_string (value.length () + 1, value.c_str ()));
766 5 : const char* attribute = fn_attribute_to_string (name);
767 5 : tree ident = attribute ? get_identifier (attribute) : NULL;
768 :
769 5 : if (ident)
770 5 : fn_attributes = tree_cons (ident, attribute_value, fn_attributes);
771 5 : }
772 :
773 16672 : for (auto attr: int_array_attributes)
774 : {
775 5 : gcc_jit_fn_attribute& name = std::get<0>(attr);
776 5 : std::vector<int>& values = std::get<1>(attr);
777 :
778 5 : const char* attribute = fn_attribute_to_string (name);
779 5 : tree ident = attribute ? get_identifier (attribute) : NULL;
780 :
781 5 : if (!ident)
782 0 : continue;
783 :
784 5 : tree tree_list = NULL_TREE;
785 5 : tree *p_tree_list = &tree_list;
786 10 : for (auto value : values)
787 : {
788 5 : tree int_value = build_int_cst (integer_type_node, value);
789 5 : *p_tree_list = build_tree_list (NULL, int_value);
790 5 : p_tree_list = &TREE_CHAIN (*p_tree_list);
791 : }
792 5 : fn_attributes = tree_cons (ident, tree_list, fn_attributes);
793 5 : }
794 :
795 16667 : decl_attributes (&fndecl, fn_attributes, 0);
796 16667 : function *func = new function (this, fndecl, kind);
797 16667 : m_functions.safe_push (func);
798 16667 : return func;
799 : }
800 :
801 : /* In use by new_global and new_global_initialized. */
802 :
803 : tree
804 1061 : playback::context::
805 : global_new_decl (location *loc,
806 : enum gcc_jit_global_kind kind,
807 : type *type,
808 : const char *name,
809 : enum global_var_flags flags,
810 : const std::vector<std::pair<gcc_jit_variable_attribute,
811 : std::string>> &attributes,
812 : bool readonly)
813 : {
814 1061 : gcc_assert (type);
815 1061 : gcc_assert (name);
816 :
817 1061 : tree type_tree = type->as_tree ();
818 :
819 1061 : tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
820 : get_identifier (name),
821 : type_tree);
822 :
823 1061 : TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
824 :
825 :
826 1061 : int will_be_init = flags & (GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT |
827 : GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT);
828 :
829 : /* A VAR_DECL with DECL_INITIAL will not end up in .common section. */
830 1061 : if (!will_be_init)
831 196 : DECL_COMMON (inner) = 1;
832 :
833 1061 : switch (kind)
834 : {
835 0 : default:
836 0 : gcc_unreachable ();
837 :
838 920 : case GCC_JIT_GLOBAL_EXPORTED:
839 920 : TREE_STATIC (inner) = 1;
840 920 : break;
841 :
842 96 : case GCC_JIT_GLOBAL_INTERNAL:
843 96 : TREE_STATIC (inner) = 1;
844 96 : break;
845 :
846 45 : case GCC_JIT_GLOBAL_IMPORTED:
847 45 : DECL_EXTERNAL (inner) = 1;
848 45 : break;
849 : }
850 :
851 1061 : if (TYPE_READONLY (type_tree) || readonly)
852 145 : TREE_READONLY (inner) = 1;
853 :
854 1061 : if (loc)
855 5 : set_tree_location (inner, loc);
856 :
857 1061 : set_variable_string_attribute (attributes, inner);
858 :
859 1061 : return inner;
860 : }
861 :
862 : void
863 3253 : playback::
864 : set_variable_string_attribute (
865 : const std::vector<std::pair<gcc_jit_variable_attribute,
866 : std::string>> &string_attributes,
867 : tree decl)
868 : {
869 3253 : tree var_attributes = NULL_TREE;
870 3258 : for (auto attr: string_attributes)
871 : {
872 5 : gcc_jit_variable_attribute& name = std::get<0>(attr);
873 5 : std::string& value = std::get<1>(attr);
874 10 : tree attribute_value = build_tree_list (NULL_TREE,
875 5 : ::build_string (value.length () + 1, value.c_str ()));
876 5 : tree ident = get_identifier (variable_attribute_to_string (name));
877 5 : if (ident)
878 5 : var_attributes = tree_cons (ident, attribute_value, var_attributes);
879 5 : }
880 3253 : decl_attributes (&decl, var_attributes, 0);
881 3253 : }
882 :
883 : /* In use by new_global and new_global_initialized. */
884 :
885 : playback::lvalue *
886 1061 : playback::context::
887 : global_finalize_lvalue (tree inner)
888 : {
889 1061 : m_globals.safe_push (inner);
890 :
891 1061 : return new lvalue (this, inner);
892 : }
893 :
894 : /* Construct a playback::lvalue instance (wrapping a tree). */
895 :
896 : playback::lvalue *
897 1046 : playback::context::
898 : new_global (location *loc,
899 : enum gcc_jit_global_kind kind,
900 : type *type,
901 : const char *name,
902 : enum global_var_flags flags,
903 : const std::vector<std::pair<gcc_jit_variable_attribute,
904 : std::string>> &attributes,
905 : bool readonly)
906 : {
907 1046 : tree inner =
908 1046 : global_new_decl (loc, kind, type, name, flags, attributes, readonly);
909 :
910 1046 : return global_finalize_lvalue (inner);
911 : }
912 :
913 : void
914 850 : playback::context::
915 : global_set_init_rvalue (lvalue* variable,
916 : rvalue* init)
917 : {
918 850 : tree inner = variable->as_tree ();
919 :
920 : /* We need to fold all expressions as much as possible. The code
921 : for a DECL_INITIAL only handles some operations,
922 : etc addition, minus, 'address of'. See output_addressed_constants ()
923 : in varasm.cc. */
924 850 : tree init_tree = init->as_tree ();
925 850 : tree folded = fold_const_var (init_tree);
926 :
927 850 : if (!TREE_CONSTANT (folded))
928 : {
929 15 : tree name = DECL_NAME (inner);
930 :
931 15 : if (name != NULL_TREE)
932 15 : add_error (NULL,
933 : "unable to convert initial value for the global variable %s"
934 : " to a compile-time constant",
935 15 : IDENTIFIER_POINTER (name));
936 : else
937 0 : add_error (NULL,
938 : "unable to convert initial value for global variable"
939 : " to a compile-time constant");
940 15 : return;
941 : }
942 :
943 835 : DECL_INITIAL (inner) = folded;
944 : }
945 :
946 : playback::rvalue *
947 675 : playback::context::
948 : new_ctor (location *loc,
949 : type *type,
950 : const auto_vec<field*> *fields,
951 : const auto_vec<rvalue*> *rvalues)
952 : {
953 675 : tree type_tree = type->as_tree ();
954 :
955 : /* Handle empty ctors first. I.e. set everything to 0. */
956 675 : if (rvalues->length () == 0)
957 60 : return new rvalue (this, build_constructor (type_tree, NULL));
958 :
959 : /* Handle arrays (and return). */
960 615 : if (TREE_CODE (type_tree) == ARRAY_TYPE)
961 : {
962 240 : int n = rvalues->length ();
963 : /* The vec for the constructor node. */
964 240 : vec<constructor_elt, va_gc> *v = NULL;
965 240 : vec_alloc (v, n);
966 :
967 1020 : for (int i = 0; i < n; i++)
968 : {
969 780 : rvalue *rv = (*rvalues)[i];
970 : /* null rvalues indicate that the element should be zeroed. */
971 780 : if (rv)
972 705 : CONSTRUCTOR_APPEND_ELT (v,
973 : build_int_cst (size_type_node, i),
974 : rv->as_tree ());
975 : else
976 855 : CONSTRUCTOR_APPEND_ELT (v,
977 : build_int_cst (size_type_node, i),
978 : build_zero_cst (TREE_TYPE (type_tree)));
979 : }
980 :
981 240 : tree ctor = build_constructor (type_tree, v);
982 :
983 240 : if (loc)
984 0 : set_tree_location (ctor, loc);
985 :
986 240 : return new rvalue (this, ctor);
987 : }
988 :
989 : /* Handle structs and unions. */
990 375 : int n = fields->length ();
991 :
992 : /* The vec for the constructor node. */
993 375 : vec<constructor_elt, va_gc> *v = NULL;
994 375 : vec_alloc (v, n);
995 :
996 : /* Iterate over the fields, building initializations. */
997 990 : for (int i = 0;i < n; i++)
998 : {
999 615 : tree field = (*fields)[i]->as_tree ();
1000 615 : rvalue *rv = (*rvalues)[i];
1001 : /* If the value is NULL, it means we should zero the field. */
1002 615 : if (rv)
1003 525 : CONSTRUCTOR_APPEND_ELT (v, field, rv->as_tree ());
1004 : else
1005 : {
1006 90 : tree zero_cst = build_zero_cst (TREE_TYPE (field));
1007 705 : CONSTRUCTOR_APPEND_ELT (v, field, zero_cst);
1008 : }
1009 : }
1010 :
1011 375 : tree ctor = build_constructor (type_tree, v);
1012 :
1013 375 : if (loc)
1014 0 : set_tree_location (ctor, loc);
1015 :
1016 375 : return new rvalue (this, build_constructor (type_tree, v));
1017 : }
1018 :
1019 : /* Fill 'constructor_elements' with the memory content of
1020 : 'initializer'. Each element of the initializer is of the size of
1021 : type T. In use by new_global_initialized.*/
1022 :
1023 : template<typename T>
1024 : static void
1025 15 : load_blob_in_ctor (vec<constructor_elt, va_gc> *&constructor_elements,
1026 : size_t num_elem,
1027 : const void *initializer)
1028 : {
1029 : /* Loosely based on 'output_init_element' c-typeck.cc:9691. */
1030 15 : const T *p = (const T *)initializer;
1031 15 : tree node = make_unsigned_type (BITS_PER_UNIT * sizeof (T));
1032 20555 : for (size_t i = 0; i < num_elem; i++)
1033 : {
1034 41080 : constructor_elt celt =
1035 20540 : { build_int_cst (long_unsigned_type_node, i),
1036 20540 : build_int_cst (node, p[i]) };
1037 20540 : vec_safe_push (constructor_elements, celt);
1038 : }
1039 15 : }
1040 :
1041 : /* Construct an initialized playback::lvalue instance (wrapping a
1042 : tree). */
1043 :
1044 : playback::lvalue *
1045 15 : playback::context::
1046 : new_global_initialized (location *loc,
1047 : enum gcc_jit_global_kind kind,
1048 : type *type,
1049 : size_t element_size,
1050 : size_t initializer_num_elem,
1051 : const void *initializer,
1052 : const char *name,
1053 : enum global_var_flags flags,
1054 : const std::vector<std::pair<gcc_jit_variable_attribute,
1055 : std::string>> &attributes,
1056 : bool readonly)
1057 : {
1058 15 : tree inner = global_new_decl (loc, kind, type, name, flags, attributes, readonly);
1059 :
1060 15 : vec<constructor_elt, va_gc> *constructor_elements = NULL;
1061 :
1062 15 : switch (element_size)
1063 : {
1064 10 : case 1:
1065 10 : load_blob_in_ctor<uint8_t> (constructor_elements, initializer_num_elem,
1066 : initializer);
1067 10 : break;
1068 0 : case 2:
1069 0 : load_blob_in_ctor<uint16_t> (constructor_elements, initializer_num_elem,
1070 : initializer);
1071 0 : break;
1072 5 : case 4:
1073 5 : load_blob_in_ctor<uint32_t> (constructor_elements, initializer_num_elem,
1074 : initializer);
1075 5 : break;
1076 0 : case 8:
1077 0 : load_blob_in_ctor<uint64_t> (constructor_elements, initializer_num_elem,
1078 : initializer);
1079 0 : break;
1080 0 : default:
1081 : /* This function is serving on sizes returned by 'get_size',
1082 : these are all covered by the previous cases. */
1083 0 : gcc_unreachable ();
1084 : }
1085 : /* Compare with 'pop_init_level' c-typeck.cc:8780. */
1086 15 : tree ctor = build_constructor (type->as_tree (), constructor_elements);
1087 15 : constructor_elements = NULL;
1088 :
1089 : /* Compare with 'store_init_value' c-typeck.cc:7555. */
1090 15 : DECL_INITIAL (inner) = ctor;
1091 :
1092 15 : return global_finalize_lvalue (inner);
1093 : }
1094 :
1095 : /* Implementation of the various
1096 : gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
1097 : methods.
1098 : Each of these constructs a playback::rvalue instance (wrapping a tree).
1099 :
1100 : These specializations are required to be in the same namespace
1101 : as the template, hence we now have to enter the gcc::jit::playback
1102 : namespace. */
1103 :
1104 : namespace playback
1105 : {
1106 :
1107 : /* Specialization of making an rvalue from a const, for host <int>. */
1108 :
1109 : template <>
1110 : rvalue *
1111 6064 : context::
1112 : new_rvalue_from_const <int> (type *type,
1113 : int value)
1114 : {
1115 : // FIXME: type-checking, or coercion?
1116 6064 : tree inner_type = type->as_tree ();
1117 6064 : if (INTEGRAL_TYPE_P (inner_type))
1118 : {
1119 5457 : tree inner = build_int_cst (inner_type, value);
1120 5457 : return new rvalue (this, inner);
1121 : }
1122 : else
1123 : {
1124 607 : REAL_VALUE_TYPE real_value;
1125 607 : real_from_integer (&real_value, VOIDmode, value, SIGNED);
1126 607 : tree inner = build_real (inner_type, real_value);
1127 607 : return new rvalue (this, inner);
1128 : }
1129 : }
1130 :
1131 : /* Specialization of making an rvalue from a const, for host <long>. */
1132 :
1133 : template <>
1134 : rvalue *
1135 75 : context::
1136 : new_rvalue_from_const <long> (type *type,
1137 : long value)
1138 : {
1139 : // FIXME: type-checking, or coercion?
1140 75 : tree inner_type = type->as_tree ();
1141 75 : if (INTEGRAL_TYPE_P (inner_type))
1142 : {
1143 75 : tree inner = build_int_cst (inner_type, value);
1144 75 : return new rvalue (this, inner);
1145 : }
1146 : else
1147 : {
1148 0 : REAL_VALUE_TYPE real_value;
1149 0 : real_from_integer (&real_value, VOIDmode, value, SIGNED);
1150 0 : tree inner = build_real (inner_type, real_value);
1151 0 : return new rvalue (this, inner);
1152 : }
1153 : }
1154 :
1155 : /* Specialization of making an rvalue from a const, for host <double>. */
1156 :
1157 : template <>
1158 : rvalue *
1159 185 : context::
1160 : new_rvalue_from_const <double> (type *type,
1161 : double value)
1162 : {
1163 : // FIXME: type-checking, or coercion?
1164 185 : tree inner_type = type->as_tree ();
1165 :
1166 185 : mpfr_t mpf_value;
1167 :
1168 185 : mpfr_init2 (mpf_value, 64);
1169 185 : mpfr_set_d (mpf_value, value, MPFR_RNDN);
1170 :
1171 : /* We have a "double", we want a REAL_VALUE_TYPE.
1172 :
1173 : realmpfr.cc:real_from_mpfr. */
1174 185 : REAL_VALUE_TYPE real_value;
1175 185 : real_from_mpfr (&real_value, mpf_value, inner_type, MPFR_RNDN);
1176 185 : tree inner = build_real (inner_type, real_value);
1177 185 : return new rvalue (this, inner);
1178 : }
1179 :
1180 : /* Specialization of making an rvalue from a const, for host <void *>. */
1181 :
1182 : template <>
1183 : rvalue *
1184 145 : context::
1185 : new_rvalue_from_const <void *> (type *type,
1186 : void *value)
1187 : {
1188 145 : tree inner_type = type->as_tree ();
1189 : /* FIXME: how to ensure we have a wide enough type? */
1190 145 : tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
1191 145 : return new rvalue (this, inner);
1192 : }
1193 :
1194 : /* We're done implementing the specializations of
1195 : gcc::jit::playback::context::new_rvalue_from_const <T>
1196 : so we can exit the gcc::jit::playback namespace. */
1197 :
1198 : } // namespace playback
1199 :
1200 : /* Construct a playback::rvalue instance (wrapping a tree). */
1201 :
1202 : playback::rvalue *
1203 15 : playback::context::
1204 : new_sizeof (type *type)
1205 : {
1206 15 : tree inner = TYPE_SIZE_UNIT (type->as_tree ());
1207 15 : return new rvalue (this, inner);
1208 : }
1209 :
1210 : /* Construct a playback::rvalue instance (wrapping a tree). */
1211 :
1212 : playback::rvalue *
1213 15 : playback::context::
1214 : new_alignof (type *type)
1215 : {
1216 15 : int alignment = TYPE_ALIGN (type->as_tree ()) / BITS_PER_UNIT;
1217 15 : tree inner = build_int_cst (integer_type_node, alignment);
1218 15 : return new rvalue (this, inner);
1219 : }
1220 :
1221 : /* Construct a playback::rvalue instance (wrapping a tree). */
1222 :
1223 : playback::rvalue *
1224 187 : playback::context::
1225 : new_string_literal (const char *value)
1226 : {
1227 : /* Compare with c-family/c-common.cc: fix_string_type. */
1228 187 : size_t len = strlen (value);
1229 187 : tree i_type = build_index_type (size_int (len));
1230 187 : tree a_type = build_array_type (char_type_node, i_type);
1231 : /* build_string len parameter must include NUL terminator when
1232 : building C strings. */
1233 187 : tree t_str = ::build_string (len + 1, value);
1234 187 : TREE_TYPE (t_str) = a_type;
1235 :
1236 : /* Convert to (const char*), loosely based on
1237 : c/c-typeck.cc: array_to_pointer_conversion,
1238 : by taking address of start of string. */
1239 187 : tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
1240 :
1241 187 : return new rvalue (this, t_addr);
1242 : }
1243 :
1244 : /* Construct a playback::rvalue instance (wrapping a tree) for a
1245 : vector. */
1246 :
1247 : playback::rvalue *
1248 120 : playback::context::new_rvalue_from_vector (location *,
1249 : type *type,
1250 : const auto_vec<rvalue *> &elements)
1251 : {
1252 120 : vec<constructor_elt, va_gc> *v;
1253 240 : vec_alloc (v, elements.length ());
1254 600 : for (unsigned i = 0; i < elements.length (); ++i)
1255 480 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
1256 120 : tree t_ctor = build_constructor (type->as_tree (), v);
1257 120 : return new rvalue (this, t_ctor);
1258 : }
1259 :
1260 : /* Construct a playback::rvalue instance (wrapping a tree) for a
1261 : vector perm. */
1262 :
1263 : playback::rvalue *
1264 15 : playback::context::new_rvalue_vector_perm (location *loc,
1265 : rvalue* elements1,
1266 : rvalue* elements2,
1267 : rvalue* mask)
1268 : {
1269 15 : tree t_elements1 = elements1->as_tree ();
1270 15 : tree t_elements2 = elements2->as_tree ();
1271 15 : tree t_mask = mask->as_tree ();
1272 :
1273 15 : tree t_vector_perm = build3 (VEC_PERM_EXPR, TREE_TYPE (t_elements1),
1274 : t_elements1, t_elements2, t_mask);
1275 15 : if (loc)
1276 0 : set_tree_location (t_vector_perm, loc);
1277 15 : return new rvalue (this, t_vector_perm);
1278 : }
1279 :
1280 : /* Coerce a tree expression into a boolean tree expression. */
1281 :
1282 : tree
1283 620 : playback::context::
1284 : as_truth_value (tree expr, location *loc)
1285 : {
1286 : /* Compare to c-typeck.cc:c_objc_common_truthvalue_conversion */
1287 620 : tree typed_zero = fold_build1 (CONVERT_EXPR,
1288 : TREE_TYPE (expr),
1289 : integer_zero_node);
1290 620 : if (loc)
1291 0 : set_tree_location (typed_zero, loc);
1292 :
1293 620 : tree type = TREE_TYPE (expr);
1294 620 : expr = fold_build2_loc (UNKNOWN_LOCATION,
1295 : NE_EXPR, type, expr, typed_zero);
1296 620 : if (loc)
1297 0 : set_tree_location (expr, loc);
1298 :
1299 620 : return expr;
1300 : }
1301 :
1302 : /* Add a "top-level" basic asm statement (i.e. one outside of any functions)
1303 : containing ASM_STMTS.
1304 :
1305 : Compare with c_parser_asm_definition. */
1306 :
1307 : void
1308 10 : playback::context::add_top_level_asm (const char *asm_stmts)
1309 : {
1310 10 : tree asm_str = build_string (asm_stmts);
1311 10 : symtab->finalize_toplevel_asm (asm_str);
1312 10 : }
1313 :
1314 : /* Construct a playback::rvalue instance (wrapping a tree) for a
1315 : unary op. */
1316 :
1317 : playback::rvalue *
1318 128 : playback::context::
1319 : new_unary_op (location *loc,
1320 : enum gcc_jit_unary_op op,
1321 : type *result_type,
1322 : rvalue *a)
1323 : {
1324 : // FIXME: type-checking, or coercion?
1325 128 : enum tree_code inner_op;
1326 :
1327 128 : gcc_assert (result_type);
1328 128 : gcc_assert (a);
1329 :
1330 128 : tree node = a->as_tree ();
1331 128 : node = fold_const_var (node);
1332 :
1333 128 : tree inner_result = NULL;
1334 :
1335 128 : switch (op)
1336 : {
1337 0 : default:
1338 0 : add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
1339 0 : return NULL;
1340 :
1341 : case GCC_JIT_UNARY_OP_MINUS:
1342 : inner_op = NEGATE_EXPR;
1343 : break;
1344 :
1345 30 : case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
1346 30 : inner_op = BIT_NOT_EXPR;
1347 30 : break;
1348 :
1349 20 : case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
1350 20 : node = as_truth_value (node, loc);
1351 20 : inner_result = invert_truthvalue (node);
1352 20 : if (loc)
1353 0 : set_tree_location (inner_result, loc);
1354 20 : return new rvalue (this, inner_result);
1355 :
1356 15 : case GCC_JIT_UNARY_OP_ABS:
1357 15 : inner_op = ABS_EXPR;
1358 15 : break;
1359 : }
1360 :
1361 108 : inner_result = build1 (inner_op,
1362 : result_type->as_tree (),
1363 : node);
1364 :
1365 : /* Try to fold. */
1366 108 : inner_result = fold (inner_result);
1367 :
1368 108 : if (loc)
1369 0 : set_tree_location (inner_result, loc);
1370 :
1371 108 : return new rvalue (this, inner_result);
1372 : }
1373 :
1374 : /* Construct a playback::rvalue instance (wrapping a tree) for a
1375 : binary op. */
1376 :
1377 : playback::rvalue *
1378 3844 : playback::context::
1379 : new_binary_op (location *loc,
1380 : enum gcc_jit_binary_op op,
1381 : type *result_type,
1382 : rvalue *a, rvalue *b)
1383 : {
1384 : // FIXME: type-checking, or coercion?
1385 3844 : enum tree_code inner_op;
1386 :
1387 3844 : gcc_assert (result_type);
1388 3844 : gcc_assert (a);
1389 3844 : gcc_assert (b);
1390 :
1391 3844 : tree node_a = a->as_tree ();
1392 3844 : node_a = fold_const_var (node_a);
1393 :
1394 3844 : tree node_b = b->as_tree ();
1395 3844 : node_b = fold_const_var (node_b);
1396 :
1397 3844 : switch (op)
1398 : {
1399 0 : default:
1400 0 : add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
1401 0 : return NULL;
1402 :
1403 : case GCC_JIT_BINARY_OP_PLUS:
1404 : inner_op = PLUS_EXPR;
1405 : break;
1406 :
1407 278 : case GCC_JIT_BINARY_OP_MINUS:
1408 278 : inner_op = MINUS_EXPR;
1409 278 : break;
1410 :
1411 1250 : case GCC_JIT_BINARY_OP_MULT:
1412 1250 : inner_op = MULT_EXPR;
1413 1250 : break;
1414 :
1415 159 : case GCC_JIT_BINARY_OP_DIVIDE:
1416 159 : if (FLOAT_TYPE_P (result_type->as_tree ()))
1417 : /* Floating-point division: */
1418 : inner_op = RDIV_EXPR;
1419 : else
1420 : /* Truncating to zero: */
1421 : inner_op = TRUNC_DIV_EXPR;
1422 : break;
1423 :
1424 15 : case GCC_JIT_BINARY_OP_MODULO:
1425 15 : inner_op = TRUNC_MOD_EXPR;
1426 15 : break;
1427 :
1428 215 : case GCC_JIT_BINARY_OP_BITWISE_AND:
1429 215 : inner_op = BIT_AND_EXPR;
1430 215 : break;
1431 :
1432 30 : case GCC_JIT_BINARY_OP_BITWISE_XOR:
1433 30 : inner_op = BIT_XOR_EXPR;
1434 30 : break;
1435 :
1436 30 : case GCC_JIT_BINARY_OP_BITWISE_OR:
1437 30 : inner_op = BIT_IOR_EXPR;
1438 30 : break;
1439 :
1440 240 : case GCC_JIT_BINARY_OP_LOGICAL_AND:
1441 240 : node_a = as_truth_value (node_a, loc);
1442 240 : node_b = as_truth_value (node_b, loc);
1443 240 : inner_op = TRUTH_ANDIF_EXPR;
1444 240 : break;
1445 :
1446 60 : case GCC_JIT_BINARY_OP_LOGICAL_OR:
1447 60 : node_a = as_truth_value (node_a, loc);
1448 60 : node_b = as_truth_value (node_b, loc);
1449 60 : inner_op = TRUTH_ORIF_EXPR;
1450 60 : break;
1451 :
1452 30 : case GCC_JIT_BINARY_OP_LSHIFT:
1453 30 : inner_op = LSHIFT_EXPR;
1454 30 : break;
1455 :
1456 40 : case GCC_JIT_BINARY_OP_RSHIFT:
1457 40 : inner_op = RSHIFT_EXPR;
1458 40 : break;
1459 : }
1460 :
1461 3844 : tree inner_expr = build2 (inner_op,
1462 : result_type->as_tree (),
1463 : node_a,
1464 : node_b);
1465 :
1466 : /* Try to fold the expression. */
1467 3844 : inner_expr = fold (inner_expr);
1468 :
1469 3844 : if (loc)
1470 265 : set_tree_location (inner_expr, loc);
1471 :
1472 3844 : return new rvalue (this, inner_expr);
1473 : }
1474 :
1475 : /* Construct a playback::rvalue instance (wrapping a tree) for a
1476 : comparison. */
1477 :
1478 : playback::rvalue *
1479 1509 : playback::context::
1480 : new_comparison (location *loc,
1481 : enum gcc_jit_comparison op,
1482 : rvalue *a, rvalue *b, type *vec_result_type)
1483 : {
1484 : // FIXME: type-checking, or coercion?
1485 1509 : enum tree_code inner_op;
1486 :
1487 1509 : gcc_assert (a);
1488 1509 : gcc_assert (b);
1489 :
1490 1509 : switch (op)
1491 : {
1492 0 : default:
1493 0 : add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
1494 0 : return NULL;
1495 :
1496 : case GCC_JIT_COMPARISON_EQ:
1497 : inner_op = EQ_EXPR;
1498 : break;
1499 : case GCC_JIT_COMPARISON_NE:
1500 : inner_op = NE_EXPR;
1501 : break;
1502 : case GCC_JIT_COMPARISON_LT:
1503 : inner_op = LT_EXPR;
1504 : break;
1505 : case GCC_JIT_COMPARISON_LE:
1506 : inner_op = LE_EXPR;
1507 : break;
1508 : case GCC_JIT_COMPARISON_GT:
1509 : inner_op = GT_EXPR;
1510 : break;
1511 : case GCC_JIT_COMPARISON_GE:
1512 : inner_op = GE_EXPR;
1513 : break;
1514 : }
1515 :
1516 1509 : tree node_a = a->as_tree ();
1517 1509 : node_a = fold_const_var (node_a);
1518 1509 : tree node_b = b->as_tree ();
1519 1509 : node_b = fold_const_var (node_b);
1520 :
1521 1509 : tree inner_expr;
1522 1509 : tree a_type = TREE_TYPE (node_a);
1523 1509 : if (VECTOR_TYPE_P (a_type))
1524 : {
1525 : /* Build a vector comparison. See build_vec_cmp in c-typeck.cc for
1526 : reference. */
1527 135 : tree t_vec_result_type = vec_result_type->as_tree ();
1528 135 : tree zero_vec = build_zero_cst (t_vec_result_type);
1529 135 : tree minus_one_vec = build_minus_one_cst (t_vec_result_type);
1530 135 : tree cmp_type = truth_type_for (a_type);
1531 135 : tree cmp = build2 (inner_op, cmp_type, node_a, node_b);
1532 135 : inner_expr = build3 (VEC_COND_EXPR, t_vec_result_type, cmp, minus_one_vec,
1533 : zero_vec);
1534 : }
1535 : else
1536 : {
1537 1374 : inner_expr = build2 (inner_op,
1538 : boolean_type_node,
1539 : node_a,
1540 : node_b);
1541 : }
1542 :
1543 : /* Try to fold. */
1544 1509 : inner_expr = fold (inner_expr);
1545 :
1546 1509 : if (loc)
1547 21 : set_tree_location (inner_expr, loc);
1548 1509 : return new rvalue (this, inner_expr);
1549 : }
1550 :
1551 : /* Construct a playback::rvalue instance (wrapping a tree) for a
1552 : function call. */
1553 :
1554 : playback::rvalue *
1555 820 : playback::context::
1556 : build_call (location *loc,
1557 : tree fn_ptr,
1558 : const auto_vec<rvalue *> *args,
1559 : bool require_tail_call)
1560 : {
1561 820 : vec<tree, va_gc> *tree_args;
1562 1545 : vec_alloc (tree_args, args->length ());
1563 1987 : for (unsigned i = 0; i < args->length (); i++)
1564 1167 : tree_args->quick_push ((*args)[i]->as_tree ());
1565 :
1566 820 : if (loc)
1567 37 : set_tree_location (fn_ptr, loc);
1568 :
1569 820 : tree fn = TREE_TYPE (fn_ptr);
1570 820 : tree fn_type = TREE_TYPE (fn);
1571 820 : tree return_type = TREE_TYPE (fn_type);
1572 :
1573 820 : tree call = build_call_vec (return_type,
1574 : fn_ptr, tree_args);
1575 :
1576 820 : if (require_tail_call)
1577 20 : CALL_EXPR_MUST_TAIL_CALL (call) = 1;
1578 :
1579 820 : return new rvalue (this, call);
1580 :
1581 : /* see c-typeck.cc: build_function_call
1582 : which calls build_function_call_vec
1583 :
1584 : which does lots of checking, then:
1585 : result = build_call_array_loc (loc, TREE_TYPE (fntype),
1586 : function, nargs, argarray);
1587 : which is in tree.cc
1588 : (see also build_call_vec)
1589 : */
1590 : }
1591 :
1592 : /* Construct a playback::rvalue instance (wrapping a tree) for a
1593 : call to a specific function. */
1594 :
1595 : playback::rvalue *
1596 805 : playback::context::
1597 : new_call (location *loc,
1598 : function *func,
1599 : const auto_vec<rvalue *> *args,
1600 : bool require_tail_call)
1601 : {
1602 805 : tree fndecl;
1603 :
1604 805 : gcc_assert (func);
1605 :
1606 805 : fndecl = func->as_fndecl ();
1607 :
1608 805 : tree fntype = TREE_TYPE (fndecl);
1609 :
1610 805 : tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
1611 :
1612 805 : return build_call (loc, fn, args, require_tail_call);
1613 : }
1614 :
1615 : /* Construct a playback::rvalue instance (wrapping a tree) for a
1616 : call through a function pointer. */
1617 :
1618 : playback::rvalue *
1619 15 : playback::context::
1620 : new_call_through_ptr (location *loc,
1621 : rvalue *fn_ptr,
1622 : const auto_vec<rvalue *> *args,
1623 : bool require_tail_call)
1624 : {
1625 15 : gcc_assert (fn_ptr);
1626 15 : tree t_fn_ptr = fn_ptr->as_tree ();
1627 :
1628 15 : return build_call (loc, t_fn_ptr, args, require_tail_call);
1629 : }
1630 :
1631 : /* Construct a tree for a cast. */
1632 :
1633 : tree
1634 379 : playback::context::build_cast (playback::location *loc,
1635 : playback::rvalue *expr,
1636 : playback::type *type_)
1637 : {
1638 : /* For comparison, see:
1639 : - c/c-typeck.cc:build_c_cast
1640 : - c/c-convert.cc: convert
1641 : - convert.h
1642 :
1643 : Only some kinds of cast are currently supported here. */
1644 379 : tree t_expr = expr->as_tree ();
1645 379 : t_expr = fold_const_var (t_expr);
1646 :
1647 379 : tree t_dst_type = type_->as_tree ();
1648 379 : tree t_ret = NULL;
1649 379 : t_ret = targetm.convert_to_type (t_dst_type, t_expr);
1650 379 : if (t_ret)
1651 : return t_ret;
1652 379 : enum tree_code dst_code = TREE_CODE (t_dst_type);
1653 379 : switch (dst_code)
1654 : {
1655 155 : case INTEGER_TYPE:
1656 155 : case ENUMERAL_TYPE:
1657 155 : t_ret = convert_to_integer (t_dst_type, t_expr);
1658 155 : goto maybe_fold;
1659 :
1660 34 : case BOOLEAN_TYPE:
1661 : /* Compare with c_objc_common_truthvalue_conversion and
1662 : c_common_truthvalue_conversion. */
1663 : /* For now, convert to: (t_expr != 0) */
1664 34 : t_ret = build2 (NE_EXPR, t_dst_type,
1665 : t_expr,
1666 34 : build_int_cst (TREE_TYPE (t_expr), 0));
1667 34 : goto maybe_fold;
1668 :
1669 15 : case REAL_TYPE:
1670 15 : t_ret = convert_to_real (t_dst_type, t_expr);
1671 15 : goto maybe_fold;
1672 :
1673 175 : case POINTER_TYPE:
1674 175 : t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
1675 175 : goto maybe_fold;
1676 :
1677 0 : default:
1678 0 : add_error (loc, "couldn't handle cast during playback");
1679 0 : fprintf (stderr, "input expression:\n");
1680 0 : debug_tree (t_expr);
1681 0 : fprintf (stderr, "requested type:\n");
1682 0 : debug_tree (t_dst_type);
1683 0 : return error_mark_node;
1684 :
1685 379 : maybe_fold:
1686 379 : if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
1687 379 : t_ret = fold (t_ret);
1688 : return t_ret;
1689 : }
1690 : }
1691 :
1692 : /* Construct a playback::rvalue instance (wrapping a tree) for a
1693 : cast. */
1694 :
1695 : playback::rvalue *
1696 379 : playback::context::
1697 : new_cast (playback::location *loc,
1698 : playback::rvalue *expr,
1699 : playback::type *type_)
1700 : {
1701 :
1702 379 : tree t_cast = build_cast (loc, expr, type_);
1703 379 : if (loc)
1704 9 : set_tree_location (t_cast, loc);
1705 379 : return new rvalue (this, t_cast);
1706 : }
1707 :
1708 : /* Construct a playback::rvalue instance (wrapping a tree) for a
1709 : bitcast. */
1710 :
1711 : playback::rvalue *
1712 25 : playback::context::
1713 : new_bitcast (location *loc,
1714 : rvalue *expr,
1715 : type *type_)
1716 : {
1717 25 : tree expr_size = TYPE_SIZE (expr->get_type ()->as_tree ());
1718 25 : tree type_size = TYPE_SIZE (type_->as_tree ());
1719 25 : tree t_expr = expr->as_tree ();
1720 25 : tree t_dst_type = type_->as_tree ();
1721 25 : if (expr_size != type_size)
1722 : {
1723 10 : active_playback_ctxt->add_error (loc,
1724 : "bitcast with types of different sizes");
1725 10 : fprintf (stderr, "input expression (size: " HOST_WIDE_INT_PRINT_DEC "):\n",
1726 : tree_to_uhwi (expr_size));
1727 10 : debug_tree (t_expr);
1728 10 : fprintf (stderr, "requested type (size: " HOST_WIDE_INT_PRINT_DEC "):\n",
1729 : tree_to_uhwi (type_size));
1730 10 : debug_tree (t_dst_type);
1731 : }
1732 25 : tree t_bitcast = build1 (VIEW_CONVERT_EXPR, t_dst_type, t_expr);
1733 25 : if (loc)
1734 0 : set_tree_location (t_bitcast, loc);
1735 25 : return new rvalue (this, t_bitcast);
1736 : }
1737 :
1738 : /* Construct a playback::lvalue instance (wrapping a tree) for an
1739 : array access. */
1740 :
1741 : playback::lvalue *
1742 474 : playback::context::
1743 : new_array_access (location *loc,
1744 : rvalue *ptr,
1745 : rvalue *index)
1746 : {
1747 474 : gcc_assert (ptr);
1748 474 : gcc_assert (index);
1749 :
1750 : /* For comparison, see:
1751 : c/c-typeck.cc: build_array_ref
1752 : c-family/c-common.cc: pointer_int_sum
1753 : */
1754 474 : tree t_ptr = ptr->as_tree ();
1755 474 : t_ptr = fold_const_var (t_ptr);
1756 474 : tree t_index = index->as_tree ();
1757 474 : t_index = fold_const_var (t_index);
1758 :
1759 474 : tree t_type_ptr = TREE_TYPE (t_ptr);
1760 474 : tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
1761 :
1762 474 : if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
1763 : {
1764 299 : tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
1765 : NULL_TREE, NULL_TREE);
1766 299 : t_result = fold (t_result);
1767 299 : if (loc)
1768 209 : set_tree_location (t_result, loc);
1769 299 : return new lvalue (this, t_result);
1770 : }
1771 : else
1772 : {
1773 : /* Convert index to an offset in bytes. */
1774 175 : tree t_sizeof = size_in_bytes (t_type_star_ptr);
1775 175 : t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
1776 175 : tree t_offset = fold_build2_loc (UNKNOWN_LOCATION,
1777 : MULT_EXPR, sizetype, t_index, t_sizeof);
1778 :
1779 : /* Locate (ptr + offset). */
1780 175 : tree t_address = fold_build2_loc (UNKNOWN_LOCATION,
1781 : POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
1782 :
1783 175 : tree t_indirection = fold_build1 (INDIRECT_REF, t_type_star_ptr, t_address);
1784 175 : if (loc)
1785 : {
1786 0 : set_tree_location (t_sizeof, loc);
1787 0 : set_tree_location (t_offset, loc);
1788 0 : set_tree_location (t_address, loc);
1789 0 : set_tree_location (t_indirection, loc);
1790 : }
1791 :
1792 175 : return new lvalue (this, t_indirection);
1793 : }
1794 : }
1795 :
1796 : /* Construct a playback::rvalue instance (wrapping a tree) for a
1797 : vector conversion. */
1798 :
1799 : playback::rvalue *
1800 15 : playback::context::
1801 : convert_vector (location *loc,
1802 : rvalue *vector,
1803 : type *type)
1804 : {
1805 15 : gcc_assert (vector);
1806 15 : gcc_assert (type);
1807 :
1808 : /* For comparison, see:
1809 : c/c-common.cc: c_build_vec_convert
1810 : */
1811 :
1812 15 : tree t_vector = vector->as_tree ();
1813 :
1814 15 : tree t_result =
1815 15 : build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_VEC_CONVERT,
1816 : type->as_tree (), 1, t_vector);
1817 :
1818 15 : if (loc)
1819 0 : set_tree_location (t_result, loc);
1820 :
1821 15 : return new rvalue (this, t_result);
1822 : }
1823 :
1824 : /* The following functions come from c-common.h. */
1825 : /* Like c_mark_addressable but don't check register qualifier. */
1826 : void
1827 15 : common_mark_addressable_vec (tree t)
1828 : {
1829 15 : while (handled_component_p (t) || TREE_CODE (t) == C_MAYBE_CONST_EXPR)
1830 : {
1831 0 : t = TREE_OPERAND (t, 0);
1832 : }
1833 15 : if (!VAR_P (t)
1834 15 : && TREE_CODE (t) != PARM_DECL
1835 15 : && TREE_CODE (t) != COMPOUND_LITERAL_EXPR
1836 15 : && TREE_CODE (t) != TARGET_EXPR)
1837 : return;
1838 0 : if (!VAR_P (t) || !DECL_HARD_REGISTER (t))
1839 0 : TREE_ADDRESSABLE (t) = 1;
1840 0 : if (TREE_CODE (t) == COMPOUND_LITERAL_EXPR)
1841 0 : TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (t)) = 1;
1842 0 : else if (TREE_CODE (t) == TARGET_EXPR)
1843 0 : TREE_ADDRESSABLE (TARGET_EXPR_SLOT (t)) = 1;
1844 : }
1845 :
1846 : /* Return true if TYPE is a vector type that should be subject to the GNU
1847 : vector extensions (as opposed to a vector type that is used only for
1848 : the purposes of defining target-specific built-in functions). */
1849 :
1850 : inline bool
1851 15 : gnu_vector_type_p (const_tree type)
1852 : {
1853 15 : return TREE_CODE (type) == VECTOR_TYPE && !TYPE_INDIVISIBLE_P (type);
1854 : }
1855 :
1856 : /* Return nonzero if REF is an lvalue valid for this language.
1857 : Lvalues can be assigned, unless their type has TYPE_READONLY.
1858 : Lvalues can have their address taken, unless they have C_DECL_REGISTER. */
1859 :
1860 : bool
1861 15 : lvalue_p (const_tree ref)
1862 : {
1863 15 : const enum tree_code code = TREE_CODE (ref);
1864 :
1865 15 : switch (code)
1866 : {
1867 0 : case REALPART_EXPR:
1868 0 : case IMAGPART_EXPR:
1869 0 : case COMPONENT_REF:
1870 0 : return lvalue_p (TREE_OPERAND (ref, 0));
1871 :
1872 0 : case C_MAYBE_CONST_EXPR:
1873 0 : return lvalue_p (TREE_OPERAND (ref, 1));
1874 :
1875 : case COMPOUND_LITERAL_EXPR:
1876 : case STRING_CST:
1877 : return true;
1878 :
1879 0 : case MEM_REF:
1880 0 : case TARGET_MEM_REF:
1881 : /* MEM_REFs can appear from -fgimple parsing or folding, so allow them
1882 : here as well. */
1883 0 : case INDIRECT_REF:
1884 0 : case ARRAY_REF:
1885 0 : case VAR_DECL:
1886 0 : case PARM_DECL:
1887 0 : case RESULT_DECL:
1888 0 : case ERROR_MARK:
1889 0 : return (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
1890 0 : && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE);
1891 :
1892 0 : case BIND_EXPR:
1893 0 : return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE;
1894 :
1895 : default:
1896 : return false;
1897 : }
1898 : }
1899 :
1900 : bool
1901 15 : convert_vector_to_array_for_subscript (tree *vecp)
1902 : {
1903 15 : bool ret = false;
1904 15 : if (gnu_vector_type_p (TREE_TYPE (*vecp)))
1905 : {
1906 15 : tree type = TREE_TYPE (*vecp);
1907 :
1908 15 : ret = !lvalue_p (*vecp);
1909 :
1910 : /* We are building an ARRAY_REF so mark the vector as addressable
1911 : to not run into the gimplifiers premature setting of DECL_GIMPLE_REG_P
1912 : for function parameters. */
1913 : /* NOTE: that was the missing piece for making vector access work with
1914 : optimizations enabled. */
1915 15 : common_mark_addressable_vec (*vecp);
1916 :
1917 30 : *vecp = build1 (VIEW_CONVERT_EXPR,
1918 15 : build_array_type_nelts (TREE_TYPE (type),
1919 : TYPE_VECTOR_SUBPARTS (type)),
1920 : *vecp);
1921 : }
1922 15 : return ret;
1923 : }
1924 :
1925 : /* Construct a playback::lvalue instance (wrapping a tree) for a
1926 : vector access. */
1927 :
1928 : playback::lvalue *
1929 15 : playback::context::
1930 : new_vector_access (location *loc,
1931 : rvalue *vector,
1932 : rvalue *index)
1933 : {
1934 15 : gcc_assert (vector);
1935 15 : gcc_assert (index);
1936 :
1937 : /* For comparison, see:
1938 : c/c-typeck.cc: build_array_ref
1939 : */
1940 :
1941 15 : tree t_vector = vector->as_tree ();
1942 15 : bool non_lvalue = convert_vector_to_array_for_subscript (&t_vector);
1943 15 : tree type = TREE_TYPE (TREE_TYPE (t_vector));
1944 15 : tree t_result = build4 (ARRAY_REF, type, t_vector, index->as_tree (),
1945 : NULL_TREE, NULL_TREE);
1946 15 : if (non_lvalue)
1947 15 : t_result = non_lvalue (t_result);
1948 :
1949 15 : if (loc)
1950 0 : set_tree_location (t_result, loc);
1951 15 : return new lvalue (this, t_result);
1952 : }
1953 :
1954 : /* Construct a tree for a field access. */
1955 :
1956 : tree
1957 1886 : playback::context::
1958 : new_field_access (location *loc,
1959 : tree datum,
1960 : field *field)
1961 : {
1962 1886 : gcc_assert (datum);
1963 1886 : gcc_assert (field);
1964 :
1965 : /* Compare with c/c-typeck.cc:lookup_field, build_indirect_ref, and
1966 : build_component_ref. */
1967 1886 : tree type = TREE_TYPE (datum);
1968 1886 : gcc_assert (type);
1969 1886 : gcc_assert (TREE_CODE (type) != POINTER_TYPE);
1970 :
1971 1886 : tree t_field = field->as_tree ();
1972 1886 : tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
1973 : t_field, NULL_TREE);
1974 1886 : if (loc)
1975 0 : set_tree_location (ref, loc);
1976 1886 : return ref;
1977 : }
1978 :
1979 : /* Construct a tree for a dereference. */
1980 :
1981 : tree
1982 2232 : playback::context::
1983 : new_dereference (tree ptr,
1984 : location *loc)
1985 : {
1986 2232 : gcc_assert (ptr);
1987 :
1988 2232 : tree type = TREE_TYPE (TREE_TYPE(ptr));
1989 2232 : tree datum = fold_build1 (INDIRECT_REF, type, ptr);
1990 2232 : if (loc)
1991 0 : set_tree_location (datum, loc);
1992 2232 : return datum;
1993 : }
1994 :
1995 : /* Construct a playback::type instance (wrapping a tree)
1996 : with the given alignment. */
1997 :
1998 : playback::type *
1999 160 : playback::type::
2000 : get_aligned (size_t alignment_in_bytes) const
2001 : {
2002 160 : tree t_new_type = build_variant_type_copy (m_inner);
2003 :
2004 160 : SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT);
2005 160 : TYPE_USER_ALIGN (t_new_type) = 1;
2006 :
2007 160 : return new type (t_new_type);
2008 : }
2009 :
2010 : /* Construct a playback::type instance (wrapping a tree)
2011 : for the given vector type. */
2012 :
2013 : playback::type *
2014 375 : playback::type::
2015 : get_vector (size_t num_units) const
2016 : {
2017 375 : tree t_new_type = build_vector_type (m_inner, num_units);
2018 375 : return new type (t_new_type);
2019 : }
2020 :
2021 : /* Construct a playback::lvalue instance (wrapping a tree) for a
2022 : field access. */
2023 :
2024 : playback::lvalue *
2025 199 : playback::lvalue::
2026 : access_field (location *loc,
2027 : field *field)
2028 : {
2029 199 : tree datum = as_tree ();
2030 199 : tree ref = get_context ()->new_field_access (loc, datum, field);
2031 199 : if (!ref)
2032 : return NULL;
2033 199 : return new lvalue (get_context (), ref);
2034 : }
2035 :
2036 : /* Construct a playback::rvalue instance (wrapping a tree) for a
2037 : field access. */
2038 :
2039 : playback::rvalue *
2040 139 : playback::rvalue::
2041 : access_field (location *loc,
2042 : field *field)
2043 : {
2044 139 : tree datum = as_tree ();
2045 139 : tree ref = get_context ()->new_field_access (loc, datum, field);
2046 139 : if (!ref)
2047 : return NULL;
2048 139 : return new rvalue (get_context (), ref);
2049 : }
2050 :
2051 : /* Construct a playback::lvalue instance (wrapping a tree) for a
2052 : dereferenced field access. */
2053 :
2054 : playback::lvalue *
2055 1548 : playback::rvalue::
2056 : dereference_field (location *loc,
2057 : field *field)
2058 : {
2059 1548 : tree ptr = as_tree ();
2060 1548 : tree datum = get_context ()->new_dereference (ptr, loc);
2061 1548 : if (!datum)
2062 : return NULL;
2063 1548 : tree ref = get_context ()->new_field_access (loc, datum, field);
2064 1548 : if (!ref)
2065 : return NULL;
2066 1548 : return new lvalue (get_context (), ref);
2067 : }
2068 :
2069 : /* Construct a playback::lvalue instance (wrapping a tree) for a
2070 : dereference. */
2071 :
2072 : playback::lvalue *
2073 684 : playback::rvalue::
2074 : dereference (location *loc)
2075 : {
2076 684 : tree ptr = as_tree ();
2077 684 : tree datum = get_context ()->new_dereference (ptr, loc);
2078 684 : return new lvalue (get_context (), datum);
2079 : }
2080 :
2081 : /* Mark the lvalue saying that we need to be able to take the
2082 : address of it; it should not be allocated in a register.
2083 : Compare with e.g. c/c-typeck.cc: c_mark_addressable really_atomic_lvalue.
2084 : Returns false if a failure occurred (an error will already have been
2085 : added to the active context for this case). */
2086 :
2087 : bool
2088 498 : playback::lvalue::
2089 : mark_addressable (location *loc)
2090 : {
2091 498 : tree x = as_tree ();
2092 :
2093 558 : while (1)
2094 528 : switch (TREE_CODE (x))
2095 : {
2096 5 : case COMPONENT_REF:
2097 5 : if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x, 1)))
2098 : {
2099 5 : gcc_assert (gcc::jit::active_playback_ctxt);
2100 5 : gcc::jit::
2101 5 : active_playback_ctxt->add_error (loc,
2102 : "cannot take address of "
2103 : "bit-field");
2104 5 : return false;
2105 : }
2106 : /* fallthrough */
2107 30 : case ADDR_EXPR:
2108 30 : case ARRAY_REF:
2109 30 : case REALPART_EXPR:
2110 30 : case IMAGPART_EXPR:
2111 30 : x = TREE_OPERAND (x, 0);
2112 30 : break;
2113 :
2114 0 : case COMPOUND_LITERAL_EXPR:
2115 0 : case CONSTRUCTOR:
2116 0 : TREE_ADDRESSABLE (x) = 1;
2117 0 : return true;
2118 :
2119 433 : case VAR_DECL:
2120 433 : case CONST_DECL:
2121 433 : case PARM_DECL:
2122 433 : case RESULT_DECL:
2123 : /* (we don't have a concept of a "register" declaration) */
2124 : /* fallthrough */
2125 433 : case FUNCTION_DECL:
2126 433 : TREE_ADDRESSABLE (x) = 1;
2127 : /* fallthrough */
2128 : default:
2129 : return true;
2130 : }
2131 : }
2132 :
2133 : /* Construct a playback::rvalue instance (wrapping a tree) for an
2134 : address-lookup. */
2135 :
2136 : playback::rvalue *
2137 498 : playback::lvalue::
2138 : get_address (location *loc)
2139 : {
2140 498 : tree t_lvalue = as_tree ();
2141 498 : tree t_thistype = TREE_TYPE (t_lvalue);
2142 498 : tree t_ptrtype = build_pointer_type (t_thistype);
2143 498 : tree ptr = fold_build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
2144 498 : if (loc)
2145 0 : get_context ()->set_tree_location (ptr, loc);
2146 498 : if (mark_addressable (loc))
2147 493 : return new rvalue (get_context (), ptr);
2148 : else
2149 : return NULL;
2150 : }
2151 :
2152 : /* The wrapper subclasses are GC-managed, but can own non-GC memory.
2153 : Provide this finalization hook for calling then they are collected,
2154 : which calls the finalizer vfunc. This allows them to call "release"
2155 : on any vec<> within them. */
2156 :
2157 : static void
2158 76940 : wrapper_finalizer (void *ptr)
2159 : {
2160 76940 : playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
2161 76940 : wrapper->finalizer ();
2162 76940 : }
2163 :
2164 : /* gcc::jit::playback::wrapper subclasses are GC-managed:
2165 : allocate them using ggc_internal_cleared_alloc. */
2166 :
2167 : void *
2168 80714 : playback::wrapper::
2169 : operator new (size_t sz)
2170 : {
2171 80714 : return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
2172 :
2173 : }
2174 :
2175 : /* Constructor for gcc:jit::playback::function. */
2176 :
2177 16667 : playback::function::
2178 : function (context *ctxt,
2179 : tree fndecl,
2180 16667 : enum gcc_jit_function_kind kind)
2181 16667 : : m_ctxt(ctxt),
2182 16667 : m_inner_fndecl (fndecl),
2183 16667 : m_inner_bind_expr (NULL),
2184 16667 : m_kind (kind),
2185 16667 : m_blocks ()
2186 : {
2187 16667 : if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
2188 : {
2189 : /* Create a BIND_EXPR, and within it, a statement list. */
2190 3346 : m_stmt_list = alloc_stmt_list ();
2191 3346 : m_stmt_iter = tsi_start (m_stmt_list);
2192 3346 : m_inner_block = make_node (BLOCK);
2193 3346 : m_inner_bind_expr =
2194 3346 : build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
2195 : }
2196 : else
2197 : {
2198 13321 : m_inner_block = NULL;
2199 13321 : m_stmt_list = NULL;
2200 : }
2201 16667 : }
2202 :
2203 : /* Hand-written GC-marking hook for playback functions. */
2204 :
2205 : void
2206 36309119 : playback::function::
2207 : gt_ggc_mx ()
2208 : {
2209 36309119 : gt_ggc_m_9tree_node (m_inner_fndecl);
2210 36309119 : gt_ggc_m_9tree_node (m_inner_bind_expr);
2211 36309119 : gt_ggc_m_9tree_node (m_stmt_list);
2212 36309119 : gt_ggc_m_9tree_node (m_inner_block);
2213 36309119 : }
2214 :
2215 : /* Don't leak vec's internal buffer (in non-GC heap) when we are
2216 : GC-ed. */
2217 :
2218 : void
2219 14741 : playback::function::finalizer ()
2220 : {
2221 14741 : m_blocks.release ();
2222 14741 : }
2223 :
2224 : /* Get the return type of a playback function, in tree form. */
2225 :
2226 : tree
2227 3702 : playback::function::
2228 : get_return_type_as_tree () const
2229 : {
2230 3702 : return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
2231 : }
2232 :
2233 : /* Construct a new local within this playback::function. */
2234 :
2235 : playback::lvalue *
2236 2192 : playback::function::
2237 : new_local (location *loc,
2238 : type *type,
2239 : const char *name,
2240 : const std::vector<std::pair<gcc_jit_variable_attribute,
2241 : std::string>> &attributes)
2242 : {
2243 2192 : gcc_assert (type);
2244 2192 : tree inner;
2245 2192 : if (name)
2246 2187 : inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
2247 : get_identifier (name),
2248 : type->as_tree ());
2249 : else
2250 : {
2251 5 : inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
2252 : create_tmp_var_name ("JITTMP"),
2253 : type->as_tree ());
2254 5 : DECL_ARTIFICIAL (inner) = 1;
2255 5 : DECL_IGNORED_P (inner) = 1;
2256 5 : DECL_NAMELESS (inner) = 1;
2257 : }
2258 2192 : DECL_CONTEXT (inner) = this->m_inner_fndecl;
2259 :
2260 : /* Prepend to BIND_EXPR_VARS: */
2261 2192 : DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
2262 2192 : BIND_EXPR_VARS (m_inner_bind_expr) = inner;
2263 :
2264 2192 : set_variable_string_attribute (attributes, inner);
2265 :
2266 2192 : if (loc)
2267 21 : set_tree_location (inner, loc);
2268 2192 : return new lvalue (m_ctxt, inner);
2269 : }
2270 :
2271 : /* Construct a new block within this playback::function. */
2272 :
2273 : playback::block *
2274 5833 : playback::function::
2275 : new_block (const char *name)
2276 : {
2277 5833 : gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
2278 :
2279 5833 : block *result = new playback::block (this, name);
2280 5833 : m_blocks.safe_push (result);
2281 5833 : return result;
2282 : }
2283 :
2284 : /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
2285 : this playback::function. */
2286 :
2287 : playback::rvalue *
2288 15 : playback::function::get_address (location *loc)
2289 : {
2290 15 : tree t_fndecl = as_fndecl ();
2291 15 : tree t_fntype = TREE_TYPE (t_fndecl);
2292 15 : tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
2293 15 : if (loc)
2294 0 : m_ctxt->set_tree_location (t_fnptr, loc);
2295 15 : return new rvalue (m_ctxt, t_fnptr);
2296 : }
2297 :
2298 : /* Build a statement list for the function as a whole out of the
2299 : lists of statements for the individual blocks, building labels
2300 : for each block. */
2301 :
2302 : void
2303 16652 : playback::function::
2304 : build_stmt_list ()
2305 : {
2306 16652 : int i;
2307 16652 : block *b;
2308 :
2309 16652 : JIT_LOG_SCOPE (m_ctxt->get_logger ());
2310 :
2311 22470 : FOR_EACH_VEC_ELT (m_blocks, i, b)
2312 : {
2313 5818 : int j;
2314 5818 : tree stmt;
2315 :
2316 5818 : b->m_label_expr = build1 (LABEL_EXPR,
2317 : void_type_node,
2318 : b->as_label_decl ());
2319 5818 : tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
2320 :
2321 23162 : FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
2322 11526 : tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
2323 : }
2324 16652 : }
2325 :
2326 : /* Finish compiling the given function, potentially running the
2327 : garbage-collector.
2328 : The function will have a statement list by now.
2329 : Amongst other things, this gimplifies the statement list,
2330 : and calls cgraph_node::finalize_function on the function. */
2331 :
2332 : void
2333 16652 : playback::function::
2334 : postprocess ()
2335 : {
2336 16652 : JIT_LOG_SCOPE (m_ctxt->get_logger ());
2337 :
2338 16652 : if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
2339 0 : debug_tree (m_stmt_list);
2340 :
2341 : /* Do we need this to force cgraphunit.cc to output the function? */
2342 16652 : if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
2343 : {
2344 3191 : DECL_EXTERNAL (m_inner_fndecl) = 0;
2345 3191 : DECL_PRESERVE_P (m_inner_fndecl) = 1;
2346 : }
2347 :
2348 16652 : if (m_kind == GCC_JIT_FUNCTION_INTERNAL
2349 16652 : ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
2350 : {
2351 140 : DECL_EXTERNAL (m_inner_fndecl) = 0;
2352 140 : TREE_PUBLIC (m_inner_fndecl) = 0;
2353 : }
2354 :
2355 16652 : if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
2356 : {
2357 : /* Seem to need this in gimple-low.cc: */
2358 3331 : gcc_assert (m_inner_block);
2359 3331 : DECL_INITIAL (m_inner_fndecl) = m_inner_block;
2360 :
2361 : /* how to add to function? the following appears to be how to
2362 : set the body of a m_inner_fndecl: */
2363 3331 : DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
2364 :
2365 : /* Ensure that locals appear in the debuginfo. */
2366 3331 : BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
2367 :
2368 : //debug_tree (m_inner_fndecl);
2369 :
2370 : /* Convert to gimple: */
2371 : //printf("about to gimplify_function_tree\n");
2372 3331 : gimplify_function_tree (m_inner_fndecl);
2373 : //printf("finished gimplify_function_tree\n");
2374 :
2375 3331 : current_function_decl = m_inner_fndecl;
2376 3331 : if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
2377 0 : dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
2378 : //debug_tree (m_inner_fndecl);
2379 :
2380 : //printf("about to add to cgraph\n");
2381 : /* Add to cgraph: */
2382 3331 : cgraph_node::finalize_function (m_inner_fndecl, false);
2383 : /* This can trigger a collection, so we need to have all of
2384 : the funcs as roots. */
2385 :
2386 3331 : current_function_decl = NULL;
2387 : }
2388 : else
2389 : /* Add to cgraph to output aliases: */
2390 13321 : rest_of_decl_compilation (m_inner_fndecl, true, 0);
2391 16652 : }
2392 :
2393 : /* Don't leak vec's internal buffer (in non-GC heap) when we are
2394 : GC-ed. */
2395 :
2396 : void
2397 5731 : playback::block::finalizer ()
2398 : {
2399 5731 : m_stmts.release ();
2400 5731 : }
2401 :
2402 : /* Add an eval of the rvalue to the function's statement list. */
2403 :
2404 : void
2405 256 : playback::block::
2406 : add_eval (location *loc,
2407 : rvalue *rvalue)
2408 : {
2409 256 : gcc_assert (rvalue);
2410 :
2411 256 : if (loc)
2412 9 : set_tree_location (rvalue->as_tree (), loc);
2413 :
2414 256 : add_stmt (rvalue->as_tree ());
2415 256 : }
2416 :
2417 : /* Add an assignment to the function's statement list. */
2418 :
2419 : void
2420 4929 : playback::block::
2421 : add_assignment (location *loc,
2422 : lvalue *lvalue,
2423 : rvalue *rvalue)
2424 : {
2425 4929 : gcc_assert (lvalue);
2426 4929 : gcc_assert (rvalue);
2427 :
2428 4929 : tree t_lvalue = lvalue->as_tree ();
2429 4929 : tree t_rvalue = rvalue->as_tree ();
2430 4929 : if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
2431 : {
2432 320 : t_rvalue = build1 (CONVERT_EXPR,
2433 320 : TREE_TYPE (t_lvalue),
2434 : t_rvalue);
2435 320 : if (loc)
2436 0 : set_tree_location (t_rvalue, loc);
2437 : }
2438 :
2439 4929 : tree stmt =
2440 4929 : build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
2441 : t_lvalue, t_rvalue);
2442 4929 : if (loc)
2443 390 : set_tree_location (stmt, loc);
2444 4929 : add_stmt (stmt);
2445 4929 : }
2446 :
2447 : /* Add a comment to the function's statement list.
2448 : For now this is done by adding a dummy label. */
2449 :
2450 : void
2451 458 : playback::block::
2452 : add_comment (location *loc,
2453 : const char *text)
2454 : {
2455 : /* Wrap the text in C-style comment delimiters. */
2456 458 : size_t sz =
2457 : (3 /* opening delim */
2458 458 : + strlen (text)
2459 : + 3 /* closing delim */
2460 : + 1 /* terminator */);
2461 458 : char *wrapped = (char *)ggc_internal_alloc (sz);
2462 458 : snprintf (wrapped, sz, "/* %s */", text);
2463 :
2464 : /* For now we simply implement this by adding a dummy label with a name
2465 : containing the given text. */
2466 458 : tree identifier = get_identifier (wrapped);
2467 458 : tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
2468 : identifier, void_type_node);
2469 458 : DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
2470 :
2471 458 : tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
2472 458 : if (loc)
2473 202 : set_tree_location (label_expr, loc);
2474 458 : add_stmt (label_expr);
2475 458 : }
2476 :
2477 : /* Add a conditional jump statement to the function's statement list. */
2478 :
2479 : void
2480 879 : playback::block::
2481 : add_conditional (location *loc,
2482 : rvalue *boolval,
2483 : block *on_true,
2484 : block *on_false)
2485 : {
2486 879 : gcc_assert (boolval);
2487 879 : gcc_assert (on_true);
2488 879 : gcc_assert (on_false);
2489 :
2490 : /* COND_EXPR wants statement lists for the true/false operands, but we
2491 : want labels.
2492 : Shim it by creating jumps to the labels */
2493 879 : tree true_jump = build1 (GOTO_EXPR, void_type_node,
2494 : on_true->as_label_decl ());
2495 879 : if (loc)
2496 37 : set_tree_location (true_jump, loc);
2497 :
2498 879 : tree false_jump = build1 (GOTO_EXPR, void_type_node,
2499 : on_false->as_label_decl ());
2500 879 : if (loc)
2501 37 : set_tree_location (false_jump, loc);
2502 :
2503 879 : tree stmt =
2504 879 : build3 (COND_EXPR, void_type_node, boolval->as_tree (),
2505 : true_jump, false_jump);
2506 879 : if (loc)
2507 37 : set_tree_location (stmt, loc);
2508 879 : add_stmt (stmt);
2509 879 : }
2510 :
2511 : /* Add an unconditional jump statement to the function's statement list. */
2512 :
2513 : void
2514 1222 : playback::block::
2515 : add_jump (location *loc,
2516 : block *target)
2517 : {
2518 1222 : gcc_assert (target);
2519 :
2520 : // see c_finish_loop
2521 : //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
2522 : //add_stmt (top);
2523 :
2524 : //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
2525 1222 : TREE_USED (target->as_label_decl ()) = 1;
2526 1222 : tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
2527 1222 : if (loc)
2528 48 : set_tree_location (stmt, loc);
2529 1222 : add_stmt (stmt);
2530 :
2531 : /*
2532 : from c-typeck.cc:
2533 : tree
2534 : c_finish_goto_label (location_t loc, tree label)
2535 : {
2536 : tree decl = lookup_label_for_goto (loc, label);
2537 : if (!decl)
2538 : return NULL_TREE;
2539 : TREE_USED (decl) = 1;
2540 : {
2541 : tree t = build1 (GOTO_EXPR, void_type_node, decl);
2542 : SET_EXPR_LOCATION (t, loc);
2543 : return add_stmt (t);
2544 : }
2545 : }
2546 : */
2547 :
2548 1222 : }
2549 :
2550 : /* Add a return statement to the function's statement list. */
2551 :
2552 : void
2553 3702 : playback::block::
2554 : add_return (location *loc,
2555 : rvalue *rvalue)
2556 : {
2557 3702 : tree modify_retval = NULL;
2558 3702 : tree return_type = m_func->get_return_type_as_tree ();
2559 3702 : if (rvalue)
2560 : {
2561 3173 : tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
2562 3173 : tree t_rvalue = rvalue->as_tree ();
2563 3173 : if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
2564 110 : t_rvalue = build1 (CONVERT_EXPR,
2565 110 : TREE_TYPE (t_lvalue),
2566 : t_rvalue);
2567 3173 : modify_retval = build2 (MODIFY_EXPR, return_type,
2568 : t_lvalue, t_rvalue);
2569 3173 : if (loc)
2570 68 : set_tree_location (modify_retval, loc);
2571 : }
2572 3702 : tree return_stmt = build1 (RETURN_EXPR, return_type,
2573 : modify_retval);
2574 3702 : if (loc)
2575 80 : set_tree_location (return_stmt, loc);
2576 :
2577 3702 : add_stmt (return_stmt);
2578 3702 : }
2579 :
2580 : /* Helper function for playback::block::add_switch.
2581 : Construct a case label for the given range, followed by a goto stmt
2582 : to the given block, appending them to stmt list *ptr_t_switch_body. */
2583 :
2584 : static void
2585 100 : add_case (tree *ptr_t_switch_body,
2586 : tree t_low_value,
2587 : tree t_high_value,
2588 : playback::block *dest_block)
2589 : {
2590 100 : tree t_label = create_artificial_label (UNKNOWN_LOCATION);
2591 100 : DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
2592 :
2593 100 : tree t_case_label =
2594 100 : build_case_label (t_low_value, t_high_value, t_label);
2595 100 : append_to_statement_list (t_case_label, ptr_t_switch_body);
2596 :
2597 100 : tree t_goto_stmt =
2598 100 : build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
2599 100 : append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
2600 100 : }
2601 :
2602 : /* Add a switch statement to the function's statement list.
2603 :
2604 : We create a switch body, and populate it with case labels, each
2605 : followed by a goto to the desired block. */
2606 :
2607 : void
2608 20 : playback::block::
2609 : add_switch (location *loc,
2610 : rvalue *expr,
2611 : block *default_block,
2612 : const auto_vec <case_> *cases)
2613 : {
2614 : /* Compare with:
2615 : - c/c-typeck.cc: c_start_case
2616 : - c-family/c-common.cc:c_add_case_label
2617 : - java/expr.cc:expand_java_switch and expand_java_add_case
2618 : We've already rejected overlaps and duplicates in
2619 : libgccjit.cc:case_range_validator::validate. */
2620 :
2621 20 : tree t_expr = expr->as_tree ();
2622 20 : tree t_type = TREE_TYPE (t_expr);
2623 :
2624 20 : tree t_switch_body = alloc_stmt_list ();
2625 :
2626 20 : int i;
2627 20 : case_ *c;
2628 100 : FOR_EACH_VEC_ELT (*cases, i, c)
2629 : {
2630 80 : tree t_low_value = c->m_min_value->as_tree ();
2631 80 : tree t_high_value = c->m_max_value->as_tree ();
2632 80 : add_case (&t_switch_body, t_low_value, t_high_value, c->m_dest_block);
2633 : }
2634 : /* Default label. */
2635 20 : add_case (&t_switch_body, NULL_TREE, NULL_TREE, default_block);
2636 :
2637 20 : tree switch_stmt = build2 (SWITCH_EXPR, t_type, t_expr, t_switch_body);
2638 20 : if (loc)
2639 0 : set_tree_location (switch_stmt, loc);
2640 20 : add_stmt (switch_stmt);
2641 20 : }
2642 :
2643 : /* Convert OPERANDS to a tree-based chain suitable for creating an
2644 : extended asm stmt.
2645 : Compare with c_parser_asm_operands. */
2646 :
2647 : static tree
2648 140 : build_operand_chain (const auto_vec <playback::asm_operand> *operands)
2649 : {
2650 140 : tree result = NULL_TREE;
2651 140 : unsigned i;
2652 140 : playback::asm_operand *asm_op;
2653 240 : FOR_EACH_VEC_ELT (*operands, i, asm_op)
2654 : {
2655 100 : tree name = build_string (asm_op->m_asm_symbolic_name);
2656 100 : tree str = build_string (asm_op->m_constraint);
2657 100 : tree value = asm_op->m_expr;
2658 100 : result = chainon (result,
2659 : build_tree_list (build_tree_list (name, str),
2660 : value));
2661 : }
2662 140 : return result;
2663 : }
2664 :
2665 : /* Convert CLOBBERS to a tree-based list suitable for creating an
2666 : extended asm stmt.
2667 : Compare with c_parser_asm_clobbers. */
2668 :
2669 : static tree
2670 70 : build_clobbers (const auto_vec <const char *> *clobbers)
2671 : {
2672 70 : tree list = NULL_TREE;
2673 70 : unsigned i;
2674 70 : const char *clobber;
2675 120 : FOR_EACH_VEC_ELT (*clobbers, i, clobber)
2676 : {
2677 50 : tree str = build_string (clobber);
2678 50 : list = tree_cons (NULL_TREE, str, list);
2679 : }
2680 70 : return list;
2681 : }
2682 :
2683 : /* Convert BLOCKS to a tree-based list suitable for creating an
2684 : extended asm stmt.
2685 : Compare with c_parser_asm_goto_operands. */
2686 :
2687 : static tree
2688 70 : build_goto_operands (const auto_vec <playback::block *> *blocks)
2689 : {
2690 70 : tree list = NULL_TREE;
2691 70 : unsigned i;
2692 70 : playback::block *b;
2693 90 : FOR_EACH_VEC_ELT (*blocks, i, b)
2694 : {
2695 20 : tree label = b->as_label_decl ();
2696 20 : tree name = build_string (IDENTIFIER_POINTER (DECL_NAME (label)));
2697 20 : TREE_USED (label) = 1;
2698 20 : list = tree_cons (name, label, list);
2699 : }
2700 70 : return nreverse (list);
2701 : }
2702 :
2703 : /* Add an extended asm statement to this block.
2704 :
2705 : Compare with c_parser_asm_statement (in c/c-parser.cc)
2706 : and build_asm_expr (in c/c-typeck.cc). */
2707 :
2708 : void
2709 70 : playback::block::add_extended_asm (location *loc,
2710 : const char *asm_template,
2711 : bool is_volatile,
2712 : bool is_inline,
2713 : const auto_vec <asm_operand> *outputs,
2714 : const auto_vec <asm_operand> *inputs,
2715 : const auto_vec <const char *> *clobbers,
2716 : const auto_vec <block *> *goto_blocks)
2717 : {
2718 70 : tree t_string = build_string (asm_template);
2719 70 : tree t_outputs = build_operand_chain (outputs);
2720 70 : tree t_inputs = build_operand_chain (inputs);
2721 70 : tree t_clobbers = build_clobbers (clobbers);
2722 70 : tree t_labels = build_goto_operands (goto_blocks);
2723 70 : t_string
2724 70 : = resolve_asm_operand_names (t_string, t_outputs, t_inputs, t_labels);
2725 70 : tree asm_stmt
2726 70 : = build5 (ASM_EXPR, void_type_node,
2727 : t_string, t_outputs, t_inputs, t_clobbers, t_labels);
2728 :
2729 : /* asm statements without outputs, including simple ones, are treated
2730 : as volatile. */
2731 110 : ASM_VOLATILE_P (asm_stmt) = (outputs->length () == 0);
2732 70 : ASM_BASIC_P (asm_stmt) = 0;
2733 70 : ASM_INLINE_P (asm_stmt) = is_inline;
2734 70 : if (is_volatile)
2735 20 : ASM_VOLATILE_P (asm_stmt) = 1;
2736 70 : if (loc)
2737 0 : set_tree_location (asm_stmt, loc);
2738 70 : add_stmt (asm_stmt);
2739 70 : }
2740 :
2741 : /* Constructor for gcc::jit::playback::block. */
2742 :
2743 5833 : playback::block::
2744 : block (function *func,
2745 5833 : const char *name)
2746 5833 : : m_func (func),
2747 5833 : m_stmts ()
2748 : {
2749 5833 : tree identifier;
2750 :
2751 5833 : gcc_assert (func);
2752 : // name can be NULL
2753 5833 : if (name)
2754 4876 : identifier = get_identifier (name);
2755 : else
2756 : identifier = NULL;
2757 5833 : m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
2758 : identifier, void_type_node);
2759 5833 : DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
2760 5833 : m_label_expr = NULL;
2761 5833 : }
2762 :
2763 : // This is basically std::lock_guard but it can call the private lock/unlock
2764 : // members of playback::context.
2765 : struct playback::context::scoped_lock
2766 : {
2767 1331 : scoped_lock (context &ctx) : m_ctx (&ctx) { m_ctx->lock (); }
2768 2662 : ~scoped_lock () { m_ctx->unlock (); }
2769 :
2770 : context *m_ctx;
2771 :
2772 : // Not movable or copyable.
2773 : scoped_lock (scoped_lock &&) = delete;
2774 : scoped_lock &operator= (scoped_lock &&) = delete;
2775 : };
2776 :
2777 : /* Compile a playback::context:
2778 :
2779 : - Use the context's options to cconstruct command-line options, and
2780 : call into the rest of GCC (toplev::main).
2781 : - Assuming it succeeds, we have a .s file.
2782 : - We then run the "postprocess" vfunc:
2783 :
2784 : (A) In-memory compile ("gcc_jit_context_compile")
2785 :
2786 : For an in-memory compile we have the playback::compile_to_memory
2787 : subclass; "postprocess" will convert the .s file to a .so DSO,
2788 : and load it in memory (via dlopen), wrapping the result up as
2789 : a jit::result and returning it.
2790 :
2791 : (B) Compile to file ("gcc_jit_context_compile_to_file")
2792 :
2793 : When compiling to a file, we have the playback::compile_to_file
2794 : subclass; "postprocess" will either copy the .s file to the
2795 : destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
2796 : the driver to convert it as necessary, copying the result. */
2797 :
2798 : void
2799 1331 : playback::context::
2800 : compile ()
2801 : {
2802 1331 : JIT_LOG_SCOPE (get_logger ());
2803 :
2804 1331 : const char *ctxt_progname;
2805 :
2806 1331 : int keep_intermediates =
2807 1331 : get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
2808 :
2809 1331 : m_tempdir = new tempdir (get_logger (), keep_intermediates);
2810 1331 : if (!m_tempdir->create ())
2811 : return;
2812 :
2813 : /* Call into the rest of gcc.
2814 : For now, we have to assemble command-line options to pass into
2815 : toplev::main, so that they can be parsed. */
2816 :
2817 : /* Pass in user-provided program name as argv0, if any, so that it
2818 : makes it into GCC's "progname" global, used in various diagnostics. */
2819 1331 : ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
2820 :
2821 1331 : if (!ctxt_progname)
2822 119 : ctxt_progname = "libgccjit.so";
2823 :
2824 1331 : auto_vec <recording::requested_dump> requested_dumps;
2825 1331 : m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
2826 :
2827 : /* Acquire the JIT mutex and set "this" as the active playback ctxt. */
2828 1331 : scoped_lock lock(*this);
2829 :
2830 1331 : auto_string_vec fake_args;
2831 1331 : make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
2832 1331 : if (errors_occurred ())
2833 : return;
2834 :
2835 : /* This runs the compiler. */
2836 1331 : toplev toplev (get_timer (), /* external_timer */
2837 1331 : false); /* init_signals */
2838 1331 : enter_scope ("toplev::main");
2839 1331 : if (get_logger ())
2840 7084 : for (unsigned i = 0; i < fake_args.length (); i++)
2841 6477 : get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
2842 :
2843 : /* Add a trailing null to argvec; this is not counted in argc. */
2844 1331 : fake_args.safe_push (nullptr);
2845 2662 : toplev.main (/* The trailing null is not counted in argv. */
2846 1331 : fake_args.length () - 1,
2847 : const_cast <char **> (fake_args.address ()));
2848 1331 : exit_scope ("toplev::main");
2849 :
2850 : /* Extracting dumps makes use of the gcc::dump_manager, hence we
2851 : need to do it between toplev::main (which creates the dump manager)
2852 : and toplev::finalize (which deletes it). */
2853 1331 : extract_any_requested_dumps (&requested_dumps);
2854 :
2855 : /* Clean up the compiler. */
2856 1331 : enter_scope ("toplev::finalize");
2857 1331 : toplev.finalize ();
2858 1331 : exit_scope ("toplev::finalize");
2859 :
2860 : /* Ideally we would release the jit mutex here, but we can't yet since
2861 : followup activities use timevars, which are global state. */
2862 :
2863 1331 : if (errors_occurred ())
2864 55 : return;
2865 :
2866 1276 : if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
2867 0 : dump_generated_code ();
2868 :
2869 : /* We now have a .s file.
2870 :
2871 : Run any postprocessing steps. This will either convert the .s file to
2872 : a .so DSO, and load it in memory (playback::compile_to_memory), or
2873 : convert the .s file to the requested output format, and copy it to a
2874 : given file (playback::compile_to_file). */
2875 1276 : postprocess (ctxt_progname);
2876 1331 : }
2877 :
2878 : /* Implementation of class gcc::jit::playback::compile_to_memory,
2879 : a subclass of gcc::jit::playback::context. */
2880 :
2881 : /* playback::compile_to_memory's trivial constructor. */
2882 :
2883 1173 : playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
2884 : playback::context (ctxt),
2885 1173 : m_result (NULL)
2886 : {
2887 1173 : JIT_LOG_SCOPE (get_logger ());
2888 1173 : }
2889 :
2890 : /* Implementation of the playback::context::process vfunc for compiling
2891 : to memory.
2892 :
2893 : Convert the .s file to a .so DSO, and load it in memory (via dlopen),
2894 : wrapping the result up as a jit::result and returning it. */
2895 :
2896 : void
2897 1118 : playback::compile_to_memory::postprocess (const char *ctxt_progname)
2898 : {
2899 1118 : JIT_LOG_SCOPE (get_logger ());
2900 1118 : convert_to_dso (ctxt_progname);
2901 1118 : if (errors_occurred ())
2902 5 : return;
2903 1113 : m_result = dlopen_built_dso ();
2904 1118 : }
2905 :
2906 : /* Implementation of class gcc::jit::playback::compile_to_file,
2907 : a subclass of gcc::jit::playback::context. */
2908 :
2909 : /* playback::compile_to_file's trivial constructor. */
2910 :
2911 126 : playback::compile_to_file::compile_to_file (recording::context *ctxt,
2912 : enum gcc_jit_output_kind output_kind,
2913 126 : const char *output_path) :
2914 : playback::context (ctxt),
2915 126 : m_output_kind (output_kind),
2916 126 : m_output_path (output_path)
2917 : {
2918 126 : JIT_LOG_SCOPE (get_logger ());
2919 126 : }
2920 :
2921 : /* Implementation of the playback::context::process vfunc for compiling
2922 : to a file.
2923 :
2924 : Either copy the .s file to the given destination (for
2925 : GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
2926 : as necessary, copying the result. */
2927 :
2928 : void
2929 126 : playback::compile_to_file::postprocess (const char *ctxt_progname)
2930 : {
2931 126 : JIT_LOG_SCOPE (get_logger ());
2932 :
2933 : /* The driver takes different actions based on the filename, so
2934 : we provide a filename with an appropriate suffix for the
2935 : output kind, and then copy it up to the user-provided path,
2936 : rather than directly compiling it to the requested output path. */
2937 :
2938 126 : switch (m_output_kind)
2939 : {
2940 0 : default:
2941 0 : gcc_unreachable ();
2942 :
2943 105 : case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
2944 105 : copy_file (get_tempdir ()->get_path_s_file (),
2945 : m_output_path);
2946 : /* The .s file is automatically unlinked by tempdir::~tempdir. */
2947 105 : break;
2948 :
2949 5 : case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
2950 5 : {
2951 5 : char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
2952 : "/fake.o",
2953 : NULL);
2954 5 : invoke_driver (ctxt_progname,
2955 : get_tempdir ()->get_path_s_file (),
2956 : tmp_o_path,
2957 : TV_ASSEMBLE,
2958 : false, /* bool shared, */
2959 : false);/* bool run_linker */
2960 5 : if (!errors_occurred ())
2961 : {
2962 5 : copy_file (tmp_o_path,
2963 : m_output_path);
2964 5 : get_tempdir ()->add_temp_file (tmp_o_path);
2965 : }
2966 : else
2967 0 : free (tmp_o_path);
2968 : }
2969 : break;
2970 :
2971 5 : case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
2972 5 : invoke_driver (ctxt_progname,
2973 : get_tempdir ()->get_path_s_file (),
2974 : get_tempdir ()->get_path_so_file (),
2975 : TV_ASSEMBLE,
2976 : true, /* bool shared, */
2977 : true);/* bool run_linker */
2978 5 : if (!errors_occurred ())
2979 5 : copy_file (get_tempdir ()->get_path_so_file (),
2980 : m_output_path);
2981 : /* The .so file is automatically unlinked by tempdir::~tempdir. */
2982 : break;
2983 :
2984 11 : case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
2985 11 : {
2986 11 : char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
2987 : "/fake.exe",
2988 : NULL);
2989 11 : invoke_driver (ctxt_progname,
2990 : get_tempdir ()->get_path_s_file (),
2991 : tmp_exe_path,
2992 : TV_ASSEMBLE,
2993 : false, /* bool shared, */
2994 : true);/* bool run_linker */
2995 11 : if (!errors_occurred ())
2996 : {
2997 11 : copy_file (tmp_exe_path,
2998 : m_output_path);
2999 11 : get_tempdir ()->add_temp_file (tmp_exe_path);
3000 : }
3001 : else
3002 0 : free (tmp_exe_path);
3003 : }
3004 : break;
3005 :
3006 : }
3007 :
3008 126 : }
3009 :
3010 : /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
3011 : the "executable" bits).
3012 :
3013 : Any errors that occur are reported on the context and hence count as
3014 : a failure of the compile.
3015 :
3016 : We can't in general hardlink or use "rename" from the tempdir since
3017 : it might be on a different filesystem to the destination. For example,
3018 : I get EXDEV: "Invalid cross-device link". */
3019 :
3020 : void
3021 126 : playback::compile_to_file::copy_file (const char *src_path,
3022 : const char *dst_path)
3023 : {
3024 126 : JIT_LOG_SCOPE (get_logger ());
3025 126 : if (get_logger ())
3026 : {
3027 125 : get_logger ()->log ("src_path: %s", src_path);
3028 125 : get_logger ()->log ("dst_path: %s", dst_path);
3029 : }
3030 :
3031 126 : FILE *f_in = NULL;
3032 126 : FILE *f_out = NULL;
3033 126 : size_t total_sz_in = 0;
3034 126 : size_t total_sz_out = 0;
3035 126 : char buf[4096];
3036 126 : size_t sz_in;
3037 126 : struct stat stat_buf;
3038 :
3039 126 : f_in = fopen (src_path, "rb");
3040 126 : if (!f_in)
3041 : {
3042 0 : add_error (NULL,
3043 : "unable to open %s for reading: %s",
3044 : src_path,
3045 0 : xstrerror (errno));
3046 0 : return;
3047 : }
3048 :
3049 : /* Use stat on the filedescriptor to get the mode,
3050 : so that we can copy it over (in particular, the
3051 : "executable" bits). */
3052 126 : if (fstat (fileno (f_in), &stat_buf) == -1)
3053 : {
3054 0 : add_error (NULL,
3055 : "unable to fstat %s: %s",
3056 : src_path,
3057 0 : xstrerror (errno));
3058 0 : fclose (f_in);
3059 0 : return;
3060 : }
3061 :
3062 126 : f_out = fopen (dst_path, "wb");
3063 126 : if (!f_out)
3064 : {
3065 0 : add_error (NULL,
3066 : "unable to open %s for writing: %s",
3067 : dst_path,
3068 0 : xstrerror (errno));
3069 0 : fclose (f_in);
3070 0 : return;
3071 : }
3072 :
3073 327 : while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
3074 : {
3075 201 : total_sz_in += sz_in;
3076 201 : size_t sz_out_remaining = sz_in;
3077 201 : size_t sz_out_so_far = 0;
3078 402 : while (sz_out_remaining)
3079 : {
3080 201 : size_t sz_out = fwrite (buf + sz_out_so_far,
3081 : 1,
3082 : sz_out_remaining,
3083 : f_out);
3084 201 : gcc_assert (sz_out <= sz_out_remaining);
3085 201 : if (!sz_out)
3086 : {
3087 0 : add_error (NULL,
3088 : "error writing to %s: %s",
3089 : dst_path,
3090 0 : xstrerror (errno));
3091 0 : fclose (f_in);
3092 0 : fclose (f_out);
3093 0 : return;
3094 : }
3095 201 : total_sz_out += sz_out;
3096 201 : sz_out_so_far += sz_out;
3097 201 : sz_out_remaining -= sz_out;
3098 : }
3099 201 : gcc_assert (sz_out_so_far == sz_in);
3100 : }
3101 :
3102 126 : if (!feof (f_in))
3103 0 : add_error (NULL,
3104 : "error reading from %s: %s",
3105 : src_path,
3106 0 : xstrerror (errno));
3107 :
3108 126 : fclose (f_in);
3109 :
3110 126 : gcc_assert (total_sz_in == total_sz_out);
3111 126 : if (get_logger ())
3112 125 : get_logger ()->log ("total bytes copied: %zu", total_sz_out);
3113 :
3114 : /* fchmod does not exist in Windows. */
3115 : #ifndef _WIN32
3116 : /* Set the permissions of the copy to those of the original file,
3117 : in particular the "executable" bits. */
3118 126 : if (fchmod (fileno (f_out), stat_buf.st_mode) == -1)
3119 0 : add_error (NULL,
3120 : "error setting mode of %s: %s",
3121 : dst_path,
3122 0 : xstrerror (errno));
3123 : #endif
3124 :
3125 126 : fclose (f_out);
3126 126 : }
3127 :
3128 : /* Helper functions for gcc::jit::playback::context::compile. */
3129 :
3130 : /* This mutex guards gcc::jit::recording::context::compile, so that only
3131 : one thread can be accessing the bulk of GCC's state at once. */
3132 :
3133 : static std::mutex jit_mutex;
3134 :
3135 : /* Acquire jit_mutex and set "this" as the active playback ctxt. */
3136 :
3137 : void
3138 1331 : playback::context::lock ()
3139 : {
3140 1331 : auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
3141 :
3142 : /* Acquire the big GCC mutex. */
3143 1331 : JIT_LOG_SCOPE (get_logger ());
3144 1331 : jit_mutex.lock ();
3145 1331 : gcc_assert (active_playback_ctxt == NULL);
3146 1331 : active_playback_ctxt = this;
3147 1331 : }
3148 :
3149 : /* Release jit_mutex and clear the active playback ctxt. */
3150 :
3151 : void
3152 1331 : playback::context::unlock ()
3153 : {
3154 : /* Release the big GCC mutex. */
3155 1331 : JIT_LOG_SCOPE (get_logger ());
3156 1331 : gcc_assert (active_playback_ctxt == this);
3157 1331 : active_playback_ctxt = NULL;
3158 1331 : jit_mutex.unlock ();
3159 1331 : }
3160 :
3161 : /* Callback used by gcc::jit::playback::context::make_fake_args when
3162 : invoking driver_get_configure_time_options.
3163 : Populate a vec <char * > with the configure-time options. */
3164 :
3165 : static void
3166 262 : append_arg_from_driver (const char *option, void *user_data)
3167 : {
3168 262 : gcc_assert (option);
3169 262 : gcc_assert (user_data);
3170 262 : vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
3171 262 : argvec->safe_push (concat ("-", option, NULL));
3172 262 : }
3173 :
3174 : /* Build a fake argv for toplev::main from the options set
3175 : by the user on the context . */
3176 :
3177 : void
3178 1331 : playback::context::
3179 : make_fake_args (vec <char *> *argvec,
3180 : const char *ctxt_progname,
3181 : vec <recording::requested_dump> *requested_dumps)
3182 : {
3183 1331 : JIT_LOG_SCOPE (get_logger ());
3184 :
3185 : #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
3186 : #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
3187 :
3188 1331 : ADD_ARG (ctxt_progname);
3189 1331 : ADD_ARG (get_path_c_file ());
3190 1331 : ADD_ARG ("-fPIC");
3191 :
3192 : /* Handle int options: */
3193 1331 : switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
3194 : {
3195 0 : default:
3196 0 : add_error (NULL,
3197 : "unrecognized optimization level: %i",
3198 : get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
3199 0 : return;
3200 :
3201 179 : case 0:
3202 179 : ADD_ARG ("-O0");
3203 179 : break;
3204 :
3205 105 : case 1:
3206 105 : ADD_ARG ("-O1");
3207 105 : break;
3208 :
3209 115 : case 2:
3210 115 : ADD_ARG ("-O2");
3211 115 : break;
3212 :
3213 932 : case 3:
3214 932 : ADD_ARG ("-O3");
3215 932 : break;
3216 : }
3217 : /* What about -Os? */
3218 :
3219 : /* Handle bool options: */
3220 1331 : if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
3221 827 : ADD_ARG ("-g");
3222 :
3223 : /* Suppress timing (and other) info. */
3224 1331 : if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
3225 : {
3226 1331 : ADD_ARG ("-quiet");
3227 1331 : quiet_flag = 1;
3228 : }
3229 :
3230 : /* Aggressively garbage-collect, to shake out bugs: */
3231 1331 : if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
3232 : {
3233 817 : ADD_ARG ("--param=ggc-min-expand=0");
3234 817 : ADD_ARG ("--param=ggc-min-heapsize=0");
3235 : }
3236 :
3237 1331 : if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
3238 : {
3239 0 : ADD_ARG ("-fdump-tree-all");
3240 0 : ADD_ARG ("-fdump-rtl-all");
3241 0 : ADD_ARG ("-fdump-ipa-all");
3242 : }
3243 :
3244 : /* Add "-fdump-" options for any calls to
3245 : gcc_jit_context_enable_dump. */
3246 : {
3247 : int i;
3248 : recording::requested_dump *d;
3249 1381 : FOR_EACH_VEC_ELT (*requested_dumps, i, d)
3250 : {
3251 50 : char *arg = concat ("-fdump-", d->m_dumpname, NULL);
3252 50 : ADD_ARG_TAKE_OWNERSHIP (arg);
3253 : }
3254 : }
3255 :
3256 : /* PR jit/64810: Add any target-specific default options
3257 : from OPTION_DEFAULT_SPECS, normally provided by the driver
3258 : in the non-jit case.
3259 :
3260 : The target-specific code can define OPTION_DEFAULT_SPECS:
3261 : default command options in the form of spec macros for the
3262 : driver to expand ().
3263 :
3264 : For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
3265 : if not overriden, injects the defaults as extra arguments to
3266 : cc1 etc.
3267 : For the jit case, we need to add these arguments here. The
3268 : input format (using the specs language) means that we have to run
3269 : part of the driver code here (driver_get_configure_time_options).
3270 :
3271 : To avoid running the spec-expansion code every time, we just do
3272 : it the first time (via a function-static flag), saving the result
3273 : into a function-static vec.
3274 : This flag and vec are global state (i.e. per-process).
3275 : They are guarded by the jit mutex. */
3276 1331 : {
3277 1331 : static bool have_configure_time_options = false;
3278 1331 : static vec <char *> configure_time_options;
3279 :
3280 1331 : if (have_configure_time_options)
3281 1200 : log ("reusing cached configure-time options");
3282 : else
3283 : {
3284 131 : have_configure_time_options = true;
3285 131 : log ("getting configure-time options from driver");
3286 131 : driver_get_configure_time_options (append_arg_from_driver,
3287 : &configure_time_options);
3288 : }
3289 :
3290 1331 : int i;
3291 1331 : char *opt;
3292 :
3293 1331 : if (get_logger ())
3294 1821 : FOR_EACH_VEC_ELT (configure_time_options, i, opt)
3295 1214 : log ("configure_time_options[%i]: %s", i, opt);
3296 :
3297 : /* configure_time_options should now contain the expanded options
3298 : from OPTION_DEFAULT_SPECS (if any). */
3299 3993 : FOR_EACH_VEC_ELT (configure_time_options, i, opt)
3300 : {
3301 2662 : gcc_assert (opt);
3302 2662 : gcc_assert (opt[0] == '-');
3303 2662 : ADD_ARG (opt);
3304 : }
3305 : }
3306 :
3307 1331 : if (get_timer ())
3308 400 : ADD_ARG ("-ftime-report");
3309 :
3310 : /* Add any user-provided extra options, starting with any from
3311 : parent contexts. */
3312 1331 : m_recording_ctxt->append_command_line_options (argvec);
3313 :
3314 : #undef ADD_ARG
3315 : #undef ADD_ARG_TAKE_OWNERSHIP
3316 1331 : }
3317 :
3318 : /* The second half of the implementation of gcc_jit_context_enable_dump.
3319 : Iterate through the requested dumps, reading the underlying files
3320 : into heap-allocated buffers, writing pointers to the buffers into
3321 : the char ** pointers provided by client code.
3322 : Client code is responsible for calling free on the results. */
3323 :
3324 : void
3325 1331 : playback::context::
3326 : extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
3327 : {
3328 1331 : JIT_LOG_SCOPE (get_logger ());
3329 :
3330 1331 : int i;
3331 1331 : recording::requested_dump *d;
3332 1381 : FOR_EACH_VEC_ELT (*requested_dumps, i, d)
3333 : {
3334 50 : dump_file_info *dfi;
3335 50 : char *filename;
3336 50 : char *content;
3337 :
3338 50 : dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
3339 50 : if (!dfi)
3340 : {
3341 5 : add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
3342 5 : continue;
3343 : }
3344 :
3345 45 : filename = g->get_dumps ()->get_dump_file_name (dfi);
3346 45 : content = read_dump_file (filename);
3347 45 : *(d->m_out_ptr) = content;
3348 45 : m_tempdir->add_temp_file (filename);
3349 : }
3350 1331 : }
3351 :
3352 : /* Helper function for playback::context::extract_any_requested_dumps
3353 : (itself for use in implementation of gcc_jit_context_enable_dump).
3354 :
3355 : Attempt to read the complete file at the given path, returning the
3356 : bytes found there as a buffer.
3357 : The caller is responsible for calling free on the result.
3358 : Errors will be reported on the context, and lead to NULL being
3359 : returned; an out-of-memory error will terminate the process. */
3360 :
3361 : char *
3362 45 : playback::context::read_dump_file (const char *path)
3363 : {
3364 45 : char *result = NULL;
3365 45 : size_t total_sz = 0;
3366 45 : char buf[4096];
3367 45 : size_t sz;
3368 45 : FILE *f_in;
3369 :
3370 45 : f_in = fopen (path, "r");
3371 45 : if (!f_in)
3372 : {
3373 0 : add_error (NULL, "unable to open %s for reading", path);
3374 0 : return NULL;
3375 : }
3376 :
3377 5310 : while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
3378 : {
3379 5265 : size_t old_total_sz = total_sz;
3380 5265 : total_sz += sz;
3381 5265 : result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
3382 5265 : memcpy (result + old_total_sz, buf, sz);
3383 : }
3384 :
3385 45 : if (!feof (f_in))
3386 : {
3387 0 : add_error (NULL, "error reading from %s", path);
3388 0 : free (result);
3389 0 : fclose (f_in);
3390 0 : return NULL;
3391 : }
3392 :
3393 45 : fclose (f_in);
3394 :
3395 45 : if (result)
3396 : {
3397 45 : result[total_sz] = '\0';
3398 45 : return result;
3399 : }
3400 : else
3401 0 : return xstrdup ("");
3402 : }
3403 :
3404 : /* Part of playback::context::compile ().
3405 :
3406 : We have a .s file; we want a .so file.
3407 : We could reuse parts of gcc/gcc.cc to do this.
3408 : For now, just use the driver binary from the install, as
3409 : named in gcc-driver-name.h
3410 : e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0". */
3411 :
3412 : void
3413 1118 : playback::context::
3414 : convert_to_dso (const char *ctxt_progname)
3415 : {
3416 1118 : JIT_LOG_SCOPE (get_logger ());
3417 :
3418 1118 : invoke_driver (ctxt_progname,
3419 1118 : m_tempdir->get_path_s_file (),
3420 1118 : m_tempdir->get_path_so_file (),
3421 : TV_ASSEMBLE,
3422 : true, /* bool shared, */
3423 : true);/* bool run_linker */
3424 1118 : }
3425 :
3426 : static const char * const gcc_driver_name = GCC_DRIVER_NAME;
3427 :
3428 : void
3429 1139 : playback::context::
3430 : invoke_driver (const char *ctxt_progname,
3431 : const char *input_file,
3432 : const char *output_file,
3433 : timevar_id_t tv_id,
3434 : bool shared,
3435 : bool run_linker)
3436 : {
3437 1139 : JIT_LOG_SCOPE (get_logger ());
3438 :
3439 1139 : bool embedded_driver
3440 1139 : = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
3441 :
3442 : /* Currently this lumps together both assembling and linking into
3443 : TV_ASSEMBLE. */
3444 1139 : auto_timevar assemble_timevar (get_timer (), tv_id);
3445 1139 : auto_string_vec argvec;
3446 : #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
3447 :
3448 1139 : ADD_ARG (gcc_driver_name);
3449 :
3450 1139 : add_multilib_driver_arguments (&argvec);
3451 :
3452 1139 : if (shared)
3453 1123 : ADD_ARG ("-shared");
3454 :
3455 1139 : if (!run_linker)
3456 5 : ADD_ARG ("-c");
3457 :
3458 1139 : ADD_ARG (input_file);
3459 1139 : ADD_ARG ("-o");
3460 1139 : ADD_ARG (output_file);
3461 :
3462 : /* Don't use the linker plugin.
3463 : If running with just a "make" and not a "make install", then we'd
3464 : run into
3465 : "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
3466 : libto_plugin is a .la at build time, with it becoming installed with
3467 : ".so" suffix: i.e. it doesn't exist with a .so suffix until install
3468 : time. */
3469 1139 : ADD_ARG ("-fno-use-linker-plugin");
3470 :
3471 : #if defined (DARWIN_X86) || defined (DARWIN_PPC)
3472 : /* macOS's linker defaults to treating undefined symbols as errors.
3473 : If the context has any imported functions or globals they will be
3474 : undefined until the .so is dynamically-linked into the process.
3475 : Ensure that the driver passes in "-undefined dynamic_lookup" to the
3476 : linker. */
3477 : ADD_ARG ("-Wl,-undefined,dynamic_lookup");
3478 : #endif
3479 :
3480 1139 : if (0)
3481 : ADD_ARG ("-v");
3482 :
3483 : /* Add any user-provided driver extra options. */
3484 :
3485 1139 : m_recording_ctxt->append_driver_options (&argvec);
3486 :
3487 : #undef ADD_ARG
3488 :
3489 : /* pex_one's error-handling requires pname to be non-NULL. */
3490 1139 : gcc_assert (ctxt_progname);
3491 :
3492 1139 : if (get_logger ())
3493 3581 : for (unsigned i = 0; i < argvec.length (); i++)
3494 3134 : get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
3495 :
3496 1139 : if (embedded_driver)
3497 1134 : invoke_embedded_driver (&argvec);
3498 : else
3499 5 : invoke_external_driver (ctxt_progname, &argvec);
3500 1139 : }
3501 :
3502 : void
3503 1134 : playback::context::
3504 : invoke_embedded_driver (const vec <char *> *argvec)
3505 : {
3506 1134 : JIT_LOG_SCOPE (get_logger ());
3507 1134 : driver d (true, /* can_finalize */
3508 1134 : false); /* debug */
3509 2268 : int result = d.main (argvec->length (),
3510 1134 : const_cast <char **> (argvec->address ()));
3511 1134 : d.finalize ();
3512 1134 : if (result)
3513 0 : add_error (NULL, "error invoking gcc driver");
3514 1134 : }
3515 :
3516 : void
3517 5 : playback::context::
3518 : invoke_external_driver (const char *ctxt_progname,
3519 : vec <char *> *argvec)
3520 : {
3521 5 : JIT_LOG_SCOPE (get_logger ());
3522 5 : const char *errmsg;
3523 5 : int exit_status = 0;
3524 5 : int err = 0;
3525 :
3526 : /* pex argv arrays are NULL-terminated. */
3527 5 : argvec->safe_push (NULL);
3528 :
3529 5 : errmsg = pex_one (PEX_SEARCH, /* int flags, */
3530 : gcc_driver_name,
3531 5 : const_cast <char *const *> (argvec->address ()),
3532 : ctxt_progname, /* const char *pname */
3533 : NULL, /* const char *outname */
3534 : NULL, /* const char *errname */
3535 : &exit_status, /* int *status */
3536 : &err); /* int *err*/
3537 5 : if (errmsg)
3538 : {
3539 5 : add_error (NULL, "error invoking gcc driver: %s", errmsg);
3540 5 : return;
3541 : }
3542 :
3543 : /* pex_one can return a NULL errmsg when the executable wasn't
3544 : found (or doesn't exist), so trap these cases also. */
3545 0 : if (exit_status || err)
3546 : {
3547 0 : add_error (NULL,
3548 : "error invoking gcc driver: exit_status: %i err: %i",
3549 : exit_status, err);
3550 0 : add_error (NULL,
3551 : "whilst attempting to run a driver named: %s",
3552 : gcc_driver_name);
3553 0 : add_error (NULL,
3554 : "PATH was: %s",
3555 : getenv ("PATH"));
3556 0 : return;
3557 : }
3558 5 : }
3559 :
3560 : /* Extract the target-specific MULTILIB_DEFAULTS to
3561 : multilib_defaults_raw for use by
3562 : playback::context::add_multilib_driver_arguments (). */
3563 :
3564 : #ifndef MULTILIB_DEFAULTS
3565 : #define MULTILIB_DEFAULTS { "" }
3566 : #endif
3567 :
3568 : static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
3569 :
3570 : /* Helper function for playback::context::invoke_driver ().
3571 :
3572 : 32-bit and 64-bit multilib peer builds of libgccjit.so may share
3573 : a driver binary. We need to pass in options to the shared driver
3574 : to get the appropriate assembler/linker options for this multilib
3575 : peer. */
3576 :
3577 : void
3578 1139 : playback::context::
3579 : add_multilib_driver_arguments (vec <char *> *argvec)
3580 : {
3581 1139 : JIT_LOG_SCOPE (get_logger ());
3582 :
3583 : /* Add copies of the arguments in multilib_defaults_raw to argvec,
3584 : prepending each with a "-". */
3585 2278 : for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
3586 1139 : if (multilib_defaults_raw[i][0])
3587 1139 : argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
3588 1139 : }
3589 :
3590 : /* Dynamically-link the built DSO file into this process, using dlopen.
3591 : Wrap it up within a jit::result *, and return that.
3592 : Return NULL if any errors occur, reporting them on this context. */
3593 :
3594 : result *
3595 1113 : playback::context::
3596 : dlopen_built_dso ()
3597 : {
3598 1113 : JIT_LOG_SCOPE (get_logger ());
3599 1113 : auto_timevar load_timevar (get_timer (), TV_LOAD);
3600 1113 : result::handle handle = NULL;
3601 1113 : result *result_obj = NULL;
3602 :
3603 : #ifdef _WIN32
3604 : /* Clear any existing error. */
3605 : SetLastError(0);
3606 :
3607 : handle = LoadLibrary(m_tempdir->get_path_so_file ());
3608 : if (GetLastError() != 0) {
3609 : print_last_error();
3610 : }
3611 : #else
3612 1113 : const char *error = NULL;
3613 : /* Clear any existing error. */
3614 1113 : dlerror ();
3615 :
3616 1113 : handle = dlopen (m_tempdir->get_path_so_file (),
3617 : RTLD_NOW | RTLD_LOCAL);
3618 1113 : if ((error = dlerror()) != NULL) {
3619 0 : add_error (NULL, "%s", error);
3620 : }
3621 : #endif
3622 :
3623 1113 : if (handle)
3624 : {
3625 : /* We've successfully dlopened the result; create a
3626 : jit::result object to wrap it.
3627 :
3628 : We're done with the tempdir for now, but if the user
3629 : has requested debugging, the user's debugger might not
3630 : be capable of dealing with the .so file being unlinked
3631 : immediately, so keep it around until after the result
3632 : is released. We do this by handing over ownership of
3633 : the jit::tempdir to the result. See PR jit/64206. */
3634 1113 : tempdir *handover_tempdir;
3635 1113 : if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
3636 : {
3637 706 : handover_tempdir = m_tempdir;
3638 706 : m_tempdir = NULL;
3639 : /* The tempdir will eventually be cleaned up in the
3640 : jit::result's dtor. */
3641 706 : log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
3642 : " handing over tempdir to jit::result");
3643 : }
3644 : else
3645 : {
3646 407 : handover_tempdir = NULL;
3647 : /* ... and retain ownership of m_tempdir so we clean it
3648 : up it the playback::context's dtor. */
3649 407 : log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
3650 : " retaining ownership of tempdir");
3651 : }
3652 :
3653 1113 : result_obj = new result (get_logger (), handle, handover_tempdir);
3654 : }
3655 : else
3656 : result_obj = NULL;
3657 :
3658 2226 : return result_obj;
3659 1113 : }
3660 :
3661 : /* Top-level hook for playing back a recording context.
3662 :
3663 : This plays back m_recording_ctxt, and, if no errors
3664 : occurred builds statement lists for and then postprocesses
3665 : every function in the result. */
3666 :
3667 : void
3668 1326 : playback::context::
3669 : replay ()
3670 : {
3671 1326 : JIT_LOG_SCOPE (get_logger ());
3672 :
3673 1326 : init_types ();
3674 1326 : jit_target_init ();
3675 :
3676 : /* Replay the recorded events: */
3677 1326 : timevar_push (TV_JIT_REPLAY);
3678 :
3679 : /* Ensure that builtins that could be needed during optimization
3680 : get created ahead of time. */
3681 1326 : builtins_manager *bm = m_recording_ctxt->get_builtins_manager ();
3682 1326 : bm->ensure_optimization_builtins_exist ();
3683 :
3684 1326 : m_recording_ctxt->replay_into (this);
3685 :
3686 : /* Clean away the temporary references from recording objects
3687 : to playback objects. We have to do this now since the
3688 : latter are GC-allocated, but the former don't mark these
3689 : refs. Hence we must stop using them before the GC can run. */
3690 1326 : m_recording_ctxt->disassociate_from_playback ();
3691 :
3692 : /* The builtins_manager is associated with the recording::context
3693 : and might be reused for future compiles on other playback::contexts,
3694 : but its m_attributes array is not GTY-labeled and hence will become
3695 : nonsense if the GC runs. Purge this state. */
3696 1326 : bm->finish_playback ();
3697 :
3698 1326 : timevar_pop (TV_JIT_REPLAY);
3699 :
3700 1326 : if (!errors_occurred ())
3701 : {
3702 1291 : int i;
3703 1291 : function *func;
3704 1291 : tree global;
3705 : /* No GC can happen yet; process the cached source locations. */
3706 1291 : handle_locations ();
3707 :
3708 : /* Finalize globals. See how FORTRAN 95 does it in gfc_be_parse_file()
3709 : for a simple reference. */
3710 3613 : FOR_EACH_VEC_ELT (m_globals, i, global)
3711 1031 : rest_of_decl_compilation (global, true, true);
3712 :
3713 1427 : wrapup_global_declarations (m_globals.address(), m_globals.length());
3714 :
3715 : /* We've now created tree nodes for the stmts in the various blocks
3716 : in each function, but we haven't built each function's single stmt
3717 : list yet. Do so now. */
3718 19234 : FOR_EACH_VEC_ELT (m_functions, i, func)
3719 16652 : func->build_stmt_list ();
3720 :
3721 : /* No GC can have happened yet. */
3722 :
3723 : /* Postprocess the functions. This could trigger GC. */
3724 17943 : FOR_EACH_VEC_ELT (m_functions, i, func)
3725 : {
3726 16652 : gcc_assert (func);
3727 16652 : func->postprocess ();
3728 : }
3729 : }
3730 1326 : }
3731 :
3732 : /* Dump the generated .s file to stderr. */
3733 :
3734 : void
3735 0 : playback::context::
3736 : dump_generated_code ()
3737 : {
3738 0 : JIT_LOG_SCOPE (get_logger ());
3739 0 : char buf[4096];
3740 0 : size_t sz;
3741 0 : FILE *f_in = fopen (get_path_s_file (), "r");
3742 0 : if (!f_in)
3743 0 : return;
3744 :
3745 0 : while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
3746 0 : fwrite (buf, 1, sz, stderr);
3747 :
3748 0 : fclose (f_in);
3749 0 : }
3750 :
3751 : /* Get the supposed path of the notional "fake.c" file within the
3752 : tempdir. This file doesn't exist, but the rest of the compiler
3753 : needs a name. */
3754 :
3755 : const char *
3756 1331 : playback::context::
3757 : get_path_c_file () const
3758 : {
3759 1331 : return m_tempdir->get_path_c_file ();
3760 : }
3761 :
3762 : /* Get the path of the assembler output file "fake.s" file within the
3763 : tempdir. */
3764 :
3765 : const char *
3766 0 : playback::context::
3767 : get_path_s_file () const
3768 : {
3769 0 : return m_tempdir->get_path_s_file ();
3770 : }
3771 :
3772 : /* Get the path of the DSO object file "fake.so" file within the
3773 : tempdir. */
3774 :
3775 : const char *
3776 0 : playback::context::
3777 : get_path_so_file () const
3778 : {
3779 0 : return m_tempdir->get_path_so_file ();
3780 : }
3781 :
3782 : /* qsort comparator for comparing pairs of playback::source_line *,
3783 : ordering them by line number. */
3784 :
3785 : static int
3786 5518 : line_comparator (const void *lhs, const void *rhs)
3787 : {
3788 5518 : const playback::source_line *line_lhs = \
3789 : *static_cast<const playback::source_line * const*> (lhs);
3790 5518 : const playback::source_line *line_rhs = \
3791 : *static_cast<const playback::source_line * const*> (rhs);
3792 5518 : return line_lhs->get_line_num () - line_rhs->get_line_num ();
3793 : }
3794 :
3795 : /* qsort comparator for comparing pairs of playback::location *,
3796 : ordering them by column number. */
3797 :
3798 : static int
3799 6713 : location_comparator (const void *lhs, const void *rhs)
3800 : {
3801 6713 : const playback::location *loc_lhs = \
3802 : *static_cast<const playback::location * const *> (lhs);
3803 6713 : const playback::location *loc_rhs = \
3804 : *static_cast<const playback::location * const *> (rhs);
3805 6713 : return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
3806 : }
3807 :
3808 : /* Initialize the NAME_TYPE of the primitive types as well as some
3809 : others. */
3810 : void
3811 1326 : playback::context::
3812 : init_types ()
3813 : {
3814 : /* See lto_init () in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc
3815 : for reference. If TYPE_NAME is not set, debug info will not contain types */
3816 : #define NAME_TYPE(t,n) \
3817 : if (t) \
3818 : TYPE_NAME (t) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, \
3819 : get_identifier (n), t)
3820 :
3821 1326 : NAME_TYPE (integer_type_node, "int");
3822 1326 : NAME_TYPE (char_type_node, "char");
3823 1326 : NAME_TYPE (long_integer_type_node, "long int");
3824 1326 : NAME_TYPE (unsigned_type_node, "unsigned int");
3825 1326 : NAME_TYPE (long_unsigned_type_node, "long unsigned int");
3826 1326 : NAME_TYPE (long_long_integer_type_node, "long long int");
3827 1326 : NAME_TYPE (long_long_unsigned_type_node, "long long unsigned int");
3828 1326 : NAME_TYPE (short_integer_type_node, "short int");
3829 1326 : NAME_TYPE (short_unsigned_type_node, "short unsigned int");
3830 1326 : if (signed_char_type_node != char_type_node)
3831 1326 : NAME_TYPE (signed_char_type_node, "signed char");
3832 1326 : if (unsigned_char_type_node != char_type_node)
3833 1326 : NAME_TYPE (unsigned_char_type_node, "unsigned char");
3834 1326 : NAME_TYPE (float_type_node, "float");
3835 1326 : NAME_TYPE (double_type_node, "double");
3836 1326 : NAME_TYPE (long_double_type_node, "long double");
3837 1326 : NAME_TYPE (void_type_node, "void");
3838 1326 : NAME_TYPE (boolean_type_node, "bool");
3839 1326 : NAME_TYPE (complex_float_type_node, "complex float");
3840 1326 : NAME_TYPE (complex_double_type_node, "complex double");
3841 1326 : NAME_TYPE (complex_long_double_type_node, "complex long double");
3842 :
3843 1326 : m_const_char_ptr = build_pointer_type(
3844 : build_qualified_type (char_type_node, TYPE_QUAL_CONST));
3845 :
3846 1326 : NAME_TYPE (m_const_char_ptr, "char");
3847 1326 : NAME_TYPE (size_type_node, "size_t");
3848 1326 : NAME_TYPE (fileptr_type_node, "FILE");
3849 : #undef NAME_TYPE
3850 1326 : }
3851 :
3852 : /* Our API allows locations to be created in arbitrary orders, but the
3853 : linemap API requires locations to be created in ascending order
3854 : as if we were tokenizing files.
3855 :
3856 : This hook sorts all of the locations that have been created, and
3857 : calls into the linemap API, creating linemap entries in sorted order
3858 : for our locations. */
3859 :
3860 : void
3861 1291 : playback::context::
3862 : handle_locations ()
3863 : {
3864 : /* Create the source code locations, following the ordering rules
3865 : imposed by the linemap API.
3866 :
3867 : line_table is a global. */
3868 1291 : JIT_LOG_SCOPE (get_logger ());
3869 1291 : int i;
3870 1291 : source_file *file;
3871 :
3872 1353 : FOR_EACH_VEC_ELT (m_source_files, i, file)
3873 : {
3874 62 : linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
3875 :
3876 : /* Sort lines by ascending line numbers. */
3877 62 : file->m_source_lines.qsort (&line_comparator);
3878 :
3879 : int j;
3880 : source_line *line;
3881 455 : FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
3882 : {
3883 393 : int k;
3884 393 : location *loc;
3885 :
3886 : /* Sort locations in line by ascending column numbers. */
3887 393 : line->m_locations.qsort (&location_comparator);
3888 :
3889 : /* Determine maximum column within this line. */
3890 393 : gcc_assert (line->m_locations.length () > 0);
3891 393 : location *final_column =
3892 393 : line->m_locations[line->m_locations.length () - 1];
3893 393 : int max_col = final_column->get_column_num ();
3894 :
3895 393 : linemap_line_start (line_table, line->get_line_num (), max_col);
3896 1916 : FOR_EACH_VEC_ELT (line->m_locations, k, loc)
3897 : {
3898 737 : loc->m_srcloc = \
3899 737 : linemap_position_for_column (line_table, loc->get_column_num ());
3900 : }
3901 : }
3902 :
3903 62 : linemap_add (line_table, LC_LEAVE, false, NULL, 0);
3904 : }
3905 :
3906 : /* line_table should now be populated; every playback::location should
3907 : now have an m_srcloc. */
3908 :
3909 : /* Now assign them to tree nodes as appropriate. */
3910 : std::pair<tree, location *> *cached_location;
3911 :
3912 2851 : FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
3913 : {
3914 1560 : tree t = cached_location->first;
3915 1560 : location_t srcloc = cached_location->second->m_srcloc;
3916 :
3917 : /* This covers expressions: */
3918 1560 : if (CAN_HAVE_LOCATION_P (t))
3919 1449 : SET_EXPR_LOCATION (t, srcloc);
3920 111 : else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
3921 111 : DECL_SOURCE_LOCATION (t) = srcloc;
3922 : else
3923 : {
3924 : /* Don't know how to set location on this node. */
3925 : }
3926 : }
3927 1291 : }
3928 :
3929 : /* We handle errors on a playback::context by adding them to the
3930 : corresponding recording::context. */
3931 :
3932 : void
3933 45 : playback::context::
3934 : add_error (location *loc, const char *fmt, ...)
3935 : {
3936 45 : va_list ap;
3937 45 : va_start (ap, fmt);
3938 45 : m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
3939 : diagnostics::kind::error, fmt, ap);
3940 45 : va_end (ap);
3941 45 : }
3942 :
3943 : /* We handle errors on a playback::context by adding them to the
3944 : corresponding recording::context. */
3945 :
3946 : void
3947 0 : playback::context::
3948 : add_error_va (location *loc, const char *fmt, va_list ap)
3949 : {
3950 0 : m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
3951 : diagnostics::kind::error, fmt, ap);
3952 0 : }
3953 :
3954 : /* Report a diagnostic up to the jit context, so that the
3955 : compilation is treated as a failure if the diagnostic
3956 : is an error. */
3957 :
3958 : void
3959 25 : playback::context::
3960 : add_diagnostic (const char *text,
3961 : const diagnostics::diagnostic_info &diagnostic)
3962 : {
3963 : /* Get location information (if any) from the diagnostic.
3964 : The recording::context::add_error[_va] methods require a
3965 : recording::location. We can't lookup the playback::location
3966 : from the file/line/column since any playback location instances
3967 : may have been garbage-collected away by now, so instead we create
3968 : another recording::location directly. */
3969 25 : location_t gcc_loc = diagnostic_location (&diagnostic);
3970 25 : recording::location *rec_loc = NULL;
3971 25 : if (gcc_loc)
3972 : {
3973 10 : expanded_location exploc = expand_location (gcc_loc);
3974 10 : if (exploc.file)
3975 5 : rec_loc = m_recording_ctxt->new_location (exploc.file,
3976 : exploc.line,
3977 : exploc.column,
3978 : false);
3979 : }
3980 :
3981 25 : m_recording_ctxt->add_diagnostic (rec_loc, diagnostic.m_kind, "%s", text);
3982 25 : }
3983 :
3984 : /* Dealing with the linemap API. */
3985 :
3986 : /* Construct a playback::location for a recording::location, if it
3987 : doesn't exist already. */
3988 :
3989 : playback::location *
3990 965 : playback::context::
3991 : new_location (recording::location *rloc,
3992 : const char *filename,
3993 : int line,
3994 : int column)
3995 : {
3996 : /* Get the source_file for filename, creating if necessary. */
3997 965 : source_file *src_file = get_source_file (filename);
3998 : /* Likewise for the line within the file. */
3999 965 : source_line *src_line = src_file->get_source_line (line);
4000 : /* Likewise for the column within the line. */
4001 965 : location *loc = src_line->get_location (rloc, column);
4002 965 : return loc;
4003 : }
4004 :
4005 : /* Deferred setting of the location for a given tree, by adding the
4006 : (tree, playback::location) pair to a list of deferred associations.
4007 : We will actually set the location on the tree later on once
4008 : the location_t for the playback::location exists. */
4009 :
4010 : void
4011 1560 : playback::context::
4012 : set_tree_location (tree t, location *loc)
4013 : {
4014 1560 : gcc_assert (loc);
4015 1560 : m_cached_locations.safe_push (std::make_pair (t, loc));
4016 1560 : }
4017 :
4018 :
4019 : /* Construct a playback::source_file for the given source
4020 : filename, if it doesn't exist already. */
4021 :
4022 : playback::source_file *
4023 965 : playback::context::
4024 : get_source_file (const char *filename)
4025 : {
4026 : /* Locate the file.
4027 : For simplicitly, this is currently a linear search.
4028 : Replace with a hash if this shows up in the profile. */
4029 965 : int i;
4030 965 : source_file *file;
4031 965 : tree ident_filename = get_identifier (filename);
4032 :
4033 2698 : FOR_EACH_VEC_ELT (m_source_files, i, file)
4034 1671 : if (file->filename_as_tree () == ident_filename)
4035 : return file;
4036 :
4037 : /* Not found. */
4038 62 : file = new source_file (ident_filename);
4039 62 : m_source_files.safe_push (file);
4040 62 : return file;
4041 : }
4042 :
4043 : /* Constructor for gcc::jit::playback::source_file. */
4044 :
4045 62 : playback::source_file::source_file (tree filename) :
4046 62 : m_source_lines (),
4047 62 : m_filename (filename)
4048 : {
4049 62 : }
4050 :
4051 : /* Don't leak vec's internal buffer (in non-GC heap) when we are
4052 : GC-ed. */
4053 :
4054 : void
4055 56 : playback::source_file::finalizer ()
4056 : {
4057 56 : m_source_lines.release ();
4058 56 : }
4059 :
4060 : /* Construct a playback::source_line for the given line
4061 : within this source file, if one doesn't exist already. */
4062 :
4063 : playback::source_line *
4064 965 : playback::source_file::
4065 : get_source_line (int line_num)
4066 : {
4067 : /* Locate the line.
4068 : For simplicitly, this is currently a linear search.
4069 : Replace with a hash if this shows up in the profile. */
4070 965 : int i;
4071 965 : source_line *line;
4072 :
4073 7404 : FOR_EACH_VEC_ELT (m_source_lines, i, line)
4074 7011 : if (line->get_line_num () == line_num)
4075 : return line;
4076 :
4077 : /* Not found. */
4078 393 : line = new source_line (this, line_num);
4079 393 : m_source_lines.safe_push (line);
4080 393 : return line;
4081 : }
4082 :
4083 : /* Constructor for gcc::jit::playback::source_line. */
4084 :
4085 393 : playback::source_line::source_line (source_file *file, int line_num) :
4086 393 : m_locations (),
4087 393 : m_source_file (file),
4088 393 : m_line_num (line_num)
4089 : {
4090 393 : }
4091 :
4092 : /* Don't leak vec's internal buffer (in non-GC heap) when we are
4093 : GC-ed. */
4094 :
4095 : void
4096 324 : playback::source_line::finalizer ()
4097 : {
4098 324 : m_locations.release ();
4099 324 : }
4100 :
4101 : /* Construct a playback::location for the given column
4102 : within this line of a specific source file, if one doesn't exist
4103 : already. */
4104 :
4105 : playback::location *
4106 965 : playback::source_line::
4107 : get_location (recording::location *rloc, int column_num)
4108 : {
4109 965 : int i;
4110 965 : location *loc;
4111 :
4112 : /* Another linear search that probably should be a hash table. */
4113 5376 : FOR_EACH_VEC_ELT (m_locations, i, loc)
4114 4639 : if (loc->get_column_num () == column_num)
4115 : return loc;
4116 :
4117 : /* Not found. */
4118 737 : loc = new location (rloc, this, column_num);
4119 737 : m_locations.safe_push (loc);
4120 737 : return loc;
4121 : }
4122 :
4123 : /* Constructor for gcc::jit::playback::location. */
4124 :
4125 737 : playback::location::location (recording::location *loc,
4126 : source_line *line,
4127 737 : int column_num) :
4128 737 : m_srcloc (UNKNOWN_LOCATION),
4129 737 : m_recording_loc (loc),
4130 737 : m_line (line),
4131 737 : m_column_num(column_num)
4132 : {
4133 737 : }
4134 :
4135 : /* The active gcc::jit::playback::context instance. This is a singleton,
4136 : guarded by jit_mutex. */
4137 :
4138 : playback::context *active_playback_ctxt;
4139 :
4140 : } // namespace gcc::jit
4141 :
4142 : } // namespace gcc
|