Hi! This patch implements the remaining changes from in between 3.1 draft and 3.1 final, in the light of the http://www.openmp.org/forum/viewtopic.php?f=10&t=1199 clarification. #pragma omp atomic x = x + 6 + 2; is now allowed, as well as #pragma omp atomic capture { x = x | 7 + 1; v = x; } etc. In the C FE I had to change c_parser_binary_expression slightly, like I've changed cp_parser_binary_expression already a few years ago for OpenMP 3.0, because we don't want to parse #pragma omp atomic x = x * 6 + 2; as if it was x = x * (6 + 2);. Regtested on x86_64-linux, committed to gomp-3_1-branch.
2011-07-30 Jakub Jelinek <ja...@redhat.com> * c-common.h (c_finish_omp_atomic): Add rhs1 argument. * c-omp.c (c_finish_omp_atomic): Add rhs1 argument. If it has side-effects, evaluate those too in the right spot, if it is a decl and lhs is also a decl, error out if they aren't the same. Fix order of omit_two_operands_loc arguments. * c-parser.c (enum c_parser_prec): New enum, moved from within c_parser_binary_expression. (c_parser_binary_expression): Add PREC argument. Stop parsing if operator has lower or equal precedence than PREC. (c_parser_conditional_expression, c_parser_omp_for_loop): Adjust callers. (c_parser_omp_atomic): Parse x = x binop expr; stmts in #pragma omp atomic update and in #pragma omp atomic capture structured block forms. Adjust c_finish_omp_atomic caller. Fix up error handling in capture structured blocks. * cp-tree.h (finish_omp_atomic): Add rhs1 argument. * parser.c (cp_parser_omp_atomic): Parse x = x binop expr; stmts in #pragma omp atomic update and in #pragma omp atomic capture structured block forms. Adjust finish_omp_atomic caller. Fix up error handling in capture structured blocks. * pt.c (tsubst_expr) <case OMP_ATOMIC>: Find saved rhs1 value if any and pass it to finish_omp_atomic. * semantics.c (finish_omp_atomic): Add rhs1 argument. Adjust c_finish_omp_atomic caller and store rhs1 inside of OMP_ATOMIC arguments. * gcc.dg/gomp/atomic-5.c: Adjust expected diagnostics. * gcc.dg/gomp/atomic-15.c: New test. * g++.dg/gomp/atomic-5.C: Adjust expected diagnostics. * g++.dg/gomp/atomic-15.C: New test. * testsuite/libgomp.c/atomic-14.c: New test. * testsuite/libgomp.c++/atomic-8.C: New test. * testsuite/libgomp.c++/atomic-9.C: New test. --- gcc/c-family/c-common.h.jj 2011-07-11 17:33:51.000000000 +0200 +++ gcc/c-family/c-common.h 2011-07-30 15:00:38.000000000 +0200 @@ -1005,7 +1005,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); extern void c_finish_omp_flush (location_t); extern void c_finish_omp_taskwait (location_t); extern void c_finish_omp_taskyield (location_t); --- gcc/c-family/c-omp.c.jj 2011-07-11 19:57:49.000000000 +0200 +++ gcc/c-family/c-omp.c 2011-07-30 14:59:03.000000000 +0200 @@ -1,7 +1,8 @@ /* This file contains routines to construct GNU OpenMP constructs, called from parsing in the C and C++ front ends. - Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011 + Free Software Foundation, Inc. Contributed by Richard Henderson <r...@redhat.com>, Diego Novillo <dnovi...@redhat.com>. @@ -122,12 +123,13 @@ 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 v, tree lhs1, tree rhs1) { tree x, type, addr; if (lhs == error_mark_node || rhs == error_mark_node - || v == error_mark_node || lhs1 == error_mark_node) + || v == error_mark_node || lhs1 == error_mark_node + || rhs1 == error_mark_node) return error_mark_node; /* ??? According to one reading of the OpenMP spec, complex type are @@ -188,6 +190,20 @@ c_finish_omp_atomic (location_t loc, enu x = build2 (code, type, addr, rhs); SET_EXPR_LOCATION (x, loc); + /* Generally it is hard to prove lhs1 and lhs are the same memory + location, just diagnose different variables. */ + if (rhs1 + && TREE_CODE (rhs1) == VAR_DECL + && TREE_CODE (lhs) == VAR_DECL + && rhs1 != lhs) + { + if (code == OMP_ATOMIC) + error_at (loc, "%<#pragma omp atomic update%> uses two different variables for memory"); + else + error_at (loc, "%<#pragma omp atomic capture%> uses two different variables for memory"); + return error_mark_node; + } + if (code != OMP_ATOMIC) { /* Generally it is hard to prove lhs1 and lhs are the same memory @@ -202,6 +218,13 @@ c_finish_omp_atomic (location_t loc, enu } x = build_modify_expr (loc, v, NULL_TREE, NOP_EXPR, loc, x, NULL_TREE); + if (rhs1 && rhs1 != lhs) + { + tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, 0); + if (rhs1addr == error_mark_node) + return error_mark_node; + x = omit_one_operand_loc (loc, type, x, rhs1addr); + } if (lhs1 && lhs1 != lhs) { tree lhs1addr = build_unary_op (loc, ADDR_EXPR, lhs1, 0); @@ -212,10 +235,17 @@ c_finish_omp_atomic (location_t loc, enu else { x = save_expr (x); - x = omit_two_operands_loc (loc, type, x, lhs1addr, x); + x = omit_two_operands_loc (loc, type, x, x, lhs1addr); } } } + else if (rhs1 && rhs1 != lhs) + { + tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, 0); + if (rhs1addr == error_mark_node) + return error_mark_node; + x = omit_one_operand_loc (loc, type, x, rhs1addr); + } return x; } --- gcc/c-parser.c.jj 2011-07-12 13:10:57.000000000 +0200 +++ gcc/c-parser.c 2011-07-30 17:56:18.000000000 +0200 @@ -1090,6 +1090,23 @@ typedef enum c_dtr_syn { C_DTR_PARM } c_dtr_syn; +/* The binary operation precedence levels, where 0 is a dummy lowest level + used for the bottom of the stack. */ +enum c_parser_prec { + PREC_NONE, + PREC_LOGOR, + PREC_LOGAND, + PREC_BITOR, + PREC_BITXOR, + PREC_BITAND, + PREC_EQ, + PREC_REL, + PREC_SHIFT, + PREC_ADD, + PREC_MULT, + NUM_PRECS +}; + 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, @@ -1138,7 +1155,8 @@ static tree c_parser_asm_clobbers (c_par static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *); static struct c_expr c_parser_conditional_expression (c_parser *, struct c_expr *); -static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *); +static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *, + enum c_parser_prec); 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 *); @@ -5309,7 +5327,7 @@ c_parser_conditional_expression (c_parse gcc_assert (!after || c_dialect_objc ()); - cond = c_parser_binary_expression (parser, after); + cond = c_parser_binary_expression (parser, after, PREC_NONE); if (c_parser_next_token_is_not (parser, CPP_QUERY)) return cond; @@ -5394,7 +5412,8 @@ c_parser_conditional_expression (c_parse /* 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. + starting the expression as an initializer. PREC is the starting + precedence, usually PREC_NONE. multiplicative-expression: cast-expression @@ -5446,7 +5465,8 @@ c_parser_conditional_expression (c_parse */ static struct c_expr -c_parser_binary_expression (c_parser *parser, struct c_expr *after) +c_parser_binary_expression (c_parser *parser, struct c_expr *after, + enum c_parser_prec prec) { /* A binary expression is parsed using operator-precedence parsing, with the operands being cast expressions. All the binary @@ -5469,28 +5489,12 @@ c_parser_binary_expression (c_parser *pa expressions, we also need to adjust c_inhibit_evaluation_warnings as appropriate when the operators are pushed and popped. */ - /* The precedence levels, where 0 is a dummy lowest level used for - the bottom of the stack. */ - enum prec { - PREC_NONE, - PREC_LOGOR, - PREC_LOGAND, - PREC_BITOR, - PREC_BITXOR, - PREC_BITAND, - PREC_EQ, - PREC_REL, - PREC_SHIFT, - PREC_ADD, - PREC_MULT, - NUM_PRECS - }; struct { /* The expression at this stack level. */ struct c_expr expr; /* The precedence of the operator on its left, PREC_NONE at the bottom of the stack. */ - enum prec prec; + enum c_parser_prec prec; /* The operation on its left. */ enum tree_code op; /* The source location of this operation. */ @@ -5529,11 +5533,11 @@ c_parser_binary_expression (c_parser *pa 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_NONE; + stack[0].prec = prec; sp = 0; while (true) { - enum prec oprec; + enum c_parser_prec oprec; enum tree_code ocode; if (parser->error) goto out; @@ -5617,9 +5621,13 @@ c_parser_binary_expression (c_parser *pa goto out; } binary_loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); while (oprec <= stack[sp].prec) - POP; + { + if (sp == 0) + goto out; + POP; + } + c_parser_consume_token (parser); switch (ocode) { case TRUTH_ANDIF_EXPR: @@ -9135,6 +9143,9 @@ c_parser_omp_structured_block (c_parser 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 @@ -9142,7 +9153,7 @@ c_parser_omp_structured_block (c_parser write-stmt # pragma omp atomic update new-line - expression-stmt + update-stmt # pragma omp atomic capture new-line capture-stmt @@ -9154,10 +9165,12 @@ c_parser_omp_structured_block (c_parser 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; expression-stmt; } | { expression-stmt; v = x; } + { v = x; update-stmt; } | { update-stmt; v = x; } where x and v are lvalue expressions with scalar type. @@ -9166,7 +9179,8 @@ c_parser_omp_structured_block (c_parser static void c_parser_omp_atomic (location_t loc, c_parser *parser) { - tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, lhs1 = NULL_TREE; + 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; @@ -9250,6 +9264,17 @@ restart: 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: @@ -9347,19 +9372,85 @@ restart: opcode = BIT_XOR_EXPR; break; case CPP_EQ: - if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + if (structured_block || code == OMP_ATOMIC) { - code = OMP_ATOMIC_CAPTURE_OLD; - v = lhs; - lhs = NULL_TREE; + 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); - lhs1 = c_parser_unary_expression (parser).value; - lhs1 = c_fully_fold (lhs1, false, NULL); - if (lhs1 == error_mark_node) - goto saw_error; - if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + rhs1 = c_parser_unary_expression (parser).value; + rhs1 = c_fully_fold (rhs1, false, NULL); + if (rhs1 == error_mark_node) goto saw_error; - goto restart; + 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: @@ -9381,6 +9472,7 @@ restart: 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 %<;%>")) @@ -9402,7 +9494,7 @@ restart: c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"); } done: - stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1); + stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1); if (stmt != error_mark_node) add_stmt (stmt); @@ -9570,7 +9662,8 @@ c_parser_omp_for_loop (location_t loc, if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) { location_t cond_loc = c_parser_peek_token (parser)->location; - struct c_expr cond_expr = c_parser_binary_expression (parser, NULL); + struct c_expr cond_expr = c_parser_binary_expression (parser, NULL, + PREC_NONE); cond = cond_expr.value; cond = c_objc_common_truthvalue_conversion (cond_loc, cond); --- gcc/cp/cp-tree.h.jj 2011-07-29 18:34:03.000000000 +0200 +++ gcc/cp/cp-tree.h 2011-07-30 14:24:00.000000000 +0200 @@ -5449,7 +5449,7 @@ extern tree finish_omp_task (tree, tre extern tree finish_omp_for (location_t, tree, tree, tree, tree, tree, tree, tree); extern void finish_omp_atomic (enum tree_code, enum tree_code, - tree, tree, tree, tree); + tree, tree, tree, tree, tree); extern void finish_omp_barrier (void); extern void finish_omp_flush (void); extern void finish_omp_taskwait (void); --- gcc/cp/parser.c.jj 2011-07-12 13:48:18.000000000 +0200 +++ gcc/cp/parser.c 2011-07-30 17:32:34.000000000 +0200 @@ -24197,6 +24197,9 @@ cp_parser_omp_structured_block (cp_parse 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 @@ -24204,7 +24207,7 @@ cp_parser_omp_structured_block (cp_parse write-stmt # pragma omp atomic update new-line - expression-stmt + update-stmt # pragma omp atomic capture new-line capture-stmt @@ -24216,10 +24219,12 @@ cp_parser_omp_structured_block (cp_parse 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; expression-stmt; } | { expression-stmt; v = x; } + { v = x; update-stmt; } | { update-stmt; v = x; } where x and v are lvalue expressions with scalar type. */ @@ -24227,7 +24232,7 @@ static void cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) { tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, lhs1 = NULL_TREE; - tree orig_lhs; + tree rhs1 = NULL_TREE, orig_lhs; enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR; bool structured_block = false; @@ -24387,19 +24392,74 @@ restart: opcode = BIT_XOR_EXPR; break; case CPP_EQ: - if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + if (structured_block || code == OMP_ATOMIC) { - code = OMP_ATOMIC_CAPTURE_OLD; - v = lhs; - lhs = NULL_TREE; + enum cp_parser_prec oprec; + cp_token *token; cp_lexer_consume_token (parser->lexer); - lhs1 = cp_parser_unary_expression (parser, /*address_p=*/false, + rhs1 = cp_parser_unary_expression (parser, /*address_p=*/false, /*cast_p=*/false, NULL); - if (lhs1 == error_mark_node) + if (rhs1 == error_mark_node) goto saw_error; - if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + token = cp_lexer_peek_token (parser->lexer); + 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; + } + 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 restart; + goto stmt_done; } /* FALLTHROUGH */ default: @@ -24414,6 +24474,7 @@ restart: goto saw_error; break; } +stmt_done: if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) { if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) @@ -24435,13 +24496,24 @@ restart: cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); } done: - finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1); + finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1); if (!structured_block) cp_parser_consume_semicolon_at_end_of_statement (parser); return; saw_error: cp_parser_skip_to_end_of_block_or_statement (parser); + if (structured_block) + { + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)) + cp_lexer_consume_token (parser->lexer); + else if (code == OMP_ATOMIC_CAPTURE_NEW) + { + cp_parser_skip_to_end_of_block_or_statement (parser); + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)) + cp_lexer_consume_token (parser->lexer); + } + } } --- gcc/cp/pt.c.jj 2011-07-11 17:43:38.000000000 +0200 +++ gcc/cp/pt.c 2011-07-30 15:17:47.000000000 +0200 @@ -12525,15 +12525,23 @@ tsubst_expr (tree t, tree args, tsubst_f if (TREE_CODE (TREE_OPERAND (t, 1)) != MODIFY_EXPR) { tree op1 = TREE_OPERAND (t, 1); - tree lhs = RECUR (TREE_OPERAND (op1, 0)); - tree rhs = RECUR (TREE_OPERAND (op1, 1)); + tree rhs1 = NULL_TREE; + tree lhs, rhs; + if (TREE_CODE (op1) == COMPOUND_EXPR) + { + rhs1 = RECUR (TREE_OPERAND (op1, 0)); + op1 = TREE_OPERAND (op1, 1); + } + lhs = RECUR (TREE_OPERAND (op1, 0)); + rhs = RECUR (TREE_OPERAND (op1, 1)); finish_omp_atomic (OMP_ATOMIC, TREE_CODE (op1), lhs, rhs, - NULL_TREE, NULL_TREE); + NULL_TREE, NULL_TREE, rhs1); } else { tree op1 = TREE_OPERAND (t, 1); tree v = NULL_TREE, lhs, rhs = NULL_TREE, lhs1 = NULL_TREE; + tree rhs1 = NULL_TREE; enum tree_code code = TREE_CODE (TREE_OPERAND (op1, 1)); enum tree_code opcode = NOP_EXPR; if (code == OMP_ATOMIC_READ) @@ -12547,6 +12555,11 @@ tsubst_expr (tree t, tree args, tsubst_f tree op11 = TREE_OPERAND (TREE_OPERAND (op1, 1), 1); v = RECUR (TREE_OPERAND (op1, 0)); lhs1 = RECUR (TREE_OPERAND (TREE_OPERAND (op1, 1), 0)); + if (TREE_CODE (op11) == COMPOUND_EXPR) + { + rhs1 = RECUR (TREE_OPERAND (op11, 0)); + op11 = TREE_OPERAND (op11, 1); + } lhs = RECUR (TREE_OPERAND (op11, 0)); rhs = RECUR (TREE_OPERAND (op11, 1)); opcode = TREE_CODE (op11); @@ -12557,7 +12570,7 @@ tsubst_expr (tree t, tree args, tsubst_f lhs = RECUR (TREE_OPERAND (op1, 0)); rhs = RECUR (TREE_OPERAND (op1, 1)); } - finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1); + finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1); } break; --- gcc/cp/semantics.c.jj 2011-07-29 18:34:34.000000000 +0200 +++ gcc/cp/semantics.c 2011-07-30 15:05:41.000000000 +0200 @@ -4713,12 +4713,13 @@ finish_omp_for (location_t locus, tree d void finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, - tree rhs, tree v, tree lhs1) + tree rhs, tree v, tree lhs1, tree rhs1) { tree orig_lhs; tree orig_rhs; tree orig_v; tree orig_lhs1; + tree orig_rhs1; bool dependent_p; tree stmt; @@ -4726,6 +4727,7 @@ finish_omp_atomic (enum tree_code code, orig_rhs = rhs; orig_v = v; orig_lhs1 = lhs1; + orig_rhs1 = rhs1; dependent_p = false; stmt = NULL_TREE; @@ -4736,7 +4738,8 @@ finish_omp_atomic (enum tree_code code, dependent_p = (type_dependent_expression_p (lhs) || (rhs && type_dependent_expression_p (rhs)) || (v && type_dependent_expression_p (v)) - || (lhs1 && type_dependent_expression_p (lhs1))); + || (lhs1 && type_dependent_expression_p (lhs1)) + || (rhs1 && type_dependent_expression_p (rhs1))); if (!dependent_p) { lhs = build_non_dependent_expr (lhs); @@ -4746,12 +4749,14 @@ finish_omp_atomic (enum tree_code code, v = build_non_dependent_expr (v); if (lhs1) lhs1 = build_non_dependent_expr (lhs1); + if (rhs1) + rhs1 = build_non_dependent_expr (rhs1); } } if (!dependent_p) { stmt = c_finish_omp_atomic (input_location, code, opcode, lhs, rhs, - v, lhs1); + v, lhs1, rhs1); if (stmt == error_mark_node) return; } @@ -4768,6 +4773,8 @@ finish_omp_atomic (enum tree_code code, stmt = build2 (MODIFY_EXPR, void_type_node, orig_lhs, orig_rhs); else stmt = build2 (opcode, void_type_node, orig_lhs, orig_rhs); + if (orig_rhs1) + stmt = build_min_nt (COMPOUND_EXPR, orig_rhs1, stmt); if (code != OMP_ATOMIC) { stmt = build_min_nt (code, orig_lhs1, stmt); --- gcc/testsuite/gcc.dg/gomp/atomic-15.c.jj 2011-07-30 17:46:15.000000000 +0200 +++ gcc/testsuite/gcc.dg/gomp/atomic-15.c 2011-07-30 17:45:20.000000000 +0200 @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +int x = 6; + +int +main () +{ + int v; + #pragma omp atomic + x = x * 7 + 6; /* { dg-error "expected" } */ + #pragma omp atomic + x = x * 7 ^ 6; /* { dg-error "expected" } */ + #pragma omp atomic update + x = x - 8 + 6; /* { dg-error "expected" } */ + #pragma omp atomic + x = x ^ 7 | 2; /* { dg-error "expected" } */ + #pragma omp atomic + x = x / 7 * 2; /* { dg-error "expected" } */ + #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" } */ + #pragma omp atomic capture + { v = x; x = x - 8 + 6; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { v = x; x = x ^ 7 | 2; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { v = x; x = x / 7 * 2; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { v = x; x = x / 7 / 2; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { x = x * 7 + 6; v = x; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { x = x * 7 ^ 6; v = x; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { x = x - 8 + 6; v = x; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { x = x ^ 7 | 2; v = x; } /* { dg-error "expected" } */ + (void) v; + return 0; +} --- gcc/testsuite/gcc.dg/gomp/atomic-5.c.jj 2011-02-24 14:13:38.000000000 +0100 +++ gcc/testsuite/gcc.dg/gomp/atomic-5.c 2011-07-30 17:42:04.000000000 +0200 @@ -11,9 +11,9 @@ void f1(void) #pragma omp atomic x %= 2; /* { dg-error "invalid operator" } */ #pragma omp atomic - x = x + 1; /* { dg-error "invalid operator" } */ + x = x + 1; #pragma omp atomic - x = 1; /* { dg-error "invalid operator" } */ + x = 1; /* { dg-error "invalid form" } */ #pragma omp atomic ++y; /* { dg-error "read-only variable" } */ #pragma omp atomic --- gcc/testsuite/g++.dg/gomp/atomic-15.C.jj 2011-07-30 17:34:51.000000000 +0200 +++ gcc/testsuite/g++.dg/gomp/atomic-15.C 2011-07-30 17:33:18.000000000 +0200 @@ -0,0 +1,46 @@ +// { dg-do compile } +// { dg-options "-fopenmp" } + +int x = 6; + +int +main () +{ + int v; + #pragma omp atomic + x = x * 7 + 6; // { dg-error "expected" } + #pragma omp atomic + x = x * 7 ^ 6; // { dg-error "expected" } + #pragma omp atomic update + x = x - 8 + 6; // { dg-error "expected" } + #pragma omp atomic + x = x ^ 7 | 2; // { dg-error "expected" } + #pragma omp atomic + x = x / 7 * 2; // { dg-error "expected" } + #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" } + #pragma omp atomic capture + { v = x; x = x - 8 + 6; } // { dg-error "expected" } + #pragma omp atomic capture + { v = x; x = x ^ 7 | 2; } // { dg-error "expected" } + #pragma omp atomic capture + { v = x; x = x / 7 * 2; } // { dg-error "expected" } + #pragma omp atomic capture + { v = x; x = x / 7 / 2; } // { dg-error "expected" } + #pragma omp atomic capture + { x = x * 7 + 6; v = x; } // { dg-error "expected" } + #pragma omp atomic capture + { x = x * 7 ^ 6; v = x; } // { dg-error "expected" } + #pragma omp atomic capture + { x = x - 8 + 6; v = x; } // { dg-error "expected" } + #pragma omp atomic capture + { x = x ^ 7 | 2; v = x; } // { dg-error "expected" } + (void) v; + return 0; +} --- gcc/testsuite/g++.dg/gomp/atomic-5.C.jj 2011-02-24 14:16:31.000000000 +0100 +++ gcc/testsuite/g++.dg/gomp/atomic-5.C 2011-07-30 17:41:15.000000000 +0200 @@ -9,9 +9,9 @@ void f1(void) #pragma omp atomic x %= 2; /* { dg-error "invalid operator" } */ #pragma omp atomic - x = x + 1; /* { dg-error "invalid operator" } */ + x = x + 1; #pragma omp atomic - x = 1; /* { dg-error "invalid operator" } */ + x = 1; /* { dg-error "invalid form" } */ #pragma omp atomic ++y; /* { dg-error "read-only variable" } */ #pragma omp atomic --- libgomp/testsuite/libgomp.c/atomic-14.c.jj 2011-07-30 17:45:48.000000000 +0200 +++ libgomp/testsuite/libgomp.c/atomic-14.c 2011-07-30 17:44:08.000000000 +0200 @@ -0,0 +1,137 @@ +/* { dg-do run } */ + +extern void abort (void); +int x = 6, cnt; + +int +foo (void) +{ + return cnt++; +} + +int +main () +{ + int v, *p; + #pragma omp atomic update + x = x + 7; + #pragma omp atomic + x = x + 7 + 6; + #pragma omp atomic update + x = x + 2 * 3; + #pragma omp atomic + x = x * (2 - 1); + #pragma omp atomic read + v = x; + if (v != 32) + abort (); + #pragma omp atomic write + x = 0; + #pragma omp atomic capture + { + v = x; + x = x | 1 ^ 2; + } + if (v != 0) + abort (); + #pragma omp atomic capture + { + v = x; + x = x | 4 | 2; + } + if (v != 3) + abort (); + #pragma omp atomic read + v = x; + if (v != 7) + abort (); + #pragma omp atomic capture + { + x = x ^ 6 & 2; + v = x; + } + if (v != 5) + abort (); + #pragma omp atomic capture + { x = x - (6 + 4); v = x; } + if (v != -5) + abort (); + #pragma omp atomic capture + { v = x; x = x - (1 | 2); } + if (v != -5) + abort (); + #pragma omp atomic read + v = x; + if (v != -8) + abort (); + #pragma omp atomic + x = x * -4 / 2; + #pragma omp atomic read + v = x; + if (v != 16) + abort (); + p = &x; + #pragma omp atomic update + p[foo (), 0] = p[foo (), 0] - 16; + #pragma omp atomic read + v = x; + if (cnt != 2 || v != 0) + abort (); + #pragma omp atomic capture + { + p[foo (), 0] += 6; + v = p[foo (), 0]; + } + if (cnt != 4 || v != 6) + abort (); + #pragma omp atomic capture + { + v = p[foo (), 0]; + p[foo (), 0] += 6; + } + if (cnt != 6 || v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 12) + abort (); + #pragma omp atomic capture + { + p[foo (), 0] = p[foo (), 0] + 6; + v = p[foo (), 0]; + } + if (cnt != 9 || v != 18) + abort (); + #pragma omp atomic capture + { + v = p[foo (), 0]; + p[foo (), 0] = p[foo (), 0] + 6; + } + if (cnt != 12 || v != 18) + abort (); + #pragma omp atomic read + v = x; + if (v != 24) + abort (); + #pragma omp atomic capture + { v = p[foo (), 0]; p[foo (), 0]++; } + #pragma omp atomic capture + { v = p[foo (), 0]; ++p[foo (), 0]; } + #pragma omp atomic capture + { p[foo (), 0]++; v = p[foo (), 0]; } + #pragma omp atomic capture + { ++p[foo (), 0]; v = p[foo (), 0]; } + if (cnt != 20 || v != 28) + abort (); + #pragma omp atomic capture + { v = p[foo (), 0]; p[foo (), 0]--; } + #pragma omp atomic capture + { v = p[foo (), 0]; --p[foo (), 0]; } + #pragma omp atomic capture + { p[foo (), 0]--; v = p[foo (), 0]; } + #pragma omp atomic capture + { --p[foo (), 0]; v = p[foo (), 0]; } + if (cnt != 28 || v != 24) + abort (); + return 0; +} --- libgomp/testsuite/libgomp.c++/atomic-8.C.jj 2011-07-30 17:22:09.000000000 +0200 +++ libgomp/testsuite/libgomp.c++/atomic-8.C 2011-07-30 17:37:05.000000000 +0200 @@ -0,0 +1,137 @@ +// { dg-do run } + +extern "C" void abort (); +int x = 6, cnt; + +int +foo () +{ + return cnt++; +} + +int +main () +{ + int v, *p; + #pragma omp atomic update + x = x + 7; + #pragma omp atomic + x = x + 7 + 6; + #pragma omp atomic update + x = x + 2 * 3; + #pragma omp atomic + x = x * (2 - 1); + #pragma omp atomic read + v = x; + if (v != 32) + abort (); + #pragma omp atomic write + x = 0; + #pragma omp atomic capture + { + v = x; + x = x | 1 ^ 2; + } + if (v != 0) + abort (); + #pragma omp atomic capture + { + v = x; + x = x | 4 | 2; + } + if (v != 3) + abort (); + #pragma omp atomic read + v = x; + if (v != 7) + abort (); + #pragma omp atomic capture + { + x = x ^ 6 & 2; + v = x; + } + if (v != 5) + abort (); + #pragma omp atomic capture + { x = x - (6 + 4); v = x; } + if (v != -5) + abort (); + #pragma omp atomic capture + { v = x; x = x - (1 | 2); } + if (v != -5) + abort (); + #pragma omp atomic read + v = x; + if (v != -8) + abort (); + #pragma omp atomic + x = x * -4 / 2; + #pragma omp atomic read + v = x; + if (v != 16) + abort (); + p = &x; + #pragma omp atomic update + p[foo (), 0] = p[foo (), 0] - 16; + #pragma omp atomic read + v = x; + if (cnt != 2 || v != 0) + abort (); + #pragma omp atomic capture + { + p[foo (), 0] += 6; + v = p[foo (), 0]; + } + if (cnt != 4 || v != 6) + abort (); + #pragma omp atomic capture + { + v = p[foo (), 0]; + p[foo (), 0] += 6; + } + if (cnt != 6 || v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 12) + abort (); + #pragma omp atomic capture + { + p[foo (), 0] = p[foo (), 0] + 6; + v = p[foo (), 0]; + } + if (cnt != 9 || v != 18) + abort (); + #pragma omp atomic capture + { + v = p[foo (), 0]; + p[foo (), 0] = p[foo (), 0] + 6; + } + if (cnt != 12 || v != 18) + abort (); + #pragma omp atomic read + v = x; + if (v != 24) + abort (); + #pragma omp atomic capture + { v = p[foo (), 0]; p[foo (), 0]++; } + #pragma omp atomic capture + { v = p[foo (), 0]; ++p[foo (), 0]; } + #pragma omp atomic capture + { p[foo (), 0]++; v = p[foo (), 0]; } + #pragma omp atomic capture + { ++p[foo (), 0]; v = p[foo (), 0]; } + if (cnt != 20 || v != 28) + abort (); + #pragma omp atomic capture + { v = p[foo (), 0]; p[foo (), 0]--; } + #pragma omp atomic capture + { v = p[foo (), 0]; --p[foo (), 0]; } + #pragma omp atomic capture + { p[foo (), 0]--; v = p[foo (), 0]; } + #pragma omp atomic capture + { --p[foo (), 0]; v = p[foo (), 0]; } + if (cnt != 28 || v != 24) + abort (); + return 0; +} --- libgomp/testsuite/libgomp.c++/atomic-9.C.jj 2011-07-30 17:35:13.000000000 +0200 +++ libgomp/testsuite/libgomp.c++/atomic-9.C 2011-07-30 17:37:47.000000000 +0200 @@ -0,0 +1,148 @@ +// { dg-do run } + +extern "C" void abort (); + +int cnt; + +int +foo () +{ + return cnt++; +} + +template <typename T> +void +bar () +{ + extern T x; + T v, *p; + #pragma omp atomic update + x = x + 7; + #pragma omp atomic + x = x + 7 + 6; + #pragma omp atomic update + x = x + 2 * 3; + #pragma omp atomic + x = x * (2 - 1); + #pragma omp atomic read + v = x; + if (v != 32) + abort (); + #pragma omp atomic write + x = 0; + #pragma omp atomic capture + { + v = x; + x = x | 1 ^ 2; + } + if (v != 0) + abort (); + #pragma omp atomic capture + { + v = x; + x = x | 4 | 2; + } + if (v != 3) + abort (); + #pragma omp atomic read + v = x; + if (v != 7) + abort (); + #pragma omp atomic capture + { + x = x ^ 6 & 2; + v = x; + } + if (v != 5) + abort (); + #pragma omp atomic capture + { x = x - (6 + 4); v = x; } + if (v != -5) + abort (); + #pragma omp atomic capture + { v = x; x = x - (1 | 2); } + if (v != -5) + abort (); + #pragma omp atomic read + v = x; + if (v != -8) + abort (); + #pragma omp atomic + x = x * -4 / 2; + #pragma omp atomic read + v = x; + if (v != 16) + abort (); + p = &x; + #pragma omp atomic update + p[foo (), 0] = p[foo (), 0] - 16; + #pragma omp atomic read + v = x; + if (cnt != 2 || v != 0) + abort (); + #pragma omp atomic capture + { + p[foo (), 0] += 6; + v = p[foo (), 0]; + } + if (cnt != 4 || v != 6) + abort (); + #pragma omp atomic capture + { + v = p[foo (), 0]; + p[foo (), 0] += 6; + } + if (cnt != 6 || v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 12) + abort (); + #pragma omp atomic capture + { + p[foo (), 0] = p[foo (), 0] + 6; + v = p[foo (), 0]; + } + if (cnt != 9 || v != 18) + abort (); + #pragma omp atomic capture + { + v = p[foo (), 0]; + p[foo (), 0] = p[foo (), 0] + 6; + } + if (cnt != 12 || v != 18) + abort (); + #pragma omp atomic read + v = x; + if (v != 24) + abort (); + #pragma omp atomic capture + { v = p[foo (), 0]; p[foo (), 0]++; } + #pragma omp atomic capture + { v = p[foo (), 0]; ++p[foo (), 0]; } + #pragma omp atomic capture + { p[foo (), 0]++; v = p[foo (), 0]; } + #pragma omp atomic capture + { ++p[foo (), 0]; v = p[foo (), 0]; } + if (cnt != 20 || v != 28) + abort (); + #pragma omp atomic capture + { v = p[foo (), 0]; p[foo (), 0]--; } + #pragma omp atomic capture + { v = p[foo (), 0]; --p[foo (), 0]; } + #pragma omp atomic capture + { p[foo (), 0]--; v = p[foo (), 0]; } + #pragma omp atomic capture + { --p[foo (), 0]; v = p[foo (), 0]; } + if (cnt != 28 || v != 24) + abort (); +} + +int x = 6; + +int +main () +{ + bar <int> (); + return 0; +} Jakub