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 
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 *
get_str_option(enum gcc_jit_str_option opt)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
get_int_option(enum gcc_jit_int_option opt)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
get_bool_option(enum gcc_jit_bool_option opt)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
get_inner_bool_option(enum inner_bool_option opt)191   get_inner_bool_option (enum inner_bool_option opt) const
192   {
193     return m_recording_ctxt->get_inner_bool_option (opt);
194   }
195 
get_builtins_manager()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 
errors_occurred()233   bool errors_occurred () const
234   {
235     return m_recording_ctxt->errors_occurred ();
236   }
237 
get_timer()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:
get_tempdir()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 
get_result_obj()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.  */
finalizer()374   virtual void finalizer () { }
375 
376 };
377 
378 class type : public wrapper
379 {
380 public:
type(tree inner)381   type (tree inner)
382     : m_inner(inner)
383   {}
384 
as_tree()385   tree as_tree () const { return m_inner; }
386 
get_pointer()387   type *get_pointer () const { return new type (build_pointer_type (m_inner)); }
388 
get_const()389   type *get_const () const
390   {
391     return new type (build_qualified_type (m_inner, TYPE_QUAL_CONST));
392   }
393 
get_volatile()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:
compound_type(tree inner)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:
field(tree inner)419   field (tree inner)
420     : m_inner(inner)
421   {}
422 
as_tree()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 
as_fndecl()439   tree as_fndecl () const { return m_inner_fndecl; }
440 
get_kind()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
set_tree_location(tree t,location * loc)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 {
case_case_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 
as_label_decl()501   tree as_label_decl () const { return m_label_decl; }
502 
get_function()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
set_tree_location(tree t,location * loc)544   set_tree_location (tree t, location *loc)
545   {
546     m_func->set_tree_location (t, loc);
547   }
548 
add_stmt(tree stmt)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:
rvalue(context * ctxt,tree inner)569   rvalue (context *ctxt, tree inner)
570     : m_ctxt (ctxt),
571       m_inner (inner)
572   {}
573 
574   rvalue *
as_rvalue()575   as_rvalue () { return this; }
576 
as_tree()577   tree as_tree () const { return m_inner; }
578 
get_context()579   context *get_context () const { return m_ctxt; }
580 
581   type *
get_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:
lvalue(context * ctxt,tree inner)603   lvalue (context *ctxt, tree inner)
604     : rvalue(ctxt, inner)
605   {}
606 
607   lvalue *
as_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:
param(context * ctxt,tree inner)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 
filename_as_tree()648   tree filename_as_tree () const { return m_filename; }
649 
650   const char*
get_filename()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 
get_line_num()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 
get_column_num()685   int get_column_num () const { return m_column_num; }
686 
get_recording_loc()687   recording::location *get_recording_loc () const { return m_recording_loc; }
688 
689   source_location 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