------- Comment #2 from jakub at gcc dot gnu dot org  2006-04-28 15:07 -------
One incremental fix for the global var case is:
--- omp-low.c.jj5       2006-04-28 13:29:49.000000000 +0200
+++ omp-low.c   2006-04-28 16:22:36.000000000 +0200
@@ -674,9 +674,6 @@ omp_copy_decl (tree var, copy_body_data
   omp_context *ctx = (omp_context *) cb;
   tree new_var;

-  if (is_global_var (var) || decl_function_context (var) != ctx->cb.src_fn)
-    return var;
-
   if (TREE_CODE (var) == LABEL_DECL)
     {
       new_var = create_artificial_label ();
@@ -695,6 +692,9 @@ omp_copy_decl (tree var, copy_body_data
        return new_var;
     }

+  if (is_global_var (var) || decl_function_context (var) != ctx->cb.src_fn)
+    return var;
+
   return error_mark_node;
 }

without this we don't remap privatized global vars except directly in the
omp context that privatized them.
Testcase I was looking at is:
extern void abort (void);
extern void omp_set_dynamic (int);
int n = 6;

int
main (void)
{
  int i, x = 0;
  omp_set_dynamic (0);
#pragma omp parallel for num_threads (16) firstprivate (n) lastprivate (n) \
                         schedule (static, 1) reduction (+: x)
  for (i = 0; i < 16; i++)
    {
      if (n != 6)
        ++x;
      n = i;
    }
  if (x || n != 15)
    abort ();
  return 0;
}

With the above patch, we still create wrong code, with 2 different bugs:
1) there is no barrier to separate firstprivate assignments from lastprivate
2) on the sender side, we store the global var n into
.omp_data_o.4D.1945.nD.1938, but on the receiver side we access either the
remapped private n (assuming the above patch is in) or, when accessing the
outside n we use the global variable n rather than .omp_data_iD.1937.nD.1938

To fix 2), we need to decide where to pass global vars, either the sender side
will do nothing and receiver side will remain as is, or the receiver side will
use .omp_data_i fields even for global vars.  I'd say the sender side should be
changed unless we have some important reason why we need to do an extra copy
(if passed by reference, there is certainly no point in doing that).

As for 1), I believe that whenever there is any
OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE clause we need to do the same as we do
for copyin_by_ref, at least for the time being (later on we could replace that
by a more sofisticated special case barrier implementation), because
even if the firstprivate/lastprivate var is a scalar passed by value in
.omp_data_* struct, firstprivate copying copies it from that struct and
lastprivate copying writes it into the same struct same field, so if say
one of threads is delayed for whatever reason, it will execute firstprivate
copying after other thread that handled the last case performed the lastprivate
copying back (well, scalar by value could perhaps be done even without that
by allocating two fields instead of one, one write only and one readonly, but
by reference/is_reference/VLA need to be with barrier in all cases).

In addition to this, I'm not sure what exactly the standard requires say when
firstprivate is used on a global var.  The global var can be visible to the
threads and they can modify it, do we need to make any guarantees about what
exact value gets assigned to the privatized n variable in various threads?
As in, is the following program making a valid assumption or not?
int n = 2;
void bar (void) { n = 4; }
void
foo (void)
{
  if (n != 2)
    return;
  #pragma omp parallel firstprivate (n)
    {
      if (n != 2)
        abort ();
      bar ();
    }
}
}


-- 

jakub at gcc dot gnu dot org changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |dnovillo at gcc dot gnu dot
                   |                            |org


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26943

Reply via email to