I hit a problem in on one of my reduction test cases where the GOACC_JOIN was getting cloned. Nvptx requires FORK and JOIN to be single-entry, single-exit regions, or some form of thread divergence may occur. When that happens, we cannot use the shfl instruction for reductions or broadcasting (if the warp is divergent), and it may cause problems with synchronization in general.
Nathan ran into a similar problem in one of the ssa passes when he added support for predication in the nvptx backend. Part of his solution was to add a gimple_call_internal_unique_p function to determine if internal functions are safe to be cloned. This patch teaches the tracer to scan each basic block for internal function calls using gimple_call_internal_unique_p, and mark the blocks that contain certain OpenACC internal functions calls as ignored. It is a shame that gimple_statement_iterators do not play nicely with const_basic_block. Is this patch ok for gomp-4_0-branch? Cesar
2015-08-25 Cesar Philippidis <ce...@codesourcery.com> gcc/ * tracer.c (ignore_bb_p): Change bb argument from const_basic_block to basic_block. Check for non-clonable calls to internal functions. diff --git a/gcc/tracer.c b/gcc/tracer.c index cad7ab1..f20c158 100644 --- a/gcc/tracer.c +++ b/gcc/tracer.c @@ -58,7 +58,7 @@ #include "fibonacci_heap.h" static int count_insns (basic_block); -static bool ignore_bb_p (const_basic_block); +static bool ignore_bb_p (basic_block); static bool better_p (const_edge, const_edge); static edge find_best_successor (basic_block); static edge find_best_predecessor (basic_block); @@ -91,8 +91,9 @@ bb_seen_p (basic_block bb) /* Return true if we should ignore the basic block for purposes of tracing. */ static bool -ignore_bb_p (const_basic_block bb) +ignore_bb_p (basic_block bb) { + gimple_stmt_iterator gsi; gimple g; if (bb->index < NUM_FIXED_BLOCKS) @@ -106,6 +107,16 @@ ignore_bb_p (const_basic_block bb) if (g && gimple_code (g) == GIMPLE_TRANSACTION) return true; + /* Ignore blocks containing non-clonable function calls. */ + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + g = gsi_stmt (gsi); + + if (is_gimple_call (g) && gimple_call_internal_p (g) + && gimple_call_internal_unique_p (g)) + return true; + } + return false; }