public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [gomp3.1] #pragma omp atomic updates and fixes
@ 2011-07-30 20:32 Jakub Jelinek
  0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2011-07-30 20:32 UTC (permalink / raw)
  To: gcc-patches

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  <jakub@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 <rth@redhat.com>,
 		  Diego Novillo <dnovillo@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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2011-07-30 16:44 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-30 20:32 [gomp3.1] #pragma omp atomic updates and fixes Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).