jit-playback.h revision 1.4
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
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  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
240private:
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
263private:
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
284protected:
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
312private:
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
328class 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
340class 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). */
366class wrapper
367{
368public:
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
378class type : public wrapper
379{
380public:
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
402private:
403  tree m_inner;
404};
405
406class compound_type : public type
407{
408public:
409  compound_type (tree inner)
410    : type (inner)
411  {}
412
413  void set_fields (const auto_vec<field *> *fields);
414};
415
416class field : public wrapper
417{
418public:
419  field (tree inner)
420    : m_inner(inner)
421  {}
422
423  tree as_tree () const { return m_inner; }
424
425private:
426  tree m_inner;
427};
428
429class function : public wrapper
430{
431public:
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
460public:
461  context *m_ctxt;
462
463public:
464  void
465  set_tree_location (tree t, location *loc)
466  {
467    m_ctxt->set_tree_location (t, loc);
468  }
469
470private:
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
480struct 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
493class block : public wrapper
494{
495public:
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
542private:
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
555private:
556  function *m_func;
557  tree m_label_decl;
558  vec<tree> m_stmts;
559
560public: // for now
561  tree m_label_expr;
562
563  friend class function;
564};
565
566class rvalue : public wrapper
567{
568public:
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
595private:
596  context *m_ctxt;
597  tree m_inner;
598};
599
600class lvalue : public rvalue
601{
602public:
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
619class param : public lvalue
620{
621public:
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 */
639class source_file : public wrapper
640{
641public:
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
655private:
656  tree m_filename;
657};
658
659/* A source line, with one or more locations of interest.  */
660class source_line : public wrapper
661{
662public:
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
673private:
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.  */
680class location : public wrapper
681{
682public:
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  source_location m_srcloc;
690
691private:
692  recording::location *m_recording_loc;
693  source_line *m_line;
694  int m_column_num;
695};
696
697} // namespace gcc::jit::playback
698
699extern playback::context *active_playback_ctxt;
700
701} // namespace gcc::jit
702
703} // namespace gcc
704
705#endif /* JIT_PLAYBACK_H */
706
707