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 
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   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 *
get_str_option(enum gcc_jit_str_option opt)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
get_int_option(enum gcc_jit_int_option opt)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
get_bool_option(enum gcc_jit_bool_option opt)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
get_inner_bool_option(enum inner_bool_option opt)197   get_inner_bool_option (enum inner_bool_option opt) const
198   {
199     return m_recording_ctxt->get_inner_bool_option (opt);
200   }
201 
get_builtins_manager()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 
errors_occurred()239   bool errors_occurred () const
240   {
241     return m_recording_ctxt->errors_occurred ();
242   }
243 
get_timer()244   timer *get_timer () const { return m_recording_ctxt->get_timer (); }
245 
246 private:
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 
269 private:
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 
290 protected:
get_tempdir()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 
318 private:
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 
333 class 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 
get_result_obj()339   result *get_result_obj () const { return m_result; }
340 
341  private:
342   result *m_result;
343 };
344 
345 class 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). */
371 class wrapper
372 {
373 public:
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.  */
finalizer()379   virtual void finalizer () { }
380 
381 };
382 
383 class type : public wrapper
384 {
385 public:
type(tree inner)386   type (tree inner)
387     : m_inner(inner)
388   {}
389 
as_tree()390   tree as_tree () const { return m_inner; }
391 
get_pointer()392   type *get_pointer () const { return new type (build_pointer_type (m_inner)); }
393 
get_const()394   type *get_const () const
395   {
396     return new type (build_qualified_type (m_inner, TYPE_QUAL_CONST));
397   }
398 
get_volatile()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 
407 private:
408   tree m_inner;
409 };
410 
411 class compound_type : public type
412 {
413 public:
compound_type(tree inner)414   compound_type (tree inner)
415     : type (inner)
416   {}
417 
418   void set_fields (const auto_vec<field *> *fields);
419 };
420 
421 class field : public wrapper
422 {
423 public:
field(tree inner)424   field (tree inner)
425     : m_inner(inner)
426   {}
427 
as_tree()428   tree as_tree () const { return m_inner; }
429 
430 private:
431   tree m_inner;
432 };
433 
434 class bitfield : public field {};
435 
436 class function : public wrapper
437 {
438 public:
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 
as_fndecl()446   tree as_fndecl () const { return m_inner_fndecl; }
447 
get_kind()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 
467 public:
468   context *m_ctxt;
469 
470 public:
471   void
set_tree_location(tree t,location * loc)472   set_tree_location (tree t, location *loc)
473   {
474     m_ctxt->set_tree_location (t, loc);
475   }
476 
477 private:
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 
487 struct case_
488 {
case_case_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 
500 class block : public wrapper
501 {
502 public:
503   block (function *func,
504 	 const char *name);
505 
506   void finalizer () FINAL OVERRIDE;
507 
as_label_decl()508   tree as_label_decl () const { return m_label_decl; }
509 
get_function()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 
549 private:
550   void
set_tree_location(tree t,location * loc)551   set_tree_location (tree t, location *loc)
552   {
553     m_func->set_tree_location (t, loc);
554   }
555 
add_stmt(tree stmt)556   void add_stmt (tree stmt)
557   {
558     /* TODO: use one stmt_list per block.  */
559     m_stmts.safe_push (stmt);
560   }
561 
562 private:
563   function *m_func;
564   tree m_label_decl;
565   vec<tree> m_stmts;
566 
567 public: // for now
568   tree m_label_expr;
569 
570   friend class function;
571 };
572 
573 class rvalue : public wrapper
574 {
575 public:
rvalue(context * ctxt,tree inner)576   rvalue (context *ctxt, tree inner)
577     : m_ctxt (ctxt),
578       m_inner (inner)
579   {}
580 
581   rvalue *
as_rvalue()582   as_rvalue () { return this; }
583 
as_tree()584   tree as_tree () const { return m_inner; }
585 
get_context()586   context *get_context () const { return m_ctxt; }
587 
588   type *
get_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 
602 private:
603   context *m_ctxt;
604   tree m_inner;
605 };
606 
607 class lvalue : public rvalue
608 {
609 public:
lvalue(context * ctxt,tree inner)610   lvalue (context *ctxt, tree inner)
611     : rvalue(ctxt, inner)
612   {}
613 
614   lvalue *
as_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 
624 private:
625   bool mark_addressable (location *loc);
626 };
627 
628 class param : public lvalue
629 {
630 public:
param(context * ctxt,tree inner)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 */
648 class source_file : public wrapper
649 {
650 public:
651   source_file (tree filename);
652   void finalizer () FINAL OVERRIDE;
653 
654   source_line *
655   get_source_line (int line_num);
656 
filename_as_tree()657   tree filename_as_tree () const { return m_filename; }
658 
659   const char*
get_filename()660   get_filename () const { return IDENTIFIER_POINTER (m_filename); }
661 
662   vec<source_line *> m_source_lines;
663 
664 private:
665   tree m_filename;
666 };
667 
668 /* A source line, with one or more locations of interest.  */
669 class source_line : public wrapper
670 {
671 public:
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 
get_line_num()678   int get_line_num () const { return m_line_num; }
679 
680   vec<location *> m_locations;
681 
682 private:
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.  */
689 class location : public wrapper
690 {
691 public:
692   location (recording::location *loc, source_line *line, int column_num);
693 
get_column_num()694   int get_column_num () const { return m_column_num; }
695 
get_recording_loc()696   recording::location *get_recording_loc () const { return m_recording_loc; }
697 
698   location_t m_srcloc;
699 
700 private:
701   recording::location *m_recording_loc;
702   source_line *m_line;
703   int m_column_num;
704 };
705 
706 } // namespace gcc::jit::playback
707 
708 extern playback::context *active_playback_ctxt;
709 
710 } // namespace gcc::jit
711 
712 } // namespace gcc
713 
714 #endif /* JIT_PLAYBACK_H */
715