Commit 917948d3 by Zdenek Dvorak Committed by Zdenek Dvorak

cgraphbuild.c (rebuild_cgraph_edges): Export.

	* cgraphbuild.c (rebuild_cgraph_edges): Export.
	* cgraph.h (rebuild_cgraph_edges): Declare.
	* tree-pass.h (pass_expand_omp_ssa): New.
	* omp-low.c (find_omp_clause): Export.
	(copy_var_decl): Split from omp_copy_decl_2.
	(build_omp_barrier): Return the call to emit instead of emitting
	it directly.
	(lower_rec_input_clauses, expand_omp_single): Gimplify the result of
	build_omp_barrier.
	(extract_omp_for_data, expand_parallel_call, expand_omp_parallel,
	expand_omp_for_generic, expand_omp_for_static_nochunk,
	expand_omp_for_static_chunk, expand_omp_for, expand_omp_sections):
	Adapted to work on SSA form.
	(execute_expand_omp): Do not invalidate dominance information.
	(gate_expand_omp): Do not run with -fopenmp-ssa flag.
	(gate_expand_omp_ssa, pass_expand_omp_ssa): New.
	* gimplify.c (gimplify_omp_for): Ensure that the control variable is
	a gimple_reg.
	(force_gimple_operand): Allow gimplifying code expressions without
	value.
	* tree-predcom.c (mark_virtual_ops_for_renaming): Handle phi nodes.
	* common.opt (fopenmp-ssa): New.
	* tree-flow.h (find_omp_clause, copy_var_decl): Declare.
	* Makefile.in (tree-cfg.o): Add TREE_INLINE_H dependency.
	* tree-cfg.c: Include tree-inline.h.
	(struct move_stmt_d): Replace vars_to_remove by vars_map field.
	(replace_by_duplicate_decl, replace_ssa_name,
	mark_virtual_ops_in_region): New functions.
	(move_stmt_r, move_block_to_fn, move_sese_region_to_fn): Adapted
	to work on SSA form.
	* passes.c (init_optimization_passes): Add pass_expand_omp_ssa pass.
	* tree-ssa-operands.c (get_expr_operands): Handle operands of OMP
	constructs.

