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