1 /* Internals of libgccjit: classes for playing back recorded API calls. 2 Copyright (C) 2013-2021 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 #ifndef JIT_PLAYBACK_H 22 #define JIT_PLAYBACK_H 23 24 #include <utility> // for std::pair 25 26 #include "timevar.h" 27 28 #include "jit-recording.h" 29 30 struct diagnostic_context; 31 struct diagnostic_info; 32 33 namespace gcc { 34 35 namespace jit { 36 37 /********************************************************************** 38 Playback. 39 **********************************************************************/ 40 41 namespace playback { 42 43 /* playback::context is an abstract base class. 44 45 The two concrete subclasses are: 46 - playback::compile_to_memory 47 - playback::compile_to_file. */ 48 49 class context : public log_user 50 { 51 public: 52 context (::gcc::jit::recording::context *ctxt); 53 ~context (); 54 55 void gt_ggc_mx (); 56 57 void replay (); 58 59 location * 60 new_location (recording::location *rloc, 61 const char *filename, 62 int line, 63 int column); 64 65 type * 66 get_type (enum gcc_jit_types type); 67 68 type * 69 new_array_type (location *loc, 70 type *element_type, 71 int num_elements); 72 73 field * 74 new_field (location *loc, 75 type *type, 76 const char *name); 77 78 field * 79 new_bitfield (location *loc, 80 type *type, 81 int width, 82 const char *name); 83 84 compound_type * 85 new_compound_type (location *loc, 86 const char *name, 87 bool is_struct); /* else is union */ 88 89 type * 90 new_function_type (type *return_type, 91 const auto_vec<type *> *param_types, 92 int is_variadic); 93 94 param * 95 new_param (location *loc, 96 type *type, 97 const char *name); 98 99 function * 100 new_function (location *loc, 101 enum gcc_jit_function_kind kind, 102 type *return_type, 103 const char *name, 104 const auto_vec<param *> *params, 105 int is_variadic, 106 enum built_in_function builtin_id); 107 108 lvalue * 109 new_global (location *loc, 110 enum gcc_jit_global_kind kind, 111 type *type, 112 const char *name); 113 114 lvalue * 115 new_global_initialized (location *loc, 116 enum gcc_jit_global_kind kind, 117 type *type, 118 size_t element_size, 119 size_t initializer_num_elem, 120 const void *initializer, 121 const char *name); 122 123 template <typename HOST_TYPE> 124 rvalue * 125 new_rvalue_from_const (type *type, 126 HOST_TYPE value); 127 128 rvalue * 129 new_string_literal (const char *value); 130 131 rvalue * 132 new_rvalue_from_vector (location *loc, 133 type *type, 134 const auto_vec<rvalue *> &elements); 135 136 rvalue * 137 new_unary_op (location *loc, 138 enum gcc_jit_unary_op op, 139 type *result_type, 140 rvalue *a); 141 142 rvalue * 143 new_binary_op (location *loc, 144 enum gcc_jit_binary_op op, 145 type *result_type, 146 rvalue *a, rvalue *b); 147 148 rvalue * 149 new_comparison (location *loc, 150 enum gcc_jit_comparison op, 151 rvalue *a, rvalue *b); 152 153 rvalue * 154 new_call (location *loc, 155 function *func, 156 const auto_vec<rvalue *> *args, 157 bool require_tail_call); 158 159 rvalue * 160 new_call_through_ptr (location *loc, 161 rvalue *fn_ptr, 162 const auto_vec<rvalue *> *args, 163 bool require_tail_call); 164 165 rvalue * 166 new_cast (location *loc, 167 rvalue *expr, 168 type *type_); 169 170 lvalue * 171 new_array_access (location *loc, 172 rvalue *ptr, 173 rvalue *index); 174 175 void 176 set_str_option (enum gcc_jit_str_option opt, 177 const char *value); 178 179 void 180 set_int_option (enum gcc_jit_int_option opt, 181 int value); 182 183 void 184 set_bool_option (enum gcc_jit_bool_option opt, 185 int value); 186 187 const char * get_str_option(enum gcc_jit_str_option opt)188 get_str_option (enum gcc_jit_str_option opt) const 189 { 190 return m_recording_ctxt->get_str_option (opt); 191 } 192 193 int get_int_option(enum gcc_jit_int_option opt)194 get_int_option (enum gcc_jit_int_option opt) const 195 { 196 return m_recording_ctxt->get_int_option (opt); 197 } 198 199 int get_bool_option(enum gcc_jit_bool_option opt)200 get_bool_option (enum gcc_jit_bool_option opt) const 201 { 202 return m_recording_ctxt->get_bool_option (opt); 203 } 204 205 int get_inner_bool_option(enum inner_bool_option opt)206 get_inner_bool_option (enum inner_bool_option opt) const 207 { 208 return m_recording_ctxt->get_inner_bool_option (opt); 209 } 210 get_builtins_manager()211 builtins_manager *get_builtins_manager () const 212 { 213 return m_recording_ctxt->get_builtins_manager (); 214 } 215 216 void 217 compile (); 218 219 void 220 add_error (location *loc, const char *fmt, ...) 221 GNU_PRINTF(3, 4); 222 223 void 224 add_error_va (location *loc, const char *fmt, va_list ap) 225 GNU_PRINTF(3, 0); 226 227 const char * 228 get_first_error () const; 229 230 void 231 add_diagnostic (struct diagnostic_context *context, 232 struct diagnostic_info *diagnostic); 233 234 void 235 set_tree_location (tree t, location *loc); 236 237 tree 238 new_field_access (location *loc, 239 tree datum, 240 field *field); 241 242 tree 243 new_dereference (tree ptr, location *loc); 244 245 tree 246 as_truth_value (tree expr, location *loc); 247 errors_occurred()248 bool errors_occurred () const 249 { 250 return m_recording_ctxt->errors_occurred (); 251 } 252 get_timer()253 timer *get_timer () const { return m_recording_ctxt->get_timer (); } 254 255 void add_top_level_asm (const char *asm_stmts); 256 257 private: 258 void dump_generated_code (); 259 260 rvalue * 261 build_call (location *loc, 262 tree fn_ptr, 263 const auto_vec<rvalue *> *args, 264 bool require_tail_call); 265 266 tree 267 build_cast (location *loc, 268 rvalue *expr, 269 type *type_); 270 271 source_file * 272 get_source_file (const char *filename); 273 274 tree 275 get_tree_node_for_type (enum gcc_jit_types type_); 276 277 void handle_locations (); 278 279 void init_types (); 280 281 const char * get_path_c_file () const; 282 const char * get_path_s_file () const; 283 const char * get_path_so_file () const; 284 285 tree 286 global_new_decl (location *loc, 287 enum gcc_jit_global_kind kind, 288 type *type, 289 const char *name); 290 lvalue * 291 global_finalize_lvalue (tree inner); 292 293 private: 294 295 /* Functions for implementing "compile". */ 296 297 void acquire_mutex (); 298 void release_mutex (); 299 300 void 301 make_fake_args (vec <char *> *argvec, 302 const char *ctxt_progname, 303 vec <recording::requested_dump> *requested_dumps); 304 305 void 306 extract_any_requested_dumps 307 (vec <recording::requested_dump> *requested_dumps); 308 309 char * 310 read_dump_file (const char *path); 311 312 virtual void postprocess (const char *ctxt_progname) = 0; 313 314 protected: get_tempdir()315 tempdir *get_tempdir () { return m_tempdir; } 316 317 void 318 convert_to_dso (const char *ctxt_progname); 319 320 void 321 invoke_driver (const char *ctxt_progname, 322 const char *input_file, 323 const char *output_file, 324 timevar_id_t tv_id, 325 bool shared, 326 bool run_linker); 327 328 void 329 add_multilib_driver_arguments (vec <char *> *argvec); 330 331 result * 332 dlopen_built_dso (); 333 334 private: 335 void 336 invoke_embedded_driver (const vec <char *> *argvec); 337 338 void 339 invoke_external_driver (const char *ctxt_progname, 340 vec <char *> *argvec); 341 342 private: 343 ::gcc::jit::recording::context *m_recording_ctxt; 344 345 tempdir *m_tempdir; 346 347 auto_vec<function *> m_functions; 348 auto_vec<tree> m_globals; 349 tree m_const_char_ptr; 350 351 /* Source location handling. */ 352 auto_vec<source_file *> m_source_files; 353 354 auto_vec<std::pair<tree, location *> > m_cached_locations; 355 }; 356 357 class compile_to_memory : public context 358 { 359 public: 360 compile_to_memory (recording::context *ctxt); 361 void postprocess (const char *ctxt_progname) FINAL OVERRIDE; 362 get_result_obj()363 result *get_result_obj () const { return m_result; } 364 365 private: 366 result *m_result; 367 }; 368 369 class compile_to_file : public context 370 { 371 public: 372 compile_to_file (recording::context *ctxt, 373 enum gcc_jit_output_kind output_kind, 374 const char *output_path); 375 void postprocess (const char *ctxt_progname) FINAL OVERRIDE; 376 377 private: 378 void 379 copy_file (const char *src_path, 380 const char *dst_path); 381 382 private: 383 enum gcc_jit_output_kind m_output_kind; 384 const char *m_output_path; 385 }; 386 387 388 /* A temporary wrapper object. 389 These objects are (mostly) only valid during replay. 390 We allocate them on the GC heap, so that they will be cleaned 391 the next time the GC collects. 392 The exception is the "function" class, which is tracked and marked by 393 the jit::context, since it needs to stay alive during post-processing 394 (when the GC could run). */ 395 class wrapper 396 { 397 public: 398 /* Allocate in the GC heap. */ 399 void *operator new (size_t sz); 400 401 /* Some wrapper subclasses contain vec<> and so need to 402 release them when they are GC-ed. */ finalizer()403 virtual void finalizer () { } 404 405 }; 406 407 class type : public wrapper 408 { 409 public: type(tree inner)410 type (tree inner) 411 : m_inner(inner) 412 {} 413 as_tree()414 tree as_tree () const { return m_inner; } 415 get_pointer()416 type *get_pointer () const { return new type (build_pointer_type (m_inner)); } 417 get_const()418 type *get_const () const 419 { 420 return new type (build_qualified_type (m_inner, TYPE_QUAL_CONST)); 421 } 422 get_volatile()423 type *get_volatile () const 424 { 425 return new type (build_qualified_type (m_inner, TYPE_QUAL_VOLATILE)); 426 } 427 428 type *get_aligned (size_t alignment_in_bytes) const; 429 type *get_vector (size_t num_units) const; 430 431 private: 432 tree m_inner; 433 }; 434 435 class compound_type : public type 436 { 437 public: compound_type(tree inner)438 compound_type (tree inner) 439 : type (inner) 440 {} 441 442 void set_fields (const auto_vec<field *> *fields); 443 }; 444 445 class field : public wrapper 446 { 447 public: field(tree inner)448 field (tree inner) 449 : m_inner(inner) 450 {} 451 as_tree()452 tree as_tree () const { return m_inner; } 453 454 private: 455 tree m_inner; 456 }; 457 458 class bitfield : public field {}; 459 460 class function : public wrapper 461 { 462 public: 463 function(context *ctxt, tree fndecl, enum gcc_jit_function_kind kind); 464 465 void gt_ggc_mx (); 466 void finalizer () FINAL OVERRIDE; 467 468 tree get_return_type_as_tree () const; 469 as_fndecl()470 tree as_fndecl () const { return m_inner_fndecl; } 471 get_kind()472 enum gcc_jit_function_kind get_kind () const { return m_kind; } 473 474 lvalue * 475 new_local (location *loc, 476 type *type, 477 const char *name); 478 479 block* 480 new_block (const char *name); 481 482 rvalue * 483 get_address (location *loc); 484 485 void 486 build_stmt_list (); 487 488 void 489 postprocess (); 490 491 public: 492 context *m_ctxt; 493 494 public: 495 void set_tree_location(tree t,location * loc)496 set_tree_location (tree t, location *loc) 497 { 498 m_ctxt->set_tree_location (t, loc); 499 } 500 501 private: 502 tree m_inner_fndecl; 503 tree m_inner_block; 504 tree m_inner_bind_expr; 505 enum gcc_jit_function_kind m_kind; 506 tree m_stmt_list; 507 tree_stmt_iterator m_stmt_iter; 508 vec<block *> m_blocks; 509 }; 510 511 struct case_ 512 { case_case_513 case_ (rvalue *min_value, rvalue *max_value, block *dest_block) 514 : m_min_value (min_value), 515 m_max_value (max_value), 516 m_dest_block (dest_block) 517 {} 518 519 rvalue *m_min_value; 520 rvalue *m_max_value; 521 block *m_dest_block; 522 }; 523 524 struct asm_operand 525 { asm_operandasm_operand526 asm_operand (const char *asm_symbolic_name, 527 const char *constraint, 528 tree expr) 529 : m_asm_symbolic_name (asm_symbolic_name), 530 m_constraint (constraint), 531 m_expr (expr) 532 {} 533 534 const char *m_asm_symbolic_name; 535 const char *m_constraint; 536 tree m_expr; 537 }; 538 539 class block : public wrapper 540 { 541 public: 542 block (function *func, 543 const char *name); 544 545 void finalizer () FINAL OVERRIDE; 546 as_label_decl()547 tree as_label_decl () const { return m_label_decl; } 548 get_function()549 function *get_function () const { return m_func; } 550 551 void 552 add_eval (location *loc, 553 rvalue *rvalue); 554 555 void 556 add_assignment (location *loc, 557 lvalue *lvalue, 558 rvalue *rvalue); 559 560 void 561 add_comment (location *loc, 562 const char *text); 563 564 void 565 add_conditional (location *loc, 566 rvalue *boolval, 567 block *on_true, 568 block *on_false); 569 570 block * 571 add_block (location *loc, 572 const char *name); 573 574 void 575 add_jump (location *loc, 576 block *target); 577 578 void 579 add_return (location *loc, 580 rvalue *rvalue); 581 582 void 583 add_switch (location *loc, 584 rvalue *expr, 585 block *default_block, 586 const auto_vec <case_> *cases); 587 588 void 589 add_extended_asm (location *loc, 590 const char *asm_template, 591 bool is_volatile, 592 bool is_inline, 593 const auto_vec <asm_operand> *outputs, 594 const auto_vec <asm_operand> *inputs, 595 const auto_vec <const char *> *clobbers, 596 const auto_vec <block *> *goto_blocks); 597 598 private: 599 void set_tree_location(tree t,location * loc)600 set_tree_location (tree t, location *loc) 601 { 602 m_func->set_tree_location (t, loc); 603 } 604 add_stmt(tree stmt)605 void add_stmt (tree stmt) 606 { 607 /* TODO: use one stmt_list per block. */ 608 m_stmts.safe_push (stmt); 609 } 610 611 private: 612 function *m_func; 613 tree m_label_decl; 614 vec<tree> m_stmts; 615 616 public: // for now 617 tree m_label_expr; 618 619 friend class function; 620 }; 621 622 class rvalue : public wrapper 623 { 624 public: rvalue(context * ctxt,tree inner)625 rvalue (context *ctxt, tree inner) 626 : m_ctxt (ctxt), 627 m_inner (inner) 628 { 629 /* Pre-mark tree nodes with TREE_VISITED so that they can be 630 deeply unshared during gimplification (including across 631 functions); this requires LANG_HOOKS_DEEP_UNSHARING to be true. */ 632 TREE_VISITED (inner) = 1; 633 } 634 635 rvalue * as_rvalue()636 as_rvalue () { return this; } 637 as_tree()638 tree as_tree () const { return m_inner; } 639 get_context()640 context *get_context () const { return m_ctxt; } 641 642 type * get_type()643 get_type () { return new type (TREE_TYPE (m_inner)); } 644 645 rvalue * 646 access_field (location *loc, 647 field *field); 648 649 lvalue * 650 dereference_field (location *loc, 651 field *field); 652 653 lvalue * 654 dereference (location *loc); 655 656 private: 657 context *m_ctxt; 658 tree m_inner; 659 }; 660 661 class lvalue : public rvalue 662 { 663 public: lvalue(context * ctxt,tree inner)664 lvalue (context *ctxt, tree inner) 665 : rvalue(ctxt, inner) 666 {} 667 668 lvalue * as_lvalue()669 as_lvalue () { return this; } 670 671 lvalue * 672 access_field (location *loc, 673 field *field); 674 675 rvalue * 676 get_address (location *loc); 677 678 private: 679 bool mark_addressable (location *loc); 680 }; 681 682 class param : public lvalue 683 { 684 public: param(context * ctxt,tree inner)685 param (context *ctxt, tree inner) 686 : lvalue(ctxt, inner) 687 {} 688 }; 689 690 /* Dealing with the linemap API. 691 692 It appears that libcpp requires locations to be created as if by 693 a tokenizer, creating them by filename, in ascending order of 694 line/column, whereas our API doesn't impose any such constraints: 695 we allow client code to create locations in arbitrary orders. 696 697 To square this circle, we need to cache all location creation, 698 grouping things up by filename/line, and then creating the linemap 699 entries in a post-processing phase. */ 700 701 /* A set of locations, all sharing a filename */ 702 class source_file : public wrapper 703 { 704 public: 705 source_file (tree filename); 706 void finalizer () FINAL OVERRIDE; 707 708 source_line * 709 get_source_line (int line_num); 710 filename_as_tree()711 tree filename_as_tree () const { return m_filename; } 712 713 const char* get_filename()714 get_filename () const { return IDENTIFIER_POINTER (m_filename); } 715 716 vec<source_line *> m_source_lines; 717 718 private: 719 tree m_filename; 720 }; 721 722 /* A source line, with one or more locations of interest. */ 723 class source_line : public wrapper 724 { 725 public: 726 source_line (source_file *file, int line_num); 727 void finalizer () FINAL OVERRIDE; 728 729 location * 730 get_location (recording::location *rloc, int column_num); 731 get_line_num()732 int get_line_num () const { return m_line_num; } 733 734 vec<location *> m_locations; 735 736 private: 737 source_file *m_source_file; 738 int m_line_num; 739 }; 740 741 /* A specific location on a source line. This is what we expose 742 to the client API. */ 743 class location : public wrapper 744 { 745 public: 746 location (recording::location *loc, source_line *line, int column_num); 747 get_column_num()748 int get_column_num () const { return m_column_num; } 749 get_recording_loc()750 recording::location *get_recording_loc () const { return m_recording_loc; } 751 752 location_t m_srcloc; 753 754 private: 755 recording::location *m_recording_loc; 756 source_line *m_line; 757 int m_column_num; 758 }; 759 760 } // namespace gcc::jit::playback 761 762 extern playback::context *active_playback_ctxt; 763 764 } // namespace gcc::jit 765 766 } // namespace gcc 767 768 #endif /* JIT_PLAYBACK_H */ 769