@@ -448,7 +448,7 @@ const struct attribute_spec c_common_attribute_table[] =
handle_omp_declare_variant_attribute, NULL },
{ "omp declare variant variant", 0, -1, true, false, false, false,
handle_omp_declare_variant_attribute, NULL },
- { "simd", 0, 1, true, false, false, false,
+ { "simd", 0, 4, true, false, false, false,
handle_simd_attribute, NULL },
{ "omp declare target", 0, -1, true, false, false, false,
handle_omp_declare_target_attribute, NULL },
@@ -3094,13 +3094,22 @@ handle_simd_attribute (tree *node, tree name, tree args, int, bool *no_add_attrs
{
tree t = get_identifier ("omp declare simd");
tree attr = NULL_TREE;
+
+ /* Allow
+ simd
+ simd (mask)
+ simd (mask, simdlen)
+ simd (mask, simdlen, simdabi)
+ simd (mask, simdlen, simdabi, name)
+ forms. */
+
if (args)
{
tree id = TREE_VALUE (args);
if (TREE_CODE (id) != STRING_CST)
{
- error ("attribute %qE argument not a string", name);
+ error ("attribute %qE first argument not a string", name);
*no_add_attrs = true;
return NULL_TREE;
}
@@ -3113,13 +3122,75 @@ handle_simd_attribute (tree *node, tree name, tree args, int, bool *no_add_attrs
OMP_CLAUSE_INBRANCH);
else
{
- error ("only %<inbranch%> and %<notinbranch%> flags are "
- "allowed for %<__simd__%> attribute");
+ error ("%qE attribute first argument must be %<inbranch%> or "
+ "%<notinbranch%>", name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ args = TREE_CHAIN (args);
+ }
+
+ if (args)
+ {
+ tree arg = TREE_VALUE (args);
+
+ arg = c_fully_fold (arg, false, NULL);
+ if (TREE_CODE (arg) != INTEGER_CST
+ || !INTEGRAL_TYPE_P (TREE_TYPE (arg))
+ || tree_int_cst_sgn (arg) < 0)
+ {
+ error ("%qE attribute second argument must be a non-negative "
+ "integer constant", name);
*no_add_attrs = true;
return NULL_TREE;
}
+ tree c = build_omp_clause (DECL_SOURCE_LOCATION (*node),
+ OMP_CLAUSE_SIMDLEN);
+ OMP_CLAUSE_SIMDLEN_EXPR (c) = arg;
+ OMP_CLAUSE_CHAIN (c) = attr;
+ attr = c;
+ args = TREE_CHAIN (args);
}
+ if (args)
+ {
+ tree arg = TREE_VALUE (args);
+
+ if (TREE_CODE (arg) != STRING_CST)
+ {
+ error ("%qE attribute third argument not a string", name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ tree c = build_omp_clause (DECL_SOURCE_LOCATION (*node),
+ OMP_CLAUSE__SIMDABI_);
+ OMP_CLAUSE__SIMDABI__EXPR (c) = arg;
+ OMP_CLAUSE_CHAIN (c) = attr;
+ attr = c;
+ args = TREE_CHAIN (args);
+ }
+
+ if (args)
+ {
+ tree arg = TREE_VALUE (args);
+
+ if (TREE_CODE (arg) != STRING_CST)
+ {
+ error ("%qE attribute fourth argument not a string", name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ tree c = build_omp_clause (DECL_SOURCE_LOCATION (*node),
+ OMP_CLAUSE__SIMDNAME_);
+ OMP_CLAUSE__SIMDNAME__EXPR (c) = arg;
+ OMP_CLAUSE_CHAIN (c) = attr;
+ attr = c;
+ args = TREE_CHAIN (args);
+ }
+
+ gcc_assert (args == NULL);
+
DECL_ATTRIBUTES (*node)
= tree_cons (t, build_tree_list (NULL_TREE, attr),
DECL_ATTRIBUTES (*node));
@@ -805,6 +805,9 @@ struct GTY(()) cgraph_simd_clone_arg {
/* Specific data for a SIMD function clone. */
struct GTY(()) cgraph_simd_clone {
+ /* Symbol associated with this clone or NULL if vector ABI name is used. */
+ const char *simdname;
+
/* Number of words in the SIMD lane associated with this clone. */
unsigned int simdlen;
@@ -21283,7 +21283,15 @@ aarch64_simd_clone_compute_vecsize_and_simdlen (struct cgraph_node *node,
}
}
- clonei->vecsize_mangle = 'n';
+ if (clonei->vecsize_mangle == '\0')
+ clonei->vecsize_mangle = 'n';
+ else if (clonei->vecsize_mangle != 'n')
+ {
+ /* SIMD ABI is explicitly set. */
+ warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
+ "unsupported simd abi %c", clonei->vecsize_mangle);
+ return 0;
+ }
clonei->mask_mode = VOIDmode;
elt_bits = GET_MODE_BITSIZE (SCALAR_TYPE_MODE (base_type));
if (clonei->simdlen == 0)
@@ -21841,7 +21841,18 @@ ix86_simd_clone_compute_vecsize_and_simdlen (struct cgraph_node *node,
}
}
- if (!TREE_PUBLIC (node->decl))
+ if (clonei->vecsize_mangle != '\0')
+ {
+ /* SIMD ABI is explicitly set. */
+ if (strchr ("bcde", clonei->vecsize_mangle) == NULL)
+ {
+ warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
+ "unsupported simd abi %c", clonei->vecsize_mangle);
+ return 0;
+ }
+ ret = 1;
+ }
+ else if (!TREE_PUBLIC (node->decl))
{
/* If the function isn't exported, we can pick up just one ISA
for the clones. */
@@ -3572,6 +3572,9 @@ The warnings for missing or incorrect sentinels are enabled with
@item simd
@itemx simd("@var{mask}")
+@itemx simd("@var{mask}", @var{simdlen})
+@itemx simd("@var{mask}", @var{simdlen}, "@var{simdabi}")
+@itemx simd("@var{mask}", @var{simdlen}, "@var{simdabi}", "@var{name}")
@cindex @code{simd} function attribute
This attribute enables creation of one or more function versions that
can process multiple arguments using SIMD instructions from a
@@ -3587,9 +3590,26 @@ The optional argument @var{mask} may have the value
and instructs the compiler to generate non-masked or masked
clones correspondingly. By default, all clones are generated.
-If the attribute is specified and @code{#pragma omp declare simd} is
-present on a declaration and the @option{-fopenmp} or @option{-fopenmp-simd}
-switch is specified, then the attribute is ignored.
+The optional argument @var{simdlen} is a non-negative integer
+constant specifying the number of elements processed by one call.
+By default, or when it is 0, clones are generated for the
+@var{simdlen} variants the Vector ABI specifies.
+
+The optional argument @var{simdabi} is a string specifying the
+target-dependent call ABI or SIMD ISA variant (in case there are
+multiple supported variants), the valid strings follow the rules
+of the Vector ABI document of the target. By default, all clones
+are generated.
+
+The optional argument @var{name} is a string specifying the symbol
+for the SIMD function variant, this is only valid if a single clone
+is created. By default the symbol name is determined by the name
+mangling rules of the Vector ABI document.
+
+If on a function declaration multiple simd attributes are present
+or @code{#pragma omp declare simd} directives are present and the
+@option{-fopenmp} or @option{-fopenmp-simd} switch is specified
+then the union of all function variants they describe are created.
@item stack_protect
@cindex @code{stack_protect} function attribute
@@ -1508,6 +1508,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
install_var_local (decl, ctx);
break;
+ case OMP_CLAUSE__SIMDABI_:
+ case OMP_CLAUSE__SIMDNAME_:
case OMP_CLAUSE__CACHE_:
default:
gcc_unreachable ();
@@ -1688,6 +1690,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
case OMP_CLAUSE__CONDTEMP_:
break;
+ case OMP_CLAUSE__SIMDABI_:
+ case OMP_CLAUSE__SIMDNAME_:
case OMP_CLAUSE__CACHE_:
default:
gcc_unreachable ();
@@ -153,6 +153,24 @@ simd_clone_clauses_extract (struct cgraph_node *node, tree clauses,
clone_info->simdlen
= TREE_INT_CST_LOW (OMP_CLAUSE_SIMDLEN_EXPR (t));
break;
+ case OMP_CLAUSE__SIMDABI_:
+ {
+ const char *simdabi
+ = TREE_STRING_POINTER (OMP_CLAUSE__SIMDABI__EXPR (t));
+ /* Single char simdabi is the ISA of the vector ABI. */
+ if (simdabi[0] && simdabi[1])
+ {
+ warning_at (OMP_CLAUSE_LOCATION (t), 0,
+ "ignoring unsupported simd abi %qs", simdabi);
+ return NULL;
+ }
+ clone_info->vecsize_mangle = simdabi[0];
+ break;
+ }
+ case OMP_CLAUSE__SIMDNAME_:
+ clone_info->simdname
+ = TREE_STRING_POINTER (OMP_CLAUSE__SIMDNAME__EXPR (t));
+ break;
case OMP_CLAUSE_LINEAR:
{
tree decl = OMP_CLAUSE_DECL (t);
@@ -341,9 +359,15 @@ simd_clone_mangle (struct cgraph_node *node,
unsigned int simdlen = clone_info->simdlen;
unsigned int n;
pretty_printer pp;
+ const char *str;
gcc_assert (vecsize_mangle && simdlen);
+ /* Use the specified name when given instead of mangling. */
+ str = clone_info->simdname;
+ if (str != NULL)
+ goto skip_mangle;
+
pp_string (&pp, "_ZGV");
pp_character (&pp, vecsize_mangle);
pp_character (&pp, mask);
@@ -408,12 +432,13 @@ simd_clone_mangle (struct cgraph_node *node,
}
pp_underscore (&pp);
- const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl));
+ str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl));
if (*str == '*')
++str;
pp_string (&pp, str);
str = pp_formatted_text (&pp);
+skip_mangle:
/* If there already is a SIMD clone with the same mangled name, don't
add another one. This can happen e.g. for
#pragma omp declare simd
@@ -1,7 +1,7 @@
/* { dg-do compile } */
__attribute__((__simd__("bug")))
-int simd_attr (void) { return 0; } /* { dg-error "only 'inbranch' and 'notinbranch'" } */
+int simd_attr (void) { return 0; } /* { dg-error "first argument must be 'inbranch' or 'notinbranch'" } */
__attribute__((__simd__("notinbranch", "inbranch")))
-int simd_attr2 (void) { return 0; } /* { dg-error "wrong number of arguments specified" } */
+int simd_attr2 (void) { return 0; } /* { dg-error "second argument must be a non-negative integer constant" } */
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+__attribute__ ((simd ("inbranch", -1)))
+void f1 (void) { } /* { dg-error "second argument must be a non-negative integer constant" } */
+
+__attribute__ ((simd ("inbranch", 4, 0)))
+void f2 (void) { } /* { dg-error "third argument not a string" } */
+
+__attribute__ ((simd ("inbranch", 4, "", 0)))
+void f3 (void) { } /* { dg-error "fourth argument not a string" } */
+
+__attribute__ ((simd ("inbranch", 4, "", "foo", "bar")))
+void f4 (void) { } /* { dg-error "wrong number of arguments specified" } */
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+
+__attribute__ ((simd ("inbranch", 1)))
+void f1 (void) { } /* { dg-warning "unsupported simdlen 1" } */
+
+__attribute__ ((simd ("inbranch", 4, "foobar")))
+void f2 (void) { } /* { dg-warning "ignoring unsupported simd abi" } */
new file mode 100644
@@ -0,0 +1,42 @@
+/* { dg-do compile { target aarch64*-*-* i?86-*-* x86_64-*-* } } */
+
+#if __i386__ || __x86_64__
+# define SIMDABI "b"
+#elif __aarch64__
+# define SIMDABI "n"
+#else
+# error unsupported
+#endif
+
+#ifdef __cplusplus
+# define EXTERNC extern "C"
+#else
+# define EXTERNC
+#endif
+
+EXTERNC
+__attribute__ ((simd ("notinbranch", 4)))
+float foo1 (void) { return 0; }
+
+EXTERNC
+__attribute__ ((simd ("notinbranch", 4, SIMDABI)))
+float foo2 (void) { return 0; }
+
+EXTERNC
+__attribute__ ((simd ("notinbranch", 4, SIMDABI)))
+__attribute__ ((simd ("inbranch", 4, SIMDABI)))
+float foo3 (void) { return 0; }
+
+EXTERNC
+__attribute__ ((simd ("notinbranch", 4, SIMDABI, "vec_foo4_N")))
+__attribute__ ((simd ("inbranch", 4, SIMDABI, "vec_foo4_M")))
+float foo4 (void) { return 0; }
+
+/* { dg-final { scan-assembler "_ZGV.N4_foo1:" } } */
+/* { dg-final { scan-assembler-times "_ZGV.N4_foo2:" 1 } } */
+/* { dg-final { scan-assembler-times "_ZGV.N4_foo3:" 1 } } */
+/* { dg-final { scan-assembler-times "_ZGV.M4_foo3:" 1 } } */
+/* { dg-final { scan-assembler-not "_ZGV.N4_foo4:" } } */
+/* { dg-final { scan-assembler-not "_ZGV.M4_foo4:" } } */
+/* { dg-final { scan-assembler "vec_foo4_N:" } } */
+/* { dg-final { scan-assembler "vec_foo4_M:" } } */
@@ -415,6 +415,12 @@ enum omp_clause_code {
/* OpenMP clause: simdlen (constant-integer-expression). */
OMP_CLAUSE_SIMDLEN,
+ /* extension: SIMD call ABI. */
+ OMP_CLAUSE__SIMDABI_,
+
+ /* extension: SIMD symbol name. */
+ OMP_CLAUSE__SIMDNAME_,
+
/* OpenMP clause: device_type ({host,nohost,any}). */
OMP_CLAUSE_DEVICE_TYPE,
@@ -1372,6 +1372,8 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
case OMP_CLAUSE_UNIFORM:
case OMP_CLAUSE_INBRANCH:
case OMP_CLAUSE_NOTINBRANCH:
+ case OMP_CLAUSE__SIMDABI_:
+ case OMP_CLAUSE__SIMDNAME_:
/* The following clauses are only allowed on OpenMP cancel and
cancellation point directives, which at this point have already
been lowered into a function call. */
@@ -984,6 +984,20 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags)
pp_right_paren (pp);
break;
+ case OMP_CLAUSE__SIMDABI_:
+ pp_string (pp, "_simdabi_(");
+ dump_generic_node (pp, OMP_CLAUSE__SIMDABI__EXPR (clause),
+ spc, flags, false);
+ pp_right_paren (pp);
+ break;
+
+ case OMP_CLAUSE__SIMDNAME_:
+ pp_string (pp, "_simdname_(");
+ dump_generic_node (pp, OMP_CLAUSE__SIMDNAME__EXPR (clause),
+ spc, flags, false);
+ pp_right_paren (pp);
+ break;
+
case OMP_CLAUSE_PRIORITY:
pp_string (pp, "priority(");
dump_generic_node (pp, OMP_CLAUSE_PRIORITY_EXPR (clause),
@@ -334,6 +334,8 @@ unsigned const char omp_clause_num_ops[] =
0, /* OMP_CLAUSE_PROC_BIND */
1, /* OMP_CLAUSE_SAFELEN */
1, /* OMP_CLAUSE_SIMDLEN */
+ 1, /* OMP_CLAUSE__SIMDABI_ */
+ 1, /* OMP_CLAUSE__SIMDNAME_ */
0, /* OMP_CLAUSE_DEVICE_TYPE */
0, /* OMP_CLAUSE_FOR */
0, /* OMP_CLAUSE_PARALLEL */
@@ -419,6 +421,8 @@ const char * const omp_clause_code_name[] =
"proc_bind",
"safelen",
"simdlen",
+ "_simdabi_",
+ "_simdname_",
"device_type",
"for",
"parallel",
@@ -12102,6 +12106,8 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data,
case OMP_CLAUSE__CONDTEMP_:
case OMP_CLAUSE__SCANTEMP_:
case OMP_CLAUSE__SIMDUID_:
+ case OMP_CLAUSE__SIMDABI_:
+ case OMP_CLAUSE__SIMDNAME_:
WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0));
/* FALLTHRU */
@@ -1730,6 +1730,12 @@ class auto_suppress_location_wrappers
#define OMP_CLAUSE_SIMDLEN_EXPR(NODE) \
OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SIMDLEN), 0)
+#define OMP_CLAUSE__SIMDABI__EXPR(NODE) \
+ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE__SIMDABI_), 0)
+
+#define OMP_CLAUSE__SIMDNAME__EXPR(NODE) \
+ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE__SIMDNAME_), 0)
+
#define OMP_CLAUSE__SIMDUID__DECL(NODE) \
OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE__SIMDUID_), 0)