| /* Internals of libgccjit: classes for recording calls made to the JIT API. |
| Copyright (C) 2013-2022 Free Software Foundation, Inc. |
| Contributed by David Malcolm <dmalcolm@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_RECORDING_H |
| #define JIT_RECORDING_H |
| |
| #include "jit-common.h" |
| #include "jit-logging.h" |
| |
| class timer; |
| |
| namespace gcc { |
| |
| namespace jit { |
| |
| extern const char * const unary_op_reproducer_strings[]; |
| extern const char * const binary_op_reproducer_strings[]; |
| |
| 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, bool escaped = false); |
| |
| 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); |
| |
| field * |
| new_bitfield (location *loc, |
| type *type, |
| int width, |
| 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); |
| |
| rvalue * |
| new_ctor (location *loc, |
| type *type, |
| size_t num_values, |
| field **fields, |
| rvalue **values); |
| |
| void |
| new_global_init_rvalue (lvalue *variable, |
| rvalue *init); |
| |
| template <typename HOST_TYPE> |
| rvalue * |
| new_rvalue_from_const (type *type, |
| HOST_TYPE value); |
| |
| rvalue * |
| new_string_literal (const char *value); |
| |
| rvalue * |
| new_rvalue_from_vector (location *loc, |
| vector_type *type, |
| rvalue **elements); |
| |
| 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_); |
| |
| rvalue * |
| new_bitcast (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 <char *> *argvec); |
| |
| void |
| add_driver_option (const char *optname); |
| |
| void |
| append_driver_options (auto_string_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 <recording::requested_dump> *out); |
| |
| void set_timer (timer *t) { m_timer = t; } |
| timer *get_timer () const { return m_timer; } |
| |
| void add_top_level_asm (location *loc, const char *asm_stmts); |
| |
| 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 <char *> m_command_line_options; |
| auto_vec <char *> m_driver_options; |
| |
| /* Dumpfiles that were requested via gcc_jit_context_enable_dump. */ |
| auto_vec<requested_dump> m_requested_dumps; |
| |
| /* Recorded API usage. */ |
| auto_vec<memento *> m_mementos; |
| |
| /* Specific recordings, for use by dump_to_file. */ |
| auto_vec<compound_type *> m_compound_types; |
| auto_vec<global *> m_globals; |
| auto_vec<function *> m_functions; |
| auto_vec<top_level_asm *> m_top_level_asms; |
| |
| 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; } |
| |
| memento (const memento&) = delete; |
| memento& operator= (const memento&) = delete; |
| |
| 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, bool escaped); |
| ~string (); |
| |
| const char *c_str () const { return m_buffer; } |
| |
| static string * from_printf (context *ctxt, const char *fmt, ...) |
| GNU_PRINTF(2, 3); |
| |
| void replay_into (replayer *) final override {} |
| |
| string (const string&) = delete; |
| string& operator= (const string&) = delete; |
| |
| private: |
| string * make_debug_string () final override; |
| void write_reproducer (reproducer &r) final override; |
| |
| private: |
| size_t m_len; |
| char *m_buffer; |
| |
| /* Flag to track if this string is the result of string::make_debug_string, |
| to avoid infinite recursion when logging all mementos: don't re-escape |
| such strings. */ |
| bool m_escaped; |
| }; |
| |
| 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 <playback::location *> (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 (); |
| type *get_aligned (size_t alignment_in_bytes); |
| type *get_vector (size_t num_units); |
| |
| /* 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; |
| /* Get the type size in bytes. |
| |
| This is implemented only for memento_of_get_type and |
| memento_of_get_pointer as it is used for initializing globals of |
| these types. */ |
| virtual size_t get_size () { gcc_unreachable (); } |
| |
| /* 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; } |
| virtual vector_type *dyn_cast_vector_type () { return NULL; } |
| |
| /* Is it typesafe to copy to this type from rtype? */ |
| virtual bool accepts_writes_from (type *rtype) |
| { |
| gcc_assert (rtype); |
| return this->unqualified ()->is_same_type_as (rtype->unqualified ()); |
| } |
| |
| virtual bool is_same_type_as (type *other) |
| { |
| return this == other; |
| } |
| |
| /* 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_volatile () { return NULL; } |
| virtual type *is_const () { return NULL; } |
| virtual type *is_array () = 0; |
| virtual struct_ *is_struct () { return NULL; } |
| virtual bool is_union () const { return false; } |
| virtual bool is_void () const { return false; } |
| virtual vector_type *is_vector () { return NULL; } |
| virtual bool has_known_size () const { return true; } |
| virtual bool is_signed () const = 0; |
| |
| bool is_numeric () const |
| { |
| return is_int () || is_float () || is_bool (); |
| } |
| |
| playback::type * |
| playback_type () |
| { |
| return static_cast <playback::type *> (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; |
| |
| size_t get_size () 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; |
| } |
| } else if (is_int () |
| && rtype->is_int () |
| && get_size () == rtype->get_size () |
| && is_signed () == rtype->is_signed ()) |
| { |
| /* LHS (this) is an integer of the same size and sign as rtype. */ |
| 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; } |
| bool is_signed () const final override; |
| |
| 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; } |
| |
| size_t get_size () final override; |
| |
| 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; } |
| bool is_signed () const final override { return false; } |
| |
| private: |
| string * make_debug_string () final override; |
| void write_reproducer (reproducer &r) final override; |
| |
| private: |
| type *m_other_type; |
| }; |
| |
| /* A decorated version of a type, for get_const, get_volatile, |
| get_aligned, and get_vector. */ |
| |
| class decorated_type : public type |
| { |
| public: |
| decorated_type (type *other_type) |
| : type (other_type->m_ctxt), |
| m_other_type (other_type) {} |
| |
| type *dereference () final override { return m_other_type->dereference (); } |
| |
| size_t get_size () final override { return m_other_type->get_size (); }; |
| |
| 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 (); } |
| struct_ *is_struct () final override { return m_other_type->is_struct (); } |
| bool is_signed () const final override { return m_other_type->is_signed (); } |
| |
| protected: |
| type *m_other_type; |
| }; |
| |
| /* Result of "gcc_jit_type_get_const". */ |
| class memento_of_get_const : public decorated_type |
| { |
| public: |
| memento_of_get_const (type *other_type) |
| : decorated_type (other_type) {} |
| |
| 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_same_type_as (type *other) final override |
| { |
| if (!other->is_const ()) |
| return false; |
| return m_other_type->is_same_type_as (other->is_const ()); |
| } |
| |
| type *is_const () final override { return m_other_type; } |
| |
| void replay_into (replayer *) final override; |
| |
| private: |
| string * make_debug_string () final override; |
| void write_reproducer (reproducer &r) final override; |
| }; |
| |
| /* Result of "gcc_jit_type_get_volatile". */ |
| class memento_of_get_volatile : public decorated_type |
| { |
| public: |
| memento_of_get_volatile (type *other_type) |
| : decorated_type (other_type) {} |
| |
| bool is_same_type_as (type *other) final override |
| { |
| if (!other->is_volatile ()) |
| return false; |
| return m_other_type->is_same_type_as (other->is_volatile ()); |
| } |
| |
| /* Strip off the "volatile", giving the underlying type. */ |
| type *unqualified () final override { return m_other_type; } |
| |
| type *is_volatile () final override { return m_other_type; } |
| |
| void replay_into (replayer *) final override; |
| |
| private: |
| string * make_debug_string () final override; |
| void write_reproducer (reproducer &r) final override; |
| }; |
| |
| /* Result of "gcc_jit_type_get_aligned". */ |
| class memento_of_get_aligned : public decorated_type |
| { |
| public: |
| memento_of_get_aligned (type *other_type, size_t alignment_in_bytes) |
| : decorated_type (other_type), |
| m_alignment_in_bytes (alignment_in_bytes) {} |
| |
| /* Strip off the alignment, giving the underlying type. */ |
| type *unqualified () final override { return m_other_type; } |
| |
| void replay_into (replayer *) final override; |
| |
| private: |
| string * make_debug_string () final override; |
| void write_reproducer (reproducer &r) final override; |
| |
| private: |
| size_t m_alignment_in_bytes; |
| }; |
| |
| /* Result of "gcc_jit_type_get_vector". */ |
| class vector_type : public decorated_type |
| { |
| public: |
| vector_type (type *other_type, size_t num_units) |
| : decorated_type (other_type), |
| m_num_units (num_units) {} |
| |
| size_t get_num_units () const { return m_num_units; } |
| |
| vector_type *dyn_cast_vector_type () final override { return this; } |
| |
| type *get_element_type () { return m_other_type; } |
| |
| void replay_into (replayer *) final override; |
| |
| vector_type *is_vector () final override { return this; } |
| |
| private: |
| string * make_debug_string () final override; |
| void write_reproducer (reproducer &r) final override; |
| |
| private: |
| size_t m_num_units; |
| }; |
| |
| 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; } |
| int num_elements () { return m_num_elements; } |
| bool is_signed () const final override { return false; } |
| |
| 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_same_type_as (type *other) 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 is_signed () const final override { return false; } |
| |
| void replay_into (replayer *) final override; |
| |
| type * get_return_type () const { return m_return_type; } |
| const vec<type *> &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<type *> 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 *) override; |
| |
| void write_to_dump (dump &d) override; |
| |
| playback::field * |
| playback_field () const |
| { |
| return static_cast <playback::field *> (m_playback_obj); |
| } |
| |
| private: |
| string * make_debug_string () override; |
| void write_reproducer (reproducer &r) override; |
| |
| protected: |
| location *m_loc; |
| type *m_type; |
| string *m_name; |
| compound_type *m_container; |
| }; |
| |
| |
| class bitfield : public field |
| { |
| public: |
| bitfield (context *ctxt, |
| location *loc, |
| type *type, |
| int width, |
| string *name) |
| : field (ctxt, loc, type, name), |
| m_width (width) |
| {} |
| |
| void replay_into (replayer *) final override; |
| |
| void write_to_dump (dump &d) final override; |
| |
| private: |
| string * make_debug_string () final override; |
| void write_reproducer (reproducer &r) final override; |
| |
| private: |
| int m_width; |
| }; |
| |
| /* 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 is_signed () const final override { return false; } |
| |
| bool has_known_size () const final override { return m_fields != NULL; } |
| |
| playback::compound_type * |
| playback_compound_type () |
| { |
| return static_cast <playback::compound_type *> (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; |
| |
| struct_ *is_struct () final override { return this; } |
| |
| 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<field *> m_fields; |
| }; |
| |
| class union_ : public compound_type |
| { |
| public: |
| union_ (context *ctxt, |
| location *loc, |
| string *name); |
| |
| void replay_into (replayer *r) final override; |
| |
| bool is_union () const final override { return true; } |
| |
| private: |
| string * make_debug_string () final override; |
| void write_reproducer (reproducer &r) final override; |
| }; |
| |
| /* 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.cc. */ |
| |
| 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 <playback::rvalue *> (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_), |
| m_link_section (NULL), |
| m_reg_name (NULL), |
| m_tls_model (GCC_JIT_TLS_MODEL_NONE), |
| m_alignment (0) |
| {} |
| |
| playback::lvalue * |
| playback_lvalue () const |
| { |
| return static_cast <playback::lvalue *> (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); |
| virtual bool is_global () const { return false; } |
| void set_tls_model (enum gcc_jit_tls_model model); |
| void set_link_section (const char *name); |
| void set_register_name (const char *reg_name); |
| void set_alignment (unsigned bytes); |
| unsigned get_alignment () const { return m_alignment; } |
| |
| protected: |
| string *m_link_section; |
| string *m_reg_name; |
| enum gcc_jit_tls_model m_tls_model; |
| unsigned m_alignment; |
| }; |
| |
| 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 <playback::param *> (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 <playback::function *> (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<param *> &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); |
| |
| rvalue *get_address (location *loc); |
| |
| 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<param *> m_params; |
| int m_is_variadic; |
| enum built_in_function m_builtin_id; |
| auto_vec<local *> m_locals; |
| auto_vec<block *> m_blocks; |
| type *m_fn_ptr_type; |
| }; |
| |
| 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); |
| |
| extended_asm * |
| add_extended_asm (location *loc, |
| const char *asm_template); |
| |
| 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); |
| |
| extended_asm * |
| end_with_extended_asm_goto (location *loc, |
| const char *asm_template, |
| int num_goto_blocks, |
| block **goto_blocks, |
| block *fallthrough_block); |
| |
| playback::block * |
| playback_block () const |
| { |
| return static_cast <playback::block *> (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 <block *> 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<statement *> 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) |
| { |
| m_initializer = NULL; |
| m_initializer_num_bytes = 0; |
| } |
| ~global () |
| { |
| free (m_initializer); |
| } |
| |
| void replay_into (replayer *) final override; |
| |
| void visit_children (rvalue_visitor *) final override {} |
| |
| void write_to_dump (dump &d) final override; |
| |
| bool is_global () const final override { return true; } |
| |
| void |
| set_initializer (const void *initializer, |
| size_t num_bytes) |
| { |
| if (m_initializer) |
| free (m_initializer); |
| m_initializer = xmalloc (num_bytes); |
| memcpy (m_initializer, initializer, num_bytes); |
| m_initializer_num_bytes = num_bytes; |
| } |
| |
| void set_flags (int flag_fields) |
| { |
| m_flags = (enum global_var_flags)(m_flags | flag_fields); |
| } |
| /* Returns true if any of the flags in the argument is set. */ |
| bool test_flags_anyof (int flag_fields) const |
| { |
| return m_flags & flag_fields; |
| } |
| |
| enum gcc_jit_global_kind get_kind () const |
| { |
| return m_kind; |
| } |
| |
| void set_rvalue_init (rvalue *val) { m_rvalue_init = val; } |
| |
| private: |
| string * make_debug_string () final override { return m_name; } |
| template <typename T> |
| void write_initializer_reproducer (const char *id, reproducer &r); |
| 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; |
| enum global_var_flags m_flags = GLOBAL_VAR_FLAGS_NONE; |
| string *m_name; |
| void *m_initializer; |
| rvalue *m_rvalue_init = nullptr; /* Only needed for write_dump. */ |
| size_t m_initializer_num_bytes; |
| }; |
| |
| template <typename HOST_TYPE> |
| 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 memento_of_new_rvalue_from_vector : public rvalue |
| { |
| public: |
| memento_of_new_rvalue_from_vector (context *ctxt, |
| location *loc, |
| vector_type *type, |
| rvalue **elements); |
| |
| 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: |
| vector_type *m_vector_type; |
| auto_vec<rvalue *> m_elements; |
| }; |
| |
| class ctor : public rvalue |
| { |
| public: |
| ctor (context *ctxt, |
| location *loc, |
| type *type) |
| : rvalue (ctxt, loc, type) |
| { } |
| |
| 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; |
| } |
| |
| public: |
| auto_vec<field *> m_fields; |
| auto_vec<rvalue *> m_values; |
| }; |
| |
| 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 bitcast : public rvalue |
| { |
| public: |
| bitcast (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<rvalue *> 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 function_pointer : public rvalue |
| { |
| public: |
| function_pointer (context *ctxt, |
| location *loc, |
| function *fn, |
| type *type) |
| : rvalue (ctxt, loc, type), |
| m_fn (fn) {} |
| |
| 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: |
| function *m_fn; |
| }; |
| |
| 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 <block *> 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 <block *> 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 <block *> 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 <block *> 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 <block *> 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 <case_ *> m_cases; |
| }; |
| |
| class asm_operand : public memento |
| { |
| public: |
| asm_operand (extended_asm *ext_asm, |
| string *asm_symbolic_name, |
| string *constraint); |
| |
| const char *get_symbolic_name () const |
| { |
| if (m_asm_symbolic_name) |
| return m_asm_symbolic_name->c_str (); |
| else |
| return NULL; |
| } |
| |
| const char *get_constraint () const |
| { |
| return m_constraint->c_str (); |
| } |
| |
| virtual void print (pretty_printer *pp) const; |
| |
| private: |
| string * make_debug_string () final override; |
| |
| protected: |
| extended_asm *m_ext_asm; |
| string *m_asm_symbolic_name; |
| string *m_constraint; |
| }; |
| |
| class output_asm_operand : public asm_operand |
| { |
| public: |
| output_asm_operand (extended_asm *ext_asm, |
| string *asm_symbolic_name, |
| string *constraint, |
| lvalue *dest) |
| : asm_operand (ext_asm, asm_symbolic_name, constraint), |
| m_dest (dest) |
| {} |
| |
| lvalue *get_lvalue () const { return m_dest; } |
| |
| void replay_into (replayer *) final override {} |
| |
| void print (pretty_printer *pp) const final override; |
| |
| private: |
| void write_reproducer (reproducer &r) final override; |
| |
| private: |
| lvalue *m_dest; |
| }; |
| |
| class input_asm_operand : public asm_operand |
| { |
| public: |
| input_asm_operand (extended_asm *ext_asm, |
| string *asm_symbolic_name, |
| string *constraint, |
| rvalue *src) |
| : asm_operand (ext_asm, asm_symbolic_name, constraint), |
| m_src (src) |
| {} |
| |
| rvalue *get_rvalue () const { return m_src; } |
| |
| void replay_into (replayer *) final override {} |
| |
| void print (pretty_printer *pp) const final override; |
| |
| private: |
| void write_reproducer (reproducer &r) final override; |
| |
| private: |
| rvalue *m_src; |
| }; |
| |
| /* Abstract base class for extended_asm statements. */ |
| |
| class extended_asm : public statement |
| { |
| public: |
| extended_asm (block *b, |
| location *loc, |
| string *asm_template) |
| : statement (b, loc), |
| m_asm_template (asm_template), |
| m_is_volatile (false), |
| m_is_inline (false) |
| {} |
| |
| void set_volatile_flag (bool flag) { m_is_volatile = flag; } |
| void set_inline_flag (bool flag) { m_is_inline = flag; } |
| |
| void add_output_operand (const char *asm_symbolic_name, |
| const char *constraint, |
| lvalue *dest); |
| void add_input_operand (const char *asm_symbolic_name, |
| const char *constraint, |
| rvalue *src); |
| void add_clobber (const char *victim); |
| |
| void replay_into (replayer *r) override; |
| |
| string *get_asm_template () const { return m_asm_template; } |
| |
| virtual bool is_goto () const = 0; |
| virtual void maybe_print_gotos (pretty_printer *) const = 0; |
| |
| protected: |
| void write_flags (reproducer &r); |
| void write_clobbers (reproducer &r); |
| |
| private: |
| string * make_debug_string () final override; |
| virtual void maybe_populate_playback_blocks |
| (auto_vec <playback::block *> *out) = 0; |
| |
| protected: |
| string *m_asm_template; |
| bool m_is_volatile; |
| bool m_is_inline; |
| auto_vec<output_asm_operand *> m_output_ops; |
| auto_vec<input_asm_operand *> m_input_ops; |
| auto_vec<string *> m_clobbers; |
| }; |
| |
| /* An extended_asm that's not a goto, as created by |
| gcc_jit_block_add_extended_asm. */ |
| |
| class extended_asm_simple : public extended_asm |
| { |
| public: |
| extended_asm_simple (block *b, |
| location *loc, |
| string *asm_template) |
| : extended_asm (b, loc, asm_template) |
| {} |
| |
| void write_reproducer (reproducer &r) override; |
| bool is_goto () const final override { return false; } |
| void maybe_print_gotos (pretty_printer *) const final override {} |
| |
| private: |
| void maybe_populate_playback_blocks |
| (auto_vec <playback::block *> *) final override |
| {} |
| }; |
| |
| /* An extended_asm that's a asm goto, as created by |
| gcc_jit_block_end_with_extended_asm_goto. */ |
| |
| class extended_asm_goto : public extended_asm |
| { |
| public: |
| extended_asm_goto (block *b, |
| location *loc, |
| string *asm_template, |
| int num_goto_blocks, |
| block **goto_blocks, |
| block *fallthrough_block); |
| |
| void replay_into (replayer *r) final override; |
| void write_reproducer (reproducer &r) override; |
| |
| vec <block *> get_successor_blocks () const final override; |
| |
| bool is_goto () const final override { return true; } |
| void maybe_print_gotos (pretty_printer *) const final override; |
| |
| private: |
| void maybe_populate_playback_blocks |
| (auto_vec <playback::block *> *out) final override; |
| |
| private: |
| auto_vec <block *> m_goto_blocks; |
| block *m_fallthrough_block; |
| }; |
| |
| /* A group of top-level asm statements, as created by |
| gcc_jit_context_add_top_level_asm. */ |
| |
| class top_level_asm : public memento |
| { |
| public: |
| top_level_asm (context *ctxt, location *loc, string *asm_stmts); |
| |
| void write_to_dump (dump &d) final override; |
| |
| private: |
| void replay_into (replayer *r) final override; |
| string * make_debug_string () final override; |
| void write_reproducer (reproducer &r) final override; |
| |
| private: |
| location *m_loc; |
| string *m_asm_stmts; |
| }; |
| |
| class global_init_rvalue : public memento |
| { |
| public: |
| global_init_rvalue (context *ctxt, lvalue *variable, rvalue *init) : |
| memento (ctxt), m_variable (variable), m_init (init) {}; |
| |
| void write_to_dump (dump &d) final override; |
| |
| private: |
| void replay_into (replayer *r) final override; |
| string * make_debug_string () final override; |
| void write_reproducer (reproducer &r) final override; |
| |
| private: |
| lvalue *m_variable; |
| rvalue *m_init; |
| }; |
| |
| } // 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 <typename HOST_TYPE> |
| recording::rvalue * |
| recording::context::new_rvalue_from_const (recording::type *type, |
| HOST_TYPE value) |
| { |
| recording::rvalue *result = |
| new memento_of_new_rvalue_from_const <HOST_TYPE> (this, NULL, type, value); |
| record (result); |
| return result; |
| } |
| |
| /* Don't call this directly. Call types_kinda_same. */ |
| bool |
| types_kinda_same_internal (recording::type *a, |
| recording::type *b); |
| |
| /* Strip all qualifiers and count pointer depth, returning true |
| if the types and pointer depth are the same, otherwise false. |
| |
| For array and vector types the number of element also |
| has to match, aswell as the element types themself. */ |
| static inline bool |
| types_kinda_same (recording::type *a, recording::type *b) |
| { |
| /* Handle trivial case here, to allow for inlining. */ |
| return a == b || types_kinda_same_internal (a, b); |
| } |
| |
| } // namespace gcc::jit |
| |
| } // namespace gcc |
| |
| #endif /* JIT_RECORDING_H */ |