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