/* Parser for C and Objective-C.
- Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011,
- 2012 Free Software Foundation, Inc.
+ Copyright (C) 1987-2013 Free Software Foundation, Inc.
Parser actions based on the old Bison parser; structure somewhat
influenced by and fragments based on the C++ parser.
#include "coretypes.h"
#include "tm.h" /* For rtl.h: needs enum reg_class. */
#include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "trans-mem.h"
#include "langhooks.h"
#include "input.h"
#include "cpplib.h"
#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"
#include "target.h"
#include "cgraph.h"
#include "plugin.h"
+#include "omp-low.h"
\f
/* Initialization routine for this file. */
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. */
case RID_UNION:
case RID_TYPEOF:
case RID_CONST:
+ case RID_ATOMIC:
case RID_VOLATILE:
case RID_RESTRICT:
case RID_ATTRIBUTE:
case RID_FRACT:
case RID_ACCUM:
case RID_SAT:
+ case RID_AUTO_TYPE:
return true;
default:
return false;
case RID_VOLATILE:
case RID_RESTRICT:
case RID_ATTRIBUTE:
+ case RID_ATOMIC:
return true;
default:
return false;
case RID_ACCUM:
case RID_SAT:
case RID_ALIGNAS:
+ case RID_ATOMIC:
+ case RID_AUTO_TYPE:
return true;
default:
return false;
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--;
}
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;
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,
- bool, enum c_lookahead_kind);
+ bool, bool, bool, enum c_lookahead_kind);
static struct c_typespec c_parser_enum_specifier (c_parser *);
static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);
static tree c_parser_struct_declaration (c_parser *);
static void c_parser_statement_after_labels (c_parser *);
static void c_parser_if_statement (c_parser *);
static void c_parser_switch_statement (c_parser *);
-static void c_parser_while_statement (c_parser *);
-static void c_parser_do_statement (c_parser *);
-static void c_parser_for_statement (c_parser *);
+static void c_parser_while_statement (c_parser *, bool);
+static void c_parser_do_statement (c_parser *, bool);
+static void c_parser_for_statement (c_parser *, bool);
static tree c_parser_asm_statement (c_parser *);
-static tree c_parser_asm_operands (c_parser *, bool);
+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 *);
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. */
static bool c_parser_objc_diagnose_bad_element_prefix
(c_parser *, struct c_declspecs *);
+/* Cilk Plus supporting routines. */
+static void c_parser_cilk_simd (c_parser *);
+static bool c_parser_cilk_verify_simd (c_parser *, enum pragma_context);
+static tree c_parser_array_notation (location_t, c_parser *, tree, tree);
+
/* Parse a translation unit (C90 6.7, C99 6.9).
translation-unit:
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
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;
fndef_ok = !nested;
}
- c_parser_declspecs (parser, specs, true, true, start_attr_ok, cla_nonabstract_decl);
+ c_parser_declspecs (parser, specs, true, true, start_attr_ok,
+ true, true, cla_nonabstract_decl);
if (parser->error)
{
c_parser_skip_to_end_of_block_or_statement (parser);
return;
}
finish_declspecs (specs);
+ bool auto_type_p = specs->typespec_word == cts_auto_type;
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
- if (empty_ok)
+ if (auto_type_p)
+ error_at (here, "%<__auto_type%> in empty declaration");
+ else if (empty_ok)
shadow_tag (specs);
else
{
shadow_tag_warned (specs, 1);
return;
}
- else if (c_dialect_objc ())
+ else if (c_dialect_objc () && !auto_type_p)
{
/* Prefix attributes are an error on method decls. */
switch (c_parser_peek_token (parser)->type)
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;
+ }
+ if (auto_type_p && declarator->kind != cdk_id)
+ {
+ error_at (here,
+ "%<__auto_type%> requires a plain identifier"
+ " as declarator");
c_parser_skip_to_end_of_block_or_statement (parser);
return;
}
struct c_expr init;
location_t init_loc;
c_parser_consume_token (parser);
- /* The declaration of the variable is in effect while
- its initializer is parsed. */
- d = start_decl (declarator, specs, true,
- chainon (postfix_attrs, all_prefix_attrs));
- if (!d)
- d = error_mark_node;
- start_init (d, asm_name, global_bindings_p ());
- init_loc = c_parser_peek_token (parser)->location;
- init = c_parser_initializer (parser);
- finish_init ();
+ if (auto_type_p)
+ {
+ start_init (NULL_TREE, asm_name, global_bindings_p ());
+ init_loc = c_parser_peek_token (parser)->location;
+ init = c_parser_expr_no_commas (parser, NULL);
+ if (TREE_CODE (init.value) == COMPONENT_REF
+ && DECL_C_BIT_FIELD (TREE_OPERAND (init.value, 1)))
+ error_at (here,
+ "%<__auto_type%> used with a bit-field"
+ " initializer");
+ init = convert_lvalue_to_rvalue (init_loc, init, true, true);
+ tree init_type = TREE_TYPE (init.value);
+ /* As with typeof, remove _Atomic and const
+ qualifiers from atomic types. */
+ if (init_type != error_mark_node && TYPE_ATOMIC (init_type))
+ init_type
+ = c_build_qualified_type (init_type,
+ (TYPE_QUALS (init_type)
+ & ~(TYPE_QUAL_ATOMIC
+ | TYPE_QUAL_CONST)));
+ bool vm_type = variably_modified_type_p (init_type,
+ NULL_TREE);
+ if (vm_type)
+ init.value = c_save_expr (init.value);
+ finish_init ();
+ specs->typespec_kind = ctsk_typeof;
+ specs->locations[cdw_typedef] = init_loc;
+ specs->typedef_p = true;
+ specs->type = init_type;
+ if (vm_type)
+ {
+ bool maybe_const = true;
+ tree type_expr = c_fully_fold (init.value, false,
+ &maybe_const);
+ specs->expr_const_operands &= maybe_const;
+ if (specs->expr)
+ specs->expr = build2 (COMPOUND_EXPR,
+ TREE_TYPE (type_expr),
+ specs->expr, type_expr);
+ else
+ specs->expr = type_expr;
+ }
+ d = start_decl (declarator, specs, true,
+ 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);
+ }
+ else
+ {
+ /* The declaration of the variable is in effect while
+ its initializer is parsed. */
+ d = start_decl (declarator, specs, true,
+ 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);
+ finish_init ();
+ }
if (d != error_mark_node)
{
maybe_warn_string_init (TREE_TYPE (d), init);
}
else
{
+ if (auto_type_p)
+ {
+ error_at (here,
+ "%<__auto_type%> requires an initialized "
+ "data declaration");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
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);
}
if (c_parser_next_token_is (parser, CPP_COMMA))
{
+ if (auto_type_p)
+ {
+ error_at (here,
+ "%<__auto_type%> may only be used with"
+ " a single declarator");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
c_parser_consume_token (parser);
if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
all_prefix_attrs = chainon (c_parser_attributes (parser),
return;
}
}
+ else if (auto_type_p)
+ {
+ error_at (here,
+ "%<__auto_type%> requires an initialized data declaration");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
else if (!fndef_ok)
{
c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, "
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);
+ if (flag_enable_cilkplus && contains_array_notation_expr (fnbody))
+ fnbody = expand_array_notation_exprs (fnbody);
if (nested)
{
tree decl = current_function_decl;
/* Parse some declaration specifiers (possibly none) (C90 6.5, C99
6.7), adding them to SPECS (which may already include some).
Storage class specifiers are accepted iff SCSPEC_OK; type
- specifiers are accepted iff TYPESPEC_OK; attributes are accepted at
- the start iff START_ATTR_OK.
+ specifiers are accepted iff TYPESPEC_OK; alignment specifiers are
+ accepted iff ALIGNSPEC_OK; attributes are accepted at the start
+ iff START_ATTR_OK; __auto_type is accepted iff AUTO_TYPE_OK.
declaration-specifiers:
storage-class-specifier declaration-specifiers[opt]
static
auto
register
+ _Thread_local
+
+ (_Thread_local is new in C11.)
C99 6.7.4:
function-specifier:
struct-or-union-specifier
enum-specifier
typedef-name
+ atomic-type-specifier
(_Bool and _Complex are new in C99.)
+ (atomic-type-specifier is new in C11.)
C90 6.5.3, C99 6.7.3:
restrict
volatile
address-space-qualifier
+ _Atomic
(restrict is new in C99.)
+ (_Atomic is new in C11.)
GNU extensions:
type-specifier:
typeof-specifier
+ __auto_type
__int128
_Decimal32
_Decimal64
(_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf)
+ atomic-type-specifier
+ _Atomic ( type-name )
+
Objective-C:
type-specifier:
static void
c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
bool scspec_ok, bool typespec_ok, bool start_attr_ok,
+ bool alignspec_ok, bool auto_type_ok,
enum c_lookahead_kind la)
{
bool attrs_ok = start_attr_ok;
c_parser_peek_token (parser)->value);
c_parser_consume_token (parser);
break;
+ case RID_AUTO_TYPE:
+ if (!auto_type_ok)
+ goto out;
+ /* Fall through. */
case RID_UNSIGNED:
case RID_LONG:
case RID_INT128:
t = c_parser_typeof_specifier (parser);
declspecs_add_type (loc, specs, t);
break;
+ case RID_ATOMIC:
+ /* C parser handling of Objective-C constructs needs
+ checking for correct lvalue-to-rvalue conversions, and
+ the code in build_modify_expr handling various
+ Objective-C cases, and that in build_unary_op handling
+ Objective-C cases for increment / decrement, also needs
+ updating; uses of TYPE_MAIN_VARIANT in objc_compare_types
+ and objc_types_are_equivalent may also need updates. */
+ if (c_dialect_objc ())
+ sorry ("%<_Atomic%> in Objective-C");
+ /* C parser handling of OpenMP constructs needs checking for
+ correct lvalue-to-rvalue conversions. */
+ if (flag_openmp)
+ sorry ("%<_Atomic%> with OpenMP");
+ if (!flag_isoc11)
+ {
+ if (flag_isoc99)
+ pedwarn (loc, OPT_Wpedantic,
+ "ISO C99 does not support the %<_Atomic%> qualifier");
+ else
+ pedwarn (loc, OPT_Wpedantic,
+ "ISO C90 does not support the %<_Atomic%> qualifier");
+ }
+ attrs_ok = true;
+ tree value;
+ value = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ if (typespec_ok && c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ /* _Atomic ( type-name ). */
+ seen_type = true;
+ c_parser_consume_token (parser);
+ struct c_type_name *type = c_parser_type_name (parser);
+ t.kind = ctsk_typeof;
+ t.spec = error_mark_node;
+ t.expr = NULL_TREE;
+ t.expr_const_operands = true;
+ if (type != NULL)
+ t.spec = groktypename (type, &t.expr,
+ &t.expr_const_operands);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ if (t.spec != error_mark_node)
+ {
+ if (TREE_CODE (t.spec) == ARRAY_TYPE)
+ error_at (loc, "%<_Atomic%>-qualified array type");
+ else if (TREE_CODE (t.spec) == FUNCTION_TYPE)
+ error_at (loc, "%<_Atomic%>-qualified function type");
+ else if (TYPE_QUALS (t.spec) != TYPE_UNQUALIFIED)
+ error_at (loc, "%<_Atomic%> applied to a qualified type");
+ else
+ t.spec = c_build_qualified_type (t.spec, TYPE_QUAL_ATOMIC);
+ }
+ declspecs_add_type (loc, specs, t);
+ }
+ else
+ declspecs_add_qual (loc, specs, value);
+ break;
case RID_CONST:
case RID_VOLATILE:
case RID_RESTRICT:
declspecs_add_attrs (loc, specs, attrs);
break;
case RID_ALIGNAS:
+ if (!alignspec_ok)
+ goto out;
align = c_parser_alignas_specifier (parser);
declspecs_add_alignas (loc, specs, align);
break;
/* 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
}
specs = build_null_declspecs ();
decl_loc = c_parser_peek_token (parser)->location;
- c_parser_declspecs (parser, specs, false, true, true, cla_nonabstract_decl);
+ /* Strictly by the standard, we shouldn't allow _Alignas here,
+ but it appears to have been intended to allow it there, so
+ we're keeping it as it is until WG14 reaches a conclusion
+ of N1731.
+ <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1731.pdf> */
+ c_parser_declspecs (parser, specs, false, true, true,
+ true, false, cla_nonabstract_decl);
if (parser->error)
return NULL_TREE;
if (!specs->declspecs_seen_p)
if (was_vm)
ret.expr = c_fully_fold (expr.value, false, &ret.expr_const_operands);
pop_maybe_used (was_vm);
+ /* For use in macros such as those in <stdatomic.h>, remove
+ _Atomic and const qualifiers from atomic types. (Possibly
+ all qualifiers should be removed; const can be an issue for
+ more macros using typeof than just the <stdatomic.h>
+ ones.) */
+ if (ret.spec != error_mark_node && TYPE_ATOMIC (ret.spec))
+ ret.spec = c_build_qualified_type (ret.spec,
+ (TYPE_QUALS (ret.spec)
+ & ~(TYPE_QUAL_ATOMIC
+ | TYPE_QUAL_CONST)));
}
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
return ret;
type-qualifier-list type-qualifier
type-qualifier-list attributes
+ array-declarator:
+ [ type-qualifier-list[opt] assignment-expression[opt] ]
+ [ static type-qualifier-list[opt] assignment-expression ]
+ [ type-qualifier-list static assignment-expression ]
+ [ type-qualifier-list[opt] * ]
+
parameter-type-list:
parameter-list
parameter-list , ...
struct c_declspecs *quals_attrs = build_null_declspecs ();
struct c_declarator *inner;
c_parser_consume_token (parser);
- c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
+ c_parser_declspecs (parser, quals_attrs, false, false, true,
+ false, false, cla_prefer_id);
inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
if (inner == NULL)
return NULL;
struct c_declspecs *quals_attrs = build_null_declspecs ();
bool static_seen;
bool star_seen;
- tree dimen;
+ struct c_expr dimen;
+ dimen.value = NULL_TREE;
+ dimen.original_code = ERROR_MARK;
+ dimen.original_type = NULL_TREE;
c_parser_consume_token (parser);
- c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
+ c_parser_declspecs (parser, quals_attrs, false, false, true,
+ false, false, cla_prefer_id);
static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC);
if (static_seen)
c_parser_consume_token (parser);
if (static_seen && !quals_attrs->declspecs_seen_p)
- c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
+ c_parser_declspecs (parser, quals_attrs, false, false, true,
+ false, false, cla_prefer_id);
if (!quals_attrs->declspecs_seen_p)
quals_attrs = NULL;
/* If "static" is present, there must be an array dimension.
if (static_seen)
{
star_seen = false;
- dimen = c_parser_expr_no_commas (parser, NULL).value;
+ dimen = c_parser_expr_no_commas (parser, NULL);
}
else
{
if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
{
- dimen = NULL_TREE;
+ dimen.value = NULL_TREE;
star_seen = false;
}
+ else if (flag_enable_cilkplus
+ && c_parser_next_token_is (parser, CPP_COLON))
+ {
+ dimen.value = error_mark_node;
+ star_seen = false;
+ error_at (c_parser_peek_token (parser)->location,
+ "array notations cannot be used in declaration");
+ c_parser_consume_token (parser);
+ }
else if (c_parser_next_token_is (parser, CPP_MULT))
{
if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE)
{
- dimen = NULL_TREE;
+ dimen.value = NULL_TREE;
star_seen = true;
c_parser_consume_token (parser);
}
else
{
star_seen = false;
- dimen = c_parser_expr_no_commas (parser, NULL).value;
+ dimen = c_parser_expr_no_commas (parser, NULL);
}
}
else
{
star_seen = false;
- dimen = c_parser_expr_no_commas (parser, NULL).value;
+ dimen = c_parser_expr_no_commas (parser, NULL);
}
}
if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
c_parser_consume_token (parser);
+ else if (flag_enable_cilkplus
+ && c_parser_next_token_is (parser, CPP_COLON))
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "array notations cannot be used in declaration");
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
+ return NULL;
+ }
else
{
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
return NULL;
}
- if (dimen)
- mark_exp_read (dimen);
- declarator = build_array_declarator (brace_loc, dimen, quals_attrs,
+ if (dimen.value)
+ dimen = convert_lvalue_to_rvalue (brace_loc, dimen, true, true);
+ declarator = build_array_declarator (brace_loc, dimen.value, quals_attrs,
static_seen, star_seen);
if (declarator == NULL)
return NULL;
/* 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))
{
declspecs_add_attrs (input_location, specs, attrs);
attrs = NULL_TREE;
}
- c_parser_declspecs (parser, specs, true, true, true, cla_nonabstract_decl);
+ c_parser_declspecs (parser, specs, true, true, true, true, false,
+ cla_nonabstract_decl);
finish_declspecs (specs);
pending_xref_error ();
prefix_attrs = specs->attrs;
case RID_SAT:
case RID_TRANSACTION_ATOMIC:
case RID_TRANSACTION_CANCEL:
+ case RID_ATOMIC:
+ case RID_AUTO_TYPE:
ok = true;
break;
default:
struct c_declarator *declarator;
struct c_type_name *ret;
bool dummy = false;
- c_parser_declspecs (parser, specs, false, true, true, cla_prefer_type);
+ c_parser_declspecs (parser, specs, false, true, true, false, false,
+ cla_prefer_type);
if (!specs->declspecs_seen_p)
{
c_parser_error (parser, "expected specifier-qualifier-list");
ret = c_parser_expr_no_commas (parser, NULL);
if (TREE_CODE (ret.value) != STRING_CST
&& TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR)
- ret = default_function_array_read_conversion (loc, ret);
+ ret = convert_lvalue_to_rvalue (loc, ret, true, true);
return ret;
}
}
c_parser_consume_token (parser);
exp_loc = c_parser_peek_token (parser)->location;
next = c_parser_expr_no_commas (parser, NULL);
- next = default_function_array_read_conversion (exp_loc,
- next);
+ next = convert_lvalue_to_rvalue (exp_loc, next,
+ true, true);
rec = build_compound_expr (comma_loc, rec, next.value);
}
parse_message_args:
if (init.value != NULL_TREE
&& TREE_CODE (init.value) != STRING_CST
&& TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR)
- init = default_function_array_read_conversion (loc, init);
+ init = convert_lvalue_to_rvalue (loc, init, true, true);
}
process_init_element (init, false, braced_init_obstack);
}
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)
}
stmt = c_begin_compound_stmt (true);
c_parser_compound_statement_nostart (parser);
+
+ /* If the compound stmt contains array notations, then we expand them. */
+ if (flag_enable_cilkplus && contains_array_notation_expr (stmt))
+ stmt = expand_array_notation_exprs (stmt);
return c_end_compound_stmt (brace_loc, stmt, true);
}
{
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)
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);
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);
}
}
}
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
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
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
c_parser_switch_statement (parser);
break;
case RID_WHILE:
- c_parser_while_statement (parser);
+ c_parser_while_statement (parser, false);
break;
case RID_DO:
- c_parser_do_statement (parser);
+ c_parser_do_statement (parser, false);
break;
case RID_FOR:
- c_parser_for_statement (parser);
+ c_parser_for_statement (parser, false);
+ break;
+ case RID_CILK_SYNC:
+ c_parser_consume_token (parser);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ if (!flag_enable_cilkplus)
+ error_at (loc, "-fcilkplus must be enabled to use %<_Cilk_sync%>");
+ else
+ add_stmt (build_cilk_sync ());
break;
case RID_GOTO:
c_parser_consume_token (parser);
}
else if (c_parser_next_token_is (parser, CPP_MULT))
{
- tree val;
+ struct c_expr val;
c_parser_consume_token (parser);
- val = c_parser_expression (parser).value;
- mark_exp_read (val);
- stmt = c_finish_goto_ptr (loc, val);
+ val = c_parser_expression (parser);
+ val = convert_lvalue_to_rvalue (loc, val, false, true);
+ stmt = c_finish_goto_ptr (loc, val.value);
}
else
c_parser_error (parser, "expected identifier or %<*%>");
}
else
{
- tree expr = c_parser_expression (parser).value;
- expr = c_fully_fold (expr, false, NULL);
- stmt = objc_build_throw_stmt (loc, expr);
+ struct c_expr expr = c_parser_expression (parser);
+ expr = convert_lvalue_to_rvalue (loc, expr, false, false);
+ expr.value = c_fully_fold (expr.value, false, NULL);
+ stmt = objc_build_throw_stmt (loc, expr.value);
goto expect_semicolon;
}
break;
bool first_if = false;
tree first_body, second_body;
bool in_if_block;
+ tree if_stmt;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF));
c_parser_consume_token (parser);
else
second_body = NULL_TREE;
c_finish_if_stmt (loc, cond, first_body, second_body, first_if);
- add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
+ if_stmt = c_end_compound_stmt (loc, block, flag_isoc99);
+
+ /* If the if statement contains array notations, then we expand them. */
+ if (flag_enable_cilkplus && contains_array_notation_expr (if_stmt))
+ if_stmt = fix_conditional_array_notations (if_stmt);
+ add_stmt (if_stmt);
}
/* Parse a switch statement (C90 6.6.4, C99 6.8.4).
static void
c_parser_switch_statement (c_parser *parser)
{
+ struct c_expr ce;
tree block, expr, body, save_break;
location_t switch_loc = c_parser_peek_token (parser)->location;
location_t switch_cond_loc;
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
switch_cond_loc = c_parser_peek_token (parser)->location;
- expr = c_parser_expression (parser).value;
+ ce = c_parser_expression (parser);
+ ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, false);
+ expr = ce.value;
+ if (flag_enable_cilkplus && contains_array_notation_expr (expr))
+ {
+ error_at (switch_cond_loc,
+ "array notations cannot be used as a condition for switch "
+ "statement");
+ expr = error_mark_node;
+ }
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
}
else
*/
static void
-c_parser_while_statement (c_parser *parser)
+c_parser_while_statement (c_parser *parser, bool ivdep)
{
tree block, cond, body, save_break, save_cont;
location_t loc;
block = c_begin_compound_stmt (flag_isoc99);
loc = c_parser_peek_token (parser)->location;
cond = c_parser_paren_condition (parser);
+ if (flag_enable_cilkplus && contains_array_notation_expr (cond))
+ {
+ error_at (loc, "array notations cannot be used as a condition for while "
+ "statement");
+ cond = error_mark_node;
+ }
+
+ if (ivdep && cond != error_mark_node)
+ cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_ivdep_kind));
save_break = c_break_label;
c_break_label = NULL_TREE;
save_cont = c_cont_label;
*/
static void
-c_parser_do_statement (c_parser *parser)
+c_parser_do_statement (c_parser *parser, bool ivdep)
{
tree block, cond, body, save_break, save_cont, new_break, new_cont;
location_t loc;
new_cont = c_cont_label;
c_cont_label = save_cont;
cond = c_parser_paren_condition (parser);
+ if (flag_enable_cilkplus && contains_array_notation_expr (cond))
+ {
+ error_at (loc, "array notations cannot be used as a condition for a "
+ "do-while statement");
+ cond = error_mark_node;
+ }
+ if (ivdep && cond != error_mark_node)
+ cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_ivdep_kind));
if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
c_parser_skip_to_end_of_block_or_statement (parser);
c_finish_loop (loc, cond, NULL, body, new_break, new_cont, false);
*/
static void
-c_parser_for_statement (c_parser *parser)
+c_parser_for_statement (c_parser *parser, bool ivdep)
{
tree block, cond, incr, save_break, save_cont, body;
/* The following are only used when parsing an ObjC foreach statement. */
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))
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);
{
init_expr:
{
+ struct c_expr ce;
tree init_expression;
- init_expression = c_parser_expression (parser).value;
+ ce = c_parser_expression (parser);
+ init_expression = ce.value;
parser->objc_could_be_foreach_context = false;
if (c_parser_next_token_is_keyword (parser, RID_IN))
{
}
else
{
+ ce = convert_lvalue_to_rvalue (loc, ce, true, false);
+ init_expression = ce.value;
c_finish_expr_stmt (loc, init_expression);
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
{
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
- c_parser_consume_token (parser);
- cond = NULL_TREE;
+ if (ivdep)
+ {
+ c_parser_error (parser, "missing loop condition in loop with "
+ "%<GCC ivdep%> pragma");
+ cond = error_mark_node;
+ }
+ else
+ {
+ c_parser_consume_token (parser);
+ cond = NULL_TREE;
+ }
}
else
{
cond = c_parser_condition (parser);
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ if (flag_enable_cilkplus && contains_array_notation_expr (cond))
+ {
+ error_at (loc, "array notations cannot be used in a "
+ "condition for a for-loop");
+ cond = error_mark_node;
+ }
+ c_parser_skip_until_found (parser, CPP_SEMICOLON,
+ "expected %<;%>");
}
+ if (ivdep && cond != error_mark_node)
+ cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_ivdep_kind));
}
/* Parse the increment expression (the third expression in a
for-statement). In the case of a foreach-statement, this is
collection_expression = c_fully_fold (c_parser_expression (parser).value,
false, NULL);
else
- incr = c_process_expr_stmt (loc, c_parser_expression (parser).value);
+ {
+ struct c_expr ce = c_parser_expression (parser);
+ ce = convert_lvalue_to_rvalue (loc, ce, true, false);
+ incr = c_process_expr_stmt (loc, ce.value);
+ }
}
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
}
/* For asm goto, we don't allow output operands, but reserve
the slot for a future extension that does allow them. */
if (!is_goto)
- outputs = c_parser_asm_operands (parser, false);
+ outputs = c_parser_asm_operands (parser);
break;
case 1:
- inputs = c_parser_asm_operands (parser, true);
+ inputs = c_parser_asm_operands (parser);
break;
case 2:
clobbers = c_parser_asm_clobbers (parser);
goto error;
}
-/* Parse asm operands, a GNU extension. If CONVERT_P (for inputs but
- not outputs), apply the default conversion of functions and arrays
- to pointers.
+/* Parse asm operands, a GNU extension.
asm-operands:
asm-operand
*/
static tree
-c_parser_asm_operands (c_parser *parser, bool convert_p)
+c_parser_asm_operands (c_parser *parser)
{
tree list = NULL_TREE;
- location_t loc;
while (true)
{
tree name, str;
parser->lex_untranslated_string = true;
return NULL_TREE;
}
- loc = c_parser_peek_token (parser)->location;
expr = c_parser_expression (parser);
mark_exp_read (expr.value);
- if (convert_p)
- expr = default_function_array_conversion (loc, expr);
- expr.value = c_fully_fold (expr.value, false, NULL);
parser->lex_untranslated_string = true;
if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
{
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)
{
c_parser_consume_token (parser);
exp_location = c_parser_peek_token (parser)->location;
rhs = c_parser_expr_no_commas (parser, NULL);
- rhs = default_function_array_read_conversion (exp_location, rhs);
+ rhs = convert_lvalue_to_rvalue (exp_location, rhs, true, true);
+
ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type,
code, exp_location, rhs.value,
rhs.original_type);
*/
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;
cond_loc = c_parser_peek_token (parser)->location;
- cond = default_function_array_read_conversion (cond_loc, cond);
+ cond = convert_lvalue_to_rvalue (cond_loc, cond, true, true);
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_COLON))
{
}
{
location_t exp2_loc = c_parser_peek_token (parser)->location;
- exp2 = c_parser_conditional_expression (parser, NULL);
- exp2 = default_function_array_read_conversion (exp2_loc, exp2);
+ exp2 = c_parser_conditional_expression (parser, NULL, NULL_TREE);
+ exp2 = convert_lvalue_to_rvalue (exp2_loc, exp2, true, true);
}
c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
ret.value = build_conditional_expr (colon_loc, cond.value,
/* 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
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
break; \
} \
stack[sp - 1].expr \
- = default_function_array_read_conversion (stack[sp - 1].loc, \
- stack[sp - 1].expr); \
+ = convert_lvalue_to_rvalue (stack[sp - 1].loc, \
+ stack[sp - 1].expr, true, true); \
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); \
+ = convert_lvalue_to_rvalue (stack[sp].loc, \
+ stack[sp].expr, true, true); \
+ 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)
{
}
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)
{
case TRUTH_ANDIF_EXPR:
stack[sp].expr
- = default_function_array_read_conversion (stack[sp].loc,
- stack[sp].expr);
+ = convert_lvalue_to_rvalue (stack[sp].loc,
+ stack[sp].expr, true, true);
stack[sp].expr.value = c_objc_common_truthvalue_conversion
(stack[sp].loc, default_conversion (stack[sp].expr.value));
c_inhibit_evaluation_warnings += (stack[sp].expr.value
break;
case TRUTH_ORIF_EXPR:
stack[sp].expr
- = default_function_array_read_conversion (stack[sp].loc,
- stack[sp].expr);
+ = convert_lvalue_to_rvalue (stack[sp].loc,
+ stack[sp].expr, true, true);
stack[sp].expr.value = c_objc_common_truthvalue_conversion
(stack[sp].loc, default_conversion (stack[sp].expr.value));
c_inhibit_evaluation_warnings += (stack[sp].expr.value
{
location_t expr_loc = c_parser_peek_token (parser)->location;
expr = c_parser_cast_expression (parser, NULL);
- expr = default_function_array_read_conversion (expr_loc, expr);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true);
}
ret.value = c_cast_expr (cast_loc, type_name, expr.value);
ret.original_code = ERROR_MARK;
c_parser_consume_token (parser);
exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_read_conversion (exp_loc, op);
- return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op);
+
+ /* If there is array notations in op, we expand them. */
+ if (flag_enable_cilkplus && TREE_CODE (op.value) == ARRAY_NOTATION_REF)
+ return fix_array_notation_expr (exp_loc, PREINCREMENT_EXPR, op);
+ else
+ {
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op);
+ }
case CPP_MINUS_MINUS:
c_parser_consume_token (parser);
exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_read_conversion (exp_loc, op);
- return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op);
+
+ /* If there is array notations in op, we expand them. */
+ if (flag_enable_cilkplus && TREE_CODE (op.value) == ARRAY_NOTATION_REF)
+ return fix_array_notation_expr (exp_loc, PREDECREMENT_EXPR, op);
+ else
+ {
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op);
+ }
case CPP_AND:
c_parser_consume_token (parser);
op = c_parser_cast_expression (parser, NULL);
c_parser_consume_token (parser);
exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_read_conversion (exp_loc, op);
+ op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
ret.value = build_indirect_ref (op_loc, op.value, RO_UNARY_STAR);
return ret;
case CPP_PLUS:
c_parser_consume_token (parser);
exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_read_conversion (exp_loc, op);
+ op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
return parser_build_unary_op (op_loc, CONVERT_EXPR, op);
case CPP_MINUS:
c_parser_consume_token (parser);
exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_read_conversion (exp_loc, op);
+ op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
return parser_build_unary_op (op_loc, NEGATE_EXPR, op);
case CPP_COMPL:
c_parser_consume_token (parser);
exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_read_conversion (exp_loc, op);
+ op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op);
case CPP_NOT:
c_parser_consume_token (parser);
exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- op = default_function_array_read_conversion (exp_loc, op);
+ op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op);
case CPP_AND_AND:
/* Refer to the address of a label as a pointer. */
stores the arguments in CEXPR_LIST. */
static bool
c_parser_get_builtin_args (c_parser *parser, const char *bname,
- vec<c_expr_t, va_gc> **ret_cexpr_list)
+ vec<c_expr_t, va_gc> **ret_cexpr_list,
+ bool choose_expr_p)
{
location_t loc = c_parser_peek_token (parser)->location;
vec<c_expr_t, va_gc> *cexpr_list;
c_expr_t expr;
+ bool saved_force_folding_builtin_constant_p;
*ret_cexpr_list = NULL;
if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
return true;
}
+ saved_force_folding_builtin_constant_p
+ = force_folding_builtin_constant_p;
+ force_folding_builtin_constant_p |= choose_expr_p;
expr = c_parser_expr_no_commas (parser, NULL);
+ force_folding_builtin_constant_p
+ = saved_force_folding_builtin_constant_p;
vec_alloc (cexpr_list, 1);
C_EXPR_APPEND (cexpr_list, expr);
while (c_parser_next_token_is (parser, CPP_COMMA))
return true;
}
+/* This represents a single generic-association. */
+
+struct c_generic_association
+{
+ /* The location of the starting token of the type. */
+ location_t type_location;
+ /* The association's type, or NULL_TREE for 'default'. */
+ tree type;
+ /* The association's expression. */
+ struct c_expr expression;
+};
+
+/* Parse a generic-selection. (C11 6.5.1.1).
+
+ generic-selection:
+ _Generic ( assignment-expression , generic-assoc-list )
+
+ generic-assoc-list:
+ generic-association
+ generic-assoc-list , generic-association
+
+ generic-association:
+ type-name : assignment-expression
+ default : assignment-expression
+*/
+
+static struct c_expr
+c_parser_generic_selection (c_parser *parser)
+{
+ vec<c_generic_association> associations = vNULL;
+ struct c_expr selector, error_expr;
+ tree selector_type;
+ struct c_generic_association matched_assoc;
+ bool match_found = false;
+ location_t generic_loc, selector_loc;
+
+ error_expr.original_code = ERROR_MARK;
+ error_expr.original_type = NULL;
+ error_expr.value = error_mark_node;
+ matched_assoc.type_location = UNKNOWN_LOCATION;
+ matched_assoc.type = NULL_TREE;
+ matched_assoc.expression = error_expr;
+
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_GENERIC));
+ generic_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ if (!flag_isoc11)
+ {
+ if (flag_isoc99)
+ pedwarn (generic_loc, OPT_Wpedantic,
+ "ISO C99 does not support %<_Generic%>");
+ else
+ pedwarn (generic_loc, OPT_Wpedantic,
+ "ISO C90 does not support %<_Generic%>");
+ }
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return error_expr;
+
+ c_inhibit_evaluation_warnings++;
+ selector_loc = c_parser_peek_token (parser)->location;
+ selector = c_parser_expr_no_commas (parser, NULL);
+ selector = default_function_array_conversion (selector_loc, selector);
+ c_inhibit_evaluation_warnings--;
+
+ if (selector.value == error_mark_node)
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return selector;
+ }
+ selector_type = TREE_TYPE (selector.value);
+ /* In ISO C terms, rvalues (including the controlling expression of
+ _Generic) do not have qualified types. */
+ if (TREE_CODE (selector_type) != ARRAY_TYPE)
+ selector_type = TYPE_MAIN_VARIANT (selector_type);
+ /* In ISO C terms, _Noreturn is not part of the type of expressions
+ such as &abort, but in GCC it is represented internally as a type
+ qualifier. */
+ if (FUNCTION_POINTER_TYPE_P (selector_type)
+ && TYPE_QUALS (TREE_TYPE (selector_type)) != TYPE_UNQUALIFIED)
+ selector_type
+ = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (selector_type)));
+
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return error_expr;
+ }
+
+ while (1)
+ {
+ struct c_generic_association assoc, *iter;
+ unsigned int ix;
+ c_token *token = c_parser_peek_token (parser);
+
+ assoc.type_location = token->location;
+ if (token->type == CPP_KEYWORD && token->keyword == RID_DEFAULT)
+ {
+ c_parser_consume_token (parser);
+ assoc.type = NULL_TREE;
+ }
+ else
+ {
+ struct c_type_name *type_name;
+
+ type_name = c_parser_type_name (parser);
+ if (type_name == NULL)
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ goto error_exit;
+ }
+ assoc.type = groktypename (type_name, NULL, NULL);
+ if (assoc.type == error_mark_node)
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ goto error_exit;
+ }
+
+ if (TREE_CODE (assoc.type) == FUNCTION_TYPE)
+ error_at (assoc.type_location,
+ "%<_Generic%> association has function type");
+ else if (!COMPLETE_TYPE_P (assoc.type))
+ error_at (assoc.type_location,
+ "%<_Generic%> association has incomplete type");
+
+ if (variably_modified_type_p (assoc.type, NULL_TREE))
+ error_at (assoc.type_location,
+ "%<_Generic%> association has "
+ "variable length type");
+ }
+
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ goto error_exit;
+ }
+
+ assoc.expression = c_parser_expr_no_commas (parser, NULL);
+ if (assoc.expression.value == error_mark_node)
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ goto error_exit;
+ }
+
+ for (ix = 0; associations.iterate (ix, &iter); ++ix)
+ {
+ if (assoc.type == NULL_TREE)
+ {
+ if (iter->type == NULL_TREE)
+ {
+ error_at (assoc.type_location,
+ "duplicate %<default%> case in %<_Generic%>");
+ inform (iter->type_location, "original %<default%> is here");
+ }
+ }
+ else if (iter->type != NULL_TREE)
+ {
+ if (comptypes (assoc.type, iter->type))
+ {
+ error_at (assoc.type_location,
+ "%<_Generic%> specifies two compatible types");
+ inform (iter->type_location, "compatible type is here");
+ }
+ }
+ }
+
+ if (assoc.type == NULL_TREE)
+ {
+ if (!match_found)
+ {
+ matched_assoc = assoc;
+ match_found = true;
+ }
+ }
+ else if (comptypes (assoc.type, selector_type))
+ {
+ if (!match_found || matched_assoc.type == NULL_TREE)
+ {
+ matched_assoc = assoc;
+ match_found = true;
+ }
+ else
+ {
+ error_at (assoc.type_location,
+ "%<_Generic> selector matches multiple associations");
+ inform (matched_assoc.type_location,
+ "other match is here");
+ }
+ }
+
+ associations.safe_push (assoc);
+
+ if (c_parser_peek_token (parser)->type != CPP_COMMA)
+ break;
+ c_parser_consume_token (parser);
+ }
+
+ associations.release ();
+
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return error_expr;
+ }
+
+ if (!match_found)
+ {
+ error_at (selector_loc, "%<_Generic%> selector of type %qT is not "
+ "compatible with any association",
+ selector_type);
+ return error_expr;
+ }
+
+ return matched_assoc.expression;
+
+ error_exit:
+ associations.release ();
+ return error_expr;
+}
/* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2).
constant
string-literal
( expression )
+ generic-selection
GNU extensions:
}
else
{
+ struct c_expr ce;
tree idx;
loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
- idx = c_parser_expression (parser).value;
+ ce = c_parser_expression (parser);
+ ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+ idx = ce.value;
idx = c_fully_fold (idx, false, NULL);
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
c_parser_consume_token (parser);
if (!c_parser_get_builtin_args (parser,
"__builtin_choose_expr",
- &cexpr_list))
+ &cexpr_list, true))
{
expr.value = error_mark_node;
break;
c_parser_consume_token (parser);
if (!c_parser_get_builtin_args (parser,
"__builtin_complex",
- &cexpr_list))
+ &cexpr_list, false))
{
expr.value = error_mark_node;
break;
e1_p = &(*cexpr_list)[0];
e2_p = &(*cexpr_list)[1];
- mark_exp_read (e1_p->value);
+ *e1_p = convert_lvalue_to_rvalue (loc, *e1_p, true, true);
if (TREE_CODE (e1_p->value) == EXCESS_PRECISION_EXPR)
e1_p->value = convert (TREE_TYPE (e1_p->value),
TREE_OPERAND (e1_p->value, 0));
- mark_exp_read (e2_p->value);
+ *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true);
if (TREE_CODE (e2_p->value) == EXCESS_PRECISION_EXPR)
e2_p->value = convert (TREE_TYPE (e2_p->value),
TREE_OPERAND (e2_p->value, 0));
c_parser_consume_token (parser);
if (!c_parser_get_builtin_args (parser,
"__builtin_shuffle",
- &cexpr_list))
+ &cexpr_list, false))
{
expr.value = error_mark_node;
break;
}
FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p)
- mark_exp_read (p->value);
+ *p = convert_lvalue_to_rvalue (loc, *p, true, true);
if (vec_safe_length (cexpr_list) == 2)
expr.value =
expr.value = objc_build_encode_expr (type);
}
break;
+ case RID_GENERIC:
+ expr = c_parser_generic_selection (parser);
+ break;
+ case RID_CILK_SPAWN:
+ c_parser_consume_token (parser);
+ if (!flag_enable_cilkplus)
+ {
+ error_at (loc, "-fcilkplus must be enabled to use "
+ "%<_Cilk_spawn%>");
+ expr = c_parser_postfix_expression (parser);
+ expr.value = error_mark_node;
+ }
+ if (c_parser_peek_token (parser)->keyword == RID_CILK_SPAWN)
+ {
+ error_at (loc, "consecutive %<_Cilk_spawn%> keywords "
+ "are not permitted");
+ /* Now flush out all the _Cilk_spawns. */
+ while (c_parser_peek_token (parser)->keyword == RID_CILK_SPAWN)
+ c_parser_consume_token (parser);
+ expr = c_parser_postfix_expression (parser);
+ }
+ else
+ {
+ expr = c_parser_postfix_expression (parser);
+ expr.value = build_cilk_spawn (loc, expr.value);
+ }
+ break;
default:
c_parser_error (parser, "expected expression");
expr.value = error_mark_node;
tree sizeof_arg[3];
unsigned int i;
vec<tree, va_gc> *exprlist;
- vec<tree, va_gc> *origtypes;
+ vec<tree, va_gc> *origtypes = NULL;
while (true)
{
location_t op_loc = c_parser_peek_token (parser)->location;
case CPP_OPEN_SQUARE:
/* Array reference. */
c_parser_consume_token (parser);
- idx = c_parser_expression (parser).value;
- c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
- "expected %<]%>");
- expr.value = build_array_ref (op_loc, expr.value, idx);
+ if (flag_enable_cilkplus
+ && c_parser_peek_token (parser)->type == CPP_COLON)
+ /* If we are here, then we have something like this:
+ Array [ : ]
+ */
+ expr.value = c_parser_array_notation (expr_loc, parser, NULL_TREE,
+ expr.value);
+ else
+ {
+ idx = c_parser_expression (parser).value;
+ /* Here we have 3 options:
+ 1. Array [EXPR] -- Normal Array call.
+ 2. Array [EXPR : EXPR] -- Array notation without stride.
+ 3. Array [EXPR : EXPR : EXPR] -- Array notation with stride.
+
+ For 1, we just handle it just like a normal array expression.
+ For 2 and 3 we handle it like we handle array notations. The
+ idx value we have above becomes the initial/start index.
+ */
+ if (flag_enable_cilkplus
+ && c_parser_peek_token (parser)->type == CPP_COLON)
+ expr.value = c_parser_array_notation (expr_loc, parser, idx,
+ expr.value);
+ else
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ expr.value = build_array_ref (op_loc, expr.value, idx);
+ }
+ }
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
break;
case CPP_DEREF:
/* Structure element reference. */
c_parser_consume_token (parser);
- expr = default_function_array_conversion (expr_loc, expr);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, true, false);
if (c_parser_next_token_is (parser, CPP_NAME))
ident = c_parser_peek_token (parser)->value;
else
case CPP_PLUS_PLUS:
/* Postincrement. */
c_parser_consume_token (parser);
- expr = default_function_array_read_conversion (expr_loc, expr);
- expr.value = build_unary_op (op_loc,
- POSTINCREMENT_EXPR, expr.value, 0);
+ /* If the expressions have array notations, we expand them. */
+ if (flag_enable_cilkplus
+ && TREE_CODE (expr.value) == ARRAY_NOTATION_REF)
+ expr = fix_array_notation_expr (expr_loc, POSTINCREMENT_EXPR, expr);
+ else
+ {
+ expr = default_function_array_read_conversion (expr_loc, expr);
+ expr.value = build_unary_op (op_loc,
+ POSTINCREMENT_EXPR, expr.value, 0);
+ }
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
break;
case CPP_MINUS_MINUS:
/* Postdecrement. */
c_parser_consume_token (parser);
- expr = default_function_array_read_conversion (expr_loc, expr);
- expr.value = build_unary_op (op_loc,
- POSTDECREMENT_EXPR, expr.value, 0);
+ /* If the expressions have array notations, we expand them. */
+ if (flag_enable_cilkplus
+ && TREE_CODE (expr.value) == ARRAY_NOTATION_REF)
+ expr = fix_array_notation_expr (expr_loc, POSTDECREMENT_EXPR, expr);
+ else
+ {
+ expr = default_function_array_read_conversion (expr_loc, expr);
+ expr.value = build_unary_op (op_loc,
+ POSTDECREMENT_EXPR, expr.value, 0);
+ }
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
break;
static struct c_expr
c_parser_expression (c_parser *parser)
{
+ location_t tloc = c_parser_peek_token (parser)->location;
struct c_expr expr;
expr = c_parser_expr_no_commas (parser, NULL);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ expr = convert_lvalue_to_rvalue (tloc, expr, true, false);
while (c_parser_next_token_is (parser, CPP_COMMA))
{
struct c_expr next;
if (DECL_P (lhsval) || handled_component_p (lhsval))
mark_exp_read (lhsval);
next = c_parser_expr_no_commas (parser, NULL);
- next = default_function_array_conversion (expr_loc, next);
+ next = convert_lvalue_to_rvalue (expr_loc, next, true, false);
expr.value = build_compound_expr (loc, expr.value, next.value);
expr.original_code = COMPOUND_EXPR;
expr.original_type = next.original_type;
return expr;
}
-/* Parse an expression and convert functions or arrays to
- pointers. */
+/* Parse an expression and convert functions or arrays to pointers and
+ lvalues to rvalues. */
static struct c_expr
c_parser_expression_conv (c_parser *parser)
struct c_expr expr;
location_t loc = c_parser_peek_token (parser)->location;
expr = c_parser_expression (parser);
- expr = default_function_array_conversion (loc, expr);
+ expr = convert_lvalue_to_rvalue (loc, expr, true, false);
return expr;
}
/* Parse a non-empty list of expressions. If CONVERT_P, convert
- functions and arrays to pointers. If FOLD_P, fold the expressions.
+ functions and arrays to pointers and lvalues to rvalues. If
+ FOLD_P, fold the expressions.
nonempty-expr-list:
assignment-expression
cur_sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location;
expr = c_parser_expr_no_commas (parser, NULL);
if (convert_p)
- expr = default_function_array_read_conversion (loc, expr);
+ expr = convert_lvalue_to_rvalue (loc, expr, true, true);
if (fold_p)
expr.value = c_fully_fold (expr.value, false, NULL);
ret->quick_push (expr.value);
cur_sizeof_arg_loc = UNKNOWN_LOCATION;
expr = c_parser_expr_no_commas (parser, NULL);
if (convert_p)
- expr = default_function_array_read_conversion (loc, expr);
+ expr = convert_lvalue_to_rvalue (loc, expr, true, true);
if (fold_p)
expr.value = c_fully_fold (expr.value, false, NULL);
vec_safe_push (ret, expr.value);
}
else
c_parser_declaration_or_fndef (parser, false, false, true,
- false, true, NULL);
+ false, true, NULL, vNULL);
break;
}
}
objc_maybe_warn_exceptions (loc);
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
- expr = c_parser_expression (parser).value;
+ struct c_expr ce = c_parser_expression (parser);
+ ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+ expr = ce.value;
expr = c_fully_fold (expr, false, NULL);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
}
break continue return goto asm sizeof typeof __alignof
unsigned long const short volatile signed restrict _Complex
in out inout bycopy byref oneway int char float double void _Bool
+ _Atomic
??? Why this selection of keywords but not, for example, storage
class specifiers? */
case RID_DOUBLE:
case RID_VOID:
case RID_BOOL:
+ case RID_ATOMIC:
+ case RID_AUTO_TYPE:
c_parser_consume_token (parser);
return value;
default:
static tree
c_parser_objc_receiver (c_parser *parser)
{
+ location_t loc = c_parser_peek_token (parser)->location;
+
if (c_parser_peek_token (parser)->type == CPP_NAME
&& (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME
|| c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
c_parser_consume_token (parser);
return objc_get_class_reference (id);
}
- return c_fully_fold (c_parser_expression (parser).value, false, NULL);
+ struct c_expr ce = c_parser_expression (parser);
+ ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+ return c_fully_fold (ce.value, false, NULL);
}
/* Parse objc-message-args.
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 "
c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
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);
+ case PRAGMA_OMP_DECLARE_REDUCTION:
+ c_parser_omp_declare (parser, context);
return false;
-
+ case PRAGMA_IVDEP:
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+ if (!c_parser_next_token_is_keyword (parser, RID_FOR)
+ && !c_parser_next_token_is_keyword (parser, RID_WHILE)
+ && !c_parser_next_token_is_keyword (parser, RID_DO))
+ {
+ c_parser_error (parser, "for, while or do statement expected");
+ return false;
+ }
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ c_parser_for_statement (parser, true);
+ else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
+ c_parser_while_statement (parser, true);
+ else
+ c_parser_do_statement (parser, true);
+ 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);
+ return false;
+
+ case PRAGMA_CILK_SIMD:
+ if (!c_parser_cilk_verify_simd (parser, context))
+ return false;
+ c_parser_consume_pragma (parser);
+ c_parser_cilk_simd (parser);
+ return false;
+
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");
c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name));
}
\f
-/* 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
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;
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;
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;
}
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)
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;
}
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
+ || !tree_fits_shwi_p (num)
+ || (n = tree_to_shwi (num)) <= 0
|| (int) n != n)
{
error_at (loc,
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)
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)
{
code = MAX_EXPR;
break;
}
+ reduc_id = c_parser_peek_token (parser)->value;
+ break;
}
- /* FALLTHRU */
default:
c_parser_error (parser,
"expected %<+%>, %<*%>, %<-%>, %<&%>, "
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;
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;
}
return c;
}
-/* 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. */
+/* OpenMP 4.0:
+ inbranch
+ notinbranch */
static tree
-c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
- const char *where)
+c_parser_omp_clause_branch (c_parser *parser ATTRIBUTE_UNUSED,
+ enum omp_clause_code code, tree list)
{
- tree clauses = NULL;
- bool first = true;
+ check_no_duplicate_clause (list, code, omp_clause_code_name[code]);
- while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
- {
- location_t here;
- pragma_omp_clause c_kind;
- const char *c_name;
- tree prev = clauses;
+ tree c = build_omp_clause (c_parser_peek_token (parser)->location, code);
+ OMP_CLAUSE_CHAIN (c) = list;
- if (!first && c_parser_next_token_is (parser, CPP_COMMA))
- c_parser_consume_token (parser);
+ return c;
+}
- first = false;
- here = c_parser_peek_token (parser)->location;
- c_kind = c_parser_omp_clause_name (parser);
+/* OpenMP 4.0:
+ parallel
+ for
+ sections
+ taskgroup */
- switch (c_kind)
+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)))
{
- case PRAGMA_OMP_CLAUSE_COLLAPSE:
- clauses = c_parser_omp_clause_collapse (parser, clauses);
- c_name = "collapse";
- break;
- case PRAGMA_OMP_CLAUSE_COPYIN:
- clauses = c_parser_omp_clause_copyin (parser, clauses);
- c_name = "copyin";
- break;
- case PRAGMA_OMP_CLAUSE_COPYPRIVATE:
- clauses = c_parser_omp_clause_copyprivate (parser, clauses);
- c_name = "copyprivate";
- break;
- case PRAGMA_OMP_CLAUSE_DEFAULT:
- clauses = c_parser_omp_clause_default (parser, clauses);
- c_name = "default";
- break;
- case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
- clauses = c_parser_omp_clause_firstprivate (parser, clauses);
- c_name = "firstprivate";
- break;
- case PRAGMA_OMP_CLAUSE_FINAL:
- clauses = c_parser_omp_clause_final (parser, clauses);
- c_name = "final";
- break;
- case PRAGMA_OMP_CLAUSE_IF:
- clauses = c_parser_omp_clause_if (parser, clauses);
- c_name = "if";
- break;
- case PRAGMA_OMP_CLAUSE_LASTPRIVATE:
- clauses = c_parser_omp_clause_lastprivate (parser, clauses);
- c_name = "lastprivate";
- break;
- case PRAGMA_OMP_CLAUSE_MERGEABLE:
- clauses = c_parser_omp_clause_mergeable (parser, clauses);
- c_name = "mergeable";
- break;
- case PRAGMA_OMP_CLAUSE_NOWAIT:
- clauses = c_parser_omp_clause_nowait (parser, clauses);
- c_name = "nowait";
- break;
- case PRAGMA_OMP_CLAUSE_NUM_THREADS:
- clauses = c_parser_omp_clause_num_threads (parser, clauses);
- c_name = "num_threads";
- break;
- case PRAGMA_OMP_CLAUSE_ORDERED:
- clauses = c_parser_omp_clause_ordered (parser, clauses);
- c_name = "ordered";
- break;
- case PRAGMA_OMP_CLAUSE_PRIVATE:
- clauses = c_parser_omp_clause_private (parser, clauses);
- c_name = "private";
- break;
- case PRAGMA_OMP_CLAUSE_REDUCTION:
- clauses = c_parser_omp_clause_reduction (parser, clauses);
- c_name = "reduction";
- break;
- case PRAGMA_OMP_CLAUSE_SCHEDULE:
- clauses = c_parser_omp_clause_schedule (parser, clauses);
- c_name = "schedule";
- break;
- case PRAGMA_OMP_CLAUSE_SHARED:
- clauses = c_parser_omp_clause_shared (parser, clauses);
- c_name = "shared";
- break;
- case PRAGMA_OMP_CLAUSE_UNTIED:
- clauses = c_parser_omp_clause_untied (parser, clauses);
- c_name = "untied";
- break;
- default:
- c_parser_error (parser, "expected %<#pragma omp%> clause");
- goto saw_error;
+ c_parser_error (parser, "expected integer expression");
+ return list;
}
- if (((mask >> c_kind) & 1) == 0 && !parser->error)
+ /* 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)
{
- /* Remove the invalid clause(s) from the list to avoid
- confusing the rest of the compiler. */
- clauses = prev;
- error_at (here, "%qs is not valid for %qs", c_name, where);
+ warning_at (expr_loc, 0, "%<num_teams%> value must be positive");
+ t = integer_one_node;
}
- }
- saw_error:
- c_parser_skip_to_pragma_eol (parser);
+ check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TEAMS, "num_teams");
- return c_finish_omp_clauses (clauses);
-}
+ 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;
+ }
-/* OpenMP 2.5:
- structured-block:
- statement
+ return list;
+}
- In practice, we're also interested in adding the statement to an
- outer node. So it is convenient if we work around the fact that
- c_parser_statement calls add_stmt. */
+/* OpenMP 4.0:
+ thread_limit ( expression ) */
static tree
-c_parser_omp_structured_block (c_parser *parser)
+c_parser_omp_clause_thread_limit (c_parser *parser, tree list)
{
- tree stmt = push_stmt_list ();
- c_parser_statement (parser);
- return pop_stmt_list (stmt);
-}
-
-/* OpenMP 2.5:
- # pragma omp atomic new-line
- expression-stmt
+ 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);
- expression-stmt:
- x binop= expr | x++ | ++x | x-- | --x
- binop:
- +, *, -, /, &, ^, |, <<, >>
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
- where x is an lvalue expression with scalar type.
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ c_parser_error (parser, "expected integer expression");
+ return list;
+ }
- OpenMP 3.1:
- # pragma omp atomic new-line
- update-stmt
+ /* 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;
+ }
- # pragma omp atomic read new-line
- read-stmt
+ check_no_duplicate_clause (list, OMP_CLAUSE_THREAD_LIMIT,
+ "thread_limit");
- # pragma omp atomic write new-line
- write-stmt
+ 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;
+ }
- # pragma omp atomic update new-line
- update-stmt
+ return list;
+}
- # pragma omp atomic capture new-line
- capture-stmt
+/* OpenMP 4.0:
+ aligned ( variable-list )
+ aligned ( variable-list : constant-expression ) */
- # pragma omp atomic capture new-line
- capture-block
+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;
- read-stmt:
- v = x
- write-stmt:
- x = expr
- update-stmt:
- expression-stmt | x = x binop expr
- capture-stmt:
- v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x
- capture-block:
- { v = x; update-stmt; } | { update-stmt; v = x; }
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
- where x and v are lvalue expressions with scalar type.
+ nl = c_parser_omp_variable_list (parser, clause_loc,
+ OMP_CLAUSE_ALIGNED, list);
- LOC is the location of the #pragma token. */
+ 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;
+ }
-static void
-c_parser_omp_atomic (location_t loc, c_parser *parser)
+ 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)
{
- tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE;
- tree lhs1 = NULL_TREE, rhs1 = NULL_TREE;
- tree stmt, orig_lhs;
- enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR;
- struct c_expr rhs_expr;
- bool structured_block = false;
+ 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 (p, "read"))
- code = OMP_ATOMIC_READ;
- else if (!strcmp (p, "write"))
- code = NOP_EXPR;
- else if (!strcmp (p, "update"))
- code = OMP_ATOMIC;
- else if (!strcmp (p, "capture"))
- code = OMP_ATOMIC_CAPTURE_NEW;
+ 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
- p = NULL;
- if (p)
- c_parser_consume_token (parser);
+ goto invalid_kind;
}
- c_parser_skip_to_pragma_eol (parser);
+ else
+ goto invalid_kind;
- switch (code)
+ 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)
{
- case OMP_ATOMIC_READ:
- case NOP_EXPR: /* atomic write */
- v = c_parser_unary_expression (parser).value;
- v = c_fully_fold (v, false, NULL);
- if (v == error_mark_node)
- goto saw_error;
- loc = c_parser_peek_token (parser)->location;
- if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
- goto saw_error;
- if (code == NOP_EXPR)
- lhs = c_parser_expression (parser).value;
+ 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
- lhs = c_parser_unary_expression (parser).value;
- lhs = c_fully_fold (lhs, false, NULL);
- if (lhs == error_mark_node)
- goto saw_error;
- if (code == NOP_EXPR)
{
- /* atomic write is represented by OMP_ATOMIC with NOP_EXPR
- opcode. */
- code = OMP_ATOMIC;
- rhs = lhs;
- lhs = v;
- v = NULL_TREE;
+ c_parser_error (parser, "invalid map kind");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return list;
}
- goto done;
- case OMP_ATOMIC_CAPTURE_NEW:
- if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ 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_consume_token (parser);
- structured_block = true;
+ 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
- {
- v = c_parser_unary_expression (parser).value;
- v = c_fully_fold (v, false, NULL);
- if (v == error_mark_node)
- goto saw_error;
- if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
- goto saw_error;
- }
- break;
- default:
- break;
+ 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, omp_clause_mask mask,
+ const char *where, bool finish_p = true)
+{
+ tree clauses = NULL;
+ bool first = true;
+
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ location_t here;
+ pragma_omp_clause c_kind;
+ const char *c_name;
+ tree prev = clauses;
+
+ if (!first && c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+
+ here = c_parser_peek_token (parser)->location;
+ c_kind = c_parser_omp_clause_name (parser);
+
+ switch (c_kind)
+ {
+ case PRAGMA_OMP_CLAUSE_COLLAPSE:
+ clauses = c_parser_omp_clause_collapse (parser, clauses);
+ c_name = "collapse";
+ break;
+ case PRAGMA_OMP_CLAUSE_COPYIN:
+ clauses = c_parser_omp_clause_copyin (parser, clauses);
+ c_name = "copyin";
+ break;
+ case PRAGMA_OMP_CLAUSE_COPYPRIVATE:
+ clauses = c_parser_omp_clause_copyprivate (parser, clauses);
+ c_name = "copyprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEFAULT:
+ clauses = c_parser_omp_clause_default (parser, clauses);
+ c_name = "default";
+ break;
+ case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
+ clauses = c_parser_omp_clause_firstprivate (parser, clauses);
+ c_name = "firstprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_FINAL:
+ clauses = c_parser_omp_clause_final (parser, clauses);
+ c_name = "final";
+ break;
+ case PRAGMA_OMP_CLAUSE_IF:
+ clauses = c_parser_omp_clause_if (parser, clauses);
+ c_name = "if";
+ break;
+ case PRAGMA_OMP_CLAUSE_LASTPRIVATE:
+ clauses = c_parser_omp_clause_lastprivate (parser, clauses);
+ c_name = "lastprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_MERGEABLE:
+ clauses = c_parser_omp_clause_mergeable (parser, clauses);
+ c_name = "mergeable";
+ break;
+ case PRAGMA_OMP_CLAUSE_NOWAIT:
+ clauses = c_parser_omp_clause_nowait (parser, clauses);
+ c_name = "nowait";
+ break;
+ case PRAGMA_OMP_CLAUSE_NUM_THREADS:
+ clauses = c_parser_omp_clause_num_threads (parser, clauses);
+ c_name = "num_threads";
+ break;
+ case PRAGMA_OMP_CLAUSE_ORDERED:
+ clauses = c_parser_omp_clause_ordered (parser, clauses);
+ c_name = "ordered";
+ break;
+ case PRAGMA_OMP_CLAUSE_PRIVATE:
+ clauses = c_parser_omp_clause_private (parser, clauses);
+ c_name = "private";
+ break;
+ case PRAGMA_OMP_CLAUSE_REDUCTION:
+ clauses = c_parser_omp_clause_reduction (parser, clauses);
+ c_name = "reduction";
+ break;
+ case PRAGMA_OMP_CLAUSE_SCHEDULE:
+ clauses = c_parser_omp_clause_schedule (parser, clauses);
+ c_name = "schedule";
+ break;
+ case PRAGMA_OMP_CLAUSE_SHARED:
+ clauses = c_parser_omp_clause_shared (parser, clauses);
+ c_name = "shared";
+ break;
+ case PRAGMA_OMP_CLAUSE_UNTIED:
+ 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
+ confusing the rest of the compiler. */
+ clauses = prev;
+ error_at (here, "%qs is not valid for %qs", c_name, where);
+ }
+ }
+
+ saw_error:
+ c_parser_skip_to_pragma_eol (parser);
+
+ if (finish_p)
+ return c_finish_omp_clauses (clauses);
+
+ return clauses;
+}
+
+/* OpenMP 2.5:
+ structured-block:
+ statement
+
+ In practice, we're also interested in adding the statement to an
+ outer node. So it is convenient if we work around the fact that
+ c_parser_statement calls add_stmt. */
+
+static tree
+c_parser_omp_structured_block (c_parser *parser)
+{
+ tree stmt = push_stmt_list ();
+ c_parser_statement (parser);
+ return pop_stmt_list (stmt);
+}
+
+/* OpenMP 2.5:
+ # pragma omp atomic new-line
+ expression-stmt
+
+ expression-stmt:
+ x binop= expr | x++ | ++x | x-- | --x
+ binop:
+ +, *, -, /, &, ^, |, <<, >>
+
+ where x is an lvalue expression with scalar type.
+
+ OpenMP 3.1:
+ # pragma omp atomic new-line
+ update-stmt
+
+ # pragma omp atomic read new-line
+ read-stmt
+
+ # pragma omp atomic write new-line
+ write-stmt
+
+ # pragma omp atomic update new-line
+ update-stmt
+
+ # pragma omp atomic capture new-line
+ capture-stmt
+
+ # pragma omp atomic capture new-line
+ capture-block
+
+ read-stmt:
+ v = x
+ write-stmt:
+ x = expr
+ update-stmt:
+ expression-stmt | x = x binop expr
+ capture-stmt:
+ 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. */
+
+static void
+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, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE;
+ enum tree_code code = OMP_ATOMIC, opcode = NOP_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))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (!strcmp (p, "read"))
+ code = OMP_ATOMIC_READ;
+ else if (!strcmp (p, "write"))
+ code = NOP_EXPR;
+ else if (!strcmp (p, "update"))
+ code = OMP_ATOMIC;
+ else if (!strcmp (p, "capture"))
+ code = OMP_ATOMIC_CAPTURE_NEW;
+ else
+ p = NULL;
+ 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)
+ {
+ case OMP_ATOMIC_READ:
+ case NOP_EXPR: /* atomic write */
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ loc = c_parser_peek_token (parser)->location;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ if (code == NOP_EXPR)
+ lhs = c_parser_expression (parser).value;
+ else
+ lhs = c_parser_unary_expression (parser).value;
+ lhs = c_fully_fold (lhs, false, NULL);
+ if (lhs == error_mark_node)
+ goto saw_error;
+ if (code == NOP_EXPR)
+ {
+ /* atomic write is represented by OMP_ATOMIC with NOP_EXPR
+ opcode. */
+ code = OMP_ATOMIC;
+ rhs = lhs;
+ lhs = v;
+ v = NULL_TREE;
+ }
+ goto done;
+ case OMP_ATOMIC_CAPTURE_NEW:
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ c_parser_consume_token (parser);
+ structured_block = true;
+ }
+ else
+ {
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* For structured_block case we don't know yet whether
+ old or new x should be captured. */
+restart:
+ 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))
+ {
+ case ERROR_MARK:
+ saw_error:
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ if (structured_block)
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ c_parser_consume_token (parser);
+ else if (code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ c_parser_consume_token (parser);
+ }
+ }
+ return;
+
+ case POSTINCREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREINCREMENT_EXPR:
+ lhs = TREE_OPERAND (lhs, 0);
+ unfolded_lhs = NULL_TREE;
+ opcode = PLUS_EXPR;
+ rhs = integer_one_node;
+ break;
+
+ case POSTDECREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREDECREMENT_EXPR:
+ lhs = TREE_OPERAND (lhs, 0);
+ unfolded_lhs = NULL_TREE;
+ opcode = MINUS_EXPR;
+ rhs = integer_one_node;
+ break;
+
+ case COMPOUND_EXPR:
+ if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR
+ && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR
+ && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR
+ && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0)
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND
+ (TREE_OPERAND (lhs, 1), 0), 0)))
+ == BOOLEAN_TYPE)
+ /* Undo effects of boolean_increment for post {in,de}crement. */
+ lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0);
+ /* FALLTHRU */
+ case MODIFY_EXPR:
+ if (TREE_CODE (lhs) == MODIFY_EXPR
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE)
+ {
+ /* Undo effects of boolean_increment. */
+ if (integer_onep (TREE_OPERAND (lhs, 1)))
+ {
+ /* 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
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ break;
+ }
+ if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR
+ && TREE_OPERAND (lhs, 0)
+ == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0))
+ {
+ /* 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
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ break;
+ }
+ }
+ /* FALLTHRU */
+ default:
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_MULT_EQ:
+ opcode = MULT_EXPR;
+ break;
+ case CPP_DIV_EQ:
+ opcode = TRUNC_DIV_EXPR;
+ break;
+ case CPP_PLUS_EQ:
+ opcode = PLUS_EXPR;
+ break;
+ case CPP_MINUS_EQ:
+ opcode = MINUS_EXPR;
+ break;
+ case CPP_LSHIFT_EQ:
+ opcode = LSHIFT_EXPR;
+ break;
+ case CPP_RSHIFT_EQ:
+ opcode = RSHIFT_EXPR;
+ break;
+ case CPP_AND_EQ:
+ opcode = BIT_AND_EXPR;
+ break;
+ case CPP_OR_EQ:
+ opcode = BIT_IOR_EXPR;
+ break;
+ case CPP_XOR_EQ:
+ opcode = BIT_XOR_EXPR;
+ break;
+ case CPP_EQ:
+ 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))
+ {
+ 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))
+ {
+ 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;
+ }
+ 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%>");
+ goto saw_error;
+ }
+
+ /* Arrange to pass the location of the assignment operator to
+ c_finish_omp_atomic. */
+ loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ 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;
+ }
+stmt_done:
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ goto saw_error;
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ 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;
+ }
+ if (structured_block)
+ {
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+ }
+done:
+ 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);
+
+ if (!structured_block)
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+}
+
+
+/* OpenMP 2.5:
+ # pragma omp barrier new-line
+*/
+
+static void
+c_parser_omp_barrier (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+
+ c_finish_omp_barrier (loc);
+}
+
+/* OpenMP 2.5:
+ # pragma omp critical [(name)] new-line
+ structured-block
+
+ LOC is the location of the #pragma itself. */
+
+static tree
+c_parser_omp_critical (location_t loc, c_parser *parser)
+{
+ tree stmt, name = NULL;
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ name = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ else
+ c_parser_error (parser, "expected identifier");
+ }
+ else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ c_parser_error (parser, "expected %<(%> or end of line");
+ c_parser_skip_to_pragma_eol (parser);
+
+ stmt = c_parser_omp_structured_block (parser);
+ return c_finish_omp_critical (loc, stmt, name);
+}
+
+/* OpenMP 2.5:
+ # pragma omp flush flush-vars[opt] new-line
+
+ flush-vars:
+ ( variable-list ) */
+
+static void
+c_parser_omp_flush (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_OPEN_PAREN))
+ c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
+ else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ c_parser_error (parser, "expected %<(%> or end of line");
+ c_parser_skip_to_pragma_eol (parser);
+
+ c_finish_omp_flush (loc);
+}
+
+/* Parse the restricted form of the for statement allowed by OpenMP.
+ The real trick here is to determine the loop control variable early
+ so that we can push a new decl if necessary to make it private.
+ LOC is the location of the OMP in "#pragma omp". */
+
+static tree
+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;
+ bool fail = false, open_brace_parsed = false;
+ int i, collapse = 1, nbraces = 0;
+ location_t for_loc;
+ vec<tree, va_gc> *for_block = make_tree_vector ();
+
+ for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
+ if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
+ collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl));
+
+ gcc_assert (collapse >= 1);
+
+ declv = make_tree_vec (collapse);
+ initv = make_tree_vec (collapse);
+ condv = make_tree_vec (collapse);
+ incrv = make_tree_vec (collapse);
+
+ if (!c_parser_next_token_is_keyword (parser, RID_FOR))
+ {
+ c_parser_error (parser, "for statement expected");
+ return NULL;
+ }
+ for_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+
+ for (i = 0; i < collapse; i++)
+ {
+ int bracecount = 0;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ goto pop_scopes;
+
+ /* Parse the initialization declaration or expression. */
+ if (c_parser_next_tokens_start_declaration (parser))
+ {
+ 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, vNULL);
+ decl = check_for_loop_decls (for_loc, flag_isoc99);
+ if (decl == NULL)
+ goto error_init;
+ if (DECL_INITIAL (decl) == error_mark_node)
+ decl = error_mark_node;
+ init = decl;
+ }
+ else if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
+ {
+ struct c_expr decl_exp;
+ struct c_expr init_exp;
+ location_t init_loc;
+
+ decl_exp = c_parser_postfix_expression (parser);
+ decl = decl_exp.value;
+
+ c_parser_require (parser, CPP_EQ, "expected %<=%>");
+
+ init_loc = c_parser_peek_token (parser)->location;
+ init_exp = c_parser_expr_no_commas (parser, NULL);
+ init_exp = default_function_array_read_conversion (init_loc,
+ init_exp);
+ init = build_modify_expr (init_loc, decl, decl_exp.original_type,
+ NOP_EXPR, init_loc, init_exp.value,
+ init_exp.original_type);
+ init = c_process_expr_stmt (init_loc, init);
+
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ else
+ {
+ error_init:
+ c_parser_error (parser,
+ "expected iteration declaration or initialization");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ fail = true;
+ goto parse_next;
+ }
+
+ /* Parse the loop condition. */
+ cond = NULL_TREE;
+ 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, NULL_TREE);
+
+ cond = cond_expr.value;
+ cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
+ cond = c_fully_fold (cond, false, NULL);
+ switch (cond_expr.original_code)
+ {
+ case GT_EXPR:
+ case GE_EXPR:
+ case LT_EXPR:
+ case LE_EXPR:
+ break;
+ case NE_EXPR:
+ if (code == CILK_SIMD)
+ break;
+ /* FALLTHRU. */
+ default:
+ /* Can't be cond = error_mark_node, because we want to preserve
+ the location until c_finish_omp_for. */
+ cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node);
+ break;
+ }
+ protected_set_expr_location (cond, cond_loc);
+ }
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+
+ /* Parse the increment expression. */
+ incr = NULL_TREE;
+ if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+ {
+ location_t incr_loc = c_parser_peek_token (parser)->location;
+
+ incr = c_process_expr_stmt (incr_loc,
+ c_parser_expression (parser).value);
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (decl == NULL || decl == error_mark_node || init == error_mark_node)
+ fail = true;
+ else
+ {
+ TREE_VEC_ELT (declv, i) = decl;
+ TREE_VEC_ELT (initv, i) = init;
+ TREE_VEC_ELT (condv, i) = cond;
+ TREE_VEC_ELT (incrv, i) = incr;
+ }
+
+ parse_next:
+ if (i == collapse - 1)
+ break;
+
+ /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed
+ in between the collapsed for loops to be still considered perfectly
+ nested. Hopefully the final version clarifies this.
+ For now handle (multiple) {'s and empty statements. */
+ do
+ {
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ {
+ c_parser_consume_token (parser);
+ break;
+ }
+ else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ c_parser_consume_token (parser);
+ bracecount++;
+ }
+ else if (bracecount
+ && c_parser_next_token_is (parser, CPP_SEMICOLON))
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_error (parser, "not enough perfectly nested loops");
+ if (bracecount)
+ {
+ open_brace_parsed = true;
+ bracecount--;
+ }
+ fail = true;
+ collapse = 0;
+ break;
+ }
+ }
+ while (1);
+
+ nbraces += bracecount;
+ }
+
+ save_break = c_break_label;
+ if (code == CILK_SIMD)
+ c_break_label = build_int_cst (size_type_node, 2);
+ else
+ c_break_label = size_one_node;
+ save_cont = c_cont_label;
+ c_cont_label = NULL_TREE;
+ body = push_stmt_list ();
+
+ if (open_brace_parsed)
+ {
+ location_t here = c_parser_peek_token (parser)->location;
+ stmt = c_begin_compound_stmt (true);
+ c_parser_compound_statement_nostart (parser);
+ add_stmt (c_end_compound_stmt (here, stmt, true));
+ }
+ else
+ add_stmt (c_parser_c99_block_statement (parser));
+ if (c_cont_label)
+ {
+ tree t = build1 (LABEL_EXPR, void_type_node, c_cont_label);
+ SET_EXPR_LOCATION (t, loc);
+ add_stmt (t);
+ }
+
+ body = pop_stmt_list (body);
+ c_break_label = save_break;
+ c_cont_label = save_cont;
+
+ while (nbraces)
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ c_parser_consume_token (parser);
+ nbraces--;
+ }
+ else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_error (parser, "collapsed loops not perfectly nested");
+ while (nbraces)
+ {
+ location_t here = c_parser_peek_token (parser)->location;
+ stmt = c_begin_compound_stmt (true);
+ add_stmt (body);
+ c_parser_compound_statement_nostart (parser);
+ body = c_end_compound_stmt (here, stmt, true);
+ nbraces--;
+ }
+ goto pop_scopes;
+ }
+ }
+
+ /* Only bother calling c_finish_omp_for if we haven't already generated
+ an error from the initialization parsing. */
+ if (!fail)
+ {
+ stmt = c_finish_omp_for (loc, code, declv, initv, condv,
+ incrv, body, NULL);
+ if (stmt)
+ {
+ if (cclauses != NULL
+ && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL)
+ {
+ tree *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);
+ else
+ {
+ for (i = 0; i < collapse; i++)
+ if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c))
+ break;
+ if (i == collapse)
+ c = &OMP_CLAUSE_CHAIN (*c);
+ else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE)
+ {
+ error_at (loc,
+ "iteration variable %qD should not be firstprivate",
+ OMP_CLAUSE_DECL (*c));
+ *c = OMP_CLAUSE_CHAIN (*c);
+ }
+ else
+ {
+ /* Copy lastprivate (decl) clause to OMP_FOR_CLAUSES,
+ change it to shared (decl) in
+ OMP_PARALLEL_CLAUSES. */
+ tree l = build_omp_clause (OMP_CLAUSE_LOCATION (*c),
+ OMP_CLAUSE_LASTPRIVATE);
+ OMP_CLAUSE_DECL (l) = OMP_CLAUSE_DECL (*c);
+ OMP_CLAUSE_CHAIN (l) = clauses;
+ clauses = l;
+ OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED);
+ }
+ }
+ }
+ OMP_FOR_CLAUSES (stmt) = clauses;
+ }
+ ret = stmt;
+ }
+pop_scopes:
+ while (!for_block->is_empty ())
+ {
+ /* FIXME diagnostics: LOC below should be the actual location of
+ this particular for block. We need to build a list of
+ locations to go along with FOR_BLOCK. */
+ stmt = c_end_compound_stmt (loc, for_block->pop (), true);
+ add_stmt (stmt);
+ }
+ release_tree_vector (for_block);
+ 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 \
+ ( (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,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+ tree block, clauses, ret;
+
+ 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);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
+ 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;
+ }
+ }
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ return NULL_TREE;
+ }
+
+ 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, OMP_FOR, clauses, cclauses);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
+/* OpenMP 2.5:
+ # pragma omp master new-line
+ structured-block
+
+ LOC is the location of the #pragma token.
+*/
+
+static tree
+c_parser_omp_master (location_t loc, c_parser *parser)
+{
+ c_parser_skip_to_pragma_eol (parser);
+ return c_finish_omp_master (loc, c_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 2.5:
+ # pragma omp ordered new-line
+ structured-block
+
+ LOC is the location of the #pragma itself.
+*/
+
+static tree
+c_parser_omp_ordered (location_t loc, c_parser *parser)
+{
+ c_parser_skip_to_pragma_eol (parser);
+ return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 2.5:
+
+ section-scope:
+ { section-sequence }
+
+ section-sequence:
+ section-directive[opt] structured-block
+ section-sequence section-directive structured-block
- /* 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;
- lhs = c_fully_fold (lhs, false, NULL);
- orig_lhs = lhs;
- switch (TREE_CODE (lhs))
+ SECTIONS_LOC is the location of the #pragma omp sections. */
+
+static tree
+c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser)
+{
+ tree stmt, substmt;
+ bool error_suppress = false;
+ location_t loc;
+
+ loc = c_parser_peek_token (parser)->location;
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
{
- case ERROR_MARK:
- saw_error:
- c_parser_skip_to_end_of_block_or_statement (parser);
- if (structured_block)
- {
- if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
- c_parser_consume_token (parser);
- else if (code == OMP_ATOMIC_CAPTURE_NEW)
- {
- c_parser_skip_to_end_of_block_or_statement (parser);
- if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
- c_parser_consume_token (parser);
- }
- }
- return;
+ /* Avoid skipping until the end of the block. */
+ parser->error = false;
+ return NULL_TREE;
+ }
- case POSTINCREMENT_EXPR:
- if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
- code = OMP_ATOMIC_CAPTURE_OLD;
- /* FALLTHROUGH */
- case PREINCREMENT_EXPR:
- lhs = TREE_OPERAND (lhs, 0);
- opcode = PLUS_EXPR;
- rhs = integer_one_node;
- break;
+ stmt = push_stmt_list ();
- case POSTDECREMENT_EXPR:
- if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
- code = OMP_ATOMIC_CAPTURE_OLD;
- /* FALLTHROUGH */
- case PREDECREMENT_EXPR:
- lhs = TREE_OPERAND (lhs, 0);
- opcode = MINUS_EXPR;
- rhs = integer_one_node;
- break;
+ if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION)
+ {
+ substmt = c_parser_omp_structured_block (parser);
+ substmt = build1 (OMP_SECTION, void_type_node, substmt);
+ SET_EXPR_LOCATION (substmt, loc);
+ add_stmt (substmt);
+ }
- case COMPOUND_EXPR:
- if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR
- && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR
- && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR
- && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0)
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND
- (TREE_OPERAND (lhs, 1), 0), 0)))
- == BOOLEAN_TYPE)
- /* Undo effects of boolean_increment for post {in,de}crement. */
- lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0);
- /* FALLTHRU */
- case MODIFY_EXPR:
- if (TREE_CODE (lhs) == MODIFY_EXPR
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE)
+ while (1)
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ break;
+ if (c_parser_next_token_is (parser, CPP_EOF))
+ break;
+
+ loc = c_parser_peek_token (parser)->location;
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
{
- /* Undo effects of boolean_increment. */
- if (integer_onep (TREE_OPERAND (lhs, 1)))
- {
- /* This is pre or post increment. */
- rhs = TREE_OPERAND (lhs, 1);
- lhs = TREE_OPERAND (lhs, 0);
- opcode = NOP_EXPR;
- if (code == OMP_ATOMIC_CAPTURE_NEW
- && !structured_block
- && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
- code = OMP_ATOMIC_CAPTURE_OLD;
- break;
- }
- if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR
- && TREE_OPERAND (lhs, 0)
- == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0))
- {
- /* This is pre or post decrement. */
- rhs = TREE_OPERAND (lhs, 1);
- lhs = TREE_OPERAND (lhs, 0);
- opcode = NOP_EXPR;
- if (code == OMP_ATOMIC_CAPTURE_NEW
- && !structured_block
- && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
- code = OMP_ATOMIC_CAPTURE_OLD;
- break;
- }
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+ error_suppress = false;
}
- /* FALLTHRU */
- default:
- switch (c_parser_peek_token (parser)->type)
+ else if (!error_suppress)
{
- case CPP_MULT_EQ:
- opcode = MULT_EXPR;
- break;
- case CPP_DIV_EQ:
- opcode = TRUNC_DIV_EXPR;
- break;
- case CPP_PLUS_EQ:
- opcode = PLUS_EXPR;
- break;
- case CPP_MINUS_EQ:
- opcode = MINUS_EXPR;
- break;
- case CPP_LSHIFT_EQ:
- opcode = LSHIFT_EXPR;
- break;
- case CPP_RSHIFT_EQ:
- opcode = RSHIFT_EXPR;
- break;
- case CPP_AND_EQ:
- opcode = BIT_AND_EXPR;
- break;
- case CPP_OR_EQ:
- opcode = BIT_IOR_EXPR;
- break;
- case CPP_XOR_EQ:
- opcode = BIT_XOR_EXPR;
- break;
- case CPP_EQ:
- if (structured_block || code == OMP_ATOMIC)
- {
- 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 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;
- }
- 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 */
- default:
- c_parser_error (parser,
- "invalid operator for %<#pragma omp atomic%>");
- goto saw_error;
+ error_at (loc, "expected %<#pragma omp section%> or %<}%>");
+ error_suppress = true;
}
- /* Arrange to pass the location of the assignment operator to
- 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;
- rhs = c_fully_fold (rhs, false, NULL);
- break;
- }
-stmt_done:
- if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
- {
- if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
- goto saw_error;
- v = c_parser_unary_expression (parser).value;
- v = c_fully_fold (v, false, NULL);
- if (v == error_mark_node)
- goto saw_error;
- if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
- goto saw_error;
- lhs1 = c_parser_unary_expression (parser).value;
- lhs1 = c_fully_fold (lhs1, false, NULL);
- if (lhs1 == error_mark_node)
- goto saw_error;
- }
- if (structured_block)
- {
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
- c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+ substmt = c_parser_omp_structured_block (parser);
+ substmt = build1 (OMP_SECTION, void_type_node, substmt);
+ SET_EXPR_LOCATION (substmt, loc);
+ add_stmt (substmt);
}
-done:
- stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1);
- if (stmt != error_mark_node)
- add_stmt (stmt);
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE,
+ "expected %<#pragma omp section%> or %<}%>");
- if (!structured_block)
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
-}
+ substmt = pop_stmt_list (stmt);
+
+ stmt = make_node (OMP_SECTIONS);
+ SET_EXPR_LOCATION (stmt, sections_loc);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_SECTIONS_BODY (stmt) = substmt;
+ return add_stmt (stmt);
+}
/* OpenMP 2.5:
- # pragma omp barrier new-line
+ # pragma omp sections sections-clause[optseq] newline
+ sections-scope
+
+ LOC is the location of the #pragma token.
*/
-static void
-c_parser_omp_barrier (c_parser *parser)
+#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,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
{
- location_t loc = c_parser_peek_token (parser)->location;
- c_parser_consume_pragma (parser);
- c_parser_skip_to_pragma_eol (parser);
+ tree block, clauses, ret;
- c_finish_omp_barrier (loc);
+ 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);
+ if (ret)
+ OMP_SECTIONS_CLAUSES (ret) = clauses;
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
}
/* OpenMP 2.5:
- # pragma omp critical [(name)] new-line
- structured-block
+ # pragma parallel parallel-clause new-line
+ # pragma parallel for parallel-for-clause new-line
+ # pragma parallel sections parallel-sections-clause new-line
- LOC is the location of the #pragma itself. */
+ LOC is the location of the #pragma token.
+*/
+
+#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_critical (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)
{
- tree stmt, name = NULL;
+ tree stmt, clauses, block;
- if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ 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);
- if (c_parser_next_token_is (parser, CPP_NAME))
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_for (loc, parser, p_name, mask, cclauses);
+ 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 (!flag_openmp) /* flag_openmp_simd */
+ {
+ 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)
{
- name = c_parser_peek_token (parser)->value;
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
c_parser_consume_token (parser);
- c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ 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;
}
- else
- c_parser_error (parser, "expected identifier");
}
- else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
- c_parser_error (parser, "expected %<(%> or end of line");
- c_parser_skip_to_pragma_eol (parser);
- stmt = c_parser_omp_structured_block (parser);
- return c_finish_omp_critical (loc, stmt, name);
-}
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
-/* OpenMP 2.5:
- # pragma omp flush flush-vars[opt] new-line
+ block = c_begin_omp_parallel ();
+ c_parser_statement (parser);
+ stmt = c_finish_omp_parallel (loc, clauses, block);
- flush-vars:
- ( variable-list ) */
+ return stmt;
+}
-static void
-c_parser_omp_flush (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_OPEN_PAREN))
- c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
- else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
- c_parser_error (parser, "expected %<(%> or end of line");
- c_parser_skip_to_pragma_eol (parser);
+/* OpenMP 2.5:
+ # pragma omp single single-clause[optseq] new-line
+ structured-block
- c_finish_omp_flush (loc);
-}
+ LOC is the location of the #pragma.
+*/
-/* Parse the restricted form of the for statement allowed by OpenMP.
- The real trick here is to determine the loop control variable early
- so that we can push a new decl if necessary to make it private.
- LOC is the location of the OMP in "#pragma omp". */
+#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_for_loop (location_t loc,
- c_parser *parser, tree clauses, tree *par_clauses)
+c_parser_omp_single (location_t loc, c_parser *parser)
{
- tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
- tree declv, condv, incrv, initv, ret = NULL;
- bool fail = false, open_brace_parsed = false;
- int i, collapse = 1, nbraces = 0;
- location_t for_loc;
- vec<tree, va_gc> *for_block = make_tree_vector ();
+ tree stmt = make_node (OMP_SINGLE);
+ SET_EXPR_LOCATION (stmt, loc);
+ TREE_TYPE (stmt) = void_type_node;
- for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
- if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
- collapse = tree_low_cst (OMP_CLAUSE_COLLAPSE_EXPR (cl), 0);
+ OMP_SINGLE_CLAUSES (stmt)
+ = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK,
+ "#pragma omp single");
+ OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser);
- gcc_assert (collapse >= 1);
+ return add_stmt (stmt);
+}
- declv = make_tree_vec (collapse);
- initv = make_tree_vec (collapse);
- condv = make_tree_vec (collapse);
- incrv = make_tree_vec (collapse);
+/* OpenMP 3.0:
+ # pragma omp task task-clause[optseq] new-line
- if (!c_parser_next_token_is_keyword (parser, RID_FOR))
- {
- c_parser_error (parser, "for statement expected");
- return NULL;
- }
- for_loc = c_parser_peek_token (parser)->location;
- c_parser_consume_token (parser);
+ LOC is the location of the #pragma.
+*/
- for (i = 0; i < collapse; i++)
- {
- int bracecount = 0;
+#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))
- if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
- goto pop_scopes;
+static tree
+c_parser_omp_task (location_t loc, c_parser *parser)
+{
+ tree clauses, block;
- /* Parse the initialization declaration or expression. */
- if (c_parser_next_tokens_start_declaration (parser))
- {
- 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);
- decl = check_for_loop_decls (for_loc, flag_isoc99);
- if (decl == NULL)
- goto error_init;
- if (DECL_INITIAL (decl) == error_mark_node)
- decl = error_mark_node;
- init = decl;
- }
- else if (c_parser_next_token_is (parser, CPP_NAME)
- && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
- {
- struct c_expr decl_exp;
- struct c_expr init_exp;
- location_t init_loc;
+ clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK,
+ "#pragma omp task");
- decl_exp = c_parser_postfix_expression (parser);
- decl = decl_exp.value;
+ block = c_begin_omp_task ();
+ c_parser_statement (parser);
+ return c_finish_omp_task (loc, clauses, block);
+}
- c_parser_require (parser, CPP_EQ, "expected %<=%>");
+/* OpenMP 3.0:
+ # pragma omp taskwait new-line
+*/
- init_loc = c_parser_peek_token (parser)->location;
- init_exp = c_parser_expr_no_commas (parser, NULL);
- init_exp = default_function_array_read_conversion (init_loc,
- init_exp);
- init = build_modify_expr (init_loc, decl, decl_exp.original_type,
- NOP_EXPR, init_loc, init_exp.value,
- init_exp.original_type);
- init = c_process_expr_stmt (init_loc, init);
+static void
+c_parser_omp_taskwait (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
- }
- else
- {
- error_init:
- c_parser_error (parser,
- "expected iteration declaration or initialization");
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
- "expected %<)%>");
- fail = true;
- goto parse_next;
- }
+ c_finish_omp_taskwait (loc);
+}
- /* Parse the loop condition. */
- cond = NULL_TREE;
- 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);
+/* OpenMP 3.1:
+ # pragma omp taskyield new-line
+*/
- cond = cond_expr.value;
- cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
- cond = c_fully_fold (cond, false, NULL);
- switch (cond_expr.original_code)
- {
- case GT_EXPR:
- case GE_EXPR:
- case LT_EXPR:
- case LE_EXPR:
- break;
- default:
- /* Can't be cond = error_mark_node, because we want to preserve
- the location until c_finish_omp_for. */
- cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node);
- break;
- }
- protected_set_expr_location (cond, cond_loc);
- }
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+static void
+c_parser_omp_taskyield (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
- /* Parse the increment expression. */
- incr = NULL_TREE;
- if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
- {
- location_t incr_loc = c_parser_peek_token (parser)->location;
+ c_finish_omp_taskyield (loc);
+}
- incr = c_process_expr_stmt (incr_loc,
- c_parser_expression (parser).value);
- }
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+/* OpenMP 4.0:
+ # pragma omp taskgroup new-line
+*/
- if (decl == NULL || decl == error_mark_node || init == error_mark_node)
- fail = true;
- else
- {
- TREE_VEC_ELT (declv, i) = decl;
- TREE_VEC_ELT (initv, i) = init;
- TREE_VEC_ELT (condv, i) = cond;
- TREE_VEC_ELT (incrv, i) = incr;
- }
+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));
+}
- parse_next:
- if (i == collapse - 1)
- break;
+/* OpenMP 4.0:
+ # pragma omp cancel cancel-clause[optseq] new-line
- /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed
- in between the collapsed for loops to be still considered perfectly
- nested. Hopefully the final version clarifies this.
- For now handle (multiple) {'s and empty statements. */
- do
- {
- if (c_parser_next_token_is_keyword (parser, RID_FOR))
- {
- c_parser_consume_token (parser);
- break;
- }
- else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
- {
- c_parser_consume_token (parser);
- bracecount++;
- }
- else if (bracecount
- && c_parser_next_token_is (parser, CPP_SEMICOLON))
- c_parser_consume_token (parser);
- else
- {
- c_parser_error (parser, "not enough perfectly nested loops");
- if (bracecount)
- {
- open_brace_parsed = true;
- bracecount--;
- }
- fail = true;
- collapse = 0;
- break;
- }
- }
- while (1);
+ 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))
- nbraces += bracecount;
- }
+static void
+c_parser_omp_cancel (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
- save_break = c_break_label;
- c_break_label = size_one_node;
- save_cont = c_cont_label;
- c_cont_label = NULL_TREE;
- body = push_stmt_list ();
+ c_parser_consume_pragma (parser);
+ tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK,
+ "#pragma omp cancel");
- if (open_brace_parsed)
+ 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))
{
- location_t here = c_parser_peek_token (parser)->location;
- stmt = c_begin_compound_stmt (true);
- c_parser_compound_statement_nostart (parser);
- add_stmt (c_end_compound_stmt (here, stmt, true));
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "point") == 0)
+ {
+ c_parser_consume_token (parser);
+ point_seen = true;
+ }
}
- else
- add_stmt (c_parser_c99_block_statement (parser));
- if (c_cont_label)
+ if (!point_seen)
{
- tree t = build1 (LABEL_EXPR, void_type_node, c_cont_label);
- SET_EXPR_LOCATION (t, loc);
- add_stmt (t);
+ c_parser_error (parser, "expected %<point%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return;
}
- body = pop_stmt_list (body);
- c_break_label = save_break;
- c_cont_label = save_cont;
+ clauses
+ = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK,
+ "#pragma omp cancellation point");
- while (nbraces)
+ 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))
{
- if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
- {
- c_parser_consume_token (parser);
- nbraces--;
- }
- else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
- c_parser_consume_token (parser);
+ 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)
{
- c_parser_error (parser, "collapsed loops not perfectly nested");
- while (nbraces)
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+ c_parser_consume_token (parser);
+ if (!flag_openmp) /* flag_openmp_simd */
{
- location_t here = c_parser_peek_token (parser)->location;
- stmt = c_begin_compound_stmt (true);
- add_stmt (body);
- c_parser_compound_statement_nostart (parser);
- body = c_end_compound_stmt (here, stmt, true);
- nbraces--;
+ if (simd)
+ return c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
+ else
+ return c_parser_omp_parallel (loc, parser, p_name, mask,
+ cclauses);
}
- goto pop_scopes;
+ 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;
}
}
-
- /* Only bother calling c_finish_omp_for if we haven't already generated
- an error from the initialization parsing. */
- if (!fail)
+ if (!flag_openmp) /* flag_openmp_simd */
{
- stmt = c_finish_omp_for (loc, declv, initv, condv, incrv, body, NULL);
- if (stmt)
- {
- if (par_clauses != NULL)
- {
- tree *c;
- for (c = par_clauses; *c ; )
- if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE
- && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE)
- c = &OMP_CLAUSE_CHAIN (*c);
- else
- {
- for (i = 0; i < collapse; i++)
- if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c))
- break;
- if (i == collapse)
- c = &OMP_CLAUSE_CHAIN (*c);
- else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE)
- {
- error_at (loc,
- "iteration variable %qD should not be firstprivate",
- OMP_CLAUSE_DECL (*c));
- *c = OMP_CLAUSE_CHAIN (*c);
- }
- else
- {
- /* Copy lastprivate (decl) clause to OMP_FOR_CLAUSES,
- change it to shared (decl) in
- OMP_PARALLEL_CLAUSES. */
- tree l = build_omp_clause (OMP_CLAUSE_LOCATION (*c),
- OMP_CLAUSE_LASTPRIVATE);
- OMP_CLAUSE_DECL (l) = OMP_CLAUSE_DECL (*c);
- OMP_CLAUSE_CHAIN (l) = clauses;
- clauses = l;
- OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED);
- }
- }
- }
- OMP_FOR_CLAUSES (stmt) = clauses;
- }
- ret = stmt;
+ c_parser_skip_to_pragma_eol (parser);
+ return NULL_TREE;
}
-pop_scopes:
- while (!for_block->is_empty ())
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
{
- /* FIXME diagnostics: LOC below should be the actual location of
- this particular for block. We need to build a list of
- locations to go along with FOR_BLOCK. */
- stmt = c_end_compound_stmt (loc, for_block->pop (), true);
- add_stmt (stmt);
+ omp_split_clauses (loc, OMP_DISTRIBUTE, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE];
}
- release_tree_vector (for_block);
+
+ 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 2.5:
- #pragma omp for for-clause[optseq] new-line
- for-loop
-
- LOC is the location of the #pragma token.
-*/
+/* OpenMP 4.0:
+ # pragma omp teams teams-clause[optseq] new-line
+ structured-block */
-#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_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_for (location_t loc, c_parser *parser)
+c_parser_omp_teams (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
{
- tree block, clauses, ret;
+ tree clauses, block, ret;
- clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK,
- "#pragma omp for");
+ strcat (p_name, " teams");
+ mask |= OMP_TEAMS_CLAUSE_MASK;
- block = c_begin_compound_stmt (true);
- ret = c_parser_omp_for_loop (loc, parser, clauses, NULL);
- block = c_end_compound_stmt (loc, block, true);
- add_stmt (block);
+ 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;
- return ret;
+ c_parser_consume_token (parser);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_distribute (loc, parser, p_name, mask, cclauses);
+ 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);
+ }
+ }
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ return NULL_TREE;
+ }
+
+ 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 2.5:
- # pragma omp master new-line
- structured-block
+/* OpenMP 4.0:
+ # pragma omp target data target-data-clause[optseq] new-line
+ structured-block */
- LOC is the location of the #pragma token.
-*/
+#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_master (location_t loc, c_parser *parser)
+c_parser_omp_target_data (location_t loc, c_parser *parser)
{
- c_parser_skip_to_pragma_eol (parser);
- return c_finish_omp_master (loc, c_parser_omp_structured_block (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 2.5:
- # pragma omp ordered new-line
- structured-block
+/* OpenMP 4.0:
+ # pragma omp target update target-update-clause[optseq] new-line */
- LOC is the location of the #pragma itself.
-*/
+#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 tree
-c_parser_omp_ordered (location_t loc, c_parser *parser)
+static bool
+c_parser_omp_target_update (location_t loc, c_parser *parser,
+ enum pragma_context context)
{
- c_parser_skip_to_pragma_eol (parser);
- return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser));
-}
+ 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;
+ }
-/* OpenMP 2.5:
+ 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;
+ }
- section-scope:
- { section-sequence }
+ 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;
+}
- section-sequence:
- section-directive[opt] structured-block
- section-sequence section-directive structured-block
+/* OpenMP 4.0:
+ # pragma omp target target-clause[optseq] new-line
+ structured-block */
- SECTIONS_LOC is the location of the #pragma omp sections. */
+#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 tree
-c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser)
+static bool
+c_parser_omp_target (c_parser *parser, enum pragma_context context)
{
- tree stmt, substmt;
- bool error_suppress = false;
- location_t loc;
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
- loc = c_parser_peek_token (parser)->location;
- if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ if (context != pragma_stmt && context != pragma_compound)
{
- /* Avoid skipping until the end of the block. */
- parser->error = false;
- return NULL_TREE;
+ 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, "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);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_teams (loc, parser, p_name,
+ OMP_TARGET_CLAUSE_MASK, cclauses);
+ 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;
+ }
+ else if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ return NULL_TREE;
+ }
+ else 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);
+ }
+ }
+
+ 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);
- stmt = push_stmt_list ();
-
- if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION)
+ while (c_parser_next_token_is (parser, CPP_PRAGMA))
{
- substmt = push_stmt_list ();
-
- while (1)
+ 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_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;
+ 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;
}
-
- substmt = pop_stmt_list (substmt);
- substmt = build1 (OMP_SECTION, void_type_node, substmt);
- SET_EXPR_LOCATION (substmt, loc);
- add_stmt (substmt);
+ 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);
}
- while (1)
- {
- if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
- break;
- if (c_parser_next_token_is (parser, CPP_EOF))
- break;
+ /* 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);
- loc = c_parser_peek_token (parser)->location;
- if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
+ switch (context)
+ {
+ case pragma_external:
+ if (c_parser_next_token_is (parser, CPP_KEYWORD)
+ && c_parser_peek_token (parser)->keyword == RID_EXTENSION)
{
- c_parser_consume_pragma (parser);
- c_parser_skip_to_pragma_eol (parser);
- error_suppress = false;
+ 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 if (!error_suppress)
+ 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)
{
- error_at (loc, "expected %<#pragma omp section%> or %<}%>");
- error_suppress = true;
+ 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);
}
-
- substmt = c_parser_omp_structured_block (parser);
- substmt = build1 (OMP_SECTION, void_type_node, substmt);
- SET_EXPR_LOCATION (substmt, loc);
- add_stmt (substmt);
+ 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 ();
}
- c_parser_skip_until_found (parser, CPP_CLOSE_BRACE,
- "expected %<#pragma omp section%> or %<}%>");
-
- substmt = pop_stmt_list (stmt);
-
- stmt = make_node (OMP_SECTIONS);
- SET_EXPR_LOCATION (stmt, sections_loc);
- TREE_TYPE (stmt) = void_type_node;
- OMP_SECTIONS_BODY (stmt) = substmt;
-
- return add_stmt (stmt);
+ clauses.release ();
}
-/* OpenMP 2.5:
- # pragma omp sections sections-clause[optseq] newline
- sections-scope
+/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed,
+ and put that into "omp declare simd" attribute. */
- LOC is the location of the #pragma token.
-*/
+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;
+ }
-#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))
+ if (parms == NULL_TREE)
+ parms = DECL_ARGUMENTS (fndecl);
-static tree
-c_parser_omp_sections (location_t loc, c_parser *parser)
-{
- tree block, clauses, ret;
+ unsigned int tokens_avail = parser->tokens_avail;
+ gcc_assert (parser->tokens == &parser->tokens_buf[0]);
+ parser->tokens = clauses.address ();
+ parser->tokens_avail = clauses.length ();
- clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK,
- "#pragma omp sections");
+ /* 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;
- block = c_begin_compound_stmt (true);
- ret = c_parser_omp_sections_scope (loc, parser);
- if (ret)
- OMP_SECTIONS_CLAUSES (ret) = clauses;
- block = c_end_compound_stmt (loc, block, true);
- add_stmt (block);
+ 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;
+ }
- return ret;
+ parser->tokens = &parser->tokens_buf[0];
+ parser->tokens_avail = tokens_avail;
+ clauses[0].type = CPP_PRAGMA;
}
-/* OpenMP 2.5:
- # pragma parallel parallel-clause new-line
- # pragma parallel for parallel-for-clause new-line
- # pragma parallel sections parallel-sections-clause new-line
- LOC is the location of the #pragma token.
-*/
+/* OpenMP 4.0:
+ # pragma omp declare target new-line
+ declarations and definitions
+ # pragma omp end declare target new-line */
-#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))
-
-static tree
-c_parser_omp_parallel (location_t loc, c_parser *parser)
+static void
+c_parser_omp_declare_target (c_parser *parser)
{
- 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;
+ c_parser_skip_to_pragma_eol (parser);
+ current_omp_declare_target_attribute++;
+}
- if (c_parser_next_token_is_keyword (parser, RID_FOR))
+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);
- p_kind = PRAGMA_OMP_PARALLEL_FOR;
- p_name = "#pragma omp parallel for";
- mask |= OMP_FOR_CLAUSE_MASK;
- mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
- }
- 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)
+ 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_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);
+ 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--;
+}
- clauses = c_parser_omp_all_clauses (parser, mask, p_name);
- switch (p_kind)
+/* 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)
{
- case PRAGMA_OMP_PARALLEL:
- block = c_begin_omp_parallel ();
- c_parser_statement (parser);
- stmt = c_finish_omp_parallel (loc, clauses, block);
- break;
+ error ("%<#pragma omp declare reduction%> not at file or block scope");
+ goto fail;
+ }
- 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;
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ goto fail;
- 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;
+ 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:
- gcc_unreachable ();
+ c_parser_error (parser,
+ "expected %<+%>, %<*%>, %<-%>, %<&%>, "
+ "%<^%>, %<|%>, %<&&%>, %<||%>, %<min%> or identifier");
+ goto fail;
}
- return stmt;
-}
+ 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);
-/* OpenMP 2.5:
- # pragma omp single single-clause[optseq] new-line
- structured-block
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ goto fail;
- LOC is the location of the #pragma.
-*/
+ 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;
+ }
-#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))
+ 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;
+ }
-static tree
-c_parser_omp_single (location_t loc, c_parser *parser)
-{
- tree stmt = make_node (OMP_SINGLE);
- SET_EXPR_LOCATION (stmt, loc);
- TREE_TYPE (stmt) = void_type_node;
+ 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);
- OMP_SINGLE_CLAUSES (stmt)
- = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK,
- "#pragma omp single");
- OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (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);
+ }
- return add_stmt (stmt);
-}
+ 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;
+ }
-/* OpenMP 3.0:
- # pragma omp task task-clause[optseq] new-line
+ 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;
+ }
- LOC is the location of the #pragma.
-*/
+ if (!bad)
+ {
+ c_parser_skip_to_pragma_eol (parser);
-#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))
+ 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);
+ }
+ }
-static tree
-c_parser_omp_task (location_t loc, c_parser *parser)
-{
- tree clauses, block;
+ 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 ();
- clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK,
- "#pragma omp task");
+ if (!clauses.is_empty ())
+ {
+ parser->tokens = &parser->tokens_buf[0];
+ parser->tokens_avail = tokens_avail;
+ }
+ if (bad)
+ goto fail;
+ if (errs != errorcount)
+ break;
+ }
- block = c_begin_omp_task ();
- c_parser_statement (parser);
- return c_finish_omp_task (loc, clauses, block);
+ clauses.release ();
+ types.release ();
}
-/* OpenMP 3.0:
- # pragma omp taskwait new-line
-*/
-
-static void
-c_parser_omp_taskwait (c_parser *parser)
-{
- location_t loc = c_parser_peek_token (parser)->location;
- c_parser_consume_pragma (parser);
- c_parser_skip_to_pragma_eol (parser);
-
- c_finish_omp_taskwait (loc);
-}
-/* OpenMP 3.1:
- # pragma omp taskyield new-line
-*/
+/* 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_taskyield (c_parser *parser)
+c_parser_omp_declare (c_parser *parser, enum pragma_context context)
{
- location_t loc = c_parser_peek_token (parser)->location;
c_parser_consume_pragma (parser);
- c_parser_skip_to_pragma_eol (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 (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+ if (strcmp (p, "target") == 0)
+ {
+ c_parser_consume_token (parser);
+ c_parser_omp_declare_target (parser);
+ return;
+ }
+ }
- c_finish_omp_taskyield (loc);
+ 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. */
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;
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);
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);
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 ();
}
c_parser_skip_to_pragma_eol (parser);
}
+\f
+/* Cilk Plus <#pragma simd> parsing routines. */
+
+/* Helper function for c_parser_pragma. Perform some sanity checking
+ for <#pragma simd> constructs. Returns FALSE if there was a
+ problem. */
+
+static bool
+c_parser_cilk_verify_simd (c_parser *parser,
+ enum pragma_context context)
+{
+ if (!flag_enable_cilkplus)
+ {
+ warning (0, "pragma simd ignored because -fcilkplus is not enabled");
+ c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+ return false;
+ }
+ if (context == pragma_external)
+ {
+ c_parser_error (parser,"pragma simd must be inside a function");
+ c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+ return false;
+ }
+ return true;
+}
+
+/* Cilk Plus:
+ vectorlength ( constant-expression ) */
+
+static tree
+c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses)
+{
+ /* The vectorlength clause behaves exactly like OpenMP's safelen
+ clause. Represent it in OpenMP terms. */
+ check_no_duplicate_clause (clauses, OMP_CLAUSE_SAFELEN, "vectorlength");
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return clauses;
+
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree expr = c_parser_expr_no_commas (parser, NULL).value;
+ expr = c_fully_fold (expr, false, NULL);
+
+ if (!TREE_TYPE (expr)
+ || !TREE_CONSTANT (expr)
+ || !INTEGRAL_TYPE_P (TREE_TYPE (expr)))
+ error_at (loc, "vectorlength must be an integer constant");
+ else if (wi::exact_log2 (expr) == -1)
+ error_at (loc, "vectorlength must be a power of 2");
+ else
+ {
+ tree u = build_omp_clause (loc, OMP_CLAUSE_SAFELEN);
+ OMP_CLAUSE_SAFELEN_EXPR (u) = expr;
+ OMP_CLAUSE_CHAIN (u) = clauses;
+ clauses = u;
+ }
+
+ c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ return clauses;
+}
+
+/* Cilk Plus:
+ linear ( simd-linear-variable-list )
+
+ simd-linear-variable-list:
+ simd-linear-variable
+ simd-linear-variable-list , simd-linear-variable
+
+ simd-linear-variable:
+ id-expression
+ id-expression : simd-linear-step
+
+ simd-linear-step:
+ conditional-expression */
+
+static tree
+c_parser_cilk_clause_linear (c_parser *parser, tree clauses)
+{
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return clauses;
+
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ if (c_parser_next_token_is_not (parser, CPP_NAME)
+ || c_parser_peek_token (parser)->id_kind != C_ID_ID)
+ c_parser_error (parser, "expected identifier");
+
+ while (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+ {
+ tree var = lookup_name (c_parser_peek_token (parser)->value);
+
+ if (var == NULL)
+ {
+ undeclared_variable (c_parser_peek_token (parser)->location,
+ c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ }
+ else if (var == error_mark_node)
+ c_parser_consume_token (parser);
+ else
+ {
+ tree step = integer_one_node;
+
+ /* Parse the linear step if present. */
+ if (c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ {
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+
+ tree expr = c_parser_expr_no_commas (parser, NULL).value;
+ expr = c_fully_fold (expr, false, NULL);
+
+ if (TREE_TYPE (expr)
+ && INTEGRAL_TYPE_P (TREE_TYPE (expr))
+ && (TREE_CONSTANT (expr)
+ || DECL_P (expr)))
+ step = expr;
+ else
+ c_parser_error (parser,
+ "step size must be an integer constant "
+ "expression or an integer variable");
+ }
+ else
+ c_parser_consume_token (parser);
+
+ /* Use OMP_CLAUSE_LINEAR, which has the same semantics. */
+ tree u = build_omp_clause (loc, OMP_CLAUSE_LINEAR);
+ OMP_CLAUSE_DECL (u) = var;
+ OMP_CLAUSE_LINEAR_STEP (u) = step;
+ OMP_CLAUSE_CHAIN (u) = clauses;
+ clauses = u;
+ }
+
+ if (c_parser_next_token_is_not (parser, CPP_COMMA))
+ break;
+
+ c_parser_consume_token (parser);
+ }
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ return clauses;
+}
+
+/* Returns the name of the next clause. If the clause is not
+ recognized SIMD_OMP_CLAUSE_NONE is returned and the next token is
+ not consumed. Otherwise, the appropriate pragma_simd_clause is
+ returned and the token is consumed. */
+
+static pragma_cilk_clause
+c_parser_cilk_clause_name (c_parser *parser)
+{
+ pragma_cilk_clause result;
+ c_token *token = c_parser_peek_token (parser);
+
+ if (!token->value || token->type != CPP_NAME)
+ return PRAGMA_CILK_CLAUSE_NONE;
+
+ const char *p = IDENTIFIER_POINTER (token->value);
+
+ if (!strcmp (p, "vectorlength"))
+ result = PRAGMA_CILK_CLAUSE_VECTORLENGTH;
+ else if (!strcmp (p, "linear"))
+ result = PRAGMA_CILK_CLAUSE_LINEAR;
+ else if (!strcmp (p, "private"))
+ result = PRAGMA_CILK_CLAUSE_PRIVATE;
+ else if (!strcmp (p, "firstprivate"))
+ result = PRAGMA_CILK_CLAUSE_FIRSTPRIVATE;
+ else if (!strcmp (p, "lastprivate"))
+ result = PRAGMA_CILK_CLAUSE_LASTPRIVATE;
+ else if (!strcmp (p, "reduction"))
+ result = PRAGMA_CILK_CLAUSE_REDUCTION;
+ else
+ return PRAGMA_CILK_CLAUSE_NONE;
+
+ c_parser_consume_token (parser);
+ return result;
+}
+
+/* Parse all #<pragma simd> clauses. Return the list of clauses
+ found. */
+
+static tree
+c_parser_cilk_all_clauses (c_parser *parser)
+{
+ tree clauses = NULL;
+
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ pragma_cilk_clause c_kind;
+
+ c_kind = c_parser_cilk_clause_name (parser);
+
+ switch (c_kind)
+ {
+ case PRAGMA_CILK_CLAUSE_VECTORLENGTH:
+ clauses = c_parser_cilk_clause_vectorlength (parser, clauses);
+ break;
+ case PRAGMA_CILK_CLAUSE_LINEAR:
+ clauses = c_parser_cilk_clause_linear (parser, clauses);
+ break;
+ case PRAGMA_CILK_CLAUSE_PRIVATE:
+ /* Use the OpenMP counterpart. */
+ clauses = c_parser_omp_clause_private (parser, clauses);
+ break;
+ case PRAGMA_CILK_CLAUSE_FIRSTPRIVATE:
+ /* Use the OpenMP counterpart. */
+ clauses = c_parser_omp_clause_firstprivate (parser, clauses);
+ break;
+ case PRAGMA_CILK_CLAUSE_LASTPRIVATE:
+ /* Use the OpenMP counterpart. */
+ clauses = c_parser_omp_clause_lastprivate (parser, clauses);
+ break;
+ case PRAGMA_CILK_CLAUSE_REDUCTION:
+ /* Use the OpenMP counterpart. */
+ clauses = c_parser_omp_clause_reduction (parser, clauses);
+ break;
+ default:
+ c_parser_error (parser, "expected %<#pragma simd%> clause");
+ goto saw_error;
+ }
+ }
+
+ saw_error:
+ c_parser_skip_to_pragma_eol (parser);
+ return c_finish_cilk_clauses (clauses);
+}
+
+/* Main entry point for parsing Cilk Plus <#pragma simd> for
+ loops. */
+static void
+c_parser_cilk_simd (c_parser *parser ATTRIBUTE_UNUSED)
+{
+ char p_name[100];
+ strcpy (p_name, "#pragma omp");
+ tree clauses = c_parser_cilk_all_clauses (parser);
+ tree block = c_begin_compound_stmt (true);
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_omp_for_loop (loc, parser, CILK_SIMD, clauses, NULL);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+}
+\f
/* Parse a transaction attribute (GCC Extension).
transaction-attribute:
*/
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;
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)
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)
the_parser = NULL;
}
+/* This function parses Cilk Plus array notation. The starting index is
+ passed in INITIAL_INDEX and the array name is passes in ARRAY_VALUE. The
+ return value of this function is a tree_node called VALUE_TREE of type
+ ARRAY_NOTATION_REF. */
+
+static tree
+c_parser_array_notation (location_t loc, c_parser *parser, tree initial_index,
+ tree array_value)
+{
+ c_token *token = NULL;
+ tree start_index = NULL_TREE, end_index = NULL_TREE, stride = NULL_TREE;
+ tree value_tree = NULL_TREE, type = NULL_TREE, array_type = NULL_TREE;
+ tree array_type_domain = NULL_TREE;
+
+ if (array_value == error_mark_node)
+ {
+ /* No need to continue. If either of these 2 were true, then an error
+ must be emitted already. Thus, no need to emit them twice. */
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
+ return error_mark_node;
+ }
+
+ array_type = TREE_TYPE (array_value);
+ gcc_assert (array_type);
+ type = TREE_TYPE (array_type);
+ token = c_parser_peek_token (parser);
+
+ if (token->type == CPP_EOF)
+ {
+ c_parser_error (parser, "expected %<:%> or numeral");
+ return value_tree;
+ }
+ else if (token->type == CPP_COLON)
+ {
+ if (!initial_index)
+ {
+ /* If we are here, then we have a case like this A[:]. */
+ c_parser_consume_token (parser);
+ if (TREE_CODE (array_type) == POINTER_TYPE)
+ {
+ error_at (loc, "start-index and length fields necessary for "
+ "using array notations in pointers");
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
+ return error_mark_node;
+ }
+ if (TREE_CODE (array_type) == FUNCTION_TYPE)
+ {
+ error_at (loc, "array notations cannot be used with function "
+ "type");
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
+ return error_mark_node;
+ }
+ array_type_domain = TYPE_DOMAIN (array_type);
+
+ if (!array_type_domain)
+ {
+ error_at (loc, "start-index and length fields necessary for "
+ "using array notations in dimensionless arrays");
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
+ return error_mark_node;
+ }
+
+ start_index = TYPE_MINVAL (array_type_domain);
+ start_index = fold_build1 (CONVERT_EXPR, ptrdiff_type_node,
+ start_index);
+ if (!TYPE_MAXVAL (array_type_domain)
+ || !TREE_CONSTANT (TYPE_MAXVAL (array_type_domain)))
+ {
+ error_at (loc, "start-index and length fields necessary for "
+ "using array notations in variable-length arrays");
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
+ return error_mark_node;
+ }
+ end_index = TYPE_MAXVAL (array_type_domain);
+ end_index = fold_build2 (PLUS_EXPR, TREE_TYPE (end_index),
+ end_index, integer_one_node);
+ end_index = fold_build1 (CONVERT_EXPR, ptrdiff_type_node, end_index);
+ stride = build_int_cst (integer_type_node, 1);
+ stride = fold_build1 (CONVERT_EXPR, ptrdiff_type_node, stride);
+ }
+ else if (initial_index != error_mark_node)
+ {
+ /* If we are here, then there should be 2 possibilities:
+ 1. Array [EXPR : EXPR]
+ 2. Array [EXPR : EXPR : EXPR]
+ */
+ start_index = initial_index;
+
+ if (TREE_CODE (array_type) == FUNCTION_TYPE)
+ {
+ error_at (loc, "array notations cannot be used with function "
+ "type");
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
+ return error_mark_node;
+ }
+ c_parser_consume_token (parser); /* consume the ':' */
+ struct c_expr ce = c_parser_expression (parser);
+ ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+ end_index = ce.value;
+ if (!end_index || end_index == error_mark_node)
+ {
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return error_mark_node;
+ }
+ if (c_parser_peek_token (parser)->type == CPP_COLON)
+ {
+ c_parser_consume_token (parser);
+ ce = c_parser_expression (parser);
+ ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+ stride = ce.value;
+ if (!stride || stride == error_mark_node)
+ {
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return error_mark_node;
+ }
+ }
+ }
+ else
+ c_parser_error (parser, "expected array notation expression");
+ }
+ else
+ c_parser_error (parser, "expected array notation expression");
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>");
+
+ value_tree = build_array_notation_ref (loc, array_value, start_index,
+ end_index, stride, type);
+ if (value_tree != error_mark_node)
+ SET_EXPR_LOCATION (value_tree, loc);
+ return value_tree;
+}
+
#include "gt-c-c-parser.h"