Patchwork [gomp4] Handle seq_cst clause on OpenMP atomics

login
register
mail settings
Submitter Jakub Jelinek
Date April 30, 2013, 4:10 p.m.
Message ID <20130430161042.GR28963@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/240658/
State New
Headers show

Comments

Jakub Jelinek - April 30, 2013, 4:10 p.m.
Hi!

Something I've missed in the latest draft, there can be seq_cst
clause to request sequentially atomic operation as opposed to relaxed.

Handled thusly:

2013-04-30  Jakub Jelinek  <jakub@redhat.com>

	* gimple-pretty-print.c (dump_gimple_omp_atomic_load,
	dump_gimple_omp_atomic_store): Handle gimple_omp_atomic_seq_cst_p.
	* gimple.h (enum gf_mask): Add GF_OMP_ATOMIC_SEQ_CST.
	(gimple_omp_atomic_set_seq_cst, gimple_omp_atomic_seq_cst_p): New
	inline functions.
	* omp-low.c (expand_omp_atomic_load, expand_omp_atomic_store,
	expand_omp_atomic_fetch_op): If gimple_omp_atomic_seq_cst_p,
	pass MEMMODEL_SEQ_CST instead of MEMMODEL_RELAXED to the builtin.
	* gimplify.c (gimplify_omp_atomic): Handle OMP_ATOMIC_SEQ_CST.
	* tree-pretty-print.c (dump_generic_node): Handle OMP_ATOMIC_SEQ_CST.
	* tree.def (OMP_ATOMIC): Add comment that OMP_ATOMIC* must stay
	consecutive.
	* tree.h (OMP_ATOMIC_SEQ_CST): Define.
c/
	* c-parser.c (c_parser_omp_atomic): Parse seq_cst clause, pass
	true if it is present to c_finish_omp_atomic.
cp/
	* pt.c (tsubst_expr): Pass OMP_ATOMIC_SEQ_CST to finish_omp_atomic.
	* semantics.c (finish_omp_atomic): Add seq_cst argument, pass
	it through to c_finish_omp_atomic or store into OMP_ATOMIC_SEQ_CST.
	* cp-tree.h (finish_omp_atomic): Adjust prototype.
	* parser.c (cp_parser_omp_atomic): Parse seq_cst clause, pass
	true if it is present to finish_omp_atomic.
c-family/
	* c-omp.c (c_finish_omp_atomic): Add seq_cst argument, store it
	into OMP_ATOMIC_SEQ_CST bit.
	* c-common.h (c_finish_omp_atomic): Adjust prototype.
testsuite/
	* testsuite/libgomp.c/atomic-17.c: New test.
	* testsuite/libgomp.c++/atomic-14.C: New test.
	* testsuite/libgomp.c++/atomic-15.C: New test.


	Jakub

Patch

