summaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/ChangeLog111
-rw-r--r--gcc/c/c-decl.c176
-rw-r--r--gcc/c/c-lang.h3
-rw-r--r--gcc/c/c-parser.c2526
-rw-r--r--gcc/c/c-tree.h9
-rw-r--r--gcc/c/c-typeck.c1016
6 files changed, 3548 insertions, 293 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index a22d51d8121..e6efc317315 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,114 @@
+2013-10-11 Jakub Jelinek <jakub@redhat.com>
+
+ * c-lang.h (current_omp_declare_target_attribute): New extern
+ decl.
+ * c-parser.c: Include c-lang.h.
+ (struct c_parser): Change tokens to c_token *.
+ Add tokens_buf field. Change tokens_avail type to unsigned int.
+ (c_parser_consume_token): If parser->tokens isn't
+ &parser->tokens_buf[0], increment parser->tokens.
+ (c_parser_consume_pragma): Likewise.
+ (enum pragma_context): Add pragma_struct and pragma_param.
+ (c_parser_external_declaration): Adjust
+ c_parser_declaration_or_fndef caller.
+ (c_parser_declaration_or_fndef): Add omp_declare_simd_clauses
+ argument, if it is non-vNULL vector, call c_finish_omp_declare_simd.
+ Adjust recursive call.
+ (c_parser_struct_or_union_specifier): Use pragma_struct instead
+ of pragma_external.
+ (c_parser_parameter_declaration): Use pragma_param instead of
+ pragma_external.
+ (c_parser_compound_statement_nostart, c_parser_label,
+ c_parser_for_statement): Adjust
+ c_parser_declaration_or_fndef callers.
+ (c_parser_expr_no_commas): Add omp_atomic_lhs argument, pass
+ it through to c_parser_conditional_expression.
+ (c_parser_conditional_expression): Add omp_atomic_lhs argument,
+ pass it through to c_parser_binary_expression. Adjust recursive
+ call.
+ (c_parser_binary_expression): Remove prec argument, add
+ omp_atomic_lhs argument instead. Always start from PREC_NONE, if
+ omp_atomic_lhs is non-NULL and one of the arguments of toplevel
+ binop matches it, use build2 instead of parser_build_binary_op.
+ (c_parser_pragma): Handle PRAGMA_OMP_CANCEL,
+ PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_TARGET,
+ PRAGMA_OMP_END_DECLARE_TARGET, PRAGMA_OMP_DECLARE_REDUCTION.
+ Handle pragma_struct and pragma_param the same as pragma_external.
+ (c_parser_omp_clause_name): Parse new OpenMP 4.0 clause names.
+ (c_parser_omp_variable_list): Parse array sections for
+ OMP_CLAUSE_{DEPEND,MAP,TO,FROM} clauses.
+ (c_parser_omp_clause_collapse): Fully fold collapse expression.
+ (c_parser_omp_clause_reduction): Handle user defined reductions.
+ (c_parser_omp_clause_branch, c_parser_omp_clause_cancelkind,
+ c_parser_omp_clause_num_teams, c_parser_omp_clause_thread_limit,
+ c_parser_omp_clause_aligned, c_parser_omp_clause_linear,
+ c_parser_omp_clause_safelen, c_parser_omp_clause_simdlen,
+ c_parser_omp_clause_depend, c_parser_omp_clause_map,
+ c_parser_omp_clause_device, c_parser_omp_clause_dist_schedule,
+ c_parser_omp_clause_proc_bind, c_parser_omp_clause_to,
+ c_parser_omp_clause_from, c_parser_omp_clause_uniform): New functions.
+ (c_parser_omp_all_clauses): Add finish_p argument. Don't call
+ c_finish_omp_clauses if it is false. Handle new OpenMP 4.0 clauses.
+ (c_parser_omp_atomic): Parse seq_cst clause, pass true if it is
+ present to c_finish_omp_atomic. Handle OpenMP 4.0 atomic forms.
+ (c_parser_omp_for_loop): Add CODE argument, pass it through
+ to c_finish_omp_for. Change last argument to cclauses,
+ and adjust uses to grab parallel clauses from the array of all
+ the split clauses. Adjust c_parser_binary_expression,
+ c_parser_declaration_or_fndef and c_finish_omp_for callers.
+ (omp_split_clauses): New function.
+ (c_parser_omp_simd): New function.
+ (c_parser_omp_for): Add p_name, mask and cclauses arguments.
+ Allow the function to be called also when parsing combined constructs,
+ and call c_parser_omp_simd when parsing for simd.
+ (c_parser_omp_sections_scope): If section-sequence doesn't start with
+ #pragma omp section, require exactly one structured-block instead of
+ sequence of statements.
+ (c_parser_omp_sections): Add p_name, mask and cclauses arguments.
+ Allow the function to be called also when parsing combined constructs.
+ (c_parser_omp_parallel): Add p_name, mask and cclauses arguments.
+ Allow the function to be called also when parsing combined
+ constructs.
+ (c_parser_omp_taskgroup, c_parser_omp_cancel,
+ c_parser_omp_cancellation_point, c_parser_omp_distribute,
+ c_parser_omp_teams, c_parser_omp_target_data,
+ c_parser_omp_target_update, c_parser_omp_target,
+ c_parser_omp_declare_simd, c_finish_omp_declare_simd,
+ c_parser_omp_declare_target, c_parser_omp_end_declare_target,
+ c_parser_omp_declare_reduction, c_parser_omp_declare): New functions.
+ (c_parser_omp_construct): Add p_name and mask vars. Handle
+ PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_SIMD, PRAGMA_OMP_TASKGROUP,
+ PRAGMA_OMP_TEAMS. Adjust c_parser_omp_for, c_parser_omp_parallel
+ and c_parser_omp_sections callers.
+ (c_parse_file): Initialize tparser.tokens and the_parser->tokens here.
+ (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK,
+ OMP_SINGLE_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1.
+ (OMP_PARALLEL_CLAUSE_MASK): Likewise. Add OMP_CLAUSE_PROC_BIND.
+ (OMP_TASK_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1. Add
+ OMP_CLAUSE_DEPEND.
+ (OMP_SIMD_CLAUSE_MASK, OMP_CANCEL_CLAUSE_MASK,
+ OMP_CANCELLATION_POINT_CLAUSE_MASK, OMP_DISTRIBUTE_CLAUSE_MASK,
+ OMP_TEAMS_CLAUSE_MASK, OMP_TARGET_DATA_CLAUSE_MASK,
+ OMP_TARGET_UPDATE_CLAUSE_MASK, OMP_TARGET_CLAUSE_MASK,
+ OMP_DECLARE_SIMD_CLAUSE_MASK): Define.
+ * c-typeck.c: Include tree-inline.h.
+ (c_finish_omp_cancel, c_finish_omp_cancellation_point,
+ handle_omp_array_sections_1, handle_omp_array_sections,
+ c_clone_omp_udr, c_find_omp_placeholder_r): New functions.
+ (c_finish_omp_clauses): Handle new OpenMP 4.0 clauses and
+ user defined reductions.
+ (c_tree_equal): New function.
+ * c-tree.h (temp_store_parm_decls, temp_pop_parm_decls,
+ c_finish_omp_cancel, c_finish_omp_cancellation_point, c_tree_equal,
+ c_omp_reduction_id, c_omp_reduction_decl, c_omp_reduction_lookup,
+ c_check_omp_declare_reduction_r): New prototypes.
+ * c-decl.c (current_omp_declare_target_attribute): New variable.
+ (c_decl_attributes): New function.
+ (start_decl, start_function): Use it instead of decl_attributes.
+ (temp_store_parm_decls, temp_pop_parm_decls, c_omp_reduction_id,
+ c_omp_reduction_decl, c_omp_reduction_lookup,
+ c_check_omp_declare_reduction_r): New functions.
+
2013-09-25 Tom Tromey <tromey@redhat.com>
* Make-lang.in (c/gccspec.o): Remove.
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index f26334829d8..0554e72703f 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -147,6 +147,9 @@ static bool undef_nested_function;
enum machine_mode c_default_pointer_mode = VOIDmode;
+/* If non-zero, implicit "omp declare target" attribute is added into the
+ attribute lists. */
+int current_omp_declare_target_attribute;
/* Each c_binding structure describes one binding of an identifier to
a decl. All the decls in a scope - irrespective of namespace - are
@@ -3971,6 +3974,35 @@ groktypename (struct c_type_name *type_name, tree *expr,
return type;
}
+/* Wrapper for decl_attributes that adds some implicit attributes
+ to VAR_DECLs or FUNCTION_DECLs. */
+
+static tree
+c_decl_attributes (tree *node, tree attributes, int flags)
+{
+ /* Add implicit "omp declare target" attribute if requested. */
+ if (current_omp_declare_target_attribute
+ && ((TREE_CODE (*node) == VAR_DECL && TREE_STATIC (*node))
+ || TREE_CODE (*node) == FUNCTION_DECL))
+ {
+ if (TREE_CODE (*node) == VAR_DECL
+ && ((DECL_CONTEXT (*node)
+ && TREE_CODE (DECL_CONTEXT (*node)) == FUNCTION_DECL)
+ || (current_function_decl && !DECL_EXTERNAL (*node))))
+ error ("%q+D in block scope inside of declare target directive",
+ *node);
+ else if (TREE_CODE (*node) == VAR_DECL
+ && !COMPLETE_TYPE_P (TREE_TYPE (*node)))
+ error ("%q+D in declare target directive does not have mappable type",
+ *node);
+ else
+ attributes = tree_cons (get_identifier ("omp declare target"),
+ NULL_TREE, attributes);
+ }
+ return decl_attributes (node, attributes, flags);
+}
+
+
/* Decode a declarator in an ordinary declaration or data definition.
This is called as soon as the type information and variable name
have been parsed, before parsing the initializer if any.
@@ -4105,7 +4137,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
DECL_COMMON (decl) = 1;
/* Set attributes here so if duplicate decl, will have proper attributes. */
- decl_attributes (&decl, attributes, 0);
+ c_decl_attributes (&decl, attributes, 0);
/* Handle gnu_inline attribute. */
if (declspecs->inline_p
@@ -7727,7 +7759,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
loc = DECL_SOURCE_LOCATION (decl1);
- decl_attributes (&decl1, attributes, 0);
+ c_decl_attributes (&decl1, attributes, 0);
if (DECL_DECLARED_INLINE_P (decl1)
&& DECL_UNINLINABLE (decl1)
@@ -8324,6 +8356,44 @@ store_parm_decls (void)
if (arg_info->pending_sizes)
add_stmt (arg_info->pending_sizes);
}
+
+/* Store PARM_DECLs in PARMS into scope temporarily. Used for
+ c_finish_omp_declare_simd for function prototypes. No diagnostics
+ should be done. */
+
+void
+temp_store_parm_decls (tree fndecl, tree parms)
+{
+ push_scope ();
+ for (tree p = parms; p; p = DECL_CHAIN (p))
+ {
+ DECL_CONTEXT (p) = fndecl;
+ if (DECL_NAME (p))
+ bind (DECL_NAME (p), p, current_scope,
+ /*invisible=*/false, /*nested=*/false,
+ UNKNOWN_LOCATION);
+ }
+}
+
+/* Undo what temp_store_parm_decls did. */
+
+void
+temp_pop_parm_decls (void)
+{
+ /* Clear all bindings in this temporary scope, so that
+ pop_scope doesn't create a BLOCK. */
+ struct c_binding *b = current_scope->bindings;
+ current_scope->bindings = NULL;
+ for (; b; b = free_binding_and_advance (b))
+ {
+ gcc_assert (TREE_CODE (b->decl) == PARM_DECL);
+ gcc_assert (I_SYMBOL_BINDING (b->id) == b);
+ I_SYMBOL_BINDING (b->id) = b->shadowed;
+ if (b->shadowed && b->shadowed->u.type)
+ TREE_TYPE (b->shadowed->decl) = b->shadowed->u.type;
+ }
+ pop_scope ();
+}
/* Finish up a function declaration and compile that function
@@ -10158,4 +10228,106 @@ c_register_addr_space (const char *word, addr_space_t as)
ridpointers [rid] = id;
}
+/* Return identifier to look up for omp declare reduction. */
+
+tree
+c_omp_reduction_id (enum tree_code reduction_code, tree reduction_id)
+{
+ const char *p = NULL;
+ switch (reduction_code)
+ {
+ case PLUS_EXPR: p = "+"; break;
+ case MULT_EXPR: p = "*"; break;
+ case MINUS_EXPR: p = "-"; break;
+ case BIT_AND_EXPR: p = "&"; break;
+ case BIT_XOR_EXPR: p = "^"; break;
+ case BIT_IOR_EXPR: p = "|"; break;
+ case TRUTH_ANDIF_EXPR: p = "&&"; break;
+ case TRUTH_ORIF_EXPR: p = "||"; break;
+ case MIN_EXPR: p = "min"; break;
+ case MAX_EXPR: p = "max"; break;
+ default:
+ break;
+ }
+
+ if (p == NULL)
+ {
+ if (TREE_CODE (reduction_id) != IDENTIFIER_NODE)
+ return error_mark_node;
+ p = IDENTIFIER_POINTER (reduction_id);
+ }
+
+ const char prefix[] = "omp declare reduction ";
+ size_t lenp = sizeof (prefix);
+ size_t len = strlen (p);
+ char *name = XALLOCAVEC (char, lenp + len);
+ memcpy (name, prefix, lenp - 1);
+ memcpy (name + lenp - 1, p, len + 1);
+ return get_identifier (name);
+}
+
+/* Lookup REDUCTION_ID in the current scope, or create an artificial
+ VAR_DECL, bind it into the current scope and return it. */
+
+tree
+c_omp_reduction_decl (tree reduction_id)
+{
+ struct c_binding *b = I_SYMBOL_BINDING (reduction_id);
+ if (b != NULL && B_IN_CURRENT_SCOPE (b))
+ return b->decl;
+
+ tree decl = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ reduction_id, integer_type_node);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_EXTERNAL (decl) = 1;
+ TREE_STATIC (decl) = 1;
+ TREE_PUBLIC (decl) = 0;
+ bind (reduction_id, decl, current_scope, true, false, BUILTINS_LOCATION);
+ return decl;
+}
+
+/* Lookup REDUCTION_ID in the first scope where it has entry for TYPE. */
+
+tree
+c_omp_reduction_lookup (tree reduction_id, tree type)
+{
+ struct c_binding *b = I_SYMBOL_BINDING (reduction_id);
+ while (b)
+ {
+ tree t;
+ for (t = DECL_INITIAL (b->decl); t; t = TREE_CHAIN (t))
+ if (comptypes (TREE_PURPOSE (t), type))
+ return TREE_VALUE (t);
+ b = b->shadowed;
+ }
+ return error_mark_node;
+}
+
+/* Helper function called via walk_tree, to diagnose invalid
+ #pragma omp declare reduction combiners or initializers. */
+
+tree
+c_check_omp_declare_reduction_r (tree *tp, int *, void *data)
+{
+ tree *vars = (tree *) data;
+ if (SSA_VAR_P (*tp)
+ && !DECL_ARTIFICIAL (*tp)
+ && *tp != vars[0]
+ && *tp != vars[1])
+ {
+ location_t loc = DECL_SOURCE_LOCATION (vars[0]);
+ if (strcmp (IDENTIFIER_POINTER (DECL_NAME (vars[0])), "omp_out") == 0)
+ error_at (loc, "%<#pragma omp declare reduction%> combiner refers to "
+ "variable %qD which is not %<omp_out%> nor %<omp_in%>",
+ *tp);
+ else
+ error_at (loc, "%<#pragma omp declare reduction%> initializer refers "
+ "to variable %qD which is not %<omp_priv%> nor "
+ "%<omp_orig%>",
+ *tp);
+ return *tp;
+ }
+ return NULL_TREE;
+}
+
#include "gt-c-c-decl.h"
diff --git a/gcc/c/c-lang.h b/gcc/c/c-lang.h
index 5ff7cd5422e..cbd5d1fa643 100644
--- a/gcc/c/c-lang.h
+++ b/gcc/c/c-lang.h
@@ -55,5 +55,8 @@ struct GTY(()) language_function {
int warn_about_return_type;
};
+/* If non-zero, implicit "omp declare target" attribute is added into the
+ attribute lists. */
+extern GTY(()) int current_omp_declare_target_attribute;
#endif /* ! GCC_C_LANG_H */
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index b612e29c852..8d609936107 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
#include "timevar.h"
#include "c-family/c-pragma.h"
#include "c-tree.h"
+#include "c-lang.h"
#include "flags.h"
#include "ggc.h"
#include "c-family/c-common.h"
@@ -162,9 +163,12 @@ typedef struct GTY (()) c_token {
tokens of look-ahead; more are not needed for C. */
typedef struct GTY(()) c_parser {
/* The look-ahead tokens. */
- c_token tokens[2];
- /* How many look-ahead tokens are available (0, 1 or 2). */
- short tokens_avail;
+ c_token * GTY((skip)) tokens;
+ /* Buffer for look-ahead tokens. */
+ c_token tokens_buf[2];
+ /* How many look-ahead tokens are available (0, 1 or 2, or
+ more if parsing from pre-lexed tokens). */
+ unsigned int tokens_avail;
/* True if a syntax error is being recovered from; false otherwise.
c_parser_error sets this flag. It should clear this flag when
enough tokens have been consumed to recover from the error. */
@@ -736,7 +740,9 @@ c_parser_consume_token (c_parser *parser)
gcc_assert (parser->tokens[0].type != CPP_EOF);
gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL);
gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA);
- if (parser->tokens_avail == 2)
+ if (parser->tokens != &parser->tokens_buf[0])
+ parser->tokens++;
+ else if (parser->tokens_avail == 2)
parser->tokens[0] = parser->tokens[1];
parser->tokens_avail--;
}
@@ -750,7 +756,9 @@ c_parser_consume_pragma (c_parser *parser)
gcc_assert (!parser->in_pragma);
gcc_assert (parser->tokens_avail >= 1);
gcc_assert (parser->tokens[0].type == CPP_PRAGMA);
- if (parser->tokens_avail == 2)
+ if (parser->tokens != &parser->tokens_buf[0])
+ parser->tokens++;
+ else if (parser->tokens_avail == 2)
parser->tokens[0] = parser->tokens[1];
parser->tokens_avail--;
parser->in_pragma = true;
@@ -1112,7 +1120,7 @@ enum c_parser_prec {
static void c_parser_external_declaration (c_parser *);
static void c_parser_asm_definition (c_parser *);
static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
- bool, bool, tree *);
+ bool, bool, tree *, vec<c_token>);
static void c_parser_static_assert_declaration_no_semi (c_parser *);
static void c_parser_static_assert_declaration (c_parser *);
static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
@@ -1155,11 +1163,12 @@ static tree c_parser_asm_statement (c_parser *);
static tree c_parser_asm_operands (c_parser *);
static tree c_parser_asm_goto_operands (c_parser *);
static tree c_parser_asm_clobbers (c_parser *);
-static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *);
+static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *,
+ tree = NULL_TREE);
static struct c_expr c_parser_conditional_expression (c_parser *,
- struct c_expr *);
+ struct c_expr *, tree);
static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
- enum c_parser_prec);
+ tree);
static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_unary_expression (c_parser *);
static struct c_expr c_parser_sizeof_expression (c_parser *);
@@ -1185,9 +1194,15 @@ static void c_parser_omp_barrier (c_parser *);
static void c_parser_omp_flush (c_parser *);
static void c_parser_omp_taskwait (c_parser *);
static void c_parser_omp_taskyield (c_parser *);
+static void c_parser_omp_cancel (c_parser *);
+static void c_parser_omp_cancellation_point (c_parser *);
-enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
+enum pragma_context { pragma_external, pragma_struct, pragma_param,
+ pragma_stmt, pragma_compound };
static bool c_parser_pragma (c_parser *, enum pragma_context);
+static bool c_parser_omp_target (c_parser *, enum pragma_context);
+static void c_parser_omp_end_declare_target (c_parser *);
+static void c_parser_omp_declare (c_parser *, enum pragma_context);
/* These Objective-C parser functions are only ever called when
compiling Objective-C. */
@@ -1360,11 +1375,14 @@ c_parser_external_declaration (c_parser *parser)
an @interface or @protocol with prefix attributes). We can
only tell which after parsing the declaration specifiers, if
any, and the first declarator. */
- c_parser_declaration_or_fndef (parser, true, true, true, false, true, NULL);
+ c_parser_declaration_or_fndef (parser, true, true, true, false, true,
+ NULL, vNULL);
break;
}
}
+static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
+
/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
6.7, 6.9.1). If FNDEF_OK is true, a function definition is
accepted; otherwise (old-style parameter declarations) only other
@@ -1440,7 +1458,8 @@ static void
c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
bool static_assert_ok, bool empty_ok,
bool nested, bool start_attr_ok,
- tree *objc_foreach_object_declaration)
+ tree *objc_foreach_object_declaration,
+ vec<c_token> omp_declare_simd_clauses)
{
struct c_declspecs *specs;
tree prefix_attrs;
@@ -1610,6 +1629,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
C_DTR_NORMAL, &dummy);
if (declarator == NULL)
{
+ if (omp_declare_simd_clauses.exists ())
+ c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE,
+ omp_declare_simd_clauses);
c_parser_skip_to_end_of_block_or_statement (parser);
return;
}
@@ -1646,6 +1668,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
chainon (postfix_attrs, all_prefix_attrs));
if (!d)
d = error_mark_node;
+ if (omp_declare_simd_clauses.exists ())
+ c_finish_omp_declare_simd (parser, d, NULL_TREE,
+ omp_declare_simd_clauses);
start_init (d, asm_name, global_bindings_p ());
init_loc = c_parser_peek_token (parser)->location;
init = c_parser_initializer (parser);
@@ -1662,6 +1687,28 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
tree d = start_decl (declarator, specs, false,
chainon (postfix_attrs,
all_prefix_attrs));
+ if (omp_declare_simd_clauses.exists ())
+ {
+ tree parms = NULL_TREE;
+ if (d && TREE_CODE (d) == FUNCTION_DECL)
+ {
+ struct c_declarator *ce = declarator;
+ while (ce != NULL)
+ if (ce->kind == cdk_function)
+ {
+ parms = ce->u.arg_info->parms;
+ break;
+ }
+ else
+ ce = ce->declarator;
+ }
+ if (parms)
+ temp_store_parm_decls (d, parms);
+ c_finish_omp_declare_simd (parser, d, parms,
+ omp_declare_simd_clauses);
+ if (parms)
+ temp_pop_parm_decls ();
+ }
if (d)
finish_decl (d, UNKNOWN_LOCATION, NULL_TREE,
NULL_TREE, asm_name);
@@ -1751,8 +1798,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
while (c_parser_next_token_is_not (parser, CPP_EOF)
&& c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
c_parser_declaration_or_fndef (parser, false, false, false,
- true, false, NULL);
+ true, false, NULL, vNULL);
store_parm_decls ();
+ if (omp_declare_simd_clauses.exists ())
+ c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
+ omp_declare_simd_clauses);
DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
= c_parser_peek_token (parser)->location;
fnbody = c_parser_compound_statement (parser);
@@ -2481,7 +2531,7 @@ c_parser_struct_or_union_specifier (c_parser *parser)
/* Accept #pragmas at struct scope. */
if (c_parser_next_token_is (parser, CPP_PRAGMA))
{
- c_parser_pragma (parser, pragma_external);
+ c_parser_pragma (parser, pragma_struct);
continue;
}
/* Parse some comma-separated declarations, but not the
@@ -3329,7 +3379,7 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs)
/* Accept #pragmas between parameter declarations. */
while (c_parser_next_token_is (parser, CPP_PRAGMA))
- c_parser_pragma (parser, pragma_external);
+ c_parser_pragma (parser, pragma_param);
if (!c_parser_next_token_starts_declspecs (parser))
{
@@ -4074,7 +4124,11 @@ c_parser_initval (c_parser *parser, struct c_expr *after,
openmp-directive:
barrier-directive
- flush-directive */
+ flush-directive
+ taskwait-directive
+ taskyield-directive
+ cancel-directive
+ cancellation-point-directive */
static tree
c_parser_compound_statement (c_parser *parser)
@@ -4179,7 +4233,8 @@ c_parser_compound_statement_nostart (c_parser *parser)
{
last_label = false;
mark_valid_location_for_stdc_pragma (false);
- c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL);
+ c_parser_declaration_or_fndef (parser, true, true, true, true,
+ true, NULL, vNULL);
if (last_stmt)
pedwarn_c90 (loc,
(pedantic && !flag_isoc99)
@@ -4207,7 +4262,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
last_label = false;
mark_valid_location_for_stdc_pragma (false);
c_parser_declaration_or_fndef (parser, true, true, true, true,
- true, NULL);
+ true, NULL, vNULL);
/* Following the old parser, __extension__ does not
disable this diagnostic. */
restore_extension_diagnostics (ext);
@@ -4345,7 +4400,8 @@ c_parser_label (c_parser *parser)
c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false,
/*static_assert_ok*/ true,
/*empty_ok*/ true, /*nested*/ true,
- /*start_attr_ok*/ true, NULL);
+ /*start_attr_ok*/ true, NULL,
+ vNULL);
}
}
}
@@ -4408,9 +4464,12 @@ c_parser_label (c_parser *parser)
openmp-construct:
parallel-construct
for-construct
+ simd-construct
+ for-simd-construct
sections-construct
single-construct
parallel-for-construct
+ parallel-for-simd-construct
parallel-sections-construct
master-construct
critical-construct
@@ -4423,6 +4482,12 @@ c_parser_label (c_parser *parser)
for-construct:
for-directive iteration-statement
+ simd-construct:
+ simd-directive iteration-statements
+
+ for-simd-construct:
+ for-simd-directive iteration-statements
+
sections-construct:
sections-directive section-scope
@@ -4432,6 +4497,9 @@ c_parser_label (c_parser *parser)
parallel-for-construct:
parallel-for-directive iteration-statement
+ parallel-for-simd-construct:
+ parallel-for-simd-directive iteration-statement
+
parallel-sections-construct:
parallel-sections-directive section-scope
@@ -4979,7 +5047,7 @@ c_parser_for_statement (c_parser *parser)
else if (c_parser_next_tokens_start_declaration (parser))
{
c_parser_declaration_or_fndef (parser, true, true, true, true, true,
- &object_expression);
+ &object_expression, vNULL);
parser->objc_could_be_foreach_context = false;
if (c_parser_next_token_is_keyword (parser, RID_IN))
@@ -5008,7 +5076,7 @@ c_parser_for_statement (c_parser *parser)
ext = disable_extension_diagnostics ();
c_parser_consume_token (parser);
c_parser_declaration_or_fndef (parser, true, true, true, true,
- true, &object_expression);
+ true, &object_expression, vNULL);
parser->objc_could_be_foreach_context = false;
restore_extension_diagnostics (ext);
@@ -5396,13 +5464,14 @@ c_parser_asm_goto_operands (c_parser *parser)
error. */
static struct c_expr
-c_parser_expr_no_commas (c_parser *parser, struct c_expr *after)
+c_parser_expr_no_commas (c_parser *parser, struct c_expr *after,
+ tree omp_atomic_lhs)
{
struct c_expr lhs, rhs, ret;
enum tree_code code;
location_t op_location, exp_location;
gcc_assert (!after || c_dialect_objc ());
- lhs = c_parser_conditional_expression (parser, after);
+ lhs = c_parser_conditional_expression (parser, after, omp_atomic_lhs);
op_location = c_parser_peek_token (parser)->location;
switch (c_parser_peek_token (parser)->type)
{
@@ -5476,14 +5545,15 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after)
*/
static struct c_expr
-c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
+c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
+ tree omp_atomic_lhs)
{
struct c_expr cond, exp1, exp2, ret;
location_t cond_loc, colon_loc, middle_loc;
gcc_assert (!after || c_dialect_objc ());
- cond = c_parser_binary_expression (parser, after, PREC_NONE);
+ cond = c_parser_binary_expression (parser, after, omp_atomic_lhs);
if (c_parser_next_token_is_not (parser, CPP_QUERY))
return cond;
@@ -5535,7 +5605,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
}
{
location_t exp2_loc = c_parser_peek_token (parser)->location;
- exp2 = c_parser_conditional_expression (parser, NULL);
+ exp2 = c_parser_conditional_expression (parser, NULL, NULL_TREE);
exp2 = default_function_array_read_conversion (exp2_loc, exp2);
}
c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
@@ -5568,8 +5638,13 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
/* Parse a binary expression; that is, a logical-OR-expression (C90
6.3.5-6.3.14, C99 6.5.5-6.5.14). If AFTER is not NULL then it is
an Objective-C message expression which is the primary-expression
- starting the expression as an initializer. PREC is the starting
- precedence, usually PREC_NONE.
+ starting the expression as an initializer.
+
+ OMP_ATOMIC_LHS is NULL, unless parsing OpenMP #pragma omp atomic,
+ when it should be the unfolded lhs. In a valid OpenMP source,
+ one of the operands of the toplevel binary expression must be equal
+ to it. In that case, just return a build2 created binary operation
+ rather than result of parser_build_binary_op.
multiplicative-expression:
cast-expression
@@ -5622,7 +5697,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
static struct c_expr
c_parser_binary_expression (c_parser *parser, struct c_expr *after,
- enum c_parser_prec prec)
+ tree omp_atomic_lhs)
{
/* A binary expression is parsed using operator-precedence parsing,
with the operands being cast expressions. All the binary
@@ -5680,16 +5755,30 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after,
stack[sp].expr \
= default_function_array_read_conversion (stack[sp].loc, \
stack[sp].expr); \
- stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \
- stack[sp].op, \
- stack[sp - 1].expr, \
- stack[sp].expr); \
+ if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1 \
+ && c_parser_peek_token (parser)->type == CPP_SEMICOLON \
+ && ((1 << stack[sp].prec) \
+ & (1 << (PREC_BITOR | PREC_BITXOR | PREC_BITAND | PREC_SHIFT \
+ | PREC_ADD | PREC_MULT))) \
+ && stack[sp].op != TRUNC_MOD_EXPR \
+ && stack[0].expr.value != error_mark_node \
+ && stack[1].expr.value != error_mark_node \
+ && (c_tree_equal (stack[0].expr.value, omp_atomic_lhs) \
+ || c_tree_equal (stack[1].expr.value, omp_atomic_lhs))) \
+ stack[0].expr.value \
+ = build2 (stack[1].op, TREE_TYPE (stack[0].expr.value), \
+ stack[0].expr.value, stack[1].expr.value); \
+ else \
+ stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \
+ stack[sp].op, \
+ stack[sp - 1].expr, \
+ stack[sp].expr); \
sp--; \
} while (0)
gcc_assert (!after || c_dialect_objc ());
stack[0].loc = c_parser_peek_token (parser)->location;
stack[0].expr = c_parser_cast_expression (parser, after);
- stack[0].prec = prec;
+ stack[0].prec = PREC_NONE;
sp = 0;
while (true)
{
@@ -5778,11 +5867,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after,
}
binary_loc = c_parser_peek_token (parser)->location;
while (oprec <= stack[sp].prec)
- {
- if (sp == 0)
- goto out;
- POP;
- }
+ POP;
c_parser_consume_token (parser);
switch (ocode)
{
@@ -7955,7 +8040,7 @@ c_parser_objc_methodprotolist (c_parser *parser)
}
else
c_parser_declaration_or_fndef (parser, false, false, true,
- false, true, NULL);
+ false, true, NULL, vNULL);
break;
}
}
@@ -8936,10 +9021,39 @@ c_parser_pragma (c_parser *parser, enum pragma_context context)
c_parser_omp_taskyield (parser);
return false;
+ case PRAGMA_OMP_CANCEL:
+ if (context != pragma_compound)
+ {
+ if (context == pragma_stmt)
+ c_parser_error (parser, "%<#pragma omp cancel%> may only be "
+ "used in compound statements");
+ goto bad_stmt;
+ }
+ c_parser_omp_cancel (parser);
+ return false;
+
+ case PRAGMA_OMP_CANCELLATION_POINT:
+ if (context != pragma_compound)
+ {
+ if (context == pragma_stmt)
+ c_parser_error (parser, "%<#pragma omp cancellation point%> may "
+ "only be used in compound statements");
+ goto bad_stmt;
+ }
+ c_parser_omp_cancellation_point (parser);
+ return false;
+
case PRAGMA_OMP_THREADPRIVATE:
c_parser_omp_threadprivate (parser);
return false;
+ case PRAGMA_OMP_TARGET:
+ return c_parser_omp_target (parser, context);
+
+ case PRAGMA_OMP_END_DECLARE_TARGET:
+ c_parser_omp_end_declare_target (parser);
+ return false;
+
case PRAGMA_OMP_SECTION:
error_at (c_parser_peek_token (parser)->location,
"%<#pragma omp section%> may only be used in "
@@ -8947,6 +9061,10 @@ c_parser_pragma (c_parser *parser, enum pragma_context context)
c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
return false;
+ case PRAGMA_OMP_DECLARE_REDUCTION:
+ c_parser_omp_declare (parser, context);
+ return false;
+
case PRAGMA_GCC_PCH_PREPROCESS:
c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first");
c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
@@ -8955,7 +9073,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context)
default:
if (id < PRAGMA_FIRST_EXTERNAL)
{
- if (context == pragma_external)
+ if (context != pragma_stmt && context != pragma_compound)
{
bad_stmt:
c_parser_error (parser, "expected declaration specifiers");
@@ -9020,7 +9138,7 @@ c_parser_pragma_pch_preprocess (c_parser *parser)
c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name));
}
-/* OpenMP 2.5 parsing routines. */
+/* OpenMP 2.5 / 3.0 / 3.1 / 4.0 parsing routines. */
/* Returns name of the next clause.
If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and
@@ -9036,12 +9154,18 @@ c_parser_omp_clause_name (c_parser *parser)
result = PRAGMA_OMP_CLAUSE_IF;
else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT))
result = PRAGMA_OMP_CLAUSE_DEFAULT;
+ else if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ result = PRAGMA_OMP_CLAUSE_FOR;
else if (c_parser_next_token_is (parser, CPP_NAME))
{
const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
switch (p[0])
{
+ case 'a':
+ if (!strcmp ("aligned", p))
+ result = PRAGMA_OMP_CLAUSE_ALIGNED;
+ break;
case 'c':
if (!strcmp ("collapse", p))
result = PRAGMA_OMP_CLAUSE_COLLAPSE;
@@ -9050,23 +9174,45 @@ c_parser_omp_clause_name (c_parser *parser)
else if (!strcmp ("copyprivate", p))
result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
break;
+ case 'd':
+ if (!strcmp ("depend", p))
+ result = PRAGMA_OMP_CLAUSE_DEPEND;
+ else if (!strcmp ("device", p))
+ result = PRAGMA_OMP_CLAUSE_DEVICE;
+ else if (!strcmp ("dist_schedule", p))
+ result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE;
+ break;
case 'f':
if (!strcmp ("final", p))
result = PRAGMA_OMP_CLAUSE_FINAL;
else if (!strcmp ("firstprivate", p))
result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
+ else if (!strcmp ("from", p))
+ result = PRAGMA_OMP_CLAUSE_FROM;
+ break;
+ case 'i':
+ if (!strcmp ("inbranch", p))
+ result = PRAGMA_OMP_CLAUSE_INBRANCH;
break;
case 'l':
if (!strcmp ("lastprivate", p))
result = PRAGMA_OMP_CLAUSE_LASTPRIVATE;
+ else if (!strcmp ("linear", p))
+ result = PRAGMA_OMP_CLAUSE_LINEAR;
break;
case 'm':
- if (!strcmp ("mergeable", p))
+ if (!strcmp ("map", p))
+ result = PRAGMA_OMP_CLAUSE_MAP;
+ else if (!strcmp ("mergeable", p))
result = PRAGMA_OMP_CLAUSE_MERGEABLE;
break;
case 'n':
- if (!strcmp ("nowait", p))
+ if (!strcmp ("notinbranch", p))
+ result = PRAGMA_OMP_CLAUSE_NOTINBRANCH;
+ else if (!strcmp ("nowait", p))
result = PRAGMA_OMP_CLAUSE_NOWAIT;
+ else if (!strcmp ("num_teams", p))
+ result = PRAGMA_OMP_CLAUSE_NUM_TEAMS;
else if (!strcmp ("num_threads", p))
result = PRAGMA_OMP_CLAUSE_NUM_THREADS;
break;
@@ -9075,21 +9221,41 @@ c_parser_omp_clause_name (c_parser *parser)
result = PRAGMA_OMP_CLAUSE_ORDERED;
break;
case 'p':
- if (!strcmp ("private", p))
+ if (!strcmp ("parallel", p))
+ result = PRAGMA_OMP_CLAUSE_PARALLEL;
+ else if (!strcmp ("private", p))
result = PRAGMA_OMP_CLAUSE_PRIVATE;
+ else if (!strcmp ("proc_bind", p))
+ result = PRAGMA_OMP_CLAUSE_PROC_BIND;
break;
case 'r':
if (!strcmp ("reduction", p))
result = PRAGMA_OMP_CLAUSE_REDUCTION;
break;
case 's':
- if (!strcmp ("schedule", p))
+ if (!strcmp ("safelen", p))
+ result = PRAGMA_OMP_CLAUSE_SAFELEN;
+ else if (!strcmp ("schedule", p))
result = PRAGMA_OMP_CLAUSE_SCHEDULE;
+ else if (!strcmp ("sections", p))
+ result = PRAGMA_OMP_CLAUSE_SECTIONS;
else if (!strcmp ("shared", p))
result = PRAGMA_OMP_CLAUSE_SHARED;
+ else if (!strcmp ("simdlen", p))
+ result = PRAGMA_OMP_CLAUSE_SIMDLEN;
+ break;
+ case 't':
+ if (!strcmp ("taskgroup", p))
+ result = PRAGMA_OMP_CLAUSE_TASKGROUP;
+ else if (!strcmp ("thread_limit", p))
+ result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT;
+ else if (!strcmp ("to", p))
+ result = PRAGMA_OMP_CLAUSE_TO;
break;
case 'u':
- if (!strcmp ("untied", p))
+ if (!strcmp ("uniform", p))
+ result = PRAGMA_OMP_CLAUSE_UNIFORM;
+ else if (!strcmp ("untied", p))
result = PRAGMA_OMP_CLAUSE_UNTIED;
break;
}
@@ -9133,8 +9299,7 @@ check_no_duplicate_clause (tree clauses, enum omp_clause_code code,
static tree
c_parser_omp_variable_list (c_parser *parser,
location_t clause_loc,
- enum omp_clause_code kind,
- tree list)
+ enum omp_clause_code kind, tree list)
{
if (c_parser_next_token_is_not (parser, CPP_NAME)
|| c_parser_peek_token (parser)->id_kind != C_ID_ID)
@@ -9146,22 +9311,70 @@ c_parser_omp_variable_list (c_parser *parser,
tree t = lookup_name (c_parser_peek_token (parser)->value);
if (t == NULL_TREE)
- undeclared_variable (c_parser_peek_token (parser)->location,
- c_parser_peek_token (parser)->value);
- else if (t == error_mark_node)
+ {
+ undeclared_variable (c_parser_peek_token (parser)->location,
+ c_parser_peek_token (parser)->value);
+ t = error_mark_node;
+ }
+
+ c_parser_consume_token (parser);
+
+ if (t == error_mark_node)
;
else if (kind != 0)
{
- tree u = build_omp_clause (clause_loc, kind);
- OMP_CLAUSE_DECL (u) = t;
- OMP_CLAUSE_CHAIN (u) = list;
- list = u;
+ switch (kind)
+ {
+ case OMP_CLAUSE_MAP:
+ case OMP_CLAUSE_FROM:
+ case OMP_CLAUSE_TO:
+ case OMP_CLAUSE_DEPEND:
+ while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ {
+ tree low_bound = NULL_TREE, length = NULL_TREE;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_next_token_is (parser, CPP_COLON))
+ low_bound = c_parser_expression (parser).value;
+ if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ length = integer_one_node;
+ else
+ {
+ /* Look for `:'. */
+ if (!c_parser_require (parser, CPP_COLON,
+ "expected %<:%>"))
+ {
+ t = error_mark_node;
+ break;
+ }
+ if (!c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ length = c_parser_expression (parser).value;
+ }
+ /* Look for the closing `]'. */
+ if (!c_parser_require (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>"))
+ {
+ t = error_mark_node;
+ break;
+ }
+ t = tree_cons (low_bound, length, t);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (t != error_mark_node)
+ {
+ tree u = build_omp_clause (clause_loc, kind);
+ OMP_CLAUSE_DECL (u) = t;
+ OMP_CLAUSE_CHAIN (u) = list;
+ list = u;
+ }
}
else
list = tree_cons (t, NULL_TREE, list);
- c_parser_consume_token (parser);
-
if (c_parser_next_token_is_not (parser, CPP_COMMA))
break;
@@ -9209,6 +9422,8 @@ c_parser_omp_clause_collapse (c_parser *parser, tree list)
}
if (num == error_mark_node)
return list;
+ mark_exp_read (num);
+ num = c_fully_fold (num, false, NULL);
if (!INTEGRAL_TYPE_P (TREE_TYPE (num))
|| !host_integerp (num, 0)
|| (n = tree_low_cst (num, 0)) <= 0
@@ -9474,11 +9689,17 @@ c_parser_omp_clause_private (c_parser *parser, tree list)
reduction-operator:
One of: + * - & ^ | && ||
-
+
OpenMP 3.1:
reduction-operator:
- One of: + * - & ^ | && || max min */
+ One of: + * - & ^ | && || max min
+
+ OpenMP 4.0:
+
+ reduction-operator:
+ One of: + * - & ^ | && ||
+ identifier */
static tree
c_parser_omp_clause_reduction (c_parser *parser, tree list)
@@ -9486,7 +9707,8 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list)
location_t clause_loc = c_parser_peek_token (parser)->location;
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
- enum tree_code code;
+ enum tree_code code = ERROR_MARK;
+ tree reduc_id = NULL_TREE;
switch (c_parser_peek_token (parser)->type)
{
@@ -9528,8 +9750,9 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list)
code = MAX_EXPR;
break;
}
+ reduc_id = c_parser_peek_token (parser)->value;
+ break;
}
- /* FALLTHRU */
default:
c_parser_error (parser,
"expected %<+%>, %<*%>, %<-%>, %<&%>, "
@@ -9538,6 +9761,7 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list)
return list;
}
c_parser_consume_token (parser);
+ reduc_id = c_omp_reduction_id (code, reduc_id);
if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
{
tree nl, c;
@@ -9545,7 +9769,17 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list)
nl = c_parser_omp_variable_list (parser, clause_loc,
OMP_CLAUSE_REDUCTION, list);
for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
- OMP_CLAUSE_REDUCTION_CODE (c) = code;
+ {
+ tree type = TREE_TYPE (OMP_CLAUSE_DECL (c));
+ OMP_CLAUSE_REDUCTION_CODE (c) = code;
+ if (code == ERROR_MARK
+ || !(INTEGRAL_TYPE_P (type)
+ || TREE_CODE (type) == REAL_TYPE
+ || TREE_CODE (type) == COMPLEX_TYPE))
+ OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
+ = c_omp_reduction_lookup (reduc_id,
+ TYPE_MAIN_VARIANT (type));
+ }
list = nl;
}
@@ -9675,13 +9909,544 @@ c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list)
return c;
}
+/* OpenMP 4.0:
+ inbranch
+ notinbranch */
+
+static tree
+c_parser_omp_clause_branch (c_parser *parser ATTRIBUTE_UNUSED,
+ enum omp_clause_code code, tree list)
+{
+ check_no_duplicate_clause (list, code, omp_clause_code_name[code]);
+
+ tree c = build_omp_clause (c_parser_peek_token (parser)->location, code);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* OpenMP 4.0:
+ parallel
+ for
+ sections
+ taskgroup */
+
+static tree
+c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED,
+ enum omp_clause_code code, tree list)
+{
+ tree c = build_omp_clause (c_parser_peek_token (parser)->location, code);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* OpenMP 4.0:
+ num_teams ( expression ) */
+
+static tree
+c_parser_omp_clause_num_teams (c_parser *parser, tree list)
+{
+ location_t num_teams_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ tree c, t = c_parser_expression (parser).value;
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ c_parser_error (parser, "expected integer expression");
+ return list;
+ }
+
+ /* Attempt to statically determine when the number isn't positive. */
+ c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
+ build_int_cst (TREE_TYPE (t), 0));
+ if (CAN_HAVE_LOCATION_P (c))
+ SET_EXPR_LOCATION (c, expr_loc);
+ if (c == boolean_true_node)
+ {
+ warning_at (expr_loc, 0, "%<num_teams%> value must be positive");
+ t = integer_one_node;
+ }
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TEAMS, "num_teams");
+
+ c = build_omp_clause (num_teams_loc, OMP_CLAUSE_NUM_TEAMS);
+ OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+/* OpenMP 4.0:
+ thread_limit ( expression ) */
+
+static tree
+c_parser_omp_clause_thread_limit (c_parser *parser, tree list)
+{
+ location_t num_teams_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ tree c, t = c_parser_expression (parser).value;
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ c_parser_error (parser, "expected integer expression");
+ return list;
+ }
+
+ /* Attempt to statically determine when the number isn't positive. */
+ c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
+ build_int_cst (TREE_TYPE (t), 0));
+ if (CAN_HAVE_LOCATION_P (c))
+ SET_EXPR_LOCATION (c, expr_loc);
+ if (c == boolean_true_node)
+ {
+ warning_at (expr_loc, 0, "%<thread_limit%> value must be positive");
+ t = integer_one_node;
+ }
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_THREAD_LIMIT,
+ "thread_limit");
+
+ c = build_omp_clause (num_teams_loc, OMP_CLAUSE_THREAD_LIMIT);
+ OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+/* OpenMP 4.0:
+ aligned ( variable-list )
+ aligned ( variable-list : constant-expression ) */
+
+static tree
+c_parser_omp_clause_aligned (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ tree nl, c;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ nl = c_parser_omp_variable_list (parser, clause_loc,
+ OMP_CLAUSE_ALIGNED, list);
+
+ if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ c_parser_consume_token (parser);
+ tree alignment = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (alignment);
+ alignment = c_fully_fold (alignment, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (alignment))
+ && TREE_CODE (alignment) != INTEGER_CST
+ && tree_int_cst_sgn (alignment) != 1)
+ {
+ error_at (clause_loc, "%<aligned%> clause alignment expression must "
+ "be positive constant integer expression");
+ alignment = NULL_TREE;
+ }
+
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment;
+ }
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return nl;
+}
+
+/* OpenMP 4.0:
+ linear ( variable-list )
+ linear ( variable-list : expression ) */
+
+static tree
+c_parser_omp_clause_linear (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ tree nl, c, step;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ nl = c_parser_omp_variable_list (parser, clause_loc,
+ OMP_CLAUSE_LINEAR, list);
+
+ if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ c_parser_consume_token (parser);
+ step = c_parser_expression (parser).value;
+ mark_exp_read (step);
+ step = c_fully_fold (step, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (step)))
+ {
+ error_at (clause_loc, "%<linear%> clause step expression must "
+ "be integral");
+ step = integer_one_node;
+ }
+
+ }
+ else
+ step = integer_one_node;
+
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ {
+ OMP_CLAUSE_LINEAR_STEP (c) = step;
+ }
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return nl;
+}
+
+/* OpenMP 4.0:
+ safelen ( constant-expression ) */
+
+static tree
+c_parser_omp_clause_safelen (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ tree c, t;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ t = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+ && TREE_CODE (t) != INTEGER_CST
+ && tree_int_cst_sgn (t) != 1)
+ {
+ error_at (clause_loc, "%<safelen%> clause expression must "
+ "be positive constant integer expression");
+ t = NULL_TREE;
+ }
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ if (t == NULL_TREE || t == error_mark_node)
+ return list;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_SAFELEN, "safelen");
+
+ c = build_omp_clause (clause_loc, OMP_CLAUSE_SAFELEN);
+ OMP_CLAUSE_SAFELEN_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 4.0:
+ simdlen ( constant-expression ) */
+
+static tree
+c_parser_omp_clause_simdlen (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ tree c, t;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ t = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+ && TREE_CODE (t) != INTEGER_CST
+ && tree_int_cst_sgn (t) != 1)
+ {
+ error_at (clause_loc, "%<simdlen%> clause expression must "
+ "be positive constant integer expression");
+ t = NULL_TREE;
+ }
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ if (t == NULL_TREE || t == error_mark_node)
+ return list;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen");
+
+ c = build_omp_clause (clause_loc, OMP_CLAUSE_SIMDLEN);
+ OMP_CLAUSE_SIMDLEN_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 4.0:
+ depend ( depend-kind: variable-list )
+
+ depend-kind:
+ in | out | inout */
+
+static tree
+c_parser_omp_clause_depend (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT;
+ tree nl, c;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp ("in", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_IN;
+ else if (strcmp ("inout", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_INOUT;
+ else if (strcmp ("out", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_OUT;
+ else
+ goto invalid_kind;
+ }
+ else
+ goto invalid_kind;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ goto resync_fail;
+
+ nl = c_parser_omp_variable_list (parser, clause_loc,
+ OMP_CLAUSE_DEPEND, list);
+
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_DEPEND_KIND (c) = kind;
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return nl;
+
+ invalid_kind:
+ c_parser_error (parser, "invalid depend kind");
+ resync_fail:
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return list;
+}
+
+/* OpenMP 4.0:
+ map ( map-kind: variable-list )
+ map ( variable-list )
+
+ map-kind:
+ alloc | to | from | tofrom */
+
+static tree
+c_parser_omp_clause_map (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ enum omp_clause_map_kind kind = OMP_CLAUSE_MAP_TOFROM;
+ tree nl, c;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp ("alloc", p) == 0)
+ kind = OMP_CLAUSE_MAP_ALLOC;
+ else if (strcmp ("to", p) == 0)
+ kind = OMP_CLAUSE_MAP_TO;
+ else if (strcmp ("from", p) == 0)
+ kind = OMP_CLAUSE_MAP_FROM;
+ else if (strcmp ("tofrom", p) == 0)
+ kind = OMP_CLAUSE_MAP_TOFROM;
+ else
+ {
+ c_parser_error (parser, "invalid map kind");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return list;
+ }
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ }
+
+ nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list);
+
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_MAP_KIND (c) = kind;
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return nl;
+}
+
+/* OpenMP 4.0:
+ device ( expression ) */
+
+static tree
+c_parser_omp_clause_device (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ tree c, t = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ c_parser_error (parser, "expected integer expression");
+ return list;
+ }
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE, "device");
+
+ c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE);
+ OMP_CLAUSE_DEVICE_ID (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+/* OpenMP 4.0:
+ dist_schedule ( static )
+ dist_schedule ( static , expression ) */
+
+static tree
+c_parser_omp_clause_dist_schedule (c_parser *parser, tree list)
+{
+ tree c, t = NULL_TREE;
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ if (!c_parser_next_token_is_keyword (parser, RID_STATIC))
+ {
+ c_parser_error (parser, "invalid dist_schedule kind");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return list;
+ }
+
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+
+ t = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ else
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<,%> or %<)%>");
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule");
+ if (t == error_mark_node)
+ return list;
+
+ c = build_omp_clause (loc, OMP_CLAUSE_DIST_SCHEDULE);
+ OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 4.0:
+ proc_bind ( proc-bind-kind )
+
+ proc-bind-kind:
+ master | close | spread */
+
+static tree
+c_parser_omp_clause_proc_bind (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ enum omp_clause_proc_bind_kind kind;
+ tree c;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp ("master", p) == 0)
+ kind = OMP_CLAUSE_PROC_BIND_MASTER;
+ else if (strcmp ("close", p) == 0)
+ kind = OMP_CLAUSE_PROC_BIND_CLOSE;
+ else if (strcmp ("spread", p) == 0)
+ kind = OMP_CLAUSE_PROC_BIND_SPREAD;
+ else
+ goto invalid_kind;
+ }
+ else
+ goto invalid_kind;
+
+ c_parser_consume_token (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ c = build_omp_clause (clause_loc, OMP_CLAUSE_PROC_BIND);
+ OMP_CLAUSE_PROC_BIND_KIND (c) = kind;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+
+ invalid_kind:
+ c_parser_error (parser, "invalid proc_bind kind");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return list;
+}
+
+/* OpenMP 4.0:
+ to ( variable-list ) */
+
+static tree
+c_parser_omp_clause_to (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list);
+}
+
+/* OpenMP 4.0:
+ from ( variable-list ) */
+
+static tree
+c_parser_omp_clause_from (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list);
+}
+
+/* OpenMP 4.0:
+ uniform ( variable-list ) */
+
+static tree
+c_parser_omp_clause_uniform (c_parser *parser, tree list)
+{
+ /* The clauses location. */
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ list = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_UNIFORM,
+ list);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ return list;
+}
+
/* Parse all OpenMP clauses. The set clauses allowed by the directive
is a bitmask in MASK. Return the list of clauses found; the result
of clause default goes in *pdefault. */
static tree
-c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
- const char *where)
+c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
+ const char *where, bool finish_p = true)
{
tree clauses = NULL;
bool first = true;
@@ -9696,7 +10461,6 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
if (!first && c_parser_next_token_is (parser, CPP_COMMA))
c_parser_consume_token (parser);
- first = false;
here = c_parser_peek_token (parser)->location;
c_kind = c_parser_omp_clause_name (parser);
@@ -9770,11 +10534,116 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
clauses = c_parser_omp_clause_untied (parser, clauses);
c_name = "untied";
break;
+ case PRAGMA_OMP_CLAUSE_INBRANCH:
+ clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH,
+ clauses);
+ c_name = "inbranch";
+ break;
+ case PRAGMA_OMP_CLAUSE_NOTINBRANCH:
+ clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_NOTINBRANCH,
+ clauses);
+ c_name = "notinbranch";
+ break;
+ case PRAGMA_OMP_CLAUSE_PARALLEL:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL,
+ clauses);
+ c_name = "parallel";
+ if (!first)
+ {
+ clause_not_first:
+ error_at (here, "%qs must be the first clause of %qs",
+ c_name, where);
+ clauses = prev;
+ }
+ break;
+ case PRAGMA_OMP_CLAUSE_FOR:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR,
+ clauses);
+ c_name = "for";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_SECTIONS:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS,
+ clauses);
+ c_name = "sections";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_TASKGROUP:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP,
+ clauses);
+ c_name = "taskgroup";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_TO:
+ clauses = c_parser_omp_clause_to (parser, clauses);
+ c_name = "to";
+ break;
+ case PRAGMA_OMP_CLAUSE_FROM:
+ clauses = c_parser_omp_clause_from (parser, clauses);
+ c_name = "from";
+ break;
+ case PRAGMA_OMP_CLAUSE_UNIFORM:
+ clauses = c_parser_omp_clause_uniform (parser, clauses);
+ c_name = "uniform";
+ break;
+ case PRAGMA_OMP_CLAUSE_NUM_TEAMS:
+ clauses = c_parser_omp_clause_num_teams (parser, clauses);
+ c_name = "num_teams";
+ break;
+ case PRAGMA_OMP_CLAUSE_THREAD_LIMIT:
+ clauses = c_parser_omp_clause_thread_limit (parser, clauses);
+ c_name = "thread_limit";
+ break;
+ case PRAGMA_OMP_CLAUSE_ALIGNED:
+ clauses = c_parser_omp_clause_aligned (parser, clauses);
+ c_name = "aligned";
+ break;
+ case PRAGMA_OMP_CLAUSE_LINEAR:
+ clauses = c_parser_omp_clause_linear (parser, clauses);
+ c_name = "linear";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEPEND:
+ clauses = c_parser_omp_clause_depend (parser, clauses);
+ c_name = "depend";
+ break;
+ case PRAGMA_OMP_CLAUSE_MAP:
+ clauses = c_parser_omp_clause_map (parser, clauses);
+ c_name = "map";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEVICE:
+ clauses = c_parser_omp_clause_device (parser, clauses);
+ c_name = "device";
+ break;
+ case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE:
+ clauses = c_parser_omp_clause_dist_schedule (parser, clauses);
+ c_name = "dist_schedule";
+ break;
+ case PRAGMA_OMP_CLAUSE_PROC_BIND:
+ clauses = c_parser_omp_clause_proc_bind (parser, clauses);
+ c_name = "proc_bind";
+ break;
+ case PRAGMA_OMP_CLAUSE_SAFELEN:
+ clauses = c_parser_omp_clause_safelen (parser, clauses);
+ c_name = "safelen";
+ break;
+ case PRAGMA_OMP_CLAUSE_SIMDLEN:
+ clauses = c_parser_omp_clause_simdlen (parser, clauses);
+ c_name = "simdlen";
+ break;
default:
c_parser_error (parser, "expected %<#pragma omp%> clause");
goto saw_error;
}
+ first = false;
+
if (((mask >> c_kind) & 1) == 0 && !parser->error)
{
/* Remove the invalid clause(s) from the list to avoid
@@ -9787,7 +10656,10 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
saw_error:
c_parser_skip_to_pragma_eol (parser);
- return c_finish_omp_clauses (clauses);
+ if (finish_p)
+ return c_finish_omp_clauses (clauses);
+
+ return clauses;
}
/* OpenMP 2.5:
@@ -9843,10 +10715,18 @@ c_parser_omp_structured_block (c_parser *parser)
update-stmt:
expression-stmt | x = x binop expr
capture-stmt:
- v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x
+ v = expression-stmt
capture-block:
{ v = x; update-stmt; } | { update-stmt; v = x; }
+ OpenMP 4.0:
+ update-stmt:
+ expression-stmt | x = x binop expr | x = expr binop x
+ capture-stmt:
+ v = update-stmt
+ capture-block:
+ { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; }
+
where x and v are lvalue expressions with scalar type.
LOC is the location of the #pragma token. */
@@ -9856,10 +10736,13 @@ c_parser_omp_atomic (location_t loc, c_parser *parser)
{
tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE;
tree lhs1 = NULL_TREE, rhs1 = NULL_TREE;
- tree stmt, orig_lhs;
+ tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE;
enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR;
- struct c_expr rhs_expr;
+ struct c_expr expr;
+ location_t eloc;
bool structured_block = false;
+ bool swapped = false;
+ bool seq_cst = false;
if (c_parser_next_token_is (parser, CPP_NAME))
{
@@ -9878,6 +10761,15 @@ c_parser_omp_atomic (location_t loc, c_parser *parser)
if (p)
c_parser_consume_token (parser);
}
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (!strcmp (p, "seq_cst"))
+ {
+ seq_cst = true;
+ c_parser_consume_token (parser);
+ }
+ }
c_parser_skip_to_pragma_eol (parser);
switch (code)
@@ -9931,7 +10823,11 @@ c_parser_omp_atomic (location_t loc, c_parser *parser)
/* For structured_block case we don't know yet whether
old or new x should be captured. */
restart:
- lhs = c_parser_unary_expression (parser).value;
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_unary_expression (parser);
+ lhs = expr.value;
+ expr = default_function_array_conversion (eloc, expr);
+ unfolded_lhs = expr.value;
lhs = c_fully_fold (lhs, false, NULL);
orig_lhs = lhs;
switch (TREE_CODE (lhs))
@@ -9958,6 +10854,7 @@ restart:
/* FALLTHROUGH */
case PREINCREMENT_EXPR:
lhs = TREE_OPERAND (lhs, 0);
+ unfolded_lhs = NULL_TREE;
opcode = PLUS_EXPR;
rhs = integer_one_node;
break;
@@ -9968,6 +10865,7 @@ restart:
/* FALLTHROUGH */
case PREDECREMENT_EXPR:
lhs = TREE_OPERAND (lhs, 0);
+ unfolded_lhs = NULL_TREE;
opcode = MINUS_EXPR;
rhs = integer_one_node;
break;
@@ -9993,6 +10891,7 @@ restart:
/* This is pre or post increment. */
rhs = TREE_OPERAND (lhs, 1);
lhs = TREE_OPERAND (lhs, 0);
+ unfolded_lhs = NULL_TREE;
opcode = NOP_EXPR;
if (code == OMP_ATOMIC_CAPTURE_NEW
&& !structured_block
@@ -10007,6 +10906,7 @@ restart:
/* This is pre or post decrement. */
rhs = TREE_OPERAND (lhs, 1);
lhs = TREE_OPERAND (lhs, 0);
+ unfolded_lhs = NULL_TREE;
opcode = NOP_EXPR;
if (code == OMP_ATOMIC_CAPTURE_NEW
&& !structured_block
@@ -10047,87 +10947,67 @@ restart:
opcode = BIT_XOR_EXPR;
break;
case CPP_EQ:
- if (structured_block || code == OMP_ATOMIC)
+ c_parser_consume_token (parser);
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expr_no_commas (parser, NULL, unfolded_lhs);
+ rhs1 = expr.value;
+ switch (TREE_CODE (rhs1))
{
- location_t aloc = c_parser_peek_token (parser)->location;
- location_t rhs_loc;
- enum c_parser_prec oprec = PREC_NONE;
-
- c_parser_consume_token (parser);
- rhs1 = c_parser_unary_expression (parser).value;
- rhs1 = c_fully_fold (rhs1, false, NULL);
- if (rhs1 == error_mark_node)
- goto saw_error;
- switch (c_parser_peek_token (parser)->type)
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs))
{
- case CPP_SEMICOLON:
- if (code == OMP_ATOMIC_CAPTURE_NEW)
- {
- code = OMP_ATOMIC_CAPTURE_OLD;
- v = lhs;
- lhs = NULL_TREE;
- lhs1 = rhs1;
- rhs1 = NULL_TREE;
- c_parser_consume_token (parser);
- goto restart;
- }
- c_parser_error (parser,
- "invalid form of %<#pragma omp atomic%>");
- goto saw_error;
- case CPP_MULT:
- opcode = MULT_EXPR;
- oprec = PREC_MULT;
- break;
- case CPP_DIV:
- opcode = TRUNC_DIV_EXPR;
- oprec = PREC_MULT;
- break;
- case CPP_PLUS:
- opcode = PLUS_EXPR;
- oprec = PREC_ADD;
- break;
- case CPP_MINUS:
- opcode = MINUS_EXPR;
- oprec = PREC_ADD;
- break;
- case CPP_LSHIFT:
- opcode = LSHIFT_EXPR;
- oprec = PREC_SHIFT;
- break;
- case CPP_RSHIFT:
- opcode = RSHIFT_EXPR;
- oprec = PREC_SHIFT;
- break;
- case CPP_AND:
- opcode = BIT_AND_EXPR;
- oprec = PREC_BITAND;
- break;
- case CPP_OR:
- opcode = BIT_IOR_EXPR;
- oprec = PREC_BITOR;
- break;
- case CPP_XOR:
- opcode = BIT_XOR_EXPR;
- oprec = PREC_BITXOR;
- break;
- default:
- c_parser_error (parser,
- "invalid operator for %<#pragma omp atomic%>");
- goto saw_error;
+ opcode = TREE_CODE (rhs1);
+ rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL);
+ rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL);
+ goto stmt_done;
}
- loc = aloc;
- c_parser_consume_token (parser);
- rhs_loc = c_parser_peek_token (parser)->location;
- if (commutative_tree_code (opcode))
- oprec = (enum c_parser_prec) (oprec - 1);
- rhs_expr = c_parser_binary_expression (parser, NULL, oprec);
- rhs_expr = default_function_array_read_conversion (rhs_loc,
- rhs_expr);
- rhs = rhs_expr.value;
- rhs = c_fully_fold (rhs, false, NULL);
- goto stmt_done;
- }
- /* FALLTHROUGH */
+ if (c_tree_equal (TREE_OPERAND (rhs1, 1), unfolded_lhs))
+ {
+ opcode = TREE_CODE (rhs1);
+ rhs = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL);
+ rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL);
+ swapped = !commutative_tree_code (opcode);
+ goto stmt_done;
+ }
+ break;
+ case ERROR_MARK:
+ goto saw_error;
+ default:
+ break;
+ }
+ if (c_parser_peek_token (parser)->type == CPP_SEMICOLON)
+ {
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ v = lhs;
+ lhs = NULL_TREE;
+ expr = default_function_array_read_conversion (eloc, expr);
+ unfolded_lhs1 = expr.value;
+ lhs1 = c_fully_fold (unfolded_lhs1, false, NULL);
+ rhs1 = NULL_TREE;
+ c_parser_consume_token (parser);
+ goto restart;
+ }
+ if (structured_block)
+ {
+ opcode = NOP_EXPR;
+ expr = default_function_array_read_conversion (eloc, expr);
+ rhs = c_fully_fold (expr.value, false, NULL);
+ rhs1 = NULL_TREE;
+ goto stmt_done;
+ }
+ }
+ c_parser_error (parser, "invalid form of %<#pragma omp atomic%>");
+ goto saw_error;
default:
c_parser_error (parser,
"invalid operator for %<#pragma omp atomic%>");
@@ -10138,12 +11018,10 @@ restart:
c_finish_omp_atomic. */
loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
- {
- location_t rhs_loc = c_parser_peek_token (parser)->location;
- rhs_expr = c_parser_expression (parser);
- rhs_expr = default_function_array_read_conversion (rhs_loc, rhs_expr);
- }
- rhs = rhs_expr.value;
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expression (parser);
+ expr = default_function_array_read_conversion (eloc, expr);
+ rhs = expr.value;
rhs = c_fully_fold (rhs, false, NULL);
break;
}
@@ -10158,7 +11036,11 @@ stmt_done:
goto saw_error;
if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
goto saw_error;
- lhs1 = c_parser_unary_expression (parser).value;
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_unary_expression (parser);
+ lhs1 = expr.value;
+ expr = default_function_array_read_conversion (eloc, expr);
+ unfolded_lhs1 = expr.value;
lhs1 = c_fully_fold (lhs1, false, NULL);
if (lhs1 == error_mark_node)
goto saw_error;
@@ -10169,7 +11051,16 @@ stmt_done:
c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
}
done:
- stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1);
+ if (unfolded_lhs && unfolded_lhs1
+ && !c_tree_equal (unfolded_lhs, unfolded_lhs1))
+ {
+ error ("%<#pragma omp atomic capture%> uses two different "
+ "expressions for memory");
+ stmt = error_mark_node;
+ }
+ else
+ stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1,
+ swapped, seq_cst);
if (stmt != error_mark_node)
add_stmt (stmt);
@@ -10249,8 +11140,8 @@ c_parser_omp_flush (c_parser *parser)
LOC is the location of the OMP in "#pragma omp". */
static tree
-c_parser_omp_for_loop (location_t loc,
- c_parser *parser, tree clauses, tree *par_clauses)
+c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
+ tree clauses, tree *cclauses)
{
tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
tree declv, condv, incrv, initv, ret = NULL;
@@ -10290,7 +11181,8 @@ c_parser_omp_for_loop (location_t loc,
{
if (i > 0)
vec_safe_push (for_block, c_begin_compound_stmt (true));
- c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL);
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true,
+ NULL, vNULL);
decl = check_for_loop_decls (for_loc, flag_isoc99);
if (decl == NULL)
goto error_init;
@@ -10337,8 +11229,8 @@ c_parser_omp_for_loop (location_t loc,
if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
{
location_t cond_loc = c_parser_peek_token (parser)->location;
- struct c_expr cond_expr = c_parser_binary_expression (parser, NULL,
- PREC_NONE);
+ struct c_expr cond_expr
+ = c_parser_binary_expression (parser, NULL, NULL_TREE);
cond = cond_expr.value;
cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
@@ -10477,13 +11369,15 @@ c_parser_omp_for_loop (location_t loc,
an error from the initialization parsing. */
if (!fail)
{
- stmt = c_finish_omp_for (loc, declv, initv, condv, incrv, body, NULL);
+ stmt = c_finish_omp_for (loc, code, declv, initv, condv,
+ incrv, body, NULL);
if (stmt)
{
- if (par_clauses != NULL)
+ if (cclauses != NULL
+ && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL)
{
tree *c;
- for (c = par_clauses; *c ; )
+ for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; )
if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE
&& OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE)
c = &OMP_CLAUSE_CHAIN (*c);
@@ -10532,33 +11426,128 @@ pop_scopes:
return ret;
}
+/* Helper function for OpenMP parsing, split clauses and call
+ finish_omp_clauses on each of the set of clauses afterwards. */
+
+static void
+omp_split_clauses (location_t loc, enum tree_code code,
+ omp_clause_mask mask, tree clauses, tree *cclauses)
+{
+ int i;
+ c_omp_split_clauses (loc, code, mask, clauses, cclauses);
+ for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
+ if (cclauses[i])
+ cclauses[i] = c_finish_omp_clauses (cclauses[i]);
+}
+
+/* OpenMP 4.0:
+ #pragma omp simd simd-clause[optseq] new-line
+ for-loop
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OMP_SIMD_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE))
+
+static tree
+c_parser_omp_simd (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+ tree block, clauses, ret;
+
+ strcat (p_name, " simd");
+ mask |= OMP_SIMD_CLAUSE_MASK;
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED);
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
+ }
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, cclauses);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
/* OpenMP 2.5:
#pragma omp for for-clause[optseq] new-line
for-loop
+ OpenMP 4.0:
+ #pragma omp for simd for-simd-clause[optseq] new-line
+ for-loop
+
LOC is the location of the #pragma token.
*/
-#define OMP_FOR_CLAUSE_MASK \
- ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \
- | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \
- | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \
- | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE) \
- | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+#define OMP_FOR_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
static tree
-c_parser_omp_for (location_t loc, c_parser *parser)
+c_parser_omp_for (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
{
tree block, clauses, ret;
- clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK,
- "#pragma omp for");
+ strcat (p_name, " for");
+ mask |= OMP_FOR_CLAUSE_MASK;
+ if (cclauses)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (strcmp (p, "simd") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL_TREE)
+ return ret;
+ ret = make_node (OMP_FOR);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_FOR_BODY (ret) = block;
+ OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+ SET_EXPR_LOCATION (ret, loc);
+ add_stmt (ret);
+ return ret;
+ }
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+ }
block = c_begin_compound_stmt (true);
- ret = c_parser_omp_for_loop (loc, parser, clauses, NULL);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_FOR, clauses, cclauses);
block = c_end_compound_stmt (loc, block, true);
add_stmt (block);
@@ -10623,21 +11612,7 @@ c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser)
if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION)
{
- substmt = push_stmt_list ();
-
- while (1)
- {
- c_parser_statement (parser);
-
- if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
- break;
- if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
- break;
- if (c_parser_next_token_is (parser, CPP_EOF))
- break;
- }
-
- substmt = pop_stmt_list (substmt);
+ substmt = c_parser_omp_structured_block (parser);
substmt = build1 (OMP_SECTION, void_type_node, substmt);
SET_EXPR_LOCATION (substmt, loc);
add_stmt (substmt);
@@ -10688,20 +11663,30 @@ c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser)
LOC is the location of the #pragma token.
*/
-#define OMP_SECTIONS_CLAUSE_MASK \
- ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \
- | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+#define OMP_SECTIONS_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
static tree
-c_parser_omp_sections (location_t loc, c_parser *parser)
+c_parser_omp_sections (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
{
tree block, clauses, ret;
- clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK,
- "#pragma omp sections");
+ strcat (p_name, " sections");
+ mask |= OMP_SECTIONS_CLAUSE_MASK;
+ if (cclauses)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS];
+ }
block = c_begin_compound_stmt (true);
ret = c_parser_omp_sections_scope (loc, parser);
@@ -10721,76 +11706,72 @@ c_parser_omp_sections (location_t loc, c_parser *parser)
LOC is the location of the #pragma token.
*/
-#define OMP_PARALLEL_CLAUSE_MASK \
- ( (1u << PRAGMA_OMP_CLAUSE_IF) \
- | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \
- | (1u << PRAGMA_OMP_CLAUSE_SHARED) \
- | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \
- | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \
- | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+#define OMP_PARALLEL_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND))
static tree
-c_parser_omp_parallel (location_t loc, c_parser *parser)
+c_parser_omp_parallel (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
{
- enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL;
- const char *p_name = "#pragma omp parallel";
- tree stmt, clauses, par_clause, ws_clause, block;
- unsigned int mask = OMP_PARALLEL_CLAUSE_MASK;
+ tree stmt, clauses, block;
+
+ strcat (p_name, " parallel");
+ mask |= OMP_PARALLEL_CLAUSE_MASK;
if (c_parser_next_token_is_keyword (parser, RID_FOR))
{
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
c_parser_consume_token (parser);
- p_kind = PRAGMA_OMP_PARALLEL_FOR;
- p_name = "#pragma omp parallel for";
- mask |= OMP_FOR_CLAUSE_MASK;
- mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+ block = c_begin_omp_parallel ();
+ c_parser_omp_for (loc, parser, p_name, mask, cclauses);
+ stmt
+ = c_finish_omp_parallel (loc, cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
+ }
+ else if (cclauses)
+ {
+ error_at (loc, "expected %<for%> after %qs", p_name);
+ c_parser_skip_to_pragma_eol (parser);
+ return NULL_TREE;
}
else if (c_parser_next_token_is (parser, CPP_NAME))
{
const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
if (strcmp (p, "sections") == 0)
{
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
c_parser_consume_token (parser);
- p_kind = PRAGMA_OMP_PARALLEL_SECTIONS;
- p_name = "#pragma omp parallel sections";
- mask |= OMP_SECTIONS_CLAUSE_MASK;
- mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+ block = c_begin_omp_parallel ();
+ c_parser_omp_sections (loc, parser, p_name, mask, cclauses);
+ stmt = c_finish_omp_parallel (loc,
+ cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
}
}
- clauses = c_parser_omp_all_clauses (parser, mask, p_name);
-
- switch (p_kind)
- {
- case PRAGMA_OMP_PARALLEL:
- block = c_begin_omp_parallel ();
- c_parser_statement (parser);
- stmt = c_finish_omp_parallel (loc, clauses, block);
- break;
-
- case PRAGMA_OMP_PARALLEL_FOR:
- block = c_begin_omp_parallel ();
- c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
- c_parser_omp_for_loop (loc, parser, ws_clause, &par_clause);
- stmt = c_finish_omp_parallel (loc, par_clause, block);
- OMP_PARALLEL_COMBINED (stmt) = 1;
- break;
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
- case PRAGMA_OMP_PARALLEL_SECTIONS:
- block = c_begin_omp_parallel ();
- c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
- stmt = c_parser_omp_sections_scope (loc, parser);
- if (stmt)
- OMP_SECTIONS_CLAUSES (stmt) = ws_clause;
- stmt = c_finish_omp_parallel (loc, par_clause, block);
- OMP_PARALLEL_COMBINED (stmt) = 1;
- break;
-
- default:
- gcc_unreachable ();
- }
+ block = c_begin_omp_parallel ();
+ c_parser_statement (parser);
+ stmt = c_finish_omp_parallel (loc, clauses, block);
return stmt;
}
@@ -10802,11 +11783,11 @@ c_parser_omp_parallel (location_t loc, c_parser *parser)
LOC is the location of the #pragma.
*/
-#define OMP_SINGLE_CLAUSE_MASK \
- ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+#define OMP_SINGLE_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
static tree
c_parser_omp_single (location_t loc, c_parser *parser)
@@ -10829,15 +11810,16 @@ c_parser_omp_single (location_t loc, c_parser *parser)
LOC is the location of the #pragma.
*/
-#define OMP_TASK_CLAUSE_MASK \
- ( (1u << PRAGMA_OMP_CLAUSE_IF) \
- | (1u << PRAGMA_OMP_CLAUSE_UNTIED) \
- | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \
- | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_SHARED) \
- | (1u << PRAGMA_OMP_CLAUSE_FINAL) \
- | (1u << PRAGMA_OMP_CLAUSE_MERGEABLE))
+#define OMP_TASK_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND))
static tree
c_parser_omp_task (location_t loc, c_parser *parser)
@@ -10880,6 +11862,983 @@ c_parser_omp_taskyield (c_parser *parser)
c_finish_omp_taskyield (loc);
}
+/* OpenMP 4.0:
+ # pragma omp taskgroup new-line
+*/
+
+static tree
+c_parser_omp_taskgroup (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_skip_to_pragma_eol (parser);
+ return c_finish_omp_taskgroup (loc, c_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 4.0:
+ # pragma omp cancel cancel-clause[optseq] new-line
+
+ LOC is the location of the #pragma.
+*/
+
+#define OMP_CANCEL_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static void
+c_parser_omp_cancel (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ c_parser_consume_pragma (parser);
+ tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK,
+ "#pragma omp cancel");
+
+ c_finish_omp_cancel (loc, clauses);
+}
+
+/* OpenMP 4.0:
+ # pragma omp cancellation point cancelpt-clause[optseq] new-line
+
+ LOC is the location of the #pragma.
+*/
+
+#define OMP_CANCELLATION_POINT_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP))
+
+static void
+c_parser_omp_cancellation_point (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree clauses;
+ bool point_seen = false;
+
+ c_parser_consume_pragma (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "point") == 0)
+ {
+ c_parser_consume_token (parser);
+ point_seen = true;
+ }
+ }
+ if (!point_seen)
+ {
+ c_parser_error (parser, "expected %<point%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+
+ clauses
+ = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK,
+ "#pragma omp cancellation point");
+
+ c_finish_omp_cancellation_point (loc, clauses);
+}
+
+/* OpenMP 4.0:
+ #pragma omp distribute distribute-clause[optseq] new-line
+ for-loop */
+
+#define OMP_DISTRIBUTE_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE))
+
+static tree
+c_parser_omp_distribute (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+ tree clauses, block, ret;
+
+ strcat (p_name, " distribute");
+ mask |= OMP_DISTRIBUTE_CLAUSE_MASK;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ bool simd = false;
+ bool parallel = false;
+
+ if (strcmp (p, "simd") == 0)
+ simd = true;
+ else
+ parallel = strcmp (p, "parallel") == 0;
+ if (parallel || simd)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (true);
+ if (simd)
+ ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
+ else
+ ret = c_parser_omp_parallel (loc, parser, p_name, mask, cclauses);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL)
+ return ret;
+ ret = make_node (OMP_DISTRIBUTE);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_FOR_BODY (ret) = block;
+ OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE];
+ SET_EXPR_LOCATION (ret, loc);
+ add_stmt (ret);
+ return ret;
+ }
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_DISTRIBUTE, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE];
+ }
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_DISTRIBUTE, clauses, NULL);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
+/* OpenMP 4.0:
+ # pragma omp teams teams-clause[optseq] new-line
+ structured-block */
+
+#define OMP_TEAMS_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT))
+
+static tree
+c_parser_omp_teams (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+ tree clauses, block, ret;
+
+ strcat (p_name, " teams");
+ mask |= OMP_TEAMS_CLAUSE_MASK;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "distribute") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_distribute (loc, parser, p_name, mask, cclauses);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL)
+ return ret;
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+ ret = make_node (OMP_TEAMS);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_TEAMS_CLAUSES (ret) = clauses;
+ OMP_TEAMS_BODY (ret) = block;
+ return add_stmt (ret);
+ }
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+ }
+
+ tree stmt = make_node (OMP_TEAMS);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_TEAMS_CLAUSES (stmt) = clauses;
+ OMP_TEAMS_BODY (stmt) = c_parser_omp_structured_block (parser);
+
+ return add_stmt (stmt);
+}
+
+/* OpenMP 4.0:
+ # pragma omp target data target-data-clause[optseq] new-line
+ structured-block */
+
+#define OMP_TARGET_DATA_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static tree
+c_parser_omp_target_data (location_t loc, c_parser *parser)
+{
+ tree stmt = make_node (OMP_TARGET_DATA);
+ TREE_TYPE (stmt) = void_type_node;
+
+ OMP_TARGET_DATA_CLAUSES (stmt)
+ = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
+ "#pragma omp target data");
+ keep_next_level ();
+ tree block = c_begin_compound_stmt (true);
+ add_stmt (c_parser_omp_structured_block (parser));
+ OMP_TARGET_DATA_BODY (stmt) = c_end_compound_stmt (loc, block, true);
+
+ SET_EXPR_LOCATION (stmt, loc);
+ return add_stmt (stmt);
+}
+
+/* OpenMP 4.0:
+ # pragma omp target update target-update-clause[optseq] new-line */
+
+#define OMP_TARGET_UPDATE_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static bool
+c_parser_omp_target_update (location_t loc, c_parser *parser,
+ enum pragma_context context)
+{
+ if (context == pragma_stmt)
+ {
+ error_at (loc,
+ "%<#pragma omp target update%> may only be "
+ "used in compound statements");
+ c_parser_skip_to_pragma_eol (parser);
+ return false;
+ }
+
+ tree clauses
+ = c_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK,
+ "#pragma omp target update");
+ if (find_omp_clause (clauses, OMP_CLAUSE_TO) == NULL_TREE
+ && find_omp_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE)
+ {
+ error_at (loc,
+ "%<#pragma omp target update must contain at least one "
+ "%<from%> or %<to%> clauses");
+ return false;
+ }
+
+ tree stmt = make_node (OMP_TARGET_UPDATE);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses;
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+ return false;
+}
+
+/* OpenMP 4.0:
+ # pragma omp target target-clause[optseq] new-line
+ structured-block */
+
+#define OMP_TARGET_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static bool
+c_parser_omp_target (c_parser *parser, enum pragma_context context)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+
+ if (context != pragma_stmt && context != pragma_compound)
+ {
+ c_parser_error (parser, "expected declaration specifiers");
+ c_parser_skip_to_pragma_eol (parser);
+ return false;
+ }
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (strcmp (p, "data") == 0)
+ {
+ c_parser_consume_token (parser);
+ c_parser_omp_target_data (loc, parser);
+ return true;
+ }
+ else if (strcmp (p, "update") == 0)
+ {
+ c_parser_consume_token (parser);
+ return c_parser_omp_target_update (loc, parser, context);
+ }
+ else if (strcmp (p, "teams") == 0)
+ {
+ tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT];
+ char p_name[sizeof ("#pragma omp target teams distribute "
+ "parallel for simd")];
+
+ c_parser_consume_token (parser);
+ strcpy (p_name, "#pragma omp target");
+ keep_next_level ();
+ tree block = c_begin_compound_stmt (true);
+ tree ret = c_parser_omp_teams (loc, parser, p_name,
+ OMP_TARGET_CLAUSE_MASK, cclauses);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL)
+ return ret;
+ tree stmt = make_node (OMP_TARGET);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
+ OMP_TARGET_BODY (stmt) = block;
+ add_stmt (stmt);
+ return true;
+ }
+ }
+
+ tree stmt = make_node (OMP_TARGET);
+ TREE_TYPE (stmt) = void_type_node;
+
+ OMP_TARGET_CLAUSES (stmt)
+ = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
+ "#pragma omp target");
+ keep_next_level ();
+ tree block = c_begin_compound_stmt (true);
+ add_stmt (c_parser_omp_structured_block (parser));
+ OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true);
+
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+ return true;
+}
+
+/* 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_INBRANCH) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH))
+
+static void
+c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
+{
+ vec<c_token> clauses = vNULL;
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ clauses.release ();
+ return;
+ }
+ clauses.safe_push (*token);
+ c_parser_consume_token (parser);
+ }
+ clauses.safe_push (*c_parser_peek_token (parser));
+ c_parser_skip_to_pragma_eol (parser);
+
+ while (c_parser_next_token_is (parser, CPP_PRAGMA))
+ {
+ if (c_parser_peek_token (parser)->pragma_kind
+ != PRAGMA_OMP_DECLARE_REDUCTION
+ || c_parser_peek_2nd_token (parser)->type != CPP_NAME
+ || strcmp (IDENTIFIER_POINTER
+ (c_parser_peek_2nd_token (parser)->value),
+ "simd") != 0)
+ {
+ c_parser_error (parser,
+ "%<#pragma omp declare simd%> must be followed by "
+ "function declaration or definition or another "
+ "%<#pragma omp declare simd%>");
+ clauses.release ();
+ return;
+ }
+ c_parser_consume_pragma (parser);
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ clauses.release ();
+ return;
+ }
+ clauses.safe_push (*token);
+ c_parser_consume_token (parser);
+ }
+ clauses.safe_push (*c_parser_peek_token (parser));
+ c_parser_skip_to_pragma_eol (parser);
+ }
+
+ /* Make sure nothing tries to read past the end of the tokens. */
+ c_token eof_token;
+ memset (&eof_token, 0, sizeof (eof_token));
+ eof_token.type = CPP_EOF;
+ clauses.safe_push (eof_token);
+ clauses.safe_push (eof_token);
+
+ switch (context)
+ {
+ case pragma_external:
+ if (c_parser_next_token_is (parser, CPP_KEYWORD)
+ && c_parser_peek_token (parser)->keyword == RID_EXTENSION)
+ {
+ int ext = disable_extension_diagnostics ();
+ do
+ c_parser_consume_token (parser);
+ while (c_parser_next_token_is (parser, CPP_KEYWORD)
+ && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
+ c_parser_declaration_or_fndef (parser, true, true, true, false, true,
+ NULL, clauses);
+ restore_extension_diagnostics (ext);
+ }
+ else
+ c_parser_declaration_or_fndef (parser, true, true, true, false, true,
+ NULL, clauses);
+ break;
+ case pragma_struct:
+ case pragma_param:
+ c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by "
+ "function declaration or definition");
+ break;
+ case pragma_compound:
+ case pragma_stmt:
+ if (c_parser_next_token_is (parser, CPP_KEYWORD)
+ && c_parser_peek_token (parser)->keyword == RID_EXTENSION)
+ {
+ int ext = disable_extension_diagnostics ();
+ do
+ c_parser_consume_token (parser);
+ while (c_parser_next_token_is (parser, CPP_KEYWORD)
+ && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
+ if (c_parser_next_tokens_start_declaration (parser))
+ {
+ c_parser_declaration_or_fndef (parser, true, true, true, true,
+ true, NULL, clauses);
+ restore_extension_diagnostics (ext);
+ break;
+ }
+ restore_extension_diagnostics (ext);
+ }
+ else if (c_parser_next_tokens_start_declaration (parser))
+ {
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true,
+ NULL, clauses);
+ break;
+ }
+ c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by "
+ "function declaration or definition");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ clauses.release ();
+}
+
+/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed,
+ and put that into "omp declare simd" attribute. */
+
+static void
+c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
+ vec<c_token> clauses)
+{
+ /* Normally first token is CPP_NAME "simd". CPP_EOF there indicates
+ error has been reported and CPP_PRAGMA that c_finish_omp_declare_simd
+ has already processed the tokens. */
+ if (clauses[0].type == CPP_EOF)
+ return;
+ if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL)
+ {
+ error ("%<#pragma omp declare simd%> not immediately followed by "
+ "a function declaration or definition");
+ clauses[0].type = CPP_EOF;
+ return;
+ }
+ if (clauses[0].type != CPP_NAME)
+ {
+ error_at (DECL_SOURCE_LOCATION (fndecl),
+ "%<#pragma omp declare simd%> not immediately followed by "
+ "a single function declaration or definition");
+ clauses[0].type = CPP_EOF;
+ return;
+ }
+
+ if (parms == NULL_TREE)
+ parms = DECL_ARGUMENTS (fndecl);
+
+ unsigned int tokens_avail = parser->tokens_avail;
+ gcc_assert (parser->tokens == &parser->tokens_buf[0]);
+ parser->tokens = clauses.address ();
+ parser->tokens_avail = clauses.length ();
+
+ /* c_parser_omp_declare_simd pushed 2 extra CPP_EOF tokens at the end. */
+ while (parser->tokens_avail > 3)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ gcc_assert (token->type == CPP_NAME
+ && strcmp (IDENTIFIER_POINTER (token->value), "simd") == 0);
+ c_parser_consume_token (parser);
+ parser->in_pragma = true;
+
+ tree c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
+ "#pragma omp declare simd");
+ c = c_omp_declare_simd_clauses_to_numbers (parms, c);
+ if (c != NULL_TREE)
+ c = tree_cons (NULL_TREE, c, NULL_TREE);
+ c = build_tree_list (get_identifier ("omp declare simd"), c);
+ TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl);
+ DECL_ATTRIBUTES (fndecl) = c;
+ }
+
+ parser->tokens = &parser->tokens_buf[0];
+ parser->tokens_avail = tokens_avail;
+ clauses[0].type = CPP_PRAGMA;
+}
+
+
+/* OpenMP 4.0:
+ # pragma omp declare target new-line
+ declarations and definitions
+ # pragma omp end declare target new-line */
+
+static void
+c_parser_omp_declare_target (c_parser *parser)
+{
+ c_parser_skip_to_pragma_eol (parser);
+ current_omp_declare_target_attribute++;
+}
+
+static void
+c_parser_omp_end_declare_target (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
+ "declare") == 0)
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
+ "target") == 0)
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_error (parser, "expected %<target%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+ }
+ else
+ {
+ c_parser_error (parser, "expected %<declare%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+ c_parser_skip_to_pragma_eol (parser);
+ if (!current_omp_declare_target_attribute)
+ error_at (loc, "%<#pragma omp end declare target%> without corresponding "
+ "%<#pragma omp declare target%>");
+ else
+ current_omp_declare_target_attribute--;
+}
+
+
+/* OpenMP 4.0
+ #pragma omp declare reduction (reduction-id : typename-list : expression) \
+ initializer-clause[opt] new-line
+
+ initializer-clause:
+ initializer (omp_priv = initializer)
+ initializer (function-name (argument-list)) */
+
+static void
+c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context)
+{
+ unsigned int tokens_avail = 0, i;
+ vec<tree> types = vNULL;
+ vec<c_token> clauses = vNULL;
+ enum tree_code reduc_code = ERROR_MARK;
+ tree reduc_id = NULL_TREE;
+ tree type;
+ location_t rloc = c_parser_peek_token (parser)->location;
+
+ if (context == pragma_struct || context == pragma_param)
+ {
+ error ("%<#pragma omp declare reduction%> not at file or block scope");
+ goto fail;
+ }
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ goto fail;
+
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_PLUS:
+ reduc_code = PLUS_EXPR;
+ break;
+ case CPP_MULT:
+ reduc_code = MULT_EXPR;
+ break;
+ case CPP_MINUS:
+ reduc_code = MINUS_EXPR;
+ break;
+ case CPP_AND:
+ reduc_code = BIT_AND_EXPR;
+ break;
+ case CPP_XOR:
+ reduc_code = BIT_XOR_EXPR;
+ break;
+ case CPP_OR:
+ reduc_code = BIT_IOR_EXPR;
+ break;
+ case CPP_AND_AND:
+ reduc_code = TRUTH_ANDIF_EXPR;
+ break;
+ case CPP_OR_OR:
+ reduc_code = TRUTH_ORIF_EXPR;
+ break;
+ case CPP_NAME:
+ const char *p;
+ p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "min") == 0)
+ {
+ reduc_code = MIN_EXPR;
+ break;
+ }
+ if (strcmp (p, "max") == 0)
+ {
+ reduc_code = MAX_EXPR;
+ break;
+ }
+ reduc_id = c_parser_peek_token (parser)->value;
+ break;
+ default:
+ c_parser_error (parser,
+ "expected %<+%>, %<*%>, %<-%>, %<&%>, "
+ "%<^%>, %<|%>, %<&&%>, %<||%>, %<min%> or identifier");
+ goto fail;
+ }
+
+ tree orig_reduc_id, reduc_decl;
+ orig_reduc_id = reduc_id;
+ reduc_id = c_omp_reduction_id (reduc_code, reduc_id);
+ reduc_decl = c_omp_reduction_decl (reduc_id);
+ c_parser_consume_token (parser);
+
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ goto fail;
+
+ while (true)
+ {
+ location_t loc = c_parser_peek_token (parser)->location;
+ struct c_type_name *ctype = c_parser_type_name (parser);
+ if (ctype != NULL)
+ {
+ type = groktypename (ctype, NULL, NULL);
+ if (type == error_mark_node)
+ ;
+ else if ((INTEGRAL_TYPE_P (type)
+ || TREE_CODE (type) == REAL_TYPE
+ || TREE_CODE (type) == COMPLEX_TYPE)
+ && orig_reduc_id == NULL_TREE)
+ error_at (loc, "predeclared arithmetic type in "
+ "%<#pragma omp declare reduction%>");
+ else if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == ARRAY_TYPE)
+ error_at (loc, "function or array type in "
+ "%<#pragma omp declare reduction%>");
+ else if (TYPE_QUALS_NO_ADDR_SPACE (type))
+ error_at (loc, "const, volatile or restrict qualified type in "
+ "%<#pragma omp declare reduction%>");
+ else
+ {
+ tree t;
+ for (t = DECL_INITIAL (reduc_decl); t; t = TREE_CHAIN (t))
+ if (comptypes (TREE_PURPOSE (t), type))
+ {
+ error_at (loc, "redeclaration of %qs "
+ "%<#pragma omp declare reduction%> for "
+ "type %qT",
+ IDENTIFIER_POINTER (reduc_id)
+ + sizeof ("omp declare reduction ") - 1,
+ type);
+ location_t ploc
+ = DECL_SOURCE_LOCATION (TREE_VEC_ELT (TREE_VALUE (t),
+ 0));
+ error_at (ploc, "previous %<#pragma omp declare "
+ "reduction%>");
+ break;
+ }
+ if (t == NULL_TREE)
+ types.safe_push (type);
+ }
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")
+ || types.is_empty ())
+ {
+ fail:
+ clauses.release ();
+ types.release ();
+ while (true)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF || token->type == CPP_PRAGMA_EOL)
+ break;
+ c_parser_consume_token (parser);
+ }
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+
+ if (types.length () > 1)
+ {
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ goto fail;
+ clauses.safe_push (*token);
+ c_parser_consume_token (parser);
+ }
+ clauses.safe_push (*c_parser_peek_token (parser));
+ c_parser_skip_to_pragma_eol (parser);
+
+ /* Make sure nothing tries to read past the end of the tokens. */
+ c_token eof_token;
+ memset (&eof_token, 0, sizeof (eof_token));
+ eof_token.type = CPP_EOF;
+ clauses.safe_push (eof_token);
+ clauses.safe_push (eof_token);
+ }
+
+ int errs = errorcount;
+ FOR_EACH_VEC_ELT (types, i, type)
+ {
+ tokens_avail = parser->tokens_avail;
+ gcc_assert (parser->tokens == &parser->tokens_buf[0]);
+ if (!clauses.is_empty ())
+ {
+ parser->tokens = clauses.address ();
+ parser->tokens_avail = clauses.length ();
+ parser->in_pragma = true;
+ }
+
+ bool nested = current_function_decl != NULL_TREE;
+ if (nested)
+ c_push_function_context ();
+ tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
+ reduc_id, default_function_type);
+ current_function_decl = fndecl;
+ allocate_struct_function (fndecl, true);
+ push_scope ();
+ tree stmt = push_stmt_list ();
+ /* Intentionally BUILTINS_LOCATION, so that -Wshadow doesn't
+ warn about these. */
+ tree omp_out = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ get_identifier ("omp_out"), type);
+ DECL_ARTIFICIAL (omp_out) = 1;
+ DECL_CONTEXT (omp_out) = fndecl;
+ pushdecl (omp_out);
+ tree omp_in = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ get_identifier ("omp_in"), type);
+ DECL_ARTIFICIAL (omp_in) = 1;
+ DECL_CONTEXT (omp_in) = fndecl;
+ pushdecl (omp_in);
+ struct c_expr combiner = c_parser_expression (parser);
+ struct c_expr initializer;
+ tree omp_priv = NULL_TREE, omp_orig = NULL_TREE;
+ bool bad = false;
+ initializer.value = error_mark_node;
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ bad = true;
+ else if (c_parser_next_token_is (parser, CPP_NAME)
+ && strcmp (IDENTIFIER_POINTER
+ (c_parser_peek_token (parser)->value),
+ "initializer") == 0)
+ {
+ c_parser_consume_token (parser);
+ pop_scope ();
+ push_scope ();
+ omp_priv = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ get_identifier ("omp_priv"), type);
+ DECL_ARTIFICIAL (omp_priv) = 1;
+ DECL_INITIAL (omp_priv) = error_mark_node;
+ DECL_CONTEXT (omp_priv) = fndecl;
+ pushdecl (omp_priv);
+ omp_orig = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ get_identifier ("omp_orig"), type);
+ DECL_ARTIFICIAL (omp_orig) = 1;
+ DECL_CONTEXT (omp_orig) = fndecl;
+ pushdecl (omp_orig);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ bad = true;
+ else if (!c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected %<omp_priv%> or "
+ "function-name");
+ bad = true;
+ }
+ else if (strcmp (IDENTIFIER_POINTER
+ (c_parser_peek_token (parser)->value),
+ "omp_priv") != 0)
+ {
+ if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN
+ || c_parser_peek_token (parser)->id_kind != C_ID_ID)
+ {
+ c_parser_error (parser, "expected function-name %<(%>");
+ bad = true;
+ }
+ else
+ initializer = c_parser_postfix_expression (parser);
+ if (initializer.value
+ && TREE_CODE (initializer.value) == CALL_EXPR)
+ {
+ int j;
+ tree c = initializer.value;
+ for (j = 0; j < call_expr_nargs (c); j++)
+ if (TREE_CODE (CALL_EXPR_ARG (c, j)) == ADDR_EXPR
+ && TREE_OPERAND (CALL_EXPR_ARG (c, j), 0) == omp_priv)
+ break;
+ if (j == call_expr_nargs (c))
+ error ("one of the initializer call arguments should be "
+ "%<&omp_priv%>");
+ }
+ }
+ else
+ {
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ bad = true;
+ else
+ {
+ tree st = push_stmt_list ();
+ start_init (omp_priv, NULL_TREE, 0);
+ location_t loc = c_parser_peek_token (parser)->location;
+ struct c_expr init = c_parser_initializer (parser);
+ finish_init ();
+ finish_decl (omp_priv, loc, init.value,
+ init.original_type, NULL_TREE);
+ pop_stmt_list (st);
+ }
+ }
+ if (!bad
+ && !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ bad = true;
+ }
+
+ if (!bad)
+ {
+ c_parser_skip_to_pragma_eol (parser);
+
+ tree t = tree_cons (type, make_tree_vec (omp_priv ? 6 : 3),
+ DECL_INITIAL (reduc_decl));
+ DECL_INITIAL (reduc_decl) = t;
+ DECL_SOURCE_LOCATION (omp_out) = rloc;
+ TREE_VEC_ELT (TREE_VALUE (t), 0) = omp_out;
+ TREE_VEC_ELT (TREE_VALUE (t), 1) = omp_in;
+ TREE_VEC_ELT (TREE_VALUE (t), 2) = combiner.value;
+ walk_tree (&combiner.value, c_check_omp_declare_reduction_r,
+ &TREE_VEC_ELT (TREE_VALUE (t), 0), NULL);
+ if (omp_priv)
+ {
+ DECL_SOURCE_LOCATION (omp_priv) = rloc;
+ TREE_VEC_ELT (TREE_VALUE (t), 3) = omp_priv;
+ TREE_VEC_ELT (TREE_VALUE (t), 4) = omp_orig;
+ TREE_VEC_ELT (TREE_VALUE (t), 5) = initializer.value;
+ walk_tree (&initializer.value, c_check_omp_declare_reduction_r,
+ &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL);
+ walk_tree (&DECL_INITIAL (omp_priv),
+ c_check_omp_declare_reduction_r,
+ &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL);
+ }
+ }
+
+ pop_stmt_list (stmt);
+ pop_scope ();
+ if (cfun->language != NULL)
+ {
+ ggc_free (cfun->language);
+ cfun->language = NULL;
+ }
+ set_cfun (NULL);
+ current_function_decl = NULL_TREE;
+ if (nested)
+ c_pop_function_context ();
+
+ if (!clauses.is_empty ())
+ {
+ parser->tokens = &parser->tokens_buf[0];
+ parser->tokens_avail = tokens_avail;
+ }
+ if (bad)
+ goto fail;
+ if (errs != errorcount)
+ break;
+ }
+
+ clauses.release ();
+ types.release ();
+}
+
+
+/* OpenMP 4.0
+ #pragma omp declare simd declare-simd-clauses[optseq] new-line
+ #pragma omp declare reduction (reduction-id : typename-list : expression) \
+ initializer-clause[opt] new-line
+ #pragma omp declare target new-line */
+
+static void
+c_parser_omp_declare (c_parser *parser, enum pragma_context context)
+{
+ c_parser_consume_pragma (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "simd") == 0)
+ {
+ /* c_parser_consume_token (parser); done in
+ c_parser_omp_declare_simd. */
+ c_parser_omp_declare_simd (parser, context);
+ return;
+ }
+ if (strcmp (p, "reduction") == 0)
+ {
+ c_parser_consume_token (parser);
+ c_parser_omp_declare_reduction (parser, context);
+ return;
+ }
+ if (strcmp (p, "target") == 0)
+ {
+ c_parser_consume_token (parser);
+ c_parser_omp_declare_target (parser);
+ return;
+ }
+ }
+
+ c_parser_error (parser, "expected %<simd%> or %<reduction%> "
+ "or %<target%>");
+ c_parser_skip_to_pragma_eol (parser);
+}
+
/* Main entry point to parsing most OpenMP pragmas. */
static void
@@ -10888,6 +12847,8 @@ c_parser_omp_construct (c_parser *parser)
enum pragma_kind p_kind;
location_t loc;
tree stmt;
+ char p_name[sizeof "#pragma omp teams distribute parallel for simd"];
+ omp_clause_mask mask (0);
loc = c_parser_peek_token (parser)->location;
p_kind = c_parser_peek_token (parser)->pragma_kind;
@@ -10901,8 +12862,13 @@ c_parser_omp_construct (c_parser *parser)
case PRAGMA_OMP_CRITICAL:
stmt = c_parser_omp_critical (loc, parser);
break;
+ case PRAGMA_OMP_DISTRIBUTE:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_distribute (loc, parser, p_name, mask, NULL);
+ break;
case PRAGMA_OMP_FOR:
- stmt = c_parser_omp_for (loc, parser);
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_for (loc, parser, p_name, mask, NULL);
break;
case PRAGMA_OMP_MASTER:
stmt = c_parser_omp_master (loc, parser);
@@ -10911,10 +12877,16 @@ c_parser_omp_construct (c_parser *parser)
stmt = c_parser_omp_ordered (loc, parser);
break;
case PRAGMA_OMP_PARALLEL:
- stmt = c_parser_omp_parallel (loc, parser);
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL);
break;
case PRAGMA_OMP_SECTIONS:
- stmt = c_parser_omp_sections (loc, parser);
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_sections (loc, parser, p_name, mask, NULL);
+ break;
+ case PRAGMA_OMP_SIMD:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_simd (loc, parser, p_name, mask, NULL);
break;
case PRAGMA_OMP_SINGLE:
stmt = c_parser_omp_single (loc, parser);
@@ -10922,6 +12894,13 @@ c_parser_omp_construct (c_parser *parser)
case PRAGMA_OMP_TASK:
stmt = c_parser_omp_task (loc, parser);
break;
+ case PRAGMA_OMP_TASKGROUP:
+ stmt = c_parser_omp_taskgroup (parser);
+ break;
+ case PRAGMA_OMP_TEAMS:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL);
+ break;
default:
gcc_unreachable ();
}
@@ -11148,7 +13127,7 @@ c_parser_transaction_expression (c_parser *parser, enum rid keyword)
*/
static tree
-c_parser_transaction_cancel(c_parser *parser)
+c_parser_transaction_cancel (c_parser *parser)
{
location_t loc = c_parser_peek_token (parser)->location;
tree attrs;
@@ -11208,6 +13187,7 @@ c_parse_file (void)
c_parser tparser;
memset (&tparser, 0, sizeof tparser);
+ tparser.tokens = &tparser.tokens_buf[0];
the_parser = &tparser;
if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS)
@@ -11215,6 +13195,8 @@ c_parse_file (void)
the_parser = ggc_alloc_c_parser ();
*the_parser = tparser;
+ if (tparser.tokens == &tparser.tokens_buf[0])
+ the_parser->tokens = &the_parser->tokens_buf[0];
/* Initialize EH, if we've been told to do so. */
if (flag_exceptions)
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index d1a871daa68..2565ccb4f15 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -526,6 +526,8 @@ extern tree start_struct (location_t, enum tree_code, tree,
struct c_struct_parse_info **);
extern void store_parm_decls (void);
extern void store_parm_decls_from (struct c_arg_info *);
+extern void temp_store_parm_decls (tree, tree);
+extern void temp_pop_parm_decls (void);
extern tree xref_tag (enum tree_code, tree);
extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree);
extern struct c_parm *build_c_parm (struct c_declspecs *, tree,
@@ -637,9 +639,12 @@ extern tree c_begin_omp_parallel (void);
extern tree c_finish_omp_parallel (location_t, tree, tree);
extern tree c_begin_omp_task (void);
extern tree c_finish_omp_task (location_t, tree, tree);
+extern void c_finish_omp_cancel (location_t, tree);
+extern void c_finish_omp_cancellation_point (location_t, tree);
extern tree c_finish_omp_clauses (tree);
extern tree c_build_va_arg (location_t, tree, tree);
extern tree c_finish_transaction (location_t, tree, int);
+extern bool c_tree_equal (tree, tree);
/* Set to 0 at beginning of a function definition, set to 1 if
a return statement that specifies a return value is seen. */
@@ -663,6 +668,10 @@ extern enum machine_mode c_default_pointer_mode;
/* In c-decl.c */
extern void c_finish_incomplete_decl (tree);
extern void c_write_global_declarations (void);
+extern tree c_omp_reduction_id (enum tree_code, tree);
+extern tree c_omp_reduction_decl (tree);
+extern tree c_omp_reduction_lookup (tree, tree);
+extern tree c_check_omp_declare_reduction_r (tree *, int *, void *);
/* In c-errors.c */
extern void pedwarn_c90 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 7ecafe4894c..16e39b2ad70 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-iterator.h"
#include "bitmap.h"
#include "gimple.h"
+#include "tree-inline.h"
#include "c-family/c-objc.h"
#include "c-family/c-common.h"
#include "c-family/c-ubsan.h"
@@ -10692,6 +10693,537 @@ c_finish_omp_task (location_t loc, tree clauses, tree block)
return add_stmt (stmt);
}
+/* Generate GOMP_cancel call for #pragma omp cancel. */
+
+void
+c_finish_omp_cancel (location_t loc, tree clauses)
+{
+ tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCEL);
+ int mask = 0;
+ if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL))
+ mask = 1;
+ else if (find_omp_clause (clauses, OMP_CLAUSE_FOR))
+ mask = 2;
+ else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS))
+ mask = 4;
+ else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP))
+ mask = 8;
+ else
+ {
+ error_at (loc, "%<#pragma omp cancel must specify one of "
+ "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> "
+ "clauses");
+ return;
+ }
+ tree ifc = find_omp_clause (clauses, OMP_CLAUSE_IF);
+ if (ifc != NULL_TREE)
+ {
+ tree type = TREE_TYPE (OMP_CLAUSE_IF_EXPR (ifc));
+ ifc = fold_build2_loc (OMP_CLAUSE_LOCATION (ifc), NE_EXPR,
+ boolean_type_node, OMP_CLAUSE_IF_EXPR (ifc),
+ build_zero_cst (type));
+ }
+ else
+ ifc = boolean_true_node;
+ tree stmt = build_call_expr_loc (loc, fn, 2,
+ build_int_cst (integer_type_node, mask),
+ ifc);
+ add_stmt (stmt);
+}
+
+/* Generate GOMP_cancellation_point call for
+ #pragma omp cancellation point. */
+
+void
+c_finish_omp_cancellation_point (location_t loc, tree clauses)
+{
+ tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCELLATION_POINT);
+ int mask = 0;
+ if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL))
+ mask = 1;
+ else if (find_omp_clause (clauses, OMP_CLAUSE_FOR))
+ mask = 2;
+ else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS))
+ mask = 4;
+ else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP))
+ mask = 8;
+ else
+ {
+ error_at (loc, "%<#pragma omp cancellation point must specify one of "
+ "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> "
+ "clauses");
+ return;
+ }
+ tree stmt = build_call_expr_loc (loc, fn, 1,
+ build_int_cst (integer_type_node, mask));
+ add_stmt (stmt);
+}
+
+/* Helper function for handle_omp_array_sections. Called recursively
+ to handle multiple array-section-subscripts. C is the clause,
+ T current expression (initially OMP_CLAUSE_DECL), which is either
+ a TREE_LIST for array-section-subscript (TREE_PURPOSE is low-bound
+ expression if specified, TREE_VALUE length expression if specified,
+ TREE_CHAIN is what it has been specified after, or some decl.
+ TYPES vector is populated with array section types, MAYBE_ZERO_LEN
+ set to true if any of the array-section-subscript could have length
+ of zero (explicit or implicit), FIRST_NON_ONE is the index of the
+ first array-section-subscript which is known not to have length
+ of one. Given say:
+ map(a[:b][2:1][:c][:2][:d][e:f][2:5])
+ FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c]
+ all are or may have length of 1, array-section-subscript [:2] is the
+ first one knonwn not to have length 1. For array-section-subscript
+ <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't
+ 0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we
+ can if MAYBE_ZERO_LEN is false. MAYBE_ZERO_LEN will be true in the above
+ case though, as some lengths could be zero. */
+
+static tree
+handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
+ bool &maybe_zero_len, unsigned int &first_non_one)
+{
+ tree ret, low_bound, length, type;
+ if (TREE_CODE (t) != TREE_LIST)
+ {
+ if (t == error_mark_node || TREE_TYPE (t) == error_mark_node)
+ return error_mark_node;
+ if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+ {
+ if (DECL_P (t))
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qD is not a variable in %qs clause", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ else
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qE is not a variable in %qs clause", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND
+ && TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qD is threadprivate variable in %qs clause", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ return t;
+ }
+
+ ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types,
+ maybe_zero_len, first_non_one);
+ if (ret == error_mark_node || ret == NULL_TREE)
+ return ret;
+
+ type = TREE_TYPE (ret);
+ low_bound = TREE_PURPOSE (t);
+ length = TREE_VALUE (t);
+
+ if (low_bound == error_mark_node || length == error_mark_node)
+ return error_mark_node;
+
+ if (low_bound && !INTEGRAL_TYPE_P (TREE_TYPE (low_bound)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "low bound %qE of array section does not have integral type",
+ low_bound);
+ return error_mark_node;
+ }
+ if (length && !INTEGRAL_TYPE_P (TREE_TYPE (length)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "length %qE of array section does not have integral type",
+ length);
+ return error_mark_node;
+ }
+ if (low_bound
+ && TREE_CODE (low_bound) == INTEGER_CST
+ && TYPE_PRECISION (TREE_TYPE (low_bound))
+ > TYPE_PRECISION (sizetype))
+ low_bound = fold_convert (sizetype, low_bound);
+ if (length
+ && TREE_CODE (length) == INTEGER_CST
+ && TYPE_PRECISION (TREE_TYPE (length))
+ > TYPE_PRECISION (sizetype))
+ length = fold_convert (sizetype, length);
+ if (low_bound == NULL_TREE)
+ low_bound = integer_zero_node;
+
+ if (length != NULL_TREE)
+ {
+ if (!integer_nonzerop (length))
+ maybe_zero_len = true;
+ if (first_non_one == types.length ()
+ && (TREE_CODE (length) != INTEGER_CST || integer_onep (length)))
+ first_non_one++;
+ }
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ if (length == NULL_TREE
+ && (TYPE_DOMAIN (type) == NULL_TREE
+ || TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "for unknown bound array type length expression must "
+ "be specified");
+ return error_mark_node;
+ }
+ if (TREE_CODE (low_bound) == INTEGER_CST
+ && tree_int_cst_sgn (low_bound) == -1)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "negative low bound in array section in %qs clause",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ if (length != NULL_TREE
+ && TREE_CODE (length) == INTEGER_CST
+ && tree_int_cst_sgn (length) == -1)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "negative length in array section in %qs clause",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ if (TYPE_DOMAIN (type)
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (type))
+ && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
+ == INTEGER_CST)
+ {
+ tree size = size_binop (PLUS_EXPR,
+ TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
+ size_one_node);
+ if (TREE_CODE (low_bound) == INTEGER_CST)
+ {
+ if (tree_int_cst_lt (size, low_bound))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "low bound %qE above array section size "
+ "in %qs clause", low_bound,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ if (tree_int_cst_equal (size, low_bound))
+ maybe_zero_len = true;
+ else if (length == NULL_TREE
+ && first_non_one == types.length ()
+ && tree_int_cst_equal
+ (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
+ low_bound))
+ first_non_one++;
+ }
+ else if (length == NULL_TREE)
+ {
+ maybe_zero_len = true;
+ if (first_non_one == types.length ())
+ first_non_one++;
+ }
+ if (length && TREE_CODE (length) == INTEGER_CST)
+ {
+ if (tree_int_cst_lt (size, length))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "length %qE above array section size "
+ "in %qs clause", length,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ if (TREE_CODE (low_bound) == INTEGER_CST)
+ {
+ tree lbpluslen
+ = size_binop (PLUS_EXPR,
+ fold_convert (sizetype, low_bound),
+ fold_convert (sizetype, length));
+ if (TREE_CODE (lbpluslen) == INTEGER_CST
+ && tree_int_cst_lt (size, lbpluslen))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "high bound %qE above array section size "
+ "in %qs clause", lbpluslen,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ }
+ }
+ }
+ else if (length == NULL_TREE)
+ {
+ maybe_zero_len = true;
+ if (first_non_one == types.length ())
+ first_non_one++;
+ }
+
+ /* For [lb:] we will need to evaluate lb more than once. */
+ if (length == NULL_TREE && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
+ {
+ tree lb = c_save_expr (low_bound);
+ if (lb != low_bound)
+ {
+ TREE_PURPOSE (t) = lb;
+ low_bound = lb;
+ }
+ }
+ }
+ else if (TREE_CODE (type) == POINTER_TYPE)
+ {
+ if (length == NULL_TREE)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "for pointer type length expression must be specified");
+ return error_mark_node;
+ }
+ /* If there is a pointer type anywhere but in the very first
+ array-section-subscript, the array section can't be contiguous. */
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND
+ && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "array section is not contiguous in %qs clause",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ }
+ else
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qE does not have pointer or array type", ret);
+ return error_mark_node;
+ }
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
+ types.safe_push (TREE_TYPE (ret));
+ /* We will need to evaluate lb more than once. */
+ tree lb = c_save_expr (low_bound);
+ if (lb != low_bound)
+ {
+ TREE_PURPOSE (t) = lb;
+ low_bound = lb;
+ }
+ ret = build_array_ref (OMP_CLAUSE_LOCATION (c), ret, low_bound);
+ return ret;
+}
+
+/* Handle array sections for clause C. */
+
+static bool
+handle_omp_array_sections (tree c)
+{
+ bool maybe_zero_len = false;
+ unsigned int first_non_one = 0;
+ vec<tree> types = vNULL;
+ tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types,
+ maybe_zero_len, first_non_one);
+ if (first == error_mark_node)
+ {
+ types.release ();
+ return true;
+ }
+ if (first == NULL_TREE)
+ {
+ types.release ();
+ return false;
+ }
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND)
+ {
+ tree t = OMP_CLAUSE_DECL (c);
+ tree tem = NULL_TREE;
+ types.release ();
+ /* Need to evaluate side effects in the length expressions
+ if any. */
+ while (TREE_CODE (t) == TREE_LIST)
+ {
+ if (TREE_VALUE (t) && TREE_SIDE_EFFECTS (TREE_VALUE (t)))
+ {
+ if (tem == NULL_TREE)
+ tem = TREE_VALUE (t);
+ else
+ tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem),
+ TREE_VALUE (t), tem);
+ }
+ t = TREE_CHAIN (t);
+ }
+ if (tem)
+ first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first);
+ first = c_fully_fold (first, false, NULL);
+ OMP_CLAUSE_DECL (c) = first;
+ }
+ else
+ {
+ unsigned int num = types.length (), i;
+ tree t, side_effects = NULL_TREE, size = NULL_TREE;
+ tree condition = NULL_TREE;
+
+ if (int_size_in_bytes (TREE_TYPE (first)) <= 0)
+ maybe_zero_len = true;
+
+ for (i = num, t = OMP_CLAUSE_DECL (c); i > 0;
+ t = TREE_CHAIN (t))
+ {
+ tree low_bound = TREE_PURPOSE (t);
+ tree length = TREE_VALUE (t);
+
+ i--;
+ if (low_bound
+ && TREE_CODE (low_bound) == INTEGER_CST
+ && TYPE_PRECISION (TREE_TYPE (low_bound))
+ > TYPE_PRECISION (sizetype))
+ low_bound = fold_convert (sizetype, low_bound);
+ if (length
+ && TREE_CODE (length) == INTEGER_CST
+ && TYPE_PRECISION (TREE_TYPE (length))
+ > TYPE_PRECISION (sizetype))
+ length = fold_convert (sizetype, length);
+ if (low_bound == NULL_TREE)
+ low_bound = integer_zero_node;
+ if (!maybe_zero_len && i > first_non_one)
+ {
+ if (integer_nonzerop (low_bound))
+ goto do_warn_noncontiguous;
+ if (length != NULL_TREE
+ && TREE_CODE (length) == INTEGER_CST
+ && TYPE_DOMAIN (types[i])
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (types[i]))
+ && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])))
+ == INTEGER_CST)
+ {
+ tree size;
+ size = size_binop (PLUS_EXPR,
+ TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])),
+ size_one_node);
+ if (!tree_int_cst_equal (length, size))
+ {
+ do_warn_noncontiguous:
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "array section is not contiguous in %qs "
+ "clause",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ types.release ();
+ return true;
+ }
+ }
+ if (length != NULL_TREE
+ && TREE_SIDE_EFFECTS (length))
+ {
+ if (side_effects == NULL_TREE)
+ side_effects = length;
+ else
+ side_effects = build2 (COMPOUND_EXPR,
+ TREE_TYPE (side_effects),
+ length, side_effects);
+ }
+ }
+ else
+ {
+ tree l;
+
+ if (i > first_non_one && length && integer_nonzerop (length))
+ continue;
+ if (length)
+ l = fold_convert (sizetype, length);
+ else
+ {
+ l = size_binop (PLUS_EXPR,
+ TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])),
+ size_one_node);
+ l = size_binop (MINUS_EXPR, l,
+ fold_convert (sizetype, low_bound));
+ }
+ if (i > first_non_one)
+ {
+ l = fold_build2 (NE_EXPR, boolean_type_node, l,
+ size_zero_node);
+ if (condition == NULL_TREE)
+ condition = l;
+ else
+ condition = fold_build2 (BIT_AND_EXPR, boolean_type_node,
+ l, condition);
+ }
+ else if (size == NULL_TREE)
+ {
+ size = size_in_bytes (TREE_TYPE (types[i]));
+ size = size_binop (MULT_EXPR, size, l);
+ if (condition)
+ size = fold_build3 (COND_EXPR, sizetype, condition,
+ size, size_zero_node);
+ }
+ else
+ size = size_binop (MULT_EXPR, size, l);
+ }
+ }
+ types.release ();
+ if (side_effects)
+ size = build2 (COMPOUND_EXPR, sizetype, side_effects, size);
+ first = c_fully_fold (first, false, NULL);
+ OMP_CLAUSE_DECL (c) = first;
+ if (size)
+ size = c_fully_fold (size, false, NULL);
+ OMP_CLAUSE_SIZE (c) = size;
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+ return false;
+ tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
+ OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER;
+ if (!c_mark_addressable (t))
+ return false;
+ OMP_CLAUSE_DECL (c2) = t;
+ t = build_fold_addr_expr (first);
+ t = fold_convert_loc (OMP_CLAUSE_LOCATION (c), ptrdiff_type_node, t);
+ tree ptr = OMP_CLAUSE_DECL (c2);
+ if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
+ ptr = build_fold_addr_expr (ptr);
+ t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
+ ptrdiff_type_node, t,
+ fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+ ptrdiff_type_node, ptr));
+ t = c_fully_fold (t, false, NULL);
+ OMP_CLAUSE_SIZE (c2) = t;
+ OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
+ OMP_CLAUSE_CHAIN (c) = c2;
+ }
+ return false;
+}
+
+/* Helper function of finish_omp_clauses. Clone STMT as if we were making
+ an inline call. But, remap
+ the OMP_DECL1 VAR_DECL (omp_out resp. omp_orig) to PLACEHOLDER
+ and OMP_DECL2 VAR_DECL (omp_in resp. omp_priv) to DECL. */
+
+static tree
+c_clone_omp_udr (tree stmt, tree omp_decl1, tree omp_decl2,
+ tree decl, tree placeholder)
+{
+ copy_body_data id;
+ struct pointer_map_t *decl_map = pointer_map_create ();
+
+ *pointer_map_insert (decl_map, omp_decl1) = placeholder;
+ *pointer_map_insert (decl_map, omp_decl2) = decl;
+ memset (&id, 0, sizeof (id));
+ id.src_fn = DECL_CONTEXT (omp_decl1);
+ id.dst_fn = current_function_decl;
+ id.src_cfun = DECL_STRUCT_FUNCTION (id.src_fn);
+ id.decl_map = decl_map;
+
+ id.copy_decl = copy_decl_no_change;
+ id.transform_call_graph_edges = CB_CGE_DUPLICATE;
+ id.transform_new_cfg = true;
+ id.transform_return_to_modify = false;
+ id.transform_lang_insert_block = NULL;
+ id.eh_lp_nr = 0;
+ walk_tree (&stmt, copy_tree_body_r, &id, NULL);
+ pointer_map_destroy (decl_map);
+ return stmt;
+}
+
+/* Helper function of c_finish_omp_clauses, called via walk_tree.
+ Find OMP_CLAUSE_PLACEHOLDER (passed in DATA) in *TP. */
+
+static tree
+c_find_omp_placeholder_r (tree *tp, int *, void *data)
+{
+ if (*tp == (tree) data)
+ return *tp;
+ return NULL_TREE;
+}
+
/* For all elements of CLAUSES, validate them vs OpenMP constraints.
Remove any elements from the list that are invalid. */
@@ -10699,13 +11231,17 @@ tree
c_finish_omp_clauses (tree clauses)
{
bitmap_head generic_head, firstprivate_head, lastprivate_head;
+ bitmap_head aligned_head;
tree c, t, *pc = &clauses;
- const char *name;
+ bool branch_seen = false;
+ bool copyprivate_seen = false;
+ tree *nowait_clause = NULL;
bitmap_obstack_initialize (NULL);
bitmap_initialize (&generic_head, &bitmap_default_obstack);
bitmap_initialize (&firstprivate_head, &bitmap_default_obstack);
bitmap_initialize (&lastprivate_head, &bitmap_default_obstack);
+ bitmap_initialize (&aligned_head, &bitmap_default_obstack);
for (pc = &clauses, c = clauses; c ; c = *pc)
{
@@ -10716,28 +11252,19 @@ c_finish_omp_clauses (tree clauses)
switch (OMP_CLAUSE_CODE (c))
{
case OMP_CLAUSE_SHARED:
- name = "shared";
need_implicitly_determined = true;
goto check_dup_generic;
case OMP_CLAUSE_PRIVATE:
- name = "private";
need_complete = true;
need_implicitly_determined = true;
goto check_dup_generic;
case OMP_CLAUSE_REDUCTION:
- name = "reduction";
need_implicitly_determined = true;
t = OMP_CLAUSE_DECL (c);
- if (AGGREGATE_TYPE_P (TREE_TYPE (t))
- || POINTER_TYPE_P (TREE_TYPE (t)))
- {
- error_at (OMP_CLAUSE_LOCATION (c),
- "%qE has invalid type for %<reduction%>", t);
- remove = true;
- }
- else if (FLOAT_TYPE_P (TREE_TYPE (t)))
+ if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == NULL_TREE
+ && FLOAT_TYPE_P (TREE_TYPE (t)))
{
enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c);
const char *r_name = NULL;
@@ -10776,14 +11303,88 @@ c_finish_omp_clauses (tree clauses)
remove = true;
}
}
+ else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == error_mark_node)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "user defined reduction not found for %qD", t);
+ remove = true;
+ }
+ else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
+ {
+ tree list = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
+ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t));
+ tree placeholder = build_decl (OMP_CLAUSE_LOCATION (c),
+ VAR_DECL, NULL_TREE, type);
+ OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder;
+ DECL_ARTIFICIAL (placeholder) = 1;
+ DECL_IGNORED_P (placeholder) = 1;
+ if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 0)))
+ c_mark_addressable (placeholder);
+ if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 1)))
+ c_mark_addressable (OMP_CLAUSE_DECL (c));
+ OMP_CLAUSE_REDUCTION_MERGE (c)
+ = c_clone_omp_udr (TREE_VEC_ELT (list, 2),
+ TREE_VEC_ELT (list, 0),
+ TREE_VEC_ELT (list, 1),
+ OMP_CLAUSE_DECL (c), placeholder);
+ OMP_CLAUSE_REDUCTION_MERGE (c)
+ = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR,
+ void_type_node, NULL_TREE,
+ OMP_CLAUSE_REDUCTION_MERGE (c), NULL_TREE);
+ TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_MERGE (c)) = 1;
+ if (TREE_VEC_LENGTH (list) == 6)
+ {
+ if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 3)))
+ c_mark_addressable (OMP_CLAUSE_DECL (c));
+ if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 4)))
+ c_mark_addressable (placeholder);
+ tree init = TREE_VEC_ELT (list, 5);
+ if (init == error_mark_node)
+ init = DECL_INITIAL (TREE_VEC_ELT (list, 3));
+ OMP_CLAUSE_REDUCTION_INIT (c)
+ = c_clone_omp_udr (init, TREE_VEC_ELT (list, 4),
+ TREE_VEC_ELT (list, 3),
+ OMP_CLAUSE_DECL (c), placeholder);
+ if (TREE_VEC_ELT (list, 5) == error_mark_node)
+ OMP_CLAUSE_REDUCTION_INIT (c)
+ = build2 (INIT_EXPR, TREE_TYPE (t), t,
+ OMP_CLAUSE_REDUCTION_INIT (c));
+ if (walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c),
+ c_find_omp_placeholder_r,
+ placeholder, NULL))
+ OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c) = 1;
+ }
+ else
+ {
+ tree init;
+ if (AGGREGATE_TYPE_P (TREE_TYPE (t)))
+ init = build_constructor (TREE_TYPE (t), NULL);
+ else
+ init = fold_convert (TREE_TYPE (t), integer_zero_node);
+ OMP_CLAUSE_REDUCTION_INIT (c)
+ = build2 (INIT_EXPR, TREE_TYPE (t), t, init);
+ }
+ OMP_CLAUSE_REDUCTION_INIT (c)
+ = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR,
+ void_type_node, NULL_TREE,
+ OMP_CLAUSE_REDUCTION_INIT (c), NULL_TREE);
+ TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_INIT (c)) = 1;
+ }
goto check_dup_generic;
case OMP_CLAUSE_COPYPRIVATE:
- name = "copyprivate";
+ copyprivate_seen = true;
+ if (nowait_clause)
+ {
+ error_at (OMP_CLAUSE_LOCATION (*nowait_clause),
+ "%<nowait%> clause must not be used together "
+ "with %<copyprivate%>");
+ *nowait_clause = OMP_CLAUSE_CHAIN (*nowait_clause);
+ nowait_clause = NULL;
+ }
goto check_dup_generic;
case OMP_CLAUSE_COPYIN:
- name = "copyin";
t = OMP_CLAUSE_DECL (c);
if (TREE_CODE (t) != VAR_DECL || !DECL_THREAD_LOCAL_P (t))
{
@@ -10793,12 +11394,37 @@ c_finish_omp_clauses (tree clauses)
}
goto check_dup_generic;
+ case OMP_CLAUSE_LINEAR:
+ t = OMP_CLAUSE_DECL (c);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+ && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "linear clause applied to non-integral non-pointer "
+ "variable with type %qT", TREE_TYPE (t));
+ remove = true;
+ break;
+ }
+ if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) == POINTER_TYPE)
+ {
+ tree s = OMP_CLAUSE_LINEAR_STEP (c);
+ s = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR,
+ OMP_CLAUSE_DECL (c), s);
+ s = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
+ sizetype, s, OMP_CLAUSE_DECL (c));
+ if (s == error_mark_node)
+ s = size_one_node;
+ OMP_CLAUSE_LINEAR_STEP (c) = s;
+ }
+ goto check_dup_generic;
+
check_dup_generic:
t = OMP_CLAUSE_DECL (c);
if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
{
error_at (OMP_CLAUSE_LOCATION (c),
- "%qE is not a variable in clause %qs", t, name);
+ "%qE is not a variable in clause %qs", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
remove = true;
}
else if (bitmap_bit_p (&generic_head, DECL_UID (t))
@@ -10814,7 +11440,6 @@ c_finish_omp_clauses (tree clauses)
break;
case OMP_CLAUSE_FIRSTPRIVATE:
- name = "firstprivate";
t = OMP_CLAUSE_DECL (c);
need_complete = true;
need_implicitly_determined = true;
@@ -10836,7 +11461,6 @@ c_finish_omp_clauses (tree clauses)
break;
case OMP_CLAUSE_LASTPRIVATE:
- name = "lastprivate";
t = OMP_CLAUSE_DECL (c);
need_complete = true;
need_implicitly_determined = true;
@@ -10857,16 +11481,167 @@ c_finish_omp_clauses (tree clauses)
bitmap_set_bit (&lastprivate_head, DECL_UID (t));
break;
+ case OMP_CLAUSE_ALIGNED:
+ t = OMP_CLAUSE_DECL (c);
+ if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qE is not a variable in %<aligned%> clause", t);
+ remove = true;
+ }
+ else if (bitmap_bit_p (&aligned_head, DECL_UID (t)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qE appears more than once in %<aligned%> clauses",
+ t);
+ remove = true;
+ }
+ else
+ bitmap_set_bit (&aligned_head, DECL_UID (t));
+ break;
+
+ case OMP_CLAUSE_DEPEND:
+ t = OMP_CLAUSE_DECL (c);
+ if (TREE_CODE (t) == TREE_LIST)
+ {
+ if (handle_omp_array_sections (c))
+ remove = true;
+ break;
+ }
+ if (t == error_mark_node)
+ remove = true;
+ else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qE is not a variable in %<depend%> clause", t);
+ remove = true;
+ }
+ else if (!c_mark_addressable (t))
+ remove = true;
+ break;
+
+ case OMP_CLAUSE_MAP:
+ case OMP_CLAUSE_TO:
+ case OMP_CLAUSE_FROM:
+ t = OMP_CLAUSE_DECL (c);
+ if (TREE_CODE (t) == TREE_LIST)
+ {
+ if (handle_omp_array_sections (c))
+ remove = true;
+ else
+ {
+ t = OMP_CLAUSE_DECL (c);
+ if (!COMPLETE_TYPE_P (TREE_TYPE (t)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "array section does not have mappable type "
+ "in %qs clause",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ }
+ break;
+ }
+ if (t == error_mark_node)
+ remove = true;
+ else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qE is not a variable in %qs clause", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ else if (TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qD is threadprivate variable in %qs clause", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ else if (!c_mark_addressable (t))
+ remove = true;
+ else if (!COMPLETE_TYPE_P (TREE_TYPE (t))
+ && !(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qD does not have a mappable type in %qs clause", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ else if (bitmap_bit_p (&generic_head, DECL_UID (t)))
+ {
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+ error ("%qD appears more than once in motion clauses", t);
+ else
+ error ("%qD appears more than once in map clauses", t);
+ remove = true;
+ }
+ else
+ bitmap_set_bit (&generic_head, DECL_UID (t));
+ break;
+
+ case OMP_CLAUSE_UNIFORM:
+ t = OMP_CLAUSE_DECL (c);
+ if (TREE_CODE (t) != PARM_DECL)
+ {
+ if (DECL_P (t))
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qD is not an argument in %<uniform%> clause", t);
+ else
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qE is not an argument in %<uniform%> clause", t);
+ remove = true;
+ }
+ break;
+
+ case OMP_CLAUSE_NOWAIT:
+ if (copyprivate_seen)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<nowait%> clause must not be used together "
+ "with %<copyprivate%>");
+ remove = true;
+ break;
+ }
+ nowait_clause = pc;
+ pc = &OMP_CLAUSE_CHAIN (c);
+ continue;
+
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NUM_THREADS:
+ case OMP_CLAUSE_NUM_TEAMS:
+ case OMP_CLAUSE_THREAD_LIMIT:
case OMP_CLAUSE_SCHEDULE:
- case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_COLLAPSE:
case OMP_CLAUSE_FINAL:
case OMP_CLAUSE_MERGEABLE:
+ case OMP_CLAUSE_SAFELEN:
+ case OMP_CLAUSE_SIMDLEN:
+ case OMP_CLAUSE_DEVICE:
+ case OMP_CLAUSE_DIST_SCHEDULE:
+ case OMP_CLAUSE_PARALLEL:
+ case OMP_CLAUSE_FOR:
+ case OMP_CLAUSE_SECTIONS:
+ case OMP_CLAUSE_TASKGROUP:
+ case OMP_CLAUSE_PROC_BIND:
+ pc = &OMP_CLAUSE_CHAIN (c);
+ continue;
+
+ case OMP_CLAUSE_INBRANCH:
+ case OMP_CLAUSE_NOTINBRANCH:
+ if (branch_seen)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<inbranch%> clause is incompatible with "
+ "%<notinbranch%>");
+ remove = true;
+ break;
+ }
+ branch_seen = true;
pc = &OMP_CLAUSE_CHAIN (c);
continue;
@@ -10912,7 +11687,8 @@ c_finish_omp_clauses (tree clauses)
{
error_at (OMP_CLAUSE_LOCATION (c),
"%qE is predetermined %qs for %qs",
- t, share_name, name);
+ t, share_name,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
remove = true;
}
}
@@ -11016,3 +11792,205 @@ c_build_va_arg (location_t loc, tree expr, tree type)
"C++ requires promoted type, not enum type, in %<va_arg%>");
return build_va_arg (loc, expr, type);
}
+
+/* Return truthvalue of whether T1 is the same tree structure as T2.
+ Return 1 if they are the same. Return 0 if they are different. */
+
+bool
+c_tree_equal (tree t1, tree t2)
+{
+ enum tree_code code1, code2;
+
+ if (t1 == t2)
+ return true;
+ if (!t1 || !t2)
+ return false;
+
+ for (code1 = TREE_CODE (t1);
+ CONVERT_EXPR_CODE_P (code1)
+ || code1 == NON_LVALUE_EXPR;
+ code1 = TREE_CODE (t1))
+ t1 = TREE_OPERAND (t1, 0);
+ for (code2 = TREE_CODE (t2);
+ CONVERT_EXPR_CODE_P (code2)
+ || code2 == NON_LVALUE_EXPR;
+ code2 = TREE_CODE (t2))
+ t2 = TREE_OPERAND (t2, 0);
+
+ /* They might have become equal now. */
+ if (t1 == t2)
+ return true;
+
+ if (code1 != code2)
+ return false;
+
+ switch (code1)
+ {
+ case INTEGER_CST:
+ return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
+ && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2);
+
+ case REAL_CST:
+ return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
+
+ case STRING_CST:
+ return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
+ && !memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
+ TREE_STRING_LENGTH (t1));
+
+ case FIXED_CST:
+ return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1),
+ TREE_FIXED_CST (t2));
+
+ case COMPLEX_CST:
+ return c_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2))
+ && c_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2));
+
+ case VECTOR_CST:
+ return operand_equal_p (t1, t2, OEP_ONLY_CONST);
+
+ case CONSTRUCTOR:
+ /* We need to do this when determining whether or not two
+ non-type pointer to member function template arguments
+ are the same. */
+ if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2))
+ || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2))
+ return false;
+ {
+ tree field, value;
+ unsigned int i;
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value)
+ {
+ constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i);
+ if (!c_tree_equal (field, elt2->index)
+ || !c_tree_equal (value, elt2->value))
+ return false;
+ }
+ }
+ return true;
+
+ case TREE_LIST:
+ if (!c_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)))
+ return false;
+ if (!c_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2)))
+ return false;
+ return c_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2));
+
+ case SAVE_EXPR:
+ return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+
+ case CALL_EXPR:
+ {
+ tree arg1, arg2;
+ call_expr_arg_iterator iter1, iter2;
+ if (!c_tree_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
+ return false;
+ for (arg1 = first_call_expr_arg (t1, &iter1),
+ arg2 = first_call_expr_arg (t2, &iter2);
+ arg1 && arg2;
+ arg1 = next_call_expr_arg (&iter1),
+ arg2 = next_call_expr_arg (&iter2))
+ if (!c_tree_equal (arg1, arg2))
+ return false;
+ if (arg1 || arg2)
+ return false;
+ return true;
+ }
+
+ case TARGET_EXPR:
+ {
+ tree o1 = TREE_OPERAND (t1, 0);
+ tree o2 = TREE_OPERAND (t2, 0);
+
+ /* Special case: if either target is an unallocated VAR_DECL,
+ it means that it's going to be unified with whatever the
+ TARGET_EXPR is really supposed to initialize, so treat it
+ as being equivalent to anything. */
+ if (TREE_CODE (o1) == VAR_DECL && DECL_NAME (o1) == NULL_TREE
+ && !DECL_RTL_SET_P (o1))
+ /*Nop*/;
+ else if (TREE_CODE (o2) == VAR_DECL && DECL_NAME (o2) == NULL_TREE
+ && !DECL_RTL_SET_P (o2))
+ /*Nop*/;
+ else if (!c_tree_equal (o1, o2))
+ return false;
+
+ return c_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+ }
+
+ case COMPONENT_REF:
+ if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1))
+ return false;
+ return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+
+ case PARM_DECL:
+ case VAR_DECL:
+ case CONST_DECL:
+ case FIELD_DECL:
+ case FUNCTION_DECL:
+ case IDENTIFIER_NODE:
+ case SSA_NAME:
+ return false;
+
+ case TREE_VEC:
+ {
+ unsigned ix;
+ if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2))
+ return false;
+ for (ix = TREE_VEC_LENGTH (t1); ix--;)
+ if (!c_tree_equal (TREE_VEC_ELT (t1, ix),
+ TREE_VEC_ELT (t2, ix)))
+ return false;
+ return true;
+ }
+
+ default:
+ break;
+ }
+
+ switch (TREE_CODE_CLASS (code1))
+ {
+ case tcc_unary:
+ case tcc_binary:
+ case tcc_comparison:
+ case tcc_expression:
+ case tcc_vl_exp:
+ case tcc_reference:
+ case tcc_statement:
+ {
+ int i, n = TREE_OPERAND_LENGTH (t1);
+
+ switch (code1)
+ {
+ case PREINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ n = 1;
+ break;
+ case ARRAY_REF:
+ n = 2;
+ break;
+ default:
+ break;
+ }
+
+ if (TREE_CODE_CLASS (code1) == tcc_vl_exp
+ && n != TREE_OPERAND_LENGTH (t2))
+ return false;
+
+ for (i = 0; i < n; ++i)
+ if (!c_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i)))
+ return false;
+
+ return true;
+ }
+
+ case tcc_type:
+ return comptypes (t1, t2);
+ default:
+ gcc_unreachable ();
+ }
+ /* We can get here with --disable-checking. */
+ return false;
+}