2007-06-25 Jakub Jelinek PR libgomp/32468 * omp-low.c (check_combined_parallel): New function. (lower_omp_parallel): Call it via walk_stmts, set OMP_PARALLEL_COMBINED if appropriate. (determine_parallel_type): If OMP_FOR resp. OMP_SECTIONS isn't the only statement in WS_ENTRY_BB or OMP_RETURN the only one in PAR_EXIT_BB and not OMP_PARALLEL_COMBINED, don't consider it as combined parallel. --- gcc/omp-low.c.jj 2007-06-21 13:38:10.000000000 +0200 +++ gcc/omp-low.c 2007-06-25 19:21:35.000000000 +0200 @@ -385,10 +385,13 @@ determine_parallel_type (struct omp_regi if (single_succ (par_entry_bb) == ws_entry_bb && single_succ (ws_exit_bb) == par_exit_bb - && workshare_safe_to_combine_p (par_entry_bb, ws_entry_bb)) + && workshare_safe_to_combine_p (par_entry_bb, ws_entry_bb) + && (OMP_PARALLEL_COMBINED (last_stmt (par_entry_bb)) + || (last_and_only_stmt (ws_entry_bb) + && last_and_only_stmt (par_exit_bb)))) { - tree ws_stmt = last_stmt (region->inner->entry); + tree ws_stmt = last_stmt (ws_entry_bb); if (region->inner->type == OMP_FOR) { /* If this is a combined parallel loop, we need to determine @@ -4060,6 +4065,28 @@ lower_omp_for (tree *stmt_p, omp_context *stmt_p = new_stmt; } +/* Callback for walk_stmts. Check if *TP only contains OMP_FOR + or OMP_PARALLEL. */ + +static tree +check_combined_parallel (tree *tp, int *walk_subtrees, void *data) +{ + struct walk_stmt_info *wi = data; + int *info = wi->info; + + *walk_subtrees = 0; + switch (TREE_CODE (*tp)) + { + case OMP_FOR: + case OMP_SECTIONS: + *info = *info == 0 ? 1 : -1; + break; + default: + *info = -1; + break; + } + return NULL; +} /* Lower the OpenMP parallel directive in *STMT_P. CTX holds context information for the directive. */ @@ -4077,6 +4104,19 @@ lower_omp_parallel (tree *stmt_p, omp_co par_bind = OMP_PARALLEL_BODY (stmt); par_body = BIND_EXPR_BODY (par_bind); child_fn = ctx->cb.dst_fn; + if (!OMP_PARALLEL_COMBINED (stmt)) + { + struct walk_stmt_info wi; + int ws_num = 0; + + memset (&wi, 0, sizeof (wi)); + wi.callback = check_combined_parallel; + wi.info = &ws_num; + wi.val_only = true; + walk_stmts (&wi, &par_bind); + if (ws_num == 1) + OMP_PARALLEL_COMBINED (stmt) = 1; + } push_gimplify_context (); --- gcc/testsuite/gcc.dg/gomp/pr32468-1.c.jj 2007-06-25 21:04:31.000000000 +0200 +++ gcc/testsuite/gcc.dg/gomp/pr32468-1.c 2007-06-25 21:07:35.000000000 +0200 @@ -0,0 +1,100 @@ +/* PR libgomp/32468 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fopenmp -fdump-tree-ompexp" } */ + +extern int printf (const char *, ...); +extern int omp_get_thread_num (void), omp_get_num_threads (void); +extern int bar (void); +extern int baz (const char *, ...); + +void +f1 (void) +{ +#pragma omp parallel + { + baz ("%d/%d\n", omp_get_thread_num (), omp_get_num_threads ()); + #pragma omp sections + { + #pragma omp section + printf ("section1 %d/%d\n", omp_get_thread_num (), omp_get_num_threads ()); + #pragma omp section + printf ("section2 %d/%d\n", omp_get_thread_num (), omp_get_num_threads ()); + } + } +} + +void +f2 (void) +{ +#pragma omp parallel + { + #pragma omp sections + { + #pragma omp section + printf ("section1 %d/%d\n", omp_get_thread_num (), omp_get_num_threads ()); + #pragma omp section + printf ("section2 %d/%d\n", omp_get_thread_num (), omp_get_num_threads ()); + } + baz ("%d/%d\n", omp_get_thread_num (), omp_get_num_threads ()); + } +} + +void +f3 (void) +{ +#pragma omp parallel + { + int bb = bar (); + #pragma omp sections + { + #pragma omp section + printf ("section1 %d/%d\n", omp_get_thread_num (), omp_get_num_threads ()); + #pragma omp section + printf ("section2 %d/%d\n", omp_get_thread_num (), omp_get_num_threads ()); + } + } +} + +void +f4 (void) +{ + int i; +#pragma omp parallel + { + baz ("%d/%d\n", omp_get_thread_num (), omp_get_num_threads ()); + #pragma omp for schedule (dynamic, 15) + for (i = 0; i < 10000; i++) + printf ("section1 %d/%d\n", omp_get_thread_num (), omp_get_num_threads ()); + } +} + +void +f5 (void) +{ + int i; +#pragma omp parallel + { + #pragma omp for schedule (dynamic, 15) + for (i = 0; i < 10000; i++) + printf ("section1 %d/%d\n", omp_get_thread_num (), omp_get_num_threads ()); + baz ("%d/%d\n", omp_get_thread_num (), omp_get_num_threads ()); + } +} + +void +f6 (void) +{ + int i; +#pragma omp parallel + { + int bb = bar (); + #pragma omp for schedule (runtime) + for (i = 0; i < 10000; i++) + printf ("section1 %d/%d\n", omp_get_thread_num (), omp_get_num_threads ()); + } +} + +/* There should not be a GOMP_parallel_{loop,sections}* call. */ +/* { dg-final { scan-tree-dump-times "GOMP_parallel_loop" 0 "ompexp"} } */ +/* { dg-final { scan-tree-dump-times "GOMP_parallel_sections" 0 "ompexp"} } */ +/* { dg-final { cleanup-tree-dump "ompexp" } } */ Jakub