--- gcc/gimple-pretty-print.c.jj	2013-03-27 13:01:09.000000000 +0100
+++ gcc/gimple-pretty-print.c	2013-04-30 17:34:10.663125084 +0200
@@ -1805,6 +1805,8 @@  dump_gimple_omp_atomic_load (pretty_prin
   else
     {
       pp_string (buffer, "#pragma omp atomic_load");
+      if (gimple_omp_atomic_seq_cst_p (gs))
+	pp_string (buffer, " seq_cst");
       if (gimple_omp_atomic_need_value_p (gs))
 	pp_string (buffer, " [needed]");
       newline_and_indent (buffer, spc + 2);
@@ -1835,6 +1837,8 @@  dump_gimple_omp_atomic_store (pretty_pri
   else
     {
       pp_string (buffer, "#pragma omp atomic_store ");
+      if (gimple_omp_atomic_seq_cst_p (gs))
+	pp_string (buffer, "seq_cst ");
       if (gimple_omp_atomic_need_value_p (gs))
 	pp_string (buffer, "[needed] ");
       pp_character (buffer, '(');
--- gcc/c/c-parser.c.jj	2013-04-24 18:22:37.000000000 +0200
+++ gcc/c/c-parser.c	2013-04-30 16:32:45.967276133 +0200
@@ -10218,10 +10218,23 @@  c_parser_omp_atomic (location_t loc, c_p
   location_t eloc;
   bool structured_block = false;
   bool swapped = false;
+  bool seq_cst = false;
 
   if (c_parser_next_token_is (parser, CPP_NAME))
     {
       const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (!strcmp (p, "seq_cst"))
+	{
+	  seq_cst = true;
+	  c_parser_consume_token (parser);
+	  if (c_parser_next_token_is (parser, CPP_COMMA)
+	      && c_parser_peek_2nd_token (parser)->type == CPP_NAME)
+	    c_parser_consume_token (parser);
+	}
+    }
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
 
       if (!strcmp (p, "read"))
 	code = OMP_ATOMIC_READ;
@@ -10236,6 +10249,23 @@  c_parser_omp_atomic (location_t loc, c_p
       if (p)
 	c_parser_consume_token (parser);
     }
+  if (!seq_cst)
+    {
+      if (c_parser_next_token_is (parser, CPP_COMMA)
+	  && c_parser_peek_2nd_token (parser)->type == CPP_NAME)
+	c_parser_consume_token (parser);
+
+      if (c_parser_next_token_is (parser, CPP_NAME))
+	{
+	  const char *p
+	    = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+	  if (!strcmp (p, "seq_cst"))
+	    {
+	      seq_cst = true;
+	      c_parser_consume_token (parser);
+	    }
+	}
+    }
   c_parser_skip_to_pragma_eol (parser);
 
   switch (code)
@@ -10526,7 +10556,7 @@  done:
     }
   else
     stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1,
-				swapped);
+				swapped, seq_cst);
   if (stmt != error_mark_node)
     add_stmt (stmt);
 
--- gcc/gimple.h.jj	2013-03-27 13:01:09.000000000 +0100
+++ gcc/gimple.h	2013-04-30 16:02:24.164400181 +0200
@@ -114,6 +114,7 @@  enum gf_mask {
 
     GF_OMP_SECTION_LAST		= 1 << 0,
     GF_OMP_ATOMIC_NEED_VALUE	= 1 << 0,
+    GF_OMP_ATOMIC_SEQ_CST	= 1 << 1,
     GF_PREDICT_TAKEN		= 1 << 15
 };
 
@@ -1727,6 +1728,29 @@  gimple_omp_atomic_set_need_value (gimple
 }
 
 
+/* Return true if OMP atomic load/store statement G has the
+   GF_OMP_ATOMIC_SEQ_CST flag set.  */
+
+static inline bool
+gimple_omp_atomic_seq_cst_p (const_gimple g)
+{
+  if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD)
+    GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE);
+  return (gimple_omp_subcode (g) & GF_OMP_ATOMIC_SEQ_CST) != 0;
+}
+
+
+/* Set the GF_OMP_ATOMIC_SEQ_CST flag on G.  */
+
+static inline void
+gimple_omp_atomic_set_seq_cst (gimple g)
+{
+  if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD)
+    GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE);
+  g->gsbase.subcode |= GF_OMP_ATOMIC_SEQ_CST;
+}
+
+
 /* Return the number of operands for statement GS.  */
 
 static inline unsigned
--- gcc/omp-low.c.jj	2013-04-30 10:26:40.000000000 +0200
+++ gcc/omp-low.c	2013-04-30 17:07:27.888328410 +0200
@@ -5472,7 +5472,10 @@  expand_omp_atomic_load (basic_block load
   itype = TREE_TYPE (TREE_TYPE (decl));
 
   call = build_call_expr_loc (loc, decl, 2, addr,
-			      build_int_cst (NULL, MEMMODEL_RELAXED));
+			      build_int_cst (NULL,
+					     gimple_omp_atomic_seq_cst_p (stmt)
+					     ? MEMMODEL_SEQ_CST
+					     : MEMMODEL_RELAXED));
   if (!useless_type_conversion_p (type, itype))
     call = fold_build1_loc (loc, VIEW_CONVERT_EXPR, type, call);
   call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call);
