# Contains the commits from https://github.com/antoyo/gcc/ needed for rustc_codegen_gcc to work diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000000..5fab7cf772c --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,32 @@ +name: CI + +on: + - push + - pull_request + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v2 + + - name: Install mpfr + run: sudo apt-get install gcc-10 libmpfr-dev libmpc-dev + + - name: Build libgccjit + run: | + cd .. + ls + mkdir build install + cd build + ../gcc/configure --enable-host-shared --enable-languages=jit,c++ --disable-bootstrap --disable-multilib --prefix=$(pwd)/../install + make -j4 + + - uses: actions/upload-artifact@v2 + with: + name: libgccjit.so + path: /home/runner/work/gcc/build/gcc/libgccjit.so diff --git a/gcc/config/i386/i386-builtins.cc b/gcc/config/i386/i386-builtins.cc index 01192ef4259..37df854ba51 100644 --- a/gcc/config/i386/i386-builtins.cc +++ b/gcc/config/i386/i386-builtins.cc @@ -226,6 +226,22 @@ static GTY(()) tree ix86_builtins[(int) IX86_BUILTIN_MAX]; struct builtin_isa ix86_builtins_isa[(int) IX86_BUILTIN_MAX]; +static void +clear_builtin_types (void) +{ + for (int i = 0 ; i < IX86_BT_LAST_CPTR + 1 ; i++) + ix86_builtin_type_tab[i] = NULL; + + for (int i = 0 ; i < IX86_BUILTIN_MAX ; i++) + { + ix86_builtins[i] = NULL; + ix86_builtins_isa[i].set_and_not_built_p = true; + } + + for (int i = 0 ; i < IX86_BT_LAST_ALIAS + 1 ; i++) + ix86_builtin_func_type_tab[i] = NULL; +} + tree get_ix86_builtin (enum ix86_builtins c) { return ix86_builtins[c]; @@ -1443,6 +1459,8 @@ ix86_init_builtins (void) { tree ftype, decl; + clear_builtin_types (); + ix86_init_builtin_types (); /* Builtins to get CPU type and features. */ diff --git a/gcc/dwarf2asm.cc b/gcc/dwarf2asm.cc index 65b95fee243..e66cd30c1fe 100644 --- a/gcc/dwarf2asm.cc +++ b/gcc/dwarf2asm.cc @@ -1159,4 +1159,14 @@ dw2_asm_output_encoded_addr_rtx (int encoding, rtx addr, bool is_public, va_end (ap); } +void dwarf2asm_cc_finalize (void) +{ + if (indirect_pool) + { + indirect_pool->empty(); + indirect_pool = NULL; + } + dw2_const_labelno = 0; +} + #include "gt-dwarf2asm.h" diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h index 37a0a05e5bb..80695b3c6c8 100644 --- a/gcc/dwarf2asm.h +++ b/gcc/dwarf2asm.h @@ -86,6 +86,8 @@ extern const char *eh_data_format_name (int); extern rtx dw2_force_const_mem (rtx, bool); extern void dw2_output_indirect_constants (void); +void dwarf2asm_cc_finalize (void); + /* These are currently unused. */ #if 0 diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index 1f39df3b1e2..61b711d4a52 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -1003,6 +1003,9 @@ dwarf2out_do_cfi_startproc (bool second) if (targetm.asm_out.make_eh_symbol_indirect != NULL) ref = targetm.asm_out.make_eh_symbol_indirect (ref, true); else + // TODO: HERE: should not insert multiple times the same personality function. + // If we don't, we segfault later, possibly because we don't generate the info for the duplicates. + // I'm not sure why it's attempting to insert multiple times the same personality function. ref = dw2_force_const_mem (ref, true); } diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc index a11f72f606b..61603c37230 100644 --- a/gcc/emit-rtl.cc +++ b/gcc/emit-rtl.cc @@ -6191,8 +6191,13 @@ init_emit_once (void) /* Don't use gen_rtx_CONST_INT here since gen_rtx_CONST_INT in this case tries to use these variables. */ for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++) - const_int_rtx[i + MAX_SAVED_CONST_INT] = - gen_rtx_raw_CONST_INT (VOIDmode, (HOST_WIDE_INT) i); + { + // Do not initialize twice the constants because there are used elsewhere + // and libgccjit execute this function twice. + if (const_int_rtx[i + MAX_SAVED_CONST_INT] == NULL) + const_int_rtx[i + MAX_SAVED_CONST_INT] = + gen_rtx_raw_CONST_INT (VOIDmode, (HOST_WIDE_INT) i); + } if (STORE_FLAG_VALUE >= - MAX_SAVED_CONST_INT && STORE_FLAG_VALUE <= MAX_SAVED_CONST_INT) diff --git a/gcc/expr.cc b/gcc/expr.cc index 15be1c8db99..7fa2c114cb2 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -13365,6 +13365,7 @@ const_vector_from_tree (tree exp) tree build_personality_function (const char *lang) { + // TODO: rewrite by calling build_personality_function_with_name. const char *unwind_and_version; tree decl, type; char *name; @@ -13406,6 +13407,28 @@ build_personality_function (const char *lang) return decl; } +tree +build_personality_function_with_name (const char *name) +{ + tree decl, type; + + type = build_function_type_list (unsigned_type_node, + integer_type_node, integer_type_node, + long_long_unsigned_type_node, + ptr_type_node, ptr_type_node, NULL_TREE); + decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, + get_identifier (name), type); + DECL_ARTIFICIAL (decl) = 1; + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + + /* Zap the nonsensical SYMBOL_REF_DECL for this. What we're left with + are the flags assigned by targetm.encode_section_info. */ + SET_SYMBOL_REF_DECL (XEXP (DECL_RTL (decl), 0), NULL); + + return decl; +} + /* Extracts the personality function of DECL and returns the corresponding libfunc. */ diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index 0687567bc88..7ef09d71288 100644 --- a/gcc/jit/dummy-frontend.cc +++ b/gcc/jit/dummy-frontend.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #include "system.h" #include "coretypes.h" +#include "target.h" #include "jit-playback.h" #include "stor-layout.h" #include "debug.h" @@ -29,8 +30,14 @@ along with GCC; see the file COPYING3. If not see #include "options.h" #include "stringpool.h" #include "attribs.h" +#include "jit-recording.h" +#include "print-tree.h" #include +#include +#include + +using namespace gcc::jit; /* Attribute handling. */ @@ -86,6 +93,10 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = ATTR_EXCL (NULL, false, false, false) }; +hash_map target_builtins{}; +std::unordered_map target_function_types{}; +recording::context target_builtins_ctxt{NULL}; + /* Table of machine-independent attributes supported in libgccjit. */ const struct attribute_spec jit_attribute_table[] = { @@ -146,6 +157,20 @@ const struct attribute_spec jit_format_attribute_table[] = { NULL, 0, 0, false, false, false, false, NULL, NULL } }; +char* jit_personality_func_name = NULL; +static tree personality_decl; + +/* FIXME: This is a hack to preserve trees that we create from the + garbage collector. */ + +static GTY (()) tree jit_gc_root; + +void +jit_preserve_from_gc (tree t) +{ + jit_gc_root = tree_cons (NULL_TREE, t, jit_gc_root); +} + /* Attribute handlers. */ /* Handle a "noreturn" attribute; arguments as in @@ -507,12 +532,12 @@ struct GTY(()) lang_identifier /* The resulting tree type. */ union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), - chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL"))) -lang_tree_node -{ - union tree_node GTY((tag ("0"), - desc ("tree_node_structure (&%h)"))) generic; - struct lang_identifier GTY((tag ("1"))) identifier; + chain_next ("(union lang_tree_node *) jit_tree_chain_next (&%h.generic)"))) lang_tree_node + { + union tree_node GTY ((tag ("0"), + desc ("tree_node_structure (&%h)"))) + generic; + struct lang_identifier GTY ((tag ("1"))) identifier; }; /* We don't use language_function. */ @@ -578,6 +603,8 @@ jit_end_diagnostic (diagnostic_context *context, static bool jit_langhook_init (void) { + jit_gc_root = NULL_TREE; + personality_decl = NULL_TREE; gcc_assert (gcc::jit::active_playback_ctxt); JIT_LOG_SCOPE (gcc::jit::active_playback_ctxt->get_logger ()); @@ -592,15 +619,25 @@ jit_langhook_init (void) global_dc->begin_diagnostic = jit_begin_diagnostic; global_dc->end_diagnostic = jit_end_diagnostic; - build_common_tree_nodes (false); + build_common_tree_nodes (flag_signed_char); + + /* I don't know why this has to be done explicitly. */ + void_list_node = build_tree_list (NULL_TREE, void_type_node); + target_builtins.empty (); build_common_builtin_nodes (); + /* Initialize EH, if we've been told to do so. */ + if (flag_exceptions) + using_eh_for_cleanups (); + /* The default precision for floating point numbers. This is used for floating point constants with abstract type. This may eventually be controllable by a command line option. */ mpfr_set_default_prec (256); + targetm.init_builtins (); + return true; } @@ -668,11 +705,216 @@ jit_langhook_type_for_mode (machine_mode mode, int unsignedp) return NULL; } -/* Record a builtin function. We just ignore builtin functions. */ +recording::type* tree_type_to_jit_type (tree type) +{ + if (TREE_CODE (type) == VECTOR_TYPE) + { + tree inner_type = TREE_TYPE (type); + recording::type* element_type = tree_type_to_jit_type (inner_type); + poly_uint64 size = TYPE_VECTOR_SUBPARTS (type); + long constant_size = size.to_constant(); + if (element_type != NULL) + return element_type->get_vector (constant_size); + return NULL; + } + if (TREE_CODE (type) == REFERENCE_TYPE) + { + // For __builtin_ms_va_start. + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type. + } + if (TREE_CODE (type) == RECORD_TYPE) + { + // For __builtin_sysv_va_copy. + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type. + } + for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++) + { + if (type == FLOATN_NX_TYPE_NODE (i)) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type. + } + } + if (type == void_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); + } + else if (type == ptr_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID_PTR); + } + else if (type == const_ptr_type_node) + { + // Void const ptr. + recording::type* result = new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID_PTR); + return new recording::memento_of_get_const (result); + } + else if (type == unsigned_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UNSIGNED_INT); + } + else if (type == long_unsigned_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UNSIGNED_LONG); + } + else if (type == integer_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_INT); + } + else if (type == long_integer_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_LONG); + } + else if (type == long_long_integer_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_LONG_LONG); + } + else if (type == signed_char_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_SIGNED_CHAR); + } + else if (type == char_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_CHAR); + } + else if (type == unsigned_intQI_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UINT8_T); + } + else if (type == short_integer_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_SHORT); + } + else if (type == short_unsigned_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UNSIGNED_SHORT); + } + else if (type == complex_float_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_COMPLEX_FLOAT); + } + else if (type == complex_double_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_COMPLEX_DOUBLE); + } + else if (type == complex_long_double_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE); + } + else if (type == float_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_FLOAT); + } + else if (type == double_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_DOUBLE); + } + else if (type == long_double_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_LONG_DOUBLE); + } + else if (type == bfloat16_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_BFLOAT16); + } + else if (type == dfloat128_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type. + } + else if (type == long_long_unsigned_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UNSIGNED_LONG_LONG); + } + else if (type == boolean_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_BOOL); + } + else if (type == size_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_SIZE_T); + } + else if (TREE_CODE (type) == POINTER_TYPE) + { + tree inner_type = TREE_TYPE (type); + recording::type* element_type = tree_type_to_jit_type (inner_type); + return element_type->get_pointer(); + } + else + { + // Attempt to find an unqualified type when the current type has qualifiers. + tree tp = TYPE_MAIN_VARIANT (type); + for ( ; tp != NULL ; tp = TYPE_NEXT_VARIANT (tp)) + { + if (TYPE_QUALS (tp) == 0 && type != tp) + { + recording::type* result = tree_type_to_jit_type (tp); + if (result != NULL) + { + if (TYPE_READONLY (tp)) + result = new recording::memento_of_get_const (result); + if (TYPE_VOLATILE (tp)) + result = new recording::memento_of_get_volatile (result); + return result; + } + } + } + + fprintf (stderr, "Unknown type:\n"); + debug_tree (type); + abort (); + } + + return NULL; +} + +/* Record a builtin function. We save their types to be able to check types + in recording and for reflection. */ static tree jit_langhook_builtin_function (tree decl) { + if (TREE_CODE (decl) == FUNCTION_DECL) + { + const char* name = IDENTIFIER_POINTER (DECL_NAME (decl)); + target_builtins.put (name, decl); + + std::string string_name(name); + if (target_function_types.count (string_name) == 0) + { + tree function_type = TREE_TYPE (decl); + tree arg = TYPE_ARG_TYPES (function_type); + bool is_variadic = false; + + auto_vec param_types; + + while (arg != void_list_node) + { + if (arg == NULL) + { + is_variadic = true; + break; + } + if (arg != void_list_node) + { + recording::type* arg_type = tree_type_to_jit_type(TREE_VALUE (arg)); + if (arg_type == NULL) + return decl; + param_types.safe_push (arg_type); + } + arg = TREE_CHAIN (arg); + } + + tree result_type = TREE_TYPE (function_type); + recording::type* return_type = tree_type_to_jit_type(result_type); + + if (return_type == NULL) + return decl; + + recording::function_type* func_type = new recording::function_type (&target_builtins_ctxt, return_type, param_types.length (), + param_types.address (), is_variadic, false); + + target_function_types[string_name] = func_type; + } + } return decl; } @@ -694,6 +936,25 @@ jit_langhook_getdecls (void) return NULL; } +static tree +jit_langhook_eh_personality (void) +{ + if (personality_decl == NULL_TREE) + { + if (jit_personality_func_name != NULL) { + personality_decl = build_personality_function_with_name (jit_personality_func_name); + jit_preserve_from_gc(personality_decl); + } + else { + return lhd_gcc_personality(); + } + } + return personality_decl; +} + +#undef LANG_HOOKS_EH_PERSONALITY +#define LANG_HOOKS_EH_PERSONALITY jit_langhook_eh_personality + #undef LANG_HOOKS_NAME #define LANG_HOOKS_NAME "libgccjit" diff --git a/gcc/jit/jit-builtins.cc b/gcc/jit/jit-builtins.cc index fb86c77d0fe..622a061ea89 100644 --- a/gcc/jit/jit-builtins.cc +++ b/gcc/jit/jit-builtins.cc @@ -215,7 +215,8 @@ builtins_manager::make_builtin_function (enum built_in_function builtin_id) param_types.length (), params, func_type->is_variadic (), - builtin_id); + builtin_id, + false); delete[] params; /* PR/64020 - If the client code is using builtin cos or sin, @@ -582,7 +583,8 @@ builtins_manager::make_fn_type (enum jit_builtin_type, result = m_ctxt->new_function_type (return_type, num_args, param_types, - is_variadic); + is_variadic, + false); error: delete[] param_types; @@ -609,6 +611,9 @@ builtins_manager::ensure_optimization_builtins_exist () We can't loop through all of the builtin_data array, we don't support all types yet. */ (void)get_builtin_function_by_id (BUILT_IN_TRAP); + (void)get_builtin_function_by_id (BUILT_IN_POPCOUNT); + (void)get_builtin_function_by_id (BUILT_IN_POPCOUNTL); + (void)get_builtin_function_by_id (BUILT_IN_POPCOUNTLL); } /* Playback support. */ diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h index 3ff7447fbf3..5c323411ea9 100644 --- a/gcc/jit/jit-common.h +++ b/gcc/jit/jit-common.h @@ -36,7 +36,7 @@ along with GCC; see the file COPYING3. If not see #endif #endif -const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_INT128_T + 1; +const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_BFLOAT16 + 1; /* This comment is included by the docs. @@ -93,6 +93,20 @@ const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_INT128_T + 1; End of comment for inclusion in the docs. */ +static inline tree +jit_tree_chain_next (tree t) +{ + /* TREE_CHAIN of a type is TYPE_STUB_DECL, which is different + kind of object, never a long chain of nodes. Prefer + TYPE_NEXT_VARIANT for types. */ + if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_TYPE_COMMON)) + return TYPE_NEXT_VARIANT (t); + /* Otherwise, if there is TREE_CHAIN, return it. */ + if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_COMMON)) + return TREE_CHAIN (t); + return NULL; +} + namespace gcc { namespace jit { diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 96e9227af40..0b107754ca8 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #define INCLUDE_MUTEX +#include "libgccjit.h" #include "system.h" #include "coretypes.h" #include "target.h" @@ -280,6 +281,8 @@ get_tree_node_for_type (enum gcc_jit_types type_) case GCC_JIT_TYPE_FLOAT: return float_type_node; + case GCC_JIT_TYPE_BFLOAT16: + return bfloat16_type_node; case GCC_JIT_TYPE_DOUBLE: return double_type_node; case GCC_JIT_TYPE_LONG_DOUBLE: @@ -326,7 +329,7 @@ playback::type * playback::context:: new_array_type (playback::location *loc, playback::type *element_type, - int num_elements) + unsigned long num_elements) { gcc_assert (element_type); @@ -407,7 +410,8 @@ playback::compound_type * playback::context:: new_compound_type (location *loc, const char *name, - bool is_struct) /* else is union */ + bool is_struct, /* else is union */ + bool is_packed) { gcc_assert (name); @@ -417,6 +421,9 @@ new_compound_type (location *loc, TYPE_NAME (t) = get_identifier (name); TYPE_SIZE (t) = 0; + if (is_packed) + TYPE_PACKED (t) = 1; + if (loc) set_tree_location (t, loc); @@ -424,7 +431,7 @@ new_compound_type (location *loc, } void -playback::compound_type::set_fields (const auto_vec *fields) +playback::compound_type::set_fields (const auto_vec *fields, bool is_packed) { /* Compare with c/c-decl.cc: finish_struct. */ tree t = as_tree (); @@ -441,6 +448,10 @@ playback::compound_type::set_fields (const auto_vec *fields) DECL_SIZE (x) = bitsize_int (width); DECL_BIT_FIELD (x) = 1; } + + if (is_packed && (DECL_BIT_FIELD (x) + || TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT)) + DECL_PACKED (x) = 1; fieldlist = chainon (x, fieldlist); } fieldlist = nreverse (fieldlist); @@ -499,6 +510,36 @@ new_param (location *loc, return new param (this, inner); } +const char* fn_attribute_to_string(gcc_jit_fn_attribute attr) +{ + switch (attr) + { + case GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE: + return "always_inline"; + case GCC_JIT_FN_ATTRIBUTE_INLINE: + return NULL; + case GCC_JIT_FN_ATTRIBUTE_NOINLINE: + return "noinline"; + case GCC_JIT_FN_ATTRIBUTE_TARGET: + return "target"; + case GCC_JIT_FN_ATTRIBUTE_USED: + return "used"; + case GCC_JIT_FN_ATTRIBUTE_VISIBILITY: + return "visibility"; + } + return NULL; +} + +const char* variable_attribute_to_string(gcc_jit_variable_attribute attr) +{ + switch (attr) + { + case GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY: + return "visibility"; + } + return NULL; +} + /* Construct a playback::function instance. */ playback::function * @@ -509,7 +550,10 @@ new_function (location *loc, const char *name, const auto_vec *params, int is_variadic, - enum built_in_function builtin_id) + enum built_in_function builtin_id, + const std::vector &attributes, + const std::vector> &string_attributes, + int is_target_builtin) { int i; param *param; @@ -532,6 +576,7 @@ new_function (location *loc, /* FIXME: this uses input_location: */ tree fndecl = build_fn_decl (name, fn_type); + TREE_NOTHROW (fndecl) = 0; if (loc) set_tree_location (fndecl, loc); @@ -543,6 +588,14 @@ new_function (location *loc, DECL_RESULT (fndecl) = resdecl; DECL_CONTEXT (resdecl) = fndecl; + if (is_target_builtin) + { + tree *decl = target_builtins.get(name); + if (decl != NULL) + fndecl = *decl; + else + add_error (loc, "cannot find target builtin %s", name); + } if (builtin_id) { gcc_assert (loc == NULL); @@ -594,6 +647,52 @@ new_function (location *loc, DECL_ATTRIBUTES (fndecl)); } + for (auto attr: attributes) + { + if (attr == GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE) + { + DECL_DECLARED_INLINE_P (fndecl) = 1; + DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1; + } + else if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE) + DECL_DECLARED_INLINE_P (fndecl) = 1; + else if (attr == GCC_JIT_FN_ATTRIBUTE_NOINLINE) + DECL_UNINLINABLE (fndecl) = 1; + /* See handle_used_attribute in gcc/c-family/c-attribs.cc. */ + else if (attr == GCC_JIT_FN_ATTRIBUTE_USED) + { + TREE_USED (fndecl) = 1; + DECL_PRESERVE_P (fndecl) = 1; + } + + const char* attribute = fn_attribute_to_string (attr); + if (attribute) + { + tree ident = get_identifier (attribute); + DECL_ATTRIBUTES (fndecl) = + tree_cons (ident, NULL_TREE, DECL_ATTRIBUTES (fndecl)); + } + } + + for (auto attr: string_attributes) + { + gcc_jit_fn_attribute& name = std::get<0>(attr); + std::string& value = std::get<1>(attr); + tree attribute_value = build_tree_list (NULL_TREE, ::build_string (value.length () + 1, value.c_str ())); + const char* attribute = fn_attribute_to_string (name); + tree ident = attribute ? get_identifier (attribute) : NULL; + + /* See handle_target_attribute in gcc/c-family/c-attribs.cc. */ + if (name == GCC_JIT_FN_ATTRIBUTE_TARGET) + /* We need to call valid_attribute_p so that the hook set-up some internal options. */ + if (!ident || !targetm.target_option.valid_attribute_p (fndecl, ident, attribute_value, 0)) + continue; + + if (ident) + DECL_ATTRIBUTES (fndecl) = + tree_cons (ident, attribute_value, DECL_ATTRIBUTES (fndecl)); + } + function *func = new function (this, fndecl, kind); m_functions.safe_push (func); return func; @@ -607,7 +706,9 @@ global_new_decl (location *loc, enum gcc_jit_global_kind kind, type *type, const char *name, - enum global_var_flags flags) + enum global_var_flags flags, + bool readonly, + const std::vector> &attributes) { gcc_assert (type); gcc_assert (name); @@ -646,15 +747,33 @@ global_new_decl (location *loc, break; } - if (TYPE_READONLY (type_tree)) + if (TYPE_READONLY (type_tree) || readonly) TREE_READONLY (inner) = 1; if (loc) set_tree_location (inner, loc); + set_variable_attribute (attributes, inner); + return inner; } +void +playback:: +set_variable_attribute(const std::vector> &attributes, tree decl) +{ + for (auto attr: attributes) + { + gcc_jit_variable_attribute& name = std::get<0>(attr); + std::string& value = std::get<1>(attr); + tree attribute_value = build_tree_list (NULL_TREE, ::build_string (value.length () + 1, value.c_str ())); + tree ident = get_identifier (variable_attribute_to_string (name)); + + DECL_ATTRIBUTES (decl) = + tree_cons (ident, attribute_value, DECL_ATTRIBUTES (decl)); + } +} + /* In use by new_global and new_global_initialized. */ playback::lvalue * @@ -674,10 +793,12 @@ new_global (location *loc, enum gcc_jit_global_kind kind, type *type, const char *name, - enum global_var_flags flags) + enum global_var_flags flags, + bool readonly, + const std::vector> &attributes) { tree inner = - global_new_decl (loc, kind, type, name, flags); + global_new_decl (loc, kind, type, name, flags, readonly, attributes); return global_finalize_lvalue (inner); } @@ -822,9 +943,11 @@ new_global_initialized (location *loc, size_t initializer_num_elem, const void *initializer, const char *name, - enum global_var_flags flags) + enum global_var_flags flags, + bool readonly, + const std::vector> &attributes) { - tree inner = global_new_decl (loc, kind, type, name, flags); + tree inner = global_new_decl (loc, kind, type, name, flags, readonly, attributes); vec *constructor_elements = NULL; @@ -1007,10 +1130,30 @@ playback::context::new_rvalue_from_vector (location *, vec_alloc (v, elements.length ()); for (unsigned i = 0; i < elements.length (); ++i) CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ()); - tree t_ctor = build_constructor (type->as_tree (), v); + tree t_ctor; + t_ctor = build_constructor (type->as_tree (), v); return new rvalue (this, t_ctor); } +/* Construct a playback::rvalue instance (wrapping a tree) for a + vector perm. */ + +playback::rvalue * +playback::context::new_rvalue_vector_perm (location *loc, + rvalue* elements1, + rvalue* elements2, + rvalue* mask) +{ + tree t_elements1 = elements1->as_tree (); + tree t_elements2 = elements2->as_tree (); + tree t_mask = mask->as_tree (); + + tree t_vector_perm = build3 (VEC_PERM_EXPR, TREE_TYPE (t_elements1), t_elements1, t_elements2, t_mask); + if (loc) + set_tree_location (t_vector_perm, loc); + return new rvalue (this, t_vector_perm); +} + /* Coerce a tree expression into a boolean tree expression. */ tree @@ -1527,6 +1670,163 @@ new_array_access (location *loc, } } +/* Construct a playback::rvalue instance (wrapping a tree) for a + vector conversion. */ + +playback::rvalue * +playback::context:: +convert_vector (location *loc, + rvalue *vector, + type *type) +{ + gcc_assert (vector); + gcc_assert (type); + + /* For comparison, see: + c/c-common.cc: c_build_vec_convert + */ + + tree t_vector = vector->as_tree (); + + /* It seems IFN_VEC_CONVERT only work on registers, not on memory. */ + if (TREE_CODE (t_vector) == VAR_DECL) + DECL_REGISTER (t_vector) = 1; + tree t_result = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_VEC_CONVERT, type->as_tree (), 1, t_vector); + + if (loc) + set_tree_location (t_result, loc); + + return new rvalue (this, t_result); +} + +/* The following functions come from c-common.h. */ +/* Like c_mark_addressable but don't check register qualifier. */ +void +common_mark_addressable_vec (tree t) +{ + while (handled_component_p (t) || TREE_CODE (t) == C_MAYBE_CONST_EXPR) + { + t = TREE_OPERAND (t, 0); + } + if (!VAR_P (t) + && TREE_CODE (t) != PARM_DECL + && TREE_CODE (t) != COMPOUND_LITERAL_EXPR + && TREE_CODE (t) != TARGET_EXPR) + return; + if (!VAR_P (t) || !DECL_HARD_REGISTER (t)) + TREE_ADDRESSABLE (t) = 1; + if (TREE_CODE (t) == COMPOUND_LITERAL_EXPR) + TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (t)) = 1; + else if (TREE_CODE (t) == TARGET_EXPR) + TREE_ADDRESSABLE (TARGET_EXPR_SLOT (t)) = 1; +} + +/* Return true if TYPE is a vector type that should be subject to the GNU + vector extensions (as opposed to a vector type that is used only for + the purposes of defining target-specific built-in functions). */ + +inline bool +gnu_vector_type_p (const_tree type) +{ + return TREE_CODE (type) == VECTOR_TYPE && !TYPE_INDIVISIBLE_P (type); +} + +/* Return nonzero if REF is an lvalue valid for this language. + Lvalues can be assigned, unless their type has TYPE_READONLY. + Lvalues can have their address taken, unless they have C_DECL_REGISTER. */ + +bool +lvalue_p (const_tree ref) +{ + const enum tree_code code = TREE_CODE (ref); + + switch (code) + { + case REALPART_EXPR: + case IMAGPART_EXPR: + case COMPONENT_REF: + return lvalue_p (TREE_OPERAND (ref, 0)); + + case C_MAYBE_CONST_EXPR: + return lvalue_p (TREE_OPERAND (ref, 1)); + + case COMPOUND_LITERAL_EXPR: + case STRING_CST: + return true; + + case MEM_REF: + case TARGET_MEM_REF: + /* MEM_REFs can appear from -fgimple parsing or folding, so allow them + here as well. */ + case INDIRECT_REF: + case ARRAY_REF: + case VAR_DECL: + case PARM_DECL: + case RESULT_DECL: + case ERROR_MARK: + return (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE); + + case BIND_EXPR: + return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE; + + default: + return false; + } +} + +bool +convert_vector_to_array_for_subscript (tree *vecp) +{ + bool ret = false; + if (gnu_vector_type_p (TREE_TYPE (*vecp))) + { + tree type = TREE_TYPE (*vecp); + + ret = !lvalue_p (*vecp); + + /* We are building an ARRAY_REF so mark the vector as addressable + to not run into the gimplifiers premature setting of DECL_GIMPLE_REG_P + for function parameters. */ + // NOTE: that was the missing piece for making vector access work with optimizations enabled. + common_mark_addressable_vec (*vecp); + + *vecp = build1 (VIEW_CONVERT_EXPR, + build_array_type_nelts (TREE_TYPE (type), + TYPE_VECTOR_SUBPARTS (type)), + *vecp); + } + return ret; +} + +/* Construct a playback::lvalue instance (wrapping a tree) for a + vector access. */ + +playback::lvalue * +playback::context:: +new_vector_access (location *loc, + rvalue *vector, + rvalue *index) +{ + gcc_assert (vector); + gcc_assert (index); + + /* For comparison, see: + c/c-typeck.cc: build_array_ref + */ + + tree t_vector = vector->as_tree (); + bool non_lvalue = convert_vector_to_array_for_subscript (&t_vector); + tree type = TREE_TYPE (TREE_TYPE (t_vector)); + tree t_result = build4 (ARRAY_REF, type, t_vector, index->as_tree (), NULL_TREE, NULL_TREE); + if (non_lvalue) + t_result = non_lvalue (t_result); + + if (loc) + set_tree_location (t_result, loc); + return new lvalue (this, t_result); +} + /* Construct a tree for a field access. */ tree @@ -1812,7 +2112,8 @@ playback::lvalue * playback::function:: new_local (location *loc, type *type, - const char *name) + const char *name, + const std::vector> &attributes) { gcc_assert (type); gcc_assert (name); @@ -1825,6 +2126,8 @@ new_local (location *loc, DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr); BIND_EXPR_VARS (m_inner_bind_expr) = inner; + set_variable_attribute (attributes, inner); + if (loc) set_tree_location (inner, loc); return new lvalue (m_ctxt, inner); @@ -1857,6 +2160,15 @@ playback::function::get_address (location *loc) return new rvalue (m_ctxt, t_fnptr); } +/* Construct a new local within this playback::function. */ + +void +playback::function:: +set_personality_function (function *personality_function) +{ + DECL_FUNCTION_PERSONALITY (m_inner_fndecl) = personality_function->as_fndecl (); +} + /* Build a statement list for the function as a whole out of the lists of statements for the individual blocks, building labels for each block. */ @@ -1875,6 +2187,11 @@ build_stmt_list () int j; tree stmt; + // Do not add try/catch block to the function. + // TODO: explain why. + if (b->m_is_try_or_catch) + continue; + b->m_label_expr = build1 (LABEL_EXPR, void_type_node, b->as_label_decl ()); @@ -1973,6 +2290,70 @@ add_eval (location *loc, add_stmt (rvalue->as_tree ()); } + +void +playback::block:: +add_try_catch (location *loc, + block *try_block, + block *catch_block, + bool is_finally) +{ + gcc_assert (try_block); + gcc_assert (catch_block); + + try_block->m_is_try_or_catch = true; + catch_block->m_is_try_or_catch = true; + + if (loc) + { + set_tree_location (try_block->as_label_decl (), loc); + set_tree_location (catch_block->as_label_decl (), loc); + } + + tree try_body = alloc_stmt_list (); + unsigned int i; + tree stmt; + FOR_EACH_VEC_ELT (try_block->m_stmts, i, stmt) { + append_to_statement_list (stmt, &try_body); + } + + tree catch_body = alloc_stmt_list (); + unsigned int j; + tree catch_stmt; + FOR_EACH_VEC_ELT (catch_block->m_stmts, j, catch_stmt) { + append_to_statement_list (catch_stmt, &catch_body); + } + + if (is_finally) + { + tree success_body = alloc_stmt_list (); + + // TODO: find a better way to keep the EH_ELSE_EXPR than creating an empty inline asm. + tree t_string = build_string (""); + tree asm_stmt + = build5 (ASM_EXPR, void_type_node, t_string, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); + + // asm statements without outputs, including simple ones, are treated + // as volatile. + ASM_VOLATILE_P (asm_stmt) = 1; + ASM_INPUT_P (asm_stmt) = 0; + append_to_statement_list (asm_stmt, &success_body); + + // TODO: Don't automatically add the `EH_ELSE_EXPR`. Make an API to create such a node and let the user of libgccjit + // add it manually. + catch_body = build2 (EH_ELSE_EXPR, void_type_node, success_body, catch_body); + add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, + try_body, catch_body)); + } + else + { + catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body); + tree try_catch = build2 (TRY_CATCH_EXPR, void_type_node, + try_body, catch_body); + add_stmt (try_catch); + } +} + /* Add an assignment to the function's statement list. */ void diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 43e92d67d74..b767fec6da8 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -21,7 +21,9 @@ along with GCC; see the file COPYING3. If not see #ifndef JIT_PLAYBACK_H #define JIT_PLAYBACK_H +#include #include // for std::pair +#include #include "timevar.h" #include "varasm.h" @@ -41,6 +43,9 @@ namespace jit { namespace playback { +void +set_variable_attribute(const std::vector> &attributes, tree decl); + /* playback::context is an abstract base class. The two concrete subclasses are: @@ -69,7 +74,7 @@ public: type * new_array_type (location *loc, type *element_type, - int num_elements); + unsigned long num_elements); field * new_field (location *loc, @@ -85,7 +90,8 @@ public: compound_type * new_compound_type (location *loc, const char *name, - bool is_struct); /* else is union */ + bool is_struct, /* else is union */ + bool is_packed); type * new_function_type (type *return_type, @@ -104,14 +110,19 @@ public: const char *name, const auto_vec *params, int is_variadic, - enum built_in_function builtin_id); + enum built_in_function builtin_id, + const std::vector &attributes, + const std::vector> &string_attributes, + int is_target_builtin); lvalue * new_global (location *loc, enum gcc_jit_global_kind kind, type *type, const char *name, - enum global_var_flags flags); + enum global_var_flags flags, + bool readonly, + const std::vector> &attributes); lvalue * new_global_initialized (location *loc, @@ -121,7 +132,9 @@ public: size_t initializer_num_elem, const void *initializer, const char *name, - enum global_var_flags flags); + enum global_var_flags flags, + bool readonly, + const std::vector> &attributes); rvalue * new_ctor (location *log, @@ -147,6 +160,12 @@ public: type *type, const auto_vec &elements); + rvalue * + new_rvalue_vector_perm (location *loc, + rvalue* elements1, + rvalue* elements2, + rvalue* mask); + rvalue * new_unary_op (location *loc, enum gcc_jit_unary_op op, @@ -191,6 +210,16 @@ public: rvalue *ptr, rvalue *index); + rvalue * + convert_vector (location *loc, + rvalue *vector, + type *type); + + lvalue * + new_vector_access (location *loc, + rvalue *vector, + rvalue *index); + void set_str_option (enum gcc_jit_str_option opt, const char *value); @@ -306,7 +335,9 @@ private: enum gcc_jit_global_kind kind, type *type, const char *name, - enum global_var_flags flags); + enum global_var_flags flags, + bool readonly, + const std::vector> &attributes); lvalue * global_finalize_lvalue (tree inner); @@ -460,7 +491,7 @@ public: : type (inner) {} - void set_fields (const auto_vec *fields); + void set_fields (const auto_vec *fields, bool is_packed); }; class field : public wrapper @@ -495,7 +526,8 @@ public: lvalue * new_local (location *loc, type *type, - const char *name); + const char *name, + const std::vector> &attributes); block* new_block (const char *name); @@ -503,6 +535,9 @@ public: rvalue * get_address (location *loc); + void + set_personality_function (function *personality_function); + void build_stmt_list (); @@ -573,6 +608,12 @@ public: add_eval (location *loc, rvalue *rvalue); + void + add_try_catch (location *loc, + block *try_block, + block *catch_block, + bool is_finally); + void add_assignment (location *loc, lvalue *lvalue, @@ -636,6 +677,7 @@ private: public: // for now tree m_label_expr; + bool m_is_try_or_catch = false; friend class function; }; @@ -813,4 +855,6 @@ extern playback::context *active_playback_ctxt; } // namespace gcc +extern hash_map target_builtins; + #endif /* JIT_PLAYBACK_H */ diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index 2ce272267b8..603731b7fd4 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -840,9 +840,9 @@ recording::context::get_int_type (int num_bytes, int is_signed) recording::type * recording::context::new_array_type (recording::location *loc, recording::type *element_type, - int num_elements) + unsigned long num_elements) { - if (struct_ *s = element_type->dyn_cast_struct ()) + /*if (struct_ *s = element_type->dyn_cast_struct ()) if (!s->get_fields ()) { add_error (NULL, @@ -850,7 +850,7 @@ recording::context::new_array_type (recording::location *loc, " until the fields have been set", s->get_name ()->c_str ()); return NULL; - } + }*/ recording::type *result = new recording::array_type (this, loc, element_type, num_elements); record (result); @@ -933,14 +933,16 @@ recording::function_type * recording::context::new_function_type (recording::type *return_type, int num_params, recording::type **param_types, - int is_variadic) + int is_variadic, + int is_target_builtin) { recording::function_type *fn_type = new function_type (this, return_type, num_params, param_types, - is_variadic); + is_variadic, + is_target_builtin); record (fn_type); return fn_type; } @@ -962,7 +964,8 @@ recording::context::new_function_ptr_type (recording::location *, /* unused loc = new_function_type (return_type, num_params, param_types, - is_variadic); + is_variadic, + false); /* Return a pointer-type to the function type. */ return fn_type->get_pointer (); @@ -1005,7 +1008,7 @@ recording::context::new_function (recording::location *loc, loc, kind, return_type, new_string (name), num_params, params, is_variadic, - builtin_id); + builtin_id, false); record (result); m_functions.safe_push (result); @@ -1044,6 +1047,52 @@ recording::context::get_builtin_function (const char *name) return bm->get_builtin_function (name); } +/* Create a recording::function instance for a target-specific builtin. + + Implements the post-error-checking part of + gcc_jit_context_get_target_builtin_function. */ + +recording::function * +recording::context::get_target_builtin_function (const char *name) +{ + const char *asm_name = name; + if (target_function_types.count (name) == 0) + { + fprintf (stderr, "Cannot find target builtin %s\n", name); + return NULL; + } + + recording::function_type* func_type = target_function_types[name]->copy (this)->dyn_cast_function_type (); + const vec& param_types = func_type->get_param_types (); + recording::param **params = new recording::param *[param_types.length ()]; + + int i; + recording::type *param_type; + FOR_EACH_VEC_ELT (param_types, i, param_type) + { + char buf[16]; + snprintf (buf, 16, "arg%d", i); + params[i] = new_param (NULL, + param_type, + buf); + } + + recording::function *result = + new recording::function (this, + NULL, + GCC_JIT_FUNCTION_IMPORTED, // FIXME + func_type->get_return_type (), + new_string (asm_name), + param_types.length (), + params, + func_type->is_variadic (), + BUILT_IN_NONE, + true); + record (result); + + return result; +} + /* Create a recording::global instance and add it to this context's list of mementos. @@ -1108,6 +1157,18 @@ recording::context::new_rvalue_from_vector (location *loc, return result; } +recording::rvalue * +recording::context::new_rvalue_vector_perm (location *loc, + rvalue *elements1, + rvalue *elements2, + rvalue *mask) +{ + recording::rvalue *result + = new memento_of_new_rvalue_vector_perm (this, loc, elements1, elements2, mask); + record (result); + return result; +} + recording::rvalue * recording::context::new_ctor (recording::location *loc, recording::type *type, @@ -1309,6 +1370,39 @@ recording::context::new_array_access (recording::location *loc, return result; } +/* Create a recording::convert_vector instance and add it to this context's list + of mementos. + + Implements the post-error-checking part of + gcc_jit_context_convert_vector. */ + +recording::rvalue * +recording::context::new_convert_vector (recording::location *loc, + recording::rvalue *vector, + recording::type *type) +{ + // TODO: instead have an "internal function" memento? + recording::rvalue *result = new convert_vector (this, loc, vector, type); + record (result); + return result; +} + +/* Create a recording::vector_access instance and add it to this context's list + of mementos. + + Implements the post-error-checking part of + gcc_jit_context_new_vector_access. */ + +recording::lvalue * +recording::context::new_vector_access (recording::location *loc, + recording::rvalue *vector, + recording::rvalue *index) +{ + recording::lvalue *result = new vector_access (this, loc, vector, index); + record (result); + return result; +} + /* Create a recording::case_ instance and add it to this context's list of mementos. @@ -2294,6 +2388,12 @@ recording::type::get_aligned (size_t alignment_in_bytes) return result; } +void +recording::type::set_packed () +{ + m_packed = true; +} + /* Given a type, get a vector version of the type. Implements the post-error-checking part of @@ -2372,6 +2472,10 @@ recording::memento_of_get_type::get_size () case GCC_JIT_TYPE_FLOAT: size = FLOAT_TYPE_SIZE; break; + #ifdef HAVE_BFmode + case GCC_JIT_TYPE_BFLOAT16: + return GET_MODE_UNIT_SIZE (BFmode); + #endif case GCC_JIT_TYPE_DOUBLE: size = DOUBLE_TYPE_SIZE; break; @@ -2431,6 +2535,7 @@ recording::memento_of_get_type::dereference () case GCC_JIT_TYPE_INT64_T: case GCC_JIT_TYPE_INT128_T: case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_BFLOAT16: case GCC_JIT_TYPE_DOUBLE: case GCC_JIT_TYPE_LONG_DOUBLE: case GCC_JIT_TYPE_COMPLEX_FLOAT: @@ -2495,6 +2600,7 @@ recording::memento_of_get_type::is_int () const return true; case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_BFLOAT16: case GCC_JIT_TYPE_DOUBLE: case GCC_JIT_TYPE_LONG_DOUBLE: return false; @@ -2553,6 +2659,7 @@ recording::memento_of_get_type::is_signed () const case GCC_JIT_TYPE_UINT128_T: case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_BFLOAT16: case GCC_JIT_TYPE_DOUBLE: case GCC_JIT_TYPE_LONG_DOUBLE: @@ -2612,6 +2719,7 @@ recording::memento_of_get_type::is_float () const return false; case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_BFLOAT16: case GCC_JIT_TYPE_DOUBLE: case GCC_JIT_TYPE_LONG_DOUBLE: return true; @@ -2675,6 +2783,7 @@ recording::memento_of_get_type::is_bool () const return false; case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_BFLOAT16: case GCC_JIT_TYPE_DOUBLE: case GCC_JIT_TYPE_LONG_DOUBLE: return false; @@ -2754,6 +2863,7 @@ static const char * const get_type_strings[] = { "__int32_t", /* GCC_JIT_TYPE_INT32_T */ "__int64_t", /* GCC_JIT_TYPE_INT64_T */ "__int128_t", /* GCC_JIT_TYPE_INT128_T */ + "bfloat16", /* GCC_JIT_TYPE_BFLOAT16 */ }; @@ -2800,6 +2910,7 @@ static const char * const get_type_enum_strings[] = { "GCC_JIT_TYPE_INT32_T", "GCC_JIT_TYPE_INT64_T", "GCC_JIT_TYPE_INT128_T", + "GCC_JIT_TYPE_BFLOAT16", }; void @@ -3066,7 +3177,7 @@ recording::string * recording::array_type::make_debug_string () { return string::from_printf (m_ctxt, - "%s[%d]", + "%s[%ld]", m_element_type->get_debug_string (), m_num_elements); } @@ -3082,7 +3193,7 @@ recording::array_type::write_reproducer (reproducer &r) " gcc_jit_context_new_array_type (%s,\n" " %s, /* gcc_jit_location *loc */\n" " %s, /* gcc_jit_type *element_type */\n" - " %i); /* int num_elements */\n", + " %li); /* int num_elements */\n", id, r.get_identifier (get_context ()), r.get_identifier (m_loc), @@ -3098,11 +3209,13 @@ recording::function_type::function_type (context *ctxt, type *return_type, int num_params, type **param_types, - int is_variadic) + int is_variadic, + int is_target_builtin) : type (ctxt), m_return_type (return_type), m_param_types (), - m_is_variadic (is_variadic) + m_is_variadic (is_variadic), + m_is_target_builtin (is_target_builtin) { for (int i = 0; i< num_params; i++) m_param_types.safe_push (param_types[i]); @@ -3484,7 +3597,8 @@ recording::struct_::replay_into (replayer *r) set_playback_obj ( r->new_compound_type (playback_location (r, get_loc ()), get_name ()->c_str (), - true /* is_struct */)); + true, /* is_struct */ + m_packed)); } const char * @@ -3538,7 +3652,8 @@ recording::union_::replay_into (replayer *r) set_playback_obj ( r->new_compound_type (playback_location (r, get_loc ()), get_name ()->c_str (), - false /* is_struct */)); + false, /* is_struct */ + m_packed)); } /* Implementation of recording::memento::make_debug_string for @@ -3609,7 +3724,7 @@ recording::fields::replay_into (replayer *) playback_fields.create (m_fields.length ()); for (unsigned i = 0; i < m_fields.length (); i++) playback_fields.safe_push (m_fields[i]->playback_field ()); - m_struct_or_union->playback_compound_type ()->set_fields (&playback_fields); + m_struct_or_union->playback_compound_type ()->set_fields (&playback_fields, m_struct_or_union->m_packed); } /* Override the default implementation of @@ -3979,6 +4094,11 @@ void recording::lvalue::set_alignment (unsigned bytes) m_alignment = bytes; } +void recording::lvalue::add_attribute (gcc_jit_variable_attribute attribute, const char* value) +{ + m_attributes.push_back (std::make_pair (attribute, std::string (value))); +} + /* The implementation of class gcc::jit::recording::param. */ /* Implementation of pure virtual hook recording::memento::replay_into @@ -4044,7 +4164,8 @@ recording::function::function (context *ctxt, int num_params, recording::param **params, int is_variadic, - enum built_in_function builtin_id) + enum built_in_function builtin_id, + int is_target_builtin) : memento (ctxt), m_loc (loc), m_kind (kind), @@ -4055,7 +4176,10 @@ recording::function::function (context *ctxt, m_builtin_id (builtin_id), m_locals (), m_blocks (), - m_fn_ptr_type (NULL) + m_fn_ptr_type (NULL), + m_attributes(), + m_string_attributes(), + m_is_target_builtin (is_target_builtin) { for (int i = 0; i< num_params; i++) { @@ -4114,7 +4238,40 @@ recording::function::replay_into (replayer *r) m_name->c_str (), ¶ms, m_is_variadic, - m_builtin_id)); + m_builtin_id, + m_attributes, + m_string_attributes, + m_is_target_builtin)); +} + +/* Implementation of recording::memento::make_debug_string for + setting a personality function. */ + +recording::string * +recording::memento_of_set_personality_function::make_debug_string () +{ + return string::from_printf (m_ctxt, + "%s", + m_personality_function->get_debug_string ()); +} + +/* Implementation of recording::memento::write_reproducer for setting the personality function. */ + +void +recording::memento_of_set_personality_function::write_reproducer (reproducer &r) +{ + r.write (" gcc_jit_function_set_personality_function (%s,\n" + " %s);\n", + r.get_identifier (m_function), + r.get_identifier (m_personality_function)); +} + +void +recording::function::set_personality_function (function *function) +{ + recording::memento_of_set_personality_function *result = + new memento_of_set_personality_function (m_ctxt, this, function); + m_ctxt->record (result); } /* Create a recording::local instance and add it to @@ -4259,6 +4416,13 @@ recording::function::validate () /* Iteratively walk the graph of blocks, marking their "m_is_reachable" flag, starting at the initial block. */ auto_vec worklist (m_blocks.length ()); + int j; + block *func_block; + /* Push the blocks used in try/catch because they're not successors of + other blocks. */ + FOR_EACH_VEC_ELT (m_blocks, j, func_block) + if (func_block->m_is_reachable) + worklist.safe_push (func_block); worklist.safe_push (m_blocks[0]); while (worklist.length () > 0) { @@ -4347,7 +4511,8 @@ recording::function::get_address (recording::location *loc) = m_ctxt->new_function_type (m_return_type, m_params.length (), param_types.address (), - m_is_variadic); + m_is_variadic, + m_is_target_builtin); m_fn_ptr_type = fn_type->get_pointer (); } gcc_assert (m_fn_ptr_type); @@ -4357,6 +4522,18 @@ recording::function::get_address (recording::location *loc) return result; } +void +recording::function::add_attribute (gcc_jit_fn_attribute attribute) +{ + m_attributes.push_back (attribute); +} + +void +recording::function::add_string_attribute (gcc_jit_fn_attribute attribute, const char* value) +{ + m_string_attributes.push_back (std::make_pair (attribute, std::string (value))); +} + /* Implementation of recording::memento::make_debug_string for functions. */ @@ -4441,6 +4618,31 @@ recording::block::add_eval (recording::location *loc, return result; } +/* The implementation of class gcc::jit::recording::block. */ + +/* Create a recording::try_catch instance and add it to + the block's context's list of mementos, and to the block's + list of statements. + Implements the heart of gcc_jit_block_add_try_catch. */ + +recording::statement * +recording::block::add_try_catch (location *loc, + block *try_block, + block *catch_block, + bool is_finally) +{ + statement *result = new try_catch (this, loc, try_block, catch_block, is_finally); + // TODO: explain why we set the blocks reachable state. + try_block->m_is_reachable = true; + catch_block->m_is_reachable = true; + /* The finally block can fallthrough, so we don't require the user to terminate it. */ + if (is_finally) + catch_block->m_has_been_terminated = true; + m_ctxt->record (result); + m_statements.safe_push (result); + return result; +} + /* Create a recording::assignment instance and add it to the block's context's list of mementos, and to the block's list of statements. @@ -4832,12 +5034,16 @@ recording::global::replay_into (replayer *r) / m_type->dereference ()->get_size (), m_initializer, playback_string (m_name), - m_flags) + m_flags, + m_readonly, + m_attributes) : r->new_global (playback_location (r, m_loc), m_kind, m_type->playback_type (), playback_string (m_name), - m_flags); + m_flags, + m_readonly, + m_attributes); if (m_tls_model != GCC_JIT_TLS_MODEL_NONE) global->set_tls_model (recording::tls_models[m_tls_model]); @@ -5390,6 +5596,91 @@ recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r) elements_id); } +/* The implementation of class + gcc::jit::recording::memento_of_new_rvalue_vector_perm. */ + +/* The constructor for + gcc::jit::recording::memento_of_new_rvalue_vector_perm. */ + +recording::memento_of_new_rvalue_vector_perm:: +memento_of_new_rvalue_vector_perm (context *ctxt, + location *loc, + rvalue *elements1, + rvalue *elements2, + rvalue *mask) +: rvalue (ctxt, loc, elements1->get_type ()), + m_elements1 (elements1), + m_elements2 (elements2), + m_mask (mask) +{ +} + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::memento_of_new_rvalue_vector_perm. */ + +void +recording::memento_of_new_rvalue_vector_perm::replay_into (replayer *r) +{ + playback::rvalue *playback_elements1 = m_elements1->playback_rvalue (); + playback::rvalue *playback_elements2 = m_elements2->playback_rvalue (); + playback::rvalue *playback_mask = m_mask->playback_rvalue (); + + set_playback_obj (r->new_rvalue_vector_perm (playback_location (r, m_loc), + playback_elements1, + playback_elements2, + playback_mask)); +} + +/* Implementation of pure virtual hook recording::rvalue::visit_children + for recording::memento_of_new_rvalue_from_vector. */ + + void +recording::memento_of_new_rvalue_vector_perm::visit_children (rvalue_visitor *v) +{ + v->visit (m_elements1); + v->visit (m_elements2); + v->visit (m_mask); +} + +/* Implementation of recording::memento::make_debug_string for + vectors. */ + + recording::string * +recording::memento_of_new_rvalue_vector_perm::make_debug_string () +{ + /* Now build a string. */ + string *result = string::from_printf (m_ctxt, + "shufflevector(%s, %s, %s)", + m_elements1->get_debug_string (), + m_elements2->get_debug_string (), + m_mask->get_debug_string ()); + + return result; + +} + +/* Implementation of recording::memento::write_reproducer for + vectors. */ + + void +recording::memento_of_new_rvalue_vector_perm::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "vector"); + r.write (" gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_vector_perm (%s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_location *loc */\n" + " %s, /* gcc_jit_rvalue **elements1*/\n" + " %s, /* gcc_jit_rvalue **elements2*/\n" + " %s); /* gcc_jit_rvalue **mask*/\n", + id, + r.get_identifier (get_context ()), + r.get_identifier (m_loc), + r.get_identifier_as_rvalue (m_elements1), + r.get_identifier_as_rvalue (m_elements2), + r.get_identifier_as_rvalue (m_mask)); +} + + void recording::ctor::visit_children (rvalue_visitor *v) { @@ -6260,6 +6551,114 @@ recording::array_access::write_reproducer (reproducer &r) r.get_identifier_as_rvalue (m_index)); } +/* The implementation of class gcc::jit::recording::convert_vector. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::convert_vector. */ + +void +recording::convert_vector::replay_into (replayer *r) +{ + set_playback_obj ( + r->convert_vector (playback_location (r, m_loc), + m_vector->playback_rvalue (), + m_type->playback_type ())); +} + +/* Implementation of pure virtual hook recording::rvalue::visit_children + for recording::convert_vector. */ + +void +recording::convert_vector::visit_children (rvalue_visitor *v) +{ + v->visit (m_vector); +} + +/* The implementation of class gcc::jit::recording::vector_access. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::vector_access. */ + +void +recording::vector_access::replay_into (replayer *r) +{ + set_playback_obj ( + r->new_vector_access (playback_location (r, m_loc), + m_vector->playback_rvalue (), + m_index->playback_rvalue ())); +} + +/* Implementation of pure virtual hook recording::rvalue::visit_children + for recording::vector_access. */ + +void +recording::vector_access::visit_children (rvalue_visitor *v) +{ + v->visit (m_vector); + v->visit (m_index); +} + +/* Implementation of recording::memento::make_debug_string for + array accesses. */ + +recording::string * +recording::convert_vector::make_debug_string () +{ + enum precedence prec = get_precedence (); + return string::from_printf (m_ctxt, + "(%s)%s", + m_type->get_debug_string (), + m_vector->get_debug_string_parens (prec)); +} + +/* Implementation of recording::memento::write_reproducer for + convert_vector. */ + +void +recording::convert_vector::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "lvalue"); + r.write (" gcc_jit_lvalue *%s = \n" + " gcc_jit_context_convert_vector (%s, /* gcc_jit_context *ctxt */\n" + " %s, /*gcc_jit_location *loc */\n" + " %s, /* gcc_jit_rvalue *vector */\n" + " %s); /* gcc_jit_type *type */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier (m_loc), + r.get_identifier_as_rvalue (m_vector), + r.get_identifier_as_type (m_type)); +} + +recording::string * +recording::vector_access::make_debug_string () +{ + enum precedence prec = get_precedence (); + return string::from_printf (m_ctxt, + "%s[%s]", + m_vector->get_debug_string_parens (prec), + m_index->get_debug_string_parens (prec)); +} + +/* Implementation of recording::memento::write_reproducer for + vector_access. */ + +void +recording::vector_access::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "lvalue"); + r.write (" gcc_jit_lvalue *%s = \n" + " gcc_jit_context_new_vector_access (%s, /* gcc_jit_context *ctxt */\n" + " %s, /*gcc_jit_location *loc */\n" + " %s, /* gcc_jit_rvalue *vector */\n" + " %s); /* gcc_jit_rvalue *index */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier (m_loc), + r.get_identifier_as_rvalue (m_vector), + r.get_identifier_as_rvalue (m_index)); +} + /* The implementation of class gcc::jit::recording::access_field_of_lvalue. */ /* Implementation of pure virtual hook recording::memento::replay_into @@ -6575,7 +6974,8 @@ recording::local::replay_into (replayer *r) playback::lvalue *obj = m_func->playback_function () ->new_local (playback_location (r, m_loc), m_type->playback_type (), - playback_string (m_name)); + playback_string (m_name), + m_attributes); if (m_reg_name != NULL) obj->set_register_name (m_reg_name->c_str ()); @@ -6649,6 +7049,17 @@ recording::statement::write_to_dump (dump &d) m_loc = d.make_location (); } +/* The implementation of class gcc::jit::recording::memento_of_set_personality_function. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::memento_of_set_personality_function. */ + +void +recording::memento_of_set_personality_function::replay_into (replayer *r) +{ + m_function->playback_function ()->set_personality_function (m_personality_function->playback_function ()); +} + /* The implementation of class gcc::jit::recording::eval. */ /* Implementation of pure virtual hook recording::memento::replay_into @@ -6687,6 +7098,59 @@ recording::eval::write_reproducer (reproducer &r) r.get_identifier_as_rvalue (m_rvalue)); } +/* The implementation of class gcc::jit::recording::try_catch. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::try_catch. */ + +void +recording::try_catch::replay_into (replayer *r) +{ + playback_block (get_block ()) + ->add_try_catch (playback_location (r), + m_try_block->playback_block (), + m_catch_block->playback_block (), + m_is_finally); +} + +/* Implementation of recording::memento::make_debug_string for + an eval statement. */ + +recording::string * +recording::try_catch::make_debug_string () +{ + if (m_is_finally) + return string::from_printf (m_ctxt, + "try { %s } finally { %s };", + m_try_block->get_debug_string (), + m_catch_block->get_debug_string ()); + else + return string::from_printf (m_ctxt, + "try { %s } catch { %s };", + m_try_block->get_debug_string (), + m_catch_block->get_debug_string ()); +} + +/* Implementation of recording::memento::write_reproducer for + eval statements. */ + +void +recording::try_catch::write_reproducer (reproducer &r) +{ + const char *func_name = "gcc_jit_block_add_try_catch"; + if (m_is_finally) + func_name = "gcc_jit_block_add_try_finally"; + r.write (" %s (%s, /*gcc_jit_block *block */\n" + " %s, /* gcc_jit_location *loc */\n" + " %s, /* gcc_jit_block *try_block */\n" + " %s); /* gcc_jit_block *catch_block */\n", + func_name, + r.get_identifier (get_block ()), + r.get_identifier (get_loc ()), + r.get_identifier (m_try_block), + r.get_identifier (m_catch_block)); +} + /* The implementation of class gcc::jit::recording::assignment. */ /* Implementation of pure virtual hook recording::memento::replay_into diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index e1236dec575..68a792a7cd5 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -23,13 +23,21 @@ along with GCC; see the file COPYING3. If not see #include "jit-common.h" #include "jit-logging.h" +#include "libgccjit.h" + +#include +#include + +#include +#include class timer; +extern std::unordered_map target_function_types; + namespace gcc { namespace jit { - extern const char * const unary_op_reproducer_strings[]; extern const char * const binary_op_reproducer_strings[]; @@ -91,7 +99,7 @@ public: type * new_array_type (location *loc, type *element_type, - int num_elements); + unsigned long num_elements); field * new_field (location *loc, @@ -116,7 +124,8 @@ public: new_function_type (type *return_type, int num_params, type **param_types, - int is_variadic); + int is_variadic, + int is_target_builtin); type * new_function_ptr_type (location *loc, @@ -143,6 +152,9 @@ public: function * get_builtin_function (const char *name); + function * + get_target_builtin_function (const char *name); + lvalue * new_global (location *loc, enum gcc_jit_global_kind kind, @@ -173,6 +185,12 @@ public: vector_type *type, rvalue **elements); + rvalue * + new_rvalue_vector_perm (location *loc, + rvalue *elements1, + rvalue *elements2, + rvalue *mask); + rvalue * new_unary_op (location *loc, enum gcc_jit_unary_op op, @@ -215,6 +233,16 @@ public: rvalue *ptr, rvalue *index); + rvalue * + new_convert_vector (location *loc, + rvalue *vector, + type *type); + + lvalue * + new_vector_access (location *loc, + rvalue *vector, + rvalue *index); + case_ * new_case (rvalue *min_value, rvalue *max_value, @@ -527,6 +555,8 @@ public: type *get_aligned (size_t alignment_in_bytes); type *get_vector (size_t num_units); + void set_packed (); + /* Get the type obtained when dereferencing this type. This will return NULL if it's not valid to dereference this type. @@ -539,6 +569,8 @@ public: these types. */ virtual size_t get_size () { gcc_unreachable (); } + virtual type* copy(context* ctxt) = 0; + /* Dynamic casts. */ virtual function_type *dyn_cast_function_type () { return NULL; } virtual function_type *as_a_function_type() { gcc_unreachable (); return NULL; } @@ -593,9 +625,13 @@ public: protected: type (context *ctxt) : memento (ctxt), + m_packed (false), m_pointer_to_this_type (NULL) {} +public: + bool m_packed; + private: type *m_pointer_to_this_type; }; @@ -613,6 +649,11 @@ public: size_t get_size () final override; + type* copy(context* ctxt) final override + { + return ctxt->get_type (m_kind); + } + bool accepts_writes_from (type *rtype) final override { if (m_kind == GCC_JIT_TYPE_VOID_PTR) @@ -664,6 +705,13 @@ public: type *dereference () final override { return m_other_type; } + type* copy(context* ctxt) final override + { + type* result = new memento_of_get_pointer (m_other_type->copy (ctxt)); + ctxt->record (result); + return result; + } + size_t get_size () final override; bool accepts_writes_from (type *rtype) final override; @@ -699,6 +747,7 @@ public: size_t get_size () final override { return m_other_type->get_size (); }; + // FIXME: this is wrong. A vector is not an int. 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 (); } @@ -718,10 +767,11 @@ public: memento_of_get_const (type *other_type) : decorated_type (other_type) {} - bool accepts_writes_from (type */*rtype*/) final override + type* copy(context* ctxt) final override { - /* Can't write to a "const". */ - return false; + type* result = new memento_of_get_const (m_other_type->copy (ctxt)); + ctxt->record (result); + return result; } /* Strip off the "const", giving the underlying type. */ @@ -757,6 +807,13 @@ public: return m_other_type->is_same_type_as (other->is_volatile ()); } + type* copy(context* ctxt) final override + { + type* result = new memento_of_get_volatile (m_other_type->copy (ctxt)); + ctxt->record (result); + return result; + } + /* Strip off the "volatile", giving the underlying type. */ type *unqualified () final override { return m_other_type; } @@ -777,11 +834,20 @@ public: : decorated_type (other_type), m_alignment_in_bytes (alignment_in_bytes) {} + type* copy(context* ctxt) final override + { + type* result = new memento_of_get_aligned (m_other_type->copy (ctxt), m_alignment_in_bytes); + ctxt->record (result); + return result; + } + /* Strip off the alignment, giving the underlying type. */ type *unqualified () final override { return m_other_type; } void replay_into (replayer *) final override; + vector_type *dyn_cast_vector_type () final override { return m_other_type->dyn_cast_vector_type (); } + private: string * make_debug_string () final override; void write_reproducer (reproducer &r) final override; @@ -798,6 +864,13 @@ public: : decorated_type (other_type), m_num_units (num_units) {} + type* copy(context* ctxt) final override + { + type* result = new vector_type(m_other_type->copy (ctxt), m_num_units); + ctxt->record (result); + return result; + } + size_t get_num_units () const { return m_num_units; } vector_type *dyn_cast_vector_type () final override { return this; } @@ -831,7 +904,7 @@ class array_type : public type array_type (context *ctxt, location *loc, type *element_type, - int num_elements) + unsigned long num_elements) : type (ctxt), m_loc (loc), m_element_type (element_type), @@ -840,12 +913,19 @@ class array_type : public type type *dereference () final override; + type* copy(context* ctxt) final override + { + type* result = new array_type (ctxt, m_loc, m_element_type->copy (ctxt), m_num_elements); + ctxt->record (result); + return result; + } + 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; } + unsigned long num_elements () { return m_num_elements; } bool is_signed () const final override { return false; } void replay_into (replayer *) final override; @@ -857,7 +937,7 @@ class array_type : public type private: location *m_loc; type *m_element_type; - int m_num_elements; + unsigned long m_num_elements; }; class function_type : public type @@ -867,7 +947,8 @@ public: type *return_type, int num_params, type **param_types, - int is_variadic); + int is_variadic, + int is_target_builtin); type *dereference () final override; function_type *dyn_cast_function_type () final override { return this; } @@ -875,6 +956,18 @@ public: bool is_same_type_as (type *other) final override; + type* copy(context* ctxt) final override + { + auto_vec new_params{}; + for (size_t i = 0; i < m_param_types.length (); i++) + new_params.safe_push (m_param_types[i]->copy (ctxt)); + + type* result = new function_type (ctxt, m_return_type->copy (ctxt), m_param_types.length (), new_params.address (), + m_is_variadic, m_is_target_builtin); + ctxt->record (result); + return result; + } + bool is_int () const final override { return false; } bool is_float () const final override { return false; } bool is_bool () const final override { return false; } @@ -887,6 +980,7 @@ public: 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; } + int is_target_builtin () const { return m_is_target_builtin; } string * make_debug_string_with_ptr (); @@ -903,6 +997,7 @@ private: type *m_return_type; auto_vec m_param_types; int m_is_variadic; + int m_is_target_builtin; }; class field : public memento @@ -1004,9 +1099,11 @@ public: return static_cast (m_playback_obj); } -private: +protected: location *m_loc; string *m_name; + +private: fields *m_fields; }; @@ -1019,6 +1116,13 @@ public: struct_ *dyn_cast_struct () final override { return this; } + type* copy(context* ctxt) final override + { + type* result = new struct_ (ctxt, m_loc, m_name); + ctxt->record (result); + return result; + } + type * as_type () { return this; } @@ -1066,6 +1170,13 @@ public: void replay_into (replayer *r) final override; + type* copy(context* ctxt) final override + { + type* result = new union_ (ctxt, m_loc, m_name); + ctxt->record (result); + return result; + } + bool is_union () const final override { return true; } private: @@ -1188,7 +1299,8 @@ public: m_link_section (NULL), m_reg_name (NULL), m_tls_model (GCC_JIT_TLS_MODEL_NONE), - m_alignment (0) + m_alignment (0), + m_attributes () {} playback::lvalue * @@ -1208,6 +1320,14 @@ public: as_rvalue () { return this; } const char *access_as_rvalue (reproducer &r) override; + + void set_readonly () + { + m_readonly = true; + } + + void add_attribute (gcc_jit_variable_attribute attribute, const char* value); + 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); @@ -1221,6 +1341,8 @@ protected: string *m_reg_name; enum gcc_jit_tls_model m_tls_model; unsigned m_alignment; + bool m_readonly = false; + std::vector> m_attributes; }; class param : public lvalue @@ -1274,7 +1396,8 @@ public: int num_params, param **params, int is_variadic, - enum built_in_function builtin_id); + enum built_in_function builtin_id, + int is_target_builtin); void replay_into (replayer *r) final override; @@ -1308,11 +1431,17 @@ public: void write_to_dump (dump &d) final override; + bool is_target_builtin () const { return m_is_target_builtin; } + void validate (); void dump_to_dot (const char *path); rvalue *get_address (location *loc); + void set_personality_function (function *function); + + void add_attribute (gcc_jit_fn_attribute attribute); + void add_string_attribute (gcc_jit_fn_attribute attribute, const char* value); private: string * make_debug_string () final override; @@ -1329,6 +1458,9 @@ private: auto_vec m_locals; auto_vec m_blocks; type *m_fn_ptr_type; + std::vector m_attributes; + std::vector> m_string_attributes; + int m_is_target_builtin; }; class block : public memento @@ -1357,6 +1489,12 @@ public: add_eval (location *loc, rvalue *rvalue); + statement * + add_try_catch (location *loc, + block *try_block, + block *catch_block, + bool is_finally = false); + statement * add_assignment (location *loc, lvalue *lvalue, @@ -1572,6 +1710,27 @@ private: string *m_value; }; +class memento_of_set_personality_function : public memento +{ +public: + memento_of_set_personality_function (context *ctx, + function *func, + function *personality_function) + : memento(ctx), + m_function (func), + m_personality_function (personality_function) {} + + void replay_into (replayer *r) final override; + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; + +private: + function *m_function; + function *m_personality_function; +}; + class memento_of_new_rvalue_from_vector : public rvalue { public: @@ -1597,6 +1756,33 @@ private: auto_vec m_elements; }; +class memento_of_new_rvalue_vector_perm : public rvalue +{ +public: + memento_of_new_rvalue_vector_perm (context *ctxt, + location *loc, + rvalue *elements1, + rvalue *elements2, + rvalue *mask); + + 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: + rvalue *m_elements1; + rvalue *m_elements2; + rvalue *m_mask; +}; + class ctor : public rvalue { public: @@ -1879,6 +2065,64 @@ private: rvalue *m_index; }; +class convert_vector : public rvalue +{ +public: + convert_vector (context *ctxt, + location *loc, + rvalue *vector, + type *type) + : rvalue (ctxt, loc, type), + m_vector (vector), + m_type (type) + {} + + 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_vector; + type *m_type; +}; + +class vector_access : public lvalue +{ +public: + vector_access (context *ctxt, + location *loc, + rvalue *vector, + rvalue *index) + : lvalue (ctxt, loc, vector->get_type ()->dyn_cast_vector_type ()->get_element_type ()), + m_vector (vector), + 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_vector; + rvalue *m_index; +}; + class access_field_of_lvalue : public lvalue { public: @@ -2119,6 +2363,31 @@ private: rvalue *m_rvalue; }; +class try_catch : public statement +{ +public: + try_catch (block *b, + location *loc, + block *try_block, + block *catch_block, + bool is_finally = false) + : statement (b, loc), + m_try_block (try_block), + m_catch_block (catch_block), + m_is_finally (is_finally) {} + + void replay_into (replayer *r) final override; + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; + +private: + block *m_try_block; + block *m_catch_block; + bool m_is_finally; +}; + class assignment : public statement { public: diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 8884128e8d8..bbf94231930 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -592,6 +592,20 @@ gcc_jit_type_is_pointer (gcc_jit_type *type) return (gcc_jit_type *)type->is_pointer (); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::type::is_const method, in + jit-recording.cc. */ + +gcc_jit_type * +gcc_jit_type_is_const (gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type"); + + return (gcc_jit_type *)type->is_const (); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the @@ -751,7 +765,7 @@ gcc_jit_type * gcc_jit_context_new_array_type (gcc_jit_context *ctxt, gcc_jit_location *loc, gcc_jit_type *element_type, - int num_elements) + unsigned long num_elements) { RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context"); JIT_LOG_FUNC (ctxt->get_logger ()); @@ -783,12 +797,13 @@ gcc_jit_context_new_field (gcc_jit_context *ctxt, /* LOC can be NULL. */ RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type"); RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name"); - RETURN_NULL_IF_FAIL_PRINTF2 ( + // TODO: check at playback if the size is known. + /*RETURN_NULL_IF_FAIL_PRINTF2 ( type->has_known_size (), ctxt, loc, "unknown size for field \"%s\" (type: %s)", name, - type->get_debug_string ()); + type->get_debug_string ());*/ RETURN_NULL_IF_FAIL_PRINTF1 ( !type->is_void (), ctxt, loc, @@ -995,6 +1010,7 @@ size_t gcc_jit_struct_get_field_count (gcc_jit_struct *struct_type) { RETURN_VAL_IF_FAIL (struct_type, 0, NULL, NULL, "NULL struct type"); + RETURN_VAL_IF_FAIL (struct_type->get_fields (), 0, NULL, NULL, "NULL fields"); return struct_type->get_fields ()->length (); } @@ -1745,6 +1761,23 @@ gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt, reinterpret_cast(values)); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::context::get_target_builtin_function method, in + jit-recording.c. */ + +gcc_jit_function * +gcc_jit_context_get_target_builtin_function (gcc_jit_context *ctxt, + const char *name) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + RETURN_NULL_IF_FAIL (name, ctxt, NULL, "NULL name"); + + return static_cast (ctxt->get_target_builtin_function (name)); +} + /* Public entrypoint. See description in libgccjit.h. */ extern gcc_jit_lvalue * @@ -1853,6 +1886,23 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global, return global; } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::global::set_readonly method, in + jit-recording.cc. */ + +extern void +gcc_jit_global_set_readonly (gcc_jit_lvalue *global) +{ + RETURN_IF_FAIL (global, NULL, NULL, "NULL global"); + RETURN_IF_FAIL_PRINTF1 (global->is_global (), NULL, NULL, + "lvalue \"%s\" not a global", + global->get_debug_string ()); + + global->set_readonly (); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, this calls the trivial @@ -2422,6 +2472,8 @@ gcc_jit_context_new_cast (gcc_jit_context *ctxt, /* LOC can be NULL. */ RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue"); RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type"); + gcc::jit::recording::vector_type *vector_type = type->dyn_cast_vector_type (); + RETURN_NULL_IF_FAIL (vector_type == NULL, ctxt, loc, "cannot cast vector types"); RETURN_NULL_IF_FAIL_PRINTF3 ( is_valid_cast (rvalue->get_type (), type), ctxt, loc, @@ -2488,6 +2540,60 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt, return (gcc_jit_lvalue *)ctxt->new_array_access (loc, ptr, index); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::context::new_convert_vector method in + jit-recording.cc. */ + +gcc_jit_rvalue * +gcc_jit_context_convert_vector (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *vector, + gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + /* LOC can be NULL. */ + RETURN_NULL_IF_FAIL (vector, ctxt, loc, "NULL vector"); + RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type"); + + // TODO: check if the value is a vector. + // TODO: check if type is a vector type. + // TODO: check if the number of elements in vector and type matches. + + return (gcc_jit_rvalue *)ctxt->new_convert_vector (loc, vector, type); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::context::new_vector_access method in + jit-recording.cc. */ + +extern gcc_jit_lvalue * +gcc_jit_context_new_vector_access (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *vector, + gcc_jit_rvalue *index) +{ + RETURN_NULL_IF_FAIL (index, ctxt, loc, "NULL index"); + RETURN_NULL_IF_FAIL_PRINTF2 ( + vector->get_type ()->dyn_cast_vector_type (), + ctxt, loc, + "vector: %s (type: %s) is not a vector", + vector->get_debug_string (), + vector->get_type ()->get_debug_string ()); + RETURN_NULL_IF_FAIL_PRINTF2 ( + index->get_type ()->is_numeric (), + ctxt, loc, + "index: %s (type: %s) is not of numeric type", + index->get_debug_string (), + index->get_type ()->get_debug_string ()); + + return (gcc_jit_lvalue *)ctxt->new_vector_access (loc, vector, index); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the @@ -2801,6 +2907,64 @@ gcc_jit_block_add_eval (gcc_jit_block *block, rvalue->verify_valid_within_stmt (__func__, stmt); } +/* Public entrypoint. See description in libgccjit.h. + After error-checking, the real work is done by the + gcc::jit::recording::block::add_try_catch method in jit-recording.c. */ + +void +gcc_jit_block_add_try_catch (gcc_jit_block *block, + gcc_jit_location *loc, + gcc_jit_block *try_block, + gcc_jit_block *catch_block) +{ + RETURN_IF_NOT_VALID_BLOCK (block, loc); + gcc::jit::recording::context *ctxt = block->get_context (); + JIT_LOG_FUNC (ctxt->get_logger ()); + /* LOC can be NULL. */ + RETURN_IF_FAIL (try_block, ctxt, loc, "NULL rvalue"); + RETURN_IF_FAIL (catch_block, ctxt, loc, "NULL rvalue"); + + gcc::jit::recording::statement *stmt = block->add_try_catch (loc, try_block, catch_block); + + // TODO: remove this or use it. + /* "stmt" should be good enough to be usable in error-messages, + but might still not be compilable; perform some more + error-checking here. We do this here so that the error messages + can contain a stringified version of "stmt", whilst appearing + as close as possible to the point of failure. */ + /*try_block->verify_valid_within_stmt (__func__, stmt); + catch_block->verify_valid_within_stmt (__func__, stmt);*/ +} + +/* Public entrypoint. See description in libgccjit.h. + After error-checking, the real work is done by the + gcc::jit::recording::block::add_try_catch method in jit-recording.c. */ + +void +gcc_jit_block_add_try_finally (gcc_jit_block *block, + gcc_jit_location *loc, + gcc_jit_block *try_block, + gcc_jit_block *finally_block) +{ + RETURN_IF_NOT_VALID_BLOCK (block, loc); + gcc::jit::recording::context *ctxt = block->get_context (); + JIT_LOG_FUNC (ctxt->get_logger ()); + /* LOC can be NULL. */ + RETURN_IF_FAIL (try_block, ctxt, loc, "NULL rvalue"); + RETURN_IF_FAIL (finally_block, ctxt, loc, "NULL rvalue"); + + gcc::jit::recording::statement *stmt = block->add_try_catch (loc, try_block, finally_block, true); + + // TODO: remove this or use it. + /* "stmt" should be good enough to be usable in error-messages, + but might still not be compilable; perform some more + error-checking here. We do this here so that the error messages + can contain a stringified version of "stmt", whilst appearing + as close as possible to the point of failure. */ + /*try_block->verify_valid_within_stmt (__func__, stmt); + catch_block->verify_valid_within_stmt (__func__, stmt);*/ +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the @@ -2821,7 +2985,7 @@ gcc_jit_block_add_assignment (gcc_jit_block *block, RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue"); RETURN_IF_FAIL_PRINTF4 ( compatible_types (lvalue->get_type (), - rvalue->get_type ()), + rvalue->get_type ()) || lvalue->get_type ()->is_const () != NULL, ctxt, loc, "mismatching types:" " assignment to %s (type: %s) from %s (type: %s)", @@ -2867,7 +3031,7 @@ gcc_jit_block_add_assignment_op (gcc_jit_block *block, RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue"); RETURN_IF_FAIL_PRINTF4 ( compatible_types (lvalue->get_type (), - rvalue->get_type ()), + rvalue->get_type ()) || lvalue->get_type ()->is_const () != NULL, ctxt, loc, "mismatching types:" " assignment to %s (type: %s) involving %s (type: %s)", @@ -3575,6 +3739,27 @@ gcc_jit_context_add_command_line_option (gcc_jit_context *ctxt, ctxt->add_command_line_option (optname); } +/* Public entrypoint. See description in libgccjit.h. + After error-checking, the real work is done by the + gcc::jit::recording::function::set_personality_function method, in + jit-recording.c. */ + +void +gcc_jit_function_set_personality_function (gcc_jit_function *fn, + gcc_jit_function *personality_func) +{ + RETURN_IF_FAIL (fn, NULL, NULL, "NULL function"); + + fn->set_personality_function (personality_func); +} + +extern char* jit_personality_func_name; + +void +gcc_jit_set_global_personality_function_name (char* name) { + jit_personality_func_name = name; +} + /* Public entrypoint. See description in libgccjit.h. The real work is done by the @@ -3950,6 +4135,38 @@ gcc_jit_type_get_aligned (gcc_jit_type *type, return (gcc_jit_type *)type->get_aligned (alignment_in_bytes); } +void +gcc_jit_type_set_packed (gcc_jit_type *type) +{ + RETURN_IF_FAIL (type, NULL, NULL, "NULL type"); + + type->set_packed (); +} + +void +gcc_jit_function_add_attribute (gcc_jit_function *func, gcc_jit_fn_attribute attribute) +{ + RETURN_IF_FAIL (func, NULL, NULL, "NULL func"); + + func->add_attribute (attribute); +} + +void +gcc_jit_function_add_string_attribute (gcc_jit_function *func, gcc_jit_fn_attribute attribute, const char* value) +{ + RETURN_IF_FAIL (func, NULL, NULL, "NULL func"); + + func->add_string_attribute (attribute, value); +} + +void +gcc_jit_lvalue_add_attribute (gcc_jit_lvalue *variable, gcc_jit_variable_attribute attribute, const char* value) +{ + RETURN_IF_FAIL (variable, NULL, NULL, "NULL variable"); + + variable->add_attribute (attribute, value); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the @@ -4056,6 +4273,74 @@ gcc_jit_context_new_rvalue_from_vector (gcc_jit_context *ctxt, (gcc::jit::recording::rvalue **)elements); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::context::new_rvalue_vector_perm method, in + jit-recording.cc. */ + +gcc_jit_rvalue * +gcc_jit_context_new_rvalue_vector_perm (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *elements1, + gcc_jit_rvalue *elements2, + gcc_jit_rvalue *mask) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL ctxt"); + JIT_LOG_FUNC (ctxt->get_logger ()); + + /* LOC can be NULL. */ + + gcc::jit::recording::type *elements1_type = elements1->get_type (); + gcc::jit::recording::type *elements2_type = elements2->get_type (); + RETURN_NULL_IF_FAIL_PRINTF4 ( + compatible_types (elements1->get_type ()->unqualified (), + elements2->get_type ()->unqualified ()), + ctxt, loc, + "mismatching types for vector perm:" + " elements1: %s (type: %s) elements2: %s (type: %s)", + elements1->get_debug_string (), + elements1_type->get_debug_string (), + elements2->get_debug_string (), + elements2_type->get_debug_string ()); + + gcc::jit::recording::type *mask_type = mask->get_type (); + gcc::jit::recording::vector_type *mask_vector_type = mask_type->dyn_cast_vector_type (); + gcc::jit::recording::vector_type *elements1_vector_type = elements1_type->dyn_cast_vector_type (); + + size_t mask_len = mask_vector_type->get_num_units (); + size_t elements1_len = elements1_vector_type->get_num_units (); + + RETURN_NULL_IF_FAIL_PRINTF2 ( + mask_len == elements1_len, + ctxt, loc, + "mismatching length for mask:" + " elements1 length: %ld mask length: %ld", + mask_len, + elements1_len); + + gcc::jit::recording::type *mask_element_type = mask_vector_type->get_element_type (); + + RETURN_NULL_IF_FAIL ( + mask_element_type->is_int (), + ctxt, loc, + "elements of mask must be of an integer type"); + + gcc::jit::recording::type *elements1_element_type = elements1_vector_type->get_element_type (); + size_t mask_element_size = mask_element_type->get_size (); + size_t elements1_element_size = elements1_element_type->get_size (); + + RETURN_NULL_IF_FAIL_PRINTF2 ( + mask_element_size == elements1_element_size, + ctxt, loc, + "mismatching size for mask element type:" + " elements1 element type: %ld mask element type: %ld", + mask_element_size, + elements1_element_size); + + return (gcc_jit_rvalue *)ctxt->new_rvalue_vector_perm(loc, elements1, elements2, mask); +} + /* A mutex around the cached state in parse_basever. Ideally this would be within parse_basever, but the mutex is only needed by libgccjit. */ diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index b3c389e93f6..f5537adbc91 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -604,7 +604,9 @@ enum gcc_jit_types GCC_JIT_TYPE_INT16_T, GCC_JIT_TYPE_INT32_T, GCC_JIT_TYPE_INT64_T, - GCC_JIT_TYPE_INT128_T + GCC_JIT_TYPE_INT128_T, + + GCC_JIT_TYPE_BFLOAT16, }; extern gcc_jit_type * @@ -652,7 +654,7 @@ extern gcc_jit_type * gcc_jit_context_new_array_type (gcc_jit_context *ctxt, gcc_jit_location *loc, gcc_jit_type *element_type, - int num_elements); + unsigned long num_elements); /* Struct-handling. */ @@ -1021,6 +1023,12 @@ extern gcc_jit_lvalue * gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global, gcc_jit_rvalue *init_value); +/* Create a reference to a machine-specific builtin function (sometimes called + intrinsic functions). */ +extern gcc_jit_function * +gcc_jit_context_get_target_builtin_function (gcc_jit_context *ctxt, + const char *name); + #define LIBGCCJIT_HAVE_gcc_jit_global_set_initializer /* Set an initial value for a global, which must be an array of @@ -1036,6 +1044,9 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global, const void *blob, size_t num_bytes); +extern void +gcc_jit_global_set_readonly (gcc_jit_lvalue *global); + /* Upcasting. */ extern gcc_jit_object * gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue); @@ -1292,6 +1303,18 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt, gcc_jit_rvalue *ptr, gcc_jit_rvalue *index); +extern gcc_jit_rvalue * +gcc_jit_context_convert_vector (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *vector, + gcc_jit_type *type); + +extern gcc_jit_lvalue * +gcc_jit_context_new_vector_access (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *vector, + gcc_jit_rvalue *index); + /* Field access is provided separately for both lvalues and rvalues. */ /* Accessing a field of an lvalue of struct type, analogous to: @@ -1391,6 +1414,38 @@ gcc_jit_block_add_eval (gcc_jit_block *block, gcc_jit_location *loc, gcc_jit_rvalue *rvalue); +/* Add a try/catch statement. + This is equivalent to this C++ code: + try { + try_block + } + catch (...) { + catch_block + } +*/ + +void +gcc_jit_block_add_try_catch (gcc_jit_block *block, + gcc_jit_location *loc, + gcc_jit_block *try_block, + gcc_jit_block *catch_block); + +/* Add a try/finally statement. + This is equivalent to this C++-like code: + try { + try_block + } + finally { + finally_block + } +*/ + +void +gcc_jit_block_add_try_finally (gcc_jit_block *block, + gcc_jit_location *loc, + gcc_jit_block *try_block, + gcc_jit_block *finally_block); + /* Add evaluation of an rvalue, assigning the result to the given lvalue. @@ -1788,6 +1843,12 @@ extern gcc_jit_rvalue * gcc_jit_function_get_address (gcc_jit_function *fn, gcc_jit_location *loc); +void +gcc_jit_function_set_personality_function (gcc_jit_function *fn, + gcc_jit_function *personality_func); + +extern void +gcc_jit_set_global_personality_function_name (char* name); #define LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector @@ -1806,6 +1867,21 @@ gcc_jit_context_new_rvalue_from_vector (gcc_jit_context *ctxt, size_t num_elements, gcc_jit_rvalue **elements); +/* Build a permutation vector rvalue from an 3 arrays of elements. + + "vec_type" should be a vector type, created using gcc_jit_type_get_vector. + + This API entrypoint was added in LIBGCCJIT_ABI_25; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_TARGET_BUILTIN +*/ +extern gcc_jit_rvalue * +gcc_jit_context_new_rvalue_vector_perm (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *elements1, + gcc_jit_rvalue *elements2, + gcc_jit_rvalue *mask); + #define LIBGCCJIT_HAVE_gcc_jit_version /* Functions to retrieve libgccjit version. @@ -1969,6 +2045,11 @@ gcc_jit_type_is_integral (gcc_jit_type *type); extern gcc_jit_type * gcc_jit_type_is_pointer (gcc_jit_type *type); +/* Return the type behind const type or NULL if it's not a + * const type. */ +extern gcc_jit_type * +gcc_jit_type_is_const (gcc_jit_type *type); + /* Given a type, return a dynamic cast to a vector type or NULL. */ extern gcc_jit_vector_type * gcc_jit_type_dyncast_vector (gcc_jit_type *type); @@ -1990,6 +2071,40 @@ gcc_jit_vector_type_get_element_type (gcc_jit_vector_type *vector_type); extern gcc_jit_type * gcc_jit_type_unqualified (gcc_jit_type *type); +/* Given type "T", get type "T __attribute__ ((packed))". */ +extern void +gcc_jit_type_set_packed (gcc_jit_type *type); + +/* Function attributes. */ +enum gcc_jit_fn_attribute +{ + GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE, + GCC_JIT_FN_ATTRIBUTE_INLINE, + GCC_JIT_FN_ATTRIBUTE_NOINLINE, + GCC_JIT_FN_ATTRIBUTE_TARGET, + GCC_JIT_FN_ATTRIBUTE_USED, + GCC_JIT_FN_ATTRIBUTE_VISIBILITY, +}; + +/* Add an attribute to a function. */ +// TODO: also support integer values. +extern void +gcc_jit_function_add_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute); + +extern void +gcc_jit_function_add_string_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute, const char* value); + +/* Variable attributes. */ +enum gcc_jit_variable_attribute +{ + GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY, +}; + +/* Add an attribute to a variable. */ +// TODO: also support integer values. +extern void +gcc_jit_lvalue_add_attribute (gcc_jit_lvalue *variable, enum gcc_jit_variable_attribute attribute, const char* value); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index cc22b2b414e..a10a85ceace 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -271,3 +271,49 @@ LIBGCCJIT_ABI_24 { gcc_jit_lvalue_set_alignment; gcc_jit_lvalue_get_alignment; } LIBGCCJIT_ABI_23; + +LIBGCCJIT_ABI_25 { + global: + gcc_jit_type_set_packed; +} LIBGCCJIT_ABI_24; + +LIBGCCJIT_ABI_26 { + global: + gcc_jit_type_is_const; +} LIBGCCJIT_ABI_25; + +LIBGCCJIT_ABI_27 { + global: + gcc_jit_context_convert_vector; +} LIBGCCJIT_ABI_26; + +LIBGCCJIT_ABI_28 { + global: + gcc_jit_global_set_readonly; +} LIBGCCJIT_ABI_27; + +LIBGCCJIT_ABI_29 { + global: + gcc_jit_function_add_attribute; + gcc_jit_function_add_string_attribute; +} LIBGCCJIT_ABI_28; + +LIBGCCJIT_ABI_30 { + global: + gcc_jit_lvalue_add_attribute; +} LIBGCCJIT_ABI_29; + +LIBGCCJIT_ABI_31 { + global: + gcc_jit_block_add_try_catch; + gcc_jit_block_add_try_finally; + gcc_jit_function_set_personality_function; +} LIBGCCJIT_ABI_30; + +LIBGCCJIT_ABI_32 { + global: + gcc_jit_context_get_target_builtin_function; + gcc_jit_context_new_rvalue_vector_perm; + gcc_jit_context_new_vector_access; + gcc_jit_set_global_personality_function_name; +} LIBGCCJIT_ABI_31; diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index 80606076e78..988e14ae9bc 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -319,6 +319,9 @@ /* test-setting-alignment.c: This can't be in the testcases array as it is target-specific. */ +/* test-target-builtins.c: This can't be in the testcases array as it + is target-specific. */ + /* test-string-literal.c */ #define create_code create_code_string_literal #define verify_code verify_code_string_literal diff --git a/gcc/testsuite/jit.dg/test-target-builtins.c b/gcc/testsuite/jit.dg/test-target-builtins.c new file mode 100644 index 00000000000..0ffb48e97f6 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-target-builtins.c @@ -0,0 +1,77 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +#include +#include + +#include "libgccjit.h" + +#define TEST_PROVIDES_MAIN +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + CHECK_NON_NULL (gcc_jit_context_get_target_builtin_function (ctxt, "__builtin_ia32_xgetbv")); + gcc_jit_function *builtin_eh_pointer = gcc_jit_context_get_target_builtin_function (ctxt, "__builtin_eh_pointer"); + CHECK_NON_NULL (builtin_eh_pointer); + + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *void_ptr = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR); + gcc_jit_function *func_main = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "main", + 0, NULL, + 0); + gcc_jit_rvalue *zero = gcc_jit_context_zero (ctxt, int_type); + gcc_jit_block *block = gcc_jit_function_new_block (func_main, NULL); + gcc_jit_lvalue *variable = gcc_jit_function_new_local(func_main, NULL, void_ptr, "variable"); + gcc_jit_block_add_assignment (block, NULL, variable, + gcc_jit_context_new_call (ctxt, NULL, builtin_eh_pointer, 1, &zero)); + gcc_jit_block_end_with_return (block, NULL, zero); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); +} + +int +main (int argc, char **argv) +{ + /* This is the same as the main provided by harness.h, but it first create a dummy context and compile + in order to add the target builtins to libgccjit's internal state. */ + gcc_jit_context *ctxt; + ctxt = gcc_jit_context_acquire (); + if (!ctxt) + { + fail ("gcc_jit_context_acquire failed"); + return -1; + } + gcc_jit_result *result; + result = gcc_jit_context_compile (ctxt); + gcc_jit_result_release (result); + gcc_jit_context_release (ctxt); + + int i; + + for (i = 1; i <= 5; i++) + { + snprintf (test, sizeof (test), + "%s iteration %d of %d", + extract_progname (argv[0]), + i, 5); + + //printf ("ITERATION %d\n", i); + test_jit (argv[0], NULL); + //printf ("\n"); + } + + totals (); + + return 0; +} diff --git a/gcc/toplev.cc b/gcc/toplev.cc index 42937f0ba00..4469e0f069d 100644 --- a/gcc/toplev.cc +++ b/gcc/toplev.cc @@ -2332,6 +2332,7 @@ toplev::finalize (void) cgraphunit_cc_finalize (); symtab_thunks_cc_finalize (); dwarf2out_cc_finalize (); + dwarf2asm_cc_finalize (); gcse_cc_finalize (); ipa_cp_cc_finalize (); ira_costs_cc_finalize (); diff --git a/gcc/tree.cc b/gcc/tree.cc index 78b64ee98b3..ea95e67bb79 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -15006,6 +15006,7 @@ void tree_cc_finalize (void) { clear_nonstandard_integer_type_cache (); + gcc_eh_personality_decl = NULL; } #if CHECKING_P diff --git a/gcc/tree.h b/gcc/tree.h index e730a2a3e56..99695c647fe 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -6479,6 +6479,7 @@ extern tree get_inner_reference (tree, poly_int64_pod *, poly_int64_pod *, tree *, machine_mode *, int *, int *, int *); extern tree build_personality_function (const char *); +extern tree build_personality_function_with_name (const char *); struct GTY(()) int_n_trees_t { /* These parts are initialized at runtime */