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