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 void handle_locations (); 275 276 const char * get_path_c_file () const; 277 const char * get_path_s_file () const; 278 const char * get_path_so_file () const; 279 280 tree 281 global_new_decl (location *loc, 282 enum gcc_jit_global_kind kind, 283 type *type, 284 const char *name); 285 lvalue * 286 global_finalize_lvalue (tree inner); 287 288 private: 289 290 /* Functions for implementing "compile". */ 291 292 void acquire_mutex (); 293 void release_mutex (); 294 295 void 296 make_fake_args (vec <char *> *argvec, 297 const char *ctxt_progname, 298 vec <recording::requested_dump> *requested_dumps); 299 300 void 301 extract_any_requested_dumps 302 (vec <recording::requested_dump> *requested_dumps); 303 304 char * 305 read_dump_file (const char *path); 306 307 virtual void postprocess (const char *ctxt_progname) = 0; 308 309 protected: get_tempdir()310 tempdir *get_tempdir () { return m_tempdir; } 311 312 void 313 convert_to_dso (const char *ctxt_progname); 314 315 void 316 invoke_driver (const char *ctxt_progname, 317 const char *input_file, 318 const char *output_file, 319 timevar_id_t tv_id, 320 bool shared, 321 bool run_linker); 322 323 void 324 add_multilib_driver_arguments (vec <char *> *argvec); 325 326 result * 327 dlopen_built_dso (); 328 329 private: 330 void 331 invoke_embedded_driver (const vec <char *> *argvec); 332 333 void 334 invoke_external_driver (const char *ctxt_progname, 335 vec <char *> *argvec); 336 337 private: 338 ::gcc::jit::recording::context *m_recording_ctxt; 339 340 tempdir *m_tempdir; 341 342 auto_vec<function *> m_functions; 343 auto_vec<tree> m_globals; 344 tree m_const_char_ptr; 345 346 /* Source location handling. */ 347 auto_vec<source_file *> m_source_files; 348 349 auto_vec<std::pair<tree, location *> > m_cached_locations; 350 }; 351 352 class compile_to_memory : public context 353 { 354 public: 355 compile_to_memory (recording::context *ctxt); 356 void postprocess (const char *ctxt_progname) FINAL OVERRIDE; 357 get_result_obj()358 result *get_result_obj () const { return m_result; } 359 360 private: 361 result *m_result; 362 }; 363 364 class compile_to_file : public context 365 { 366 public: 367 compile_to_file (recording::context *ctxt, 368 enum gcc_jit_output_kind output_kind, 369 const char *output_path); 370 void postprocess (const char *ctxt_progname) FINAL OVERRIDE; 371 372 private: 373 void 374 copy_file (const char *src_path, 375 const char *dst_path); 376 377 private: 378 enum gcc_jit_output_kind m_output_kind; 379 const char *m_output_path; 380 }; 381 382 383 /* A temporary wrapper object. 384 These objects are (mostly) only valid during replay. 385 We allocate them on the GC heap, so that they will be cleaned 386 the next time the GC collects. 387 The exception is the "function" class, which is tracked and marked by 388 the jit::context, since it needs to stay alive during post-processing 389 (when the GC could run). */ 390 class wrapper 391 { 392 public: 393 /* Allocate in the GC heap. */ 394 void *operator new (size_t sz); 395 396 /* Some wrapper subclasses contain vec<> and so need to 397 release them when they are GC-ed. */ finalizer()398 virtual void finalizer () { } 399 400 }; 401 402 class type : public wrapper 403 { 404 public: type(tree inner)405 type (tree inner) 406 : m_inner(inner) 407 {} 408 as_tree()409 tree as_tree () const { return m_inner; } 410 get_pointer()411 type *get_pointer () const { return new type (build_pointer_type (m_inner)); } 412 get_const()413 type *get_const () const 414 { 415 return new type (build_qualified_type (m_inner, TYPE_QUAL_CONST)); 416 } 417 get_volatile()418 type *get_volatile () const 419 { 420 return new type (build_qualified_type (m_inner, TYPE_QUAL_VOLATILE)); 421 } 422 423 type *get_aligned (size_t alignment_in_bytes) const; 424 type *get_vector (size_t num_units) const; 425 426 private: 427 tree m_inner; 428 }; 429 430 class compound_type : public type 431 { 432 public: compound_type(tree inner)433 compound_type (tree inner) 434 : type (inner) 435 {} 436 437 void set_fields (const auto_vec<field *> *fields); 438 }; 439 440 class field : public wrapper 441 { 442 public: field(tree inner)443 field (tree inner) 444 : m_inner(inner) 445 {} 446 as_tree()447 tree as_tree () const { return m_inner; } 448 449 private: 450 tree m_inner; 451 }; 452 453 class bitfield : public field {}; 454 455 class function : public wrapper 456 { 457 public: 458 function(context *ctxt, tree fndecl, enum gcc_jit_function_kind kind); 459 460 void gt_ggc_mx (); 461 void finalizer () FINAL OVERRIDE; 462 463 tree get_return_type_as_tree () const; 464 as_fndecl()465 tree as_fndecl () const { return m_inner_fndecl; } 466 get_kind()467 enum gcc_jit_function_kind get_kind () const { return m_kind; } 468 469 lvalue * 470 new_local (location *loc, 471 type *type, 472 const char *name); 473 474 block* 475 new_block (const char *name); 476 477 rvalue * 478 get_address (location *loc); 479 480 void 481 build_stmt_list (); 482 483 void 484 postprocess (); 485 486 public: 487 context *m_ctxt; 488 489 public: 490 void set_tree_location(tree t,location * loc)491 set_tree_location (tree t, location *loc) 492 { 493 m_ctxt->set_tree_location (t, loc); 494 } 495 496 private: 497 tree m_inner_fndecl; 498 tree m_inner_block; 499 tree m_inner_bind_expr; 500 enum gcc_jit_function_kind m_kind; 501 tree m_stmt_list; 502 tree_stmt_iterator m_stmt_iter; 503 vec<block *> m_blocks; 504 }; 505 506 struct case_ 507 { case_case_508 case_ (rvalue *min_value, rvalue *max_value, block *dest_block) 509 : m_min_value (min_value), 510 m_max_value (max_value), 511 m_dest_block (dest_block) 512 {} 513 514 rvalue *m_min_value; 515 rvalue *m_max_value; 516 block *m_dest_block; 517 }; 518 519 struct asm_operand 520 { asm_operandasm_operand521 asm_operand (const char *asm_symbolic_name, 522 const char *constraint, 523 tree expr) 524 : m_asm_symbolic_name (asm_symbolic_name), 525 m_constraint (constraint), 526 m_expr (expr) 527 {} 528 529 const char *m_asm_symbolic_name; 530 const char *m_constraint; 531 tree m_expr; 532 }; 533 534 class block : public wrapper 535 { 536 public: 537 block (function *func, 538 const char *name); 539 540 void finalizer () FINAL OVERRIDE; 541 as_label_decl()542 tree as_label_decl () const { return m_label_decl; } 543 get_function()544 function *get_function () const { return m_func; } 545 546 void 547 add_eval (location *loc, 548 rvalue *rvalue); 549 550 void 551 add_assignment (location *loc, 552 lvalue *lvalue, 553 rvalue *rvalue); 554 555 void 556 add_comment (location *loc, 557 const char *text); 558 559 void 560 add_conditional (location *loc, 561 rvalue *boolval, 562 block *on_true, 563 block *on_false); 564 565 block * 566 add_block (location *loc, 567 const char *name); 568 569 void 570 add_jump (location *loc, 571 block *target); 572 573 void 574 add_return (location *loc, 575 rvalue *rvalue); 576 577 void 578 add_switch (location *loc, 579 rvalue *expr, 580 block *default_block, 581 const auto_vec <case_> *cases); 582 583 void 584 add_extended_asm (location *loc, 585 const char *asm_template, 586 bool is_volatile, 587 bool is_inline, 588 const auto_vec <asm_operand> *outputs, 589 const auto_vec <asm_operand> *inputs, 590 const auto_vec <const char *> *clobbers, 591 const auto_vec <block *> *goto_blocks); 592 593 private: 594 void set_tree_location(tree t,location * loc)595 set_tree_location (tree t, location *loc) 596 { 597 m_func->set_tree_location (t, loc); 598 } 599 add_stmt(tree stmt)600 void add_stmt (tree stmt) 601 { 602 /* TODO: use one stmt_list per block. */ 603 m_stmts.safe_push (stmt); 604 } 605 606 private: 607 function *m_func; 608 tree m_label_decl; 609 vec<tree> m_stmts; 610 611 public: // for now 612 tree m_label_expr; 613 614 friend class function; 615 }; 616 617 class rvalue : public wrapper 618 { 619 public: rvalue(context * ctxt,tree inner)620 rvalue (context *ctxt, tree inner) 621 : m_ctxt (ctxt), 622 m_inner (inner) 623 { 624 /* Pre-mark tree nodes with TREE_VISITED so that they can be 625 deeply unshared during gimplification (including across 626 functions); this requires LANG_HOOKS_DEEP_UNSHARING to be true. */ 627 TREE_VISITED (inner) = 1; 628 } 629 630 rvalue * as_rvalue()631 as_rvalue () { return this; } 632 as_tree()633 tree as_tree () const { return m_inner; } 634 get_context()635 context *get_context () const { return m_ctxt; } 636 637 type * get_type()638 get_type () { return new type (TREE_TYPE (m_inner)); } 639 640 rvalue * 641 access_field (location *loc, 642 field *field); 643 644 lvalue * 645 dereference_field (location *loc, 646 field *field); 647 648 lvalue * 649 dereference (location *loc); 650 651 private: 652 context *m_ctxt; 653 tree m_inner; 654 }; 655 656 class lvalue : public rvalue 657 { 658 public: lvalue(context * ctxt,tree inner)659 lvalue (context *ctxt, tree inner) 660 : rvalue(ctxt, inner) 661 {} 662 663 lvalue * as_lvalue()664 as_lvalue () { return this; } 665 666 lvalue * 667 access_field (location *loc, 668 field *field); 669 670 rvalue * 671 get_address (location *loc); 672 673 private: 674 bool mark_addressable (location *loc); 675 }; 676 677 class param : public lvalue 678 { 679 public: param(context * ctxt,tree inner)680 param (context *ctxt, tree inner) 681 : lvalue(ctxt, inner) 682 {} 683 }; 684 685 /* Dealing with the linemap API. 686 687 It appears that libcpp requires locations to be created as if by 688 a tokenizer, creating them by filename, in ascending order of 689 line/column, whereas our API doesn't impose any such constraints: 690 we allow client code to create locations in arbitrary orders. 691 692 To square this circle, we need to cache all location creation, 693 grouping things up by filename/line, and then creating the linemap 694 entries in a post-processing phase. */ 695 696 /* A set of locations, all sharing a filename */ 697 class source_file : public wrapper 698 { 699 public: 700 source_file (tree filename); 701 void finalizer () FINAL OVERRIDE; 702 703 source_line * 704 get_source_line (int line_num); 705 filename_as_tree()706 tree filename_as_tree () const { return m_filename; } 707 708 const char* get_filename()709 get_filename () const { return IDENTIFIER_POINTER (m_filename); } 710 711 vec<source_line *> m_source_lines; 712 713 private: 714 tree m_filename; 715 }; 716 717 /* A source line, with one or more locations of interest. */ 718 class source_line : public wrapper 719 { 720 public: 721 source_line (source_file *file, int line_num); 722 void finalizer () FINAL OVERRIDE; 723 724 location * 725 get_location (recording::location *rloc, int column_num); 726 get_line_num()727 int get_line_num () const { return m_line_num; } 728 729 vec<location *> m_locations; 730 731 private: 732 source_file *m_source_file; 733 int m_line_num; 734 }; 735 736 /* A specific location on a source line. This is what we expose 737 to the client API. */ 738 class location : public wrapper 739 { 740 public: 741 location (recording::location *loc, source_line *line, int column_num); 742 get_column_num()743 int get_column_num () const { return m_column_num; } 744 get_recording_loc()745 recording::location *get_recording_loc () const { return m_recording_loc; } 746 747 location_t m_srcloc; 748 749 private: 750 recording::location *m_recording_loc; 751 source_line *m_line; 752 int m_column_num; 753 }; 754 755 } // namespace gcc::jit::playback 756 757 extern playback::context *active_playback_ctxt; 758 759 } // namespace gcc::jit 760 761 } // namespace gcc 762 763 #endif /* JIT_PLAYBACK_H */ 764