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