@@ -5544,7 +5547,10 @@  expand_omp_atomic_store (basic_block loa
   if (!useless_type_conversion_p (itype, type))
     stored_val = fold_build1_loc (loc, VIEW_CONVERT_EXPR, itype, stored_val);
   call = build_call_expr_loc (loc, decl, 3, addr, stored_val,
-			      build_int_cst (NULL, MEMMODEL_RELAXED));
+			      build_int_cst (NULL,
+					     gimple_omp_atomic_seq_cst_p (stmt)
+					     ? MEMMODEL_SEQ_CST
+					     : MEMMODEL_RELAXED));
   if (exchange)
     {
       if (!useless_type_conversion_p (type, itype))
@@ -5585,6 +5591,7 @@  expand_omp_atomic_fetch_op (basic_block
   enum tree_code code;
   bool need_old, need_new;
   enum machine_mode imode;
+  bool seq_cst;
 
   /* We expect to find the following sequences:
 
@@ -5610,6 +5617,7 @@  expand_omp_atomic_fetch_op (basic_block
     return false;
   need_new = gimple_omp_atomic_need_value_p (gsi_stmt (gsi));
   need_old = gimple_omp_atomic_need_value_p (last_stmt (load_bb));
+  seq_cst = gimple_omp_atomic_seq_cst_p (last_stmt (load_bb));
   gcc_checking_assert (!need_old || !need_new);
 
   if (!operand_equal_p (gimple_assign_lhs (stmt), stored_val, 0))
@@ -5676,7 +5684,9 @@  expand_omp_atomic_fetch_op (basic_block
      use the RELAXED memory model.  */
   call = build_call_expr_loc (loc, decl, 3, addr,
 			      fold_convert_loc (loc, itype, rhs),
-			      build_int_cst (NULL, MEMMODEL_RELAXED));
+			      build_int_cst (NULL,
+					     seq_cst ? MEMMODEL_SEQ_CST
+						     : MEMMODEL_RELAXED));
 
   if (need_old || need_new)
     {
--- gcc/gimplify.c.jj	2013-04-23 16:15:06.000000000 +0200
+++ gcc/gimplify.c	2013-04-30 17:20:19.404861154 +0200
@@ -7076,6 +7076,11 @@  gimplify_omp_atomic (tree *expr_p, gimpl
     rhs = tmp_load;
   storestmt = gimple_build_omp_atomic_store (rhs);
   gimplify_seq_add_stmt (pre_p, storestmt);
+  if (OMP_ATOMIC_SEQ_CST (*expr_p))
+    {
+      gimple_omp_atomic_set_seq_cst (loadstmt);
+      gimple_omp_atomic_set_seq_cst (storestmt);
+    }
   switch (TREE_CODE (*expr_p))
     {
     case OMP_ATOMIC_READ:
@@ -7092,7 +7097,7 @@  gimplify_omp_atomic (tree *expr_p, gimpl
       break;
     }
 
-   return GS_ALL_DONE;
+  return GS_ALL_DONE;
 }
 
 /* Gimplify a TRANSACTION_EXPR.  This involves gimplification of the
--- gcc/tree-pretty-print.c.jj	2013-03-27 13:01:09.000000000 +0100
+++ gcc/tree-pretty-print.c	2013-04-30 17:21:00.873622295 +0200
@@ -2431,6 +2431,8 @@  dump_generic_node (pretty_printer *buffe
 
     case OMP_ATOMIC:
       pp_string (buffer, "#pragma omp atomic");
+      if (OMP_ATOMIC_SEQ_CST (node))
+	pp_string (buffer, " seq_cst");
       newline_and_indent (buffer, spc + 2);
       dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
       pp_space (buffer);
@@ -2441,6 +2443,8 @@  dump_generic_node (pretty_printer *buffe
 
     case OMP_ATOMIC_READ:
       pp_string (buffer, "#pragma omp atomic read");
+      if (OMP_ATOMIC_SEQ_CST (node))
+	pp_string (buffer, " seq_cst");
       newline_and_indent (buffer, spc + 2);
       dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
       pp_space (buffer);
@@ -2449,6 +2453,8 @@  dump_generic_node (pretty_printer *buffe
     case OMP_ATOMIC_CAPTURE_OLD:
     case OMP_ATOMIC_CAPTURE_NEW:
       pp_string (buffer, "#pragma omp atomic capture");
+      if (OMP_ATOMIC_SEQ_CST (node))
+	pp_string (buffer, " seq_cst");
       newline_and_indent (buffer, spc + 2);
       dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
       pp_space (buffer);
--- gcc/cp/pt.c.jj	2013-03-27 13:01:09.000000000 +0100
+++ gcc/cp/pt.c	2013-04-30 16:23:59.019309306 +0200
@@ -13276,7 +13276,8 @@  tsubst_expr (tree t, tree args, tsubst_f
 	  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, rhs1);
+			     NULL_TREE, NULL_TREE, rhs1,
+			     OMP_ATOMIC_SEQ_CST (t));
 	}
       else
 	{
@@ -13313,7 +13314,8 @@  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, rhs1);
+	  finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1,
+			     OMP_ATOMIC_SEQ_CST (t));
 	}
       break;
 
--- gcc/cp/semantics.c.jj	2013-04-24 16:29:36.000000000 +0200
+++ gcc/cp/semantics.c	2013-04-30 16:22:36.365769312 +0200
@@ -5221,7 +5221,7 @@  finish_omp_for (location_t locus, enum t
 
 void
 finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs,
-		   tree rhs, tree v, tree lhs1, tree rhs1)
+		   tree rhs, tree v, tree lhs1, tree rhs1, bool seq_cst)
 {
   tree orig_lhs;
   tree orig_rhs;
@@ -5292,7 +5292,7 @@  finish_omp_atomic (enum tree_code code,
 	  return;
 	}
       stmt = c_finish_omp_atomic (input_location, code, opcode, lhs, rhs,
-				  v, lhs1, rhs1, swapped);
+				  v, lhs1, rhs1, swapped, seq_cst);
       if (stmt == error_mark_node)
 	return;
     }
@@ -5302,6 +5302,7 @@  finish_omp_atomic (enum tree_code code,
 	{
 	  stmt = build_min_nt_loc (EXPR_LOCATION (orig_lhs),
 				   OMP_ATOMIC_READ, orig_lhs);
+	  OMP_ATOMIC_SEQ_CST (stmt) = seq_cst;
 	  stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt);
 	}
       else
@@ -5317,10 +5318,12 @@  finish_omp_atomic (enum tree_code code,
 	    {
 	      stmt = build_min_nt_loc (EXPR_LOCATION (orig_lhs1),
 				       code, orig_lhs1, stmt);
+	      OMP_ATOMIC_SEQ_CST (stmt) = seq_cst;
 	      stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt);
 	    }
 	}
       stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node, stmt);
+      OMP_ATOMIC_SEQ_CST (stmt) = seq_cst;
     }
   add_stmt (stmt);
 }
--- gcc/cp/cp-tree.h.jj	2013-04-19 14:51:38.000000000 +0200
+++ gcc/cp/cp-tree.h	2013-04-30 16:20:00.938596128 +0200
@@ -5713,7 +5713,8 @@  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, tree,
+						 bool);
 extern void finish_omp_barrier			(void);
 extern void finish_omp_flush			(void);
 extern void finish_omp_taskwait			(void);
--- gcc/cp/parser.c.jj	2013-04-30 14:21:06.000000000 +0200
+++ gcc/cp/parser.c	2013-04-30 16:46:06.627751932 +0200
@@ -27197,12 +27197,27 @@  cp_parser_omp_atomic (cp_parser *parser,
   tree rhs1 = NULL_TREE, orig_lhs;
   enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR;
   bool structured_block = false;
+  bool seq_cst = false;
 
   if (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);
 
+      if (!strcmp (p, "seq_cst"))
+	{
+	  seq_cst = true;
+	  cp_lexer_consume_token (parser->lexer);
+	  if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
+	      && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME)
+	    cp_lexer_consume_token (parser->lexer);
+	}
+    }
+  if (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);
+
       if (!strcmp (p, "read"))
 	code = OMP_ATOMIC_READ;
       else if (!strcmp (p, "write"))
@@ -27216,6 +27231,24 @@  cp_parser_omp_atomic (cp_parser *parser,
       if (p)
 	cp_lexer_consume_token (parser->lexer);
     }
+  if (!seq_cst)
+    {
+      if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
+	  && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME)
+	cp_lexer_consume_token (parser->lexer);
+
+      if (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);
+
+	  if (!strcmp (p, "seq_cst"))
+	    {
+	      seq_cst = true;
+	      cp_lexer_consume_token (parser->lexer);
+	    }
+	}
+    }
   cp_parser_require_pragma_eol (parser, pragma_tok);
 
   switch (code)
@@ -27522,7 +27555,7 @@  stmt_done:
       cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
     }
 done:
-  finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1);
+  finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1, seq_cst);
   if (!structured_block)
     cp_parser_consume_semicolon_at_end_of_statement (parser);
   return;
--- gcc/tree.def.jj	2013-03-27 13:01:09.000000000 +0100
+++ gcc/tree.def	2013-04-30 16:00:03.603208178 +0200
@@ -1069,6 +1069,9 @@  DEFTREECODE (OMP_ORDERED, "omp_ordered",
    Operand 1: OMP_CRITICAL_NAME: Identifier for critical section.  */
 DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 2)
 
+/* OMP_ATOMIC through OMP_ATOMIC_CAPTURE_NEW must be consecutive,
+   or OMP_ATOMIC_SEQ_CST needs adjusting.  */
+
 /* OpenMP - #pragma omp atomic
    Operand 0: The address at which the atomic operation is to be performed.
 	This address should be stabilized with save_expr.
--- gcc/tree.h.jj	2013-04-19 14:51:38.000000000 +0200
+++ gcc/tree.h	2013-04-30 16:04:26.681692052 +0200
@@ -633,6 +633,9 @@  struct GTY(()) tree_base {
        OMP_PARALLEL_COMBINED in
            OMP_PARALLEL
 
+       OMP_ATOMIC_SEQ_CST in
+	   OMP_ATOMIC*
+
        OMP_CLAUSE_PRIVATE_OUTER_REF in
 	   OMP_CLAUSE_PRIVATE
 
@@ -1872,6 +1875,12 @@  extern void protected_set_expr_location
 #define OMP_PARALLEL_COMBINED(NODE) \
   (OMP_PARALLEL_CHECK (NODE)->base.private_flag)
 
+/* True if OMP_ATOMIC* is supposed to be sequentially consistent
+   as opposed to relaxed.  */
+#define OMP_ATOMIC_SEQ_CST(NODE) \
+  (TREE_RANGE_CHECK (NODE, OMP_ATOMIC, \
+		     OMP_ATOMIC_CAPTURE_NEW)->base.private_flag)
+
 /* True on a PRIVATE clause if its decl is kept around for debugging
    information only and its DECL_VALUE_EXPR is supposed to point
    to what it has been remapped to.  */
--- gcc/c-family/c-common.h.jj	2013-03-27 13:01:09.000000000 +0100
+++ gcc/c-family/c-common.h	2013-04-30 15:51:29.681164436 +0200
@@ -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, bool);
+				 tree, tree, tree, tree, tree, bool, 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);
--- gcc/c-family/c-omp.c.jj	2013-04-15 15:47:09.000000000 +0200
+++ gcc/c-family/c-omp.c	2013-04-30 16:18:03.588102175 +0200
@@ -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, bool swapped)
+		     tree v, tree lhs1, tree rhs1, bool swapped, bool seq_cst)
 {
   tree x, type, addr;
 
@@ -168,6 +168,7 @@  c_finish_omp_atomic (location_t loc, enu
     {
       x = build1 (OMP_ATOMIC_READ, type, addr);
       SET_EXPR_LOCATION (x, loc);
+      OMP_ATOMIC_SEQ_CST (x) = seq_cst;
       return build_modify_expr (loc, v, NULL_TREE, NOP_EXPR,
 				loc, x, NULL_TREE);
       return x;
@@ -192,6 +193,7 @@  c_finish_omp_atomic (location_t loc, enu
     type = void_type_node;
   x = build2 (code, type, addr, rhs);
   SET_EXPR_LOCATION (x, loc);
+  OMP_ATOMIC_SEQ_CST (x) = seq_cst;
 
   /* Generally it is hard to prove lhs1 and lhs are the same memory
      location, just diagnose different variables.  */
--- libgomp/testsuite/libgomp.c++/atomic-15.C.jj	2013-04-30 17:19:07.258282355 +0200
+++ libgomp/testsuite/libgomp.c++/atomic-15.C	2013-04-30 17:19:11.440254816 +0200
@@ -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 seq_cst
+    x = -3 + x;
+  #pragma omp atomic read seq_cst
+    v = x;
+  if (v != 3)
+    abort ();
+  #pragma omp atomic seq_cst update
+    x = 3 * 2 * 1 + x;
+  #pragma omp atomic read, seq_cst
+    v = x;
+  if (v != 9)
+    abort ();
+  #pragma omp atomic seq_cst, capture
+    v = x = x | 16;
+  if (v != 25)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    v = x = x + 14 * 2 / 4;
+  if (v != 32)
+    abort ();
+  #pragma omp atomic seq_cst capture
+    v = x = 5 | x;
+  if (v != 37)
+    abort ();
+  #pragma omp atomic capture, seq_cst
+    v = x = 40 + 12 - 2 - 7 - x;
+  if (v != 6)
+    abort ();
+  #pragma omp atomic seq_cst read
+    v = x;
+  if (v != 6)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    { v = x; x = 3 + x; }
+  if (v != 6)
+    abort ();
+  #pragma omp atomic seq_cst capture
+    { v = x; x = -1 * -1 * -1 * -1 - x; }
+  if (v != 9)
+    abort ();
+  #pragma omp atomic read seq_cst
+    v = x;
+  if (v != -8)
+    abort ();
+  #pragma omp atomic capture, seq_cst
+    { x = 2 * 2 - x; v = x; }
+  if (v != 12)
+    abort ();
+  #pragma omp atomic seq_cst capture
+    { x = 7 & x; v = x; }
+  if (v != 4)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    { v = x; x = 6; }
+  if (v != 4)
+    abort ();
+  #pragma omp atomic read, seq_cst
+    v = x;
+  if (v != 6)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    { v = x; x = 7 * 8 + 23; }
+  if (v != 6)
+    abort ();
+  #pragma omp atomic seq_cst, read
+    v = x;
+  if (v != 79)
+    abort ();
+  #pragma omp atomic capture , seq_cst
+    { v = x; x = 23 + 6 * 4; }
+  if (v != 79)
+    abort ();
+  #pragma omp atomic read seq_cst
+    v = x;
+  if (v != 47)
+    abort ();
+  #pragma omp atomic seq_cst capture
+    { v = x; x = l ? 17 : 12; }
+  if (v != 47)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    { v = x; x = l = s++ + 3; }
+  if (v != 17 || l != 4 || s != 2)
+    abort ();
+  #pragma omp atomic read seq_cst
+    v = x;
+  if (v != 4)
+    abort ();
+}
+
+int x = 6;
+
+int
+main ()
+{
+  foo <int> ();
+  return 0;
+}
--- libgomp/testsuite/libgomp.c++/atomic-14.C.jj	2013-04-30 17:16:39.941131218 +0200
+++ libgomp/testsuite/libgomp.c++/atomic-14.C	2013-04-30 17:16:48.615079902 +0200
@@ -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 seq_cst
+    x = -3 + x;
+  #pragma omp atomic read seq_cst
+    v = x;
+  if (v != 3)
+    abort ();
+  #pragma omp atomic seq_cst update
+    x = 3 * 2 * 1 + x;
+  #pragma omp atomic read, seq_cst
+    v = x;
+  if (v != 9)
+    abort ();
+  #pragma omp atomic seq_cst, capture
+    v = x = x | 16;
+  if (v != 25)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    v = x = x + 14 * 2 / 4;
+  if (v != 32)
+    abort ();
+  #pragma omp atomic seq_cst capture
+    v = x = 5 | x;
+  if (v != 37)
+    abort ();
+  #pragma omp atomic capture, seq_cst
+    v = x = 40 + 12 - 2 - 7 - x;
+  if (v != 6)
+    abort ();
+  #pragma omp atomic seq_cst read
+    v = x;
+  if (v != 6)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    { v = x; x = 3 + x; }
+  if (v != 6)
+    abort ();
+  #pragma omp atomic seq_cst capture
+    { v = x; x = -1 * -1 * -1 * -1 - x; }
+  if (v != 9)
+    abort ();
+  #pragma omp atomic read seq_cst
+    v = x;
+  if (v != -8)
+    abort ();
+  #pragma omp atomic capture, seq_cst
+    { x = 2 * 2 - x; v = x; }
+  if (v != 12)
+    abort ();
+  #pragma omp atomic seq_cst capture
+    { x = 7 & x; v = x; }
+  if (v != 4)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    { v = x; x = 6; }
+  if (v != 4)
+    abort ();
+  #pragma omp atomic read, seq_cst
+    v = x;
+  if (v != 6)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    { v = x; x = 7 * 8 + 23; }
+  if (v != 6)
+    abort ();
+  #pragma omp atomic seq_cst, read
+    v = x;
+  if (v != 79)
+    abort ();
+  #pragma omp atomic capture , seq_cst
+    { v = x; x = 23 + 6 * 4; }
+  if (v != 79)
+    abort ();
+  #pragma omp atomic read seq_cst
+    v = x;
+  if (v != 47)
+    abort ();
+  #pragma omp atomic seq_cst capture
+    { v = x; x = l ? 17 : 12; }
+  if (v != 47)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    { v = x; x = l = s++ + 3; }
+  if (v != 17 || l != 4 || s != 2)
+    abort ();
+  #pragma omp atomic read seq_cst
+    v = x;
+  if (v != 4)
+    abort ();
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/atomic-17.c.jj	2013-04-30 17:14:04.679028473 +0200
+++ libgomp/testsuite/libgomp.c/atomic-17.c	2013-04-30 17:16:00.834357522 +0200
@@ -0,0 +1,99 @@ 
+// { dg-do run }
+
+extern void abort (void);
+int x = 6;
+
+int
+main ()
+{
+  int v, l = 2, s = 1;
+  #pragma omp atomic seq_cst
+    x = -3 + x;
+  #pragma omp atomic read seq_cst
+    v = x;
+  if (v != 3)
+    abort ();
+  #pragma omp atomic seq_cst update
+    x = 3 * 2 * 1 + x;
+  #pragma omp atomic read, seq_cst
+    v = x;
+  if (v != 9)
+    abort ();
+  #pragma omp atomic seq_cst, capture
+    v = x = x | 16;
+  if (v != 25)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    v = x = x + 14 * 2 / 4;
+  if (v != 32)
+    abort ();
+  #pragma omp atomic seq_cst capture
+    v = x = 5 | x;
+  if (v != 37)
+    abort ();
+  #pragma omp atomic capture, seq_cst
+    v = x = 40 + 12 - 2 - 7 - x;
+  if (v != 6)
+    abort ();
+  #pragma omp atomic seq_cst read
+    v = x;
+  if (v != 6)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    { v = x; x = 3 + x; }
+  if (v != 6)
+    abort ();
+  #pragma omp atomic seq_cst capture
+    { v = x; x = -1 * -1 * -1 * -1 - x; }
+  if (v != 9)
+    abort ();
+  #pragma omp atomic read seq_cst
+    v = x;
+  if (v != -8)
+    abort ();
+  #pragma omp atomic capture, seq_cst
+    { x = 2 * 2 - x; v = x; }
+  if (v != 12)
+    abort ();
+  #pragma omp atomic seq_cst capture
+    { x = 7 & x; v = x; }
+  if (v != 4)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    { v = x; x = 6; }
+  if (v != 4)
+    abort ();
+  #pragma omp atomic read, seq_cst
+    v = x;
+  if (v != 6)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    { v = x; x = 7 * 8 + 23; }
+  if (v != 6)
+    abort ();
+  #pragma omp atomic seq_cst, read
+    v = x;
+  if (v != 79)
+    abort ();
+  #pragma omp atomic capture , seq_cst
+    { v = x; x = 23 + 6 * 4; }
+  if (v != 79)
+    abort ();
+  #pragma omp atomic read seq_cst
+    v = x;
+  if (v != 47)
+    abort ();
+  #pragma omp atomic seq_cst capture
+    { v = x; x = l ? 17 : 12; }
+  if (v != 47)
+    abort ();
+  #pragma omp atomic capture seq_cst
+    { v = x; x = l = s++ + 3; }
+  if (v != 17 || l != 4 || s != 2)
+    abort ();
+  #pragma omp atomic read seq_cst
+    v = x;
+  if (v != 4)
+    abort ();
+  return 0;
+}