This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gomp] atomic operations, revision 3


Fixes some arithmetic errors due to improperly short-cutting
expression evaluation.  We now go through the normal expression
generator, and then try to work out what happened afterward.

The atomic operation expansion is now done in the gimplifier
so that multiple languages can take advantage of the logic.
It's too bad I hadn't done this before Jakub did all that work
in the Fortran front end...


r~


        * Makefile.in (c-omp.o): Remove C_TREE_H.
        * c-tree.h (build_indirect_ref, build_modify_expr): Move ...
        * c-common.h: ... here.
        * c-omp.c: Don't include c-tree.h.
        (c_finish_omp_atomic): Create an OMP_ATOMIC node.
        * gimplify.c (goa_lhs_expr_p, gimplify_omp_atomic_fetch_op,
        goa_stabilize_expr, gimplify_omp_atomic_pipeline): New.
        (gimplify_omp_atomic): New.
        (gimplify_expr): Call it.
        * tree-pretty-print.c (dump_generic_node): Handle OMP_ATOMIC.
        * tree.def (OMP_ATOMIC): New.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1501.4.10
diff -u -p -d -r1.1501.4.10 Makefile.in
--- Makefile.in	23 Sep 2005 23:02:05 -0000	1.1501.4.10
+++ Makefile.in	24 Sep 2005 22:50:37 -0000
@@ -1580,7 +1580,7 @@ c-pch.o : c-pch.c $(CONFIG_H) $(SYSTEM_H
 	  $< $(OUTPUT_OPTION)
 
 c-omp.o : c-omp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
-	$(FUNCTION_H) $(C_COMMON_H) toplev.h $(TREE_GIMPLE_H) $(C_TREE_H)
+	$(FUNCTION_H) $(C_COMMON_H) toplev.h $(TREE_GIMPLE_H)
 
 # Language-independent files.
 
Index: c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.294.4.5
diff -u -p -d -r1.294.4.5 c-common.h
--- c-common.h	23 Sep 2005 15:46:16 -0000	1.294.4.5
+++ c-common.h	24 Sep 2005 22:50:37 -0000
@@ -297,6 +297,8 @@ extern tree add_stmt (tree);
 extern void push_cleanup (tree, tree, bool);
 extern tree pushdecl_top_level (tree);
 extern tree pushdecl (tree);
+extern tree build_modify_expr (tree, enum tree_code, tree);
+extern tree build_indirect_ref (tree, const char *);
 
 extern int c_expand_decl (tree);
 
Index: c-omp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/c-omp.c,v
retrieving revision 1.1.2.5
diff -u -p -d -r1.1.2.5 c-omp.c
--- c-omp.c	23 Sep 2005 20:44:38 -0000	1.1.2.5
+++ c-omp.c	24 Sep 2005 22:50:37 -0000
@@ -29,7 +29,6 @@ Software Foundation, 51 Franklin Street,
 #include "tree.h"
 #include "function.h"
 #include "c-common.h"
-#include "c-tree.h"
 #include "toplev.h"
 #include "tree-gimple.h"
 
@@ -102,169 +101,45 @@ c_finish_omp_barrier (void)
 void
 c_finish_omp_atomic (enum tree_code code, tree lhs, tree rhs)
 {
-  tree decl, x, y;
-  tree oldval, newval, rhsval, lhsaddr, type, label;
-  tree itype, oldival, newival, lhsiaddr;
+  tree x, type, addr;
 
   if (lhs == error_mark_node || rhs == error_mark_node)
     return;
 
-  type = TYPE_MAIN_VARIANT (TREE_TYPE (lhs));
-
-  /* We want rhs converted into a type compatible with lhs, without the
-     default promotions that would happen for normal arithmetic.  The
-     easiest way to do this is to build a dummy assignment expression
-     and then extract the components.  Except that that doesn't work for
-     pointer types, so we have to handle that by hand.  */
-  if (POINTER_TYPE_P (type))
-    {
-      if ((code != PLUS_EXPR && code != MINUS_EXPR)
-	  || !INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
-	{
-	  binary_op_error (code);
-	  return;
-	}
-
-      x = pointer_int_sum (code, lhs, rhs);
-      /* Stupid NON_LVALUE_EXPR... */
-      STRIP_TYPE_NOPS (x);
-      /* Be careful: pointer_int_sum calls fold.  Here we hope it can't
-	 do too much besides simplify to no operation.  */
-      if (x == lhs)
-	return;
-      gcc_assert (TREE_CODE (x) == code);
-      gcc_assert (TREE_OPERAND (x, 0) == lhs);
-      rhs = TREE_OPERAND (x, 1);
-    }
-  else if (INTEGRAL_TYPE_P (type) || SCALAR_FLOAT_TYPE_P (type))
-    {
-      x = build_modify_expr (lhs, NOP_EXPR, rhs);
-      if (x == error_mark_node)
-	return;
-      gcc_assert (TREE_CODE (x) == MODIFY_EXPR);  
-      lhs = TREE_OPERAND (x, 0);
-      rhs = TREE_OPERAND (x, 1);
-    }
-  else
+  /* ??? According to one reading of the OpenMP spec, complex type are
+     supported, but there are no atomic stores for any architecture.
+     But at least icc 9.0 doesn't support complex types here either.
+     And lets not even talk about vector types...  */
+  type = TREE_TYPE (lhs);
+  if (!INTEGRAL_TYPE_P (type)
+      && !POINTER_TYPE_P (type)
+      && !SCALAR_FLOAT_TYPE_P (type))
     {
       error ("invalid expression type for %<#pragma omp atomic%>");
       return;
     }
 
-  lhsaddr = build_unary_op (ADDR_EXPR, lhs, 0);
-  if (lhsaddr == error_mark_node)
-    return;
-
-  /* When possible, use specialized atomic update functions.  */
-  if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
-    switch (code)
-      {
-      case PLUS_EXPR:
-	decl = built_in_decls[BUILT_IN_FETCH_AND_ADD_N];
-	goto do_fetch_op;
-      case MINUS_EXPR:
-	decl = built_in_decls[BUILT_IN_FETCH_AND_SUB_N];
-	goto do_fetch_op;
-      case BIT_AND_EXPR:
-	decl = built_in_decls[BUILT_IN_FETCH_AND_AND_N];
-	goto do_fetch_op;
-      case BIT_IOR_EXPR:
-	decl = built_in_decls[BUILT_IN_FETCH_AND_OR_N];
-	goto do_fetch_op;
-      case BIT_XOR_EXPR:
-	decl = built_in_decls[BUILT_IN_FETCH_AND_XOR_N];
-	goto do_fetch_op;
-
-      do_fetch_op:
-	y = tree_cons (NULL, rhs, NULL);
-	y = tree_cons (NULL, lhsaddr, y);
-	x = resolve_overloaded_builtin (decl, y);
-	add_stmt (x);
-	return;
-
-      default:
-	break;
-      }
-
-  /* In these cases, we don't have specialized __sync builtins,
-     so we need to implement a compare and swap loop.  */
-
-  itype = NULL;
-  if (SCALAR_FLOAT_TYPE_P (type))
-    {
-      if (TYPE_PRECISION (type) == 32 || TYPE_PRECISION (type) == 64)
-	itype = c_common_type_for_size (TYPE_PRECISION (type), true);
-      else
-	{
-	  sorry ("unsupported expression type for %<#pragma omp atomic%>");
-	  return;
-	}
-    }
-
-  oldival = oldval = pushdecl (create_tmp_var_raw (type, NULL));
-  newival = newval = pushdecl (create_tmp_var_raw (type, NULL));
-  lhsiaddr = lhsaddr = save_expr (lhsaddr);
-  if (itype)
-    {
-      oldival = pushdecl (create_tmp_var_raw (itype, NULL));
-      newival = pushdecl (create_tmp_var_raw (itype, NULL));
-      lhsiaddr = fold_convert (build_pointer_type (itype), lhsaddr);
-    }
-  rhsval = pushdecl (create_tmp_var_raw (type, NULL));
-  label = create_artificial_label ();
-
-  x = build_fold_indirect_ref (lhsaddr);
-  x = build2 (MODIFY_EXPR, void_type_node, oldval, x);
-  add_stmt (x);
-
-  if (itype)
-    {
-      x = build1 (VIEW_CONVERT_EXPR, itype, oldval);
-      x = build2 (MODIFY_EXPR, void_type_node, oldival, x);
-      add_stmt (x);
-    }
-
-  if (TREE_CONSTANT (rhs))
-    rhsval = rhs;
-  else
-    {
-      x = build2 (MODIFY_EXPR, void_type_node, rhsval, rhs);
-      add_stmt (x);
-    }
-
-  add_stmt (build_stmt (LABEL_EXPR, label));
-
-  x = build_binary_op (code, oldval, rhsval, false);
-  x = build2 (MODIFY_EXPR, void_type_node, newval, x);
-  add_stmt (x);
-
-  if (itype)
-    {
-      x = build1 (VIEW_CONVERT_EXPR, itype, newval);
-      x = build2 (MODIFY_EXPR, void_type_node, newival, x);
-      add_stmt (x);
-    }
+  /* ??? Validate that rhs does not overlap lhs.  */
 
-  y = tree_cons (NULL, newival, NULL);
-  y = tree_cons (NULL, oldival, y);
-  y = tree_cons (NULL, lhsiaddr, y);
-  decl = built_in_decls[BUILT_IN_VAL_COMPARE_AND_SWAP_N];
-  x = resolve_overloaded_builtin (decl, y);
-  x = build2 (MODIFY_EXPR, void_type_node, oldival, x);
-  add_stmt (x);
+  /* Take and save the address of the lhs.  From then on we'll reference it
+     via indirection.  */
+  addr = build_unary_op (ADDR_EXPR, lhs, 0);
+  if (addr == error_mark_node)
+    return;
+  addr = save_expr (addr);
+  lhs = build_indirect_ref (addr, NULL);
 
-  if (itype)
-    {
-      x = build1 (VIEW_CONVERT_EXPR, type, oldival);
-      x = build2 (MODIFY_EXPR, void_type_node, oldval, x);
-      add_stmt (x);
-    }
+  /* There are lots of warnings, errors, and conversions that need to happen
+     in the course of interpreting a statement.  Use the normal mechanisms
+     to do this, and then take it apart again.  */
+  x = build_modify_expr (lhs, code, rhs);
+  if (x == error_mark_node)
+    return;
+  gcc_assert (TREE_CODE (x) == MODIFY_EXPR);  
+  rhs = TREE_OPERAND (x, 1);
 
-  x = build2 (NE_EXPR, boolean_type_node, oldival, newival);
-  y = build1 (GOTO_EXPR, void_type_node, label);
-  x = build3 (COND_EXPR, void_type_node, x, y, NULL);
-  add_stmt (x);
-  return;
+  /* Punt the actual generation of atomic operations to common code.  */
+  add_stmt (build2 (OMP_ATOMIC, void_type_node, addr, rhs));
 }
 
 
Index: c-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-tree.h,v
retrieving revision 1.203.4.6
diff -u -p -d -r1.203.4.6 c-tree.h
--- c-tree.h	23 Sep 2005 15:46:17 -0000	1.203.4.6
+++ c-tree.h	24 Sep 2005 22:50:38 -0000
@@ -525,7 +525,6 @@ extern tree default_conversion (tree);
 extern struct c_expr default_function_array_conversion (struct c_expr);
 extern tree composite_type (tree, tree);
 extern tree build_component_ref (tree, tree);
-extern tree build_indirect_ref (tree, const char *);
 extern tree build_array_ref (tree, tree);
 extern tree build_external_ref (tree, int, location_t);
 extern void pop_maybe_used (bool);
@@ -538,7 +537,6 @@ extern tree build_conditional_expr (tree
 extern tree build_compound_expr (tree, tree);
 extern tree c_cast_expr (struct c_type_name *, tree);
 extern tree build_c_cast (tree, tree);
-extern tree build_modify_expr (tree, enum tree_code, tree);
 extern void store_init_value (tree, tree);
 extern void error_init (const char *);
 extern void pedwarn_init (const char *);
Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.135.4.13
diff -u -p -d -r2.135.4.13 gimplify.c
--- gimplify.c	24 Sep 2005 17:07:27 -0000	2.135.4.13
+++ gimplify.c	24 Sep 2005 22:50:39 -0000
@@ -4010,6 +4010,256 @@ gimplify_omp_critical (tree *expr_p, tre
   return GS_OK;
 }
 
+/* A subroutine of gimplify_omp_atomic.  The front end is supposed to have
+   stabilized the lhs of the atomic operation as *ADDR.  Return true if 
+   EXPR is this stabilized form.  */
+
+static bool
+goa_lhs_expr_p (tree expr, tree addr)
+{
+  /* Also include casts to other type variants.  The C front end is fond
+     of adding these for e.g. volatile variables.  This is like 
+     STRIP_TYPE_NOPS but includes the main variant lookup.  */
+  while ((TREE_CODE (expr) == NOP_EXPR
+          || TREE_CODE (expr) == CONVERT_EXPR
+          || TREE_CODE (expr) == NON_LVALUE_EXPR)
+         && TREE_OPERAND (expr, 0) != error_mark_node
+         && (TYPE_MAIN_VARIANT (TREE_TYPE (expr))
+             == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (expr, 0)))))
+    expr = TREE_OPERAND (expr, 0);
+
+  if (TREE_CODE (expr) == INDIRECT_REF && TREE_OPERAND (expr, 0) == addr)
+    return true;
+  if (TREE_CODE (addr) == ADDR_EXPR && expr == TREE_OPERAND (addr, 0))
+    return true;
+  return false;
+}
+
+/* A subroutine of gimplify_omp_atomic.  Attempt to implement the atomic
+   operation as a __sync_fetch_and_op builtin.  INDEX is log2 of the
+   size of the data type, and thus usable to find the index of the builtin
+   decl.  Returns GS_UNHANDLED if the expression is not of the proper form.  */
+
+static enum gimplify_status
+gimplify_omp_atomic_fetch_op (tree *expr_p, tree addr, tree rhs, int index)
+{
+  enum built_in_function base;
+  tree decl, args, itype;
+
+  /* Check for one of the supported fetch-op operations.  */
+  switch (TREE_CODE (rhs))
+    {
+    case PLUS_EXPR:
+      base = BUILT_IN_FETCH_AND_ADD_N;
+      break;
+    case MINUS_EXPR:
+      base = BUILT_IN_FETCH_AND_SUB_N;
+      break;
+    case BIT_AND_EXPR:
+      base = BUILT_IN_FETCH_AND_AND_N;
+      break;
+    case BIT_IOR_EXPR:
+      base = BUILT_IN_FETCH_AND_OR_N;
+      break;
+    case BIT_XOR_EXPR:
+      base = BUILT_IN_FETCH_AND_XOR_N;
+      break;
+    default:
+      return GS_UNHANDLED;
+    }
+
+  /* Make sure the expression is of the proper form.  */
+  if (goa_lhs_expr_p (TREE_OPERAND (rhs, 0), addr))
+    rhs = TREE_OPERAND (rhs, 1);
+  else if (commutative_tree_code (TREE_CODE (rhs))
+	   && goa_lhs_expr_p (TREE_OPERAND (rhs, 1), addr))
+    rhs = TREE_OPERAND (rhs, 0);
+  else
+    return GS_UNHANDLED;
+
+  decl = built_in_decls[base + index + 1];
+  itype = TREE_TYPE (TREE_TYPE (decl));
+
+  args = tree_cons (NULL, fold_convert (itype, rhs), NULL);
+  args = tree_cons (NULL, addr, args);
+  *expr_p = build_function_call_expr (decl, args);
+  return GS_OK;
+}
+
+/* A subroutine of gimplify_omp_atomic_pipeline.  Walk *EXPR_P and replace
+   appearences of *LHS_ADDR with LHS_VAR.  If an expression does not involve
+   the lhs, evaluate it into a temporary.  Return 1 if the lhs appeared as
+   a subexpression, 0 if it did not, or -1 if an error was encountered.  */
+
+static int
+goa_stabilize_expr (tree *expr_p, tree *pre_p, tree lhs_addr, tree lhs_var)
+{
+  tree expr = *expr_p;
+  int saw_lhs;
+
+  if (goa_lhs_expr_p (expr, lhs_addr))
+    {
+      *expr_p = lhs_var;
+      return 1;
+    }
+  if (is_gimple_val (expr))
+    return 0;
+ 
+  saw_lhs = 0;
+  switch (TREE_CODE_CLASS (TREE_CODE (expr)))
+    {
+    case tcc_binary:
+      saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p,
+				     lhs_addr, lhs_var);
+    case tcc_unary:
+      saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p,
+				     lhs_addr, lhs_var);
+      break;
+    default:
+      break;
+    }
+
+  if (saw_lhs == 0)
+    {
+      enum gimplify_status gs;
+      gs = gimplify_expr (expr_p, pre_p, NULL, is_gimple_val, fb_rvalue);
+      if (gs != GS_ALL_DONE)
+	saw_lhs = -1;
+    }
+
+  return saw_lhs;
+}
+
+/* A subroutine of gimplify_omp_atomic.  Implement the atomic operation as:
+
+	oldval = *addr;
+      repeat:
+	newval = rhs;	// with oldval replacing *addr in rhs
+	oldval = __sync_val_compare_and_swap (addr, oldval, newval);
+	if (oldval != newval)
+	  goto repeat;
+
+   INDEX is log2 of the size of the data type, and thus usable to find the
+   index of the builtin decl.  */
+
+static enum gimplify_status
+gimplify_omp_atomic_pipeline (tree *expr_p, tree *pre_p, tree addr,
+			      tree rhs, int index)
+{
+  tree oldval, oldival, newval, newival, label;
+  tree type, itype, cmpxchg, args, x;
+
+  cmpxchg = built_in_decls[BUILT_IN_VAL_COMPARE_AND_SWAP_N + index + 1];
+  type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
+  itype = TREE_TYPE (TREE_TYPE (cmpxchg));
+
+  oldval = create_tmp_var (type, NULL);
+  newval = create_tmp_var (type, NULL);
+
+  /* Precompute as much of RHS as possible.  In the same walk, replace
+     occurrences of the lhs value with our temporary.  */
+  if (goa_stabilize_expr (&rhs, pre_p, addr, oldval) < 0)
+    return GS_ERROR;
+
+  x = build_fold_indirect_ref (addr);
+  x = build2 (MODIFY_EXPR, void_type_node, oldval, x);
+  gimplify_and_add (x, pre_p);
+
+  /* For floating-point values, we'll need to view-convert them to integers
+     so that we can perform the atomic compare and swap.  Simplify the 
+     following code by always setting up the "i"ntegral variables.  */
+  if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
+    {
+      oldival = oldval;
+      newival = newval;
+    }
+  else
+    {
+      oldival = create_tmp_var (itype, NULL);
+      newival = create_tmp_var (itype, NULL);
+
+      x = build1 (VIEW_CONVERT_EXPR, itype, oldval);
+      x = build2 (MODIFY_EXPR, void_type_node, oldival, x);
+      gimplify_and_add (x, pre_p);
+    }
+
+  label = create_artificial_label ();
+  x = build1 (LABEL_EXPR, void_type_node, label);
+  gimplify_and_add (x, pre_p);
+
+  x = build2 (MODIFY_EXPR, void_type_node, newval, rhs);
+  gimplify_and_add (x, pre_p);
+
+  if (newval != newival)
+    {
+      x = build1 (VIEW_CONVERT_EXPR, itype, newval);
+      x = build2 (MODIFY_EXPR, void_type_node, newival, x);
+      gimplify_and_add (x, pre_p);
+    }
+
+  args = tree_cons (NULL, fold_convert (itype, newival), NULL);
+  args = tree_cons (NULL, fold_convert (itype, oldival), args);
+  args = tree_cons (NULL, addr, args);
+  x = build_function_call_expr (cmpxchg, args);
+  if (oldval == oldival)
+    x = fold_convert (type, x);
+  x = build2 (MODIFY_EXPR, void_type_node, oldival, x);
+  gimplify_and_add (x, pre_p);
+
+  /* For floating point, be prepared for the loop backedge.  */
+  if (oldval != oldival)
+    {
+      x = build1 (VIEW_CONVERT_EXPR, type, oldival);
+      x = build2 (MODIFY_EXPR, void_type_node, oldval, x);
+      gimplify_and_add (x, pre_p);
+    }
+
+  /* Note that we always perform the comparison as an integer, even for
+     floating point.  This allows the atomic operation to properly 
+     succeed even with NaNs and -0.0.  */
+  x = build3 (COND_EXPR, void_type_node,
+	      build2 (NE_EXPR, boolean_type_node, oldival, newival),
+	      build1 (GOTO_EXPR, void_type_node, label), NULL);
+  gimplify_and_add (x, pre_p);
+
+  *expr_p = NULL;
+  return GS_ALL_DONE;
+}
+
+/* Gimplify an OMP_ATOMIC statement.  */
+
+static enum gimplify_status
+gimplify_omp_atomic (tree *expr_p, tree *pre_p)
+{
+  tree addr = TREE_OPERAND (*expr_p, 0);
+  tree rhs = TREE_OPERAND (*expr_p, 1);
+  tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
+  HOST_WIDE_INT index;
+
+  /* Make sure the type is one of the supported sizes.  */
+  index = tree_low_cst (TYPE_SIZE_UNIT (type), 1);
+  index = exact_log2 (index);
+  if (index < 0 || index > 3)
+    {
+      sorry ("unsupported expression type for openmp atomic");
+      return GS_ERROR;
+    }
+
+  /* When possible, use specialized atomic update functions.  */
+  if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
+    {
+      enum gimplify_status gs;
+      gs = gimplify_omp_atomic_fetch_op (expr_p, addr, rhs, index);
+      if (gs != GS_UNHANDLED)
+	return gs;
+    }
+
+  /* In these cases, we don't have specialized __sync builtins,
+     so we need to implement a compare and swap loop.  */
+  return gimplify_omp_atomic_pipeline (expr_p, pre_p, addr, rhs, index);
+}
+
+
 /*  Gimplifies the expression tree pointed to by EXPR_P.  Return 0 if
     gimplification failed.
 
@@ -4463,6 +4713,10 @@ gimplify_expr (tree *expr_p, tree *pre_p
 	  ret = gimplify_omp_critical (expr_p, pre_p, post_p);
 	  break;
 
+	case OMP_ATOMIC:
+	  ret = gimplify_omp_atomic (expr_p, pre_p);
+	  break;
+
 	default:
 	  switch (TREE_CODE_CLASS (TREE_CODE (*expr_p)))
 	    {
Index: tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pretty-print.c,v
retrieving revision 2.61.4.10
diff -u -p -d -r2.61.4.10 tree-pretty-print.c
--- tree-pretty-print.c	23 Sep 2005 20:44:39 -0000	2.61.4.10
+++ tree-pretty-print.c	24 Sep 2005 22:50:39 -0000
@@ -1579,6 +1579,16 @@ dump_generic_node (pretty_printer *buffe
       is_expr = false;
       break;
 
+    case OMP_ATOMIC:
+      pp_string (buffer, "#pragma omp atomic");
+      newline_and_indent (buffer, spc + 2);
+      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
+      pp_space (buffer);
+      pp_character (buffer, '=');
+      pp_space (buffer);
+      dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
+      break;
+
     case OMP_CLAUSE_PRIVATE:
       pp_string (buffer, "private (");
       dump_generic_node (buffer, OMP_PRIVATE_VARS (node), spc, flags, false);
Index: tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.116.4.11
diff -u -p -d -r1.116.4.11 tree.def
--- tree.def	23 Sep 2005 20:44:39 -0000	1.116.4.11
+++ tree.def	24 Sep 2005 22:50:39 -0000
@@ -989,6 +989,14 @@ DEFTREECODE (OMP_SINGLE, "omp_single", t
    Operand 1: OMP_CRITICAL_BODY: Critical section body.  */
 DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 2)
 
