From 4d715c53b340c428b39f814cda184289ea12886e Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 2 Feb 2022 21:48:41 -0500 Subject: [PATCH] Add support for machine-dependent builtins --- gcc/config/i386/i386-builtins.cc | 18 ++ gcc/jit/dummy-frontend.cc | 214 ++++++++++++++++++++++++ gcc/jit/jit-builtins.cc | 6 +- gcc/jit/jit-playback.cc | 200 ++++++++++++++++++++++- gcc/jit/jit-playback.h | 19 ++- gcc/jit/jit-recording.cc | 272 +++++++++++++++++++++++++++++-- gcc/jit/jit-recording.h | 192 +++++++++++++++++++++- gcc/jit/libgccjit.cc | 106 +++++++++++- gcc/jit/libgccjit.h | 37 +++++ gcc/jit/libgccjit.map | 8 + 10 files changed, 1038 insertions(+), 34 deletions(-) diff --git a/gcc/config/i386/i386-builtins.cc b/gcc/config/i386/i386-builtins.cc index 2570501ae7e6d..9761d9bbb1c82 100644 --- a/gcc/config/i386/i386-builtins.cc +++ b/gcc/config/i386/i386-builtins.cc @@ -224,6 +224,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]; @@ -1407,6 +1423,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/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index 42ab93bde69bd..b2549d48303b0 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 "print-tree.h" +#include "jit-recording.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[] = { @@ -608,6 +619,9 @@ jit_langhook_init (void) eventually be controllable by a command line option. */ mpfr_set_default_prec (256); + target_builtins.empty (); + targetm.init_builtins (); + return true; } @@ -675,11 +689,211 @@ jit_langhook_type_for_mode (machine_mode mode, int unsignedp) return NULL; } +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 == 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) + { + 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 just ignore builtin functions. */ 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; } diff --git a/gcc/jit/jit-builtins.cc b/gcc/jit/jit-builtins.cc index b949b73433243..1abde8e1dc8e8 100644 --- a/gcc/jit/jit-builtins.cc +++ b/gcc/jit/jit-builtins.cc @@ -217,7 +217,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, @@ -584,7 +585,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; diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 87b66e9725d2a..90bb163413461 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -507,7 +507,8 @@ 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, + int is_target_builtin) { int i; param *param; @@ -541,6 +542,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); @@ -999,16 +1008,43 @@ new_string_literal (const char *value) playback::rvalue * playback::context::new_rvalue_from_vector (location *, type *type, - const auto_vec &elements) + const auto_vec &elements, + bool constructor) { vec *v; 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; + if (constructor) + { + // TODO: document why this is needed. + t_ctor = build_vector_from_ctor (type->as_tree (), v); + } + else + 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 @@ -1250,10 +1286,24 @@ new_comparison (location *loc, tree node_b = b->as_tree (); node_b = fold_const_var (node_b); - tree inner_expr = build2 (inner_op, - boolean_type_node, - node_a, - node_b); + tree inner_expr; + tree a_type = TREE_TYPE (node_a); + if (VECTOR_TYPE_P (a_type)) + { + // TODO: document where this comes from and what it is doing. + tree zero_vec = build_zero_cst (a_type); + tree minus_one_vec = build_minus_one_cst (a_type); + tree cmp_type = truth_type_for (a_type); + tree cmp = build2 (inner_op, cmp_type, node_a, node_b); + inner_expr = build3 (VEC_COND_EXPR, a_type, cmp, minus_one_vec, zero_vec); + } + else + { + inner_expr = build2 (inner_op, + boolean_type_node, + node_a, + node_b); + } /* Try to fold. */ inner_expr = fold (inner_expr); @@ -1491,6 +1541,142 @@ new_array_access (location *loc, } } +// TODO: document where this comes from and remove the c_ prefix in the function names. +/* Like c_mark_addressable but don't check register qualifier. */ +void +c_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. + c_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-common.cc: c_build_shufflevector + */ + // TODO: use the commented code when the index is constant. + /*tree t_vector = vector->as_tree (); + tree t_type_vector = TREE_TYPE (t_vector); + t_vector = fold_const_var (t_vector); + tree t_index = index->as_tree (); + t_index = fold_const_var (t_index); + tree size = TYPE_SIZE (t_type_vector); + tree t_result = build3 (BIT_FIELD_REF, + t_type_vector, t_vector, size, bitsize_zero_node); // FIXME: it should be index * size instead of zero. + */ + + 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 (loc) + set_tree_location (t_result, loc); + return new lvalue (this, t_result); +} + /* Construct a tree for a field access. */ tree diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 06852f80df8a2..5ee7ee99c0e15 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -104,7 +104,8 @@ class context : public log_user const char *name, const auto_vec *params, int is_variadic, - enum built_in_function builtin_id); + enum built_in_function builtin_id, + int is_target_builtin); lvalue * new_global (location *loc, @@ -145,7 +146,14 @@ class context : public log_user rvalue * new_rvalue_from_vector (location *loc, type *type, - const auto_vec &elements); + const auto_vec &elements, + bool constructor); + + rvalue * + new_rvalue_vector_perm (location *loc, + rvalue* elements1, + rvalue* elements2, + rvalue* mask); rvalue * new_unary_op (location *loc, @@ -191,6 +199,11 @@ class context : public log_user rvalue *ptr, rvalue *index); + lvalue * + new_vector_access (location *loc, + rvalue *vector, + rvalue *index); + void set_str_option (enum gcc_jit_str_option opt, const char *value); @@ -812,4 +825,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 85d846c316bdc..31e486d19eaeb 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -936,14 +936,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; } @@ -965,7 +967,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 (); @@ -1008,7 +1011,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); @@ -1047,6 +1050,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; // FIXME: might require adding a suffix. See get_asm_name in jit-builtins. + 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. @@ -1106,7 +1155,19 @@ recording::context::new_rvalue_from_vector (location *loc, rvalue **elements) { recording::rvalue *result - = new memento_of_new_rvalue_from_vector (this, loc, type, elements); + = new memento_of_new_rvalue_from_vector (this, loc, type, elements, false); + record (result); + 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; } @@ -1177,6 +1238,17 @@ recording::context::new_ctor (recording::location *loc, return result; } +recording::rvalue * +recording::context::new_vector_constructor (location *loc, + vector_type *type, + rvalue **values) +{ + recording::rvalue *result + = new memento_of_new_rvalue_from_vector (this, loc, type, values, true); + record (result); + return result; +} + /* Create a recording::unary_op instance and add it to this context's list of mementos. @@ -1312,6 +1384,22 @@ recording::context::new_array_access (recording::location *loc, 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. @@ -3102,11 +3190,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]); @@ -4048,7 +4138,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), @@ -4059,7 +4150,8 @@ 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_is_target_builtin (is_target_builtin) { for (int i = 0; i< num_params; i++) { @@ -4118,7 +4210,8 @@ recording::function::replay_into (replayer *r) m_name->c_str (), ¶ms, m_is_variadic, - m_builtin_id)); + m_builtin_id, + m_is_target_builtin)); } /* Create a recording::local instance and add it to @@ -4351,7 +4444,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); @@ -5314,10 +5408,12 @@ recording::memento_of_new_rvalue_from_vector:: memento_of_new_rvalue_from_vector (context *ctxt, location *loc, vector_type *type, - rvalue **elements) + rvalue **elements, + bool constructor) : rvalue (ctxt, loc, type), m_vector_type (type), - m_elements () + m_elements (), + m_constructor (constructor) { for (unsigned i = 0; i < type->get_num_units (); i++) m_elements.safe_push (elements[i]); @@ -5336,7 +5432,8 @@ recording::memento_of_new_rvalue_from_vector::replay_into (replayer *r) set_playback_obj (r->new_rvalue_from_vector (playback_location (r, m_loc), m_type->playback_type (), - playback_elements)); + playback_elements, + m_constructor)); } /* Implementation of pure virtual hook recording::rvalue::visit_children @@ -5377,16 +5474,20 @@ recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r) r.write (" gcc_jit_rvalue *%s[%i] = {\n", elements_id, m_elements.length ()); + const char *func_name = "gcc_jit_context_new_rvalue_from_vector"; + if (m_constructor) + func_name = "gcc_jit_context_new_vector_constructor"; for (unsigned i = 0; i< m_elements.length (); i++) r.write (" %s,\n", r.get_identifier_as_rvalue (m_elements[i])); r.write (" };\n"); r.write (" gcc_jit_rvalue *%s =\n" - " gcc_jit_context_new_rvalue_from_vector (%s, /* gcc_jit_context *ctxt */\n" + " %s (%s, /* gcc_jit_context *ctxt */\n" " %s, /* gcc_jit_location *loc */\n" " %s, /* gcc_jit_type *vec_type */\n" " %i, /* size_t num_elements */ \n" " %s); /* gcc_jit_rvalue **elements*/\n", id, + func_name, r.get_identifier (get_context ()), r.get_identifier (m_loc), r.get_identifier (m_vector_type), @@ -5394,6 +5495,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) { @@ -6263,6 +6449,62 @@ recording::array_access::write_reproducer (reproducer &r) r.get_identifier_as_rvalue (m_index)); } +/* 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::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 diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index f0c5a1bf32eff..a1ac398ce640e 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -24,12 +24,16 @@ along with GCC; see the file COPYING3. If not see #include "jit-common.h" #include "jit-logging.h" +#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[]; @@ -116,7 +120,8 @@ class context : public log_user 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 +148,9 @@ class context : public log_user 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, @@ -156,6 +164,11 @@ class context : public log_user field **fields, rvalue **values); + rvalue * + new_vector_constructor (location *loc, + vector_type *type, + rvalue **values); + void new_global_init_rvalue (lvalue *variable, rvalue *init); @@ -173,6 +186,12 @@ class context : public log_user 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 +234,11 @@ class context : public log_user rvalue *ptr, rvalue *index); + lvalue * + new_vector_access (location *loc, + rvalue *vector, + rvalue *index); + case_ * new_case (rvalue *min_value, rvalue *max_value, @@ -533,6 +557,8 @@ class type : public memento 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; } @@ -607,6 +633,11 @@ class memento_of_get_type : public type size_t get_size () FINAL OVERRIDE; + virtual type* copy(context* ctxt) + { + return ctxt->get_type (m_kind); + } + bool accepts_writes_from (type *rtype) FINAL OVERRIDE { if (m_kind == GCC_JIT_TYPE_VOID_PTR) @@ -654,6 +685,13 @@ class memento_of_get_pointer : public type : type (other_type->m_ctxt), m_other_type (other_type) {} + virtual type* copy(context* ctxt) + { + type* result = new memento_of_get_pointer (m_other_type->copy (ctxt)); + ctxt->record (result); + return result; + } + type *dereference () FINAL OVERRIDE { return m_other_type; } size_t get_size () FINAL OVERRIDE; @@ -716,6 +754,13 @@ class memento_of_get_const : public decorated_type return false; } + virtual type* copy(context* ctxt) + { + 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. */ type *unqualified () FINAL OVERRIDE { return m_other_type; } @@ -749,6 +794,13 @@ class memento_of_get_volatile : public decorated_type return m_other_type->is_same_type_as (other->is_volatile ()); } + virtual type* copy(context* ctxt) + { + 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; } @@ -769,11 +821,21 @@ class memento_of_get_aligned : public decorated_type : decorated_type (other_type), m_alignment_in_bytes (alignment_in_bytes) {} + virtual type* copy(context* ctxt) + { + 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; + // FIXME: does not seem to work. + 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; @@ -790,6 +852,13 @@ class vector_type : public decorated_type : decorated_type (other_type), m_num_units (num_units) {} + virtual type* copy(context* ctxt) + { + 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; } @@ -821,6 +890,13 @@ class array_type : public type m_num_elements (num_elements) {} + virtual type* copy(context* ctxt) + { + type* result = new array_type (ctxt, m_loc, m_element_type->copy (ctxt), m_num_elements); + ctxt->record (result); + return result; + } + type *dereference () FINAL OVERRIDE; bool is_int () const FINAL OVERRIDE { return false; } @@ -850,12 +926,25 @@ class function_type : public type 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; } function_type *as_a_function_type () FINAL OVERRIDE { return this; } + virtual type* copy(context* ctxt) + { + 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_same_type_as (type *other) FINAL OVERRIDE; bool is_int () const FINAL OVERRIDE { return false; } @@ -870,6 +959,7 @@ class function_type : public type 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 (); @@ -886,6 +976,7 @@ class function_type : public type type *m_return_type; auto_vec m_param_types; int m_is_variadic; + int m_is_target_builtin; }; class field : public memento @@ -987,9 +1078,11 @@ class compound_type : public type return static_cast (m_playback_obj); } -private: +protected: location *m_loc; string *m_name; + +private: fields *m_fields; }; @@ -1002,6 +1095,13 @@ class struct_ : public compound_type struct_ *dyn_cast_struct () FINAL OVERRIDE { return this; } + virtual type* copy(context* ctxt) + { + type* result = new struct_ (ctxt, m_loc, m_name); + ctxt->record (result); + return result; + } + type * as_type () { return this; } @@ -1047,6 +1147,13 @@ class union_ : public compound_type location *loc, string *name); + virtual type* copy(context* ctxt) + { + type* result = new union_ (ctxt, m_loc, m_name); + ctxt->record (result); + return result; + } + void replay_into (replayer *r) FINAL OVERRIDE; virtual bool is_union () const FINAL OVERRIDE { return true; } @@ -1146,6 +1253,7 @@ class rvalue : public memento const char * get_debug_string_parens (enum precedence outer_prec); + virtual bool is_ctor () const { return false; } virtual bool is_constant () const { return false; } virtual bool get_wide_int (wide_int *) const { return false; } @@ -1257,7 +1365,8 @@ class function : public memento 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; @@ -1289,6 +1398,8 @@ class function : public memento bool is_variadic () const { return m_is_variadic; } + bool is_target_builtin () const { return m_is_target_builtin; } + void write_to_dump (dump &d) FINAL OVERRIDE; void validate (); @@ -1312,6 +1423,7 @@ class function : public memento auto_vec m_locals; auto_vec m_blocks; type *m_fn_ptr_type; + int m_is_target_builtin; }; class block : public memento @@ -1561,7 +1673,8 @@ class memento_of_new_rvalue_from_vector : public rvalue memento_of_new_rvalue_from_vector (context *ctxt, location *loc, vector_type *type, - rvalue **elements); + rvalue **elements, + bool constructor); void replay_into (replayer *r) FINAL OVERRIDE; @@ -1578,6 +1691,34 @@ class memento_of_new_rvalue_from_vector : public rvalue private: vector_type *m_vector_type; auto_vec m_elements; + bool m_constructor; +}; + +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 @@ -1593,6 +1734,8 @@ class ctor : public rvalue void visit_children (rvalue_visitor *) FINAL OVERRIDE; + virtual bool is_ctor () const { return true; } + private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; @@ -1675,7 +1818,13 @@ class comparison : public rvalue m_op (op), m_a (a), m_b (b) - {} + { + type *a_type = a->get_type (); + if (a_type->dyn_cast_vector_type () != NULL) + { + m_type = a_type; + } + } void replay_into (replayer *r) FINAL OVERRIDE; @@ -1846,6 +1995,35 @@ class array_access : public lvalue rvalue *m_index; }; +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: diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 2a1e4ff57183a..5c14dfeb2da0d 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -1731,6 +1731,50 @@ gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt, reinterpret_cast(values)); } +// TODO: do we need this since we have gcc_jit_context_new_rvalue_from_vector? +gcc_jit_rvalue * +gcc_jit_context_new_vector_constructor (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_type *type, + size_t num_values, + gcc_jit_rvalue **values) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type"); + + /* "vec_type" must be a vector type. */ + gcc::jit::recording::vector_type *as_vec_type + = type->dyn_cast_vector_type (); + RETURN_NULL_IF_FAIL_PRINTF1 (as_vec_type, ctxt, loc, + "%s is not a vector type", + type->get_debug_string ()); + + // TODO: check that the values are constant. + + return (gcc_jit_rvalue *)ctxt->new_vector_constructor ( + loc, + as_vec_type, + 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 * @@ -2331,7 +2375,7 @@ gcc_jit_context_new_call_through_ptr (gcc_jit_context *ctxt, RETURN_NULL_IF_FAIL_PRINTF6 ( gcc_jit_compatible_types ((gcc_jit_type*) param_type, - (gcc_jit_type*) arg->get_type ()), + (gcc_jit_type*) arg->get_type ()), ctxt, loc, "mismatching types for argument %d of fn_ptr: %s:" " assignment to param %d (type: %s) from %s (type: %s)", @@ -2407,6 +2451,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, @@ -2479,6 +2525,39 @@ 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_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 (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 (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 @@ -4043,6 +4122,31 @@ 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. */ + + // TODO: check that the type of elements1 and elements2 is the same. + // TODO: check that the lenth of mask is the same as the input vectors. + // TODO: check that mask is a **constant** vector. + + 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 c21787337e75e..424d497cb55e9 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -991,6 +991,16 @@ gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt, size_t num_values, gcc_jit_rvalue **values); +/* Create a constructor for a vector as an rvalue. +*/ + +extern gcc_jit_rvalue * +gcc_jit_context_new_vector_constructor (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_type *type, + size_t num_values, + gcc_jit_rvalue **values); + /* Set the initial value of a global of any type with an rvalue. The rvalue needs to be a constant expression, e.g. no function calls. @@ -1013,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 @@ -1265,6 +1281,12 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt, gcc_jit_rvalue *ptr, gcc_jit_rvalue *index); +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: @@ -1798,6 +1820,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. diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 43e41a2bd4a20..e7a0e36118812 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -270,3 +270,11 @@ LIBGCCJIT_ABI_24 { gcc_jit_lvalue_set_alignment; gcc_jit_lvalue_get_alignment; } LIBGCCJIT_ABI_23; + +LIBGCCJIT_ABI_25 { + global: + gcc_jit_context_get_target_builtin_function; + gcc_jit_context_new_rvalue_vector_perm; + gcc_jit_context_new_vector_constructor; + gcc_jit_context_new_vector_access; +} LIBGCCJIT_ABI_24;