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