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