+/* 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.
+   Operand 1: The expression to evaluate.  When the old value of the object
+	at the address is used in the expression, it should appear as if
+	build_fold_indirect_ref of the address.  */
+DEFTREECODE (OMP_ATOMIC, "omp_atomic", tcc_statement, 2)
+
 /* OpenMP clause: private (variable_list).  */
 DEFTREECODE (OMP_CLAUSE_PRIVATE, "private", tcc_expression, 1)
 
Index: testsuite/gcc.dg/gomp/atomic-2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/gomp/Attic/atomic-2.c,v
retrieving revision 1.1.2.1
diff -u -p -d -r1.1.2.1 atomic-2.c
--- testsuite/gcc.dg/gomp/atomic-2.c	23 Sep 2005 02:21:30 -0000	1.1.2.1
+++ testsuite/gcc.dg/gomp/atomic-2.c	24 Sep 2005 22:50:46 -0000
@@ -1,8 +1,6 @@
 /* { dg-do compile } */
 
-float x;
-double y;
-long double z;
+float x, y;
 
 void f1(void)
 {
@@ -23,41 +21,3 @@ void f1(void)
   #pragma omp atomic
     x /= 3;
 }
-
-void f2(void)
-{
-  #pragma omp atomic
-    y++;
-  #pragma omp atomic
-    y--;
-  #pragma omp atomic
-    ++y;
-  #pragma omp atomic
-    --y;
-  #pragma omp atomic
-    y += 1;
-  #pragma omp atomic
-    y -= x;
-  #pragma omp atomic
-    y *= 3;
-  #pragma omp atomic
-    y /= 3;
-}
-
-void f3(void)
-{
-  #pragma omp atomic
-    z++;
-  #pragma omp atomic
-    z--;
-  #pragma omp atomic
-    ++z;
-  #pragma omp atomic
-    --z;
-  #pragma omp atomic
-    z += 1;
-  #pragma omp atomic
-    z *= 3;
-  #pragma omp atomic
-    z /= 3;
-}
Index: testsuite/gcc.dg/gomp/atomic-6.c
===================================================================
RCS file: testsuite/gcc.dg/gomp/atomic-6.c
diff -N testsuite/gcc.dg/gomp/atomic-6.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/gomp/atomic-6.c	24 Sep 2005 22:50:46 -0000
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+
+int x[10], z;
+double y[10];
+
+void f1(void)
+{
+  #pragma omp atomic
+    x[z] /= y[z];
+}
Index: testsuite/gcc.dg/gomp/atomic-7.c
===================================================================
RCS file: testsuite/gcc.dg/gomp/atomic-7.c
diff -N testsuite/gcc.dg/gomp/atomic-7.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/gomp/atomic-7.c	24 Sep 2005 22:50:46 -0000
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+
+double x, y;
+
+void f2(void)
+{
+  #pragma omp atomic
+    y++;
+  #pragma omp atomic
+    y--;
+  #pragma omp atomic
+    ++y;
+  #pragma omp atomic
+    --y;
+  #pragma omp atomic
+    y += 1;
+  #pragma omp atomic
+    y -= x;
+  #pragma omp atomic
+    y *= 3;
+  #pragma omp atomic
+    y /= 3;
+}
Index: testsuite/gcc.dg/gomp/atomic-8.c
===================================================================
RCS file: testsuite/gcc.dg/gomp/atomic-8.c
diff -N testsuite/gcc.dg/gomp/atomic-8.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/gomp/atomic-8.c	24 Sep 2005 22:50:46 -0000
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* This test won't currently work on targets with types larger than 8 bytes. */
+/* { dg-xfail-if "" { "i?86-*-*" } { "*" } { "" } } */
+/* { dg-xfail-if "" { "x86_64-*-*" } { "*" } { "" } } */
+
+long double z;
+
+void f3(void)
+{
+  #pragma omp atomic
+    z++;
+  #pragma omp atomic
+    z--;
+  #pragma omp atomic
+    ++z;
+  #pragma omp atomic
+    --z;
+  #pragma omp atomic
+    z += 1;
+  #pragma omp atomic
+    z *= 3;
+  #pragma omp atomic
+    z /= 3;
+}
Index: testsuite/gcc.dg/gomp/atomic-9.c
===================================================================
RCS file: testsuite/gcc.dg/gomp/atomic-9.c
diff -N testsuite/gcc.dg/gomp/atomic-9.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/gomp/atomic-9.c	24 Sep 2005 22:50:46 -0000
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -fdump-tree-gimple" } */
+
+volatile int *bar(void);
+
+void f1(void)
+{
+  #pragma omp atomic
+    *bar() += 1;
+}
+
+/* { dg-final { scan-tree-dump-times "__sync_fetch_and_add" 1 "gimple" } } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]