OpenMP 4.5:
linear ( modifier ( variable-list ) )
- linear ( modifier ( variable-list ) : expression ) */
+ linear ( modifier ( variable-list ) : expression )
+
+ modifier:
+ val
+
+ OpenMP 5.2:
+ linear ( variable-list : modifiers-list )
+
+ modifiers:
+ val
+ step ( expression ) */
static tree
c_parser_omp_clause_linear (c_parser *parser, tree list)
location_t clause_loc = c_parser_peek_token (parser)->location;
tree nl, c, step;
enum omp_clause_linear_kind kind = OMP_CLAUSE_LINEAR_DEFAULT;
+ bool old_linear_modifier = false;
matching_parens parens;
if (!parens.require_open (parser))
kind = OMP_CLAUSE_LINEAR_DEFAULT;
if (kind != OMP_CLAUSE_LINEAR_DEFAULT)
{
+ old_linear_modifier = true;
c_parser_consume_token (parser);
c_parser_consume_token (parser);
}
{
c_parser_consume_token (parser);
location_t expr_loc = c_parser_peek_token (parser)->location;
- c_expr expr = c_parser_expr_no_commas (parser, NULL);
- expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
- step = expr.value;
- step = c_fully_fold (step, false, NULL);
- if (!INTEGRAL_TYPE_P (TREE_TYPE (step)))
+ bool has_modifiers = false;
+ if (kind == OMP_CLAUSE_LINEAR_DEFAULT
+ && c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_token *tok = c_parser_peek_token (parser);
+ const char *p = IDENTIFIER_POINTER (tok->value);
+ unsigned int pos = 0;
+ if (strcmp ("val", p) == 0)
+ pos = 2;
+ else if (strcmp ("step", p) == 0
+ && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN)
+ {
+ pos = 3;
+ if (c_parser_check_balanced_raw_token_sequence (parser, &pos)
+ && (c_parser_peek_nth_token_raw (parser, pos)->type
+ == CPP_CLOSE_PAREN))
+ ++pos;
+ else
+ pos = 0;
+ }
+ if (pos)
+ {
+ tok = c_parser_peek_nth_token_raw (parser, pos);
+ if (tok->type == CPP_COMMA || tok->type == CPP_CLOSE_PAREN)
+ has_modifiers = true;
+ }
+ }
+ if (has_modifiers)
+ {
+ step = NULL_TREE;
+ while (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_token *tok = c_parser_peek_token (parser);
+ const char *p = IDENTIFIER_POINTER (tok->value);
+ if (strcmp ("val", p) == 0)
+ {
+ if (kind != OMP_CLAUSE_LINEAR_DEFAULT)
+ error_at (tok->location, "multiple linear modifiers");
+ kind = OMP_CLAUSE_LINEAR_DEFAULT;
+ c_parser_consume_token (parser);
+ }
+ else if (strcmp ("step", p) == 0)
+ {
+ c_parser_consume_token (parser);
+ matching_parens parens2;
+ if (parens2.require_open (parser))
+ {
+ if (step)
+ error_at (tok->location,
+ "multiple %<step%> modifiers");
+ expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false,
+ true);
+ step = c_fully_fold (expr.value, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (step)))
+ {
+ error_at (clause_loc, "%<linear%> clause step "
+ "expression must be integral");
+ step = integer_one_node;
+ }
+ parens2.skip_until_found_close (parser);
+ }
+ else
+ break;
+ }
+ else
+ break;
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ continue;
+ }
+ break;
+ }
+ if (!step)
+ step = integer_one_node;
+ }
+ else
{
- error_at (clause_loc, "%<linear%> clause step expression must "
- "be integral");
- step = integer_one_node;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ step = c_fully_fold (expr.value, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (step)))
+ {
+ error_at (clause_loc, "%<linear%> clause step expression must "
+ "be integral");
+ step = integer_one_node;
+ }
}
}
{
OMP_CLAUSE_LINEAR_STEP (c) = step;
OMP_CLAUSE_LINEAR_KIND (c) = kind;
+ OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (c) = old_linear_modifier;
}
parens.skip_until_found_close (parser);
need_implicitly_determined = true;
t = OMP_CLAUSE_DECL (c);
if (ort != C_ORT_OMP_DECLARE_SIMD
- && OMP_CLAUSE_LINEAR_KIND (c) != OMP_CLAUSE_LINEAR_DEFAULT)
+ && OMP_CLAUSE_LINEAR_KIND (c) != OMP_CLAUSE_LINEAR_DEFAULT
+ && OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (c))
{
error_at (OMP_CLAUSE_LOCATION (c),
"modifier should not be specified in %<linear%> "
- "clause on %<simd%> or %<for%> constructs");
+ "clause on %<simd%> or %<for%> constructs when not "
+ "using OpenMP 5.2 modifiers");
OMP_CLAUSE_LINEAR_KIND (c) = OMP_CLAUSE_LINEAR_DEFAULT;
}
if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
OpenMP 4.5:
linear ( modifier ( variable-list ) )
- linear ( modifier ( variable-list ) : expression ) */
+ linear ( modifier ( variable-list ) : expression )
+
+ modifier:
+ val
+ ref
+ uval
+
+ OpenMP 5.2:
+ linear ( variable-list : modifiers-list )
+
+ modifiers:
+ val
+ ref
+ uval
+ step ( expression ) */
static tree
cp_parser_omp_clause_linear (cp_parser *parser, tree list,
tree nlist, c, step = integer_one_node;
bool colon;
enum omp_clause_linear_kind kind = OMP_CLAUSE_LINEAR_DEFAULT;
+ bool old_linear_modifier = false;
matching_parens parens;
if (!parens.require_open (parser))
else if (strcmp ("uval", p) == 0)
kind = OMP_CLAUSE_LINEAR_UVAL;
if (cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN))
- cp_lexer_consume_token (parser->lexer);
+ {
+ cp_lexer_consume_token (parser->lexer);
+ old_linear_modifier = true;
+ }
else
kind = OMP_CLAUSE_LINEAR_DEFAULT;
}
if (colon)
{
+ bool has_modifiers = false;
+ if (kind == OMP_CLAUSE_LINEAR_DEFAULT
+ && cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+ size_t pos = 0;
+ if (strcmp ("ref", p) == 0
+ || strcmp ("val", p) == 0
+ || strcmp ("uval", p) == 0)
+ pos = 2;
+ else if (strcmp ("step", p) == 0
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN))
+ {
+ pos = cp_parser_skip_balanced_tokens (parser, 2);
+ if (pos == 2)
+ pos = 0;
+ }
+ if (pos != 0
+ && (cp_lexer_nth_token_is (parser->lexer, pos, CPP_COMMA)
+ || cp_lexer_nth_token_is (parser->lexer, pos,
+ CPP_CLOSE_PAREN)))
+ has_modifiers = true;
+ }
+
step = NULL_TREE;
- if (declare_simd
- && cp_lexer_next_token_is (parser->lexer, CPP_NAME)
- && cp_lexer_nth_token_is (parser->lexer, 2, CPP_CLOSE_PAREN))
+ if (has_modifiers)
+ {
+ while (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+ enum omp_clause_linear_kind nkind = OMP_CLAUSE_LINEAR_DEFAULT;
+ if (strcmp ("ref", p) == 0)
+ nkind = OMP_CLAUSE_LINEAR_REF;
+ else if (strcmp ("val", p) == 0)
+ nkind = OMP_CLAUSE_LINEAR_VAL;
+ else if (strcmp ("uval", p) == 0)
+ nkind = OMP_CLAUSE_LINEAR_UVAL;
+ if (nkind != OMP_CLAUSE_LINEAR_DEFAULT)
+ {
+ if (kind != OMP_CLAUSE_LINEAR_DEFAULT)
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "multiple linear modifiers");
+ kind = nkind;
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else if (strcmp ("step", p) == 0)
+ {
+ location_t step_loc
+ = cp_lexer_peek_token (parser->lexer)->location;
+ cp_lexer_consume_token (parser->lexer);
+ matching_parens parens2;
+ if (parens2.require_open (parser))
+ {
+ if (step)
+ error_at (step_loc, "multiple %<step%> modifiers");
+ if (declare_simd
+ && cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ && cp_lexer_nth_token_is (parser->lexer, 2,
+ CPP_CLOSE_PAREN))
+ {
+ cp_token *token
+ = cp_lexer_peek_token (parser->lexer);
+ location_t tok_loc = token->location;
+ cp_parser_parse_tentatively (parser);
+ step = cp_parser_id_expression (parser, false, true,
+ NULL, false, false);
+ if (step != error_mark_node)
+ step = cp_parser_lookup_name_simple (parser, step,
+ tok_loc);
+ if (step == error_mark_node)
+ {
+ step = NULL_TREE;
+ cp_parser_abort_tentative_parse (parser);
+ }
+ else if (!cp_parser_parse_definitely (parser))
+ step = NULL_TREE;
+ }
+ if (!step)
+ step = cp_parser_assignment_expression (parser);
+ if (!parens2.require_close (parser))
+ cp_parser_skip_to_closing_parenthesis (parser, true,
+ false, true);
+ }
+ else
+ break;
+ }
+ else
+ break;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ continue;
+ }
+ break;
+ }
+ if (!step)
+ step = integer_one_node;
+ }
+ else if (declare_simd
+ && cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_CLOSE_PAREN))
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
cp_parser_parse_tentatively (parser);
{
OMP_CLAUSE_LINEAR_STEP (c) = step;
OMP_CLAUSE_LINEAR_KIND (c) = kind;
+ OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (c) = old_linear_modifier;
}
return nlist;
if (ort != C_ORT_OMP_DECLARE_SIMD
&& OMP_CLAUSE_LINEAR_KIND (c) != OMP_CLAUSE_LINEAR_DEFAULT)
{
- error_at (OMP_CLAUSE_LOCATION (c),
- "modifier should not be specified in %<linear%> "
- "clause on %<simd%> or %<for%> constructs");
- OMP_CLAUSE_LINEAR_KIND (c) = OMP_CLAUSE_LINEAR_DEFAULT;
+ if (OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (c))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "modifier should not be specified in %<linear%> "
+ "clause on %<simd%> or %<for%> constructs when "
+ "not using OpenMP 5.2 modifiers");
+ OMP_CLAUSE_LINEAR_KIND (c) = OMP_CLAUSE_LINEAR_DEFAULT;
+ }
+ else if (OMP_CLAUSE_LINEAR_KIND (c) != OMP_CLAUSE_LINEAR_VAL)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "modifier other than %<val%> specified in "
+ "%<linear%> clause on %<simd%> or %<for%> "
+ "constructs when using OpenMP 5.2 modifiers");
+ OMP_CLAUSE_LINEAR_KIND (c) = OMP_CLAUSE_LINEAR_DEFAULT;
+ }
}
if ((VAR_P (t) || TREE_CODE (t) == PARM_DECL)
&& !type_dependent_expression_p (t))
gcc_unreachable ();
}
OMP_CLAUSE_LINEAR_KIND (node) = kind;
+ OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (node) = 1;
if (last_step_expr && last_step == NULL_TREE)
{
if (!declare_simd)
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+int i;
+
+#pragma omp declare simd linear (x : val, step (1)) linear (y : step (2))
+int bar (int x, int y, int z);
+#pragma omp declare simd linear (x : step (1), val)
+int baz (int x, int y, int z);
+#pragma omp declare simd linear (val (x) : val) uniform (val)
+int qux (int x, int val);
+#pragma omp declare simd linear (x : val, step (val)) uniform (val)
+int corge (int x, int val);
+#pragma omp declare simd linear (x : val)
+int grault (int x);
+int step (int);
+
+void
+foo (int x, int y)
+{
+ int val = 1;
+ #pragma omp simd linear (i: step (3))
+ for (i = 0; i < 33; i += 3)
+ ;
+ #pragma omp simd linear (i: val, step (3))
+ for (i = 0; i < 33; i += 3)
+ ;
+ #pragma omp simd linear (x: step (y + 1))
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp simd linear (x: step (y + 1), val)
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for linear (x: step (y + 1))
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for linear (x: val, step (y + 1))
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for simd linear (i: step (3))
+ for (i = 0; i < 33; i += 3)
+ ;
+ #pragma omp parallel for simd linear (i: step (3), val)
+ for (i = 0; i < 33; i += 3)
+ ;
+ #pragma omp parallel for simd linear (x: step (y + 1))
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for simd linear (x: val, step (y + 1))
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for simd linear (i: val + 0)
+ for (i = 0; i < 10; i++)
+ ;
+ #pragma omp parallel for simd linear (i: step (1) * 1)
+ for (i = 0; i < 10; i++)
+ ;
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+int step (int);
+int val;
+#pragma omp declare simd linear (val (x) : step (1)) /* { dg-error "is neither constant nor a parameter" } */
+int bar (int x, int y, int z);
+#pragma omp declare simd linear (val (x) : val) /* { dg-error "is neither constant nor a parameter" } */
+int baz (int x, int y, int z);
--- /dev/null
+// { dg-do compile { target c++11 } }
+// { dg-options "-fopenmp" }
+
+int i;
+
+#pragma omp declare simd linear (x : ref, step (1)) linear (y : step (2), uval)
+int bar (int &x, int &y, int z);
+#pragma omp declare simd linear (x : step (1), uval)
+int baz (int &x, int y, int z);
+#pragma omp declare simd linear (ref (x) : ref) uniform (ref)
+int qux (int &x, int ref);
+#pragma omp declare simd linear (x : ref, step (ref)) uniform (ref)
+int corge (int &x, int ref);
+#pragma omp declare simd linear (x : ref)
+int grault (int &x);
+#pragma omp declare simd linear (x : uval)
+int waldo (int &x);
+constexpr int step (int x) { return x; }
+
+void
+foo (int &x, int &y)
+{
+ #pragma omp simd linear (x: step (y + 1))
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp simd linear (x: val, step (y + 1))
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for linear (x: step (y + 1))
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for linear (x: step (y + 1), val)
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for simd linear (x: step (y + 1))
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for simd linear (x: val, step (y + 1))
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for simd linear (x: step (1) + 0)
+ for (i = 0; i < 10; i++)
+ x += step (1) + 0;
+ {
+ constexpr int ref = 1;
+ constexpr int uval = 2;
+ #pragma omp parallel for simd linear (x: ref + 0)
+ for (i = 0; i < 10; i++)
+ x += ref + 0;
+ #pragma omp parallel for simd linear (x: uval * 1)
+ for (i = 0; i < 10; i++)
+ x += uval;
+ }
+}
--- /dev/null
+// { dg-do compile }
+// { dg-options "-fopenmp" }
+
+int i;
+
+void
+foo (int &x, int &y)
+{
+ #pragma omp simd linear (x: step (y + 1), ref) // { dg-error "modifier other than 'val' specified in 'linear' clause" }
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp simd linear (x: uval, step (y + 1)) // { dg-error "modifier other than 'val' specified in 'linear' clause" }
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for linear (x: ref, step (y + 1)) // { dg-error "modifier other than 'val' specified in 'linear' clause" }
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for linear (x: step (y + 1), uval) // { dg-error "modifier other than 'val' specified in 'linear' clause" }
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for simd linear (x: step (y + 1), ref) // { dg-error "modifier other than 'val' specified in 'linear' clause" }
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+ #pragma omp parallel for simd linear (x: uval, step (y + 1)) // { dg-error "modifier other than 'val' specified in 'linear' clause" }
+ for (i = 0; i < 10; i++)
+ x += y + 1;
+}
--- /dev/null
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-fopenmp" } */
+
+constexpr int step (int x) { return x; }
+constexpr int val = 1;
+constexpr int ref = 2;
+constexpr int uval = 3;
+#pragma omp declare simd linear (val (x) : step (1)) linear (ref (y) : step (2)) linear (uval (z) : step (3))
+int foo (int x, int &y, int &z);
+#pragma omp declare simd linear (val (x) : val) linear (ref (y) : ref) linear (uval (z) : uval)
+int bar (int x, int &y, int &z);
+#pragma omp declare simd linear (val (x) : ref) linear (ref (y) : uval) linear (uval (z) : val)
+int baz (int x, int &y, int &z);
+#pragma omp declare simd linear (val (x) : uval) linear (ref (y) : val) linear (uval (z) : ref)
+int qux (int x, int &y, int &z);
case OMP_CLAUSE_LINEAR:
pp_string (pp, "linear(");
- switch (OMP_CLAUSE_LINEAR_KIND (clause))
- {
- case OMP_CLAUSE_LINEAR_DEFAULT:
- break;
- case OMP_CLAUSE_LINEAR_REF:
- pp_string (pp, "ref(");
- break;
- case OMP_CLAUSE_LINEAR_VAL:
- pp_string (pp, "val(");
- break;
- case OMP_CLAUSE_LINEAR_UVAL:
- pp_string (pp, "uval(");
- break;
- default:
- gcc_unreachable ();
- }
+ if (OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (clause))
+ switch (OMP_CLAUSE_LINEAR_KIND (clause))
+ {
+ case OMP_CLAUSE_LINEAR_DEFAULT:
+ break;
+ case OMP_CLAUSE_LINEAR_REF:
+ pp_string (pp, "ref(");
+ break;
+ case OMP_CLAUSE_LINEAR_VAL:
+ pp_string (pp, "val(");
+ break;
+ case OMP_CLAUSE_LINEAR_UVAL:
+ pp_string (pp, "uval(");
+ break;
+ default:
+ gcc_unreachable ();
+ }
dump_generic_node (pp, OMP_CLAUSE_DECL (clause),
spc, flags, false);
- if (OMP_CLAUSE_LINEAR_KIND (clause) != OMP_CLAUSE_LINEAR_DEFAULT)
+ if (OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (clause)
+ && OMP_CLAUSE_LINEAR_KIND (clause) != OMP_CLAUSE_LINEAR_DEFAULT)
pp_right_paren (pp);
pp_colon (pp);
+ if (!OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (clause)
+ && OMP_CLAUSE_LINEAR_KIND (clause) != OMP_CLAUSE_LINEAR_DEFAULT)
+ switch (OMP_CLAUSE_LINEAR_KIND (clause))
+ {
+ case OMP_CLAUSE_LINEAR_REF:
+ pp_string (pp, "ref,step(");
+ break;
+ case OMP_CLAUSE_LINEAR_VAL:
+ pp_string (pp, "val,step(");
+ break;
+ case OMP_CLAUSE_LINEAR_UVAL:
+ pp_string (pp, "uval,step(");
+ break;
+ default:
+ gcc_unreachable ();
+ }
dump_generic_node (pp, OMP_CLAUSE_LINEAR_STEP (clause),
spc, flags, false);
+ if (!OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (clause)
+ && OMP_CLAUSE_LINEAR_KIND (clause) != OMP_CLAUSE_LINEAR_DEFAULT)
+ pp_right_paren (pp);
pp_right_paren (pp);
break;
#define OMP_CLAUSE_LINEAR_VARIABLE_STRIDE(NODE) \
TREE_PROTECTED (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LINEAR))
+/* True for a LINEAR clause with old style modifier syntax
+ linear(modifier(list)) or linear(modifier(list):step). */
+#define OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER(NODE) \
+ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LINEAR)->base.addressable_flag)
+
/* True if a LINEAR clause is for an array or allocatable variable that
needs special handling by the frontend. */
#define OMP_CLAUSE_LINEAR_ARRAY(NODE) \