Hi!

Similarly to EXEC_OMP_WORKSHARE, EXEC_OMP_ATOMIC has also very tight rules
what can and can't appear in the block, enforced through parsing and
resolving, so e.g. inserting EXEC_BLOCK there leads to ICEs.  In theory, one
could add such a BLOCK around the atomic rather than inside of it, but the
code isn't prepared to be able to do that and furthermore there is still
risk of breaking the EXEC_OMP_ATOMIC expectations.

Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux,
committed to trunk so far.

2019-12-19  Jakub Jelinek  <ja...@redhat.com>

        PR fortran/92977
        * frontend-passes.c (in_omp_atomic): New variable.
        (cfe_expr_0, matmul_to_var_expr, matmul_temp_args,
        inline_matmul_assign, call_external_blas): Don't optimize in
        EXEC_OMP_ATOMIC.
        (optimize_namespace): Clear in_omp_atomic.
        (gfc_code_walker): Set in_omp_atomic for EXEC_OMP_ATOMIC, save/restore
        it around.

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

--- gcc/fortran/frontend-passes.c.jj    2019-11-09 18:08:47.866374726 +0100
+++ gcc/fortran/frontend-passes.c       2019-12-18 14:45:23.996493420 +0100
@@ -92,6 +92,10 @@ static int forall_level;
 
 static bool in_omp_workshare;
 
+/* Keep track of whether we are within an OMP atomic.  */
+
+static bool in_omp_atomic;
+
 /* Keep track of whether we are within a WHERE statement.  */
 
 static bool in_where;
@@ -913,9 +917,9 @@ cfe_expr_0 (gfc_expr **e, int *walk_subt
   gfc_expr *newvar;
   gfc_expr **ei, **ej;
 
-  /* Don't do this optimization within OMP workshare or ASSOC lists.  */
+  /* Don't do this optimization within OMP workshare/atomic or ASSOC lists.  */
 
-  if (in_omp_workshare || in_assoc_list)
+  if (in_omp_workshare || in_omp_atomic || in_assoc_list)
     {
       *walk_subtrees = 0;
       return 0;
@@ -1464,6 +1468,7 @@ optimize_namespace (gfc_namespace *ns)
   iterator_level = 0;
   in_assoc_list = false;
   in_omp_workshare = false;
+  in_omp_atomic = false;
 
   if (flag_frontend_optimize)
     {
@@ -2818,7 +2823,7 @@ matmul_to_var_expr (gfc_expr **ep, int *
     return 0;
 
   if (forall_level > 0 || iterator_level > 0 || in_omp_workshare
-      || in_where || in_assoc_list)
+      || in_omp_atomic || in_where || in_assoc_list)
     return 0;
 
   /* Check if this is already in the form c = matmul(a,b).  */
@@ -2880,7 +2885,7 @@ matmul_temp_args (gfc_code **c, int *wal
     return 0;
 
   if (forall_level > 0 || iterator_level > 0 || in_omp_workshare
-      || in_where)
+      || in_omp_atomic || in_where)
     return 0;
 
   /* This has some duplication with inline_matmul_assign.  This
@@ -3848,7 +3853,7 @@ inline_matmul_assign (gfc_code **c, int
   /* For now don't do anything in OpenMP workshare, it confuses
      its translation, which expects only the allowed statements in there.
      We should figure out how to parallelize this eventually.  */
-  if (in_omp_workshare)
+  if (in_omp_workshare || in_omp_atomic)
     return 0;
 
   expr1 = co->expr1;
@@ -4385,7 +4390,7 @@ call_external_blas (gfc_code **c, int *w
   /* For now don't do anything in OpenMP workshare, it confuses
      its translation, which expects only the allowed statements in there. */
 
-  if (in_omp_workshare)
+  if (in_omp_workshare | in_omp_atomic)
     return 0;
 
   expr1 = co->expr1;
@@ -5047,6 +5052,7 @@ gfc_code_walker (gfc_code **c, walk_code
          gfc_code *co;
          gfc_association_list *alist;
          bool saved_in_omp_workshare;
+         bool saved_in_omp_atomic;
          bool saved_in_where;
 
          /* There might be statement insertions before the current code,
@@ -5054,6 +5060,7 @@ gfc_code_walker (gfc_code **c, walk_code
 
          co = *c;
          saved_in_omp_workshare = in_omp_workshare;
+         saved_in_omp_atomic = in_omp_atomic;
          saved_in_where = in_where;
 
          switch (co->op)
@@ -5251,6 +5258,10 @@ gfc_code_walker (gfc_code **c, walk_code
              WALK_SUBEXPR (co->ext.dt->extra_comma);
              break;
 
+           case EXEC_OMP_ATOMIC:
+             in_omp_atomic = true;
+             break;
+
            case EXEC_OMP_PARALLEL:
            case EXEC_OMP_PARALLEL_DO:
            case EXEC_OMP_PARALLEL_DO_SIMD:
@@ -5368,6 +5379,7 @@ gfc_code_walker (gfc_code **c, walk_code
            select_level --;
 
          in_omp_workshare = saved_in_omp_workshare;
+         in_omp_atomic = saved_in_omp_atomic;
          in_where = saved_in_where;
        }
     }
--- gcc/testsuite/gfortran.dg/gomp/pr92977.f90.jj       2019-12-18 
15:16:14.657486591 +0100
+++ gcc/testsuite/gfortran.dg/gomp/pr92977.f90  2019-12-18 15:16:08.310582750 
+0100
@@ -0,0 +1,15 @@
+! PR fortran/92977
+! { dg-do compile }
+! { dg-additional-options "-O2" }
+
+program pr92977
+  integer :: n = 1
+  integer :: a
+!$omp atomic write
+  a = f(n) - f(n)
+contains
+  integer function f(x)
+    integer, intent(in) :: x
+    f = x
+  end
+end

        Jakub

Reply via email to