/* Internals of libgccjit: classes for recording calls made to the JIT API. Copyright (C) 2013-2017 Free Software Foundation, Inc. Contributed by David Malcolm . 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 . */ #ifndef JIT_RECORDING_H #define JIT_RECORDING_H #include "jit-common.h" #include "jit-logging.h" class timer; namespace gcc { namespace jit { class result; class dump; class reproducer; /********************************************************************** Recording. **********************************************************************/ namespace recording { playback::location * playback_location (replayer *r, location *loc); const char * playback_string (string *str); playback::block * playback_block (block *b); /* A recording of a call to gcc_jit_context_enable_dump. */ struct requested_dump { const char *m_dumpname; char **m_out_ptr; }; /* A JIT-compilation context. */ class context : public log_user { public: context (context *parent_ctxt); ~context (); builtins_manager * get_builtins_manager (); void record (memento *m); void replay_into (replayer *r); void disassociate_from_playback (); string * new_string (const char *text); location * new_location (const char *filename, int line, int column, bool created_by_user); type * get_type (enum gcc_jit_types type); type * get_int_type (int num_bytes, int is_signed); type * new_array_type (location *loc, type *element_type, int num_elements); field * new_field (location *loc, type *type, const char *name); struct_ * new_struct_type (location *loc, const char *name); union_ * new_union_type (location *loc, const char *name); function_type * new_function_type (type *return_type, int num_params, type **param_types, int is_variadic); type * new_function_ptr_type (location *loc, type *return_type, int num_params, 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, int num_params, param **params, int is_variadic, enum built_in_function builtin_id); function * get_builtin_function (const char *name); lvalue * new_global (location *loc, enum gcc_jit_global_kind kind, type *type, const char *name); template rvalue * new_rvalue_from_const (type *type, HOST_TYPE 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, int numargs, rvalue **args); rvalue * new_call_through_ptr (location *loc, rvalue *fn_ptr, int numargs, rvalue **args); rvalue * new_cast (location *loc, rvalue *expr, type *type_); lvalue * new_array_access (location *loc, rvalue *ptr, rvalue *index); case_ * new_case (rvalue *min_value, rvalue *max_value, block *block); 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); void set_inner_bool_option (enum inner_bool_option inner_opt, int value); void add_command_line_option (const char *optname); void append_command_line_options (vec *argvec); void enable_dump (const char *dumpname, char **out_ptr); const char * get_str_option (enum gcc_jit_str_option opt) const { return m_str_options[opt]; } int get_int_option (enum gcc_jit_int_option opt) const { return m_int_options[opt]; } int get_bool_option (enum gcc_jit_bool_option opt) const { return m_bool_options[opt]; } int get_inner_bool_option (enum inner_bool_option opt) const { return m_inner_bool_options[opt]; } result * compile (); void compile_to_file (enum gcc_jit_output_kind output_kind, const char *output_path); 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; const char * get_last_error () const; bool errors_occurred () const { if (m_parent_ctxt) if (m_parent_ctxt->errors_occurred ()) return true; return m_error_count; } type *get_opaque_FILE_type (); void dump_to_file (const char *path, bool update_locations); void dump_reproducer_to_file (const char *path); void get_all_requested_dumps (vec *out); void set_timer (timer *t) { m_timer = t; } timer *get_timer () const { return m_timer; } private: void log_all_options () const; void log_str_option (enum gcc_jit_str_option opt) const; void log_int_option (enum gcc_jit_int_option opt) const; void log_bool_option (enum gcc_jit_bool_option opt) const; void log_inner_bool_option (enum inner_bool_option opt) const; void validate (); private: context *m_parent_ctxt; /* The ultimate ancestor of the contexts within a family tree of contexts. This has itself as its own m_toplevel_ctxt. */ context *m_toplevel_ctxt; timer *m_timer; int m_error_count; char *m_first_error_str; bool m_owns_first_error_str; char *m_last_error_str; bool m_owns_last_error_str; char *m_str_options[GCC_JIT_NUM_STR_OPTIONS]; int m_int_options[GCC_JIT_NUM_INT_OPTIONS]; bool m_bool_options[GCC_JIT_NUM_BOOL_OPTIONS]; bool m_inner_bool_options[NUM_INNER_BOOL_OPTIONS]; auto_vec m_command_line_options; /* Dumpfiles that were requested via gcc_jit_context_enable_dump. */ auto_vec m_requested_dumps; /* Recorded API usage. */ auto_vec m_mementos; /* Specific recordings, for use by dump_to_file. */ auto_vec m_compound_types; auto_vec m_globals; auto_vec m_functions; type *m_basic_types[NUM_GCC_JIT_TYPES]; type *m_FILE_type; builtins_manager *m_builtins_manager; // lazily created }; /* An object with lifetime managed by the context i.e. it lives until the context is released, at which point it itself is cleaned up. */ class memento { public: virtual ~memento () {} /* Hook for replaying this. */ virtual void replay_into (replayer *r) = 0; void set_playback_obj (void *obj) { m_playback_obj = obj; } /* Get the context that owns this object. Implements the post-error-checking part of gcc_jit_object_get_context. */ context *get_context () { return m_ctxt; } memento * as_object () { return this; } /* Debugging hook, for use in generating error messages etc. Implements the post-error-checking part of gcc_jit_object_get_debug_string. */ const char * get_debug_string (); virtual void write_to_dump (dump &d); virtual void write_reproducer (reproducer &r) = 0; virtual location *dyn_cast_location () { return NULL; } protected: memento (context *ctxt) : m_ctxt (ctxt), m_playback_obj (NULL), m_debug_string (NULL) { gcc_assert (ctxt); } string *new_string (const char *text) { return m_ctxt->new_string (text); } private: virtual string * make_debug_string () = 0; public: context *m_ctxt; protected: void *m_playback_obj; private: string *m_debug_string; }; /* or just use std::string? */ class string : public memento { public: string (context *ctxt, const char *text); ~string (); const char *c_str () { return m_buffer; } static string * from_printf (context *ctxt, const char *fmt, ...) GNU_PRINTF(2, 3); void replay_into (replayer *) FINAL OVERRIDE {} private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: size_t m_len; char *m_buffer; }; class location : public memento { public: location (context *ctxt, string *filename, int line, int column, bool created_by_user) : memento (ctxt), m_filename (filename), m_line (line), m_column (column), m_created_by_user (created_by_user) {} void replay_into (replayer *r) FINAL OVERRIDE; playback::location * playback_location (replayer *r) { /* Normally during playback, we can walk forwards through the list of recording objects, playing them back. The ordering of recording ensures that everything that a recording object refers to has already been played back, so we can simply look up the relevant m_playback_obj. Locations are an exception, due to the "write_to_dump" method of recording::statement. This method can set a new location on a statement after the statement is created, and thus the location appears in the context's memento list *after* the statement that refers to it. In such circumstances, the statement is replayed *before* the location, when the latter doesn't yet have a playback object. Hence we need to ensure that locations have playback objects. */ if (!m_playback_obj) { replay_into (r); } gcc_assert (m_playback_obj); return static_cast (m_playback_obj); } location *dyn_cast_location () FINAL OVERRIDE { return this; } bool created_by_user () const { return m_created_by_user; } private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: string *m_filename; int m_line; int m_column; bool m_created_by_user; }; class type : public memento { public: type *get_pointer (); type *get_const (); type *get_volatile (); /* Get the type obtained when dereferencing this type. This will return NULL if it's not valid to dereference this type. The caller is responsible for setting an error. */ virtual type *dereference () = 0; /* Dynamic casts. */ virtual function_type *dyn_cast_function_type () { return NULL; } virtual function_type *as_a_function_type() { gcc_unreachable (); return NULL; } virtual struct_ *dyn_cast_struct () { return NULL; } /* Is it typesafe to copy to this type from rtype? */ virtual bool accepts_writes_from (type *rtype) { gcc_assert (rtype); return this == rtype->unqualified (); } /* Strip off "const" etc */ virtual type *unqualified () { return this; } virtual bool is_int () const = 0; virtual bool is_float () const = 0; virtual bool is_bool () const = 0; virtual type *is_pointer () = 0; virtual type *is_array () = 0; virtual bool is_void () const { return false; } virtual bool has_known_size () const { return true; } bool is_numeric () const { return is_int () || is_float () || is_bool (); } playback::type * playback_type () { return static_cast (m_playback_obj); } virtual const char *access_as_type (reproducer &r); protected: type (context *ctxt) : memento (ctxt), m_pointer_to_this_type (NULL) {} private: type *m_pointer_to_this_type; }; /* Result of "gcc_jit_context_get_type". */ class memento_of_get_type : public type { public: memento_of_get_type (context *ctxt, enum gcc_jit_types kind) : type (ctxt), m_kind (kind) {} type *dereference () FINAL OVERRIDE; bool accepts_writes_from (type *rtype) FINAL OVERRIDE { if (m_kind == GCC_JIT_TYPE_VOID_PTR) if (rtype->is_pointer ()) { /* LHS (this) is type (void *), and the RHS is a pointer: accept it: */ return true; } return type::accepts_writes_from (rtype); } bool is_int () const FINAL OVERRIDE; bool is_float () const FINAL OVERRIDE; bool is_bool () const FINAL OVERRIDE; type *is_pointer () FINAL OVERRIDE { return dereference (); } type *is_array () FINAL OVERRIDE { return NULL; } bool is_void () const FINAL OVERRIDE { return m_kind == GCC_JIT_TYPE_VOID; } public: void replay_into (replayer *r) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: enum gcc_jit_types m_kind; }; /* Result of "gcc_jit_type_get_pointer". */ class memento_of_get_pointer : public type { public: memento_of_get_pointer (type *other_type) : type (other_type->m_ctxt), m_other_type (other_type) {} type *dereference () FINAL OVERRIDE { return m_other_type; } bool accepts_writes_from (type *rtype) FINAL OVERRIDE; void replay_into (replayer *r) FINAL OVERRIDE; bool is_int () const FINAL OVERRIDE { return false; } bool is_float () const FINAL OVERRIDE { return false; } bool is_bool () const FINAL OVERRIDE { return false; } type *is_pointer () FINAL OVERRIDE { return m_other_type; } type *is_array () FINAL OVERRIDE { return NULL; } private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: type *m_other_type; }; /* Result of "gcc_jit_type_get_const". */ class memento_of_get_const : public type { public: memento_of_get_const (type *other_type) : type (other_type->m_ctxt), m_other_type (other_type) {} type *dereference () FINAL OVERRIDE { return m_other_type->dereference (); } bool accepts_writes_from (type */*rtype*/) FINAL OVERRIDE { /* Can't write to a "const". */ return false; } /* Strip off the "const", giving the underlying type. */ type *unqualified () FINAL OVERRIDE { return m_other_type; } bool is_int () const FINAL OVERRIDE { return m_other_type->is_int (); } bool is_float () const FINAL OVERRIDE { return m_other_type->is_float (); } bool is_bool () const FINAL OVERRIDE { return m_other_type->is_bool (); } type *is_pointer () FINAL OVERRIDE { return m_other_type->is_pointer (); } type *is_array () FINAL OVERRIDE { return m_other_type->is_array (); } void replay_into (replayer *) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: type *m_other_type; }; /* Result of "gcc_jit_type_get_volatile". */ class memento_of_get_volatile : public type { public: memento_of_get_volatile (type *other_type) : type (other_type->m_ctxt), m_other_type (other_type) {} type *dereference () FINAL OVERRIDE { return m_other_type->dereference (); } /* Strip off the "volatile", giving the underlying type. */ type *unqualified () FINAL OVERRIDE { return m_other_type; } bool is_int () const FINAL OVERRIDE { return m_other_type->is_int (); } bool is_float () const FINAL OVERRIDE { return m_other_type->is_float (); } bool is_bool () const FINAL OVERRIDE { return m_other_type->is_bool (); } type *is_pointer () FINAL OVERRIDE { return m_other_type->is_pointer (); } type *is_array () FINAL OVERRIDE { return m_other_type->is_array (); } void replay_into (replayer *) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: type *m_other_type; }; class array_type : public type { public: array_type (context *ctxt, location *loc, type *element_type, int num_elements) : type (ctxt), m_loc (loc), m_element_type (element_type), m_num_elements (num_elements) {} type *dereference () FINAL OVERRIDE; bool is_int () const FINAL OVERRIDE { return false; } bool is_float () const FINAL OVERRIDE { return false; } bool is_bool () const FINAL OVERRIDE { return false; } type *is_pointer () FINAL OVERRIDE { return NULL; } type *is_array () FINAL OVERRIDE { return m_element_type; } void replay_into (replayer *) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: location *m_loc; type *m_element_type; int m_num_elements; }; class function_type : public type { public: function_type (context *ctxt, type *return_type, int num_params, type **param_types, int is_variadic); type *dereference () FINAL OVERRIDE; function_type *dyn_cast_function_type () FINAL OVERRIDE { return this; } function_type *as_a_function_type () FINAL OVERRIDE { return this; } bool is_int () const FINAL OVERRIDE { return false; } bool is_float () const FINAL OVERRIDE { return false; } bool is_bool () const FINAL OVERRIDE { return false; } type *is_pointer () FINAL OVERRIDE { return NULL; } type *is_array () FINAL OVERRIDE { return NULL; } void replay_into (replayer *) FINAL OVERRIDE; type * get_return_type () const { return m_return_type; } const vec &get_param_types () const { return m_param_types; } int is_variadic () const { return m_is_variadic; } string * make_debug_string_with_ptr (); void write_deferred_reproducer (reproducer &r, memento *ptr_type); private: string * make_debug_string () FINAL OVERRIDE; string * make_debug_string_with (const char *); void write_reproducer (reproducer &r) FINAL OVERRIDE; private: type *m_return_type; auto_vec m_param_types; int m_is_variadic; }; class field : public memento { public: field (context *ctxt, location *loc, type *type, string *name) : memento (ctxt), m_loc (loc), m_type (type), m_name (name), m_container (NULL) {} type * get_type () const { return m_type; } compound_type * get_container () const { return m_container; } void set_container (compound_type *c) { m_container = c; } void replay_into (replayer *) FINAL OVERRIDE; void write_to_dump (dump &d) FINAL OVERRIDE; playback::field * playback_field () const { return static_cast (m_playback_obj); } private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: location *m_loc; type *m_type; string *m_name; compound_type *m_container; }; /* Base class for struct_ and union_ */ class compound_type : public type { public: compound_type (context *ctxt, location *loc, string *name); string *get_name () const { return m_name; } location *get_loc () const { return m_loc; } fields * get_fields () { return m_fields; } void set_fields (location *loc, int num_fields, field **fields); type *dereference () FINAL OVERRIDE; bool is_int () const FINAL OVERRIDE { return false; } bool is_float () const FINAL OVERRIDE { return false; } bool is_bool () const FINAL OVERRIDE { return false; } type *is_pointer () FINAL OVERRIDE { return NULL; } type *is_array () FINAL OVERRIDE { return NULL; } bool has_known_size () const FINAL OVERRIDE { return m_fields != NULL; } playback::compound_type * playback_compound_type () { return static_cast (m_playback_obj); } private: location *m_loc; string *m_name; fields *m_fields; }; class struct_ : public compound_type { public: struct_ (context *ctxt, location *loc, string *name); struct_ *dyn_cast_struct () FINAL OVERRIDE { return this; } type * as_type () { return this; } void replay_into (replayer *r) FINAL OVERRIDE; const char *access_as_type (reproducer &r) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; }; // memento of struct_::set_fields class fields : public memento { public: fields (compound_type *struct_or_union, int num_fields, field **fields); void replay_into (replayer *r) FINAL OVERRIDE; void write_to_dump (dump &d) FINAL OVERRIDE; int length () const { return m_fields.length (); } field *get_field (int i) const { return m_fields[i]; } private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: compound_type *m_struct_or_union; auto_vec m_fields; }; class union_ : public compound_type { public: union_ (context *ctxt, location *loc, string *name); void replay_into (replayer *r) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: location *m_loc; string *m_name; }; /* An abstract base class for operations that visit all rvalues within an expression tree. Currently the only implementation is class rvalue_usage_validator within jit-recording.c. */ class rvalue_visitor { public: virtual ~rvalue_visitor () {} virtual void visit (rvalue *rvalue) = 0; }; /* When generating debug strings for rvalues we mimic C, so we need to mimic C's precedence levels when handling compound expressions. These are in order from strongest precedence to weakest. */ enum precedence { PRECEDENCE_PRIMARY, PRECEDENCE_POSTFIX, PRECEDENCE_UNARY, PRECEDENCE_CAST, PRECEDENCE_MULTIPLICATIVE, PRECEDENCE_ADDITIVE, PRECEDENCE_SHIFT, PRECEDENCE_RELATIONAL, PRECEDENCE_EQUALITY, PRECEDENCE_BITWISE_AND, PRECEDENCE_BITWISE_XOR, PRECEDENCE_BITWISE_IOR, PRECEDENCE_LOGICAL_AND, PRECEDENCE_LOGICAL_OR }; class rvalue : public memento { public: rvalue (context *ctxt, location *loc, type *type_) : memento (ctxt), m_loc (loc), m_type (type_), m_scope (NULL), m_parenthesized_string (NULL) { gcc_assert (type_); } location * get_loc () const { return m_loc; } /* Get the recording::type of this rvalue. Implements the post-error-checking part of gcc_jit_rvalue_get_type. */ type * get_type () const { return m_type; } playback::rvalue * playback_rvalue () const { return static_cast (m_playback_obj); } rvalue * access_field (location *loc, field *field); lvalue * dereference_field (location *loc, field *field); lvalue * dereference (location *loc); void verify_valid_within_stmt (const char *api_funcname, statement *s); virtual void visit_children (rvalue_visitor *v) = 0; void set_scope (function *scope); function *get_scope () const { return m_scope; } /* Dynamic casts. */ virtual param *dyn_cast_param () { return NULL; } virtual base_call *dyn_cast_base_call () { return NULL; } virtual const char *access_as_rvalue (reproducer &r); /* Get the debug string, wrapped in parentheses. */ const char * get_debug_string_parens (enum precedence outer_prec); virtual bool is_constant () const { return false; } virtual bool get_wide_int (wide_int *) const { return false; } private: virtual enum precedence get_precedence () const = 0; protected: location *m_loc; type *m_type; private: function *m_scope; /* NULL for globals, non-NULL for locals/params */ string *m_parenthesized_string; }; class lvalue : public rvalue { public: lvalue (context *ctxt, location *loc, type *type_) : rvalue (ctxt, loc, type_) {} playback::lvalue * playback_lvalue () const { return static_cast (m_playback_obj); } lvalue * access_field (location *loc, field *field); rvalue * get_address (location *loc); rvalue * as_rvalue () { return this; } const char *access_as_rvalue (reproducer &r) OVERRIDE; virtual const char *access_as_lvalue (reproducer &r); }; class param : public lvalue { public: param (context *ctxt, location *loc, type *type, string *name) : lvalue (ctxt, loc, type), m_name (name) {} lvalue * as_lvalue () { return this; } void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *) FINAL OVERRIDE {} playback::param * playback_param () const { return static_cast (m_playback_obj); } param *dyn_cast_param () FINAL OVERRIDE { return this; } const char *access_as_rvalue (reproducer &r) FINAL OVERRIDE; const char *access_as_lvalue (reproducer &r) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE { return m_name; } void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_PRIMARY; } private: string *m_name; }; class function : public memento { public: function (context *ctxt, location *loc, enum gcc_jit_function_kind kind, type *return_type, string *name, int num_params, param **params, int is_variadic, enum built_in_function builtin_id); void replay_into (replayer *r) FINAL OVERRIDE; playback::function * playback_function () const { return static_cast (m_playback_obj); } 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); location *get_loc () const { return m_loc; } type *get_return_type () const { return m_return_type; } string * get_name () const { return m_name; } const vec &get_params () const { return m_params; } /* Get the given param by index. Implements the post-error-checking part of gcc_jit_function_get_param. */ param *get_param (int i) const { return m_params[i]; } bool is_variadic () const { return m_is_variadic; } void write_to_dump (dump &d) FINAL OVERRIDE; void validate (); void dump_to_dot (const char *path); private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: location *m_loc; enum gcc_jit_function_kind m_kind; type *m_return_type; string *m_name; auto_vec m_params; int m_is_variadic; enum built_in_function m_builtin_id; auto_vec m_locals; auto_vec m_blocks; }; class block : public memento { public: block (function *func, int index, string *name) : memento (func->m_ctxt), m_func (func), m_index (index), m_name (name), m_statements (), m_has_been_terminated (false), m_is_reachable (false) { } /* Get the recording::function containing this block. Implements the post-error-checking part of gcc_jit_block_get_function. */ function *get_function () { return m_func; } bool has_been_terminated () { return m_has_been_terminated; } bool is_reachable () { return m_is_reachable; } statement * add_eval (location *loc, rvalue *rvalue); statement * add_assignment (location *loc, lvalue *lvalue, rvalue *rvalue); statement * add_assignment_op (location *loc, lvalue *lvalue, enum gcc_jit_binary_op op, rvalue *rvalue); statement * add_comment (location *loc, const char *text); statement * end_with_conditional (location *loc, rvalue *boolval, block *on_true, block *on_false); statement * end_with_jump (location *loc, block *target); statement * end_with_return (location *loc, rvalue *rvalue); statement * end_with_switch (location *loc, rvalue *expr, block *default_block, int num_cases, case_ **cases); playback::block * playback_block () const { return static_cast (m_playback_obj); } void write_to_dump (dump &d) FINAL OVERRIDE; bool validate (); location *get_loc () const; statement *get_first_statement () const; statement *get_last_statement () const; vec get_successor_blocks () const; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; void replay_into (replayer *r) FINAL OVERRIDE; void dump_to_dot (pretty_printer *pp); void dump_edges_to_dot (pretty_printer *pp); private: function *m_func; int m_index; string *m_name; auto_vec m_statements; bool m_has_been_terminated; bool m_is_reachable; friend class function; }; class global : public lvalue { public: global (context *ctxt, location *loc, enum gcc_jit_global_kind kind, type *type, string *name) : lvalue (ctxt, loc, type), m_kind (kind), m_name (name) {} void replay_into (replayer *) FINAL OVERRIDE; void visit_children (rvalue_visitor *) FINAL OVERRIDE {} void write_to_dump (dump &d) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE { return m_name; } void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_PRIMARY; } private: enum gcc_jit_global_kind m_kind; string *m_name; }; template class memento_of_new_rvalue_from_const : public rvalue { public: memento_of_new_rvalue_from_const (context *ctxt, location *loc, type *type, HOST_TYPE value) : rvalue (ctxt, loc, type), m_value (value) {} void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *) FINAL OVERRIDE {} bool is_constant () const FINAL OVERRIDE { return true; } bool get_wide_int (wide_int *out) const FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_PRIMARY; } private: HOST_TYPE m_value; }; class memento_of_new_string_literal : public rvalue { public: memento_of_new_string_literal (context *ctxt, location *loc, string *value) : rvalue (ctxt, loc, ctxt->get_type (GCC_JIT_TYPE_CONST_CHAR_PTR)), m_value (value) {} void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *) FINAL OVERRIDE {} private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_PRIMARY; } private: string *m_value; }; class unary_op : public rvalue { public: unary_op (context *ctxt, location *loc, enum gcc_jit_unary_op op, type *result_type, rvalue *a) : rvalue (ctxt, loc, result_type), m_op (op), m_a (a) {} void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *v) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_UNARY; } private: enum gcc_jit_unary_op m_op; rvalue *m_a; }; class binary_op : public rvalue { public: binary_op (context *ctxt, location *loc, enum gcc_jit_binary_op op, type *result_type, rvalue *a, rvalue *b) : rvalue (ctxt, loc, result_type), m_op (op), m_a (a), m_b (b) {} void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *v) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE; private: enum gcc_jit_binary_op m_op; rvalue *m_a; rvalue *m_b; }; class comparison : public rvalue { public: comparison (context *ctxt, location *loc, enum gcc_jit_comparison op, rvalue *a, rvalue *b) : rvalue (ctxt, loc, ctxt->get_type (GCC_JIT_TYPE_BOOL)), m_op (op), m_a (a), m_b (b) {} void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *v) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE; private: enum gcc_jit_comparison m_op; rvalue *m_a; rvalue *m_b; }; class cast : public rvalue { public: cast (context *ctxt, location *loc, rvalue *a, type *type_) : rvalue (ctxt, loc, type_), m_rvalue (a) {} void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *v) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_CAST; } private: rvalue *m_rvalue; }; class base_call : public rvalue { public: base_call (context *ctxt, location *loc, type *type_, int numargs, rvalue **args); enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_POSTFIX; } base_call *dyn_cast_base_call () FINAL OVERRIDE { return this; } void set_require_tail_call (bool require_tail_call) { m_require_tail_call = require_tail_call; } protected: void write_reproducer_tail_call (reproducer &r, const char *id); protected: auto_vec m_args; bool m_require_tail_call; }; class call : public base_call { public: call (context *ctxt, location *loc, function *func, int numargs, rvalue **args); void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *v) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: function *m_func; }; class call_through_ptr : public base_call { public: call_through_ptr (context *ctxt, location *loc, rvalue *fn_ptr, int numargs, rvalue **args); void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *v) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: rvalue *m_fn_ptr; }; class array_access : public lvalue { public: array_access (context *ctxt, location *loc, rvalue *ptr, rvalue *index) : lvalue (ctxt, loc, ptr->get_type ()->dereference ()), m_ptr (ptr), m_index (index) {} void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *v) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_POSTFIX; } private: rvalue *m_ptr; rvalue *m_index; }; class access_field_of_lvalue : public lvalue { public: access_field_of_lvalue (context *ctxt, location *loc, lvalue *val, field *field) : lvalue (ctxt, loc, field->get_type ()), m_lvalue (val), m_field (field) {} void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *v) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_POSTFIX; } private: lvalue *m_lvalue; field *m_field; }; class access_field_rvalue : public rvalue { public: access_field_rvalue (context *ctxt, location *loc, rvalue *val, field *field) : rvalue (ctxt, loc, field->get_type ()), m_rvalue (val), m_field (field) {} void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *v) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_POSTFIX; } private: rvalue *m_rvalue; field *m_field; }; class dereference_field_rvalue : public lvalue { public: dereference_field_rvalue (context *ctxt, location *loc, rvalue *val, field *field) : lvalue (ctxt, loc, field->get_type ()), m_rvalue (val), m_field (field) {} void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *v) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_POSTFIX; } private: rvalue *m_rvalue; field *m_field; }; class dereference_rvalue : public lvalue { public: dereference_rvalue (context *ctxt, location *loc, rvalue *val) : lvalue (ctxt, loc, val->get_type ()->dereference ()), m_rvalue (val) {} void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *v) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_UNARY; } private: rvalue *m_rvalue; }; class get_address_of_lvalue : public rvalue { public: get_address_of_lvalue (context *ctxt, location *loc, lvalue *val) : rvalue (ctxt, loc, val->get_type ()->get_pointer ()), m_lvalue (val) {} void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *v) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_UNARY; } private: lvalue *m_lvalue; }; class local : public lvalue { public: local (function *func, location *loc, type *type_, string *name) : lvalue (func->m_ctxt, loc, type_), m_func (func), m_name (name) { set_scope (func); } void replay_into (replayer *r) FINAL OVERRIDE; void visit_children (rvalue_visitor *) FINAL OVERRIDE {} void write_to_dump (dump &d) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE { return m_name; } void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { return PRECEDENCE_PRIMARY; } private: function *m_func; string *m_name; }; class statement : public memento { public: virtual vec get_successor_blocks () const; void write_to_dump (dump &d) FINAL OVERRIDE; block *get_block () const { return m_block; } location *get_loc () const { return m_loc; } protected: statement (block *b, location *loc) : memento (b->m_ctxt), m_block (b), m_loc (loc) {} playback::location * playback_location (replayer *r) const { return ::gcc::jit::recording::playback_location (r, m_loc); } private: block *m_block; location *m_loc; }; class eval : public statement { public: eval (block *b, location *loc, rvalue *rvalue) : statement (b, loc), m_rvalue (rvalue) {} void replay_into (replayer *r) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: rvalue *m_rvalue; }; class assignment : public statement { public: assignment (block *b, location *loc, lvalue *lvalue, rvalue *rvalue) : statement (b, loc), m_lvalue (lvalue), m_rvalue (rvalue) {} void replay_into (replayer *r) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: lvalue *m_lvalue; rvalue *m_rvalue; }; class assignment_op : public statement { public: assignment_op (block *b, location *loc, lvalue *lvalue, enum gcc_jit_binary_op op, rvalue *rvalue) : statement (b, loc), m_lvalue (lvalue), m_op (op), m_rvalue (rvalue) {} void replay_into (replayer *r) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: lvalue *m_lvalue; enum gcc_jit_binary_op m_op; rvalue *m_rvalue; }; class comment : public statement { public: comment (block *b, location *loc, string *text) : statement (b, loc), m_text (text) {} void replay_into (replayer *r) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: string *m_text; }; class conditional : public statement { public: conditional (block *b, location *loc, rvalue *boolval, block *on_true, block *on_false) : statement (b, loc), m_boolval (boolval), m_on_true (on_true), m_on_false (on_false) {} void replay_into (replayer *r) FINAL OVERRIDE; vec get_successor_blocks () const FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: rvalue *m_boolval; block *m_on_true; block *m_on_false; }; class jump : public statement { public: jump (block *b, location *loc, block *target) : statement (b, loc), m_target (target) {} void replay_into (replayer *r) FINAL OVERRIDE; vec get_successor_blocks () const FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: block *m_target; }; class return_ : public statement { public: return_ (block *b, location *loc, rvalue *rvalue) : statement (b, loc), m_rvalue (rvalue) {} void replay_into (replayer *r) FINAL OVERRIDE; vec get_successor_blocks () const FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: rvalue *m_rvalue; }; class case_ : public memento { public: case_ (context *ctxt, rvalue *min_value, rvalue *max_value, block *dest_block) : memento (ctxt), m_min_value (min_value), m_max_value (max_value), m_dest_block (dest_block) {} rvalue *get_min_value () const { return m_min_value; } rvalue *get_max_value () const { return m_max_value; } block *get_dest_block () const { return m_dest_block; } void replay_into (replayer *) FINAL OVERRIDE { /* empty */ } void write_reproducer (reproducer &r) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; private: rvalue *m_min_value; rvalue *m_max_value; block *m_dest_block; }; class switch_ : public statement { public: switch_ (block *b, location *loc, rvalue *expr, block *default_block, int num_cases, case_ **cases); void replay_into (replayer *r) FINAL OVERRIDE; vec get_successor_blocks () const FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; private: rvalue *m_expr; block *m_default_block; auto_vec m_cases; }; } // namespace gcc::jit::recording /* Create a recording::memento_of_new_rvalue_from_const instance and add it to this context's list of mementos. Implements the post-error-checking part of gcc_jit_context_new_rvalue_from_{int|long|double|ptr}. */ template recording::rvalue * recording::context::new_rvalue_from_const (recording::type *type, HOST_TYPE value) { recording::rvalue *result = new memento_of_new_rvalue_from_const (this, NULL, type, value); record (result); return result; } } // namespace gcc::jit } // namespace gcc #endif /* JIT_RECORDING_H */