| /* ACLE support for Arm MVE |
| Copyright (C) 2021-2022 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it |
| under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GCC is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #define IN_TARGET_CODE 1 |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include "tree.h" |
| #include "fold-const.h" |
| #include "langhooks.h" |
| #include "stringpool.h" |
| #include "attribs.h" |
| #include "diagnostic.h" |
| #include "arm-protos.h" |
| #include "arm-builtins.h" |
| #include "arm-mve-builtins.h" |
| |
| namespace arm_mve { |
| |
| /* Static information about each single-predicate or single-vector |
| ACLE type. */ |
| struct vector_type_info |
| { |
| /* The name of the type as declared by arm_mve.h. */ |
| const char *acle_name; |
| |
| /* Whether the type requires a floating point abi. */ |
| const bool requires_float; |
| }; |
| |
| /* Flag indicating whether the arm MVE types have been handled. */ |
| static bool handle_arm_mve_types_p; |
| |
| /* Information about each single-predicate or single-vector type. */ |
| static CONSTEXPR const vector_type_info vector_types[] = { |
| #define DEF_MVE_TYPE(ACLE_NAME, SCALAR_TYPE) \ |
| { #ACLE_NAME, REQUIRES_FLOAT }, |
| #include "arm-mve-builtins.def" |
| #undef DEF_MVE_TYPE |
| }; |
| |
| /* The scalar type associated with each vector type. */ |
| GTY(()) tree scalar_types[NUM_VECTOR_TYPES]; |
| |
| /* The single-predicate and single-vector types, with their built-in |
| "__simd128_..._t" name. Allow an index of NUM_VECTOR_TYPES, which always |
| yields a null tree. */ |
| static GTY(()) tree abi_vector_types[NUM_VECTOR_TYPES + 1]; |
| |
| /* Same, but with the arm_mve.h names. */ |
| GTY(()) tree acle_vector_types[3][NUM_VECTOR_TYPES + 1]; |
| |
| /* Return the MVE abi type with element of type TYPE. */ |
| static tree |
| arm_mve_type_for_scalar_type (tree eltype) |
| { |
| for (unsigned int i = 0; i < __TYPE_FINAL; ++i) |
| if (arm_simd_types[i].eltype == eltype |
| && GET_MODE_SIZE (arm_simd_types[i].mode) == 16) |
| return arm_simd_types[i].itype; |
| |
| gcc_unreachable (); |
| } |
| |
| /* Register the built-in MVE ABI vector types, such as uint32x4_t. */ |
| static void |
| register_builtin_types () |
| { |
| #define DEF_MVE_TYPE(ACLE_NAME, SCALAR_TYPE) \ |
| scalar_types[VECTOR_TYPE_ ## ACLE_NAME] = SCALAR_TYPE; |
| #include "arm-mve-builtins.def" |
| #undef DEF_MVE_TYPE |
| for (unsigned int i = 0; i < NUM_VECTOR_TYPES; ++i) |
| { |
| if (vector_types[i].requires_float && !TARGET_HAVE_MVE_FLOAT) |
| continue; |
| tree eltype = scalar_types[i]; |
| tree vectype; |
| if (eltype == boolean_type_node) |
| { |
| vectype = get_typenode_from_name (UINT16_TYPE); |
| gcc_assert (GET_MODE_SIZE (TYPE_MODE (vectype)) == 2); |
| } |
| else |
| { |
| vectype = arm_mve_type_for_scalar_type (eltype); |
| gcc_assert (VECTOR_MODE_P (TYPE_MODE (vectype)) |
| && GET_MODE_SIZE (TYPE_MODE (vectype)) == 16); |
| } |
| abi_vector_types[i] = vectype; |
| } |
| } |
| |
| /* Register vector type TYPE under its arm_mve.h name. */ |
| static void |
| register_vector_type (vector_type_index type) |
| { |
| if (vector_types[type].requires_float && !TARGET_HAVE_MVE_FLOAT) |
| return; |
| tree vectype = abi_vector_types[type]; |
| tree id = get_identifier (vector_types[type].acle_name); |
| tree decl = build_decl (input_location, TYPE_DECL, id, vectype); |
| decl = lang_hooks.decls.pushdecl (decl); |
| |
| /* Record the new ACLE type if pushdecl succeeded without error. Use |
| the ABI type otherwise, so that the type we record at least has the |
| right form, even if it doesn't have the right name. This should give |
| better error recovery behavior than installing error_mark_node or |
| installing an incorrect type. */ |
| if (decl |
| && TREE_CODE (decl) == TYPE_DECL |
| && TREE_TYPE (decl) != error_mark_node |
| && TYPE_MAIN_VARIANT (TREE_TYPE (decl)) == vectype) |
| vectype = TREE_TYPE (decl); |
| acle_vector_types[0][type] = vectype; |
| } |
| |
| /* Register tuple type TYPE with NUM_VECTORS arity under its |
| arm_mve_types.h name. */ |
| static void |
| register_builtin_tuple_types (vector_type_index type) |
| { |
| const vector_type_info* info = &vector_types[type]; |
| if (scalar_types[type] == boolean_type_node |
| || (info->requires_float && !TARGET_HAVE_MVE_FLOAT)) |
| return; |
| const char *vector_type_name = info->acle_name; |
| char buffer[sizeof ("float32x4x2_t")]; |
| for (unsigned int num_vectors = 2; num_vectors <= 4; num_vectors += 2) |
| { |
| snprintf (buffer, sizeof (buffer), "%.*sx%d_t", |
| (int) strlen (vector_type_name) - 2, vector_type_name, |
| num_vectors); |
| |
| tree vectype = acle_vector_types[0][type]; |
| tree arrtype = build_array_type_nelts (vectype, num_vectors); |
| gcc_assert (TYPE_MODE_RAW (arrtype) == TYPE_MODE (arrtype)); |
| tree field = build_decl (input_location, FIELD_DECL, |
| get_identifier ("val"), arrtype); |
| |
| tree t = lang_hooks.types.simulate_record_decl (input_location, buffer, |
| make_array_slice (&field, |
| 1)); |
| gcc_assert (TYPE_MODE_RAW (t) == TYPE_MODE (t)); |
| acle_vector_types[num_vectors >> 1][type] = TREE_TYPE (t); |
| } |
| } |
| |
| /* Implement #pragma GCC arm "arm_mve_types.h". */ |
| void |
| handle_arm_mve_types_h () |
| { |
| if (handle_arm_mve_types_p) |
| { |
| error ("duplicate definition of %qs", "arm_mve_types.h"); |
| return; |
| } |
| handle_arm_mve_types_p = true; |
| if (!TARGET_HAVE_MVE) |
| { |
| error ("this definition requires the MVE ISA extension"); |
| return; |
| } |
| register_builtin_types (); |
| for (unsigned int type_i = 0; type_i < NUM_VECTOR_TYPES; ++type_i) |
| { |
| vector_type_index type = vector_type_index (type_i); |
| register_vector_type (type); |
| if (type_i != VECTOR_TYPE_mve_pred16_t) |
| register_builtin_tuple_types (type); |
| } |
| } |
| |
| } /* end namespace arm_mve */ |
| |
| using namespace arm_mve; |
| |
| #include "gt-arm-mve-builtins.h" |