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
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;
}