Hi!

This patch adds Fortran support for OpenMP 3.1 atomics.
Tested on x86_64-linux, committed to gomp-3_1-branch.

2011-04-27  Jakub Jelinek  <ja...@redhat.com>

        * gfortran.h (gfc_statement): Add ST_OMP_END_ATOMIC.
        (gfc_omp_atomic_op): New enum typedef.
        (struct gfc_code): Add ext.omp_atomic.
        * parse.c (decode_omp_directive): Handle !$omp end atomic.
        (parse_omp_atomic): Return gfc_statement instead of void.
        For !$omp atomic capture parse two assignments instead of
        just one and require !$omp end atomic afterwards, for
        other !$omp atomic forms just allow !$omp end atomic at the
        end.
        (parse_omp_structured_block, parse_executable): Adjust
        parse_omp_atomic callers.
        * openmp.c (gfc_match_omp_atomic): Match optional
        read/write/update/capture keywords after !$omp atomic.
        (resolve_omp_atomic): Handle all OpenMP 3.1 atomic forms.
        * trans-openmp.c (gfc_trans_omp_atomic): Likewise.

        * gfortran.dg/gomp/omp_atomic2.f90: New test.

        * testsuite/libgomp.fortran/omp_atomic3.f90: New test.
        * testsuite/libgomp.fortran/omp_atomic4.f90: New test.

--- gcc/fortran/gfortran.h.jj   2011-02-24 14:19:08.000000000 +0100
+++ gcc/fortran/gfortran.h      2011-04-27 10:35:24.000000000 +0200
@@ -200,9 +200,9 @@ typedef enum
   ST_WRITE, ST_ASSIGNMENT, ST_POINTER_ASSIGNMENT, ST_SELECT_CASE, ST_SEQUENCE,
   ST_SIMPLE_IF, ST_STATEMENT_FUNCTION, ST_DERIVED_DECL, ST_LABEL_ASSIGNMENT,
   ST_ENUM, ST_ENUMERATOR, ST_END_ENUM, ST_SELECT_TYPE, ST_TYPE_IS, ST_CLASS_IS,
-  ST_OMP_ATOMIC, ST_OMP_BARRIER, ST_OMP_CRITICAL, ST_OMP_END_CRITICAL,
-  ST_OMP_END_DO, ST_OMP_END_MASTER, ST_OMP_END_ORDERED, ST_OMP_END_PARALLEL,
-  ST_OMP_END_PARALLEL_DO, ST_OMP_END_PARALLEL_SECTIONS,
+  ST_OMP_ATOMIC, ST_OMP_BARRIER, ST_OMP_CRITICAL, ST_OMP_END_ATOMIC,
+  ST_OMP_END_CRITICAL, ST_OMP_END_DO, ST_OMP_END_MASTER, ST_OMP_END_ORDERED,
+  ST_OMP_END_PARALLEL, ST_OMP_END_PARALLEL_DO, ST_OMP_END_PARALLEL_SECTIONS,
   ST_OMP_END_PARALLEL_WORKSHARE, ST_OMP_END_SECTIONS, ST_OMP_END_SINGLE,
   ST_OMP_END_WORKSHARE, ST_OMP_DO, ST_OMP_FLUSH, ST_OMP_MASTER, ST_OMP_ORDERED,
   ST_OMP_PARALLEL, ST_OMP_PARALLEL_DO, ST_OMP_PARALLEL_SECTIONS,
@@ -2064,6 +2064,15 @@ typedef enum
 }
 gfc_exec_op;
 
+typedef enum
+{
+  GFC_OMP_ATOMIC_UPDATE,
+  GFC_OMP_ATOMIC_READ,
+  GFC_OMP_ATOMIC_WRITE,
+  GFC_OMP_ATOMIC_CAPTURE
+}
+gfc_omp_atomic_op;
+
 typedef struct gfc_code
 {
   gfc_exec_op op;
@@ -2114,6 +2123,7 @@ typedef struct gfc_code
     const char *omp_name;
     gfc_namelist *omp_namelist;
     bool omp_bool;
+    gfc_omp_atomic_op omp_atomic;
   }
   ext;         /* Points to additional structures required by statement */
 
--- gcc/fortran/openmp.c.jj     2011-04-20 11:19:18.000000000 +0200
+++ gcc/fortran/openmp.c        2011-04-27 15:42:04.000000000 +0200
@@ -700,13 +700,22 @@ gfc_match_omp_ordered (void)
 match
 gfc_match_omp_atomic (void)
 {
+  gfc_omp_atomic_op op = GFC_OMP_ATOMIC_UPDATE;
+  if (gfc_match ("% update") == MATCH_YES)
+    op = GFC_OMP_ATOMIC_UPDATE;
+  else if (gfc_match ("% read") == MATCH_YES)
+    op = GFC_OMP_ATOMIC_READ;
+  else if (gfc_match ("% write") == MATCH_YES)
+    op = GFC_OMP_ATOMIC_WRITE;
+  else if (gfc_match ("% capture") == MATCH_YES)
+    op = GFC_OMP_ATOMIC_CAPTURE;
   if (gfc_match_omp_eos () != MATCH_YES)
     {
       gfc_error ("Unexpected junk after $OMP ATOMIC statement at %C");
       return MATCH_ERROR;
     }
   new_st.op = EXEC_OMP_ATOMIC;
-  new_st.ext.omp_clauses = NULL;
+  new_st.ext.omp_atomic = op;
   return MATCH_YES;
 }
 
