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   void handle_locations ();
275 
276   const char * get_path_c_file () const;
277   const char * get_path_s_file () const;
278   const char * get_path_so_file () const;
279 
280   tree
281   global_new_decl (location *loc,
282                    enum gcc_jit_global_kind kind,
283                    type *type,
284                    const char *name);
285   lvalue *
286   global_finalize_lvalue (tree inner);
287 
288 private:
289 
290   /* Functions for implementing "compile".  */
291 
292   void acquire_mutex ();
293   void release_mutex ();
294 
295   void
296   make_fake_args (vec <char *> *argvec,
297 		  const char *ctxt_progname,
298 		  vec <recording::requested_dump> *requested_dumps);
299 
300   void
301   extract_any_requested_dumps
302     (vec <recording::requested_dump> *requested_dumps);
303 
304   char *
305   read_dump_file (const char *path);
306 
307   virtual void postprocess (const char *ctxt_progname) = 0;
308 
309 protected:
get_tempdir()310   tempdir *get_tempdir () { return m_tempdir; }
311 
312   void
313   convert_to_dso (const char *ctxt_progname);
314 
315   void
316   invoke_driver (const char *ctxt_progname,
317 		 const char *input_file,
318 		 const char *output_file,
319 		 timevar_id_t tv_id,
320 		 bool shared,
321 		 bool run_linker);
322 
323   void
324   add_multilib_driver_arguments (vec <char *> *argvec);
325 
326   result *
327   dlopen_built_dso ();
328 
329  private:
330   void
331   invoke_embedded_driver (const vec <char *> *argvec);
332 
333   void
334   invoke_external_driver (const char *ctxt_progname,
335 			  vec <char *> *argvec);
336 
337 private:
338   ::gcc::jit::recording::context *m_recording_ctxt;
339 
340   tempdir *m_tempdir;
341 
342   auto_vec<function *> m_functions;
343   auto_vec<tree> m_globals;
344   tree m_const_char_ptr;
345 
346   /* Source location handling.  */
347   auto_vec<source_file *> m_source_files;
348 
349   auto_vec<std::pair<tree, location *> > m_cached_locations;
350 };
351 
352 class compile_to_memory : public context
353 {
354  public:
355   compile_to_memory (recording::context *ctxt);
356   void postprocess (const char *ctxt_progname) FINAL OVERRIDE;
357 
get_result_obj()358   result *get_result_obj () const { return m_result; }
359 
360  private:
361   result *m_result;
362 };
363 
364 class compile_to_file : public context
365 {
366  public:
367   compile_to_file (recording::context *ctxt,
368 		   enum gcc_jit_output_kind output_kind,
369 		   const char *output_path);
370   void postprocess (const char *ctxt_progname) FINAL OVERRIDE;
371 
372  private:
373   void
374   copy_file (const char *src_path,
375 	     const char *dst_path);
376 
377  private:
378   enum gcc_jit_output_kind m_output_kind;
379   const char *m_output_path;
380 };
381 
382 
383 /* A temporary wrapper object.
384    These objects are (mostly) only valid during replay.
385    We allocate them on the GC heap, so that they will be cleaned
386    the next time the GC collects.
387    The exception is the "function" class, which is tracked and marked by
388    the jit::context, since it needs to stay alive during post-processing
389    (when the GC could run). */
390 class wrapper
391 {
392 public:
393   /* Allocate in the GC heap.  */
394   void *operator new (size_t sz);
395 
396   /* Some wrapper subclasses contain vec<> and so need to
397      release them when they are GC-ed.  */
finalizer()398   virtual void finalizer () { }
399 
400 };
401 
402 class type : public wrapper
403 {
404 public:
type(tree inner)405   type (tree inner)
406     : m_inner(inner)
407   {}
408 
as_tree()409   tree as_tree () const { return m_inner; }
410 
get_pointer()411   type *get_pointer () const { return new type (build_pointer_type (m_inner)); }
412 
get_const()413   type *get_const () const
414   {
415     return new type (build_qualified_type (m_inner, TYPE_QUAL_CONST));
416   }
417 
get_volatile()418   type *get_volatile () const
419   {
420     return new type (build_qualified_type (m_inner, TYPE_QUAL_VOLATILE));
421   }
422 
423   type *get_aligned (size_t alignment_in_bytes) const;
424   type *get_vector (size_t num_units) const;
425 
426 private:
427   tree m_inner;
428 };
429 
430 class compound_type : public type
431 {
432 public:
compound_type(tree inner)433   compound_type (tree inner)
434     : type (inner)
435   {}
436 
437   void set_fields (const auto_vec<field *> *fields);
438 };
439 
440 class field : public wrapper
441 {
442 public:
field(tree inner)443   field (tree inner)
444     : m_inner(inner)
445   {}
446 
as_tree()447   tree as_tree () const { return m_inner; }
448 
449 private:
450   tree m_inner;
451 };
452 
453 class bitfield : public field {};
454 
455 class function : public wrapper
456 {
457 public:
458   function(context *ctxt, tree fndecl, enum gcc_jit_function_kind kind);
459 
460   void gt_ggc_mx ();
461   void finalizer () FINAL OVERRIDE;
462 
463   tree get_return_type_as_tree () const;
464 
as_fndecl()465   tree as_fndecl () const { return m_inner_fndecl; }
466 
get_kind()467   enum gcc_jit_function_kind get_kind () const { return m_kind; }
468 
469   lvalue *
470   new_local (location *loc,
471 	     type *type,
472 	     const char *name);
473 
474   block*
475   new_block (const char *name);
476 
477   rvalue *
478   get_address (location *loc);
479 
480   void
481   build_stmt_list ();
482 
483   void
484   postprocess ();
485 
486 public:
487   context *m_ctxt;
488 
489 public:
490   void
set_tree_location(tree t,location * loc)491   set_tree_location (tree t, location *loc)
492   {
493     m_ctxt->set_tree_location (t, loc);
494   }
495 
496 private:
497   tree m_inner_fndecl;
498   tree m_inner_block;
499   tree m_inner_bind_expr;
500   enum gcc_jit_function_kind m_kind;
501   tree m_stmt_list;
502   tree_stmt_iterator m_stmt_iter;
503   vec<block *> m_blocks;
504 };
505 
506 struct case_
507 {
case_case_508   case_ (rvalue *min_value, rvalue *max_value, block *dest_block)
509   : m_min_value (min_value),
510     m_max_value (max_value),
511     m_dest_block (dest_block)
512   {}
513 
514   rvalue *m_min_value;
515   rvalue *m_max_value;
516   block *m_dest_block;
517 };
518 
519 struct asm_operand
520 {
asm_operandasm_operand521   asm_operand (const char *asm_symbolic_name,
522 	       const char *constraint,
523 	       tree expr)
524   : m_asm_symbolic_name (asm_symbolic_name),
525     m_constraint (constraint),
526     m_expr (expr)
527   {}
528 
529   const char *m_asm_symbolic_name;
530   const char *m_constraint;
531   tree m_expr;
532 };
533 
534 class block : public wrapper
535 {
536 public:
537   block (function *func,
538 	 const char *name);
539 
540   void finalizer () FINAL OVERRIDE;
541 
as_label_decl()542   tree as_label_decl () const { return m_label_decl; }
543 
get_function()544   function *get_function () const { return m_func; }
545 
546   void
547   add_eval (location *loc,
548 	    rvalue *rvalue);
549 
550   void
551   add_assignment (location *loc,
552 		  lvalue *lvalue,
553 		  rvalue *rvalue);
554 
555   void
556   add_comment (location *loc,
557 	       const char *text);
558 
559   void
560   add_conditional (location *loc,
561 		   rvalue *boolval,
562 		   block *on_true,
563 		   block *on_false);
564 
565   block *
566   add_block (location *loc,
567 	     const char *name);
568 
569   void
570   add_jump (location *loc,
571 	    block *target);
572 
573   void
574   add_return (location *loc,
575 	      rvalue *rvalue);
576 
577   void
578   add_switch (location *loc,
579 	      rvalue *expr,
580 	      block *default_block,
581 	      const auto_vec <case_> *cases);
582 
583   void
584   add_extended_asm (location *loc,
585 		    const char *asm_template,
586 		    bool is_volatile,
587 		    bool is_inline,
588 		    const auto_vec <asm_operand> *outputs,
589 		    const auto_vec <asm_operand> *inputs,
590 		    const auto_vec <const char *> *clobbers,
591 		    const auto_vec <block *> *goto_blocks);
592 
593 private:
594   void
set_tree_location(tree t,location * loc)595   set_tree_location (tree t, location *loc)
596   {
597     m_func->set_tree_location (t, loc);
598   }
599 
add_stmt(tree stmt)600   void add_stmt (tree stmt)
601   {
602     /* TODO: use one stmt_list per block.  */
603     m_stmts.safe_push (stmt);
604   }
605 
606 private:
607   function *m_func;
608   tree m_label_decl;
609   vec<tree> m_stmts;
610 
611 public: // for now
612   tree m_label_expr;
613 
614   friend class function;
615 };
616 
617 class rvalue : public wrapper
618 {
619 public:
rvalue(context * ctxt,tree inner)620   rvalue (context *ctxt, tree inner)
621     : m_ctxt (ctxt),
622       m_inner (inner)
623   {
624     /* Pre-mark tree nodes with TREE_VISITED so that they can be
625        deeply unshared during gimplification (including across
626        functions); this requires LANG_HOOKS_DEEP_UNSHARING to be true.  */
627     TREE_VISITED (inner) = 1;
628   }
629 
630   rvalue *
as_rvalue()631   as_rvalue () { return this; }
632 
as_tree()633   tree as_tree () const { return m_inner; }
634 
get_context()635   context *get_context () const { return m_ctxt; }
636 
637   type *
get_type()638   get_type () { return new type (TREE_TYPE (m_inner)); }
639 
640   rvalue *
641   access_field (location *loc,
642 		field *field);
643 
644   lvalue *
645   dereference_field (location *loc,
646 		     field *field);
647 
648   lvalue *
649   dereference (location *loc);
650 
651 private:
652   context *m_ctxt;
653   tree m_inner;
654 };
655 
656 class lvalue : public rvalue
657 {
658 public:
lvalue(context * ctxt,tree inner)659   lvalue (context *ctxt, tree inner)
660     : rvalue(ctxt, inner)
661   {}
662 
663   lvalue *
as_lvalue()664   as_lvalue () { return this; }
665 
666   lvalue *
667   access_field (location *loc,
668 		field *field);
669 
670   rvalue *
671   get_address (location *loc);
672 
673 private:
674   bool mark_addressable (location *loc);
675 };
676 
677 class param : public lvalue
678 {
679 public:
param(context * ctxt,tree inner)680   param (context *ctxt, tree inner)
681     : lvalue(ctxt, inner)
682   {}
683 };
684 
685 /* Dealing with the linemap API.
686 
687    It appears that libcpp requires locations to be created as if by
688    a tokenizer, creating them by filename, in ascending order of
689    line/column, whereas our API doesn't impose any such constraints:
690    we allow client code to create locations in arbitrary orders.
691 
692    To square this circle, we need to cache all location creation,
693    grouping things up by filename/line, and then creating the linemap
694    entries in a post-processing phase.  */
695 
696 /* A set of locations, all sharing a filename */
697 class source_file : public wrapper
698 {
699 public:
700   source_file (tree filename);
701   void finalizer () FINAL OVERRIDE;
702 
703   source_line *
704   get_source_line (int line_num);
705 
filename_as_tree()706   tree filename_as_tree () const { return m_filename; }
707 
708   const char*
get_filename()709   get_filename () const { return IDENTIFIER_POINTER (m_filename); }
710 
711   vec<source_line *> m_source_lines;
712 
713 private:
714   tree m_filename;
715 };
716 
717 /* A source line, with one or more locations of interest.  */
718 class source_line : public wrapper
719 {
720 public:
721   source_line (source_file *file, int line_num);
722   void finalizer () FINAL OVERRIDE;
723 
724   location *
725   get_location (recording::location *rloc, int column_num);
726 
get_line_num()727   int get_line_num () const { return m_line_num; }
728 
729   vec<location *> m_locations;
730 
731 private:
732   source_file *m_source_file;
733   int m_line_num;
734 };
735 
736 /* A specific location on a source line.  This is what we expose
737    to the client API.  */
738 class location : public wrapper
739 {
740 public:
741   location (recording::location *loc, source_line *line, int column_num);
742 
get_column_num()743   int get_column_num () const { return m_column_num; }
744 
get_recording_loc()745   recording::location *get_recording_loc () const { return m_recording_loc; }
746 
747   location_t m_srcloc;
748 
749 private:
750   recording::location *m_recording_loc;
751   source_line *m_line;
752   int m_column_num;
753 };
754 
755 } // namespace gcc::jit::playback
756 
757 extern playback::context *active_playback_ctxt;
758 
759 } // namespace gcc::jit
760 
761 } // namespace gcc
762 
763 #endif /* JIT_PLAYBACK_H */
764