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