@@ -105,7 +105,7 @@ bool directive_vector = false;
bool directive_novector = false;
/* Map of middle-end built-ins that should be vectorized. */
-hash_map<nofree_string_hash, int> *gfc_vectorized_builtins;
+hash_map<nofree_string_hash, gfc_vect_builtin> *gfc_vectorized_builtins;
/* If a kind expression of a component of a parameterized derived type is
parameterized, temporarily store the expression here. */
@@ -11600,9 +11600,13 @@ gfc_match_gcc_unroll (void)
/* Match a !GCC$ builtin (b) attributes simd flags if('target') form:
The parameter b is name of a middle-end built-in.
- FLAGS is optional and must be one of:
- - (inbranch)
- - (notinbranch)
+ FLAGS is optional and must be of the form:
+ (mask)
+ (mask, simdlen)
+ (mask, simdlen, 'simdabi')
+ (mask, simdlen, 'simdabi', 'name')
+ where mask is inbranch or notinbranch, simdlen is an integer, simdabi
+ and name are strings.
IF('target') is optional and TARGET is a name of a multilib ABI.
@@ -11613,15 +11617,44 @@ gfc_match_gcc_builtin (void)
{
char builtin[GFC_MAX_SYMBOL_LEN + 1];
char target[GFC_MAX_SYMBOL_LEN + 1];
+ char simdabi[GFC_MAX_SYMBOL_LEN + 1] = "";
+ char name[GFC_MAX_SYMBOL_LEN + 1] = "";
+ bool inbranch;
+ bool flags = false;
+ int simdlen = 0;
if (gfc_match (" ( %n ) attributes simd", builtin) != MATCH_YES)
return MATCH_ERROR;
- gfc_simd_clause clause = SIMD_NONE;
- if (gfc_match (" ( notinbranch ) ") == MATCH_YES)
- clause = SIMD_NOTINBRANCH;
- else if (gfc_match (" ( inbranch ) ") == MATCH_YES)
- clause = SIMD_INBRANCH;
+ if (gfc_match (" ( ") == MATCH_YES)
+ {
+ flags = true;
+ if (gfc_match ("notinbranch") == MATCH_YES)
+ inbranch = false;
+ else if (gfc_match ("inbranch") == MATCH_YES)
+ inbranch = true;
+ else
+ {
+syntax_error:
+ gfc_error ("Syntax error in !GCC$ BUILTIN directive at %C");
+ return MATCH_ERROR;
+ }
+
+ if (gfc_match (" , ") == MATCH_YES)
+ if (gfc_match_small_int (&simdlen) != MATCH_YES || simdlen < 0)
+ goto syntax_error;
+
+ if (gfc_match (" , ") == MATCH_YES)
+ if (gfc_match (" '%n'", &simdabi) != MATCH_YES)
+ goto syntax_error;
+
+ if (gfc_match (" , ") == MATCH_YES)
+ if (gfc_match (" '%n'", &name) != MATCH_YES)
+ goto syntax_error;
+
+ if (gfc_match (" ) ") != MATCH_YES)
+ goto syntax_error;
+ }
if (gfc_match (" if ( '%n' ) ", target) == MATCH_YES)
{
@@ -11631,16 +11664,27 @@ gfc_match_gcc_builtin (void)
}
if (gfc_vectorized_builtins == NULL)
- gfc_vectorized_builtins = new hash_map<nofree_string_hash, int> ();
+ gfc_vectorized_builtins =
+ new hash_map<nofree_string_hash, gfc_vect_builtin> ();
char *r = XNEWVEC (char, strlen (builtin) + 32);
sprintf (r, "__builtin_%s", builtin);
bool existed;
- int &value = gfc_vectorized_builtins->get_or_insert (r, &existed);
- value |= clause;
+ gfc_vect_builtin *v = &gfc_vectorized_builtins->get_or_insert (r, &existed);
if (existed)
- free (r);
+ {
+ free (r);
+ gfc_vect_builtin *next = v->next;
+ v->next = new gfc_vect_builtin;
+ v = v->next;
+ v->next = next;
+ }
+ v->flags = flags;
+ v->inbranch = inbranch;
+ v->simdlen = simdlen;
+ v->simdabi = simdabi[0] ? xstrdup (simdabi) : 0;
+ v->name = name[0] ? xstrdup (name) : 0;
return MATCH_YES;
}
@@ -2812,26 +2812,18 @@ extern bool directive_ivdep;
extern bool directive_vector;
extern bool directive_novector;
-/* SIMD clause enum. */
-enum gfc_simd_clause
-{
- SIMD_NONE = (1 << 0),
- SIMD_INBRANCH = (1 << 1),
- SIMD_NOTINBRANCH = (1 << 2)
-};
-
-/* Tuple for parsing of vectorized built-ins. */
-struct gfc_vect_builtin_tuple
-{
- gfc_vect_builtin_tuple (const char *n, gfc_simd_clause t)
- : name (n), simd_type (t) {}
-
- const char *name;
- gfc_simd_clause simd_type;
+struct gfc_vect_builtin
+{
+ gfc_vect_builtin *next;
+ char *name;
+ char *simdabi;
+ bool flags;
+ bool inbranch;
+ unsigned int simdlen;
};
/* Map of middle-end built-ins that should be vectorized. */
-extern hash_map<nofree_string_hash, int> *gfc_vectorized_builtins;
+extern hash_map<nofree_string_hash, gfc_vect_builtin> *gfc_vectorized_builtins;
/* Handling Parameterized Derived Types */
bool gfc_insert_kind_parameter_exprs (gfc_expr *);
@@ -3671,12 +3671,25 @@ The syntax of the directive is
You can use this directive to define which middle-end built-ins provide vector
implementations. @code{B} is name of the middle-end built-in. @code{FLAGS}
-are optional and must be either "(inbranch)" or "(notinbranch)".
+are optional and must follow one of the forms
+@itemize
+@item @code{(mask)}
+@item @code{(mask, simdlen)}
+@item @code{(mask, simdlen, 'simdabi')}
+@item @code{(mask, simdlen, 'simdabi', 'name')}
+@end itemize
+where @code{mask} is either inbranch or notinbranch, simdlen is a non-negative
+integer, simdabi is a target specific ISA selector and name is the symbol
+name of the vector function (when not specified the name is generated according
+to the target Vector ABI document, the name is only valid to specify if the
+directive specifies a single vector funtion variant).
+
@code{IF} statement is optional and is used to filter multilib ABIs
for the built-in that should be vectorized. Example usage:
@smallexample
!GCC$ builtin (sinf) attributes simd (notinbranch) if('x86_64')
+!GCC$ builtin (cosf) attributes simd (notinbranch, 4, 'b') if('x86_64')
@end smallexample
The purpose of the directive is to provide an API among the GCC compiler and
@@ -608,29 +608,45 @@ add_simd_flag_for_built_in (tree fndecl)
return;
const char *name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
- int *clauses = gfc_vectorized_builtins->get (name);
- if (clauses)
+ gfc_vect_builtin *v = gfc_vectorized_builtins->get (name);
+ for (; v != NULL; v = v->next)
{
- for (unsigned i = 0; i < 3; i++)
- if (*clauses & (1 << i))
- {
- gfc_simd_clause simd_type = (gfc_simd_clause)*clauses;
- tree omp_clause = NULL_TREE;
- if (simd_type == SIMD_NONE)
- ; /* No SIMD clause. */
- else
- {
- omp_clause_code code
- = (simd_type == SIMD_INBRANCH
- ? OMP_CLAUSE_INBRANCH : OMP_CLAUSE_NOTINBRANCH);
- omp_clause = build_omp_clause (UNKNOWN_LOCATION, code);
- omp_clause = build_tree_list (NULL_TREE, omp_clause);
- }
-
- DECL_ATTRIBUTES (fndecl)
- = tree_cons (get_identifier ("omp declare simd"), omp_clause,
- DECL_ATTRIBUTES (fndecl));
- }
+ tree t = NULL_TREE;
+ if (v->flags)
+ {
+ omp_clause_code code
+ = (v->inbranch ? OMP_CLAUSE_INBRANCH : OMP_CLAUSE_NOTINBRANCH);
+ tree c = build_omp_clause (UNKNOWN_LOCATION, code);
+ t = c;
+ if (v->simdlen != 0)
+ {
+ c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_SIMDLEN);
+ OMP_CLAUSE_SIMDLEN_EXPR (c)
+ = build_int_cst (integer_type_node, v->simdlen);
+ OMP_CLAUSE_CHAIN (c) = t;
+ t = c;
+ }
+ if (v->simdabi != NULL)
+ {
+ c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__SIMDABI_);
+ OMP_CLAUSE__SIMDABI__EXPR (c)
+ = build_string (strlen (v->simdabi) + 1, v->simdabi);
+ OMP_CLAUSE_CHAIN (c) = t;
+ t = c;
+ }
+ if (v->name != NULL)
+ {
+ c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__SIMDNAME_);
+ OMP_CLAUSE__SIMDNAME__EXPR (c)
+ = build_string (strlen (v->name) + 1, v->name);
+ OMP_CLAUSE_CHAIN (c) = t;
+ t = c;
+ }
+ t = build_tree_list (NULL_TREE, t);
+ }
+ DECL_ATTRIBUTES (fndecl)
+ = tree_cons (get_identifier ("omp declare simd"), t,
+ DECL_ATTRIBUTES (fndecl));
}
}
@@ -659,10 +675,24 @@ gfc_adjust_builtins (void)
/* Release all strings. */
if (gfc_vectorized_builtins != NULL)
{
- for (hash_map<nofree_string_hash, int>::iterator it
+ for (hash_map<nofree_string_hash, gfc_vect_builtin>::iterator it
= gfc_vectorized_builtins->begin ();
it != gfc_vectorized_builtins->end (); ++it)
- free (CONST_CAST (char *, (*it).first));
+ {
+ free (CONST_CAST (char *, (*it).first));
+ gfc_vect_builtin *v = &(*it).second;
+ free (v->name);
+ free (v->simdabi);
+ v = v->next;
+ while (v)
+ {
+ gfc_vect_builtin *next = v->next;
+ free (v->name);
+ free (v->simdabi);
+ delete v;
+ v = next;
+ }
+ }
delete gfc_vectorized_builtins;
gfc_vectorized_builtins = NULL;
new file mode 100644
@@ -0,0 +1,18 @@
+! { dg-do compile { target { aarch64*-*-linux* x86_64-*-* i?86-*-* } } }
+! { dg-additional-options "-nostdinc -Ofast -fpre-include=simd-builtins-10.h -fdump-tree-optimized" }
+
+program test_overloaded_intrinsic
+ real(4) :: x4(3200), y4(3200)
+ real(8) :: x8(3200), y8(3200)
+
+ y4 = sin(x4)
+ print *, y4
+
+ y8 = sin(x8)
+ print *, y8
+end
+
+! { dg-final { scan-tree-dump "sinf.simdclone" "optimized" } } */
+! { dg-final { scan-tree-dump-not "sin.simdclone" "optimized" } } */
+
+! { dg-final { scan-assembler "vec_sinf" } } */
new file mode 100644
@@ -0,0 +1,6 @@
+!GCC$ builtin (sinf) attributes simd (notinbranch, 4, 'n', 'vec_sinf') if('aarch64')
+!GCC$ builtin (sinf) attributes simd (notinbranch, 4, 'n', 'vec_sinf') if('aarch64_be')
+!GCC$ builtin (sinf) attributes simd (notinbranch, 4, 'n', 'vec_sinf') if('aarch64_ilp32')
+!GCC$ builtin (sinf) attributes simd (notinbranch, 4, 'n', 'vec_sinf') if('aarch64_be_ilp32')
+!GCC$ builtin (sinf) attributes simd (notinbranch, 4, 'b', 'vec_sinf') if('x64_64')
+!GCC$ builtin (sinf) attributes simd (notinbranch, 4, 'b', 'vec_sinf') if('i386')
new file mode 100644
@@ -0,0 +1,19 @@
+! { dg-do compile { target { aarch64*-*-linux* } } }
+! { dg-additional-options "-nostdinc -Ofast -fpre-include=simd-builtins-9.h -fdump-tree-optimized" }
+
+program test_overloaded_intrinsic
+ real(4) :: x4(3200), y4(3200)
+ real(8) :: x8(3200), y8(3200)
+
+ y4 = sin(x4)
+ print *, y4
+
+ y8 = sin(x8)
+ print *, y8
+end
+
+! { dg-final { scan-tree-dump "sinf.simdclone" "optimized" { target ilp32 } } } */
+! { dg-final { scan-tree-dump-not "sin.simdclone" "optimized" { target ilp32 } } } */
+
+! { dg-final { scan-tree-dump "sin.simdclone" "optimized" { target lp64 } } } */
+! { dg-final { scan-tree-dump-not "sinf.simdclone" "optimized" { target lp64 } } } */
new file mode 100644
@@ -0,0 +1,4 @@
+!GCC$ builtin (sin) attributes simd (notinbranch, 2, 'n') if('aarch64')
+!GCC$ builtin (sin) attributes simd (notinbranch, 2, 'n') if('aarch64_be')
+!GCC$ builtin (sinf) attributes simd (notinbranch, 4, 'n') if('aarch64_ilp32')
+!GCC$ builtin (sinf) attributes simd (notinbranch, 4, 'n') if('aarch64_be_ilp32')