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