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