This files declares the gcc::jit::playback internal API, called by the dummy "frontend" to replay the public API calls made to the library. A thin wrapper around trees.
gcc/jit/ * jit-playback.h: New. --- gcc/jit/jit-playback.h | 564 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 564 insertions(+) create mode 100644 gcc/jit/jit-playback.h diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h new file mode 100644 index 0000000..dcb19bf --- /dev/null +++ b/gcc/jit/jit-playback.h @@ -0,0 +1,564 @@ +/* Internals of libgccjit: classes for playing back recorded API calls. + Copyright (C) 2013-2014 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalc...@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef JIT_PLAYBACK_H +#define JIT_PLAYBACK_H + +#include <utility> // for std::pair + +#include "jit-recording.h" + +namespace gcc { + +namespace jit { + +/********************************************************************** + Playback. + **********************************************************************/ + +namespace playback { + +class context +{ +public: + context (::gcc::jit::recording::context *ctxt); + ~context (); + + void gt_ggc_mx (); + + void replay (); + + location * + new_location (recording::location *rloc, + const char *filename, + int line, + int column); + + type * + get_type (enum gcc_jit_types type); + + type * + new_array_type (location *loc, + type *element_type, + int num_elements); + + field * + new_field (location *loc, + type *type, + const char *name); + + compound_type * + new_compound_type (location *loc, + const char *name, + bool is_struct); /* else is union */ + + type * + new_function_type (type *return_type, + vec<type *> *param_types, + int is_variadic); + + param * + new_param (location *loc, + type *type, + const char *name); + + function * + new_function (location *loc, + enum gcc_jit_function_kind kind, + type *return_type, + const char *name, + vec<param *> *params, + int is_variadic, + enum built_in_function builtin_id); + + lvalue * + new_global (location *loc, + type *type, + const char *name); + + rvalue * + new_rvalue_from_int (type *type, + int value); + + rvalue * + new_rvalue_from_double (type *type, + double value); + + rvalue * + new_rvalue_from_ptr (type *type, + void *value); + + rvalue * + new_string_literal (const char *value); + + rvalue * + new_unary_op (location *loc, + enum gcc_jit_unary_op op, + type *result_type, + rvalue *a); + + rvalue * + new_binary_op (location *loc, + enum gcc_jit_binary_op op, + type *result_type, + rvalue *a, rvalue *b); + + rvalue * + new_comparison (location *loc, + enum gcc_jit_comparison op, + rvalue *a, rvalue *b); + + rvalue * + new_call (location *loc, + function *func, + vec<rvalue *> args); + + rvalue * + new_call_through_ptr (location *loc, + rvalue *fn_ptr, + vec<rvalue *> args); + + rvalue * + new_cast (location *loc, + rvalue *expr, + type *type_); + + lvalue * + new_array_access (location *loc, + rvalue *ptr, + rvalue *index); + + void + set_str_option (enum gcc_jit_str_option opt, + const char *value); + + void + set_int_option (enum gcc_jit_int_option opt, + int value); + + void + set_bool_option (enum gcc_jit_bool_option opt, + int value); + + const char * + get_str_option (enum gcc_jit_str_option opt) const + { + return m_recording_ctxt->get_str_option (opt); + } + + int + get_int_option (enum gcc_jit_int_option opt) const + { + return m_recording_ctxt->get_int_option (opt); + } + + int + get_bool_option (enum gcc_jit_bool_option opt) const + { + return m_recording_ctxt->get_bool_option (opt); + } + + result * + compile (); + + void + add_error (location *loc, const char *fmt, ...) + GNU_PRINTF(3, 4); + + void + add_error_va (location *loc, const char *fmt, va_list ap) + GNU_PRINTF(3, 0); + + const char * + get_first_error () const; + + void + set_tree_location (tree t, location *loc); + + tree + new_field_access (location *loc, + tree datum, + field *field); + + tree + new_dereference (tree ptr, location *loc); + + tree + as_truth_value (tree expr, location *loc); + + bool errors_occurred () const + { + return m_recording_ctxt->errors_occurred (); + } + +private: + void dump_generated_code (); + + rvalue * + build_call (location *loc, + tree fn_ptr, + vec<rvalue *> args); + + tree + build_cast (location *loc, + rvalue *expr, + type *type_); + + source_file * + get_source_file (const char *filename); + + void handle_locations (); + +private: + ::gcc::jit::recording::context *m_recording_ctxt; + + /* Allocated using xmalloc (by xstrdup). */ + char *m_path_template; + + /* This either aliases m_path_template, or is NULL. */ + char *m_path_tempdir; + + /* The following are allocated using xmalloc. */ + char *m_path_c_file; + char *m_path_s_file; + char *m_path_so_file; + + vec<function *> m_functions; + tree m_char_array_type_node; + tree m_const_char_ptr; + + /* Source location handling. */ + vec<source_file *> m_source_files; + + vec<std::pair<tree, location *> > m_cached_locations; +}; + +/* A temporary wrapper object. + These objects are (mostly) only valid during replay. + We allocate them on the GC heap, so that they will be cleaned + the next time the GC collects. + The exception is the "function" class, which is tracked and marked by + the jit::context, since it needs to stay alive during post-processing + (when the GC could run). */ +class wrapper +{ +public: + /* Allocate in the GC heap. */ + void *operator new (size_t sz); + +}; + +class type : public wrapper +{ +public: + type (tree inner) + : m_inner(inner) + {} + + tree as_tree () const { return m_inner; } + + type *get_pointer () const { return new type (build_pointer_type (m_inner)); } + + type *get_const () const + { + return new type (build_qualified_type (m_inner, TYPE_QUAL_CONST)); + } + + type *get_volatile () const + { + return new type (build_qualified_type (m_inner, TYPE_QUAL_VOLATILE)); + } + +private: + tree m_inner; +}; + +class compound_type : public type +{ +public: + compound_type (tree inner) + : type (inner) + {} + + void set_fields (const vec<field *> &fields); +}; + +class field : public wrapper +{ +public: + field (tree inner) + : m_inner(inner) + {} + + tree as_tree () const { return m_inner; } + +private: + tree m_inner; +}; + +class function : public wrapper +{ +public: + function(context *ctxt, tree fndecl, enum gcc_jit_function_kind kind); + + void gt_ggc_mx (); + + tree get_return_type_as_tree () const; + + tree as_fndecl () const { return m_inner_fndecl; } + + enum gcc_jit_function_kind get_kind () const { return m_kind; } + + lvalue * + new_local (location *loc, + type *type, + const char *name); + + block* + new_block (const char *name); + + void + build_stmt_list (); + + void + postprocess (); + +public: + context *m_ctxt; + +public: + void + set_tree_location (tree t, location *loc) + { + m_ctxt->set_tree_location (t, loc); + } + +private: + tree m_inner_fndecl; + tree m_inner_block; + tree m_inner_bind_expr; + enum gcc_jit_function_kind m_kind; + tree m_stmt_list; + tree_stmt_iterator m_stmt_iter; + vec<block *> m_blocks; +}; + +class block : public wrapper +{ +public: + block (function *func, + const char *name); + + tree as_label_decl () const { return m_label_decl; } + + void + add_eval (location *loc, + rvalue *rvalue); + + void + add_assignment (location *loc, + lvalue *lvalue, + rvalue *rvalue); + + void + add_comment (location *loc, + const char *text); + + void + add_conditional (location *loc, + rvalue *boolval, + block *on_true, + block *on_false); + + block * + add_block (location *loc, + const char *name); + + void + add_jump (location *loc, + block *target); + + void + add_return (location *loc, + rvalue *rvalue); + +private: + void + set_tree_location (tree t, location *loc) + { + m_func->set_tree_location (t, loc); + } + + void add_stmt (tree stmt) + { + /* TODO: use one stmt_list per block. */ + m_stmts.safe_push (stmt); + } + +private: + function *m_func; + tree m_label_decl; + vec<tree> m_stmts; + +public: // for now + tree m_label_expr; + + friend class function; +}; + +class rvalue : public wrapper +{ +public: + rvalue (context *ctxt, tree inner) + : m_ctxt (ctxt), + m_inner (inner) + {} + + rvalue * + as_rvalue () { return this; } + + tree as_tree () const { return m_inner; } + + context *get_context () const { return m_ctxt; } + + type * + get_type () { return new type (TREE_TYPE (m_inner)); } + + rvalue * + access_field (location *loc, + field *field); + + lvalue * + dereference_field (location *loc, + field *field); + + lvalue * + dereference (location *loc); + +private: + context *m_ctxt; + tree m_inner; +}; + +class lvalue : public rvalue +{ +public: + lvalue (context *ctxt, tree inner) + : rvalue(ctxt, inner) + {} + + lvalue * + as_lvalue () { return this; } + + lvalue * + access_field (location *loc, + field *field); + + rvalue * + get_address (location *loc); + +}; + +class param : public lvalue +{ +public: + param (context *ctxt, tree inner) + : lvalue(ctxt, inner) + {} +}; + +/* Dealing with the linemap API. + + It appears that libcpp requires locations to be created as if by + a tokenizer, creating them by filename, in ascending order of + line/column, whereas our API doesn't impose any such constraints: + we allow client code to create locations in arbitrary orders. + + To square this circle, we need to cache all location creation, + grouping things up by filename/line, and then creating the linemap + entries in a post-processing phase. */ + +/* A set of locations, all sharing a filename */ +class source_file : public wrapper +{ +public: + source_file (tree filename); + + source_line * + get_source_line (int line_num); + + tree filename_as_tree () const { return m_filename; } + + const char* + get_filename () const { return IDENTIFIER_POINTER (m_filename); } + + vec<source_line *> m_source_lines; + +private: + tree m_filename; +}; + +/* A source line, with one or more locations of interest. */ +class source_line : public wrapper +{ +public: + source_line (source_file *file, int line_num); + + location * + get_location (recording::location *rloc, int column_num); + + int get_line_num () const { return m_line_num; } + + vec<location *> m_locations; + +private: + source_file *m_source_file; + int m_line_num; +}; + +/* A specific location on a source line. This is what we expose + to the client API. */ +class location : public wrapper +{ +public: + location (recording::location *loc, source_line *line, int column_num); + + int get_column_num () const { return m_column_num; } + + recording::location *get_recording_loc () const { return m_recording_loc; } + + source_location m_srcloc; + +private: + recording::location *m_recording_loc; + source_line *m_line; + int m_column_num; +}; + +} // namespace gcc::jit::playback + +extern playback::context *active_playback_ctxt; + +} // namespace gcc::jit + +} // namespace gcc + +#endif /* JIT_PLAYBACK_H */ + -- 1.8.5.3