@@ -9500,10 +9500,18 @@ c_parser_omp_structured_block (c_parser
update-stmt:
expression-stmt | x = x binop expr
capture-stmt:
- v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x
+ v = expression-stmt
capture-block:
{ v = x; update-stmt; } | { update-stmt; v = x; }
+ OpenMP 4.0:
+ update-stmt:
+ expression-stmt | x = x binop expr | x = expr binop x
+ capture-stmt:
+ v = update-stmt
+ capture-block:
+ { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; }
+
where x and v are lvalue expressions with scalar type.
LOC is the location of the #pragma token. */
@@ -9826,7 +9834,8 @@ stmt_done:
c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
}
done:
- stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1);
+ stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1,
+ false);
if (stmt != error_mark_node)
add_stmt (stmt);
@@ -7471,9 +7471,11 @@ cp_parser_binary_expression (cp_parser*
*/
if (no_toplevel_fold_p
&& lookahead_prec <= current.prec
- && sp == stack
- && TREE_CODE_CLASS (current.tree_type) == tcc_comparison)
- current.lhs = build2 (current.tree_type, boolean_type_node,
+ && sp == stack)
+ current.lhs = build2 (current.tree_type,
+ TREE_CODE_CLASS (current.tree_type)
+ == tcc_comparison
+ ? boolean_type_node : TREE_TYPE (current.lhs),
current.lhs, rhs);
else
current.lhs = build_x_binary_op (current.loc, current.tree_type,
@@ -26426,10 +26428,18 @@ cp_parser_omp_structured_block (cp_parse
update-stmt:
expression-stmt | x = x binop expr
capture-stmt:
- v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x
+ v = expression-stmt
capture-block:
{ v = x; update-stmt; } | { update-stmt; v = x; }
+ OpenMP 4.0:
+ update-stmt:
+ expression-stmt | x = x binop expr | x = expr binop x
+ capture-stmt:
+ v = update-stmt
+ capture-block:
+ { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; }
+
where x and v are lvalue expressions with scalar type. */
static void
@@ -26596,75 +26606,139 @@ restart:
opcode = BIT_XOR_EXPR;
break;
case CPP_EQ:
- if (structured_block || code == OMP_ATOMIC)
+ enum cp_parser_prec oprec;
+ cp_token *token;
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_parse_tentatively (parser);
+ rhs1 = cp_parser_simple_cast_expression (parser);
+ if (rhs1 == error_mark_node)
{
- enum cp_parser_prec oprec;
- cp_token *token;
- cp_lexer_consume_token (parser->lexer);
- rhs1 = cp_parser_unary_expression (parser, /*address_p=*/false,
- /*cast_p=*/false, NULL);
- if (rhs1 == error_mark_node)
- goto saw_error;
- token = cp_lexer_peek_token (parser->lexer);
- switch (token->type)
+ cp_parser_abort_tentative_parse (parser);
+ cp_parser_simple_cast_expression (parser);
+ goto saw_error;
+ }
+ token = cp_lexer_peek_token (parser->lexer);
+ if (token->type != CPP_SEMICOLON && !cp_tree_equal (lhs, rhs1))
+ {
+ cp_parser_abort_tentative_parse (parser);
+ cp_parser_parse_tentatively (parser);
+ rhs = cp_parser_binary_expression (parser, false, true,
+ PREC_NOT_OPERATOR, NULL);
+ if (rhs == error_mark_node)
+ {
+ cp_parser_abort_tentative_parse (parser);
+ cp_parser_binary_expression (parser, false, true,
+ PREC_NOT_OPERATOR, NULL);
+ goto saw_error;
+ }
+ switch (TREE_CODE (rhs))
{
- case CPP_SEMICOLON:
- if (code == OMP_ATOMIC_CAPTURE_NEW)
+ 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 (cp_tree_equal (lhs, TREE_OPERAND (rhs, 1)))
{
- code = OMP_ATOMIC_CAPTURE_OLD;
- v = lhs;
- lhs = NULL_TREE;
- lhs1 = rhs1;
- rhs1 = NULL_TREE;
- cp_lexer_consume_token (parser->lexer);
- goto restart;
+ if (cp_parser_parse_definitely (parser))
+ {
+ opcode = TREE_CODE (rhs);
+ rhs1 = TREE_OPERAND (rhs, 0);
+ rhs = TREE_OPERAND (rhs, 1);
+ goto stmt_done;
+ }
+ else
+ goto saw_error;
}
- cp_parser_error (parser,
- "invalid form of %<#pragma omp atomic%>");
- goto saw_error;
- case CPP_MULT:
- opcode = MULT_EXPR;
- break;
- case CPP_DIV:
- opcode = TRUNC_DIV_EXPR;
- break;
- case CPP_PLUS:
- opcode = PLUS_EXPR;
- break;
- case CPP_MINUS:
- opcode = MINUS_EXPR;
- break;
- case CPP_LSHIFT:
- opcode = LSHIFT_EXPR;
- break;
- case CPP_RSHIFT:
- opcode = RSHIFT_EXPR;
- break;
- case CPP_AND:
- opcode = BIT_AND_EXPR;
- break;
- case CPP_OR:
- opcode = BIT_IOR_EXPR;
- break;
- case CPP_XOR:
- opcode = BIT_XOR_EXPR;
break;
default:
- cp_parser_error (parser,
- "invalid operator for %<#pragma omp atomic%>");
- goto saw_error;
+ break;
}
- oprec = TOKEN_PRECEDENCE (token);
- gcc_assert (oprec != PREC_NOT_OPERATOR);
- if (commutative_tree_code (opcode))
- oprec = (enum cp_parser_prec) (oprec - 1);
- cp_lexer_consume_token (parser->lexer);
- rhs = cp_parser_binary_expression (parser, false, false,
- oprec, NULL);
- if (rhs == error_mark_node)
- goto saw_error;
- goto stmt_done;
+ cp_parser_abort_tentative_parse (parser);
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_OLD)
+ {
+ rhs = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+ if (rhs == error_mark_node)
+ goto saw_error;
+ opcode = NOP_EXPR;
+ rhs1 = NULL_TREE;
+ goto stmt_done;
+ }
+ cp_parser_error (parser,
+ "invalid form of %<#pragma omp atomic%>");
+ goto saw_error;
+ }
+ if (!cp_parser_parse_definitely (parser))
+ goto saw_error;
+ switch (token->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;
+ cp_lexer_consume_token (parser->lexer);
+ goto restart;
+ }
+ else if (structured_block)
+ {
+ opcode = NOP_EXPR;
+ rhs = rhs1;
+ rhs1 = NULL_TREE;
+ goto stmt_done;
+ }
+ cp_parser_error (parser,
+ "invalid form of %<#pragma omp atomic%>");
+ goto saw_error;
+ case CPP_MULT:
+ opcode = MULT_EXPR;
+ break;
+ case CPP_DIV:
+ opcode = TRUNC_DIV_EXPR;
+ break;
+ case CPP_PLUS:
+ opcode = PLUS_EXPR;
+ break;
+ case CPP_MINUS:
+ opcode = MINUS_EXPR;
+ break;
+ case CPP_LSHIFT:
+ opcode = LSHIFT_EXPR;
+ break;
+ case CPP_RSHIFT:
+ opcode = RSHIFT_EXPR;
+ break;
+ case CPP_AND:
+ opcode = BIT_AND_EXPR;
+ break;
+ case CPP_OR:
+ opcode = BIT_IOR_EXPR;
+ break;
+ case CPP_XOR:
+ opcode = BIT_XOR_EXPR;
+ break;
+ default:
+ cp_parser_error (parser,
+ "invalid operator for %<#pragma omp atomic%>");
+ goto saw_error;
}
+ oprec = TOKEN_PRECEDENCE (token);
+ gcc_assert (oprec != PREC_NOT_OPERATOR);
+ if (commutative_tree_code (opcode))
+ oprec = (enum cp_parser_prec) (oprec - 1);
+ cp_lexer_consume_token (parser->lexer);
+ rhs = cp_parser_binary_expression (parser, false, false,
+ oprec, NULL);
+ if (rhs == error_mark_node)
+ goto saw_error;
+ goto stmt_done;
/* FALLTHROUGH */
default:
cp_parser_error (parser,
@@ -13268,6 +13268,8 @@ tsubst_expr (tree t, tree args, tsubst_f
lhs = RECUR (TREE_OPERAND (op11, 0));
rhs = RECUR (TREE_OPERAND (op11, 1));
opcode = TREE_CODE (op11);
+ if (opcode == MODIFY_EXPR)
+ opcode = NOP_EXPR;
}
else
{
@@ -5009,8 +5009,36 @@ finish_omp_atomic (enum tree_code code,
}
if (!dependent_p)
{
+ bool swapped = false;
+ if (rhs1 && cp_tree_equal (lhs, rhs))
+ {
+ tree tem = rhs;
+ rhs = rhs1;
+ rhs1 = tem;
+ swapped = !commutative_tree_code (opcode);
+ }
+ if (rhs1 && !cp_tree_equal (lhs, rhs1))
+ {
+ if (code == OMP_ATOMIC)
+ error ("%<#pragma omp atomic update%> uses two different "
+ "expressions for memory");
+ else
+ error ("%<#pragma omp atomic capture%> uses two different "
+ "expressions for memory");
+ return;
+ }
+ if (lhs1 && !cp_tree_equal (lhs, lhs1))
+ {
+ if (code == OMP_ATOMIC)
+ error ("%<#pragma omp atomic update%> uses two different "
+ "expressions for memory");
+ else
+ error ("%<#pragma omp atomic capture%> uses two different "
+ "expressions for memory");
+ return;
+ }
stmt = c_finish_omp_atomic (input_location, code, opcode, lhs, rhs,
- v, lhs1, rhs1);
+ v, lhs1, rhs1, swapped);
if (stmt == error_mark_node)
return;
}
@@ -122,7 +122,7 @@ c_finish_omp_taskyield (location_t loc)
tree
c_finish_omp_atomic (location_t loc, enum tree_code code,
enum tree_code opcode, tree lhs, tree rhs,
- tree v, tree lhs1, tree rhs1)
+ tree v, tree lhs1, tree rhs1, bool swapped)
{
tree x, type, addr;
@@ -176,8 +176,12 @@ c_finish_omp_atomic (location_t loc, enu
/* There are lots of warnings, errors, and conversions that need to happen
in the course of interpreting a statement. Use the normal mechanisms
to do this, and then take it apart again. */
- x = build_modify_expr (input_location, lhs, NULL_TREE, opcode,
- input_location, rhs, NULL_TREE);
+ if (swapped)
+ {
+ rhs = build2_loc (loc, opcode, TREE_TYPE (lhs), rhs, lhs);
+ opcode = NOP_EXPR;
+ }
+ x = build_modify_expr (loc, lhs, NULL_TREE, opcode, loc, rhs, NULL_TREE);
if (x == error_mark_node)
return error_mark_node;
gcc_assert (TREE_CODE (x) == MODIFY_EXPR);
@@ -1035,7 +1035,7 @@ extern tree c_finish_omp_critical (locat
extern tree c_finish_omp_ordered (location_t, tree);
extern void c_finish_omp_barrier (location_t);
extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code,
- tree, tree, tree, tree, tree);
+ tree, tree, tree, tree, tree, bool);
extern void c_finish_omp_flush (location_t);
extern void c_finish_omp_taskwait (location_t);
extern void c_finish_omp_taskyield (location_t);
@@ -20,8 +20,6 @@ main ()
#pragma omp atomic
x = x / 7 / 2; /* { dg-error "expected" } */
#pragma omp atomic capture
- v = x = x | 6; /* { dg-error "invalid operator" } */
- #pragma omp atomic capture
{ v = x; x = x * 7 + 6; } /* { dg-error "expected" } */
#pragma omp atomic capture
{ v = x; x = x * 7 ^ 6; } /* { dg-error "expected" } */
@@ -0,0 +1,99 @@
+// { dg-do run }
+
+extern "C" void abort (void);
+int x = 6;
+
+int
+main ()
+{
+ int v, l = 2, s = 1;
+ #pragma omp atomic
+ x = -3 + x;
+ #pragma omp atomic read
+ v = x;
+ if (v != 3)
+ abort ();
+ #pragma omp atomic update
+ x = 3 * 2 * 1 + x;
+ #pragma omp atomic read
+ v = x;
+ if (v != 9)
+ abort ();
+ #pragma omp atomic capture
+ v = x = x | 16;
+ if (v != 25)
+ abort ();
+ #pragma omp atomic capture
+ v = x = x + 14 * 2 / 4;
+ if (v != 32)
+ abort ();
+ #pragma omp atomic capture
+ v = x = 5 | x;
+ if (v != 37)
+ abort ();
+ #pragma omp atomic capture
+ v = x = 40 + 12 - 2 - 7 - x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = 3 + x; }
+ if (v != 6)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = -1 * -1 * -1 * -1 - x; }
+ if (v != 9)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != -8)
+ abort ();
+ #pragma omp atomic capture
+ { x = 2 * 2 - x; v = x; }
+ if (v != 12)
+ abort ();
+ #pragma omp atomic capture
+ { x = 7 & x; v = x; }
+ if (v != 4)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = 6; }
+ if (v != 4)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = 7 * 8 + 23; }
+ if (v != 6)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 79)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = 23 + 6 * 4; }
+ if (v != 79)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 47)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = l ? 17 : 12; }
+ if (v != 47)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = l = s++ + 3; }
+ if (v != 17 || l != 4 || s != 2)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 4)
+ abort ();
+ return 0;
+}
@@ -0,0 +1,108 @@
+// { dg-do run }
+
+extern "C" void abort (void);
+
+template <typename T>
+void
+foo ()
+{
+ extern T x;
+ T v, l = 2, s = 1;
+ #pragma omp atomic
+ x = -3 + x;
+ #pragma omp atomic read
+ v = x;
+ if (v != 3)
+ abort ();
+ #pragma omp atomic update
+ x = 3 * 2 * 1 + x;
+ #pragma omp atomic read
+ v = x;
+ if (v != 9)
+ abort ();
+ #pragma omp atomic capture
+ v = x = x | 16;
+ if (v != 25)
+ abort ();
+ #pragma omp atomic capture
+ v = x = x + 14 * 2 / 4;
+ if (v != 32)
+ abort ();
+ #pragma omp atomic capture
+ v = x = 5 | x;
+ if (v != 37)
+ abort ();
+ #pragma omp atomic capture
+ v = x = 40 + 12 - 2 - 7 - x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = 3 + x; }
+ if (v != 6)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = -1 * -1 * -1 * -1 - x; }
+ if (v != 9)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != -8)
+ abort ();
+ #pragma omp atomic capture
+ { x = 2 * 2 - x; v = x; }
+ if (v != 12)
+ abort ();
+ #pragma omp atomic capture
+ { x = 7 & x; v = x; }
+ if (v != 4)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = 6; }
+ if (v != 4)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = 7 * 8 + 23; }
+ if (v != 6)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 79)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = 23 + 6 * 4; }
+ if (v != 79)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 47)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = l ? 17 : 12; }
+ if (v != 47)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = l = s++ + 3; }
+ if (v != 17 || l != 4 || s != 2)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 4)
+ abort ();
+}
+
+int x = 6;
+
+int
+main ()
+{
+ foo <int> ();
+ return 0;
+}
@@ -0,0 +1,58 @@
+// { dg-do run }
+
+extern "C" void abort ();
+int x = 6, cnt;
+
+int
+foo ()
+{
+ return cnt++;
+}
+
+int
+main ()
+{
+ int v, *p;
+ p = &x;
+ #pragma omp atomic update
+ p[foo (), 0] = 16 + 6 - p[foo (), 0];
+ #pragma omp atomic read
+ v = x;
+ if (cnt != 2 || v != 16)
+ abort ();
+ #pragma omp atomic capture
+ v = p[foo () + foo (), 0] = p[foo () + foo (), 0] + 3;
+ if (cnt != 6 || v != 19)
+ abort ();
+ #pragma omp atomic capture
+ v = p[foo (), 0] = 12 * 1 / 2 + (foo (), 0) + p[foo (), 0];
+ if (cnt != 9 || v != 25)
+ abort ();
+ #pragma omp atomic capture
+ {
+ v = p[foo () & 0]; p[foo () & 0] = (foo (), 1) * 9 - p[foo () & 0];
+ }
+ if (cnt != 13 || v != 25)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != -16)
+ abort ();
+ #pragma omp atomic capture
+ {
+ p[0 & foo ()] = 16 - 2 + 3 + p[0 & foo ()]; v = p[0 & foo ()];
+ }
+ if (cnt != 16 || v != 1)
+ abort ();
+ #pragma omp atomic capture
+ {
+ v = p[foo (), 0]; p[foo (), 0] = (foo (), 7) ? 13 : foo () + 6;
+ }
+ if (cnt != 19 || v != 1)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 13)
+ abort ();
+ return 0;
+}
@@ -0,0 +1,68 @@
+// { dg-do run }
+
+extern "C" void abort ();
+int cnt;
+
+int
+foo ()
+{
+ return cnt++;
+}
+
+template <typename T>
+void
+bar ()
+{
+ extern T x;
+ T v, *p;
+ p = &x;
+ #pragma omp atomic update
+ p[foo (), 0] = 16 + 6 - p[foo (), 0];
+ #pragma omp atomic read
+ v = x;
+ if (cnt != 2 || v != 16)
+ abort ();
+ #pragma omp atomic capture
+ v = p[foo () + foo (), 0] = p[foo () + foo (), 0] + 3;
+ if (cnt != 6 || v != 19)
+ abort ();
+ #pragma omp atomic capture
+ v = p[foo (), 0] = 12 * 1 / 2 + (foo (), 0) + p[foo (), 0];
+ if (cnt != 9 || v != 25)
+ abort ();
+ #pragma omp atomic capture
+ {
+ v = p[foo () & 0]; p[foo () & 0] = (foo (), 1) * 9 - p[foo () & 0];
+ }
+ if (cnt != 13 || v != 25)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != -16)
+ abort ();
+ #pragma omp atomic capture
+ {
+ p[0 & foo ()] = 16 - 2 + 3 + p[0 & foo ()]; v = p[0 & foo ()];
+ }
+ if (cnt != 16 || v != 1)
+ abort ();
+ #pragma omp atomic capture
+ {
+ v = p[foo (), 0]; p[foo (), 0] = (foo (), 7) ? 13 : foo () + 6;
+ }
+ if (cnt != 19 || v != 1)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 13)
+ abort ();
+}
+
+int x = 6;
+
+int
+main ()
+{
+ bar <int> ();
+ return 0;
+}