@@ -1100,12 +1109,18 @@ is_conversion (gfc_expr *expr, bool wide
 static void
 resolve_omp_atomic (gfc_code *code)
 {
+  gfc_code *atomic_code = code;
   gfc_symbol *var;
-  gfc_expr *expr2;
+  gfc_expr *expr2, *expr2_tmp;
 
   code = code->block->next;
   gcc_assert (code->op == EXEC_ASSIGN);
-  gcc_assert (code->next == NULL);
+  gcc_assert ((atomic_code->ext.omp_atomic != GFC_OMP_ATOMIC_CAPTURE
+              && code->next == NULL)
+             || (atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_CAPTURE
+                 && code->next != NULL
+                 && code->next->op == EXEC_ASSIGN
+                 && code->next->next == NULL));
 
   if (code->expr1->expr_type != EXPR_VARIABLE
       || code->expr1->symtree == NULL
@@ -1123,7 +1138,86 @@ resolve_omp_atomic (gfc_code *code)
   var = code->expr1->symtree->n.sym;
   expr2 = is_conversion (code->expr2, false);
   if (expr2 == NULL)
-    expr2 = code->expr2;
+    {
+      if (atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_READ
+         || atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_WRITE)
+       expr2 = is_conversion (code->expr2, true);
+      if (expr2 == NULL)
+       expr2 = code->expr2;
+    }
+
+  switch (atomic_code->ext.omp_atomic)
+    {
+    case GFC_OMP_ATOMIC_READ:
+      if (expr2->expr_type != EXPR_VARIABLE
+         || expr2->symtree == NULL
+         || expr2->rank != 0
+         || (expr2->ts.type != BT_INTEGER
+             && expr2->ts.type != BT_REAL
+             && expr2->ts.type != BT_COMPLEX
+             && expr2->ts.type != BT_LOGICAL))
+       gfc_error ("!$OMP ATOMIC READ statement must read from a scalar "
+                  "variable of intrinsic type at %L", &expr2->where);
+      return;
+    case GFC_OMP_ATOMIC_WRITE:
+      if (expr2->rank != 0 || expr_references_sym (code->expr2, var, NULL))
+       gfc_error ("expr in !$OMP ATOMIC WRITE assignment var = expr "
+                  "must be scalar and cannot reference var at %L",
+                  &expr2->where);
+      return;
+    case GFC_OMP_ATOMIC_CAPTURE:
+      expr2_tmp = expr2;
+      if (expr2 == code->expr2)
+       {
+         expr2_tmp = is_conversion (code->expr2, true);
+         if (expr2_tmp == NULL)
+           expr2_tmp = expr2;
+       }
+      if (expr2_tmp->expr_type == EXPR_VARIABLE)
+       {
+         if (expr2_tmp->symtree == NULL
+             || expr2_tmp->rank != 0
+             || (expr2_tmp->ts.type != BT_INTEGER
+                 && expr2_tmp->ts.type != BT_REAL
+                 && expr2_tmp->ts.type != BT_COMPLEX
+                 && expr2_tmp->ts.type != BT_LOGICAL)
+             || expr2_tmp->symtree->n.sym == var)
+           {
+             gfc_error ("!$OMP ATOMIC CAPTURE capture statement must read from 
"
+                        "a scalar variable of intrinsic type at %L",
+                        &expr2_tmp->where);
+             return;
+           }
+         var = expr2_tmp->symtree->n.sym;
+         code = code->next;
+         if (code->expr1->expr_type != EXPR_VARIABLE
+             || code->expr1->symtree == NULL
+             || code->expr1->rank != 0
+             || (code->expr1->ts.type != BT_INTEGER
+                 && code->expr1->ts.type != BT_REAL
+                 && code->expr1->ts.type != BT_COMPLEX
+                 && code->expr1->ts.type != BT_LOGICAL))
+           {
+             gfc_error ("!$OMP ATOMIC CAPTURE update statement must set "
+                        "a scalar variable of intrinsic type at %L",
+                        &code->expr1->where);
+             return;
+           }
+         if (code->expr1->symtree->n.sym != var)
+           {
+             gfc_error ("!$OMP ATOMIC CAPTURE capture statement reads from "
+                        "different variable than update statement writes "
+                        "into at %L", &code->expr1->where);
+             return;
+           }
+         expr2 = is_conversion (code->expr2, false);
+         if (expr2 == NULL)
+           expr2 = code->expr2;
+       }
+      break;
+    default:
+      break;
+    }
 
   if (expr2->expr_type == EXPR_OP)
     {
@@ -1325,6 +1419,53 @@ resolve_omp_atomic (gfc_code *code)
   else
     gfc_error ("!$OMP ATOMIC assignment must have an operator or intrinsic "
               "on right hand side at %L", &expr2->where);
+
+  if (atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_CAPTURE && code->next)
+    {
+      code = code->next;
+      if (code->expr1->expr_type != EXPR_VARIABLE
+         || code->expr1->symtree == NULL
+         || code->expr1->rank != 0
+         || (code->expr1->ts.type != BT_INTEGER
+             && code->expr1->ts.type != BT_REAL
+             && code->expr1->ts.type != BT_COMPLEX
+             && code->expr1->ts.type != BT_LOGICAL))
+       {
+         gfc_error ("!$OMP ATOMIC CAPTURE capture statement must set "
+                    "a scalar variable of intrinsic type at %L",
+                    &code->expr1->where);
+         return;
+       }
+
+      expr2 = is_conversion (code->expr2, false);
+      if (expr2 == NULL)
+       {
+         expr2 = is_conversion (code->expr2, true);
+         if (expr2 == NULL)
+           expr2 = code->expr2;
+       }
+
+      if (expr2->expr_type != EXPR_VARIABLE
+         || expr2->symtree == NULL
+         || expr2->rank != 0
+         || (expr2->ts.type != BT_INTEGER
+             && expr2->ts.type != BT_REAL
+             && expr2->ts.type != BT_COMPLEX
+             && expr2->ts.type != BT_LOGICAL))
+       {
+         gfc_error ("!$OMP ATOMIC CAPTURE capture statement must read "
+                    "from a scalar variable of intrinsic type at %L",
+                    &expr2->where);
+         return;
+       }
+      if (expr2->symtree->n.sym != var)
+       {
+         gfc_error ("!$OMP ATOMIC CAPTURE capture statement reads from "
+                    "different variable than update statement writes "
+                    "into at %L", &expr2->where);
+         return;
+       }
+    }
 }
 
 
--- gcc/fortran/trans-openmp.c.jj       2011-04-20 11:19:18.000000000 +0200
+++ gcc/fortran/trans-openmp.c  2011-04-27 16:03:24.000000000 +0200
@@ -1000,35 +1000,85 @@ static tree gfc_trans_omp_workshare (gfc
 static tree
 gfc_trans_omp_atomic (gfc_code *code)
 {
+  gfc_code *atomic_code = code;
   gfc_se lse;
   gfc_se rse;
+  gfc_se vse;
   gfc_expr *expr2, *e;
   gfc_symbol *var;
   stmtblock_t block;
   tree lhsaddr, type, rhs, x;
   enum tree_code op = ERROR_MARK;
+  enum tree_code aop = OMP_ATOMIC;
   bool var_on_left = false;
 
   code = code->block->next;
   gcc_assert (code->op == EXEC_ASSIGN);
-  gcc_assert (code->next == NULL);
   var = code->expr1->symtree->n.sym;
 
   gfc_init_se (&lse, NULL);
   gfc_init_se (&rse, NULL);
+  gfc_init_se (&vse, NULL);
   gfc_start_block (&block);
 
-  gfc_conv_expr (&lse, code->expr1);
-  gfc_add_block_to_block (&block, &lse.pre);
-  type = TREE_TYPE (lse.expr);
-  lhsaddr = gfc_build_addr_expr (NULL, lse.expr);
-
   expr2 = code->expr2;
   if (expr2->expr_type == EXPR_FUNCTION
       && expr2->value.function.isym->id == GFC_ISYM_CONVERSION)
     expr2 = expr2->value.function.actual->expr;
 
-  if (expr2->expr_type == EXPR_OP)
+  switch (atomic_code->ext.omp_atomic)
+    {
+    case GFC_OMP_ATOMIC_READ:
+      gfc_conv_expr (&vse, code->expr1);
+      gfc_add_block_to_block (&block, &vse.pre);
+
+      gfc_conv_expr (&lse, expr2);
+      gfc_add_block_to_block (&block, &lse.pre);
+      type = TREE_TYPE (lse.expr);
+      lhsaddr = gfc_build_addr_expr (NULL, lse.expr);
+
+      x = build1 (OMP_ATOMIC_READ, type, lhsaddr);
+      x = convert (TREE_TYPE (vse.expr), x);
+      gfc_add_modify (&block, vse.expr, x);
+
+      gfc_add_block_to_block (&block, &lse.pre);
+      gfc_add_block_to_block (&block, &rse.pre);
+
+      return gfc_finish_block (&block);
+    case GFC_OMP_ATOMIC_CAPTURE:
+      aop = OMP_ATOMIC_CAPTURE_NEW;
+      if (expr2->expr_type == EXPR_VARIABLE)
+       {
+         aop = OMP_ATOMIC_CAPTURE_OLD;
+         gfc_conv_expr (&vse, code->expr1);
+         gfc_add_block_to_block (&block, &vse.pre);
+
+         gfc_conv_expr (&lse, expr2);
+         gfc_add_block_to_block (&block, &lse.pre);
+         gfc_init_se (&lse, NULL);
+         code = code->next;
+         var = code->expr1->symtree->n.sym;
+         expr2 = code->expr2;
+         if (expr2->expr_type == EXPR_FUNCTION
+             && expr2->value.function.isym->id == GFC_ISYM_CONVERSION)
+           expr2 = expr2->value.function.actual->expr;
+       }
+      break;
+    default:
+      break;
+    }
+
+  gfc_conv_expr (&lse, code->expr1);
+  gfc_add_block_to_block (&block, &lse.pre);
+  type = TREE_TYPE (lse.expr);
+  lhsaddr = gfc_build_addr_expr (NULL, lse.expr);
+
+  if (atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_WRITE)
+    {
+      gfc_conv_expr (&rse, expr2);
+      gfc_add_block_to_block (&block, &rse.pre);
+    }
+  else if (expr2->expr_type == EXPR_OP)
     {
       gfc_expr *e;
       switch (expr2->value.op.op)
@@ -1144,25 +1194,55 @@ gfc_trans_omp_atomic (gfc_code *code)
 
   lhsaddr = save_expr (lhsaddr);
   rhs = gfc_evaluate_now (rse.expr, &block);
-  x = convert (TREE_TYPE (rhs), build_fold_indirect_ref_loc (input_location,
-                                                        lhsaddr));
 
-  if (var_on_left)
-    x = fold_build2_loc (input_location, op, TREE_TYPE (rhs), x, rhs);
+  if (atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_WRITE)
+    x = rhs;
   else
-    x = fold_build2_loc (input_location, op, TREE_TYPE (rhs), rhs, x);
+    {
+      x = convert (TREE_TYPE (rhs),
+                  build_fold_indirect_ref_loc (input_location, lhsaddr));
+      if (var_on_left)
+       x = fold_build2_loc (input_location, op, TREE_TYPE (rhs), x, rhs);
+      else
+       x = fold_build2_loc (input_location, op, TREE_TYPE (rhs), rhs, x);
+    }
 
   if (TREE_CODE (TREE_TYPE (rhs)) == COMPLEX_TYPE
       && TREE_CODE (type) != COMPLEX_TYPE)
     x = fold_build1_loc (input_location, REALPART_EXPR,
                         TREE_TYPE (TREE_TYPE (rhs)), x);
 
-  x = build2_v (OMP_ATOMIC, lhsaddr, convert (type, x));
-  gfc_add_expr_to_block (&block, x);
-
   gfc_add_block_to_block (&block, &lse.pre);
   gfc_add_block_to_block (&block, &rse.pre);
 
+  if (aop == OMP_ATOMIC)
+    {
+      x = build2_v (OMP_ATOMIC, lhsaddr, convert (type, x));
+      gfc_add_expr_to_block (&block, x);
+    }
+  else
+    {
+      if (aop == OMP_ATOMIC_CAPTURE_NEW)
+       {
+         code = code->next;
+         expr2 = code->expr2;
+         if (expr2->expr_type == EXPR_FUNCTION
+             && expr2->value.function.isym->id == GFC_ISYM_CONVERSION)
+           expr2 = expr2->value.function.actual->expr;
+
+         gcc_assert (expr2->expr_type == EXPR_VARIABLE);
+         gfc_conv_expr (&vse, code->expr1);
+         gfc_add_block_to_block (&block, &vse.pre);
+
+         gfc_init_se (&lse, NULL);
+         gfc_conv_expr (&lse, expr2);
+         gfc_add_block_to_block (&block, &lse.pre);
+       }
+      x = build2 (aop, type, lhsaddr, convert (type, x));
+      x = convert (TREE_TYPE (vse.expr), x);
+      gfc_add_modify (&block, vse.expr, x);
+    }
+
   return gfc_finish_block (&block);
 }
 
--- gcc/fortran/parse.c.jj      2011-02-24 14:19:08.000000000 +0100
+++ gcc/fortran/parse.c 2011-04-27 15:36:59.000000000 +0200
@@ -521,6 +521,7 @@ decode_omp_directive (void)
       match ("do", gfc_match_omp_do, ST_OMP_DO);
       break;
     case 'e':
+      match ("end atomic", gfc_match_omp_eos, ST_OMP_END_ATOMIC);
       match ("end critical", gfc_match_omp_critical, ST_OMP_END_CRITICAL);
       match ("end do", gfc_match_omp_end_nowait, ST_OMP_END_DO);
       match ("end master", gfc_match_omp_eos, ST_OMP_END_MASTER);
@@ -1458,6 +1459,9 @@ gfc_ascii_statement (gfc_statement st)
     case ST_OMP_DO:
       p = "!$OMP DO";
       break;
+    case ST_OMP_END_ATOMIC:
+      p = "!$OMP END ATOMIC";
+      break;
     case ST_OMP_END_CRITICAL:
       p = "!$OMP END CRITICAL";
       break;
@@ -3396,12 +3400,13 @@ parse_omp_do (gfc_statement omp_st)
 
 /* Parse the statements of OpenMP atomic directive.  */
 
-static void
+static gfc_statement
 parse_omp_atomic (void)
 {
   gfc_statement st;
   gfc_code *cp, *np;
   gfc_state_data s;
+  int count;
 
   accept_statement (ST_OMP_ATOMIC);
 
@@ -3410,21 +3415,35 @@ parse_omp_atomic (void)
   np = new_level (cp);
   np->op = cp->op;
   np->block = NULL;
+  count = 1 + (cp->ext.omp_atomic == GFC_OMP_ATOMIC_CAPTURE);
 
-  for (;;)
+  while (count)
     {
       st = next_statement ();
       if (st == ST_NONE)
        unexpected_eof ();
       else if (st == ST_ASSIGNMENT)
-       break;
+       {
+         accept_statement (st);
+         count--;
+       }
       else
        unexpected_statement (st);
     }
 
-  accept_statement (st);
-
   pop_state ();
+
+  st = next_statement ();
+  if (st == ST_OMP_END_ATOMIC)
+    {
+      gfc_clear_new_st ();
+      gfc_commit_symbols ();
+      gfc_warning_check ();
+      st = next_statement ();
+    }
+  else if (cp->ext.omp_atomic == GFC_OMP_ATOMIC_CAPTURE)
+    gfc_error ("Missing !$OMP END ATOMIC after !$OMP ATOMIC CAPTURE at %C");
+  return st;
 }
 
 
@@ -3534,8 +3553,8 @@ parse_omp_structured_block (gfc_statemen
                  continue;
 
                case ST_OMP_ATOMIC:
-                 parse_omp_atomic ();
-                 break;
+                 st = parse_omp_atomic ();
+                 continue;
 
                default:
                  cycle = false;
@@ -3715,8 +3734,8 @@ parse_executable (gfc_statement st)
          continue;
 
        case ST_OMP_ATOMIC:
-         parse_omp_atomic ();
-         break;
+         st = parse_omp_atomic ();
+         continue;
 
        default:
          return st;
--- gcc/testsuite/gfortran.dg/gomp/omp_atomic2.f90.jj   2011-04-27 
16:14:36.000000000 +0200
+++ gcc/testsuite/gfortran.dg/gomp/omp_atomic2.f90      2011-04-27 
16:10:47.000000000 +0200
@@ -0,0 +1,54 @@
+  real :: r1, r2
+  complex :: c1, c2
+  integer :: i1, i2
+!$omp atomic write
+  c1 = 0
+!$omp atomic write
+  r2 = 0
+!$omp atomic write
+  i2 = 0
+!$omp atomic read
+  r1 = c1
+!$omp atomic read
+  c2 = r2
+!$omp atomic read
+  i1 = r2
+!$omp atomic read
+  c2 = i2
+!$omp atomic write
+  c1 = r1
+!$omp atomic write
+  r2 = c2
+!$omp atomic write
+  r2 = i1
+!$omp atomic write
+  i2 = c2
+!$omp end atomic
+!$omp atomic write
+  c1 = 1 + 2 + r1
+!$omp atomic write
+  r2 = c2 + 2 + 3
+!$omp atomic write
+  r2 = 3 + 4 + i1
+!$omp atomic write
+  i2 = c2 + 4 + 5
+!$omp atomic
+  c1 = c1 * 2.
+!$omp atomic update
+  r2 = r2 / 4
+!$omp end atomic
+!$omp atomic update
+  i2 = i2 + 8
+!$omp atomic capture
+  c1 = c1 * 2.
+  r1 = c1
+!$omp end atomic
+!$omp atomic capture
+  c2 = r2
+  r2 = r2 / 4
+!$omp end atomic
+!$omp atomic capture
+  i2 = i2 + 8
+  c2 = i2
+!$omp end atomic
+end
--- libgomp/testsuite/libgomp.fortran/omp_atomic4.f90.jj        2011-04-27 
16:13:58.000000000 +0200
+++ libgomp/testsuite/libgomp.fortran/omp_atomic4.f90   2011-04-27 
14:27:34.000000000 +0200
@@ -0,0 +1,37 @@
+! { dg-do run }
+    integer (kind = 4) :: a, a2
+    integer (kind = 2) :: b, b2
+    real :: c
+    double precision :: d, d2, c2
+    integer, dimension (10) :: e
+!$omp atomic write
+    a = 1
+!$omp atomic write
+    b = 2
+!$omp atomic write
+    c = 3
+!$omp atomic write
+    d = 4
+!$omp atomic capture
+    a2 = a
+    a = a + 4
+!$omp end atomic
+!$omp atomic capture
+    b = b - 18
+    b2 = b
+!$omp end atomic
+!$omp atomic capture
+    c2 = c
+    c = 2.0 * c
+!$omp end atomic
+!$omp atomic capture
+    d = d / 2.0
+    d2 = d
+!$omp end atomic
+    if (a2 .ne. 1 .or. b2 .ne. -16 .or. c2 .ne. 3 .or. d2 .ne. 2) call abort
+!$omp atomic read
+    a2 = a
+!$omp atomic read
+    c2 = c
+    if (a2 .ne. 5 .or. b2 .ne. -16 .or. c2 .ne. 6 .or. d2 .ne. 2) call abort
+end
--- libgomp/testsuite/libgomp.fortran/omp_atomic3.f90.jj        2011-04-27 
14:03:49.000000000 +0200
+++ libgomp/testsuite/libgomp.fortran/omp_atomic3.f90   2011-04-27 
13:34:12.000000000 +0200
@@ -0,0 +1,58 @@
+! { dg-do run }
+    integer (kind = 4) :: a, a2
+    integer (kind = 2) :: b, b2
+    real :: c, f
+    double precision :: d, d2, c2
+    integer, dimension (10) :: e
+!$omp atomic write
+    a = 1
+!$omp atomic write
+    b = 2
+!$omp end atomic
+!$omp atomic write
+    c = 3
+!$omp atomic write
+    d = 1 + 2 + 3 - 2
+    e = 5
+!$omp atomic write
+    f = 6
+!$omp end atomic
+!$omp atomic
+    a = a + 4
+!$omp end atomic
+!$omp atomic update
+    b = 4 - b
+!$omp atomic
+    c = c * 2
+!$omp atomic update
+    d = 2 / d
+!$omp end atomic
+!$omp atomic read
+    a2 = a
+!$omp atomic read
+    b2 = b
+!$omp end atomic
+!$omp atomic read
+    c2 = c
+!$omp atomic read
+    d2 = d
+    if (a2 .ne. 5 .or. b2 .ne. 2 .or. c2 .ne. 6 .or. d2 .ne. 0.5) call abort
+!$omp atomic write
+    d = 1.2
+!$omp atomic
+    a = a + c + d
+!$omp atomic
+    b = b - (a + c + d)
+    if (a .ne. 12 .or. b .ne. -17) call abort
+!$omp atomic
+    a = c + d + a
+!$omp atomic
+    b = a + c + d - b
+    if (a .ne. 19 .or. b .ne. 43) call abort
+!$omp atomic
+    b = (a + c + d) - b
+    a = 32
+!$omp atomic
+    a = a / 3.4
+    if (a .ne. 9 .or. b .ne. -16) call abort
+end

        Jakub

Reply via email to