Home | History | Annotate | Line # | Download | only in jit
jit-playback.h revision 1.5
      1 /* Internals of libgccjit: classes for playing back recorded API calls.
      2    Copyright (C) 2013-2019 Free Software Foundation, Inc.
      3    Contributed by David Malcolm <dmalcolm (at) 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 *
    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
    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
    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
    191   get_inner_bool_option (enum inner_bool_option opt) const
    192   {
    193     return m_recording_ctxt->get_inner_bool_option (opt);
    194   }
    195 
    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 
    233   bool errors_occurred () const
    234   {
    235     return m_recording_ctxt->errors_occurred ();
    236   }
    237 
    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:
    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 
    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.  */
    374   virtual void finalizer () { }
    375 
    376 };
    377 
    378 class type : public wrapper
    379 {
    380 public:
    381   type (tree inner)
    382     : m_inner(inner)
    383   {}
    384 
    385   tree as_tree () const { return m_inner; }
    386 
    387   type *get_pointer () const { return new type (build_pointer_type (m_inner)); }
    388 
    389   type *get_const () const
    390   {
    391     return new type (build_qualified_type (m_inner, TYPE_QUAL_CONST));
    392   }
    393 
    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:
    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:
    419   field (tree inner)
    420     : m_inner(inner)
    421   {}
    422 
    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 
    439   tree as_fndecl () const { return m_inner_fndecl; }
    440 
    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
    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 {
    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 
    501   tree as_label_decl () const { return m_label_decl; }
    502 
    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
    544   set_tree_location (tree t, location *loc)
    545   {
    546     m_func->set_tree_location (t, loc);
    547   }
    548 
    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:
    569   rvalue (context *ctxt, tree inner)
    570     : m_ctxt (ctxt),
    571       m_inner (inner)
    572   {}
    573 
    574   rvalue *
    575   as_rvalue () { return this; }
    576 
    577   tree as_tree () const { return m_inner; }
    578 
    579   context *get_context () const { return m_ctxt; }
    580 
    581   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:
    603   lvalue (context *ctxt, tree inner)
    604     : rvalue(ctxt, inner)
    605   {}
    606 
    607   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:
    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 
    648   tree filename_as_tree () const { return m_filename; }
    649 
    650   const char*
    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 
    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 
    685   int get_column_num () const { return m_column_num; }
    686 
    687   recording::location *get_recording_loc () const { return m_recording_loc; }
    688 
    689   location_t 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