From-SVN: r128223
parent e054e6fb
2007-09-06 Zdenek Dvorak <ook@ucw.cz>
* cgraphbuild.c (rebuild_cgraph_edges): Export.
* cgraph.h (rebuild_cgraph_edges): Declare.
* tree-pass.h (pass_expand_omp_ssa): New.
* omp-low.c (find_omp_clause): Export.
(copy_var_decl): Split from omp_copy_decl_2.
(build_omp_barrier): Return the call to emit instead of emitting
it directly.
(lower_rec_input_clauses, expand_omp_single): Gimplify the result of
build_omp_barrier.
(extract_omp_for_data, expand_parallel_call, expand_omp_parallel,
expand_omp_for_generic, expand_omp_for_static_nochunk,
expand_omp_for_static_chunk, expand_omp_for, expand_omp_sections):
Adapted to work on SSA form.
(execute_expand_omp): Do not invalidate dominance information.
(gate_expand_omp): Do not run with -fopenmp-ssa flag.
(gate_expand_omp_ssa, pass_expand_omp_ssa): New.
* gimplify.c (gimplify_omp_for): Ensure that the control variable is
a gimple_reg.
(force_gimple_operand): Allow gimplifying code expressions without
value.
* tree-predcom.c (mark_virtual_ops_for_renaming): Handle phi nodes.
* common.opt (fopenmp-ssa): New.
* tree-flow.h (find_omp_clause, copy_var_decl): Declare.
* Makefile.in (tree-cfg.o): Add TREE_INLINE_H dependency.
* tree-cfg.c: Include tree-inline.h.
(struct move_stmt_d): Replace vars_to_remove by vars_map field.
(replace_by_duplicate_decl, replace_ssa_name,
mark_virtual_ops_in_region): New functions.
(move_stmt_r, move_block_to_fn, move_sese_region_to_fn): Adapted
to work on SSA form.
* passes.c (init_optimization_passes): Add pass_expand_omp_ssa pass.
* tree-ssa-operands.c (get_expr_operands): Handle operands of OMP
constructs.
2007-09-06 Laurynas Biveinis <laurynas.biveinis@gmail.com> 2007-09-06 Laurynas Biveinis <laurynas.biveinis@gmail.com>
* tree-loop-linear.c: Include obstack.h. * tree-loop-linear.c: Include obstack.h.
...@@ -2079,7 +2079,7 @@ tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ ...@@ -2079,7 +2079,7 @@ tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
$(TREE_DUMP_H) except.h langhooks.h $(CFGLOOP_H) tree-pass.h \ $(TREE_DUMP_H) except.h langhooks.h $(CFGLOOP_H) tree-pass.h \
$(CFGLAYOUT_H) $(BASIC_BLOCK_H) hard-reg-set.h toplev.h \ $(CFGLAYOUT_H) $(BASIC_BLOCK_H) hard-reg-set.h toplev.h \
tree-ssa-propagate.h tree-ssa-propagate.h $(TREE_INLINE_H)
tree-cfgcleanup.o : tree-cfgcleanup.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ tree-cfgcleanup.o : tree-cfgcleanup.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \ $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \
$(DIAGNOSTIC_H) toplev.h $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ $(DIAGNOSTIC_H) toplev.h $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
......
...@@ -344,6 +344,9 @@ struct cgraph_node *save_inline_function_body (struct cgraph_node *); ...@@ -344,6 +344,9 @@ struct cgraph_node *save_inline_function_body (struct cgraph_node *);
void record_references_in_initializer (tree); void record_references_in_initializer (tree);
bool cgraph_process_new_functions (void); bool cgraph_process_new_functions (void);
/* In cgraphbuild.c */
unsigned int rebuild_cgraph_edges (void);
/* In ipa.c */ /* In ipa.c */
bool cgraph_remove_unreachable_nodes (bool, FILE *); bool cgraph_remove_unreachable_nodes (bool, FILE *);
int cgraph_postorder (struct cgraph_node **); int cgraph_postorder (struct cgraph_node **);
......
...@@ -202,7 +202,7 @@ record_references_in_initializer (tree decl) ...@@ -202,7 +202,7 @@ record_references_in_initializer (tree decl)
/* Rebuild cgraph edges for current function node. This needs to be run after /* Rebuild cgraph edges for current function node. This needs to be run after
passes that don't update the cgraph. */ passes that don't update the cgraph. */
static unsigned int unsigned int
rebuild_cgraph_edges (void) rebuild_cgraph_edges (void)
{ {
basic_block bb; basic_block bb;
......
...@@ -709,6 +709,10 @@ fomit-frame-pointer ...@@ -709,6 +709,10 @@ fomit-frame-pointer
Common Report Var(flag_omit_frame_pointer) Optimization Common Report Var(flag_omit_frame_pointer) Optimization
When possible do not generate stack frames When possible do not generate stack frames
fopenmp-ssa
Common Report Var(flag_openmp_ssa)
Expand OpenMP operations on SSA form
foptimize-register-move foptimize-register-move
Common Report Var(flag_regmove) Optimization Common Report Var(flag_regmove) Optimization
Do the full register move optimization pass Do the full register move optimization pass
......
...@@ -5114,8 +5114,9 @@ gimplify_omp_parallel (tree *expr_p, tree *pre_p) ...@@ -5114,8 +5114,9 @@ gimplify_omp_parallel (tree *expr_p, tree *pre_p)
static enum gimplify_status static enum gimplify_status
gimplify_omp_for (tree *expr_p, tree *pre_p) gimplify_omp_for (tree *expr_p, tree *pre_p)
{ {
tree for_stmt, decl, t; tree for_stmt, decl, var, t;
enum gimplify_status ret = GS_OK; enum gimplify_status ret = GS_OK;
tree body, init_decl = NULL_TREE;
for_stmt = *expr_p; for_stmt = *expr_p;
...@@ -5134,6 +5135,20 @@ gimplify_omp_for (tree *expr_p, tree *pre_p) ...@@ -5134,6 +5135,20 @@ gimplify_omp_for (tree *expr_p, tree *pre_p)
else else
omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN); omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN);
/* If DECL is not a gimple register, create a temporary variable to act as an
iteration counter. This is valid, since DECL cannot be modified in the
body of the loop. */
if (!is_gimple_reg (decl))
{
var = create_tmp_var (TREE_TYPE (decl), get_name (decl));
GENERIC_TREE_OPERAND (t, 0) = var;
init_decl = build_gimple_modify_stmt (decl, var);
omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
}
else
var = decl;
ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1), ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
&OMP_FOR_PRE_BODY (for_stmt), &OMP_FOR_PRE_BODY (for_stmt),
NULL, is_gimple_val, fb_rvalue); NULL, is_gimple_val, fb_rvalue);
...@@ -5143,6 +5158,7 @@ gimplify_omp_for (tree *expr_p, tree *pre_p) ...@@ -5143,6 +5158,7 @@ gimplify_omp_for (tree *expr_p, tree *pre_p)
t = OMP_FOR_COND (for_stmt); t = OMP_FOR_COND (for_stmt);
gcc_assert (COMPARISON_CLASS_P (t)); gcc_assert (COMPARISON_CLASS_P (t));
gcc_assert (GENERIC_TREE_OPERAND (t, 0) == decl); gcc_assert (GENERIC_TREE_OPERAND (t, 0) == decl);
TREE_OPERAND (t, 0) = var;
ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1), ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
&OMP_FOR_PRE_BODY (for_stmt), &OMP_FOR_PRE_BODY (for_stmt),
...@@ -5155,21 +5171,23 @@ gimplify_omp_for (tree *expr_p, tree *pre_p) ...@@ -5155,21 +5171,23 @@ gimplify_omp_for (tree *expr_p, tree *pre_p)
case PREINCREMENT_EXPR: case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR: case POSTINCREMENT_EXPR:
t = build_int_cst (TREE_TYPE (decl), 1); t = build_int_cst (TREE_TYPE (decl), 1);
t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t); t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
t = build_gimple_modify_stmt (decl, t); t = build_gimple_modify_stmt (var, t);
OMP_FOR_INCR (for_stmt) = t; OMP_FOR_INCR (for_stmt) = t;
break; break;
case PREDECREMENT_EXPR: case PREDECREMENT_EXPR:
case POSTDECREMENT_EXPR: case POSTDECREMENT_EXPR:
t = build_int_cst (TREE_TYPE (decl), -1); t = build_int_cst (TREE_TYPE (decl), -1);
t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t); t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
t = build_gimple_modify_stmt (decl, t); t = build_gimple_modify_stmt (var, t);
OMP_FOR_INCR (for_stmt) = t; OMP_FOR_INCR (for_stmt) = t;
break; break;
case GIMPLE_MODIFY_STMT: case GIMPLE_MODIFY_STMT:
gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == decl); gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == decl);
GIMPLE_STMT_OPERAND (t, 0) = var;
t = GIMPLE_STMT_OPERAND (t, 1); t = GIMPLE_STMT_OPERAND (t, 1);
switch (TREE_CODE (t)) switch (TREE_CODE (t))
{ {
...@@ -5177,11 +5195,14 @@ gimplify_omp_for (tree *expr_p, tree *pre_p) ...@@ -5177,11 +5195,14 @@ gimplify_omp_for (tree *expr_p, tree *pre_p)
if (TREE_OPERAND (t, 1) == decl) if (TREE_OPERAND (t, 1) == decl)
{ {
TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0); TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0);
TREE_OPERAND (t, 0) = decl; TREE_OPERAND (t, 0) = var;
break; break;
} }
/* Fallthru. */
case MINUS_EXPR: case MINUS_EXPR:
gcc_assert (TREE_OPERAND (t, 0) == decl); gcc_assert (TREE_OPERAND (t, 0) == decl);
TREE_OPERAND (t, 0) = var;
break; break;
default: default:
gcc_unreachable (); gcc_unreachable ();
...@@ -5195,7 +5216,13 @@ gimplify_omp_for (tree *expr_p, tree *pre_p) ...@@ -5195,7 +5216,13 @@ gimplify_omp_for (tree *expr_p, tree *pre_p)
gcc_unreachable (); gcc_unreachable ();
} }
gimplify_to_stmt_list (&OMP_FOR_BODY (for_stmt)); body = OMP_FOR_BODY (for_stmt);
gimplify_to_stmt_list (&body);
t = alloc_stmt_list ();
if (init_decl)
append_to_statement_list (init_decl, &t);
append_to_statement_list (body, &t);
OMP_FOR_BODY (for_stmt) = t;
gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt)); gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt));
return ret == GS_ALL_DONE ? GS_ALL_DONE : GS_ERROR; return ret == GS_ALL_DONE ? GS_ALL_DONE : GS_ERROR;
...@@ -6591,9 +6618,18 @@ force_gimple_operand (tree expr, tree *stmts, bool simple, tree var) ...@@ -6591,9 +6618,18 @@ force_gimple_operand (tree expr, tree *stmts, bool simple, tree var)
if (var) if (var)
expr = build_gimple_modify_stmt (var, expr); expr = build_gimple_modify_stmt (var, expr);
ret = gimplify_expr (&expr, stmts, NULL, if (TREE_CODE (expr) != GIMPLE_MODIFY_STMT
gimple_test_f, fb_rvalue); && TREE_TYPE (expr) == void_type_node)
gcc_assert (ret != GS_ERROR); {
gimplify_and_add (expr, stmts);
expr = NULL_TREE;
}
else
{
ret = gimplify_expr (&expr, stmts, NULL,
gimple_test_f, fb_rvalue);
gcc_assert (ret != GS_ERROR);
}
if (gimple_referenced_vars (cfun)) if (gimple_referenced_vars (cfun))
{ {
......
...@@ -117,7 +117,7 @@ static tree maybe_lookup_decl_in_outer_ctx (tree, omp_context *); ...@@ -117,7 +117,7 @@ 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. */
static tree tree
find_omp_clause (tree clauses, enum tree_code kind) find_omp_clause (tree clauses, enum tree_code kind)
{ {
for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses)) for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses))
...@@ -151,7 +151,7 @@ is_combined_parallel (struct omp_region *region) ...@@ -151,7 +151,7 @@ is_combined_parallel (struct omp_region *region)
static void static void
extract_omp_for_data (tree for_stmt, struct omp_for_data *fd) extract_omp_for_data (tree for_stmt, struct omp_for_data *fd)
{ {
tree t; tree t, var;
fd->for_stmt = for_stmt; fd->for_stmt = for_stmt;
fd->pre = NULL; fd->pre = NULL;
...@@ -159,13 +159,14 @@ extract_omp_for_data (tree for_stmt, struct omp_for_data *fd) ...@@ -159,13 +159,14 @@ extract_omp_for_data (tree for_stmt, struct omp_for_data *fd)
t = OMP_FOR_INIT (for_stmt); t = OMP_FOR_INIT (for_stmt);
gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT); gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
fd->v = GIMPLE_STMT_OPERAND (t, 0); fd->v = GIMPLE_STMT_OPERAND (t, 0);
gcc_assert (DECL_P (fd->v)); gcc_assert (SSA_VAR_P (fd->v));
gcc_assert (TREE_CODE (TREE_TYPE (fd->v)) == INTEGER_TYPE); gcc_assert (TREE_CODE (TREE_TYPE (fd->v)) == INTEGER_TYPE);
var = TREE_CODE (fd->v) == SSA_NAME ? SSA_NAME_VAR (fd->v) : fd->v;
fd->n1 = GIMPLE_STMT_OPERAND (t, 1); fd->n1 = GIMPLE_STMT_OPERAND (t, 1);
t = OMP_FOR_COND (for_stmt); t = OMP_FOR_COND (for_stmt);
fd->cond_code = TREE_CODE (t); fd->cond_code = TREE_CODE (t);
gcc_assert (TREE_OPERAND (t, 0) == fd->v); gcc_assert (TREE_OPERAND (t, 0) == var);
fd->n2 = TREE_OPERAND (t, 1); fd->n2 = TREE_OPERAND (t, 1);
switch (fd->cond_code) switch (fd->cond_code)
{ {
...@@ -188,9 +189,9 @@ extract_omp_for_data (tree for_stmt, struct omp_for_data *fd) ...@@ -188,9 +189,9 @@ extract_omp_for_data (tree for_stmt, struct omp_for_data *fd)
t = OMP_FOR_INCR (fd->for_stmt); t = OMP_FOR_INCR (fd->for_stmt);
gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT); gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == fd->v); gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == var);
t = GIMPLE_STMT_OPERAND (t, 1); t = GIMPLE_STMT_OPERAND (t, 1);
gcc_assert (TREE_OPERAND (t, 0) == fd->v); gcc_assert (TREE_OPERAND (t, 0) == var);
switch (TREE_CODE (t)) switch (TREE_CODE (t))
{ {
case PLUS_EXPR: case PLUS_EXPR:
...@@ -513,22 +514,34 @@ use_pointer_for_field (const_tree decl, bool shared_p) ...@@ -513,22 +514,34 @@ use_pointer_for_field (const_tree decl, bool shared_p)
return false; return false;
} }
/* Construct a new automatic decl similar to VAR. */ /* Create a new VAR_DECL and copy information from VAR to it. */
static tree tree
omp_copy_decl_2 (tree var, tree name, tree type, omp_context *ctx) copy_var_decl (tree var, tree name, tree type)
{ {
tree copy = build_decl (VAR_DECL, name, type); tree copy = build_decl (VAR_DECL, name, type);
TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var); TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var);
TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (var);
DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var); DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var);
DECL_NO_TBAA_P (copy) = DECL_NO_TBAA_P (var); DECL_NO_TBAA_P (copy) = DECL_NO_TBAA_P (var);
DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var); DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var);
DECL_IGNORED_P (copy) = DECL_IGNORED_P (var); DECL_IGNORED_P (copy) = DECL_IGNORED_P (var);
DECL_CONTEXT (copy) = DECL_CONTEXT (var);
TREE_USED (copy) = 1; TREE_USED (copy) = 1;
DECL_CONTEXT (copy) = current_function_decl;
DECL_SEEN_IN_BIND_EXPR_P (copy) = 1; DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
return copy;
}
/* Construct a new automatic decl similar to VAR. */
static tree
omp_copy_decl_2 (tree var, tree name, tree type, omp_context *ctx)
{
tree copy = copy_var_decl (var, name, type);
DECL_CONTEXT (copy) = current_function_decl;
TREE_CHAIN (copy) = ctx->block_vars; TREE_CHAIN (copy) = ctx->block_vars;
ctx->block_vars = copy; ctx->block_vars = copy;
...@@ -1432,11 +1445,10 @@ scan_omp (tree *stmt_p, omp_context *ctx) ...@@ -1432,11 +1445,10 @@ scan_omp (tree *stmt_p, omp_context *ctx)
/* Build a call to GOMP_barrier. */ /* Build a call to GOMP_barrier. */
static void static tree
build_omp_barrier (tree *stmt_list) build_omp_barrier (void)
{ {
tree t = build_call_expr (built_in_decls[BUILT_IN_GOMP_BARRIER], 0); return build_call_expr (built_in_decls[BUILT_IN_GOMP_BARRIER], 0);
gimplify_and_add (t, stmt_list);
} }
/* If a context was created for STMT when it was scanned, return it. */ /* If a context was created for STMT when it was scanned, return it. */
...@@ -1829,7 +1841,7 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist, ...@@ -1829,7 +1841,7 @@ lower_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
lastprivate clauses we need to ensure the lastprivate copying lastprivate clauses we need to ensure the lastprivate copying
happens after firstprivate copying in all threads. */ happens after firstprivate copying in all threads. */
if (copyin_by_ref || lastprivate_firstprivate) if (copyin_by_ref || lastprivate_firstprivate)
build_omp_barrier (ilist); gimplify_and_add (build_omp_barrier (), ilist);
} }
...@@ -2153,12 +2165,11 @@ static void ...@@ -2153,12 +2165,11 @@ static void
expand_parallel_call (struct omp_region *region, basic_block bb, expand_parallel_call (struct omp_region *region, basic_block bb,
tree entry_stmt, tree ws_args) tree entry_stmt, tree ws_args)
{ {
tree t, t1, t2, val, cond, c, list, clauses; tree t, t1, t2, val, cond, c, clauses;
block_stmt_iterator si; block_stmt_iterator si;
int start_ix; int start_ix;
clauses = OMP_PARALLEL_CLAUSES (entry_stmt); clauses = OMP_PARALLEL_CLAUSES (entry_stmt);
push_gimplify_context ();
/* Determine what flavor of GOMP_parallel_start we will be /* Determine what flavor of GOMP_parallel_start we will be
emitting. */ emitting. */
...@@ -2204,15 +2215,28 @@ expand_parallel_call (struct omp_region *region, basic_block bb, ...@@ -2204,15 +2215,28 @@ expand_parallel_call (struct omp_region *region, basic_block bb,
cond = gimple_boolify (cond); cond = gimple_boolify (cond);
if (integer_zerop (val)) if (integer_zerop (val))
val = build2 (EQ_EXPR, unsigned_type_node, cond, val = fold_build2 (EQ_EXPR, unsigned_type_node, cond,
build_int_cst (TREE_TYPE (cond), 0)); build_int_cst (TREE_TYPE (cond), 0));
else else
{ {
basic_block cond_bb, then_bb, else_bb; basic_block cond_bb, then_bb, else_bb;
edge e; edge e, e_then, e_else;
tree t, tmp; tree t, tmp_then, tmp_else, tmp_join, tmp_var;
tmp_var = create_tmp_var (TREE_TYPE (val), NULL);
if (gimple_in_ssa_p (cfun))
{
tmp_then = make_ssa_name (tmp_var, NULL_TREE);
tmp_else = make_ssa_name (tmp_var, NULL_TREE);
tmp_join = make_ssa_name (tmp_var, NULL_TREE);
}
else
{
tmp_then = tmp_var;
tmp_else = tmp_var;
tmp_join = tmp_var;
}
tmp = create_tmp_var (TREE_TYPE (val), NULL);
e = split_block (bb, NULL); e = split_block (bb, NULL);
cond_bb = e->src; cond_bb = e->src;
bb = e->dest; bb = e->dest;
...@@ -2220,6 +2244,8 @@ expand_parallel_call (struct omp_region *region, basic_block bb, ...@@ -2220,6 +2244,8 @@ expand_parallel_call (struct omp_region *region, basic_block bb,
then_bb = create_empty_bb (cond_bb); then_bb = create_empty_bb (cond_bb);
else_bb = create_empty_bb (then_bb); else_bb = create_empty_bb (then_bb);
set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
set_immediate_dominator (CDI_DOMINATORS, else_bb, cond_bb);
t = build3 (COND_EXPR, void_type_node, t = build3 (COND_EXPR, void_type_node,
cond, NULL_TREE, NULL_TREE); cond, NULL_TREE, NULL_TREE);
...@@ -2228,29 +2254,40 @@ expand_parallel_call (struct omp_region *region, basic_block bb, ...@@ -2228,29 +2254,40 @@ expand_parallel_call (struct omp_region *region, basic_block bb,
bsi_insert_after (&si, t, BSI_CONTINUE_LINKING); bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
si = bsi_start (then_bb); si = bsi_start (then_bb);
t = build_gimple_modify_stmt (tmp, val); t = build_gimple_modify_stmt (tmp_then, val);
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (tmp_then) = t;
bsi_insert_after (&si, t, BSI_CONTINUE_LINKING); bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
si = bsi_start (else_bb); si = bsi_start (else_bb);
t = build_gimple_modify_stmt (tmp, t = build_gimple_modify_stmt (tmp_else,
build_int_cst (unsigned_type_node, 1)); build_int_cst (unsigned_type_node, 1));
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (tmp_else) = t;
bsi_insert_after (&si, t, BSI_CONTINUE_LINKING); bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE); make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
make_edge (cond_bb, else_bb, EDGE_FALSE_VALUE); make_edge (cond_bb, else_bb, EDGE_FALSE_VALUE);
make_edge (then_bb, bb, EDGE_FALLTHRU); e_then = make_edge (then_bb, bb, EDGE_FALLTHRU);
make_edge (else_bb, bb, EDGE_FALLTHRU); e_else = make_edge (else_bb, bb, EDGE_FALLTHRU);
val = tmp; if (gimple_in_ssa_p (cfun))
{
tree phi = create_phi_node (tmp_join, bb);
SSA_NAME_DEF_STMT (tmp_join) = phi;
add_phi_arg (phi, tmp_then, e_then);
add_phi_arg (phi, tmp_else, e_else);
}
val = tmp_join;
} }
list = NULL_TREE;
val = get_formal_tmp_var (val, &list);
si = bsi_start (bb); si = bsi_start (bb);
bsi_insert_after (&si, list, BSI_CONTINUE_LINKING); val = force_gimple_operand_bsi (&si, val, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
} }
list = NULL_TREE; si = bsi_last (bb);
t = OMP_PARALLEL_DATA_ARG (entry_stmt); t = OMP_PARALLEL_DATA_ARG (entry_stmt);
if (t == NULL) if (t == NULL)
t1 = null_pointer_node; t1 = null_pointer_node;
...@@ -2268,7 +2305,8 @@ expand_parallel_call (struct omp_region *region, basic_block bb, ...@@ -2268,7 +2305,8 @@ expand_parallel_call (struct omp_region *region, basic_block bb,
else else
t = build_call_expr (built_in_decls[start_ix], 3, t2, t1, val); t = build_call_expr (built_in_decls[start_ix], 3, t2, t1, val);
gimplify_and_add (t, &list); force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
t = OMP_PARALLEL_DATA_ARG (entry_stmt); t = OMP_PARALLEL_DATA_ARG (entry_stmt);
if (t == NULL) if (t == NULL)
...@@ -2276,15 +2314,12 @@ expand_parallel_call (struct omp_region *region, basic_block bb, ...@@ -2276,15 +2314,12 @@ expand_parallel_call (struct omp_region *region, basic_block bb,
else else
t = build_fold_addr_expr (t); t = build_fold_addr_expr (t);
t = build_call_expr (OMP_PARALLEL_FN (entry_stmt), 1, t); t = build_call_expr (OMP_PARALLEL_FN (entry_stmt), 1, t);
gimplify_and_add (t, &list); force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
t = build_call_expr (built_in_decls[BUILT_IN_GOMP_PARALLEL_END], 0); t = build_call_expr (built_in_decls[BUILT_IN_GOMP_PARALLEL_END], 0);
gimplify_and_add (t, &list); force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
si = bsi_last (bb);
bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
pop_gimplify_context (NULL_TREE);
} }
...@@ -2408,7 +2443,6 @@ expand_omp_parallel (struct omp_region *region) ...@@ -2408,7 +2443,6 @@ expand_omp_parallel (struct omp_region *region)
block_stmt_iterator si; block_stmt_iterator si;
tree entry_stmt; tree entry_stmt;
edge e; edge e;
bool do_cleanup_cfg = false;
entry_stmt = last_stmt (region->entry); entry_stmt = last_stmt (region->entry);
child_fn = OMP_PARALLEL_FN (entry_stmt); child_fn = OMP_PARALLEL_FN (entry_stmt);
...@@ -2437,13 +2471,12 @@ expand_omp_parallel (struct omp_region *region) ...@@ -2437,13 +2471,12 @@ expand_omp_parallel (struct omp_region *region)
bsi_remove (&si, true); bsi_remove (&si, true);
new_bb = entry_bb; new_bb = entry_bb;
remove_edge (entry_succ_e);
if (exit_bb) if (exit_bb)
{ {
exit_succ_e = single_succ_edge (exit_bb); exit_succ_e = single_succ_edge (exit_bb);
make_edge (new_bb, exit_succ_e->dest, EDGE_FALLTHRU); make_edge (new_bb, exit_succ_e->dest, EDGE_FALLTHRU);
} }
do_cleanup_cfg = true; remove_edge_and_dominated_blocks (entry_succ_e);
} }
else else
{ {
...@@ -2464,6 +2497,7 @@ expand_omp_parallel (struct omp_region *region) ...@@ -2464,6 +2497,7 @@ expand_omp_parallel (struct omp_region *region)
{ {
basic_block entry_succ_bb = single_succ (entry_bb); basic_block entry_succ_bb = single_succ (entry_bb);
block_stmt_iterator si; block_stmt_iterator si;
tree parcopy_stmt = NULL_TREE, arg, narg;
for (si = bsi_start (entry_succ_bb); ; bsi_next (&si)) for (si = bsi_start (entry_succ_bb); ; bsi_next (&si))
{ {
...@@ -2480,14 +2514,32 @@ expand_omp_parallel (struct omp_region *region) ...@@ -2480,14 +2514,32 @@ expand_omp_parallel (struct omp_region *region)
&& TREE_OPERAND (arg, 0) && TREE_OPERAND (arg, 0)
== OMP_PARALLEL_DATA_ARG (entry_stmt)) == OMP_PARALLEL_DATA_ARG (entry_stmt))
{ {
if (GIMPLE_STMT_OPERAND (stmt, 0) parcopy_stmt = stmt;
== DECL_ARGUMENTS (child_fn))
bsi_remove (&si, true);
else
GIMPLE_STMT_OPERAND (stmt, 1) = DECL_ARGUMENTS (child_fn);
break; break;
} }
} }
gcc_assert (parcopy_stmt != NULL_TREE);
arg = DECL_ARGUMENTS (child_fn);
if (!gimple_in_ssa_p (cfun))
{
if (GIMPLE_STMT_OPERAND (parcopy_stmt, 0) == arg)
bsi_remove (&si, true);
else
GIMPLE_STMT_OPERAND (parcopy_stmt, 1) = arg;
}
else
{
/* If we are in ssa form, we must load the value from the default
definition of the argument. That should not be defined now,
since the argument is not used uninitialized. */
gcc_assert (gimple_default_def (cfun, arg) == NULL);
narg = make_ssa_name (arg, build_empty_stmt ());
set_default_def (arg, narg);
GIMPLE_STMT_OPERAND (parcopy_stmt, 1) = narg;
update_stmt (parcopy_stmt);
}
} }
/* Declare local variables needed in CHILD_CFUN. */ /* Declare local variables needed in CHILD_CFUN. */
...@@ -2495,10 +2547,7 @@ expand_omp_parallel (struct omp_region *region) ...@@ -2495,10 +2547,7 @@ expand_omp_parallel (struct omp_region *region)
BLOCK_VARS (block) = list2chain (child_cfun->unexpanded_var_list); BLOCK_VARS (block) = list2chain (child_cfun->unexpanded_var_list);
DECL_SAVED_TREE (child_fn) = bb_stmt_list (single_succ (entry_bb)); DECL_SAVED_TREE (child_fn) = bb_stmt_list (single_succ (entry_bb));
/* Reset DECL_CONTEXT on locals and function arguments. */ /* Reset DECL_CONTEXT on function arguments. */
for (t = BLOCK_VARS (block); t; t = TREE_CHAIN (t))
DECL_CONTEXT (t) = child_fn;
for (t = DECL_ARGUMENTS (child_fn); t; t = TREE_CHAIN (t)) for (t = DECL_ARGUMENTS (child_fn); t; t = TREE_CHAIN (t))
DECL_CONTEXT (t) = child_fn; DECL_CONTEXT (t) = child_fn;
...@@ -2512,17 +2561,6 @@ expand_omp_parallel (struct omp_region *region) ...@@ -2512,17 +2561,6 @@ expand_omp_parallel (struct omp_region *region)
entry_bb = e->dest; entry_bb = e->dest;
single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU; single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
/* Move the parallel region into CHILD_CFUN. We need to reset
dominance information because the expansion of the inner
regions has invalidated it. */
free_dominance_info (CDI_DOMINATORS);
new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb);
if (exit_bb)
single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
DECL_STRUCT_FUNCTION (child_fn)->curr_properties
= cfun->curr_properties;
cgraph_add_new_function (child_fn, true);
/* Convert OMP_RETURN into a RETURN_EXPR. */ /* Convert OMP_RETURN into a RETURN_EXPR. */
if (exit_bb) if (exit_bb)
{ {
...@@ -2533,18 +2571,35 @@ expand_omp_parallel (struct omp_region *region) ...@@ -2533,18 +2571,35 @@ expand_omp_parallel (struct omp_region *region)
bsi_insert_after (&si, t, BSI_SAME_STMT); bsi_insert_after (&si, t, BSI_SAME_STMT);
bsi_remove (&si, true); bsi_remove (&si, true);
} }
/* Move the parallel region into CHILD_CFUN. */
if (gimple_in_ssa_p (cfun))
{
push_cfun (child_cfun);
init_tree_ssa ();
init_ssa_operands ();
cfun->gimple_df->in_ssa_p = true;
pop_cfun ();
}
new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb);
if (exit_bb)
single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
/* Inform the callgraph about the new function. */
DECL_STRUCT_FUNCTION (child_fn)->curr_properties
= cfun->curr_properties;
cgraph_add_new_function (child_fn, true);
/* Fix the callgraph edges for child_cfun. Those for cfun will be
fixed in a following pass. */
push_cfun (child_cfun);
rebuild_cgraph_edges ();
pop_cfun ();
} }
/* Emit a library call to launch the children threads. */ /* Emit a library call to launch the children threads. */
expand_parallel_call (region, new_bb, entry_stmt, ws_args); expand_parallel_call (region, new_bb, entry_stmt, ws_args);
if (do_cleanup_cfg)
{
/* Clean up the unreachable sub-graph we created above. */
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
cleanup_tree_cfg ();
}
} }
...@@ -2569,7 +2624,7 @@ expand_omp_parallel (struct omp_region *region) ...@@ -2569,7 +2624,7 @@ expand_omp_parallel (struct omp_region *region)
L3: L3:
If this is a combined omp parallel loop, instead of the call to If this is a combined omp parallel loop, instead of the call to
GOMP_loop_foo_start, we emit 'goto L2'. */ GOMP_loop_foo_start, we call GOMP_loop_foo_next. */
static void static void
expand_omp_for_generic (struct omp_region *region, expand_omp_for_generic (struct omp_region *region,
...@@ -2577,13 +2632,14 @@ expand_omp_for_generic (struct omp_region *region, ...@@ -2577,13 +2632,14 @@ expand_omp_for_generic (struct omp_region *region,
enum built_in_function start_fn, enum built_in_function start_fn,
enum built_in_function next_fn) enum built_in_function next_fn)
{ {
tree type, istart0, iend0, iend; tree type, istart0, iend0, iend, phi;
tree t, list; tree t, vmain, vback;
basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb; basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb;
basic_block l2_bb = NULL, l3_bb = NULL; basic_block l2_bb = NULL, l3_bb = NULL;
block_stmt_iterator si; block_stmt_iterator si;
bool in_combined_parallel = is_combined_parallel (region); bool in_combined_parallel = is_combined_parallel (region);
bool broken_loop = region->cont == NULL; bool broken_loop = region->cont == NULL;
edge e, ne;
gcc_assert (!broken_loop || !in_combined_parallel); gcc_assert (!broken_loop || !in_combined_parallel);
...@@ -2591,9 +2647,13 @@ expand_omp_for_generic (struct omp_region *region, ...@@ -2591,9 +2647,13 @@ expand_omp_for_generic (struct omp_region *region,
istart0 = create_tmp_var (long_integer_type_node, ".istart0"); istart0 = create_tmp_var (long_integer_type_node, ".istart0");
iend0 = create_tmp_var (long_integer_type_node, ".iend0"); iend0 = create_tmp_var (long_integer_type_node, ".iend0");
iend = create_tmp_var (type, NULL);
TREE_ADDRESSABLE (istart0) = 1; TREE_ADDRESSABLE (istart0) = 1;
TREE_ADDRESSABLE (iend0) = 1; TREE_ADDRESSABLE (iend0) = 1;
if (gimple_in_ssa_p (cfun))
{
add_referenced_var (istart0);
add_referenced_var (iend0);
}
entry_bb = region->entry; entry_bb = region->entry;
cont_bb = region->cont; cont_bb = region->cont;
...@@ -2615,12 +2675,19 @@ expand_omp_for_generic (struct omp_region *region, ...@@ -2615,12 +2675,19 @@ expand_omp_for_generic (struct omp_region *region,
si = bsi_last (entry_bb); si = bsi_last (entry_bb);
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR); gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
if (!in_combined_parallel) if (in_combined_parallel)
{
/* In a combined parallel loop, emit a call to
GOMP_loop_foo_next. */
t = build_call_expr (built_in_decls[next_fn], 2,
build_fold_addr_expr (istart0),
build_fold_addr_expr (iend0));
}
else
{ {
tree t0, t1, t2, t3, t4; tree t0, t1, t2, t3, t4;
/* If this is not a combined parallel loop, emit a call to /* If this is not a combined parallel loop, emit a call to
GOMP_loop_foo_start in ENTRY_BB. */ GOMP_loop_foo_start in ENTRY_BB. */
list = alloc_stmt_list ();
t4 = build_fold_addr_expr (iend0); t4 = build_fold_addr_expr (iend0);
t3 = build_fold_addr_expr (istart0); t3 = build_fold_addr_expr (istart0);
t2 = fold_convert (long_integer_type_node, fd->step); t2 = fold_convert (long_integer_type_node, fd->step);
...@@ -2635,58 +2702,80 @@ expand_omp_for_generic (struct omp_region *region, ...@@ -2635,58 +2702,80 @@ expand_omp_for_generic (struct omp_region *region,
else else
t = build_call_expr (built_in_decls[start_fn], 5, t = build_call_expr (built_in_decls[start_fn], 5,
t0, t1, t2, t3, t4); t0, t1, t2, t3, t4);
t = get_formal_tmp_var (t, &list);
t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
append_to_statement_list (t, &list);
bsi_insert_after (&si, list, BSI_SAME_STMT);
} }
t = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
true, BSI_SAME_STMT);
t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
bsi_insert_after (&si, t, BSI_SAME_STMT);
/* V may be used outside of the loop (e.g., to handle lastprivate clause).
If this is the case, its value is undefined if the loop is not entered
at all. To handle this case, set its initial value to N1. */
if (gimple_in_ssa_p (cfun))
{
e = find_edge (entry_bb, l3_bb);
for (phi = phi_nodes (l3_bb); phi; phi = PHI_CHAIN (phi))
if (PHI_ARG_DEF_FROM_EDGE (phi, e) == fd->v)
SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), fd->n1);
}
else
{
t = build_gimple_modify_stmt (fd->v, fd->n1);
bsi_insert_before (&si, t, BSI_SAME_STMT);
}
/* Remove the OMP_FOR statement. */
bsi_remove (&si, true); bsi_remove (&si, true);
/* Iteration setup for sequential loop goes in L0_BB. */ /* Iteration setup for sequential loop goes in L0_BB. */
list = alloc_stmt_list (); si = bsi_start (l0_bb);
t = fold_convert (type, istart0); t = fold_convert (type, istart0);
t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
false, BSI_CONTINUE_LINKING);
t = build_gimple_modify_stmt (fd->v, t); t = build_gimple_modify_stmt (fd->v, t);
gimplify_and_add (t, &list); bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (fd->v) = t;
t = fold_convert (type, iend0); t = fold_convert (type, iend0);
t = build_gimple_modify_stmt (iend, t); iend = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
gimplify_and_add (t, &list); false, BSI_CONTINUE_LINKING);
si = bsi_start (l0_bb);
bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
if (!broken_loop) if (!broken_loop)
{ {
/* Code to control the increment and predicate for the sequential /* Code to control the increment and predicate for the sequential
loop goes in the CONT_BB. */ loop goes in the CONT_BB. */
list = alloc_stmt_list (); si = bsi_last (cont_bb);
t = bsi_stmt (si);
t = build2 (PLUS_EXPR, type, fd->v, fd->step); gcc_assert (TREE_CODE (t) == OMP_CONTINUE);
t = build_gimple_modify_stmt (fd->v, t); vmain = TREE_OPERAND (t, 1);
gimplify_and_add (t, &list); vback = TREE_OPERAND (t, 0);
t = fold_build2 (PLUS_EXPR, type, vmain, fd->step);
t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
true, BSI_SAME_STMT);
t = build_gimple_modify_stmt (vback, t);
bsi_insert_before (&si, t, BSI_SAME_STMT);
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (vback) = t;
t = build2 (fd->cond_code, boolean_type_node, fd->v, iend); t = build2 (fd->cond_code, boolean_type_node, vback, iend);
t = get_formal_tmp_var (t, &list);
t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE); t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
append_to_statement_list (t, &list); bsi_insert_before (&si, t, BSI_SAME_STMT);
si = bsi_last (cont_bb); /* Remove OMP_CONTINUE. */
bsi_insert_after (&si, list, BSI_SAME_STMT);
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
bsi_remove (&si, true); bsi_remove (&si, true);
/* Emit code to get the next parallel iteration in L2_BB. */ /* Emit code to get the next parallel iteration in L2_BB. */
list = alloc_stmt_list (); si = bsi_start (l2_bb);
t = build_call_expr (built_in_decls[next_fn], 2, t = build_call_expr (built_in_decls[next_fn], 2,
build_fold_addr_expr (istart0), build_fold_addr_expr (istart0),
build_fold_addr_expr (iend0)); build_fold_addr_expr (iend0));
t = get_formal_tmp_var (t, &list); t = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE); t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
append_to_statement_list (t, &list); bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
si = bsi_start (l2_bb);
bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
} }
/* Add the loop cleanup function. */ /* Add the loop cleanup function. */
...@@ -2700,25 +2789,31 @@ expand_omp_for_generic (struct omp_region *region, ...@@ -2700,25 +2789,31 @@ expand_omp_for_generic (struct omp_region *region,
bsi_remove (&si, true); bsi_remove (&si, true);
/* Connect the new blocks. */ /* Connect the new blocks. */
if (in_combined_parallel) find_edge (entry_bb, l0_bb)->flags = EDGE_TRUE_VALUE;
{ find_edge (entry_bb, l3_bb)->flags = EDGE_FALSE_VALUE;
remove_edge (BRANCH_EDGE (entry_bb));
redirect_edge_and_branch (single_succ_edge (entry_bb), l2_bb);
}
else
{
find_edge (entry_bb, l0_bb)->flags = EDGE_TRUE_VALUE;
find_edge (entry_bb, l3_bb)->flags = EDGE_FALSE_VALUE;
}
if (!broken_loop) if (!broken_loop)
{ {
e = find_edge (cont_bb, l3_bb);
ne = make_edge (l2_bb, l3_bb, EDGE_FALSE_VALUE);
for (phi = phi_nodes (l3_bb); phi; phi = PHI_CHAIN (phi))
SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, ne),
PHI_ARG_DEF_FROM_EDGE (phi, e));
remove_edge (e);
find_edge (cont_bb, l1_bb)->flags = EDGE_TRUE_VALUE; find_edge (cont_bb, l1_bb)->flags = EDGE_TRUE_VALUE;
remove_edge (find_edge (cont_bb, l3_bb));
make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE); make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE);
make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE); make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE);
make_edge (l2_bb, l3_bb, EDGE_FALSE_VALUE);
set_immediate_dominator (CDI_DOMINATORS, l2_bb,
recompute_dominator (CDI_DOMINATORS, l2_bb));
set_immediate_dominator (CDI_DOMINATORS, l3_bb,
recompute_dominator (CDI_DOMINATORS, l3_bb));
set_immediate_dominator (CDI_DOMINATORS, l0_bb,
recompute_dominator (CDI_DOMINATORS, l0_bb));
set_immediate_dominator (CDI_DOMINATORS, l1_bb,
recompute_dominator (CDI_DOMINATORS, l1_bb));
} }
} }
...@@ -2740,9 +2835,9 @@ expand_omp_for_generic (struct omp_region *region, ...@@ -2740,9 +2835,9 @@ expand_omp_for_generic (struct omp_region *region,
q += (q * nthreads != n); q += (q * nthreads != n);
s0 = q * threadid; s0 = q * threadid;
e0 = min(s0 + q, n); e0 = min(s0 + q, n);
V = s0 * STEP + N1;
if (s0 >= e0) goto L2; else goto L0; if (s0 >= e0) goto L2; else goto L0;
L0: L0:
V = s0 * STEP + N1;
e = e0 * STEP + N1; e = e0 * STEP + N1;
L1: L1:
BODY; BODY;
...@@ -2756,7 +2851,7 @@ expand_omp_for_static_nochunk (struct omp_region *region, ...@@ -2756,7 +2851,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
struct omp_for_data *fd) struct omp_for_data *fd)
{ {
tree n, q, s0, e0, e, t, nthreads, threadid; tree n, q, s0, e0, e, t, nthreads, threadid;
tree type, list; tree type, vmain, vback;
basic_block entry_bb, exit_bb, seq_start_bb, body_bb, cont_bb; basic_block entry_bb, exit_bb, seq_start_bb, body_bb, cont_bb;
basic_block fin_bb; basic_block fin_bb;
block_stmt_iterator si; block_stmt_iterator si;
...@@ -2775,27 +2870,33 @@ expand_omp_for_static_nochunk (struct omp_region *region, ...@@ -2775,27 +2870,33 @@ expand_omp_for_static_nochunk (struct omp_region *region,
exit_bb = region->exit; exit_bb = region->exit;
/* Iteration space partitioning goes in ENTRY_BB. */ /* Iteration space partitioning goes in ENTRY_BB. */
list = alloc_stmt_list (); si = bsi_last (entry_bb);
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_NUM_THREADS], 0); t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_NUM_THREADS], 0);
t = fold_convert (type, t); t = fold_convert (type, t);
nthreads = get_formal_tmp_var (t, &list); nthreads = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
true, BSI_SAME_STMT);
t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_THREAD_NUM], 0); t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_THREAD_NUM], 0);
t = fold_convert (type, t); t = fold_convert (type, t);
threadid = get_formal_tmp_var (t, &list); threadid = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
true, BSI_SAME_STMT);
fd->n1 = fold_convert (type, fd->n1); fd->n1 = force_gimple_operand_bsi (&si,
if (!is_gimple_val (fd->n1)) fold_convert (type, fd->n1),
fd->n1 = get_formal_tmp_var (fd->n1, &list); true, NULL_TREE,
true, BSI_SAME_STMT);
fd->n2 = fold_convert (type, fd->n2); fd->n2 = force_gimple_operand_bsi (&si,
if (!is_gimple_val (fd->n2)) fold_convert (type, fd->n2),
fd->n2 = get_formal_tmp_var (fd->n2, &list); true, NULL_TREE,
true, BSI_SAME_STMT);
fd->step = fold_convert (type, fd->step); fd->step = force_gimple_operand_bsi (&si,
if (!is_gimple_val (fd->step)) fold_convert (type, fd->step),
fd->step = get_formal_tmp_var (fd->step, &list); true, NULL_TREE,
true, BSI_SAME_STMT);
t = build_int_cst (type, (fd->cond_code == LT_EXPR ? -1 : 1)); t = build_int_cst (type, (fd->cond_code == LT_EXPR ? -1 : 1));
t = fold_build2 (PLUS_EXPR, type, fd->step, t); t = fold_build2 (PLUS_EXPR, type, fd->step, t);
...@@ -2803,85 +2904,90 @@ expand_omp_for_static_nochunk (struct omp_region *region, ...@@ -2803,85 +2904,90 @@ expand_omp_for_static_nochunk (struct omp_region *region,
t = fold_build2 (MINUS_EXPR, type, t, fd->n1); t = fold_build2 (MINUS_EXPR, type, t, fd->n1);
t = fold_build2 (TRUNC_DIV_EXPR, type, t, fd->step); t = fold_build2 (TRUNC_DIV_EXPR, type, t, fd->step);
t = fold_convert (type, t); t = fold_convert (type, t);
if (is_gimple_val (t)) n = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
n = t;
else
n = get_formal_tmp_var (t, &list);
t = build2 (TRUNC_DIV_EXPR, type, n, nthreads); t = fold_build2 (TRUNC_DIV_EXPR, type, n, nthreads);
q = get_formal_tmp_var (t, &list); q = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
t = build2 (MULT_EXPR, type, q, nthreads); t = fold_build2 (MULT_EXPR, type, q, nthreads);
t = build2 (NE_EXPR, type, t, n); t = fold_build2 (NE_EXPR, type, t, n);
t = build2 (PLUS_EXPR, type, q, t); t = fold_build2 (PLUS_EXPR, type, q, t);
q = get_formal_tmp_var (t, &list); q = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
t = build2 (MULT_EXPR, type, q, threadid); t = build2 (MULT_EXPR, type, q, threadid);
s0 = get_formal_tmp_var (t, &list); s0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
t = fold_build2 (PLUS_EXPR, type, s0, q);
t = fold_build2 (MIN_EXPR, type, t, n);
e0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
t = build2 (PLUS_EXPR, type, s0, q); t = fold_convert (type, s0);
t = build2 (MIN_EXPR, type, t, n); t = fold_build2 (MULT_EXPR, type, t, fd->step);
e0 = get_formal_tmp_var (t, &list); t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
true, BSI_SAME_STMT);
t = build_gimple_modify_stmt (fd->v, t);
bsi_insert_before (&si, t, BSI_SAME_STMT);
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (fd->v) = t;
t = build2 (GE_EXPR, boolean_type_node, s0, e0); t = build2 (GE_EXPR, boolean_type_node, s0, e0);
t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE); t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
append_to_statement_list (t, &list); bsi_insert_before (&si, t, BSI_SAME_STMT);
si = bsi_last (entry_bb); /* Remove the OMP_FOR statement. */
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
bsi_insert_after (&si, list, BSI_SAME_STMT);
bsi_remove (&si, true); bsi_remove (&si, true);
/* Setup code for sequential iteration goes in SEQ_START_BB. */ /* Setup code for sequential iteration goes in SEQ_START_BB. */
list = alloc_stmt_list (); si = bsi_start (seq_start_bb);
t = fold_convert (type, s0);
t = build2 (MULT_EXPR, type, t, fd->step);
t = build2 (PLUS_EXPR, type, t, fd->n1);
t = build_gimple_modify_stmt (fd->v, t);
gimplify_and_add (t, &list);
t = fold_convert (type, e0); t = fold_convert (type, e0);
t = build2 (MULT_EXPR, type, t, fd->step); t = fold_build2 (MULT_EXPR, type, t, fd->step);
t = build2 (PLUS_EXPR, type, t, fd->n1); t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
e = get_formal_tmp_var (t, &list); e = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
si = bsi_start (seq_start_bb);
bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
/* The code controlling the sequential loop replaces the OMP_CONTINUE. */ /* The code controlling the sequential loop replaces the OMP_CONTINUE. */
list = alloc_stmt_list (); si = bsi_last (cont_bb);
t = bsi_stmt (si);
t = build2 (PLUS_EXPR, type, fd->v, fd->step); gcc_assert (TREE_CODE (t) == OMP_CONTINUE);
t = build_gimple_modify_stmt (fd->v, t); vmain = TREE_OPERAND (t, 1);
gimplify_and_add (t, &list); vback = TREE_OPERAND (t, 0);
t = build2 (fd->cond_code, boolean_type_node, fd->v, e); t = fold_build2 (PLUS_EXPR, type, vmain, fd->step);
t = get_formal_tmp_var (t, &list); t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
true, BSI_SAME_STMT);
t = build_gimple_modify_stmt (vback, t);
bsi_insert_before (&si, t, BSI_SAME_STMT);
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (vback) = t;
t = build2 (fd->cond_code, boolean_type_node, vback, e);
t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE); t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
append_to_statement_list (t, &list); bsi_insert_before (&si, t, BSI_SAME_STMT);
si = bsi_last (cont_bb); /* Remove the OMP_CONTINUE statement. */
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
bsi_insert_after (&si, list, BSI_SAME_STMT);
bsi_remove (&si, true); bsi_remove (&si, true);
/* Replace the OMP_RETURN with a barrier, or nothing. */ /* Replace the OMP_RETURN with a barrier, or nothing. */
si = bsi_last (exit_bb); si = bsi_last (exit_bb);
if (!OMP_RETURN_NOWAIT (bsi_stmt (si))) if (!OMP_RETURN_NOWAIT (bsi_stmt (si)))
{ force_gimple_operand_bsi (&si, build_omp_barrier (), false, NULL_TREE,
list = alloc_stmt_list (); false, BSI_SAME_STMT);
build_omp_barrier (&list);
bsi_insert_after (&si, list, BSI_SAME_STMT);
}
bsi_remove (&si, true); bsi_remove (&si, true);
/* Connect all the blocks. */ /* Connect all the blocks. */
find_edge (entry_bb, seq_start_bb)->flags = EDGE_FALSE_VALUE; find_edge (entry_bb, seq_start_bb)->flags = EDGE_FALSE_VALUE;
find_edge (entry_bb, fin_bb)->flags = EDGE_TRUE_VALUE; find_edge (entry_bb, fin_bb)->flags = EDGE_TRUE_VALUE;
find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE; find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE;
find_edge (cont_bb, fin_bb)->flags = EDGE_FALSE_VALUE; find_edge (cont_bb, fin_bb)->flags = EDGE_FALSE_VALUE;
set_immediate_dominator (CDI_DOMINATORS, seq_start_bb, entry_bb);
set_immediate_dominator (CDI_DOMINATORS, body_bb,
recompute_dominator (CDI_DOMINATORS, body_bb));
set_immediate_dominator (CDI_DOMINATORS, fin_bb,
recompute_dominator (CDI_DOMINATORS, fin_bb));
} }
...@@ -2899,6 +3005,9 @@ expand_omp_for_static_nochunk (struct omp_region *region, ...@@ -2899,6 +3005,9 @@ expand_omp_for_static_nochunk (struct omp_region *region,
adj = STEP + 1; adj = STEP + 1;
n = (adj + N2 - N1) / STEP; n = (adj + N2 - N1) / STEP;
trip = 0; trip = 0;
V = threadid * CHUNK * STEP + N1; -- this extra definition of V is
here so that V is defined
if the loop is not entered
L0: L0:
s0 = (trip * nthreads + threadid) * CHUNK; s0 = (trip * nthreads + threadid) * CHUNK;
e0 = min(s0 + CHUNK, n); e0 = min(s0 + CHUNK, n);
...@@ -2919,14 +3028,13 @@ expand_omp_for_static_nochunk (struct omp_region *region, ...@@ -2919,14 +3028,13 @@ expand_omp_for_static_nochunk (struct omp_region *region,
static void static void
expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
{ {
tree n, s0, e0, e, t; tree n, s0, e0, e, t, phi, nphi, args;
tree trip, nthreads, threadid; tree trip_var, trip_init, trip_main, trip_back, nthreads, threadid;
tree type; tree type, cont, v_main, v_back, v_extra;
basic_block entry_bb, exit_bb, body_bb, seq_start_bb, iter_part_bb; basic_block entry_bb, exit_bb, body_bb, seq_start_bb, iter_part_bb;
basic_block trip_update_bb, cont_bb, fin_bb; basic_block trip_update_bb, cont_bb, fin_bb;
tree list;
block_stmt_iterator si; block_stmt_iterator si;
edge se; edge se, re, ene;
type = TREE_TYPE (fd->v); type = TREE_TYPE (fd->v);
...@@ -2947,31 +3055,33 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) ...@@ -2947,31 +3055,33 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
exit_bb = region->exit; exit_bb = region->exit;
/* Trip and adjustment setup goes in ENTRY_BB. */ /* Trip and adjustment setup goes in ENTRY_BB. */
list = alloc_stmt_list (); si = bsi_last (entry_bb);
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_NUM_THREADS], 0); t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_NUM_THREADS], 0);
t = fold_convert (type, t); t = fold_convert (type, t);
nthreads = get_formal_tmp_var (t, &list); nthreads = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
true, BSI_SAME_STMT);
t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_THREAD_NUM], 0); t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_THREAD_NUM], 0);
t = fold_convert (type, t); t = fold_convert (type, t);
threadid = get_formal_tmp_var (t, &list); threadid = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
true, BSI_SAME_STMT);
fd->n1 = fold_convert (type, fd->n1);
if (!is_gimple_val (fd->n1)) fd->n1 = force_gimple_operand_bsi (&si, fold_convert (type, fd->n1),
fd->n1 = get_formal_tmp_var (fd->n1, &list); true, NULL_TREE,
true, BSI_SAME_STMT);
fd->n2 = fold_convert (type, fd->n2); fd->n2 = force_gimple_operand_bsi (&si, fold_convert (type, fd->n2),
if (!is_gimple_val (fd->n2)) true, NULL_TREE,
fd->n2 = get_formal_tmp_var (fd->n2, &list); true, BSI_SAME_STMT);
fd->step = force_gimple_operand_bsi (&si, fold_convert (type, fd->step),
fd->step = fold_convert (type, fd->step); true, NULL_TREE,
if (!is_gimple_val (fd->step)) true, BSI_SAME_STMT);
fd->step = get_formal_tmp_var (fd->step, &list); fd->chunk_size
= force_gimple_operand_bsi (&si, fold_convert (type,
fd->chunk_size = fold_convert (type, fd->chunk_size); fd->chunk_size),
if (!is_gimple_val (fd->chunk_size)) true, NULL_TREE,
fd->chunk_size = get_formal_tmp_var (fd->chunk_size, &list); true, BSI_SAME_STMT);
t = build_int_cst (type, (fd->cond_code == LT_EXPR ? -1 : 1)); t = build_int_cst (type, (fd->cond_code == LT_EXPR ? -1 : 1));
t = fold_build2 (PLUS_EXPR, type, fd->step, t); t = fold_build2 (PLUS_EXPR, type, fd->step, t);
...@@ -2979,102 +3089,170 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) ...@@ -2979,102 +3089,170 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
t = fold_build2 (MINUS_EXPR, type, t, fd->n1); t = fold_build2 (MINUS_EXPR, type, t, fd->n1);
t = fold_build2 (TRUNC_DIV_EXPR, type, t, fd->step); t = fold_build2 (TRUNC_DIV_EXPR, type, t, fd->step);
t = fold_convert (type, t); t = fold_convert (type, t);
if (is_gimple_val (t)) n = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
n = t; true, BSI_SAME_STMT);
trip_var = create_tmp_var (type, ".trip");
if (gimple_in_ssa_p (cfun))
{
add_referenced_var (trip_var);
trip_init = make_ssa_name (trip_var, NULL_TREE);
trip_main = make_ssa_name (trip_var, NULL_TREE);
trip_back = make_ssa_name (trip_var, NULL_TREE);
}
else else
n = get_formal_tmp_var (t, &list); {
trip_init = trip_var;
trip_main = trip_var;
trip_back = trip_var;
}
t = build_int_cst (type, 0); t = build_gimple_modify_stmt (trip_init, build_int_cst (type, 0));
trip = get_initialized_tmp_var (t, &list, NULL); bsi_insert_before (&si, t, BSI_SAME_STMT);
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (trip_init) = t;
si = bsi_last (entry_bb); t = fold_build2 (MULT_EXPR, type, threadid, fd->chunk_size);
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR); t = fold_build2 (MULT_EXPR, type, t, fd->step);
bsi_insert_after (&si, list, BSI_SAME_STMT); t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
v_extra = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
true, BSI_SAME_STMT);
/* Remove the OMP_FOR. */
bsi_remove (&si, true); bsi_remove (&si, true);
/* Iteration space partitioning goes in ITER_PART_BB. */ /* Iteration space partitioning goes in ITER_PART_BB. */
list = alloc_stmt_list (); si = bsi_last (iter_part_bb);
t = build2 (MULT_EXPR, type, trip, nthreads); t = fold_build2 (MULT_EXPR, type, trip_main, nthreads);
t = build2 (PLUS_EXPR, type, t, threadid); t = fold_build2 (PLUS_EXPR, type, t, threadid);
t = build2 (MULT_EXPR, type, t, fd->chunk_size); t = fold_build2 (MULT_EXPR, type, t, fd->chunk_size);
s0 = get_formal_tmp_var (t, &list); s0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
t = build2 (PLUS_EXPR, type, s0, fd->chunk_size); t = fold_build2 (PLUS_EXPR, type, s0, fd->chunk_size);
t = build2 (MIN_EXPR, type, t, n); t = fold_build2 (MIN_EXPR, type, t, n);
e0 = get_formal_tmp_var (t, &list); e0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
t = build2 (LT_EXPR, boolean_type_node, s0, n); t = build2 (LT_EXPR, boolean_type_node, s0, n);
t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE); t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
append_to_statement_list (t, &list); bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
si = bsi_start (iter_part_bb);
bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
/* Setup code for sequential iteration goes in SEQ_START_BB. */ /* Setup code for sequential iteration goes in SEQ_START_BB. */
list = alloc_stmt_list (); si = bsi_start (seq_start_bb);
t = fold_convert (type, s0); t = fold_convert (type, s0);
t = build2 (MULT_EXPR, type, t, fd->step); t = fold_build2 (MULT_EXPR, type, t, fd->step);
t = build2 (PLUS_EXPR, type, t, fd->n1); t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
false, BSI_CONTINUE_LINKING);
t = build_gimple_modify_stmt (fd->v, t); t = build_gimple_modify_stmt (fd->v, t);
gimplify_and_add (t, &list); bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (fd->v) = t;
t = fold_convert (type, e0); t = fold_convert (type, e0);
t = build2 (MULT_EXPR, type, t, fd->step); t = fold_build2 (MULT_EXPR, type, t, fd->step);
t = build2 (PLUS_EXPR, type, t, fd->n1); t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
e = get_formal_tmp_var (t, &list); e = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
false, BSI_CONTINUE_LINKING);
si = bsi_start (seq_start_bb);
bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
/* The code controlling the sequential loop goes in CONT_BB, /* The code controlling the sequential loop goes in CONT_BB,
replacing the OMP_CONTINUE. */ replacing the OMP_CONTINUE. */
list = alloc_stmt_list (); si = bsi_last (cont_bb);
cont = bsi_stmt (si);
t = build2 (PLUS_EXPR, type, fd->v, fd->step); gcc_assert (TREE_CODE (cont) == OMP_CONTINUE);
t = build_gimple_modify_stmt (fd->v, t); v_main = TREE_OPERAND (cont, 1);
gimplify_and_add (t, &list); v_back = TREE_OPERAND (cont, 0);
t = build2 (fd->cond_code, boolean_type_node, fd->v, e); t = build2 (PLUS_EXPR, type, v_main, fd->step);
t = get_formal_tmp_var (t, &list); t = build_gimple_modify_stmt (v_back, t);
bsi_insert_before (&si, t, BSI_SAME_STMT);
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (v_back) = t;
t = build2 (fd->cond_code, boolean_type_node, v_back, e);
t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE); t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
append_to_statement_list (t, &list); bsi_insert_before (&si, t, BSI_SAME_STMT);
si = bsi_last (cont_bb); /* Remove OMP_CONTINUE. */
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
bsi_insert_after (&si, list, BSI_SAME_STMT);
bsi_remove (&si, true); bsi_remove (&si, true);
/* Trip update code goes into TRIP_UPDATE_BB. */ /* Trip update code goes into TRIP_UPDATE_BB. */
list = alloc_stmt_list (); si = bsi_start (trip_update_bb);
t = build_int_cst (type, 1); t = build_int_cst (type, 1);
t = build2 (PLUS_EXPR, type, trip, t); t = build2 (PLUS_EXPR, type, trip_main, t);
t = build_gimple_modify_stmt (trip, t); t = build_gimple_modify_stmt (trip_back, t);
gimplify_and_add (t, &list); bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
if (gimple_in_ssa_p (cfun))
si = bsi_start (trip_update_bb); SSA_NAME_DEF_STMT (trip_back) = t;
bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
/* Replace the OMP_RETURN with a barrier, or nothing. */ /* Replace the OMP_RETURN with a barrier, or nothing. */
si = bsi_last (exit_bb); si = bsi_last (exit_bb);
if (!OMP_RETURN_NOWAIT (bsi_stmt (si))) if (!OMP_RETURN_NOWAIT (bsi_stmt (si)))
{ force_gimple_operand_bsi (&si, build_omp_barrier (), false, NULL_TREE,
list = alloc_stmt_list (); false, BSI_SAME_STMT);
build_omp_barrier (&list);
bsi_insert_after (&si, list, BSI_SAME_STMT);
}
bsi_remove (&si, true); bsi_remove (&si, true);
/* Connect the new blocks. */ /* Connect the new blocks. */
find_edge (iter_part_bb, seq_start_bb)->flags = EDGE_TRUE_VALUE; find_edge (iter_part_bb, seq_start_bb)->flags = EDGE_TRUE_VALUE;
find_edge (iter_part_bb, fin_bb)->flags = EDGE_FALSE_VALUE; find_edge (iter_part_bb, fin_bb)->flags = EDGE_FALSE_VALUE;
find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE; find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE;
find_edge (cont_bb, trip_update_bb)->flags = EDGE_FALSE_VALUE; find_edge (cont_bb, trip_update_bb)->flags = EDGE_FALSE_VALUE;
redirect_edge_and_branch (single_succ_edge (trip_update_bb), iter_part_bb); redirect_edge_and_branch (single_succ_edge (trip_update_bb), iter_part_bb);
if (gimple_in_ssa_p (cfun))
{
/* When we redirect the edge from trip_update_bb to iter_part_bb, we
remove arguments of the phi nodes in fin_bb. We need to create
appropriate phi nodes in iter_part_bb instead. */
se = single_pred_edge (fin_bb);
re = single_succ_edge (trip_update_bb);
ene = single_succ_edge (entry_bb);
args = PENDING_STMT (re);
PENDING_STMT (re) = NULL_TREE;
for (phi = phi_nodes (fin_bb);
phi && args;
phi = PHI_CHAIN (phi), args = TREE_CHAIN (args))
{
t = PHI_RESULT (phi);
gcc_assert (t == TREE_PURPOSE (args));
nphi = create_phi_node (t, iter_part_bb);
SSA_NAME_DEF_STMT (t) = nphi;
t = PHI_ARG_DEF_FROM_EDGE (phi, se);
/* A special case -- fd->v is not yet computed in iter_part_bb, we
need to use v_extra instead. */
if (t == fd->v)
t = v_extra;
add_phi_arg (nphi, t, ene);
add_phi_arg (nphi, TREE_VALUE (args), re);
}
gcc_assert (!phi && !args);
while ((phi = phi_nodes (fin_bb)) != NULL_TREE)
remove_phi_node (phi, NULL_TREE, false);
/* Make phi node for trip. */
phi = create_phi_node (trip_main, iter_part_bb);
SSA_NAME_DEF_STMT (trip_main) = phi;
add_phi_arg (phi, trip_back, single_succ_edge (trip_update_bb));
add_phi_arg (phi, trip_init, single_succ_edge (entry_bb));
}
set_immediate_dominator (CDI_DOMINATORS, trip_update_bb, cont_bb);
set_immediate_dominator (CDI_DOMINATORS, iter_part_bb,
recompute_dominator (CDI_DOMINATORS, iter_part_bb));
set_immediate_dominator (CDI_DOMINATORS, fin_bb,
recompute_dominator (CDI_DOMINATORS, fin_bb));
set_immediate_dominator (CDI_DOMINATORS, seq_start_bb,
recompute_dominator (CDI_DOMINATORS, seq_start_bb));
set_immediate_dominator (CDI_DOMINATORS, body_bb,
recompute_dominator (CDI_DOMINATORS, body_bb));
} }
...@@ -3085,8 +3263,6 @@ expand_omp_for (struct omp_region *region) ...@@ -3085,8 +3263,6 @@ expand_omp_for (struct omp_region *region)
{ {
struct omp_for_data fd; struct omp_for_data fd;
push_gimplify_context ();
extract_omp_for_data (last_stmt (region->entry), &fd); extract_omp_for_data (last_stmt (region->entry), &fd);
region->sched_kind = fd.sched_kind; region->sched_kind = fd.sched_kind;
...@@ -3106,8 +3282,6 @@ expand_omp_for (struct omp_region *region) ...@@ -3106,8 +3282,6 @@ expand_omp_for (struct omp_region *region)
int next_ix = BUILT_IN_GOMP_LOOP_STATIC_NEXT + fn_index; int next_ix = BUILT_IN_GOMP_LOOP_STATIC_NEXT + fn_index;
expand_omp_for_generic (region, &fd, start_ix, next_ix); expand_omp_for_generic (region, &fd, start_ix, next_ix);
} }
pop_gimplify_context (NULL);
} }
...@@ -3136,12 +3310,12 @@ expand_omp_for (struct omp_region *region) ...@@ -3136,12 +3310,12 @@ expand_omp_for (struct omp_region *region)
reduction; reduction;
If this is a combined parallel sections, replace the call to If this is a combined parallel sections, replace the call to
GOMP_sections_start with 'goto L1'. */ GOMP_sections_start with call to GOMP_sections_next. */
static void static void
expand_omp_sections (struct omp_region *region) expand_omp_sections (struct omp_region *region)
{ {
tree label_vec, l1, l2, t, u, v, sections_stmt; tree label_vec, l1, l2, t, u, sections_stmt, vin, vmain, vnext, cont;
unsigned i, casei, len; unsigned i, casei, len;
basic_block entry_bb, l0_bb, l1_bb, l2_bb, default_bb; basic_block entry_bb, l0_bb, l1_bb, l2_bb, default_bb;
block_stmt_iterator si; block_stmt_iterator si;
...@@ -3178,7 +3352,7 @@ expand_omp_sections (struct omp_region *region) ...@@ -3178,7 +3352,7 @@ expand_omp_sections (struct omp_region *region)
si = bsi_last (entry_bb); si = bsi_last (entry_bb);
sections_stmt = bsi_stmt (si); sections_stmt = bsi_stmt (si);
gcc_assert (TREE_CODE (sections_stmt) == OMP_SECTIONS); gcc_assert (TREE_CODE (sections_stmt) == OMP_SECTIONS);
v = OMP_SECTIONS_CONTROL (sections_stmt); vin = OMP_SECTIONS_CONTROL (sections_stmt);
if (!is_combined_parallel (region)) if (!is_combined_parallel (region))
{ {
/* If we are not inside a combined parallel+sections region, /* If we are not inside a combined parallel+sections region,
...@@ -3187,16 +3361,36 @@ expand_omp_sections (struct omp_region *region) ...@@ -3187,16 +3361,36 @@ expand_omp_sections (struct omp_region *region)
exit_reachable ? len - 1 : len); exit_reachable ? len - 1 : len);
u = built_in_decls[BUILT_IN_GOMP_SECTIONS_START]; u = built_in_decls[BUILT_IN_GOMP_SECTIONS_START];
t = build_call_expr (u, 1, t); t = build_call_expr (u, 1, t);
t = build_gimple_modify_stmt (v, t);
bsi_insert_after (&si, t, BSI_SAME_STMT);
} }
else
{
/* Otherwise, call GOMP_sections_next. */
u = built_in_decls[BUILT_IN_GOMP_SECTIONS_NEXT];
t = build_call_expr (u, 0);
}
t = build_gimple_modify_stmt (vin, t);
bsi_insert_after (&si, t, BSI_SAME_STMT);
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (vin) = t;
bsi_remove (&si, true); bsi_remove (&si, true);
/* The switch() statement replacing OMP_SECTIONS_SWITCH goes in L0_BB. */ /* The switch() statement replacing OMP_SECTIONS_SWITCH goes in L0_BB. */
si = bsi_last (l0_bb); si = bsi_last (l0_bb);
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_SECTIONS_SWITCH); gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_SECTIONS_SWITCH);
if (exit_reachable)
{
cont = last_stmt (l1_bb);
gcc_assert (TREE_CODE (cont) == OMP_CONTINUE);
vmain = TREE_OPERAND (cont, 1);
vnext = TREE_OPERAND (cont, 0);
}
else
{
vmain = vin;
vnext = NULL_TREE;
}
t = build3 (SWITCH_EXPR, void_type_node, v, NULL, label_vec); t = build3 (SWITCH_EXPR, void_type_node, vmain, NULL, label_vec);
bsi_insert_after (&si, t, BSI_SAME_STMT); bsi_insert_after (&si, t, BSI_SAME_STMT);
bsi_remove (&si, true); bsi_remove (&si, true);
...@@ -3257,8 +3451,10 @@ expand_omp_sections (struct omp_region *region) ...@@ -3257,8 +3451,10 @@ expand_omp_sections (struct omp_region *region)
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE); gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
t = build_call_expr (built_in_decls[BUILT_IN_GOMP_SECTIONS_NEXT], 0); t = build_call_expr (built_in_decls[BUILT_IN_GOMP_SECTIONS_NEXT], 0);
t = build_gimple_modify_stmt (v, t); t = build_gimple_modify_stmt (vnext, t);
bsi_insert_after (&si, t, BSI_SAME_STMT); bsi_insert_after (&si, t, BSI_SAME_STMT);
if (gimple_in_ssa_p (cfun))
SSA_NAME_DEF_STMT (vnext) = t;
bsi_remove (&si, true); bsi_remove (&si, true);
single_succ_edge (l1_bb)->flags = EDGE_FALLTHRU; single_succ_edge (l1_bb)->flags = EDGE_FALLTHRU;
...@@ -3274,15 +3470,7 @@ expand_omp_sections (struct omp_region *region) ...@@ -3274,15 +3470,7 @@ expand_omp_sections (struct omp_region *region)
bsi_remove (&si, true); bsi_remove (&si, true);
} }
/* Connect the new blocks. */ set_immediate_dominator (CDI_DOMINATORS, default_bb, l0_bb);
if (is_combined_parallel (region))
{
/* If this was a combined parallel+sections region, we did not
emit a GOMP_sections_start in the entry block, so we just
need to jump to L1_BB to get the next section. */
gcc_assert (exit_reachable);
redirect_edge_and_branch (single_succ_edge (entry_bb), l1_bb);
}
} }
...@@ -3312,11 +3500,8 @@ expand_omp_single (struct omp_region *region) ...@@ -3312,11 +3500,8 @@ expand_omp_single (struct omp_region *region)
si = bsi_last (exit_bb); si = bsi_last (exit_bb);
if (!OMP_RETURN_NOWAIT (bsi_stmt (si)) || need_barrier) if (!OMP_RETURN_NOWAIT (bsi_stmt (si)) || need_barrier)
{ force_gimple_operand_bsi (&si, build_omp_barrier (), false, NULL_TREE,
tree t = alloc_stmt_list (); false, BSI_SAME_STMT);
build_omp_barrier (&t);
bsi_insert_after (&si, t, BSI_SAME_STMT);
}
bsi_remove (&si, true); bsi_remove (&si, true);
single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU; single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU;
} }
...@@ -3498,8 +3683,6 @@ execute_expand_omp (void) ...@@ -3498,8 +3683,6 @@ execute_expand_omp (void)
expand_omp (root_omp_region); expand_omp (root_omp_region);
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
cleanup_tree_cfg (); cleanup_tree_cfg ();
free_omp_regions (); free_omp_regions ();
...@@ -3507,10 +3690,38 @@ execute_expand_omp (void) ...@@ -3507,10 +3690,38 @@ execute_expand_omp (void)
return 0; return 0;
} }
/* OMP expansion in SSA form. For testing purposes only. */
static bool
gate_expand_omp_ssa (void)
{
return flag_openmp_ssa && flag_openmp != 0 && errorcount == 0;
}
struct tree_opt_pass pass_expand_omp_ssa =
{
"ompexpssa", /* name */
gate_expand_omp_ssa, /* gate */
execute_expand_omp, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
0, /* tv_id */
PROP_gimple_any, /* properties_required */
PROP_gimple_lomp, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
0 /* letter */
};
/* OMP expansion -- the default pass, run before creation of SSA form. */
static bool static bool
gate_expand_omp (void) gate_expand_omp (void)
{ {
return flag_openmp != 0 && errorcount == 0; return ((!flag_openmp_ssa || !optimize)
&& flag_openmp != 0 && errorcount == 0);
} }
struct tree_opt_pass pass_expand_omp = struct tree_opt_pass pass_expand_omp =
......
...@@ -515,6 +515,7 @@ init_optimization_passes (void) ...@@ -515,6 +515,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_referenced_vars); NEXT_PASS (pass_referenced_vars);
NEXT_PASS (pass_reset_cc_flags); NEXT_PASS (pass_reset_cc_flags);
NEXT_PASS (pass_build_ssa); NEXT_PASS (pass_build_ssa);
NEXT_PASS (pass_expand_omp_ssa);
NEXT_PASS (pass_early_warn_uninitialized); NEXT_PASS (pass_early_warn_uninitialized);
NEXT_PASS (pass_rebuild_cgraph_edges); NEXT_PASS (pass_rebuild_cgraph_edges);
NEXT_PASS (pass_early_inline); NEXT_PASS (pass_early_inline);
......
...@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssa-propagate.h" #include "tree-ssa-propagate.h"
#include "value-prof.h" #include "value-prof.h"
#include "pointer-set.h" #include "pointer-set.h"
#include "tree-inline.h"
/* This file contains functions for building the Control Flow Graph (CFG) /* This file contains functions for building the Control Flow Graph (CFG)
for a function tree. */ for a function tree. */
...@@ -5248,13 +5249,89 @@ gather_blocks_in_sese_region (basic_block entry, basic_block exit, ...@@ -5248,13 +5249,89 @@ gather_blocks_in_sese_region (basic_block entry, basic_block exit,
} }
} }
/* Replaces *TP with a duplicate (belonging to function TO_CONTEXT).
The duplicates are recorded in VARS_MAP. */
static void
replace_by_duplicate_decl (tree *tp, struct pointer_map_t *vars_map,
tree to_context)
{
tree t = *tp, new_t;
struct function *f = DECL_STRUCT_FUNCTION (to_context);
void **loc;
if (DECL_CONTEXT (t) == to_context)
return;
loc = pointer_map_contains (vars_map, t);
if (!loc)
{
loc = pointer_map_insert (vars_map, t);
if (SSA_VAR_P (t))
{
new_t = copy_var_decl (t, DECL_NAME (t), TREE_TYPE (t));
f->unexpanded_var_list
= tree_cons (NULL_TREE, new_t, f->unexpanded_var_list);
}
else
{
gcc_assert (TREE_CODE (t) == CONST_DECL);
new_t = copy_node (t);
}
DECL_CONTEXT (new_t) = to_context;
*loc = new_t;
}
else
new_t = *loc;
*tp = new_t;
}
/* Creates an ssa name in TO_CONTEXT equivalent to NAME.
VARS_MAP maps old ssa names and var_decls to the new ones. */
static tree
replace_ssa_name (tree name, struct pointer_map_t *vars_map,
tree to_context)
{
void **loc;
tree new_name, decl = SSA_NAME_VAR (name);
gcc_assert (is_gimple_reg (name));
loc = pointer_map_contains (vars_map, name);
if (!loc)
{
replace_by_duplicate_decl (&decl, vars_map, to_context);
push_cfun (DECL_STRUCT_FUNCTION (to_context));
if (gimple_in_ssa_p (cfun))
add_referenced_var (decl);
new_name = make_ssa_name (decl, SSA_NAME_DEF_STMT (name));
if (SSA_NAME_IS_DEFAULT_DEF (name))
set_default_def (decl, new_name);
pop_cfun ();
loc = pointer_map_insert (vars_map, name);
*loc = new_name;
}
else
new_name = *loc;
return new_name;
}
struct move_stmt_d struct move_stmt_d
{ {
tree block; tree block;
tree from_context; tree from_context;
tree to_context; tree to_context;
bitmap vars_to_remove; struct pointer_map_t *vars_map;
htab_t new_label_map; htab_t new_label_map;
bool remap_decls_p; bool remap_decls_p;
}; };
...@@ -5289,9 +5366,11 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data) ...@@ -5289,9 +5366,11 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data)
p->remap_decls_p = save_remap_decls_p; p->remap_decls_p = save_remap_decls_p;
} }
else if (DECL_P (t) && DECL_CONTEXT (t) == p->from_context) else if (DECL_P (t) || TREE_CODE (t) == SSA_NAME)
{ {
if (TREE_CODE (t) == LABEL_DECL) if (TREE_CODE (t) == SSA_NAME)
*tp = replace_ssa_name (t, p->vars_map, p->to_context);
else if (TREE_CODE (t) == LABEL_DECL)
{ {
if (p->new_label_map) if (p->new_label_map)
{ {
...@@ -5306,20 +5385,26 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data) ...@@ -5306,20 +5385,26 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data)
} }
else if (p->remap_decls_p) else if (p->remap_decls_p)
{ {
DECL_CONTEXT (t) = p->to_context; /* Replace T with its duplicate. T should no longer appear in the
parent function, so this looks wasteful; however, it may appear
if (TREE_CODE (t) == VAR_DECL) in referenced_vars, and more importantly, as virtual operands of
statements, and in alias lists of other variables. It would be
quite difficult to expunge it from all those places. ??? It might
suffice to do this for addressable variables. */
if ((TREE_CODE (t) == VAR_DECL
&& !is_global_var (t))
|| TREE_CODE (t) == CONST_DECL)
replace_by_duplicate_decl (tp, p->vars_map, p->to_context);
if (SSA_VAR_P (t)
&& gimple_in_ssa_p (cfun))
{ {
struct function *f = DECL_STRUCT_FUNCTION (p->to_context); push_cfun (DECL_STRUCT_FUNCTION (p->to_context));
f->unexpanded_var_list add_referenced_var (*tp);
= tree_cons (0, t, f->unexpanded_var_list); pop_cfun ();
/* Mark T to be removed from the original function,
otherwise it will be given a DECL_RTL when the
original function is expanded. */
bitmap_set_bit (p->vars_to_remove, DECL_UID (t));
} }
} }
*walk_subtrees = 0;
} }
else if (TYPE_P (t)) else if (TYPE_P (t))
*walk_subtrees = 0; *walk_subtrees = 0;
...@@ -5327,6 +5412,26 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data) ...@@ -5327,6 +5412,26 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data)
return NULL_TREE; return NULL_TREE;
} }
/* Marks virtual operands of all statements in basic blocks BBS for
renaming. */
static void
mark_virtual_ops_in_region (VEC (basic_block,heap) *bbs)
{
tree phi;
block_stmt_iterator bsi;
basic_block bb;
unsigned i;
for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
{
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
mark_virtual_ops_for_renaming (phi);
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
mark_virtual_ops_for_renaming (bsi_stmt (bsi));
}
}
/* Move basic block BB from function CFUN to function DEST_FN. The /* Move basic block BB from function CFUN to function DEST_FN. The
block is moved out of the original linked list and placed after block is moved out of the original linked list and placed after
...@@ -5335,13 +5440,14 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data) ...@@ -5335,13 +5440,14 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data)
If UPDATE_EDGE_COUNT_P is true, the edge counts on both CFGs is If UPDATE_EDGE_COUNT_P is true, the edge counts on both CFGs is
updated to reflect the moved edges. updated to reflect the moved edges.
On exit, local variables that need to be removed from The local variables are remapped to new instances, VARS_MAP is used
CFUN->UNEXPANDED_VAR_LIST will have been added to VARS_TO_REMOVE. */ to record the mapping. */
static void static void
move_block_to_fn (struct function *dest_cfun, basic_block bb, move_block_to_fn (struct function *dest_cfun, basic_block bb,
basic_block after, bool update_edge_count_p, basic_block after, bool update_edge_count_p,
bitmap vars_to_remove, htab_t new_label_map, int eh_offset) struct pointer_map_t *vars_map, htab_t new_label_map,
int eh_offset)
{ {
struct control_flow_graph *cfg; struct control_flow_graph *cfg;
edge_iterator ei; edge_iterator ei;
...@@ -5349,6 +5455,7 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb, ...@@ -5349,6 +5455,7 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
block_stmt_iterator si; block_stmt_iterator si;
struct move_stmt_d d; struct move_stmt_d d;
unsigned old_len, new_len; unsigned old_len, new_len;
tree phi;
/* Remove BB from dominance structures. */ /* Remove BB from dominance structures. */
delete_from_dominance_info (CDI_DOMINATORS, bb); delete_from_dominance_info (CDI_DOMINATORS, bb);
...@@ -5385,20 +5492,39 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb, ...@@ -5385,20 +5492,39 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
VEC_replace (basic_block, cfg->x_basic_block_info, VEC_replace (basic_block, cfg->x_basic_block_info,
bb->index, bb); bb->index, bb);
/* Remap the variables in phi nodes. */
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
{
use_operand_p use;
tree op = PHI_RESULT (phi);
ssa_op_iter oi;
if (!is_gimple_reg (op))
continue;
SET_PHI_RESULT (phi, replace_ssa_name (op, vars_map, dest_cfun->decl));
FOR_EACH_PHI_ARG (use, phi, oi, SSA_OP_USE)
{
op = USE_FROM_PTR (use);
if (TREE_CODE (op) == SSA_NAME)
SET_USE (use, replace_ssa_name (op, vars_map, dest_cfun->decl));
}
}
/* The statements in BB need to be associated with a new TREE_BLOCK. /* The statements in BB need to be associated with a new TREE_BLOCK.
Labels need to be associated with a new label-to-block map. */ Labels need to be associated with a new label-to-block map. */
memset (&d, 0, sizeof (d)); memset (&d, 0, sizeof (d));
d.vars_to_remove = vars_to_remove; d.vars_map = vars_map;
d.from_context = cfun->decl;
d.to_context = dest_cfun->decl;
d.new_label_map = new_label_map;
for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
{ {
tree stmt = bsi_stmt (si); tree stmt = bsi_stmt (si);
int region; int region;
d.from_context = cfun->decl;
d.to_context = dest_cfun->decl;
d.remap_decls_p = true; d.remap_decls_p = true;
d.new_label_map = new_label_map;
if (TREE_BLOCK (stmt)) if (TREE_BLOCK (stmt))
d.block = DECL_INITIAL (dest_cfun->decl); d.block = DECL_INITIAL (dest_cfun->decl);
...@@ -5441,6 +5567,8 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb, ...@@ -5441,6 +5567,8 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
gimple_duplicate_stmt_histograms (dest_cfun, stmt, cfun, stmt); gimple_duplicate_stmt_histograms (dest_cfun, stmt, cfun, stmt);
gimple_remove_stmt_histograms (cfun, stmt); gimple_remove_stmt_histograms (cfun, stmt);
} }
update_stmt (stmt);
} }
} }
...@@ -5518,21 +5646,17 @@ basic_block ...@@ -5518,21 +5646,17 @@ basic_block
move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
basic_block exit_bb) basic_block exit_bb)
{ {
VEC(basic_block,heap) *bbs; VEC(basic_block,heap) *bbs, *dom_bbs;
basic_block after, bb, *entry_pred, *exit_succ; basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
struct function *saved_cfun; basic_block after, bb, *entry_pred, *exit_succ, abb;
struct function *saved_cfun = cfun;
int *entry_flag, *exit_flag, eh_offset; int *entry_flag, *exit_flag, eh_offset;
unsigned *entry_prob, *exit_prob;
unsigned i, num_entry_edges, num_exit_edges; unsigned i, num_entry_edges, num_exit_edges;
edge e; edge e;
edge_iterator ei; edge_iterator ei;
bitmap vars_to_remove;
htab_t new_label_map; htab_t new_label_map;
struct pointer_map_t *vars_map;
saved_cfun = cfun;
/* Collect all the blocks in the region. Manually add ENTRY_BB
because it won't be added by dfs_enumerate_from. */
calculate_dominance_info (CDI_DOMINATORS);
/* If ENTRY does not strictly dominate EXIT, this cannot be an SESE /* If ENTRY does not strictly dominate EXIT, this cannot be an SESE
region. */ region. */
...@@ -5540,10 +5664,18 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, ...@@ -5540,10 +5664,18 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
&& (!exit_bb && (!exit_bb
|| dominated_by_p (CDI_DOMINATORS, exit_bb, entry_bb))); || dominated_by_p (CDI_DOMINATORS, exit_bb, entry_bb)));
/* Collect all the blocks in the region. Manually add ENTRY_BB
because it won't be added by dfs_enumerate_from. */
bbs = NULL; bbs = NULL;
VEC_safe_push (basic_block, heap, bbs, entry_bb); VEC_safe_push (basic_block, heap, bbs, entry_bb);
gather_blocks_in_sese_region (entry_bb, exit_bb, &bbs); gather_blocks_in_sese_region (entry_bb, exit_bb, &bbs);
/* The blocks that used to be dominated by something in BBS will now be
dominated by the new block. */
dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
VEC_address (basic_block, bbs),
VEC_length (basic_block, bbs));
/* Detach ENTRY_BB and EXIT_BB from CFUN->CFG. We need to remember /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG. We need to remember
the predecessor edges to ENTRY_BB and the successor edges to the predecessor edges to ENTRY_BB and the successor edges to
EXIT_BB so that we can re-attach them to the new basic block that EXIT_BB so that we can re-attach them to the new basic block that
...@@ -5551,9 +5683,11 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, ...@@ -5551,9 +5683,11 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
num_entry_edges = EDGE_COUNT (entry_bb->preds); num_entry_edges = EDGE_COUNT (entry_bb->preds);
entry_pred = (basic_block *) xcalloc (num_entry_edges, sizeof (basic_block)); entry_pred = (basic_block *) xcalloc (num_entry_edges, sizeof (basic_block));
entry_flag = (int *) xcalloc (num_entry_edges, sizeof (int)); entry_flag = (int *) xcalloc (num_entry_edges, sizeof (int));
entry_prob = XNEWVEC (unsigned, num_entry_edges);
i = 0; i = 0;
for (ei = ei_start (entry_bb->preds); (e = ei_safe_edge (ei)) != NULL;) for (ei = ei_start (entry_bb->preds); (e = ei_safe_edge (ei)) != NULL;)
{ {
entry_prob[i] = e->probability;
entry_flag[i] = e->flags; entry_flag[i] = e->flags;
entry_pred[i++] = e->src; entry_pred[i++] = e->src;
remove_edge (e); remove_edge (e);
...@@ -5565,9 +5699,11 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, ...@@ -5565,9 +5699,11 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
exit_succ = (basic_block *) xcalloc (num_exit_edges, exit_succ = (basic_block *) xcalloc (num_exit_edges,
sizeof (basic_block)); sizeof (basic_block));
exit_flag = (int *) xcalloc (num_exit_edges, sizeof (int)); exit_flag = (int *) xcalloc (num_exit_edges, sizeof (int));
exit_prob = XNEWVEC (unsigned, num_exit_edges);
i = 0; i = 0;
for (ei = ei_start (exit_bb->succs); (e = ei_safe_edge (ei)) != NULL;) for (ei = ei_start (exit_bb->succs); (e = ei_safe_edge (ei)) != NULL;)
{ {
exit_prob[i] = e->probability;
exit_flag[i] = e->flags; exit_flag[i] = e->flags;
exit_succ[i++] = e->dest; exit_succ[i++] = e->dest;
remove_edge (e); remove_edge (e);
...@@ -5578,11 +5714,12 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, ...@@ -5578,11 +5714,12 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
num_exit_edges = 0; num_exit_edges = 0;
exit_succ = NULL; exit_succ = NULL;
exit_flag = NULL; exit_flag = NULL;
exit_prob = NULL;
} }
/* Switch context to the child function to initialize DEST_FN's CFG. */ /* Switch context to the child function to initialize DEST_FN's CFG. */
gcc_assert (dest_cfun->cfg == NULL); gcc_assert (dest_cfun->cfg == NULL);
set_cfun (dest_cfun); push_cfun (dest_cfun);
init_empty_tree_cfg (); init_empty_tree_cfg ();
...@@ -5605,46 +5742,30 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, ...@@ -5605,46 +5742,30 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
} }
} }
set_cfun (saved_cfun); pop_cfun ();
/* The ssa form for virtual operands in the source function will have to
be repaired. We do not care for the real operands -- the sese region
must be closed with respect to those. */
mark_virtual_ops_in_region (bbs);
/* Move blocks from BBS into DEST_CFUN. */ /* Move blocks from BBS into DEST_CFUN. */
gcc_assert (VEC_length (basic_block, bbs) >= 2); gcc_assert (VEC_length (basic_block, bbs) >= 2);
after = dest_cfun->cfg->x_entry_block_ptr; after = dest_cfun->cfg->x_entry_block_ptr;
vars_to_remove = BITMAP_ALLOC (NULL); vars_map = pointer_map_create ();
for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++) for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
{ {
/* No need to update edge counts on the last block. It has /* No need to update edge counts on the last block. It has
already been updated earlier when we detached the region from already been updated earlier when we detached the region from
the original CFG. */ the original CFG. */
move_block_to_fn (dest_cfun, bb, after, bb != exit_bb, vars_to_remove, move_block_to_fn (dest_cfun, bb, after, bb != exit_bb, vars_map,
new_label_map, eh_offset); new_label_map, eh_offset);
after = bb; after = bb;
} }
if (new_label_map) if (new_label_map)
htab_delete (new_label_map); htab_delete (new_label_map);
pointer_map_destroy (vars_map);
/* Remove the variables marked in VARS_TO_REMOVE from
CFUN->UNEXPANDED_VAR_LIST. Otherwise, they will be given a
DECL_RTL in the context of CFUN. */
if (!bitmap_empty_p (vars_to_remove))
{
tree *p;
for (p = &cfun->unexpanded_var_list; *p; )
{
tree var = TREE_VALUE (*p);
if (bitmap_bit_p (vars_to_remove, DECL_UID (var)))
{
*p = TREE_CHAIN (*p);
continue;
}
p = &TREE_CHAIN (*p);
}
}
BITMAP_FREE (vars_to_remove);
/* Rewire the entry and exit blocks. The successor to the entry /* Rewire the entry and exit blocks. The successor to the entry
block turns into the successor of DEST_FN's ENTRY_BLOCK_PTR in block turns into the successor of DEST_FN's ENTRY_BLOCK_PTR in
...@@ -5655,30 +5776,41 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, ...@@ -5655,30 +5776,41 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
FIXME, this is silly. The CFG ought to become a parameter to FIXME, this is silly. The CFG ought to become a parameter to
these helpers. */ these helpers. */
set_cfun (dest_cfun); push_cfun (dest_cfun);
make_edge (ENTRY_BLOCK_PTR, entry_bb, EDGE_FALLTHRU); make_edge (ENTRY_BLOCK_PTR, entry_bb, EDGE_FALLTHRU);
if (exit_bb) if (exit_bb)
make_edge (exit_bb, EXIT_BLOCK_PTR, 0); make_edge (exit_bb, EXIT_BLOCK_PTR, 0);
set_cfun (saved_cfun); pop_cfun ();
/* Back in the original function, the SESE region has disappeared, /* Back in the original function, the SESE region has disappeared,
create a new basic block in its place. */ create a new basic block in its place. */
bb = create_empty_bb (entry_pred[0]); bb = create_empty_bb (entry_pred[0]);
for (i = 0; i < num_entry_edges; i++) for (i = 0; i < num_entry_edges; i++)
make_edge (entry_pred[i], bb, entry_flag[i]); {
e = make_edge (entry_pred[i], bb, entry_flag[i]);
e->probability = entry_prob[i];
}
for (i = 0; i < num_exit_edges; i++) for (i = 0; i < num_exit_edges; i++)
make_edge (bb, exit_succ[i], exit_flag[i]); {
e = make_edge (bb, exit_succ[i], exit_flag[i]);
e->probability = exit_prob[i];
}
set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
for (i = 0; VEC_iterate (basic_block, dom_bbs, i, abb); i++)
set_immediate_dominator (CDI_DOMINATORS, abb, bb);
VEC_free (basic_block, heap, dom_bbs);
if (exit_bb) if (exit_bb)
{ {
free (exit_prob);
free (exit_flag); free (exit_flag);
free (exit_succ); free (exit_succ);
} }
free (entry_prob);
free (entry_flag); free (entry_flag);
free (entry_pred); free (entry_pred);
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
VEC_free (basic_block, heap, bbs); VEC_free (basic_block, heap, bbs);
return bb; return bb;
......
...@@ -711,6 +711,8 @@ extern struct omp_region *root_omp_region; ...@@ -711,6 +711,8 @@ extern struct omp_region *root_omp_region;
extern struct omp_region *new_omp_region (basic_block, enum tree_code, extern struct omp_region *new_omp_region (basic_block, enum tree_code,
struct omp_region *); struct omp_region *);
extern void free_omp_regions (void); extern void free_omp_regions (void);
extern tree find_omp_clause (tree, enum tree_code);
tree copy_var_decl (tree, tree, tree);
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
Function prototypes Function prototypes
......
...@@ -290,6 +290,7 @@ extern struct tree_opt_pass pass_lower_vector; ...@@ -290,6 +290,7 @@ extern struct tree_opt_pass pass_lower_vector;
extern struct tree_opt_pass pass_lower_vector_ssa; extern struct tree_opt_pass pass_lower_vector_ssa;
extern struct tree_opt_pass pass_lower_omp; extern struct tree_opt_pass pass_lower_omp;
extern struct tree_opt_pass pass_expand_omp; extern struct tree_opt_pass pass_expand_omp;
extern struct tree_opt_pass pass_expand_omp_ssa;
extern struct tree_opt_pass pass_object_sizes; extern struct tree_opt_pass pass_object_sizes;
extern struct tree_opt_pass pass_fold_builtins; extern struct tree_opt_pass pass_fold_builtins;
extern struct tree_opt_pass pass_stdarg; extern struct tree_opt_pass pass_stdarg;
......
...@@ -1393,7 +1393,16 @@ mark_virtual_ops_for_renaming (tree stmt) ...@@ -1393,7 +1393,16 @@ mark_virtual_ops_for_renaming (tree stmt)
tree var; tree var;
if (TREE_CODE (stmt) == PHI_NODE) if (TREE_CODE (stmt) == PHI_NODE)
return; {
var = PHI_RESULT (stmt);
if (is_gimple_reg (var))
return;
if (TREE_CODE (var) == SSA_NAME)
var = SSA_NAME_VAR (var);
mark_sym_for_renaming (var);
return;
}
update_stmt (stmt); update_stmt (stmt);
......
...@@ -2247,21 +2247,72 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) ...@@ -2247,21 +2247,72 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
get_expr_operands (stmt, &CHANGE_DYNAMIC_TYPE_LOCATION (expr), opf_use); get_expr_operands (stmt, &CHANGE_DYNAMIC_TYPE_LOCATION (expr), opf_use);
return; return;
case OMP_FOR:
{
tree init = OMP_FOR_INIT (expr);
tree cond = OMP_FOR_COND (expr);
tree incr = OMP_FOR_INCR (expr);
tree c, clauses = OMP_FOR_CLAUSES (stmt);
get_expr_operands (stmt, &GIMPLE_STMT_OPERAND (init, 0), opf_def);
get_expr_operands (stmt, &GIMPLE_STMT_OPERAND (init, 1), opf_use);
get_expr_operands (stmt, &TREE_OPERAND (cond, 1), opf_use);
get_expr_operands (stmt, &TREE_OPERAND (GIMPLE_STMT_OPERAND (incr, 1), 1),
opf_use);
c = find_omp_clause (clauses, OMP_CLAUSE_SCHEDULE);
if (c)
get_expr_operands (stmt, &OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c),
opf_use);
return;
}
case OMP_CONTINUE:
{
get_expr_operands (stmt, &TREE_OPERAND (expr, 0), opf_def);
get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_use);
return;
}
case OMP_PARALLEL:
{
tree c, clauses = OMP_PARALLEL_CLAUSES (stmt);
if (OMP_PARALLEL_DATA_ARG (stmt))
{
get_expr_operands (stmt, &OMP_PARALLEL_DATA_ARG (stmt), opf_use);
add_to_addressable_set (OMP_PARALLEL_DATA_ARG (stmt),
&s_ann->addresses_taken);
}
c = find_omp_clause (clauses, OMP_CLAUSE_IF);
if (c)
get_expr_operands (stmt, &OMP_CLAUSE_IF_EXPR (c), opf_use);
c = find_omp_clause (clauses, OMP_CLAUSE_NUM_THREADS);
if (c)
get_expr_operands (stmt, &OMP_CLAUSE_NUM_THREADS_EXPR (c), opf_use);
return;
}
case OMP_SECTIONS:
{
get_expr_operands (stmt, &OMP_SECTIONS_CONTROL (expr), opf_def);
return;
}
case BLOCK: case BLOCK:
case FUNCTION_DECL: case FUNCTION_DECL:
case EXC_PTR_EXPR: case EXC_PTR_EXPR:
case FILTER_EXPR: case FILTER_EXPR:
case LABEL_DECL: case LABEL_DECL:
case CONST_DECL: case CONST_DECL:
case OMP_PARALLEL:
case OMP_SECTIONS:
case OMP_FOR:
case OMP_SINGLE: case OMP_SINGLE:
case OMP_MASTER: case OMP_MASTER:
case OMP_ORDERED: case OMP_ORDERED:
case OMP_CRITICAL: case OMP_CRITICAL:
case OMP_RETURN: case OMP_RETURN:
case OMP_CONTINUE: case OMP_SECTION:
case OMP_SECTIONS_SWITCH:
/* Expressions that make no memory references. */ /* Expressions that make no memory references. */
return; return;
......
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