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