}
}
+/* Similarly, but for use in declaration parsing functions
+ which call cp_parser_handle_directive_omp_attributes. */
+
+static inline void
+cp_finalize_omp_declare_simd (cp_parser *parser, cp_omp_declare_simd_data *data)
+{
+ if (parser->omp_declare_simd != data)
+ return;
+
+ if (!parser->omp_declare_simd->error_seen
+ && !parser->omp_declare_simd->fndecl_seen)
+ error_at (parser->omp_declare_simd->loc,
+ "%<declare %s%> directive not immediately followed by "
+ "function declaration or definition",
+ parser->omp_declare_simd->variant_p ? "variant" : "simd");
+ parser->omp_declare_simd = NULL;
+}
+
/* Diagnose if #pragma acc routine isn't followed immediately by function
declaration or definition. */
};
/* Handle omp::directive and omp::sequence attributes in ATTRS
- (if any) at the start of a statement. */
+ (if any) at the start of a statement or in attribute-declaration. */
static tree
cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs)
return attrs;
}
+/* Handle omp::directive and omp::sequence attributes in *PATTRS
+ (if any) at the start or after declaration-id of a declaration. */
+
+static void
+cp_parser_handle_directive_omp_attributes (cp_parser *parser, tree *pattrs,
+ cp_omp_declare_simd_data *data,
+ bool start)
+{
+ if (!flag_openmp && !flag_openmp_simd)
+ return;
+
+ int cnt = 0;
+ bool bad = false;
+ bool variant_p = false;
+ location_t loc = UNKNOWN_LOCATION;
+ for (tree pa = *pattrs; pa; pa = TREE_CHAIN (pa))
+ if (get_attribute_namespace (pa) == omp_identifier
+ && is_attribute_p ("directive", get_attribute_name (pa)))
+ {
+ for (tree a = TREE_VALUE (pa); a; a = TREE_CHAIN (a))
+ {
+ tree d = TREE_VALUE (a);
+ gcc_assert (TREE_CODE (d) == DEFERRED_PARSE);
+ cp_token *first = DEFPARSE_TOKENS (d)->first;
+ cp_token *last = DEFPARSE_TOKENS (d)->last;
+ const char *directive[3] = {};
+ for (int i = 0; i < 3; i++)
+ {
+ tree id = NULL_TREE;
+ if (first + i == last)
+ break;
+ if (first[i].type == CPP_NAME)
+ id = first[i].u.value;
+ else if (first[i].type == CPP_KEYWORD)
+ id = ridpointers[(int) first[i].keyword];
+ else
+ break;
+ directive[i] = IDENTIFIER_POINTER (id);
+ }
+ const c_omp_directive *dir = NULL;
+ if (directive[0])
+ dir = c_omp_categorize_directive (directive[0], directive[1],
+ directive[2]);
+ if (dir == NULL)
+ continue;
+ if (dir->id == PRAGMA_OMP_DECLARE
+ && (strcmp (directive[1], "simd") == 0
+ || strcmp (directive[1], "variant") == 0))
+ {
+ if (cnt++ == 0)
+ {
+ variant_p = strcmp (directive[1], "variant") == 0;
+ loc = first->location;
+ }
+ if (start && parser->omp_declare_simd && !bad)
+ {
+ error_at (first->location,
+ "mixing OpenMP directives with attribute and "
+ "pragma syntax on the same declaration");
+ bad = true;
+ }
+ }
+ }
+ }
+
+ if (bad)
+ {
+ for (tree *pa = pattrs; *pa; )
+ if (get_attribute_namespace (*pa) == omp_identifier
+ && is_attribute_p ("directive", get_attribute_name (*pa)))
+ *pa = TREE_CHAIN (*pa);
+ else
+ pa = &TREE_CHAIN (*pa);
+ return;
+ }
+ if (cnt == 0)
+ return;
+
+ if (parser->omp_declare_simd == NULL)
+ {
+ data->error_seen = false;
+ data->fndecl_seen = false;
+ data->variant_p = variant_p;
+ data->loc = loc;
+ data->tokens = vNULL;
+ data->attribs[0] = NULL;
+ data->attribs[1] = NULL;
+ parser->omp_declare_simd = data;
+ }
+ parser->omp_declare_simd->attribs[!start] = pattrs;
+}
+
/* Parse a statement.
statement:
}
has_std_attrs = cp_lexer_peek_token (parser->lexer) != token;
+ /* Peek at the next token. */
+ token = cp_lexer_peek_token (parser->lexer);
+ bool omp_attrs_forbidden_p;
+ omp_attrs_forbidden_p = parser->omp_attrs_forbidden_p;
+
if (std_attrs && (flag_openmp || flag_openmp_simd))
- std_attrs = cp_parser_handle_statement_omp_attributes (parser, std_attrs);
+ {
+ bool handle_omp_attribs = false;
+ if (token->type == CPP_KEYWORD)
+ switch (token->keyword)
+ {
+ case RID_IF:
+ case RID_SWITCH:
+ case RID_WHILE:
+ case RID_DO:
+ case RID_FOR:
+ case RID_BREAK:
+ case RID_CONTINUE:
+ case RID_RETURN:
+ case RID_CO_RETURN:
+ case RID_GOTO:
+ case RID_AT_TRY:
+ case RID_AT_CATCH:
+ case RID_AT_FINALLY:
+ case RID_AT_SYNCHRONIZED:
+ case RID_AT_THROW:
+ case RID_TRY:
+ case RID_TRANSACTION_ATOMIC:
+ case RID_TRANSACTION_RELAXED:
+ case RID_SYNCHRONIZED:
+ case RID_ATOMIC_NOEXCEPT:
+ case RID_ATOMIC_CANCEL:
+ case RID_TRANSACTION_CANCEL:
+ handle_omp_attribs = true;
+ break;
+ default:
+ break;
+ }
+ else if (token->type == CPP_SEMICOLON
+ || token->type == CPP_OPEN_BRACE
+ || token->type == CPP_PRAGMA)
+ handle_omp_attribs = true;
+ if (handle_omp_attribs)
+ {
+ std_attrs = cp_parser_handle_statement_omp_attributes (parser,
+ std_attrs);
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+ }
parser->omp_attrs_forbidden_p = false;
- /* Peek at the next token. */
- token = cp_lexer_peek_token (parser->lexer);
/* Remember the location of the first token in the statement. */
cp_token *statement_token = token;
statement_location = token->location;
a statement all its own. */
else if (token->type == CPP_PRAGMA)
{
+ do_pragma:;
cp_lexer *lexer = parser->lexer;
bool do_restart = false;
/* Only certain OpenMP pragmas are attached to statements, and thus
return;
/* It didn't work, restore the post-attribute position. */
if (has_std_attrs)
- cp_lexer_set_token_position (parser->lexer, statement_token);
+ {
+ cp_lexer_set_token_position (parser->lexer, statement_token);
+ if (flag_openmp || flag_openmp_simd)
+ {
+ size_t i = 1;
+ bool handle_omp_attribs = true;
+ while (cp_lexer_peek_nth_token (parser->lexer, i)->keyword
+ == RID_EXTENSION)
+ i++;
+ switch (cp_lexer_peek_nth_token (parser->lexer, i)->keyword)
+ {
+ case RID_ASM:
+ case RID_NAMESPACE:
+ case RID_USING:
+ case RID_LABEL:
+ case RID_STATIC_ASSERT:
+ /* Don't handle OpenMP attribs on keywords that
+ always start a declaration statement but don't
+ accept attribute before it and therefore
+ the tentative cp_parser_declaration_statement
+ fails to parse because of that. */
+ handle_omp_attribs = false;
+ break;
+ default:
+ break;
+ }
+
+ if (handle_omp_attribs)
+ {
+ parser->omp_attrs_forbidden_p = omp_attrs_forbidden_p;
+ std_attrs
+ = cp_parser_handle_statement_omp_attributes
+ (parser, std_attrs);
+ parser->omp_attrs_forbidden_p = false;
+ token = cp_lexer_peek_token (parser->lexer);
+ if (token->type == CPP_PRAGMA)
+ goto do_pragma;
+ }
+ }
+ }
}
/* All preceding labels have been parsed at this point. */
if (loc_after_labels != NULL)
/* We no longer need to defer access checks. */
stop_deferring_access_checks ();
+ cp_omp_declare_simd_data odsd;
+ if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd))
+ cp_parser_handle_directive_omp_attributes (parser,
+ &decl_specifiers.attributes,
+ &odsd, true);
+
/* In a block scope, a valid declaration must always have a
decl-specifier-seq. By not trying to parse declarators, we can
resolve the declaration/expression ambiguity more quickly. */
else
{
pop_deferring_access_checks ();
+ cp_finalize_omp_declare_simd (parser, &odsd);
return;
}
}
done:
pop_deferring_access_checks ();
+ cp_finalize_omp_declare_simd (parser, &odsd);
}
/* Helper of cp_parser_simple_declaration, parse a decomposition declaration.
CP_PARSER_FLAGS_OPTIONAL,
&decl_specifiers,
&declares_class_or_enum);
+
+ cp_omp_declare_simd_data odsd;
+ if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd))
+ cp_parser_handle_directive_omp_attributes (parser,
+ &decl_specifiers.attributes,
+ &odsd, true);
+
/* If there was exactly one decl-specifier, and it declared a class,
and there's no declarator, then we have an explicit type
instantiation. */
cp_parser_consume_semicolon_at_end_of_statement (parser);
timevar_pop (TV_TEMPLATE_INST);
+
+ cp_finalize_omp_declare_simd (parser, &odsd);
}
/* Parse an explicit-specialization.
if (decl_spec_seq_has_spec_p (decl_specifiers, ds_consteval))
flags |= CP_PARSER_FLAGS_CONSTEVAL;
- /* Gather the attributes that were provided with the
- decl-specifiers. */
- prefix_attributes = decl_specifiers->attributes;
-
/* Assume that this is not the declarator for a function
definition. */
if (function_definition_p)
else
asm_specification = NULL_TREE;
+ /* Gather the attributes that were provided with the
+ decl-specifiers. */
+ prefix_attributes = decl_specifiers->attributes;
+
/* Look for attributes. */
attributes_start_token = cp_lexer_peek_token (parser->lexer);
attributes = cp_parser_attributes_opt (parser);
attrs = cp_parser_std_attribute_spec_seq (parser);
+ cp_omp_declare_simd_data odsd;
+ if ((flag_openmp || flag_openmp_simd)
+ && declarator
+ && declarator->std_attributes
+ && declarator->kind == cdk_id)
+ {
+ tree *pa = &declarator->std_attributes;
+ cp_parser_handle_directive_omp_attributes (parser, pa,
+ &odsd, false);
+ }
+
/* In here, we handle cases where attribute is used after
the function declaration. For example:
void func (int x) __attribute__((vector(..))); */
tree gnu_attrs = NULL_TREE;
tree requires_clause = NULL_TREE;
- late_return = (cp_parser_late_return_type_opt
- (parser, declarator, requires_clause));
+ late_return
+ = cp_parser_late_return_type_opt (parser, declarator,
+ requires_clause);
+
+ cp_finalize_omp_declare_simd (parser, &odsd);
/* Parse the virt-specifier-seq. */
virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
| CP_PARSER_FLAGS_TYPENAME_OPTIONAL),
&decl_specifiers,
&declares_class_or_enum);
+
+ cp_omp_declare_simd_data odsd;
+ if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd))
+ cp_parser_handle_directive_omp_attributes (parser,
+ &decl_specifiers.attributes,
+ &odsd, true);
+
/* Check for an invalid type-name. */
if (!decl_specifiers.any_type_specifiers_p
&& cp_parser_parse_and_diagnose_invalid_type_name (parser))
being declared. */
prefix_attributes = decl_specifiers.attributes;
decl_specifiers.attributes = NULL_TREE;
+ if (parser->omp_declare_simd
+ && (parser->omp_declare_simd->attribs[0]
+ == &decl_specifiers.attributes))
+ parser->omp_declare_simd->attribs[0] = &prefix_attributes;
/* See if these declarations will be friends. */
friend_p = cp_parser_friend_p (&decl_specifiers);
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
out:
parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+ cp_finalize_omp_declare_simd (parser, &odsd);
}
/* Parse a pure-specifier.
| CP_PARSER_FLAGS_TYPENAME_OPTIONAL),
&decl_specifiers,
&declares_class_or_enum);
+
+ cp_omp_declare_simd_data odsd;
+ if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd))
+ cp_parser_handle_directive_omp_attributes (parser,
+ &decl_specifiers.attributes,
+ &odsd, true);
+
if (friend_p)
*friend_p = cp_parser_friend_p (&decl_specifiers);
parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE;
+ cp_finalize_omp_declare_simd (parser, &odsd);
+
return decl;
}
data.error_seen = false;
data.fndecl_seen = false;
data.variant_p = variant_p;
- data.in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma;
data.tokens = vNULL;
- data.clauses = NULL_TREE;
+ data.attribs[0] = NULL;
+ data.attribs[1] = NULL;
+ data.loc = UNKNOWN_LOCATION;
/* It is safe to take the address of a local variable; it will only be
used while this scope is live. */
parser->omp_declare_simd = &data;
static tree
cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
- tree attrs, bool in_omp_attribute_pragma)
+ tree attrs)
{
matching_parens parens;
if (!parens.require_open (parser))
location_t varid_loc = make_location (caret_loc, start_loc, finish_loc);
/* For now only in C++ attributes, do it always for OpenMP 5.1. */
- if (in_omp_attribute_pragma
+ if (parser->lexer->in_omp_attribute_pragma
&& cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
&& cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
cp_lexer_consume_token (parser->lexer);
cp_lexer_consume_token (parser->lexer);
if (strcmp (kind, "simd") == 0)
{
- /* For now only in C++ attributes, do it always for OpenMP 5.1. */
- if (data->in_omp_attribute_pragma
- && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
+ /* For now only in C++ attributes, do it always for OpenMP 5.1.
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
&& cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
- cp_lexer_consume_token (parser->lexer);
+ cp_lexer_consume_token (parser->lexer); */
cl = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
"#pragma omp declare simd",
{
gcc_assert (strcmp (kind, "variant") == 0);
attrs
- = cp_finish_omp_declare_variant (parser, pragma_tok, attrs,
- data->in_omp_attribute_pragma);
+ = cp_finish_omp_declare_variant (parser, pragma_tok, attrs);
}
cp_parser_pop_lexer (parser);
}
+ cp_lexer *lexer = NULL;
+ for (int i = 0; i < 2; i++)
+ {
+ if (data->attribs[i] == NULL)
+ continue;
+ for (tree *pa = data->attribs[i]; *pa; )
+ if (get_attribute_namespace (*pa) == omp_identifier
+ && is_attribute_p ("directive", get_attribute_name (*pa)))
+ {
+ for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a))
+ {
+ tree d = TREE_VALUE (a);
+ gcc_assert (TREE_CODE (d) == DEFERRED_PARSE);
+ cp_token *first = DEFPARSE_TOKENS (d)->first;
+ cp_token *last = DEFPARSE_TOKENS (d)->last;
+ const char *directive[3] = {};
+ for (int j = 0; j < 3; j++)
+ {
+ tree id = NULL_TREE;
+ if (first + j == last)
+ break;
+ if (first[j].type == CPP_NAME)
+ id = first[j].u.value;
+ else if (first[j].type == CPP_KEYWORD)
+ id = ridpointers[(int) first[j].keyword];
+ else
+ break;
+ directive[j] = IDENTIFIER_POINTER (id);
+ }
+ const c_omp_directive *dir = NULL;
+ if (directive[0])
+ dir = c_omp_categorize_directive (directive[0], directive[1],
+ directive[2]);
+ if (dir == NULL)
+ {
+ error_at (first->location,
+ "unknown OpenMP directive name in "
+ "%<omp::directive%> attribute argument");
+ continue;
+ }
+ if (dir->id != PRAGMA_OMP_DECLARE
+ || (strcmp (directive[1], "simd") != 0
+ && strcmp (directive[1], "variant") != 0))
+ {
+ error_at (first->location,
+ "OpenMP directive other than %<declare simd%> "
+ "or %<declare variant%> appertains to a "
+ "declaration");
+ continue;
+ }
+
+ if (!flag_openmp && strcmp (directive[1], "simd") != 0)
+ continue;
+ if (lexer == NULL)
+ {
+ lexer = cp_lexer_alloc ();
+ lexer->debugging_p = parser->lexer->debugging_p;
+ }
+ vec_safe_reserve (lexer->buffer, (last - first) + 2);
+ cp_token tok = {};
+ tok.type = CPP_PRAGMA;
+ tok.keyword = RID_MAX;
+ tok.u.value = build_int_cst (NULL, PRAGMA_OMP_DECLARE);
+ tok.location = first->location;
+ lexer->buffer->quick_push (tok);
+ while (++first < last)
+ lexer->buffer->quick_push (*first);
+ tok = {};
+ tok.type = CPP_PRAGMA_EOL;
+ tok.keyword = RID_MAX;
+ tok.location = last->location;
+ lexer->buffer->quick_push (tok);
+ tok = {};
+ tok.type = CPP_EOF;
+ tok.keyword = RID_MAX;
+ tok.location = last->location;
+ lexer->buffer->quick_push (tok);
+ lexer->next = parser->lexer;
+ lexer->next_token = lexer->buffer->address ();
+ lexer->last_token = lexer->next_token
+ + lexer->buffer->length ()
+ - 1;
+ lexer->in_omp_attribute_pragma = true;
+ parser->lexer = lexer;
+ /* Move the current source position to that of the first token
+ in the new lexer. */
+ cp_lexer_set_source_position_from_token (lexer->next_token);
+
+ cp_token *pragma_tok = cp_lexer_consume_token (parser->lexer);
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *kind = IDENTIFIER_POINTER (id);
+ cp_lexer_consume_token (parser->lexer);
+
+ tree c, cl;
+ if (strcmp (kind, "simd") == 0)
+ {
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
+ cp_lexer_consume_token (parser->lexer);
+
+ omp_clause_mask mask = OMP_DECLARE_SIMD_CLAUSE_MASK;
+ cl = cp_parser_omp_all_clauses (parser, mask,
+ "#pragma omp declare simd",
+ pragma_tok);
+ if (cl)
+ cl = tree_cons (NULL_TREE, cl, NULL_TREE);
+ c = build_tree_list (get_identifier ("omp declare simd"),
+ cl);
+ TREE_CHAIN (c) = attrs;
+ if (processing_template_decl)
+ ATTR_IS_DEPENDENT (c) = 1;
+ attrs = c;
+ }
+ else
+ {
+ gcc_assert (strcmp (kind, "variant") == 0);
+ attrs
+ = cp_finish_omp_declare_variant (parser, pragma_tok,
+ attrs);
+ }
+ gcc_assert (parser->lexer != lexer);
+ vec_safe_truncate (lexer->buffer, 0);
+ }
+ *pa = TREE_CHAIN (*pa);
+ }
+ else
+ pa = &TREE_CHAIN (*pa);
+ }
+ if (lexer)
+ cp_lexer_destroy (lexer);
+
data->fndecl_seen = true;
return attrs;
}
--- /dev/null
+// { dg-do compile { target c++11 } }
+// { dg-options "-fopenmp -ffat-lto-objects -fdump-tree-gimple" }
+
+extern "C" void abort ();
+
+[[omp::directive (declare simd, linear (l))]] extern int f1 (int l);
+extern int f2 (int), f3 [[omp::directive (declare simd, uniform (m))]] (int m), f4 (int), z;
+[[omp::directive (declare simd, linear (l), simdlen(4))]] extern int f5 [[omp::directive (declare simd uniform (l) simdlen (8) notinbranch)]] (int l);
+
+int
+f1 (int l)
+{
+ return l;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f2 (int l)
+{
+ return l + 1;
+}
+
+// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f2i:" { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f3 (int l)
+{
+ return l + 2;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f4 (int l)
+{
+ return l + 3;
+}
+
+// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f4i:" { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f5 (int l)
+{ // { dg-warning "GCC does not currently support mixed size types for 'simd' functions" "" { target aarch64*-*-* } .-1 }
+ return l + 4;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f5i:" { target { i?86-*-* x86_64-*-* } } } }
+
+[[omp::directive (declare simd, linear (l), simdlen(4), notinbranch),
+ omp::directive (declare simd, uniform (l), simdlen(4), inbranch)]]
+int
+f6 [[omp::sequence (directive (declare simd uniform (l) simdlen (8), notinbranch),
+ omp::directive (declare simd linear (l) simdlen (8) inbranch))]] (int l)
+{ // { dg-warning "GCC does not currently support mixed size types for 'simd' functions" "" { target aarch64*-*-* } .-2 }
+ return l + 5;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]M4l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]N4u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]N8l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f7 (int l)
+{
+ return l + 6;
+}
+
+// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f7i:" { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f8 (int l)
+{
+ return l + 7;
+}
+
+// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f8i:" { target { i?86-*-* x86_64-*-* } } } }
+
+[[omp::sequence (omp::directive (declare variant (f7), match (construct={parallel})),
+ directive (declare simd uniform (l), simdlen(4)))]]
+int
+f9 [[omp::directive (declare simd uniform (l) simdlen (8)),
+ omp::directive (declare variant (f8) match (construct={parallel,for}))]] (int l)
+{ // { dg-warning "GCC does not currently support mixed size types for 'simd' functions" "" { target aarch64*-*-* } .-2 }
+ return l + 8;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+int z;
+
+void
+test ()
+{
+ [[omp::directive (parallel)]]
+ if (f9 (3) != 9)
+ abort ();
+ [[omp::directive (parallel for)]]
+ for (int i = 0; i < 1; i++)
+ if (f9 (4) != 11)
+ abort ();
+ if (f9 (5) != 13)
+ abort ();
+}
+
+// { dg-final { scan-tree-dump-times " = f7 \\\(3\\\);" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times " = f8 \\\(4\\\);" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times " = f9 \\\(5\\\);" 1 "gimple" } }
+
+template <int N>
+int
+f10 (int x)
+{
+ return x + N;
+}
+
+template [[omp::directive (declare simd, notinbranch)]] int f10<0> (int);
+
+// { dg-final { scan-assembler-times "_ZGVbN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+template int f10<1> [[omp::directive (declare simd inbranch linear(x))]] (int x);
+
+// { dg-final { scan-assembler-times "_ZGVbM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+template <int N>
+int f11 (int);
+
+template <> [[omp::directive (declare simd, inbranch)]] int
+f11<0> (int x)
+{
+ return x;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+template <> int
+f11<1> [[omp::directive (declare simd, notinbranch, linear (y))]] (int y)
+{
+ return y;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+struct S
+{
+ [[omp::sequence (directive (declare simd, inbranch, uniform (this)))]] int f12 (int x);
+ int f13 [[gnu::noinline, omp::directive (declare simd notinbranch uniform (this) linear (y))]] (int y) { return y; }
+};
+
+int
+S::f12 (int x)
+{
+ return x;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+// { dg-final { scan-assembler-times "_ZGVbN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f14 (S &p, int x)
+{
+ return p.f13 (x);
+}
--- /dev/null
+// { dg-do compile { target c++11 } }
+// { dg-options "-fopenmp -Wno-attributes" }
+
+namespace N {}
+namespace O { typedef int T; };
+
+void
+foo ()
+{
+ [[omp::directive (parallel)]] asm (""); // { dg-error "expected" }
+ [[omp::directive (parallel)]] __extension__ asm (""); // { dg-error "expected" }
+ __extension__ [[omp::directive (parallel)]] asm (""); // { dg-error "expected" }
+ [[omp::directive (parallel)]] namespace M = ::N; // { dg-error "expected" }
+ [[omp::directive (parallel)]] using namespace N; // { dg-bogus "expected" "" { xfail *-*-* } }
+ [[omp::directive (parallel)]] using O::T; // { dg-error "expected" }
+ [[omp::directive (parallel)]] __label__ foo; // { dg-error "expected" }
+ [[omp::directive (parallel)]] static_assert (true, ""); // { dg-error "expected" }
+ [[omp::directive (parallel)]] int a = 5; // { dg-error "not allowed to be specified in this context" }
+ int b = 0;
+ [[omp::directive (parallel)]] l: b++; // { dg-error "not allowed to be specified in this context" }
+ switch (0)
+ {
+ [[omp::directive (parallel)]] case 6: break; // { dg-error "not allowed to be specified in this context" }
+ [[omp::directive (parallel)]] default: break; // { dg-error "not allowed to be specified in this context" }
+ }
+}
+
+void
+bar ()
+{
+ [[omp::directive (declare simd)]] int a; // { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" }
+ [[omp::directive (declare simd)]] int b, f1 (int); // { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" }
+ [[omp::directive (declare simd)]] int f2 (int), c; // { dg-error "not immediately followed by function declaration or definition" }
+ int d [[omp::directive (declare simd)]]; // { dg-error "not allowed to be specified in this context" }
+ int f3 [[omp::directive (declare simd)]] (int), f4 [[omp::directive (declare simd)]] (int);
+ __extension__ [[omp::directive (declare simd)]] int f5 (int);
+ __extension__ int f6 [[omp::directive (declare simd, notinbranch)]] (int);
+ #pragma omp declare simd notinbranch
+ [[omp::directive (declare simd inbranch)]] int f7 (int); // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same declaration" }
+ [[omp::directive (declare simd notinbranch)]]
+ #pragma omp declare simd inbranch // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" }
+ int f8 (int);
+ static int t1, t2, t3, t4;
+ [[omp::directive (declare simd), omp::directive (foobar)]] int f9 (int); // { dg-error "unknown OpenMP directive name" }
+ [[omp::directive (foobar), omp::directive (declare simd)]] int f10 (int); // { dg-error "unknown OpenMP directive name" }
+ [[omp::directive (threadprivate (t1)), omp::directive (declare simd)]] int f10 (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+ [[omp::directive (declare simd), omp::directive (threadprivate (t2))]] int f11 (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+ int f12 [[omp::directive (declare simd), omp::directive (foobar)]] (int); // { dg-error "unknown OpenMP directive name" }
+ int f13 [[omp::directive (foobar), omp::directive (declare simd)]] (int); // { dg-error "unknown OpenMP directive name" }
+ int f14 [[omp::directive (threadprivate (t3)), omp::directive (declare simd)]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+ int f15 [[omp::directive (declare simd), omp::directive (threadprivate (t4))]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+}
+
+[[omp::directive (declare simd)]] int a; // { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" }
+[[omp::directive (declare simd)]] int b, f16 (int); // { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" }
+[[omp::directive (declare simd)]] int f17 (int), c; // { dg-error "not immediately followed by function declaration or definition" }
+int d [[omp::directive (declare simd)]]; // { dg-error "not allowed to be specified in this context" }
+int f18 [[omp::directive (declare simd)]] (int), f19 [[omp::directive (declare simd)]] (int);
+__extension__ [[omp::directive (declare simd)]] int f20 (int);
+__extension__ int f21 [[omp::directive (declare simd, notinbranch)]] (int);
+#pragma omp declare simd notinbranch
+[[omp::directive (declare simd inbranch)]] int f22 (int); // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same declaration" }
+[[omp::directive (declare simd notinbranch)]] // { dg-error "'declare simd' directive not immediately followed by function declaration or definition" }
+#pragma omp declare simd inbranch // { dg-error "'#pragma' is not allowed here" }
+int f23 (int);
+int t5, t6, t7, t8;
+[[omp::directive (declare simd), omp::directive (foobar)]] int f24 (int); // { dg-error "unknown OpenMP directive name" }
+[[omp::directive (foobar), omp::directive (declare simd)]] int f25 (int); // { dg-error "unknown OpenMP directive name" }
+[[omp::directive (threadprivate (t5)), omp::directive (declare simd)]] int f26 (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+[[omp::directive (declare simd), omp::directive (threadprivate (t6))]] int f27 (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+int f28 [[omp::directive (declare simd), omp::directive (foobar)]] (int); // { dg-error "unknown OpenMP directive name" }
+int f29 [[omp::directive (foobar), omp::directive (declare simd)]] (int); // { dg-error "unknown OpenMP directive name" }
+int f30 [[omp::directive (threadprivate (t7)), omp::directive (declare simd)]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+int f31 [[omp::directive (declare simd), omp::directive (threadprivate (t8))]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }