blob: 8fe6f70f7b0fed658537ec40b6ee775247074878 [file] [log] [blame]
/* 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"