On Tue, Apr 30, 2013 at 10:35:21AM -0400, Jason Merrill wrote: > On 04/29/2013 02:32 PM, Jakub Jelinek wrote: > >Should I copy the parser->omp_declare_simd_clauses vector pointer > >say into cp_declarator structure so that grokfndecl could grab it from > >there? > > That sounds good. > > >Also, for the attributes I wonder if it wouldn't be better to > >finally replace the PARM_DECLs in the clauses say with parameter indexes, > >because otherwise it might be difficult to adjust those during instantiation > >etc. > > Yes, that will probably be easier to deal with.
Ok, here is a complete patch for C++ FE only support of the #pragma omp declare simd parsing. The info is stored as "omp declare simd" attribute with an argument which is either NULL_TREE (barebone #pragma omp declare simd) or list of OMP_CLAUSEs). Tested on x86_64-linux, any comments on this before I commit it to the gomp4 branch? Like, isn't it too invasive to the C++ FE? 2013-05-06 Jakub Jelinek <ja...@redhat.com> * tree.c (omp_declare_simd_clauses_equal): New function. (attribute_value_equal): Call it for -fopenmp if TREE_VALUE of the attributes are both OMP_CLAUSEs. * tree.h (omp_declare_simd_clauses_equal): Declare. c-family/ * c-common.c (c_common_attribute_table): Add "omp declare simd" attribute. (handle_omp_declare_simd_attribute): New function. * c-common.h (c_omp_declare_simd_clauses_to_numbers, c_omp_declare_simd_clauses_to_decls): Declare. * c-omp.c (c_omp_declare_simd_clause_cmp, c_omp_declare_simd_clauses_to_numbers, c_omp_declare_simd_clauses_to_decls): New functions. cp/ * cp-tree.h (start_decl, start_function, grokmethod, grokfield): Add omp_declare_simd_clauses argument. (finish_omp_declare_simd): Declare. * decl2.c (grokfield): Add omp_declare_simd_clauses argument, pass it through to grokdeclarator. (grokbitfield): Adjust grokdeclarator caller. (is_late_template_attribute): Return true for "omp declare simd" attribute. (cp_check_const_attributes): Don't check TREE_VALUE of arg if arg isn't a TREE_LIST. * decl.c (shadow_tag, groktypename): Adjust grokdeclarator callers. (start_decl, start_function, grokmethod): Add omp_declare_simd_clauses argument, pass it through to grokdeclarator. (grokfndecl): Add omp_declare_simd_clauses argument, call finish_omp_declare_simd if non-NULL. (grokdeclarator): Add omp_declare_simd_clauses argument, pass it through to grokfndecl. * decl.h (grokdeclarator): Add omp_declare_simd_clauses argument. * pt.c (apply_late_template_attributes): Handle "omp declare simd" attribute specially. (tsubst_omp_clauses): Add declare_simd argument, don't call finish_omp_clauses if it is set. Handle OpenMP 4.0 clauses. (tsubst_expr): Adjust tsubst_omp_clauses callers. * semantics.c (finish_omp_clauses): Diagnose inbranch notinbranch. (finish_omp_declare_simd): New function. * parser.h (struct cp_parser): Add omp_declare_simd_clauses field. * parser.c (cp_ensure_no_omp_declare_simd, cp_finish_omp_declare_simd): New functions. (enum pragma_context): Add pragma_member and pragma_objc_icode. (cp_parser_trait_expr, cp_parser_conversion_type_id, cp_parser_template_parameter, cp_parser_explicit_instantiation, cp_parser_enum_specifier, cp_parser_parameter_declaration_list, cp_parser_exception_declaration, cp_parser_sizeof_operand, cp_parser_objc_method_tail_params_opt, cp_parser_objc_try_catch_finally_statement): Adjust grokdeclarator callers. (cp_parser_lambda_declarator_opt): Adjust grokmethod caller. (cp_parser_condition): Adjust start_decl caller. (cp_parser_linkage_specification, cp_parser_namespace_definition, cp_parser_class_specifier_1): Call cp_ensure_no_omp_declare_simd. (cp_parser_alias_declaration): Adjust grokfield and start_decl callers. (cp_parser_init_declarator, cp_parser_member_declaration, cp_parser_function_definition_from_specifiers_and_declarator, cp_parser_save_member_function_body): Call cp_finish_omp_declare_simd, pass parser->omp_declare_simd_clauses to start_decl, grokfield, start_function or grokmethod. (cp_parser_member_specification_opt): Pass pragma_member instead of pragma_external to cp_parser_pragma. (cp_parser_objc_interstitial_code): Pass pragma_objc_icode instead of pragma_external to cp_parser_pragma. (cp_parser_objc_class_ivars, cp_parser_objc_struct_declaration): Adjust grokfield caller. (cp_parser_omp_var_list_no_open): If parser->omp_declare_simd_clauses, just cp_parser_identifier the argument names. (cp_parser_omp_all_clauses): Don't call finish_omp_clauses for parser->omp_declare_simd_clauses. (OMP_DECLARE_SIMD_CLAUSE_MASK): Define. (cp_parser_omp_declare_simd, cp_parser_omp_declare): New functions. (cp_parser_pragma): Call cp_ensure_no_omp_declare_simd. Handle PRAGMA_OMP_DECLARE_REDUCTION. Replace == pragma_external with != pragma_stmt and != pragma_compound. testsuite/ * g++.dg/gomp/declare-simd-1.C: New test. * g++.dg/gomp/declare-simd-2.C: New test. --- gcc/tree.c.jj 2013-03-27 13:01:09.000000000 +0100 +++ gcc/tree.c 2013-05-06 11:49:55.300466043 +0200 @@ -4397,6 +4397,48 @@ build_type_attribute_qual_variant (tree return ttype; } +/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are + the same. */ + +bool +omp_declare_simd_clauses_equal (tree clauses1, tree clauses2) +{ + tree cl1, cl2; + for (cl1 = clauses1, cl2 = clauses2; + cl1 && cl2; + cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2)) + { + if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2)) + return false; + if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN) + { + if (simple_cst_equal (OMP_CLAUSE_DECL (cl1), + OMP_CLAUSE_DECL (cl2)) != 1) + return false; + } + switch (OMP_CLAUSE_CODE (cl1)) + { + case OMP_CLAUSE_ALIGNED: + if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1), + OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1) + return false; + break; + case OMP_CLAUSE_LINEAR: + if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1), + OMP_CLAUSE_LINEAR_STEP (cl2)) != 1) + return false; + break; + case OMP_CLAUSE_SIMDLEN: + if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1), + OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1) + return false; + default: + break; + } + } + return true; +} + /* Compare two attributes for their value identity. Return true if the attribute values are known to be equal; otherwise return false. */ @@ -4414,6 +4456,13 @@ attribute_value_equal (const_tree attr1, return (simple_cst_list_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1); + if (flag_openmp + && TREE_VALUE (attr1) && TREE_VALUE (attr2) + && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE + && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE) + return omp_declare_simd_clauses_equal (TREE_VALUE (attr1), + TREE_VALUE (attr2)); + return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1); } --- gcc/tree.h.jj 2013-04-30 18:03:33.000000000 +0200 +++ gcc/tree.h 2013-05-06 12:00:18.625085694 +0200 @@ -5051,6 +5051,10 @@ extern tree build_type_attribute_variant extern tree build_decl_attribute_variant (tree, tree); extern tree build_type_attribute_qual_variant (tree, tree, int); +/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are + the same. */ +extern bool omp_declare_simd_clauses_equal (tree, tree); + /* Return 0 if the attributes for two types are incompatible, 1 if they are compatible, and 2 if they are nearly compatible (which causes a warning to be generated). */ --- gcc/c-family/c-common.c.jj 2013-04-10 19:11:23.000000000 +0200 +++ gcc/c-family/c-common.c 2013-05-06 15:34:11.823524239 +0200 @@ -368,6 +368,8 @@ static tree handle_optimize_attribute (t static tree ignore_attribute (tree *, tree, tree, int, bool *); static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *); static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); +static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int, + bool *); static void check_function_nonnull (tree, int, tree *); static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); @@ -738,6 +740,8 @@ const struct attribute_spec c_common_att The name contains space to prevent its usage in source code. */ { "fn spec", 1, 1, false, true, true, handle_fnspec_attribute, false }, + { "omp declare simd", 0, -1, true, false, false, + handle_omp_declare_simd_attribute, false }, { NULL, 0, 0, false, false, false, NULL, false } }; @@ -7958,6 +7962,15 @@ handle_fnspec_attribute (tree *node ATTR return NULL_TREE; } +/* Handle an "omp declare simd" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *) +{ + return NULL_TREE; +} + /* Handle a "returns_twice" attribute; arguments as in struct attribute_spec.handler. */ --- gcc/c-family/c-common.h.jj 2013-04-30 18:03:33.000000000 +0200 +++ gcc/c-family/c-common.h 2013-05-06 11:41:07.024543300 +0200 @@ -1042,6 +1042,8 @@ extern void c_finish_omp_taskyield (loca extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree, tree, tree, tree); extern void c_split_parallel_clauses (location_t, tree, tree *, tree *); +extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree); +extern void c_omp_declare_simd_clauses_to_decls (tree, tree); extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); /* Not in c-omp.c; provided by the front end. */ --- gcc/c-family/c-omp.c.jj 2013-04-30 18:03:33.000000000 +0200 +++ gcc/c-family/c-omp.c 2013-05-06 14:54:55.226010022 +0200 @@ -637,6 +637,100 @@ c_split_parallel_clauses (location_t loc } } +/* qsort callback to compare #pragma omp declare simd clauses. */ + +static int +c_omp_declare_simd_clause_cmp (const void *p, const void *q) +{ + tree a = *(const tree *) p; + tree b = *(const tree *) q; + if (OMP_CLAUSE_CODE (a) != OMP_CLAUSE_CODE (b)) + { + if (OMP_CLAUSE_CODE (a) > OMP_CLAUSE_CODE (b)) + return -1; + return 1; + } + if (OMP_CLAUSE_CODE (a) != OMP_CLAUSE_SIMDLEN + && OMP_CLAUSE_CODE (a) != OMP_CLAUSE_INBRANCH + && OMP_CLAUSE_CODE (a) != OMP_CLAUSE_NOTINBRANCH) + { + int c = tree_low_cst (OMP_CLAUSE_DECL (a), 0); + int d = tree_low_cst (OMP_CLAUSE_DECL (b), 0); + if (c < d) + return 1; + if (c > d) + return -1; + } + return 0; +} + +/* Change PARM_DECLs in OMP_CLAUSE_DECL of #pragma omp declare simd + CLAUSES on FNDECL into argument indexes and sort them. */ + +tree +c_omp_declare_simd_clauses_to_numbers (tree fndecl, tree clauses) +{ + tree c; + vec<tree> clvec = vNULL; + + for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_SIMDLEN + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_INBRANCH + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_NOTINBRANCH) + { + tree decl = OMP_CLAUSE_DECL (c); + tree arg; + int idx; + for (arg = DECL_ARGUMENTS (fndecl), idx = 0; arg; + arg = TREE_CHAIN (arg), idx++) + if (arg == decl) + break; + if (arg == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is not an argument of %qD", decl, fndecl); + continue; + } + OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, idx); + } + clvec.safe_push (c); + } + if (!clvec.is_empty ()) + { + unsigned int len = clvec.length (), i; + clvec.qsort (c_omp_declare_simd_clause_cmp); + clauses = clvec[0]; + for (i = 0; i < len; i++) + OMP_CLAUSE_CHAIN (clvec[i]) = (i < len - 1) ? clvec[i + 1] : NULL_TREE; + } + clvec.release (); + return clauses; +} + +/* Change argument indexes in CLAUSES of FNDECL back to PARM_DECLs. */ + +void +c_omp_declare_simd_clauses_to_decls (tree fndecl, tree clauses) +{ + tree c; + + for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_SIMDLEN + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_INBRANCH + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_NOTINBRANCH) + { + int idx = tree_low_cst (OMP_CLAUSE_DECL (c), 0), i; + tree arg; + for (arg = DECL_ARGUMENTS (fndecl), i = 0; arg; + arg = TREE_CHAIN (arg), i++) + if (i == idx) + break; + gcc_assert (arg); + OMP_CLAUSE_DECL (c) = arg; + } +} + /* True if OpenMP sharing attribute of DECL is predetermined. */ enum omp_clause_default_kind --- gcc/cp/cp-tree.h.jj 2013-04-30 18:03:33.000000000 +0200 +++ gcc/cp/cp-tree.h 2013-05-02 15:24:50.000000000 +0200 @@ -5124,7 +5124,8 @@ extern void warn_misplaced_attr_for_clas extern tree check_tag_decl (cp_decl_specifier_seq *, bool); extern tree shadow_tag (cp_decl_specifier_seq *); extern tree groktypename (cp_decl_specifier_seq *, const cp_declarator *, bool); -extern tree start_decl (const cp_declarator *, cp_decl_specifier_seq *, int, tree, tree, tree *); +extern tree start_decl (const cp_declarator *, cp_decl_specifier_seq *, + int, tree, tree, tree *, vec<tree, va_gc> *); extern void start_decl_1 (tree, bool); extern bool check_array_initializer (tree, tree, tree); extern void cp_finish_decl (tree, tree, bool, tree, int); @@ -5150,12 +5151,14 @@ extern void finish_enum (tree); extern void build_enumerator (tree, tree, tree, location_t); extern tree lookup_enumerator (tree, tree); extern void start_preparsed_function (tree, tree, int); -extern int start_function (cp_decl_specifier_seq *, const cp_declarator *, tree); +extern int start_function (cp_decl_specifier_seq *, const cp_declarator *, tree, + vec<tree, va_gc> *); extern tree begin_function_body (void); extern void finish_function_body (tree); extern tree outer_curly_brace_block (tree); extern tree finish_function (int); -extern tree grokmethod (cp_decl_specifier_seq *, const cp_declarator *, tree); +extern tree grokmethod (cp_decl_specifier_seq *, const cp_declarator *, tree, + vec<tree, va_gc> *); extern void maybe_register_incomplete_var (tree); extern void maybe_commonize_var (tree); extern void complete_vars (tree); @@ -5204,7 +5207,7 @@ extern tree delete_sanity (tree, tree, extern tree check_classfn (tree, tree, tree); extern void check_member_template (tree); extern tree grokfield (const cp_declarator *, cp_decl_specifier_seq *, - tree, bool, tree, tree); + tree, bool, tree, tree, vec<tree, va_gc> *); extern tree grokbitfield (const cp_declarator *, cp_decl_specifier_seq *, tree, tree); extern tree cp_reconstruct_complex_type (tree, tree); @@ -5702,6 +5705,7 @@ extern void simplify_aggr_init_expr (tr extern void finalize_nrv (tree *, tree, tree); extern void note_decl_for_pch (tree); extern tree finish_omp_clauses (tree); +extern void finish_omp_declare_simd (tree, vec<tree, va_gc> *); extern void finish_omp_threadprivate (tree); extern tree begin_omp_structured_block (void); extern tree finish_omp_structured_block (tree); --- gcc/cp/decl2.c.jj 2013-03-20 10:07:19.000000000 +0100 +++ gcc/cp/decl2.c 2013-05-06 15:03:22.094114612 +0200 @@ -796,7 +796,7 @@ grokfield (const cp_declarator *declarat cp_decl_specifier_seq *declspecs, tree init, bool init_const_expr_p, tree asmspec_tree, - tree attrlist) + tree attrlist, vec<tree, va_gc> *omp_declare_simd_clauses) { tree value; const char *asmspec = 0; @@ -809,7 +809,8 @@ grokfield (const cp_declarator *declarat && TREE_CHAIN (init) == NULL_TREE) init = NULL_TREE; - value = grokdeclarator (declarator, declspecs, FIELD, init != 0, &attrlist); + value = grokdeclarator (declarator, declspecs, FIELD, init != 0, &attrlist, + omp_declare_simd_clauses); if (! value || error_operand_p (value)) /* friend or constructor went bad. */ return error_mark_node; @@ -1019,7 +1020,8 @@ grokbitfield (const cp_declarator *decla cp_decl_specifier_seq *declspecs, tree width, tree attrlist) { - tree value = grokdeclarator (declarator, declspecs, BITFIELD, 0, &attrlist); + tree value + = grokdeclarator (declarator, declspecs, BITFIELD, 0, &attrlist, NULL); if (value == error_mark_node) return NULL_TREE; /* friends went bad. */ @@ -1111,6 +1113,11 @@ is_late_template_attribute (tree attr, t if (is_attribute_p ("unused", name)) return false; + /* #pragma omp declare simd attribute needs to be always finalized. */ + if (flag_openmp + && is_attribute_p ("omp declare simd", name)) + return true; + /* If any of the arguments are dependent expressions, we can't evaluate the attribute until instantiation time. */ for (arg = args; arg; arg = TREE_CHAIN (arg)) @@ -1296,6 +1303,9 @@ cp_check_const_attributes (tree attribut for (attr = attributes; attr; attr = TREE_CHAIN (attr)) { tree arg; + if (TREE_VALUE (attr) == NULL_TREE + || TREE_CODE (TREE_VALUE (attr)) != TREE_LIST) + continue; for (arg = TREE_VALUE (attr); arg; arg = TREE_CHAIN (arg)) { tree expr = TREE_VALUE (arg); --- gcc/cp/decl.c.jj 2013-03-20 10:07:19.000000000 +0100 +++ gcc/cp/decl.c 2013-05-02 15:24:39.449467830 +0200 @@ -4368,7 +4368,7 @@ shadow_tag (cp_decl_specifier_seq *decls if (TYPE_FIELDS (t)) { tree decl = grokdeclarator (/*declarator=*/NULL, - declspecs, NORMAL, 0, NULL); + declspecs, NORMAL, 0, NULL, NULL); finish_anon_union (decl); } } @@ -4389,7 +4389,7 @@ groktypename (cp_decl_specifier_seq *typ = is_template_arg ? TEMPLATE_TYPE_ARG : TYPENAME; attrs = type_specifiers->attributes; type_specifiers->attributes = NULL_TREE; - type = grokdeclarator (declarator, type_specifiers, context, 0, &attrs); + type = grokdeclarator (declarator, type_specifiers, context, 0, &attrs, NULL); if (attrs && type != error_mark_node) { if (CLASS_TYPE_P (type)) @@ -4430,7 +4430,8 @@ start_decl (const cp_declarator *declara int initialized, tree attributes, tree prefix_attributes, - tree *pushed_scope_p) + tree *pushed_scope_p, + vec<tree, va_gc> *omp_declare_simd_clauses) { tree decl; tree context; @@ -4448,7 +4449,7 @@ start_decl (const cp_declarator *declara attributes = chainon (attributes, prefix_attributes); decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, - &attributes); + &attributes, omp_declare_simd_clauses); deprecated_state = DEPRECATED_NORMAL; @@ -7323,7 +7324,8 @@ grokfndecl (tree ctype, int template_count, tree in_namespace, tree* attrlist, - location_t location) + location_t location, + vec<tree, va_gc> *omp_declare_simd_clauses) { tree decl; int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE; @@ -7594,6 +7596,9 @@ grokfndecl (tree ctype, if (TYPE_NOTHROW_P (type) || nothrow_libfn_p (decl)) TREE_NOTHROW (decl) = 1; + if (omp_declare_simd_clauses) + finish_omp_declare_simd (decl, omp_declare_simd_clauses); + /* Caller will do the rest of this. */ if (check < 0) return decl; @@ -8589,7 +8595,8 @@ grokdeclarator (const cp_declarator *dec cp_decl_specifier_seq *declspecs, enum decl_context decl_context, int initialized, - tree* attrlist) + tree* attrlist, + vec<tree, va_gc> *omp_declare_simd_clauses) { tree type = NULL_TREE; int longlong = 0; @@ -10416,7 +10423,8 @@ grokdeclarator (const cp_declarator *dec inlinep | (2 * constexpr_p), sfk, funcdef_flag, template_count, in_namespace, - attrlist, declarator->id_loc); + attrlist, declarator->id_loc, + omp_declare_simd_clauses); decl = set_virt_specifiers (decl, virt_specifiers); if (decl == NULL_TREE) return error_mark_node; @@ -10637,7 +10645,8 @@ grokdeclarator (const cp_declarator *dec publicp, inlinep | (2 * constexpr_p), sfk, funcdef_flag, template_count, in_namespace, attrlist, - declarator->id_loc); + declarator->id_loc, + omp_declare_simd_clauses); if (decl == NULL_TREE) return error_mark_node; @@ -13313,11 +13322,12 @@ start_preparsed_function (tree decl1, tr int start_function (cp_decl_specifier_seq *declspecs, const cp_declarator *declarator, - tree attrs) + tree attrs, vec<tree, va_gc> *omp_declare_simd_clauses) { tree decl1; - decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, &attrs); + decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, &attrs, + omp_declare_simd_clauses); if (decl1 == error_mark_node) return 0; /* If the declarator is not suitable for a function definition, @@ -13959,10 +13969,11 @@ finish_function (int flags) tree grokmethod (cp_decl_specifier_seq *declspecs, - const cp_declarator *declarator, tree attrlist) + const cp_declarator *declarator, tree attrlist, + vec<tree, va_gc> *omp_declare_simd_clauses) { tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0, - &attrlist); + &attrlist, omp_declare_simd_clauses); if (fndecl == error_mark_node) return error_mark_node; --- gcc/cp/decl.h.jj 2013-03-20 10:07:19.000000000 +0100 +++ gcc/cp/decl.h 2013-05-02 15:19:31.331158878 +0200 @@ -34,7 +34,7 @@ enum decl_context /* We need this in here to get the decl_context definition. */ extern tree grokdeclarator (const cp_declarator *, cp_decl_specifier_seq *, - enum decl_context, int, tree*); + enum decl_context, int, tree*, vec<tree, va_gc> *); /* States indicating how grokdeclarator() should handle declspecs marked with __attribute__((deprecated)). An object declared as --- gcc/cp/parser.c.jj 2013-04-30 18:03:33.847124246 +0200 +++ gcc/cp/parser.c 2013-05-02 15:54:49.833404915 +0200 @@ -1169,6 +1169,41 @@ cp_token_cache_new (cp_token *first, cp_ return cache; } +/* Diagnose if #pragma omp declare simd isn't followed immediately + by function declaration or definition. */ + +static inline void +cp_ensure_no_omp_declare_simd (cp_parser *parser) +{ + if (parser->omp_declare_simd_clauses + && (*parser->omp_declare_simd_clauses)[0] != error_mark_node) + { + error ("%<#pragma omp declare simd%> not immediately followed by " + "function declaration or definition"); + parser->omp_declare_simd_clauses = NULL; + } +} + +/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed, + and put that into "omp declare simd" attribute. */ + +static inline void +cp_finish_omp_declare_simd (cp_parser *parser, tree fndecl) +{ + if (__builtin_expect (parser->omp_declare_simd_clauses != NULL, 0)) + { + if (fndecl == error_mark_node) + { + parser->omp_declare_simd_clauses = NULL; + return; + } + if (TREE_CODE (fndecl) != FUNCTION_DECL) + { + cp_ensure_no_omp_declare_simd (parser); + return; + } + } +} /* Decl-specifiers. */ @@ -2149,7 +2184,13 @@ static bool cp_parser_function_transacti static tree cp_parser_transaction_cancel (cp_parser *); -enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; +enum pragma_context { + pragma_external, + pragma_member, + pragma_objc_icode, + pragma_stmt, + pragma_compound +}; static bool cp_parser_pragma (cp_parser *, enum pragma_context); @@ -8126,7 +8167,7 @@ cp_parser_trait_expr (cp_parser* parser, /* Call grokdeclarator to figure out what type this is. */ type1 = grokdeclarator (NULL, &decl_specs, TYPENAME, - /*initialized=*/0, /*attrlist=*/NULL); + /*initialized=*/0, /*attrlist=*/NULL, NULL); if (binary) { @@ -8143,7 +8184,7 @@ cp_parser_trait_expr (cp_parser* parser, /* Call grokdeclarator to figure out what type this is. */ type2 = grokdeclarator (NULL, &decl_specs, TYPENAME, - /*initialized=*/0, /*attrlist=*/NULL); + /*initialized=*/0, /*attrlist=*/NULL, NULL); } cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); @@ -8600,9 +8641,7 @@ cp_parser_lambda_declarator_opt (cp_pars /*late_return_type=*/NULL_TREE); declarator->id_loc = LAMBDA_EXPR_LOCATION (lambda_expr); - fco = grokmethod (&return_type_specs, - declarator, - attributes); + fco = grokmethod (&return_type_specs, declarator, attributes, NULL); if (fco != error_mark_node) { DECL_INITIALIZED_IN_CLASS_P (fco) = 1; @@ -9447,7 +9486,7 @@ cp_parser_condition (cp_parser* parser) decl = start_decl (declarator, &type_specifiers, /*initialized_p=*/true, attributes, /*prefix_attributes=*/NULL_TREE, - &pushed_scope); + &pushed_scope, NULL); /* Parse the initializer. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) @@ -11154,6 +11193,8 @@ cp_parser_linkage_specification (cp_pars production. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { + cp_ensure_no_omp_declare_simd (parser); + /* Consume the `{' token. */ cp_lexer_consume_token (parser->lexer); /* Parse the declarations. */ @@ -11524,7 +11565,7 @@ cp_parser_conversion_type_id (cp_parser* declarator = cp_parser_conversion_declarator_opt (parser); type_specified = grokdeclarator (declarator, &type_specifiers, TYPENAME, - /*initialized=*/0, &attributes); + /*initialized=*/0, &attributes, NULL); if (attributes) cplus_decl_attributes (&type_specified, attributes, /*flags=*/0); @@ -12398,7 +12439,7 @@ cp_parser_template_parameter (cp_parser* parm = grokdeclarator (parameter_declarator->declarator, ¶meter_declarator->decl_specifiers, TPARM, /*initialized=*/0, - /*attrlist=*/NULL); + /*attrlist=*/NULL, NULL); if (parm == error_mark_node) return error_mark_node; @@ -13449,7 +13490,7 @@ cp_parser_explicit_instantiation (cp_par " %<constexpr%> specifier"); decl = grokdeclarator (declarator, &decl_specifiers, - NORMAL, 0, &decl_specifiers.attributes); + NORMAL, 0, &decl_specifiers.attributes, NULL); /* Turn access control back on for names used during template instantiation. */ pop_deferring_access_checks (); @@ -14702,7 +14743,7 @@ cp_parser_enum_specifier (cp_parser* par if (type_specifiers.type != error_mark_node) { underlying_type = grokdeclarator (NULL, &type_specifiers, TYPENAME, - /*initialized=*/0, NULL); + /*initialized=*/0, NULL, NULL); if (underlying_type == error_mark_node) underlying_type = NULL_TREE; } @@ -15049,6 +15090,7 @@ cp_parser_namespace_definition (cp_parse bool has_visibility; bool is_inline; + cp_ensure_no_omp_declare_simd (parser); if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE)) { maybe_warn_cpp0x (CPP0X_INLINE_NAMESPACES); @@ -15443,10 +15485,10 @@ cp_parser_alias_declaration (cp_parser* member_p = at_class_scope_p (); if (member_p) decl = grokfield (declarator, &decl_specs, NULL_TREE, false, - NULL_TREE, attributes); + NULL_TREE, attributes, NULL); else decl = start_decl (declarator, &decl_specs, 0, - attributes, NULL_TREE, &pushed_scope); + attributes, NULL_TREE, &pushed_scope, NULL); if (decl == error_mark_node) return decl; @@ -15981,7 +16023,8 @@ cp_parser_init_declarator (cp_parser* pa decl = start_decl (declarator, decl_specifiers, range_for_decl_p? SD_INITIALIZED : is_initialized, attributes, prefix_attributes, - &pushed_scope); + &pushed_scope, parser->omp_declare_simd_clauses); + cp_finish_omp_declare_simd (parser, decl); /* Adjust location of decl if declarator->id_loc is more appropriate: set, and decl wasn't merged with another decl, in which case its location would be different from input_location, and more accurate. */ @@ -16088,9 +16131,10 @@ cp_parser_init_declarator (cp_parser* pa decl = grokfield (declarator, decl_specifiers, initializer, !is_non_constant_init, /*asmspec=*/NULL_TREE, - prefix_attributes); + prefix_attributes, parser->omp_declare_simd_clauses); if (decl && TREE_CODE (decl) == FUNCTION_DECL) cp_parser_save_default_args (parser, decl); + cp_finish_omp_declare_simd (parser, decl); } /* Finish processing the declaration. But, skip member @@ -17425,7 +17469,7 @@ cp_parser_parameter_declaration_list (cp ¶meter->decl_specifiers, PARM, parameter->default_argument != NULL_TREE, - ¶meter->decl_specifiers.attributes); + ¶meter->decl_specifiers.attributes, NULL); deprecated_state = DEPRECATED_NORMAL; @@ -18302,6 +18346,8 @@ cp_parser_class_specifier_1 (cp_parser* return error_mark_node; } + cp_ensure_no_omp_declare_simd (parser); + /* Issue an error message if type-definitions are forbidden here. */ cp_parser_check_type_definition (parser); /* Remember that we are defining one more class. */ @@ -19079,7 +19125,7 @@ cp_parser_member_specification_opt (cp_p /* Accept #pragmas at class scope. */ if (token->type == CPP_PRAGMA) { - cp_parser_pragma (parser, pragma_external); + cp_parser_pragma (parser, pragma_member); break; } @@ -19531,13 +19577,15 @@ cp_parser_member_declaration (cp_parser* else if (declarator->kind == cdk_function) declarator->id_loc = token->location; - /* Create the declaration. */ - decl = grokfield (declarator, &decl_specifiers, - initializer, /*init_const_expr_p=*/true, - asm_specification, - attributes); + /* Create the declaration. */ + decl = grokfield (declarator, &decl_specifiers, + initializer, /*init_const_expr_p=*/true, + asm_specification, + attributes, parser->omp_declare_simd_clauses); } + cp_finish_omp_declare_simd (parser, decl); + /* Reset PREFIX_ATTRIBUTES. */ while (attributes && TREE_CHAIN (attributes) != first_attribute) attributes = TREE_CHAIN (attributes); @@ -20230,7 +20278,8 @@ cp_parser_exception_declaration (cp_pars if (!type_specifiers.any_specifiers_p) return error_mark_node; - return grokdeclarator (declarator, &type_specifiers, CATCHPARM, 1, NULL); + return grokdeclarator (declarator, &type_specifiers, CATCHPARM, 1, + NULL, NULL); } /* Parse a throw-expression. @@ -21666,7 +21715,8 @@ cp_parser_function_definition_from_speci bool success_p; /* Begin the function-definition. */ - success_p = start_function (decl_specifiers, declarator, attributes); + success_p = start_function (decl_specifiers, declarator, attributes, + parser->omp_declare_simd_clauses); /* The things we're about to see are not directly qualified by any template headers we've seen thus far. */ @@ -21678,6 +21728,12 @@ cp_parser_function_definition_from_speci might be a friend. */ perform_deferred_access_checks (tf_warning_or_error); + if (success_p) + { + cp_finish_omp_declare_simd (parser, current_function_decl); + parser->omp_declare_simd_clauses = NULL; + } + if (!success_p) { /* Skip the entire function. */ @@ -22196,7 +22252,9 @@ cp_parser_save_member_function_body (cp_ tree fn; /* Create the FUNCTION_DECL. */ - fn = grokmethod (decl_specifiers, declarator, attributes); + fn = grokmethod (decl_specifiers, declarator, attributes, + parser->omp_declare_simd_clauses); + cp_finish_omp_declare_simd (parser, fn); /* If something went badly wrong, bail out now. */ if (fn == error_mark_node) { @@ -22698,7 +22756,7 @@ cp_parser_sizeof_operand (cp_parser* par &decl_specs, TYPENAME, /*initialized=*/0, - /*attrlist=*/NULL); + /*attrlist=*/NULL, NULL); } } else if (pack_expansion_p) @@ -24500,7 +24558,7 @@ cp_parser_objc_method_tail_params_opt (c parm = grokdeclarator (parmdecl->declarator, &parmdecl->decl_specifiers, PARM, /*initialized=*/0, - /*attrlist=*/NULL); + /*attrlist=*/NULL, NULL); chainon (params, build_tree_list (NULL_TREE, parm)); token = cp_lexer_peek_token (parser->lexer); @@ -24544,7 +24602,7 @@ cp_parser_objc_interstitial_code (cp_par cp_parser_linkage_specification (parser); /* Handle #pragma, if any. */ else if (token->type == CPP_PRAGMA) - cp_parser_pragma (parser, pragma_external); + cp_parser_pragma (parser, pragma_objc_icode); /* Allow stray semicolons. */ else if (token->type == CPP_SEMICOLON) cp_lexer_consume_token (parser->lexer); @@ -24848,7 +24906,7 @@ cp_parser_objc_class_ivars (cp_parser* p else decl = grokfield (declarator, &declspecs, NULL_TREE, /*init_const_expr_p=*/false, - NULL_TREE, attributes); + NULL_TREE, attributes, NULL); /* Add the instance variable. */ if (decl != error_mark_node && decl != NULL_TREE) @@ -25182,7 +25240,7 @@ cp_parser_objc_try_catch_finally_stateme parameter_declaration = grokdeclarator (parm->declarator, &parm->decl_specifiers, PARM, /*initialized=*/0, - /*attrlist=*/NULL); + /*attrlist=*/NULL, NULL); } if (seen_open_paren) cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); @@ -25392,7 +25450,7 @@ cp_parser_objc_struct_declaration (cp_pa decl = grokfield (declarator, &declspecs, NULL_TREE, /*init_const_expr_p=*/false, - NULL_TREE, attributes); + NULL_TREE, attributes, NULL); if (decl == error_mark_node || decl == NULL_TREE) return error_mark_node; @@ -25887,20 +25945,25 @@ cp_parser_omp_var_list_no_open (cp_parse tree name, decl; token = cp_lexer_peek_token (parser->lexer); - name = cp_parser_id_expression (parser, /*template_p=*/false, - /*check_dependency_p=*/true, - /*template_p=*/NULL, - /*declarator_p=*/false, - /*optional_p=*/false); - if (name == error_mark_node) + if (parser->omp_declare_simd_clauses) + decl = name = cp_parser_identifier (parser); + else { - if (colon) - parser->colon_corrects_to_scope_p - = saved_colon_corrects_to_scope_p; - goto skip_comma; - } + name = cp_parser_id_expression (parser, /*template_p=*/false, + /*check_dependency_p=*/true, + /*template_p=*/NULL, + /*declarator_p=*/false, + /*optional_p=*/false); + if (name == error_mark_node) + { + if (colon) + parser->colon_corrects_to_scope_p + = saved_colon_corrects_to_scope_p; + goto skip_comma; + } - decl = cp_parser_lookup_name_simple (parser, name, token->location); + decl = cp_parser_lookup_name_simple (parser, name, token->location); + } if (decl == error_mark_node) cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, token->location); @@ -27040,6 +27103,8 @@ cp_parser_omp_all_clauses (cp_parser *pa } saw_error: cp_parser_skip_to_pragma_eol (parser, pragma_tok); + if (parser->omp_declare_simd_clauses) + return clauses; return finish_omp_clauses (clauses); } @@ -27799,7 +27864,7 @@ cp_parser_omp_for_loop (cp_parser *parse decl = start_decl (declarator, &type_specifiers, SD_INITIALIZED, attributes, /*prefix_attributes=*/NULL_TREE, - &pushed_scope); + &pushed_scope, NULL); auto_node = type_uses_auto (TREE_TYPE (decl)); if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)) @@ -28599,6 +28664,91 @@ cp_parser_omp_cancellation_point (cp_par finish_omp_cancellation_point (clauses); } +/* OpenMP 4.0: + # pragma omp declare simd declare-simd-clauses[optseq] new-line */ + +#define OMP_DECLARE_SIMD_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH)) + +static void +cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + bool first_p = parser->omp_declare_simd_clauses == NULL; + vec_safe_push (parser->omp_declare_simd_clauses, NULL_TREE); + tree clauses + = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, + "#pragma omp declare simd", pragma_tok); + parser->omp_declare_simd_clauses->last () = clauses; + if (first_p) + { + while (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA)) + cp_parser_pragma (parser, context); + switch (context) + { + case pragma_external: + cp_parser_declaration (parser); + break; + case pragma_member: + cp_parser_member_declaration (parser); + break; + case pragma_objc_icode: + cp_parser_block_declaration (parser, /*statement_p=*/false); + break; + default: + cp_parser_declaration_statement (parser); + break; + } + if (parser->omp_declare_simd_clauses + && (*parser->omp_declare_simd_clauses)[0] != error_mark_node + && (*parser->omp_declare_simd_clauses)[0] != integer_zero_node) + error_at (pragma_tok->location, + "%<#pragma omp declare simd%> not immediately followed by " + "function declaration or definition"); + parser->omp_declare_simd_clauses = NULL; + } +} + +/* OpenMP 4.0 + #pragma omp declare simd declare-simd-clauses[optseq] new-line + #pragma omp declare reduction (reduction-id : typename-list : expression) \ + identity-clause[opt] new-line */ + +static void +cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp (p, "simd") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_declare_simd (parser, pragma_tok, + context); + return; + } + cp_ensure_no_omp_declare_simd (parser); +/* if (strcmp (p, "reduction") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_declare_reduction (parser, pragma_tok, + context); + return; + } */ + } + cp_parser_error (parser, "expected %<simd%> or %<reduction%>"); + cp_parser_require_pragma_eol (parser, pragma_tok); +} + /* Main entry point to OpenMP statement pragmas. */ static void @@ -28998,6 +29148,8 @@ cp_parser_pragma (cp_parser *parser, enu parser->lexer->in_pragma = true; id = pragma_tok->pragma_kind; + if (id != PRAGMA_OMP_DECLARE_REDUCTION) + cp_ensure_no_omp_declare_simd (parser); switch (id) { case PRAGMA_GCC_PCH_PREPROCESS: @@ -29103,6 +29255,10 @@ cp_parser_pragma (cp_parser *parser, enu cp_parser_omp_threadprivate (parser, pragma_tok); return false; + case PRAGMA_OMP_DECLARE_REDUCTION: + cp_parser_omp_declare (parser, pragma_tok, context); + return false; + case PRAGMA_OMP_ATOMIC: case PRAGMA_OMP_CRITICAL: case PRAGMA_OMP_FOR: @@ -29114,7 +29270,7 @@ cp_parser_pragma (cp_parser *parser, enu case PRAGMA_OMP_SINGLE: case PRAGMA_OMP_TASK: case PRAGMA_OMP_TASKGROUP: - if (context == pragma_external) + if (context != pragma_stmt && context != pragma_compound) goto bad_stmt; cp_parser_omp_construct (parser, pragma_tok); return true; --- gcc/cp/parser.h.jj 2013-04-30 18:00:00.578297018 +0200 +++ gcc/cp/parser.h 2013-05-02 15:51:18.285572977 +0200 @@ -340,6 +340,15 @@ typedef struct GTY(()) cp_parser { /* The number of template parameter lists that apply directly to the current declaration. */ unsigned num_template_parameter_lists; + + /* When parsing #pragma omp declare simd, this is a vector of + the clauses, each tree is either NULL_TREE, or OMP_CLAUSE + with optional chain of other clauses. If error regarding + omp declare simd has been reported already, either + omp_declare_simd_clauses is set to NULL, or first element set + to error_mark_node. If a FUNCTION_DECL has been seen already, + first element is set to integer_zero_node. */ + vec<tree, va_gc> *omp_declare_simd_clauses; } cp_parser; /* In parser.c */ --- gcc/cp/pt.c.jj 2013-04-30 18:03:33.000000000 +0200 +++ gcc/cp/pt.c 2013-05-06 15:17:20.725304601 +0200 @@ -8431,6 +8431,8 @@ can_complete_type_without_circularity (t return 1; } +static tree tsubst_omp_clauses (tree, bool, tree, tsubst_flags_t, tree); + /* Apply any attributes which had to be deferred until instantiation time. DECL_P, ATTRIBUTES and ATTR_FLAGS are as cplus_decl_attributes; ARGS, COMPLAIN, IN_DECL are as tsubst. */ @@ -8472,15 +8474,28 @@ apply_late_template_attributes (tree *de { *p = TREE_CHAIN (t); TREE_CHAIN (t) = NULL_TREE; + if (flag_openmp + && is_attribute_p ("omp declare simd", + get_attribute_name (t)) + && TREE_VALUE (t)) + { + tree clauses = TREE_VALUE (t); + clauses = tsubst_omp_clauses (clauses, true, args, + complain, in_decl); + c_omp_declare_simd_clauses_to_decls (*decl_p, clauses); + clauses = finish_omp_clauses (clauses); + TREE_VALUE (t) + = c_omp_declare_simd_clauses_to_numbers (*decl_p, clauses); + } /* If the first attribute argument is an identifier, don't pass it through tsubst. Attributes like mode, format, cleanup and several target specific attributes expect it unmodified. */ - if (TREE_VALUE (t) - && TREE_CODE (TREE_VALUE (t)) == TREE_LIST - && TREE_VALUE (TREE_VALUE (t)) - && (TREE_CODE (TREE_VALUE (TREE_VALUE (t))) - == IDENTIFIER_NODE)) + else if (TREE_VALUE (t) + && TREE_CODE (TREE_VALUE (t)) == TREE_LIST + && TREE_VALUE (TREE_VALUE (t)) + && (TREE_CODE (TREE_VALUE (TREE_VALUE (t))) + == IDENTIFIER_NODE)) { tree chain = tsubst_expr (TREE_CHAIN (TREE_VALUE (t)), args, complain, @@ -12562,8 +12577,8 @@ tsubst_copy (tree t, tree args, tsubst_f /* Like tsubst_copy, but specifically for OpenMP clauses. */ static tree -tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain, - tree in_decl) +tsubst_omp_clauses (tree clauses, bool declare_simd, + tree args, tsubst_flags_t complain, tree in_decl) { tree new_clauses = NULL, nc, oc; @@ -12596,22 +12611,52 @@ tsubst_omp_clauses (tree clauses, tree a case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_FINAL: + case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: OMP_CLAUSE_OPERAND (nc, 0) = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl, /*integral_constant_expression_p=*/false); break; + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_ALIGNED: + OMP_CLAUSE_OPERAND (nc, 0) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, + in_decl, /*integral_constant_expression_p=*/false); + OMP_CLAUSE_OPERAND (nc, 1) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, + in_decl, /*integral_constant_expression_p=*/false); + break; + case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: break; default: gcc_unreachable (); } } - return finish_omp_clauses (nreverse (new_clauses)); + new_clauses = nreverse (new_clauses); + if (!declare_simd) + new_clauses = finish_omp_clauses (new_clauses); + return new_clauses; } /* Like tsubst_copy_and_build, but unshare TREE_LIST nodes. */ @@ -13181,7 +13226,7 @@ tsubst_expr (tree t, tree args, tsubst_f break; case OMP_PARALLEL: - tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), + tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false, args, complain, in_decl); stmt = begin_omp_parallel (); RECUR (OMP_PARALLEL_BODY (t)); @@ -13190,7 +13235,7 @@ tsubst_expr (tree t, tree args, tsubst_f break; case OMP_TASK: - tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), + tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false, args, complain, in_decl); stmt = begin_omp_task (); RECUR (OMP_TASK_BODY (t)); @@ -13206,7 +13251,7 @@ tsubst_expr (tree t, tree args, tsubst_f tree declv, initv, condv, incrv; int i; - clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), + clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false, args, complain, in_decl); declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); initv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); @@ -13237,7 +13282,8 @@ tsubst_expr (tree t, tree args, tsubst_f case OMP_SECTIONS: case OMP_SINGLE: - tmp = tsubst_omp_clauses (OMP_CLAUSES (t), args, complain, in_decl); + tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, + args, complain, in_decl); stmt = push_stmt_list (); RECUR (OMP_BODY (t)); stmt = pop_stmt_list (stmt); --- gcc/cp/semantics.c.jj 2013-04-30 18:03:33.000000000 +0200 +++ gcc/cp/semantics.c 2013-05-06 15:46:54.200232432 +0200 @@ -4028,6 +4028,7 @@ finish_omp_clauses (tree clauses) bitmap_head aligned_head; tree c, t, *pc = &clauses; const char *name; + bool branch_seen = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -4426,8 +4427,6 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_MERGEABLE: - case OMP_CLAUSE_INBRANCH: - case OMP_CLAUSE_NOTINBRANCH: case OMP_CLAUSE_PARALLEL: case OMP_CLAUSE_FOR: case OMP_CLAUSE_SECTIONS: @@ -4435,6 +4434,17 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_PROC_BIND: break; + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + if (branch_seen) + { + error ("%<inbranch%> clause is incompatible with " + "%<notinbranch%>"); + remove = true; + } + branch_seen = true; + break; + default: gcc_unreachable (); } @@ -4619,6 +4629,90 @@ finish_omp_clauses (tree clauses) return clauses; } +/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed, + and put that into "omp declare simd" attribute. */ + +void +finish_omp_declare_simd (tree fndecl, vec<tree, va_gc> *clauses) +{ + tree cl; + int i; + + if (TREE_CODE (fndecl) != FUNCTION_DECL) + return; + if ((*clauses)[0] == integer_zero_node) + { + error_at (DECL_SOURCE_LOCATION (fndecl), + "%<#pragma omp declare simd%> not immediately followed by " + "a single function declaration or definition"); + (*clauses)[0] = error_mark_node; + return; + } + if ((*clauses)[0] == error_mark_node) + return; + + FOR_EACH_VEC_SAFE_ELT (clauses, i, cl) + { + tree c, *pc, decl, name; + for (pc = &cl, c = cl; c; c = *pc) + { + bool remove = false; + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_REDUCTION: + name = OMP_CLAUSE_DECL (c); + if (name == error_mark_node) + remove = true; + else + { + for (decl = DECL_ARGUMENTS (fndecl); decl; + decl = TREE_CHAIN (decl)) + if (DECL_NAME (decl) == name) + break; + if (decl == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a function parameter", name); + remove = true; + } + else + OMP_CLAUSE_DECL (c) = decl; + } + break; + default: + break; + } + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + cl = finish_omp_clauses (cl); + cl = c_omp_declare_simd_clauses_to_numbers (fndecl, cl); + if (!processing_template_decl) + { + for (c = lookup_attribute ("omp declare simd", + DECL_ATTRIBUTES (fndecl)); + c; c = lookup_attribute ("omp declare simd", + TREE_CHAIN (c))) + if (omp_declare_simd_clauses_equal (TREE_VALUE (c), cl)) + break; + if (c) + continue; + } + c = build_tree_list (get_identifier ("omp declare simd"), cl); + TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl); + if (processing_template_decl) + ATTR_IS_DEPENDENT (c) = 1; + DECL_ATTRIBUTES (fndecl) = c; + } + + (*clauses)[0] = integer_zero_node; +} + /* For all variables in the tree_list VARS, mark them as thread local. */ void --- gcc/testsuite/g++.dg/gomp/declare-simd-1.C.jj 2013-05-02 13:09:28.009970712 +0200 +++ gcc/testsuite/g++.dg/gomp/declare-simd-1.C 2013-05-06 15:49:22.454392922 +0200 @@ -0,0 +1,212 @@ +// Test parsing of #pragma omp declare simd +// { dg-do compile } + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) \ + linear (c : 4) simdlen (8) notinbranch +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a \ + : 4) simdlen (4) inbranch +int f1 (int a, int *b, int c); + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) +int f2 (int a, int *b, int c) +{ + return a + *b + c; +} + +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) +template <typename T> +T f3 (int a, int *b, T c); + +template <> +int f3 (int, int *, int); + +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) notinbranch simdlen (4) +template <typename T> +int f4 (int a, int *b, T c) +{ + return a + *b + c; +} + +template <> +int f4 (int, int *, int); + +template <typename T> +int f5 (int a, int *b, T c); + +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) +template <> +int f5 (int a, int *b, int c); + +template <int N> +int f6 (int a, int *b, int c); + +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) inbranch simdlen (4) +template <> +int f6<3> (int a, int *b, int c); + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (long long)) linear (c : 4) simdlen (8) +__extension__ +long long f7 (long long a, long long *b, long long c); + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) notinbranch simdlen (8) +extern "C" +int f8 (int a, int *b, int c); + +extern "C" +{ + #pragma omp declare simd + int f9 (int a, int *b, int c); +} + +namespace N1 +{ + namespace N2 + { + #pragma omp declare simd simdlen (2) aligned (b : sizeof (long long) * 2) + __extension__ long long + f10 (long long *b) + { + return *b; + } + } +} + +struct A +{ + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + int f11 (int a, int *b, int c); + + #pragma omp declare simd + template <int N> + int f12 (int a, int *b, int c); + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) notinbranch simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) inbranch + static int f13 (int a, int *b, int c); + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + int f14 (int a, int *b, int c) { return a + *b + c; } + + #pragma omp declare simd + template <int N> + int f15 (int a, int *b, int c) { return a + *b + c; } + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + static int f16 (int a, int *b, int c) { return a + *b + c; } +}; + +template <> +int A::f12<2> (int, int *, int); + +template <> +int A::f15<2> (int, int *, int); + +template <typename T> +struct B +{ + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) notinbranch + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) inbranch + int f17 (int a, int *b, int c); + + #pragma omp declare simd + template <int N> + int f18 (int a, int *b, int c); + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + static int f19 (int a, int *b, int c); + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + int f20 (int a, int *b, int c) { return a + *b + c; } + + #pragma omp declare simd + template <int N> + int f21 (int a, int *b, int c) { return a + *b + c; } + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + static int f22 (int a, int *b, int c) { return a + *b + c; } + + template <int N> + int f23 (int, int *, int); + + template <int N> + static int f24 (int, int *, int); + + template <int N> + int f25 (int, int *, int); + + template <int N> + static int f26 (int, int *, int); +}; + +B <int> b; + +template <> +template <> +int B<int>::f18<0> (int, int *, int); + +template <> +template <> +int B<int>::f21<9> (int, int *, int); + +#pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) uniform (a, c) +template <> +template <> +int B<int>::f23<7> (int a, int *b, int c); + +#pragma omp declare simd simdlen (4) aligned (b : 8 * sizeof (int)) linear (a, c : 2) +template <> +template <> +int B<int>::f24<-1> (int a, int *b, int c); + +#pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) uniform (a, c) +template <> +template <> +int B<int>::f25<7> (int a, int *b, int c) +{ + return a + *b + c; +} + +#pragma omp declare simd simdlen (4) aligned (b : 8 * sizeof (int)) linear (a, c : 2) +template <> +template <> +int B<int>::f26<-1> (int a, int *b, int c) +{ + return a + *b + c; +} + +int +f27 (int x) +{ + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f28 (int a, int *b, int c); + { + x++; + #pragma omp declare simd simdlen (4) linear (c) + extern int f29 (int a, int *b, int c); + } + return x; +} + +#pragma omp declare simd simdlen (16) +int +f30 (int x) +{ + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f31 (int a, int *b, int c); + return x; +} + +template <int N> +struct C +{ + #pragma omp declare simd simdlen (N) aligned (a : N * sizeof (int)) linear (c : N) notinbranch + int f32 (int a, int *b, int c); +}; + +C <2> c; --- gcc/testsuite/g++.dg/gomp/declare-simd-2.C.jj 2013-05-02 13:09:28.009970712 +0200 +++ gcc/testsuite/g++.dg/gomp/declare-simd-2.C 2013-05-06 15:55:10.743401334 +0200 @@ -0,0 +1,60 @@ +// Test parsing of #pragma omp declare simd +// { dg-do compile } + +#pragma omp declare simd +int a; // { dg-error "not immediately followed by function declaration or definition" } + +#pragma omp declare simd +int fn1 (int a), fn2 (int a); // { dg-error "not immediately followed by a single function declaration or definition" } + +#pragma omp declare simd +int b, fn3 (int a); // { dg-error "not immediately followed by function declaration or definition" } + +#pragma omp declare simd linear (a) +int fn4 (int a), c; // { dg-error "not immediately followed by function declaration or definition" } + +#pragma omp declare simd +extern "C" // { dg-error "not immediately followed by function declaration or definition" } +{ + int fn5 (int a); +} + +#pragma omp declare simd // { dg-error "not immediately followed by function declaration or definition" } +namespace N1 +{ + int fn6 (int a); +} + +#pragma omp declare simd simdlen (4) +struct A +{ // { dg-error "not immediately followed by function declaration or definition" } + int fn7 (int a); +}; + +#pragma omp declare simd +template <typename T> +struct B +{ // { dg-error "not immediately followed by function declaration or definition" } + int fn8 (int a); +}; + +struct C +{ +#pragma omp declare simd // { dg-error "not immediately followed by function declaration or definition" } + public: // { dg-error "expected unqualified-id before" } + int fn9 (int a); +}; + +int t; + +#pragma omp declare simd +#pragma omp declare simd +#pragma omp threadprivate(t) // { dg-error "not immediately followed by function declaration or definition" } +int fn10 (int a); + +#pragma omp declare simd inbranch notinbranch +int fn11 (int); // { dg-error "clause is incompatible with" } + +#pragma omp declare simd simdlen (N) // { dg-error "was not declared in this scope" } +template <int N> +int fn12 (int); Jakub