Commit 8ca5b2a2 by Jakub Jelinek Committed by Jakub Jelinek

re PR c++/26943 ([gomp] firstprivate + lastprivate uses inefficient barrier)

	PR c++/26943
	* omp-low.c (maybe_lookup_decl_in_outer_ctx): New function.
	(build_outer_var_ref): Use maybe_lookup_decl_in_outer_ctx
	to find if var will be a global variable even in the nested context.
	(omp_copy_decl): Only check for global variable at the end, it might
	be overridden in outer contexts.
	(scan_sharing_clauses): For global variables don't create a field.
	(lower_rec_input_clauses): Do nothing for global shared variables.
	Emit a barrier at the end of ILIST if there were any decls in both
	firstprivate and lastprivate clauses.
	(lower_send_clauses): Do nothing for global variables except for
	COPYIN.

	* testsuite/libgomp.c/pr26943-1.c: New test.
	* testsuite/libgomp.c/pr26943-2.c: New test.
	* testsuite/libgomp.c/pr26943-3.c: New test.
	* testsuite/libgomp.c/pr26943-4.c: New test.
	* testsuite/libgomp.c++/pr27337.C: Remove barrier.
	* testsuite/libgomp.c++/pr26943.C: New test.

From-SVN: r113483
parent a3428e07
2006-05-02 Jakub Jelinek <jakub@redhat.com>
PR c++/26943
* omp-low.c (maybe_lookup_decl_in_outer_ctx): New function.
(build_outer_var_ref): Use maybe_lookup_decl_in_outer_ctx
to find if var will be a global variable even in the nested context.
(omp_copy_decl): Only check for global variable at the end, it might
be overridden in outer contexts.
(scan_sharing_clauses): For global variables don't create a field.
(lower_rec_input_clauses): Do nothing for global shared variables.
Emit a barrier at the end of ILIST if there were any decls in both
firstprivate and lastprivate clauses.
(lower_send_clauses): Do nothing for global variables except for
COPYIN.
2006-05-02 Zdenek Dvorak <dvorakz@suse.cz> 2006-05-02 Zdenek Dvorak <dvorakz@suse.cz>
* tree.c (unsigned_type_for, signed_type_for): Make sure a type * tree.c (unsigned_type_for, signed_type_for): Make sure a type
......
...@@ -112,6 +112,8 @@ struct omp_region *root_omp_region; ...@@ -112,6 +112,8 @@ struct omp_region *root_omp_region;
static void scan_omp (tree *, omp_context *); static void scan_omp (tree *, omp_context *);
static void lower_omp (tree *, omp_context *); static void lower_omp (tree *, omp_context *);
static tree lookup_decl_in_outer_ctx (tree, omp_context *);
static tree maybe_lookup_decl_in_outer_ctx (tree, omp_context *);
/* Find an OpenMP clause of type KIND within CLAUSES. */ /* Find an OpenMP clause of type KIND within CLAUSES. */
...@@ -560,7 +562,7 @@ build_outer_var_ref (tree var, omp_context *ctx) ...@@ -560,7 +562,7 @@ build_outer_var_ref (tree var, omp_context *ctx)
{ {
tree x; tree x;
if (is_global_var (var)) if (is_global_var (maybe_lookup_decl_in_outer_ctx (var, ctx)))
x = var; x = var;
else if (is_variable_sized (var)) else if (is_variable_sized (var))
{ {
...@@ -674,9 +676,6 @@ omp_copy_decl (tree var, copy_body_data *cb) ...@@ -674,9 +676,6 @@ omp_copy_decl (tree var, copy_body_data *cb)
omp_context *ctx = (omp_context *) cb; omp_context *ctx = (omp_context *) cb;
tree new_var; tree new_var;
if (is_global_var (var) || decl_function_context (var) != ctx->cb.src_fn)
return var;
if (TREE_CODE (var) == LABEL_DECL) if (TREE_CODE (var) == LABEL_DECL)
{ {
new_var = create_artificial_label (); new_var = create_artificial_label ();
...@@ -695,6 +694,9 @@ omp_copy_decl (tree var, copy_body_data *cb) ...@@ -695,6 +694,9 @@ omp_copy_decl (tree var, copy_body_data *cb)
return new_var; return new_var;
} }
if (is_global_var (var) || decl_function_context (var) != ctx->cb.src_fn)
return var;
return error_mark_node; return error_mark_node;
} }
...@@ -937,6 +939,10 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) ...@@ -937,6 +939,10 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
decl = OMP_CLAUSE_DECL (c); decl = OMP_CLAUSE_DECL (c);
gcc_assert (!is_variable_sized (decl)); gcc_assert (!is_variable_sized (decl));
by_ref = use_pointer_for_field (decl, true); by_ref = use_pointer_for_field (decl, true);
/* Global variables don't need to be copied,
the receiver side will use them directly. */
if (is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)))
break;
if (! TREE_READONLY (decl) if (! TREE_READONLY (decl)
|| TREE_ADDRESSABLE (decl) || TREE_ADDRESSABLE (decl)
|| by_ref || by_ref
...@@ -963,7 +969,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) ...@@ -963,7 +969,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
do_private: do_private:
if (is_variable_sized (decl)) if (is_variable_sized (decl))
break; break;
else if (is_parallel_ctx (ctx)) else if (is_parallel_ctx (ctx)
&& ! is_global_var (maybe_lookup_decl_in_outer_ctx (decl,
ctx)))
{ {
by_ref = use_pointer_for_field (decl, false); by_ref = use_pointer_for_field (decl, false);
install_var_field (decl, by_ref, ctx); install_var_field (decl, by_ref, ctx);
...@@ -1029,7 +1037,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) ...@@ -1029,7 +1037,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
case OMP_CLAUSE_SHARED: case OMP_CLAUSE_SHARED:
decl = OMP_CLAUSE_DECL (c); decl = OMP_CLAUSE_DECL (c);
fixup_remapped_decl (decl, ctx, false); if (! is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)))
fixup_remapped_decl (decl, ctx, false);
break; break;
case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_COPYPRIVATE:
...@@ -1415,6 +1424,23 @@ lookup_decl_in_outer_ctx (tree decl, omp_context *ctx) ...@@ -1415,6 +1424,23 @@ lookup_decl_in_outer_ctx (tree decl, omp_context *ctx)
} }
/* Similar to lookup_decl_in_outer_ctx, but return DECL if not found
in outer contexts. */
static tree
maybe_lookup_decl_in_outer_ctx (tree decl, omp_context *ctx)
{
tree t = NULL;
omp_context *up;
if (ctx->is_nested)
for (up = ctx->outer, t = NULL; up && t == NULL; up = up->outer)
t = maybe_lookup_decl (decl, up);
return t ? t : decl;
}
/* Construct the initialization value for reduction CLAUSE. */ /* Construct the initialization value for reduction CLAUSE. */
tree tree
...@@ -1493,6 +1519,7 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist, ...@@ -1493,6 +1519,7 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
tree_stmt_iterator diter; tree_stmt_iterator diter;
tree c, dtor, copyin_seq, x, args, ptr; tree c, dtor, copyin_seq, x, args, ptr;
bool copyin_by_ref = false; bool copyin_by_ref = false;
bool lastprivate_firstprivate = false;
int pass; int pass;
*dlist = alloc_stmt_list (); *dlist = alloc_stmt_list ();
...@@ -1518,14 +1545,22 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist, ...@@ -1518,14 +1545,22 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
continue; continue;
break; break;
case OMP_CLAUSE_SHARED: case OMP_CLAUSE_SHARED:
if (maybe_lookup_decl (OMP_CLAUSE_DECL (c), ctx) == NULL)
{
gcc_assert (is_global_var (OMP_CLAUSE_DECL (c)));
continue;
}
case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_FIRSTPRIVATE:
case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_REDUCTION:
break; break;
case OMP_CLAUSE_LASTPRIVATE: case OMP_CLAUSE_LASTPRIVATE:
if (pass != 0 if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
&& OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c)) {
continue; lastprivate_firstprivate = true;
if (pass != 0)
continue;
}
break; break;
default: default:
continue; continue;
...@@ -1611,6 +1646,9 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist, ...@@ -1611,6 +1646,9 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
switch (OMP_CLAUSE_CODE (c)) switch (OMP_CLAUSE_CODE (c))
{ {
case OMP_CLAUSE_SHARED: case OMP_CLAUSE_SHARED:
/* Shared global vars are just accessed directly. */
if (is_global_var (new_var))
break;
/* Set up the DECL_VALUE_EXPR for shared variables now. This /* Set up the DECL_VALUE_EXPR for shared variables now. This
needs to be delayed until after fixup_child_record_type so needs to be delayed until after fixup_child_record_type so
that we get the correct type during the dereference. */ that we get the correct type during the dereference. */
...@@ -1700,8 +1738,10 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist, ...@@ -1700,8 +1738,10 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
/* If any copyin variable is passed by reference, we must ensure the /* If any copyin variable is passed by reference, we must ensure the
master thread doesn't modify it before it is copied over in all master thread doesn't modify it before it is copied over in all
threads. */ threads. Similarly for variables in both firstprivate and
if (copyin_by_ref) lastprivate clauses we need to ensure the lastprivate copying
happens after firstprivate copying in all threads. */
if (copyin_by_ref || lastprivate_firstprivate)
build_omp_barrier (ilist); build_omp_barrier (ilist);
} }
...@@ -1919,6 +1959,9 @@ lower_send_clauses (tree clauses, tree *ilist, tree *olist, omp_context *ctx) ...@@ -1919,6 +1959,9 @@ lower_send_clauses (tree clauses, tree *ilist, tree *olist, omp_context *ctx)
if (ctx->is_nested) if (ctx->is_nested)
var = lookup_decl_in_outer_ctx (val, ctx); var = lookup_decl_in_outer_ctx (val, ctx);
if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_COPYIN
&& is_global_var (var))
continue;
if (is_variable_sized (val)) if (is_variable_sized (val))
continue; continue;
by_ref = use_pointer_for_field (val, false); by_ref = use_pointer_for_field (val, false);
......
2006-05-02 Jakub Jelinek <jakub@redhat.com> 2006-05-02 Jakub Jelinek <jakub@redhat.com>
PR c++/26943
* testsuite/libgomp.c/pr26943-1.c: New test.
* testsuite/libgomp.c/pr26943-2.c: New test.
* testsuite/libgomp.c/pr26943-3.c: New test.
* testsuite/libgomp.c/pr26943-4.c: New test.
* testsuite/libgomp.c++/pr27337.C: Remove barrier.
* testsuite/libgomp.c++/pr26943.C: New test.
2006-05-02 Jakub Jelinek <jakub@redhat.com>
PR middle-end/27337 PR middle-end/27337
* testsuite/libgomp.c++/pr27337.C: New test. * testsuite/libgomp.c++/pr27337.C: New test.
......
// PR c++/26943
// { dg-do run }
#include <assert.h>
#include <unistd.h>
struct S
{
public:
int x;
S () : x(-1) { }
S (const S &);
S& operator= (const S &);
void test ();
};
static volatile int hold;
S::S (const S &s)
{
#pragma omp master
sleep (1);
assert (s.x == -1);
x = 0;
}
S&
S::operator= (const S& s)
{
assert (s.x == 1);
x = 2;
return *this;
}
void
S::test ()
{
assert (x == 0);
x = 1;
}
static S x;
void
foo ()
{
#pragma omp sections firstprivate(x) lastprivate(x)
{
x.test();
}
}
int
main ()
{
#pragma omp parallel num_threads(2)
foo();
assert (x.x == 2);
return 0;
}
...@@ -48,11 +48,7 @@ foo () ...@@ -48,11 +48,7 @@ foo ()
#pragma omp parallel for firstprivate (ret) lastprivate (ret) \ #pragma omp parallel for firstprivate (ret) lastprivate (ret) \
schedule (static, 1) num_threads (4) schedule (static, 1) num_threads (4)
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ ret.i += omp_get_thread_num ();
ret.i += omp_get_thread_num ();
// FIXME: The following barrier should be unnecessary.
#pragma omp barrier
}
return ret; return ret;
} }
......
/* PR c++/26943 */
/* { dg-do run } */
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;
}
/* PR c++/26943 */
/* { dg-do run } */
extern int omp_set_dynamic (int);
extern void abort (void);
int a = 8, b = 12, c = 16, d = 20, j = 0;
char e[10] = "a", f[10] = "b", g[10] = "c", h[10] = "d";
int
main (void)
{
int i;
omp_set_dynamic (0);
#pragma omp parallel for shared (a, e) firstprivate (b, f) \
lastprivate (c, g) private (d, h) \
schedule (static, 1) num_threads (4) \
reduction (+:j)
for (i = 0; i < 4; i++)
{
if (a != 8 || b != 12 || e[0] != 'a' || f[0] != 'b')
j++;
#pragma omp barrier
#pragma omp atomic
a += i;
b += i;
c = i;
d = i;
#pragma omp atomic
e[0] += i;
f[0] += i;
g[0] = 'g' + i;
h[0] = 'h' + i;
#pragma omp barrier
if (a != 8 + 6 || b != 12 + i || c != i || d != i)
j += 8;
if (e[0] != 'a' + 6 || f[0] != 'b' + i || g[0] != 'g' + i)
j += 64;
if (h[0] != 'h' + i)
j += 512;
}
if (j || a != 8 + 6 || b != 12 || c != 3 || d != 20)
abort ();
if (e[0] != 'a' + 6 || f[0] != 'b' || g[0] != 'g' + 3 || h[0] != 'd')
abort ();
return 0;
}
/* PR c++/26943 */
/* { dg-do run } */
extern int omp_set_dynamic (int);
extern int omp_get_thread_num (void);
extern void abort (void);
int a = 8, b = 12, c = 16, d = 20, j = 0, l = 0;
char e[10] = "a", f[10] = "b", g[10] = "c", h[10] = "d";
volatile int k;
int
main (void)
{
int i;
omp_set_dynamic (0);
omp_set_nested (1);
#pragma omp parallel num_threads (2) reduction (+:l)
if (k == omp_get_thread_num ())
{
#pragma omp parallel for shared (a, e) firstprivate (b, f) \
lastprivate (c, g) private (d, h) \
schedule (static, 1) num_threads (4) \
reduction (+:j)
for (i = 0; i < 4; i++)
{
if (a != 8 || b != 12 || e[0] != 'a' || f[0] != 'b')
j++;
#pragma omp barrier
#pragma omp atomic
a += i;
b += i;
c = i;
d = i;
#pragma omp atomic
e[0] += i;
f[0] += i;
g[0] = 'g' + i;
h[0] = 'h' + i;
#pragma omp barrier
if (a != 8 + 6 || b != 12 + i || c != i || d != i)
j += 8;
if (e[0] != 'a' + 6 || f[0] != 'b' + i || g[0] != 'g' + i)
j += 64;
if (h[0] != 'h' + i)
j += 512;
}
if (j || a != 8 + 6 || b != 12 || c != 3 || d != 20)
++l;
if (e[0] != 'a' + 6 || f[0] != 'b' || g[0] != 'g' + 3 || h[0] != 'd')
l += 8;
}
if (l)
abort ();
return 0;
}
/* PR c++/26943 */
/* { dg-do run } */
extern int omp_set_dynamic (int);
extern int omp_get_thread_num (void);
extern void abort (void);
int a = 8, b = 12, c = 16, d = 20, j = 0, l = 0;
char e[10] = "a", f[10] = "b", g[10] = "c", h[10] = "d";
volatile int k;
int
main (void)
{
int i;
omp_set_dynamic (0);
omp_set_nested (1);
#pragma omp parallel num_threads (2) reduction (+:l) \
firstprivate (a, b, c, d, e, f, g, h, j)
if (k == omp_get_thread_num ())
{
#pragma omp parallel for shared (a, e) firstprivate (b, f) \
lastprivate (c, g) private (d, h) \
schedule (static, 1) num_threads (4) \
reduction (+:j)
for (i = 0; i < 4; i++)
{
if (a != 8 || b != 12 || e[0] != 'a' || f[0] != 'b')
j++;
#pragma omp barrier
#pragma omp atomic
a += i;
b += i;
c = i;
d = i;
#pragma omp atomic
e[0] += i;
f[0] += i;
g[0] = 'g' + i;
h[0] = 'h' + i;
#pragma omp barrier
if (a != 8 + 6 || b != 12 + i || c != i || d != i)
j += 8;
if (e[0] != 'a' + 6 || f[0] != 'b' + i || g[0] != 'g' + i)
j += 64;
if (h[0] != 'h' + i)
j += 512;
}
if (j || a != 8 + 6 || b != 12 || c != 3 || d != 20)
++l;
if (e[0] != 'a' + 6 || f[0] != 'b' || g[0] != 'g' + 3 || h[0] != 'd')
l += 8;
}
if (l)
abort ();
if (a != 8 || b != 12 || c != 16 || d != 20)
abort ();
if (e[0] != 'a' || f[0] != 'b' || g[0] != 'c' || h[0] != 'd')
abort ();
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment