1 /* Internals of libgccjit: classes for playing back recorded API calls.
2    Copyright (C) 2013-2021 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   lvalue *
115   new_global_initialized (location *loc,
116                           enum gcc_jit_global_kind kind,
117                           type *type,
118                           size_t element_size,
119                           size_t initializer_num_elem,
120                           const void *initializer,
121                           const char *name);
122 
123   template <typename HOST_TYPE>
124   rvalue *
125   new_rvalue_from_const (type *type,
126 			 HOST_TYPE value);
127 
128   rvalue *
129   new_string_literal (const char *value);
130 
131   rvalue *
132   new_rvalue_from_vector (location *loc,
133 			  type *type,
134 			  const auto_vec<rvalue *> &elements);
135 
136   rvalue *
137   new_unary_op (location *loc,
138 		enum gcc_jit_unary_op op,
139 		type *result_type,
140 		rvalue *a);
141 
142   rvalue *
143   new_binary_op (location *loc,
144 		 enum gcc_jit_binary_op op,
145 		 type *result_type,
146 		 rvalue *a, rvalue *b);
147 
148   rvalue *
149   new_comparison (location *loc,
150 		  enum gcc_jit_comparison op,
151 		  rvalue *a, rvalue *b);
152 
153   rvalue *
154   new_call (location *loc,
155 	    function *func,
156 	    const auto_vec<rvalue *> *args,
157 	    bool require_tail_call);
158 
159   rvalue *
160   new_call_through_ptr (location *loc,
161 			rvalue *fn_ptr,
162 			const auto_vec<rvalue *> *args,
163 			bool require_tail_call);
164 
165   rvalue *
166   new_cast (location *loc,
167 	    rvalue *expr,
168 	    type *type_);
169 
170   lvalue *
171   new_array_access (location *loc,
172 		    rvalue *ptr,
173 		    rvalue *index);
174 
175   void
176   set_str_option (enum gcc_jit_str_option opt,
177 		  const char *value);
178 
179   void
180   set_int_option (enum gcc_jit_int_option opt,
181 		  int value);
182 
183   void
184   set_bool_option (enum gcc_jit_bool_option opt,
185 		   int value);
186 
187   const char *
get_str_option(enum gcc_jit_str_option opt)188   get_str_option (enum gcc_jit_str_option opt) const
189   {
190     return m_recording_ctxt->get_str_option (opt);
191   }
192 
193   int
get_int_option(enum gcc_jit_int_option opt)194   get_int_option (enum gcc_jit_int_option opt) const
195   {
196     return m_recording_ctxt->get_int_option (opt);
197   }
198 
199   int
get_bool_option(enum gcc_jit_bool_option opt)200   get_bool_option (enum gcc_jit_bool_option opt) const
201   {
202     return m_recording_ctxt->get_bool_option (opt);
203   }
204 
205   int
get_inner_bool_option(enum inner_bool_option opt)206   get_inner_bool_option (enum inner_bool_option opt) const
207   {
208     return m_recording_ctxt->get_inner_bool_option (opt);
209   }
210 
get_builtins_manager()211   builtins_manager *get_builtins_manager () const
212   {
213     return m_recording_ctxt->get_builtins_manager ();
214   }
215 
216   void
217   compile ();
218 
219   void
220   add_error (location *loc, const char *fmt, ...)
221       GNU_PRINTF(3, 4);
222 
223   void
224   add_error_va (location *loc, const char *fmt, va_list ap)
225       GNU_PRINTF(3, 0);
226 
227   const char *
228   get_first_error () const;
229 
230   void
231   add_diagnostic (struct diagnostic_context *context,
232 		  struct diagnostic_info *diagnostic);
233 
234   void
235   set_tree_location (tree t, location *loc);
236 
237   tree
238   new_field_access (location *loc,
239 		    tree datum,
240 		    field *field);
241 
242   tree
243   new_dereference (tree ptr, location *loc);
244 
245   tree
246   as_truth_value (tree expr, location *loc);
247 
errors_occurred()248   bool errors_occurred () const
249   {
250     return m_recording_ctxt->errors_occurred ();
251   }
252 
get_timer()253   timer *get_timer () const { return m_recording_ctxt->get_timer (); }
254 
255   void add_top_level_asm (const char *asm_stmts);
256 
257 private:
258   void dump_generated_code ();
259 
260   rvalue *
261   build_call (location *loc,
262 	      tree fn_ptr,
263 	      const auto_vec<rvalue *> *args,
264 	      bool require_tail_call);
265 
266   tree
267   build_cast (location *loc,
268 	      rvalue *expr,
269 	      type *type_);
270 
271   source_file *
272   get_source_file (const char *filename);
273 
274   tree
275   get_tree_node_for_type (enum gcc_jit_types type_);
276 
277   void handle_locations ();
278 
279   void init_types ();
280 
281   const char * get_path_c_file () const;
282   const char * get_path_s_file () const;
283   const char * get_path_so_file () const;
284 
285   tree
286   global_new_decl (location *loc,
287                    enum gcc_jit_global_kind kind,
288                    type *type,
289                    const char *name);
290   lvalue *
291   global_finalize_lvalue (tree inner);
292 
293 private:
294 
295   /* Functions for implementing "compile".  */
296 
297   void acquire_mutex ();
298   void release_mutex ();
299 
300   void
301   make_fake_args (vec <char *> *argvec,
302 		  const char *ctxt_progname,
303 		  vec <recording::requested_dump> *requested_dumps);
304 
305   void
306   extract_any_requested_dumps
307     (vec <recording::requested_dump> *requested_dumps);
308 
309   char *
310   read_dump_file (const char *path);
311 
312   virtual void postprocess (const char *ctxt_progname) = 0;
313 
314 protected:
get_tempdir()315   tempdir *get_tempdir () { return m_tempdir; }
316 
317   void
318   convert_to_dso (const char *ctxt_progname);
319 
320   void
321   invoke_driver (const char *ctxt_progname,
322 		 const char *input_file,
323 		 const char *output_file,
324 		 timevar_id_t tv_id,
325 		 bool shared,
326 		 bool run_linker);
327 
328   void
329   add_multilib_driver_arguments (vec <char *> *argvec);
330 
331   result *
332   dlopen_built_dso ();
333 
334  private:
335   void
336   invoke_embedded_driver (const vec <char *> *argvec);
337 
338   void
339   invoke_external_driver (const char *ctxt_progname,
340 			  vec <char *> *argvec);
341 
342 private:
343   ::gcc::jit::recording::context *m_recording_ctxt;
344 
345   tempdir *m_tempdir;
346 
347   auto_vec<function *> m_functions;
348   auto_vec<tree> m_globals;
349   tree m_const_char_ptr;
350 
351   /* Source location handling.  */
352   auto_vec<source_file *> m_source_files;
353 
354   auto_vec<std::pair<tree, location *> > m_cached_locations;
355 };
356 
357 class compile_to_memory : public context
358 {
359  public:
360   compile_to_memory (recording::context *ctxt);
361   void postprocess (const char *ctxt_progname) FINAL OVERRIDE;
362 
get_result_obj()363   result *get_result_obj () const { return m_result; }
364 
365  private:
366   result *m_result;
367 };
368 
369 class compile_to_file : public context
370 {
371  public:
372   compile_to_file (recording::context *ctxt,
373 		   enum gcc_jit_output_kind output_kind,
374 		   const char *output_path);
375   void postprocess (const char *ctxt_progname) FINAL OVERRIDE;
376 
377  private:
378   void
379   copy_file (const char *src_path,
380 	     const char *dst_path);
381 
382  private:
383   enum gcc_jit_output_kind m_output_kind;
384   const char *m_output_path;
385 };
386 
387 
388 /* A temporary wrapper object.
389    These objects are (mostly) only valid during replay.
390    We allocate them on the GC heap, so that they will be cleaned
391    the next time the GC collects.
392    The exception is the "function" class, which is tracked and marked by
393    the jit::context, since it needs to stay alive during post-processing
394    (when the GC could run). */
395 class wrapper
396 {
397 public:
398   /* Allocate in the GC heap.  */
399   void *operator new (size_t sz);
400 
401   /* Some wrapper subclasses contain vec<> and so need to
402      release them when they are GC-ed.  */
finalizer()403   virtual void finalizer () { }
404 
405 };
406 
407 class type : public wrapper
408 {
409 public:
type(tree inner)410   type (tree inner)
411     : m_inner(inner)
412   {}
413 
as_tree()414   tree as_tree () const { return m_inner; }
415 
get_pointer()416   type *get_pointer () const { return new type (build_pointer_type (m_inner)); }
417 
get_const()418   type *get_const () const
419   {
420     return new type (build_qualified_type (m_inner, TYPE_QUAL_CONST));
421   }
422 
get_volatile()423   type *get_volatile () const
424   {
425     return new type (build_qualified_type (m_inner, TYPE_QUAL_VOLATILE));
426   }
427 
428   type *get_aligned (size_t alignment_in_bytes) const;
429   type *get_vector (size_t num_units) const;
430 
431 private:
432   tree m_inner;
433 };
434 
435 class compound_type : public type
436 {
437 public:
compound_type(tree inner)438   compound_type (tree inner)
439     : type (inner)
440   {}
441 
442   void set_fields (const auto_vec<field *> *fields);
443 };
444 
445 class field : public wrapper
446 {
447 public:
field(tree inner)448   field (tree inner)
449     : m_inner(inner)
450   {}
451 
as_tree()452   tree as_tree () const { return m_inner; }
453 
454 private:
455   tree m_inner;
456 };
457 
458 class bitfield : public field {};
459 
460 class function : public wrapper
461 {
462 public:
463   function(context *ctxt, tree fndecl, enum gcc_jit_function_kind kind);
464 
465   void gt_ggc_mx ();
466   void finalizer () FINAL OVERRIDE;
467 
468   tree get_return_type_as_tree () const;
469 
as_fndecl()470   tree as_fndecl () const { return m_inner_fndecl; }
471 
get_kind()472   enum gcc_jit_function_kind get_kind () const { return m_kind; }
473 
474   lvalue *
475   new_local (location *loc,
476 	     type *type,
477 	     const char *name);
478 
479   block*
480   new_block (const char *name);
481 
482   rvalue *
483   get_address (location *loc);
484 
485   void
486   build_stmt_list ();
487 
488   void
489   postprocess ();
490 
491 public:
492   context *m_ctxt;
493 
494 public:
495   void
set_tree_location(tree t,location * loc)496   set_tree_location (tree t, location *loc)
497   {
498     m_ctxt->set_tree_location (t, loc);
499   }
500 
501 private:
502   tree m_inner_fndecl;
503   tree m_inner_block;
504   tree m_inner_bind_expr;
505   enum gcc_jit_function_kind m_kind;
506   tree m_stmt_list;
507   tree_stmt_iterator m_stmt_iter;
508   vec<block *> m_blocks;
509 };
510 
511 struct case_
512 {
case_case_513   case_ (rvalue *min_value, rvalue *max_value, block *dest_block)
514   : m_min_value (min_value),
515     m_max_value (max_value),
516     m_dest_block (dest_block)
517   {}
518 
519   rvalue *m_min_value;
520   rvalue *m_max_value;
521   block *m_dest_block;
522 };
523 
524 struct asm_operand
525 {
asm_operandasm_operand526   asm_operand (const char *asm_symbolic_name,
527 	       const char *constraint,
528 	       tree expr)
529   : m_asm_symbolic_name (asm_symbolic_name),
530     m_constraint (constraint),
531     m_expr (expr)
532   {}
533 
534   const char *m_asm_symbolic_name;
535   const char *m_constraint;
536   tree m_expr;
537 };
538 
539 class block : public wrapper
540 {
541 public:
542   block (function *func,
543 	 const char *name);
544 
545   void finalizer () FINAL OVERRIDE;
546 
as_label_decl()547   tree as_label_decl () const { return m_label_decl; }
548 
get_function()549   function *get_function () const { return m_func; }
550 
551   void
552   add_eval (location *loc,
553 	    rvalue *rvalue);
554 
555   void
556   add_assignment (location *loc,
557 		  lvalue *lvalue,
558 		  rvalue *rvalue);
559 
560   void
561   add_comment (location *loc,
562 	       const char *text);
563 
564   void
565   add_conditional (location *loc,
566 		   rvalue *boolval,
567 		   block *on_true,
568 		   block *on_false);
569 
570   block *
571   add_block (location *loc,
572 	     const char *name);
573 
574   void
575   add_jump (location *loc,
576 	    block *target);
577 
578   void
579   add_return (location *loc,
580 	      rvalue *rvalue);
581 
582   void
583   add_switch (location *loc,
584 	      rvalue *expr,
585 	      block *default_block,
586 	      const auto_vec <case_> *cases);
587 
588   void
589   add_extended_asm (location *loc,
590 		    const char *asm_template,
591 		    bool is_volatile,
592 		    bool is_inline,
593 		    const auto_vec <asm_operand> *outputs,
594 		    const auto_vec <asm_operand> *inputs,
595 		    const auto_vec <const char *> *clobbers,
596 		    const auto_vec <block *> *goto_blocks);
597 
598 private:
599   void
set_tree_location(tree t,location * loc)600   set_tree_location (tree t, location *loc)
601   {
602     m_func->set_tree_location (t, loc);
603   }
604 
add_stmt(tree stmt)605   void add_stmt (tree stmt)
606   {
607     /* TODO: use one stmt_list per block.  */
608     m_stmts.safe_push (stmt);
609   }
610 
611 private:
612   function *m_func;
613   tree m_label_decl;
614   vec<tree> m_stmts;
615 
616 public: // for now
617   tree m_label_expr;
618 
619   friend class function;
620 };
621 
622 class rvalue : public wrapper
623 {
624 public:
rvalue(context * ctxt,tree inner)625   rvalue (context *ctxt, tree inner)
626     : m_ctxt (ctxt),
627       m_inner (inner)
628   {
629     /* Pre-mark tree nodes with TREE_VISITED so that they can be
630        deeply unshared during gimplification (including across
631        functions); this requires LANG_HOOKS_DEEP_UNSHARING to be true.  */
632     TREE_VISITED (inner) = 1;
633   }
634 
635   rvalue *
as_rvalue()636   as_rvalue () { return this; }
637 
as_tree()638   tree as_tree () const { return m_inner; }
639 
get_context()640   context *get_context () const { return m_ctxt; }
641 
642   type *
get_type()643   get_type () { return new type (TREE_TYPE (m_inner)); }
644 
645   rvalue *
646   access_field (location *loc,
647 		field *field);
648 
649   lvalue *
650   dereference_field (location *loc,
651 		     field *field);
652 
653   lvalue *
654   dereference (location *loc);
655 
656 private:
657   context *m_ctxt;
658   tree m_inner;
659 };
660 
661 class lvalue : public rvalue
662 {
663 public:
lvalue(context * ctxt,tree inner)664   lvalue (context *ctxt, tree inner)
665     : rvalue(ctxt, inner)
666   {}
667 
668   lvalue *
as_lvalue()669   as_lvalue () { return this; }
670 
671   lvalue *
672   access_field (location *loc,
673 		field *field);
674 
675   rvalue *
676   get_address (location *loc);
677 
678 private:
679   bool mark_addressable (location *loc);
680 };
681 
682 class param : public lvalue
683 {
684 public:
param(context * ctxt,tree inner)685   param (context *ctxt, tree inner)
686     : lvalue(ctxt, inner)
687   {}
688 };
689 
690 /* Dealing with the linemap API.
691 
692    It appears that libcpp requires locations to be created as if by
693    a tokenizer, creating them by filename, in ascending order of
694    line/column, whereas our API doesn't impose any such constraints:
695    we allow client code to create locations in arbitrary orders.
696 
697    To square this circle, we need to cache all location creation,
698    grouping things up by filename/line, and then creating the linemap
699    entries in a post-processing phase.  */
700 
701 /* A set of locations, all sharing a filename */
702 class source_file : public wrapper
703 {
704 public:
705   source_file (tree filename);
706   void finalizer () FINAL OVERRIDE;
707 
708   source_line *
709   get_source_line (int line_num);
710 
filename_as_tree()711   tree filename_as_tree () const { return m_filename; }
712 
713   const char*
get_filename()714   get_filename () const { return IDENTIFIER_POINTER (m_filename); }
715 
716   vec<source_line *> m_source_lines;
717 
718 private:
719   tree m_filename;
720 };
721 
722 /* A source line, with one or more locations of interest.  */
723 class source_line : public wrapper
724 {
725 public:
726   source_line (source_file *file, int line_num);
727   void finalizer () FINAL OVERRIDE;
728 
729   location *
730   get_location (recording::location *rloc, int column_num);
731 
get_line_num()732   int get_line_num () const { return m_line_num; }
733 
734   vec<location *> m_locations;
735 
736 private:
737   source_file *m_source_file;
738   int m_line_num;
739 };
740 
741 /* A specific location on a source line.  This is what we expose
742    to the client API.  */
743 class location : public wrapper
744 {
745 public:
746   location (recording::location *loc, source_line *line, int column_num);
747 
get_column_num()748   int get_column_num () const { return m_column_num; }
749 
get_recording_loc()750   recording::location *get_recording_loc () const { return m_recording_loc; }
751 
752   location_t m_srcloc;
753 
754 private:
755   recording::location *m_recording_loc;
756   source_line *m_line;
757   int m_column_num;
758 };
759 
760 } // namespace gcc::jit::playback
761 
762 extern playback::context *active_playback_ctxt;
763 
764 } // namespace gcc::jit
765 
766 } // namespace gcc
767 
768 #endif /* JIT_PLAYBACK_H */
769