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