Commit dea61d92 by Sebastian Pop Committed by Sebastian Pop

invoke.texi: Document -ftree-loop-distribution.

	* doc/invoke.texi: Document -ftree-loop-distribution.
	* tree-loop-distribution.c: New.
	* tree-pass.h (pass_loop_distribution): New.
	* graphds.h (struct graph): Add htab_t indices.
	* timevar.def (TV_TREE_LOOP_DISTRIBUTION): New.
	* tree-vectorizer.c (rename_variables_in_loop): Extern.
	(slpeel_tree_duplicate_loop_to_edge_cfg): Init PENDING_STMT to NULL.
	* tree-vectorizer.h (tree_duplicate_loop_on_edge): Declared.
	* tree-data-ref.c (debug_data_dependence_relations): New.
	(dump_data_dependence_relation): Also print data references.
	(free_data_ref): Extern.
	(same_access_functions): Moved...
	(find_vertex_for_stmt): Renamed rdg_vertex_for_stmt.
	(dump_rdg_vertex, debug_rdg_vertex, dump_rdg_component,
	debug_rdg_component, dump_rdg, debug_rdg, dot_rdg_1, dot_rdg,
	struct rdg_vertex_info, rdg_vertex_for_stmt): New.
	(create_rdg_edge_for_ddr, create_rdg_vertices): Cleaned up.
	(stmts_from_loop): Skip LABEL_EXPR.
	(hash_stmt_vertex_info, eq_stmt_vertex_info, hash_stmt_vertex_del): New.
	(build_rdg): Initialize rdg->indices htab.
	(free_rdg, stores_from_loop, ref_base_address,
	rdg_defs_used_in_other_loops_p, have_similar_memory_accesses,
	have_similar_memory_accesses_1, ref_base_address_1,
	remove_similar_memory_refs): New.
	* tree-data-ref.h: Depend on tree-chrec.h.
	(debug_data_dependence_relations, free_data_ref): Declared.
	(same_access_functions): ... here.
	(ddr_is_anti_dependent, ddrs_have_anti_deps, ddr_dependence_level): New.
	(struct rdg_vertex): Add has_mem_write and has_mem_reads.
	(RDGV_HAS_MEM_WRITE, RDGV_HAS_MEM_READS, RDG_STMT,
	RDG_MEM_WRITE_STMT, RDG_MEM_READS_STMT): New.
	(dump_rdg_vertex, debug_rdg_vertex, dump_rdg_component,
	debug_rdg_component, dump_rdg, debug_rdg, dot_rdg,
	rdg_vertex_for_stmt): Declared.
	(struct rdg_edge): Add level.
	(RDGE_LEVEL): New.
	(free_rdg, stores_from_loop, remove_similar_memory_refs,
	rdg_defs_used_in_other_loops_p, have_similar_memory_accesses): Declared.
	(rdg_has_similar_memory_accesses): New.
	* tree-vect-analyze.c: Remove unused static decls.
	* lambda.h (dependence_level): New.
	* common.opt (ftree-loop-distribution): New.
	* tree-flow.h (mark_virtual_ops_in_bb, 
	slpeel_tree_duplicate_loop_to_edge_cfg,
	rename_variables_in_loop): Declared.
	* Makefile.in (TREE_DATA_REF_H): Depend on tree-chrec.h.
	(OBJS-common): Add tree-loop-distribution.o.
	(tree-loop-distribution.o): New rule.
	* tree-cfg.c (mark_virtual_ops_in_bb): New.
	(mark_virtual_ops_in_region): Use mark_virtual_ops_in_bb.
	* passes.c (init_optimization_passes): Schedule pass_loop_distribution.

	* testsuite/gcc.dg/tree-ssa/ldist-{1..12}.c: New.

From-SVN: r132745
parent dde75838
2008-02-28 Sebastian Pop <sebastian.pop@amd.com>
* doc/invoke.texi: Document -ftree-loop-distribution.
* tree-loop-distribution.c: New.
* tree-pass.h (pass_loop_distribution): New.
* graphds.h (struct graph): Add htab_t indices.
* timevar.def (TV_TREE_LOOP_DISTRIBUTION): New.
* tree-vectorizer.c (rename_variables_in_loop): Extern.
(slpeel_tree_duplicate_loop_to_edge_cfg): Init PENDING_STMT to NULL.
* tree-vectorizer.h (tree_duplicate_loop_on_edge): Declared.
* tree-data-ref.c (debug_data_dependence_relations): New.
(dump_data_dependence_relation): Also print data references.
(free_data_ref): Extern.
(same_access_functions): Moved...
(find_vertex_for_stmt): Renamed rdg_vertex_for_stmt.
(dump_rdg_vertex, debug_rdg_vertex, dump_rdg_component,
debug_rdg_component, dump_rdg, debug_rdg, dot_rdg_1, dot_rdg,
struct rdg_vertex_info, rdg_vertex_for_stmt): New.
(create_rdg_edge_for_ddr, create_rdg_vertices): Cleaned up.
(stmts_from_loop): Skip LABEL_EXPR.
(hash_stmt_vertex_info, eq_stmt_vertex_info, hash_stmt_vertex_del): New.
(build_rdg): Initialize rdg->indices htab.
(free_rdg, stores_from_loop, ref_base_address,
rdg_defs_used_in_other_loops_p, have_similar_memory_accesses,
have_similar_memory_accesses_1, ref_base_address_1,
remove_similar_memory_refs): New.
* tree-data-ref.h: Depend on tree-chrec.h.
(debug_data_dependence_relations, free_data_ref): Declared.
(same_access_functions): ... here.
(ddr_is_anti_dependent, ddrs_have_anti_deps, ddr_dependence_level): New.
(struct rdg_vertex): Add has_mem_write and has_mem_reads.
(RDGV_HAS_MEM_WRITE, RDGV_HAS_MEM_READS, RDG_STMT,
RDG_MEM_WRITE_STMT, RDG_MEM_READS_STMT): New.
(dump_rdg_vertex, debug_rdg_vertex, dump_rdg_component,
debug_rdg_component, dump_rdg, debug_rdg, dot_rdg,
rdg_vertex_for_stmt): Declared.
(struct rdg_edge): Add level.
(RDGE_LEVEL): New.
(free_rdg, stores_from_loop, remove_similar_memory_refs,
rdg_defs_used_in_other_loops_p, have_similar_memory_accesses): Declared.
(rdg_has_similar_memory_accesses): New.
* tree-vect-analyze.c: Remove unused static decls.
* lambda.h (dependence_level): New.
* common.opt (ftree-loop-distribution): New.
* tree-flow.h (mark_virtual_ops_in_bb,
slpeel_tree_duplicate_loop_to_edge_cfg,
rename_variables_in_loop): Declared.
* Makefile.in (TREE_DATA_REF_H): Depend on tree-chrec.h.
(OBJS-common): Add tree-loop-distribution.o.
(tree-loop-distribution.o): New rule.
* tree-cfg.c (mark_virtual_ops_in_bb): New.
(mark_virtual_ops_in_region): Use mark_virtual_ops_in_bb.
* passes.c (init_optimization_passes): Schedule pass_loop_distribution.
2008-02-28 Joseph Myers <joseph@codesourcery.com> 2008-02-28 Joseph Myers <joseph@codesourcery.com>
PR target/33963 PR target/33963
......
...@@ -838,7 +838,7 @@ DIAGNOSTIC_H = diagnostic.h diagnostic.def $(PRETTY_PRINT_H) options.h ...@@ -838,7 +838,7 @@ DIAGNOSTIC_H = diagnostic.h diagnostic.def $(PRETTY_PRINT_H) options.h
C_PRETTY_PRINT_H = c-pretty-print.h $(PRETTY_PRINT_H) $(C_COMMON_H) $(TREE_H) C_PRETTY_PRINT_H = c-pretty-print.h $(PRETTY_PRINT_H) $(C_COMMON_H) $(TREE_H)
SCEV_H = tree-scalar-evolution.h $(GGC_H) tree-chrec.h $(PARAMS_H) SCEV_H = tree-scalar-evolution.h $(GGC_H) tree-chrec.h $(PARAMS_H)
LAMBDA_H = lambda.h $(TREE_H) vec.h $(GGC_H) LAMBDA_H = lambda.h $(TREE_H) vec.h $(GGC_H)
TREE_DATA_REF_H = tree-data-ref.h $(LAMBDA_H) omega.h graphds.h TREE_DATA_REF_H = tree-data-ref.h $(LAMBDA_H) omega.h graphds.h tree-chrec.h
VARRAY_H = varray.h $(MACHMODE_H) $(SYSTEM_H) coretypes.h $(TM_H) VARRAY_H = varray.h $(MACHMODE_H) $(SYSTEM_H) coretypes.h $(TM_H)
TREE_INLINE_H = tree-inline.h $(VARRAY_H) pointer-set.h TREE_INLINE_H = tree-inline.h $(VARRAY_H) pointer-set.h
REAL_H = real.h $(MACHMODE_H) REAL_H = real.h $(MACHMODE_H)
...@@ -1156,6 +1156,7 @@ OBJS-common = \ ...@@ -1156,6 +1156,7 @@ OBJS-common = \
tree-if-conv.o \ tree-if-conv.o \
tree-into-ssa.o \ tree-into-ssa.o \
tree-iterator.o \ tree-iterator.o \
tree-loop-distribution.o \
tree-loop-linear.o \ tree-loop-linear.o \
tree-nested.o \ tree-nested.o \
tree-nrv.o \ tree-nrv.o \
...@@ -2283,6 +2284,11 @@ tree-loop-linear.o: tree-loop-linear.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ ...@@ -2283,6 +2284,11 @@ tree-loop-linear.o: tree-loop-linear.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \ $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \
tree-pass.h $(TREE_DATA_REF_H) $(SCEV_H) $(EXPR_H) $(LAMBDA_H) \ tree-pass.h $(TREE_DATA_REF_H) $(SCEV_H) $(EXPR_H) $(LAMBDA_H) \
$(TARGET_H) tree-chrec.h $(OBSTACK_H) $(TARGET_H) tree-chrec.h $(OBSTACK_H)
tree-loop-distribution.o: tree-loop-distribution.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(GGC_H) $(OPTABS_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) \
$(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \
tree-pass.h $(TREE_DATA_REF_H) $(SCEV_H) $(EXPR_H) \
$(TARGET_H) tree-chrec.h tree-vectorizer.h
tree-parloops.o: tree-parloops.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ tree-parloops.o: tree-parloops.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_FLOW_H) $(TREE_H) $(RTL_H) $(CFGLOOP_H) $(TREE_DATA_REF_H) $(GGC_H) \ $(TREE_FLOW_H) $(TREE_H) $(RTL_H) $(CFGLOOP_H) $(TREE_DATA_REF_H) $(GGC_H) \
$(DIAGNOSTIC_H) tree-pass.h $(SCEV_H) langhooks.h gt-tree-parloops.h \ $(DIAGNOSTIC_H) tree-pass.h $(SCEV_H) langhooks.h gt-tree-parloops.h \
......
...@@ -1098,6 +1098,10 @@ ftree-fre ...@@ -1098,6 +1098,10 @@ ftree-fre
Common Report Var(flag_tree_fre) Optimization Common Report Var(flag_tree_fre) Optimization
Enable Full Redundancy Elimination (FRE) on trees Enable Full Redundancy Elimination (FRE) on trees
ftree-loop-distribution
Common Report Var(flag_tree_loop_distribution)
Enable loop distribution on trees
ftree-loop-im ftree-loop-im
Common Report Var(flag_tree_loop_im) Init(1) Optimization Common Report Var(flag_tree_loop_im) Init(1) Optimization
Enable loop invariant motion on trees Enable loop invariant motion on trees
......
...@@ -354,6 +354,7 @@ Objective-C and Objective-C++ Dialects}. ...@@ -354,6 +354,7 @@ Objective-C and Objective-C++ Dialects}.
-fstrict-aliasing -fstrict-overflow -fthread-jumps -ftracer -ftree-ccp @gol -fstrict-aliasing -fstrict-overflow -fthread-jumps -ftracer -ftree-ccp @gol
-ftree-ch -ftree-copy-prop -ftree-copyrename -ftree-dce @gol -ftree-ch -ftree-copy-prop -ftree-copyrename -ftree-dce @gol
-ftree-dominator-opts -ftree-dse -ftree-fre -ftree-loop-im @gol -ftree-dominator-opts -ftree-dse -ftree-fre -ftree-loop-im @gol
-ftree-loop-distribution @gol
-ftree-loop-ivcanon -ftree-loop-linear -ftree-loop-optimize @gol -ftree-loop-ivcanon -ftree-loop-linear -ftree-loop-optimize @gol
-ftree-parallelize-loops=@var{n} -ftree-pre -ftree-reassoc -ftree-salias @gol -ftree-parallelize-loops=@var{n} -ftree-pre -ftree-reassoc -ftree-salias @gol
-ftree-sink -ftree-sra -ftree-store-ccp -ftree-ter @gol -ftree-sink -ftree-sra -ftree-store-ccp -ftree-ter @gol
...@@ -5928,6 +5929,11 @@ performance and allow further loop optimizations to take place. ...@@ -5928,6 +5929,11 @@ performance and allow further loop optimizations to take place.
Compare the results of several data dependence analyzers. This option Compare the results of several data dependence analyzers. This option
is used for debugging the data dependence analyzers. is used for debugging the data dependence analyzers.
@item -ftree-loop-distribution
Perform loop distribution. This flag can improve cache performance on
big loop bodies and allow further loop optimizations, like
parallelization or vectorization, to take place.
@item -ftree-loop-im @item -ftree-loop-im
@opindex ftree-loop-im @opindex ftree-loop-im
Perform loop invariant motion on trees. This pass moves only invariants that Perform loop invariant motion on trees. This pass moves only invariants that
......
...@@ -47,6 +47,7 @@ struct graph ...@@ -47,6 +47,7 @@ struct graph
int n_vertices; /* Number of vertices. */ int n_vertices; /* Number of vertices. */
struct vertex *vertices; struct vertex *vertices;
/* The vertices. */ /* The vertices. */
htab_t indices; /* Fast lookup for indices. */
}; };
struct graph *new_graph (int); struct graph *new_graph (int);
......
...@@ -469,5 +469,22 @@ build_linear_expr (tree type, lambda_vector coefs, VEC (tree, heap) *ivs) ...@@ -469,5 +469,22 @@ build_linear_expr (tree type, lambda_vector coefs, VEC (tree, heap) *ivs)
return expr; return expr;
} }
/* Returns the dependence level for a vector DIST of size LENGTH.
LEVEL = 0 means a lexicographic dependence, i.e. a dependence due
to the sequence of statements, not carried by any loop. */
static inline unsigned
dependence_level (lambda_vector dist_vect, int length)
{
int i;
for (i = 0; i < length; i++)
if (dist_vect[i] != 0)
return i + 1;
return 0;
}
#endif /* LAMBDA_H */ #endif /* LAMBDA_H */
...@@ -625,6 +625,7 @@ init_optimization_passes (void) ...@@ -625,6 +625,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_empty_loop); NEXT_PASS (pass_empty_loop);
NEXT_PASS (pass_record_bounds); NEXT_PASS (pass_record_bounds);
NEXT_PASS (pass_check_data_deps); NEXT_PASS (pass_check_data_deps);
NEXT_PASS (pass_loop_distribution);
NEXT_PASS (pass_linear_transform); NEXT_PASS (pass_linear_transform);
NEXT_PASS (pass_iv_canon); NEXT_PASS (pass_iv_canon);
NEXT_PASS (pass_if_conversion); NEXT_PASS (pass_if_conversion);
......
2008-02-28 Sebastian Pop <sebastian.pop@amd.com>
* testsuite/gcc.dg/tree-ssa/ldist-1.c: New.
* testsuite/gcc.dg/tree-ssa/ldist-1a.c: New.
* testsuite/gcc.dg/tree-ssa/ldist-2.c: New.
* testsuite/gcc.dg/tree-ssa/ldist-3.c: New.
* testsuite/gcc.dg/tree-ssa/ldist-4.c: New.
* testsuite/gcc.dg/tree-ssa/ldist-5.c: New.
* testsuite/gcc.dg/tree-ssa/ldist-6.c: New.
* testsuite/gcc.dg/tree-ssa/ldist-7.c: New.
* testsuite/gcc.dg/tree-ssa/ldist-8.c: New.
* testsuite/gcc.dg/tree-ssa/ldist-9.c: New.
* testsuite/gcc.dg/tree-ssa/ldist-10.c: New.
* testsuite/gcc.dg/tree-ssa/ldist-11.c: New.
* testsuite/gcc.dg/tree-ssa/ldist-12.c: New.
* testsuite/gfortran.dg/ldist-1.f90: New.
2008-02-28 Uros Bizjak <ubizjak@gmail.com> 2008-02-28 Uros Bizjak <ubizjak@gmail.com>
* gcc.dg/pr34351.c: Compile for x86 targets only. Use %ebx register. * gcc.dg/pr34351.c: Compile for x86 targets only. Use %ebx register.
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" } */
void foo (int * __restrict__ ia,
int * __restrict__ ib,
int * __restrict__ oxa,
int * __restrict__ oxb,
int * __restrict__ oya,
int * __restrict__ oyb)
{
int i;
long int mya[52];
long int myb[52];
for (i=0; i < 52; i++)
{
mya[i] = ia[i] * oxa[i] + ib[i] * oxb[i];
myb[i] = -ia[i] * oxb[i] + ib[i] * oxa[i];
oya[i] = mya[i] >> 10;
oyb[i] = myb[i] >> 10;
}
/* This loop was distributed, but it is not anymore due to the cost
model changes: the result of a distribution would look like this:
| for (i=0; i < 52; i++)
| oya[i] = ia[i] * oxa[i] + ib[i] * oxb[i] >> 10;
|
| for (i=0; i < 52; i++)
| oyb[i] = -ia[i] * oxb[i] + ib[i] * oxa[i] >> 10;
and in this the array IA is read in both tasks. For maximizing
the cache reuse, ldist does not distributes this loop anymore.
*/
}
/* { dg-final { scan-tree-dump-times "distributed: split to 2 loops" 0 "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" } */
int loop1 (int k)
{
unsigned int i;
int a[1000], b[1000], c[1000];
for (i = 1; i < 1000; i ++)
{
a[i] = c[i]; /* S1 */
b[i] = a[i-1]+1; /* S2 */
}
/* Dependences:
S1->S2 (flow, level 1)
One partition as A is used in both S1 and S2.
*/
return a[1000-2] + b[1000-1] + c[1000-2];
}
/* { dg-final { scan-tree-dump-times "distributed: split to 2 loops" 0 "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" } */
void foo (int * __restrict__ ia,
int * __restrict__ ib,
int * __restrict__ oxa,
int * __restrict__ oxb,
int * __restrict__ oya,
int * __restrict__ oyb)
{
int i;
long int mya[52];
long int myb[52];
for (i=0; i < 52; i++)
{
mya[i] = ia[i] * oxa[i] + ib[i] * oxb[i];
myb[i] = -ia[i] * oxb[i] + ib[i] * oxa[i];
oya[i] = 0;
oyb[i] = myb[i] >> 10;
}
/* This loop should be distributed, and the result should look like
this:
| memset (oya, 0, 208);
| for (i=0; i < 52; i++)
| oyb[i] = -ia[i] * oxb[i] + ib[i] * oxa[i] >> 10;
*/
}
/* { dg-final { scan-tree-dump-times "distributed: split to 2 loops" 1 "ldist" } } */
/* { dg-final { scan-tree-dump-times "generated memset zero" 1 "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" } */
int foo (int * __restrict__ ia,
int * __restrict__ ib,
int * __restrict__ oxa,
int * __restrict__ oxb)
{
int i;
int oya[52], oyb[52];
for (i=0; i < 52; i++)
{
oya[i] = (ia[i] * oxa[i]) >> 10;
oyb[i] = (ib[i] * oxb[i]) >> 10;
}
return oya[22] + oyb[21];
}
/* { dg-final { scan-tree-dump-times "distributed: split to 2 loops" 1 "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" } */
int foo (int * __restrict__ ia,
int * __restrict__ ib,
int * __restrict__ oxa,
int * __restrict__ oxb)
{
int i;
int oya[52], oyb[52];
for (i=0; i < 52; i++)
{
oya[i] = (ia[i] * oxa[i] + ib[i] * oxb[i]) >> 10;
oyb[i] = (-ia[i] * oxb[i] + ib[i] * oxa[i]) >> 10;
}
return oya[22] + oyb[21];
}
/* { dg-final { scan-tree-dump-times "distributed: split to 2 loops" 0 "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" } */
void foo (int * __restrict__ a,
int * __restrict__ b,
int * __restrict__ c)
{
int i;
for (i=1; i < 10; i++)
{
a[i] += c[i];
b[i] = a[i - 1] + 1;
}
/* This loop is not distributed because the cost of spliting it:
| for (i=1; i < N; i++)
| a[i] += c[i];
|
| for (i=1; i < N; i++)
| b[i] = a[i - 1] + 1;
is higher due to data in array A that is written and then read in
another task. The cost model should forbid the transformation in
this case.
*/
}
/* { dg-final { scan-tree-dump-times "distributed: split to 2 loops" 0 "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" } */
int loop1 (int k)
{
unsigned int i;
int a[10000], b[10000], c[10000], d[10000];
a[0] = k; a[3] = k*2;
c[1] = k+1;
for (i = 2; i < (10000-1); i ++)
{
a[i] = k * i; /* S1 */
b[i] = a[i-2] + k; /* S2 */
c[i] = b[i] + a[i+1]; /* S3 */
d[i] = c[i-1] + k + i; /* S4 */
}
/*
Dependences:
S1 -> S2 (flow, level 1)
S1 -> S3 (anti, level 1)
S2 -> S3 (flow, level 0)
S3 -> S4 (flow, level 1)
There are three partitions: {S1, S3}, {S2} and {S4}.
The cost model should fuse together all the partitions, as they
are reusing the same data, ending on a single partition.
*/
return a[10000-2] + b[10000-1] + c[10000-2] + d[10000-2];
}
/* { dg-final { scan-tree-dump-times "distributed: split to 3 loops" 0 "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" } */
int loop1 (int k)
{
unsigned int i;
unsigned int j;
int a[100], b[100][100];
a[0] = k;
for (i = 1; i < 100; i ++)
{
for (j = 0; j < 100; j++)
{
a[j] = k * i;
b[i][j] = a[j-1] + k;
}
}
return b[100-1][0];
}
/* We used to distribute also innermost loops, but these could produce
too much code in the outer loop, degrading performance of scalar
code. So this test is XFAILed because the cost model of the stand
alone distribution pass has evolved. */
/* { dg-final { scan-tree-dump-times "distributed: split to 2 loops" 0 "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" } */
int loop1 (int k)
{
unsigned int i;
unsigned int j;
int a[100][100], b[100][100], c[100][100], d[100][100];
a[0][0] = k;
for (i = 1; i < 100; i ++)
for (j = 1; j < (100-1); j++)
{
a[i][j] = k * i; /* S1 */
b[i][j] = a[i][j-1] + k; /* S2 */
c[i][j] = b[i][j] + a[i][j+1]; /* S3 */
d[i][j] = c[i][j] + k + i; /* S4 */
}
/* Dependences:
S1->S2 (flow, level 2)
S1->S3 (anti, level 2)
S2->S3 (flow, level 0)
S3->S4 (flow, level 0)
*/
return a[100-1][100-1] + b[100-1][100-1] + c[100-1][100-1] + d[100-1][100-1];
}
/* FIXME: This is XFAILed because of a data dependence analysis
problem: the dependence test fails with a "don't know" relation. */
/* { dg-final { scan-tree-dump-times "distributed: split to 2 loops" 1 "ldist" { xfail *-*-* } } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" } */
int loop1 (int k)
{
unsigned int i;
int a[1000], b[1000], c[1000], d[1000];
for (i = 2; i < (1000-1); i ++) {
a[i] = k * i; /* S1 */
b[i] = a[i-2] + k; /* S2 */
c[i] = b[i-1] + a[i+1]; /* S3 */
d[i] = c[i-1] + k + i; /* S4 */
}
/* Dependences:
S1->S2 (flow, level 1)
S2->S3 (flow, level 1)
S3->S1 (anti, level 1)
S3->S4 (flow, level 1)
There are two partitions: {S1, S2, S3} and {S4}.
{S1, S2, S3} have to be in the same partition because:
- S1 (i) has to be executed before S2 (i+2), as S1 produces a[i] that is then consumed 2 iterations later by S2.
- S2 (i) has to be executed before S3 (i+1), as S2 produces b[i] that is then consumed one iteration later by S3,
- S3 (i) has to be executed before S1 (i+1), as a[i+1] has to execute before the update to a[i],
{S4} is the consumer partition: it consumes the values from array "c" produced in S3.
The cost model should fuse all the tasks together as the cost of
fetching data from caches is too high.
*/
return a[1000-2] + b[1000-1] + c[1000-2] + d[1000-2];
}
/* { dg-final { scan-tree-dump-times "distributed: split to 2 loops" 0 "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" } */
int loop1 (int k)
{
unsigned int i, z;
int a[1000], b[1000], c[1000], d[1000];
for (i = 2; i < (1000-1); i ++) {
z = a[i+1]; /* S1 */
a[i] = k * i; /* S2 */
b[i] = a[i-2] + k; /* S3 */
c[i] = b[i-1] + z; /* S4 */
d[i] = c[i-1] + b[i+1] + k + i; /* S5 */
}
/* Dependences:
S1->S2 (anti, level 1)
S1->S4 (flow, level 1, scalar)
S2->S3 (flow, level 1)
S3->S4 (flow, level 1)
S4->S5 (flow, level 1)
S5->S3 (anti, level 1)
There is a single partition: {S1, S2, S3, S4, S5}, because of the
scalar dependence z between the two partitions {S1, S2} and {S3, S4, S5}.
*/
return a[1000-2] + b[1000-1] + c[1000-2] + d[1000-2];
}
/* { dg-final { scan-tree-dump-times "distributed" 0 "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" } */
int loop1 (int k)
{
unsigned int i;
int a[1000], b[1000], c[1000], d[1000];
for (i = 2; i < (1000-1); i ++)
{
a[i] = k * i; /* S1 */
b[i] = a[i+1] + k; /* S2 */
c[i] = a[i-1] + b[i-1] + d[i-1]; /* S3 */
d[i] = a[i-1] + b[i+1] + k + i; /* S4 */
}
/* Dependences:
S1->S2 (anti, level 1)
S1->S3 (flow, level 1)
S1->S4 (flow, level 1)
S2->S3 (flow, level 1)
S2->S4 (anti, level 1)
S4->S3 (flow, level 1)
Two partitions: {S1, S2, S4} produce information that is consumed in {S3}.
So that means that the current cost model will also fuse these
two partitions into a single one for avoiding cache misses.
*/
return a[1000-2] + b[1000-1] + c[1000-2] + d[1000-2];
}
/* { dg-final { scan-tree-dump-times "distributed: split to 2 loops" 0 "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" } */
int loop1 (int k)
{
unsigned int i;
int a[1000], b[1000];
for (i = 1; i < (1000-1); i ++) {
a[i] = a[i+1] + a[i-1]; /* S1 */
b[i] = a[i-1] + k; /* S2 */
}
/*
Dependences:
S1->S2 (flow, level 1)
S1->S1 (anti, level 1)
S1->S1 (flow, level 1)
One partition, because of the cost of cache misses.
*/
return a[1000-2] + b[1000-1];
}
/* { dg-final { scan-tree-dump-times "distributed: split to 2 loops" 0 "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
! { dg-do compile }
! { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-all" }
Subroutine PADEC(DKS,DKDS,HVAR,WM,WG,FN,NS,AN,BN,CN,IT)
IMPLICIT REAL*8 (A-H, O-Z)
DIMENSION DKS(*),DKDS(*),HVAR(*)
COMPLEX*16 WM(*),WG(*),FN(*),AN(*),BN(*),CN(*)
COMPLEX*16 H2,CONST
COMMON/STRCH/ALP,BET,DH,ZH,UG,VG,T1,T2,DT,TOL,ALPHA ,HAMP,BUMP
Parameter (F1 = .8333333333333333D0, F2 = .0833333333333333D0)
SS=DT/(2.0D0)
do J=2,NS
BS=SS*DKS(J)*HVAR(J)*HVAR(J)
AN(J)=F1+2.*BS
BN(J)=F2-BS
CN(J)=F2-BS
H2=WM(J+1)
if(J.EQ.NS) then
CONST=CN(J)*H2
else
CONST=(0.D0,0.D0)
endif
FN(J)=(BS+F2)*(H2)+(F1-2.D0*BS)-CONST
end do
return
end Subroutine PADEC
! { dg-final { scan-tree-dump-times "distributed: split to 4 loops" 1 "ldist" } }
! { dg-final { cleanup-tree-dump "ldist" } }
...@@ -123,6 +123,7 @@ DEFTIMEVAR (TV_COMPLETE_UNROLL , "complete unrolling") ...@@ -123,6 +123,7 @@ DEFTIMEVAR (TV_COMPLETE_UNROLL , "complete unrolling")
DEFTIMEVAR (TV_TREE_PARALLELIZE_LOOPS, "tree parallelize loops") DEFTIMEVAR (TV_TREE_PARALLELIZE_LOOPS, "tree parallelize loops")
DEFTIMEVAR (TV_TREE_VECTORIZATION , "tree vectorization") DEFTIMEVAR (TV_TREE_VECTORIZATION , "tree vectorization")
DEFTIMEVAR (TV_TREE_LINEAR_TRANSFORM , "tree loop linear") DEFTIMEVAR (TV_TREE_LINEAR_TRANSFORM , "tree loop linear")
DEFTIMEVAR (TV_TREE_LOOP_DISTRIBUTION, "tree loop distribution")
DEFTIMEVAR (TV_CHECK_DATA_DEPS , "tree check data dependences") DEFTIMEVAR (TV_CHECK_DATA_DEPS , "tree check data dependences")
DEFTIMEVAR (TV_TREE_PREFETCH , "tree prefetching") DEFTIMEVAR (TV_TREE_PREFETCH , "tree prefetching")
DEFTIMEVAR (TV_TREE_LOOP_IVOPTS , "tree iv optimization") DEFTIMEVAR (TV_TREE_LOOP_IVOPTS , "tree iv optimization")
......
...@@ -5646,22 +5646,30 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data) ...@@ -5646,22 +5646,30 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data)
/* Marks virtual operands of all statements in basic blocks BBS for /* Marks virtual operands of all statements in basic blocks BBS for
renaming. */ renaming. */
static void void
mark_virtual_ops_in_region (VEC (basic_block,heap) *bbs) mark_virtual_ops_in_bb (basic_block bb)
{ {
tree phi; tree phi;
block_stmt_iterator bsi; block_stmt_iterator bsi;
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));
}
/* Marks virtual operands of all statements in basic blocks BBS for
renaming. */
static void
mark_virtual_ops_in_region (VEC (basic_block,heap) *bbs)
{
basic_block bb; basic_block bb;
unsigned i; unsigned i;
for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++) for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
{ mark_virtual_ops_in_bb (bb);
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
......
...@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "graphds.h" #include "graphds.h"
#include "lambda.h" #include "lambda.h"
#include "omega.h" #include "omega.h"
#include "tree-chrec.h"
/* /*
innermost_loop_behavior describes the evolution of the address of the memory innermost_loop_behavior describes the evolution of the address of the memory
...@@ -38,6 +39,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -38,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
Example 1 Example 2 Example 1 Example 2
data-ref a[j].b[i][j] *(p + x + 16B + 4B * j) data-ref a[j].b[i][j] *(p + x + 16B + 4B * j)
innermost_loop_behavior innermost_loop_behavior
base_address &a p base_address &a p
offset i * D_i x offset i * D_i x
...@@ -319,26 +321,107 @@ extern void debug_data_dependence_relation (struct data_dependence_relation *); ...@@ -319,26 +321,107 @@ extern void debug_data_dependence_relation (struct data_dependence_relation *);
extern void dump_data_dependence_relation (FILE *, extern void dump_data_dependence_relation (FILE *,
struct data_dependence_relation *); struct data_dependence_relation *);
extern void dump_data_dependence_relations (FILE *, VEC (ddr_p, heap) *); extern void dump_data_dependence_relations (FILE *, VEC (ddr_p, heap) *);
extern void debug_data_dependence_relations (VEC (ddr_p, heap) *);
extern void dump_data_dependence_direction (FILE *, extern void dump_data_dependence_direction (FILE *,
enum data_dependence_direction); enum data_dependence_direction);
extern void free_dependence_relation (struct data_dependence_relation *); extern void free_dependence_relation (struct data_dependence_relation *);
extern void free_dependence_relations (VEC (ddr_p, heap) *); extern void free_dependence_relations (VEC (ddr_p, heap) *);
extern void free_data_ref (data_reference_p);
extern void free_data_refs (VEC (data_reference_p, heap) *); extern void free_data_refs (VEC (data_reference_p, heap) *);
struct data_reference *create_data_ref (struct loop *, tree, tree, bool); struct data_reference *create_data_ref (struct loop *, tree, tree, bool);
bool find_loop_nest (struct loop *, VEC (loop_p, heap) **); bool find_loop_nest (struct loop *, VEC (loop_p, heap) **);
void compute_all_dependences (VEC (data_reference_p, heap) *, void compute_all_dependences (VEC (data_reference_p, heap) *,
VEC (ddr_p, heap) **, VEC (loop_p, heap) *, bool); VEC (ddr_p, heap) **, VEC (loop_p, heap) *, bool);
/* Return true when the DDR contains two data references that have the
same access functions. */
static inline bool
same_access_functions (const struct data_dependence_relation *ddr)
{
unsigned i;
for (i = 0; i < DDR_NUM_SUBSCRIPTS (ddr); i++)
if (!eq_evolutions_p (DR_ACCESS_FN (DDR_A (ddr), i),
DR_ACCESS_FN (DDR_B (ddr), i)))
return false;
return true;
}
/* Return true when DDR is an anti-dependence relation. */
static inline bool
ddr_is_anti_dependent (ddr_p ddr)
{
return (DDR_ARE_DEPENDENT (ddr) == NULL_TREE
&& DR_IS_READ (DDR_A (ddr))
&& !DR_IS_READ (DDR_B (ddr))
&& !same_access_functions (ddr));
}
/* Return true when DEPENDENCE_RELATIONS contains an anti-dependence. */
static inline bool
ddrs_have_anti_deps (VEC (ddr_p, heap) *dependence_relations)
{
unsigned i;
ddr_p ddr;
for (i = 0; VEC_iterate (ddr_p, dependence_relations, i, ddr); i++)
if (ddr_is_anti_dependent (ddr))
return true;
return false;
}
/* Return the dependence level for the DDR relation. */
static inline unsigned
ddr_dependence_level (ddr_p ddr)
{
unsigned vector;
unsigned level = 0;
if (DDR_DIST_VECTS (ddr))
level = dependence_level (DDR_DIST_VECT (ddr, 0), DDR_NB_LOOPS (ddr));
for (vector = 1; vector < DDR_NUM_DIST_VECTS (ddr); vector++)
level = MIN (level, dependence_level (DDR_DIST_VECT (ddr, vector),
DDR_NB_LOOPS (ddr)));
return level;
}
/* A RDG vertex representing a statement. */ /* A Reduced Dependence Graph (RDG) vertex representing a statement. */
typedef struct rdg_vertex typedef struct rdg_vertex
{ {
/* The statement represented by this vertex. */ /* The statement represented by this vertex. */
tree stmt; tree stmt;
/* True when the statement contains a write to memory. */
bool has_mem_write;
/* True when the statement contains a read from memory. */
bool has_mem_reads;
} *rdg_vertex_p; } *rdg_vertex_p;
#define RDGV_STMT(V) ((struct rdg_vertex *) ((V)->data))->stmt #define RDGV_STMT(V) ((struct rdg_vertex *) ((V)->data))->stmt
#define RDGV_HAS_MEM_WRITE(V) ((struct rdg_vertex *) ((V)->data))->has_mem_write
#define RDGV_HAS_MEM_READS(V) ((struct rdg_vertex *) ((V)->data))->has_mem_reads
#define RDG_STMT(RDG, I) RDGV_STMT (&(RDG->vertices[I]))
#define RDG_MEM_WRITE_STMT(RDG, I) RDGV_HAS_MEM_WRITE (&(RDG->vertices[I]))
#define RDG_MEM_READS_STMT(RDG, I) RDGV_HAS_MEM_READS (&(RDG->vertices[I]))
void dump_rdg_vertex (FILE *, struct graph *, int);
void debug_rdg_vertex (struct graph *, int);
void dump_rdg_component (FILE *, struct graph *, int, bitmap);
void debug_rdg_component (struct graph *, int);
void dump_rdg (FILE *, struct graph *);
void debug_rdg (struct graph *);
void dot_rdg (struct graph *);
int rdg_vertex_for_stmt (struct graph *, tree);
/* Data dependence type. */ /* Data dependence type. */
...@@ -363,11 +446,17 @@ typedef struct rdg_edge ...@@ -363,11 +446,17 @@ typedef struct rdg_edge
{ {
/* Type of the dependence. */ /* Type of the dependence. */
enum rdg_dep_type type; enum rdg_dep_type type;
/* Levels of the dependence: the depth of the loops that
carry the dependence. */
unsigned level;
} *rdg_edge_p; } *rdg_edge_p;
#define RDGE_TYPE(E) ((struct rdg_edge *) ((E)->data))->type #define RDGE_TYPE(E) ((struct rdg_edge *) ((E)->data))->type
#define RDGE_LEVEL(E) ((struct rdg_edge *) ((E)->data))->level
struct graph *build_rdg (struct loop *); struct graph *build_rdg (struct loop *);
void free_rdg (struct graph *);
/* Return the index of the variable VAR in the LOOP_NEST array. */ /* Return the index of the variable VAR in the LOOP_NEST array. */
...@@ -385,6 +474,21 @@ index_in_loop_nest (int var, VEC (loop_p, heap) *loop_nest) ...@@ -385,6 +474,21 @@ index_in_loop_nest (int var, VEC (loop_p, heap) *loop_nest)
return var_index; return var_index;
} }
void stores_from_loop (struct loop *, VEC (tree, heap) **);
void remove_similar_memory_refs (VEC (tree, heap) **);
bool rdg_defs_used_in_other_loops_p (struct graph *, int);
bool have_similar_memory_accesses (tree, tree);
/* Determines whether RDG vertices V1 and V2 access to similar memory
locations, in which case they have to be in the same partition. */
static inline bool
rdg_has_similar_memory_accesses (struct graph *rdg, int v1, int v2)
{
return have_similar_memory_accesses (RDG_STMT (rdg, v1),
RDG_STMT (rdg, v2));
}
/* In lambda-code.c */ /* In lambda-code.c */
bool lambda_transform_legal_p (lambda_trans_matrix, int, VEC (ddr_p, heap) *); bool lambda_transform_legal_p (lambda_trans_matrix, int, VEC (ddr_p, heap) *);
......
...@@ -792,6 +792,7 @@ extern void end_recording_case_labels (void); ...@@ -792,6 +792,7 @@ extern void end_recording_case_labels (void);
extern basic_block move_sese_region_to_fn (struct function *, basic_block, extern basic_block move_sese_region_to_fn (struct function *, basic_block,
basic_block); basic_block);
void remove_edge_and_dominated_blocks (edge); void remove_edge_and_dominated_blocks (edge);
void mark_virtual_ops_in_bb (basic_block);
/* In tree-cfgcleanup.c */ /* In tree-cfgcleanup.c */
extern bitmap cfgcleanup_altered_bbs; extern bitmap cfgcleanup_altered_bbs;
...@@ -1022,6 +1023,8 @@ bool tree_duplicate_loop_to_header_edge (struct loop *, edge, ...@@ -1022,6 +1023,8 @@ bool tree_duplicate_loop_to_header_edge (struct loop *, edge,
unsigned int, sbitmap, unsigned int, sbitmap,
edge, VEC (edge, heap) **, edge, VEC (edge, heap) **,
int); int);
struct loop *slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *, edge);
void rename_variables_in_loop (struct loop *);
struct loop *tree_ssa_loop_version (struct loop *, tree, struct loop *tree_ssa_loop_version (struct loop *, tree,
basic_block *); basic_block *);
tree expand_simple_operations (tree); tree expand_simple_operations (tree);
......
...@@ -265,6 +265,7 @@ extern struct tree_opt_pass pass_scev_cprop; ...@@ -265,6 +265,7 @@ extern struct tree_opt_pass pass_scev_cprop;
extern struct tree_opt_pass pass_empty_loop; extern struct tree_opt_pass pass_empty_loop;
extern struct tree_opt_pass pass_record_bounds; extern struct tree_opt_pass pass_record_bounds;
extern struct tree_opt_pass pass_if_conversion; extern struct tree_opt_pass pass_if_conversion;
extern struct tree_opt_pass pass_loop_distribution;
extern struct tree_opt_pass pass_vectorize; extern struct tree_opt_pass pass_vectorize;
extern struct tree_opt_pass pass_complete_unroll; extern struct tree_opt_pass pass_complete_unroll;
extern struct tree_opt_pass pass_parallelize_loops; extern struct tree_opt_pass pass_parallelize_loops;
......
...@@ -41,28 +41,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -41,28 +41,7 @@ along with GCC; see the file COPYING3. If not see
#include "toplev.h" #include "toplev.h"
#include "recog.h" #include "recog.h"
/* Main analysis functions. */
static bool vect_analyze_data_refs (loop_vec_info);
static bool vect_mark_stmts_to_be_vectorized (loop_vec_info);
static void vect_analyze_scalar_cycles (loop_vec_info);
static bool vect_analyze_data_ref_accesses (loop_vec_info);
static bool vect_analyze_data_ref_dependences (loop_vec_info);
static bool vect_analyze_data_refs_alignment (loop_vec_info);
static bool vect_compute_data_refs_alignment (loop_vec_info);
static bool vect_enhance_data_refs_alignment (loop_vec_info);
static bool vect_analyze_operations (loop_vec_info);
static bool vect_determine_vectorization_factor (loop_vec_info);
/* Utility functions for the analyses. */
static bool exist_non_indexing_operands_for_use_p (tree, tree);
static tree vect_get_loop_niters (struct loop *, tree *);
static bool vect_analyze_data_ref_dependence
(struct data_dependence_relation *, loop_vec_info);
static bool vect_compute_data_ref_alignment (struct data_reference *);
static bool vect_analyze_data_ref_access (struct data_reference *);
static bool vect_can_advance_ivs_p (loop_vec_info); static bool vect_can_advance_ivs_p (loop_vec_info);
static void vect_update_misalignment_for_peel
(struct data_reference *, struct data_reference *, int npeel);
/* Function vect_determine_vectorization_factor /* Function vect_determine_vectorization_factor
......
...@@ -147,24 +147,8 @@ along with GCC; see the file COPYING3. If not see ...@@ -147,24 +147,8 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pass.h" #include "tree-pass.h"
/************************************************************************* /*************************************************************************
Simple Loop Peeling Utilities
*************************************************************************/
static void slpeel_update_phis_for_duplicate_loop
(struct loop *, struct loop *, bool after);
static void slpeel_update_phi_nodes_for_guard1
(edge, struct loop *, bool, basic_block *, bitmap *);
static void slpeel_update_phi_nodes_for_guard2
(edge, struct loop *, bool, basic_block *);
static edge slpeel_add_loop_guard (basic_block, tree, basic_block, basic_block);
static void rename_use_op (use_operand_p);
static void rename_variables_in_bb (basic_block);
static void rename_variables_in_loop (struct loop *);
/*************************************************************************
General Vectorization Utilities General Vectorization Utilities
*************************************************************************/ *************************************************************************/
static void vect_set_dump_settings (void);
/* vect_dump will be set to stderr or dump_file if exist. */ /* vect_dump will be set to stderr or dump_file if exist. */
FILE *vect_dump; FILE *vect_dump;
...@@ -241,7 +225,7 @@ rename_variables_in_bb (basic_block bb) ...@@ -241,7 +225,7 @@ rename_variables_in_bb (basic_block bb)
/* Renames variables in new generated LOOP. */ /* Renames variables in new generated LOOP. */
static void void
rename_variables_in_loop (struct loop *loop) rename_variables_in_loop (struct loop *loop)
{ {
unsigned i; unsigned i;
...@@ -806,7 +790,7 @@ slpeel_make_loop_iterate_ntimes (struct loop *loop, tree niters) ...@@ -806,7 +790,7 @@ slpeel_make_loop_iterate_ntimes (struct loop *loop, tree niters)
/* Given LOOP this function generates a new copy of it and puts it /* Given LOOP this function generates a new copy of it and puts it
on E which is either the entry or exit of LOOP. */ on E which is either the entry or exit of LOOP. */
static struct loop * struct loop *
slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop, edge e) slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop, edge e)
{ {
struct loop *new_loop; struct loop *new_loop;
...@@ -871,6 +855,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop, edge e) ...@@ -871,6 +855,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop, edge e)
if (at_exit) /* Add the loop copy at exit. */ if (at_exit) /* Add the loop copy at exit. */
{ {
redirect_edge_and_branch_force (e, new_loop->header); redirect_edge_and_branch_force (e, new_loop->header);
PENDING_STMT (e) = NULL;
set_immediate_dominator (CDI_DOMINATORS, new_loop->header, e->src); set_immediate_dominator (CDI_DOMINATORS, new_loop->header, e->src);
if (was_imm_dom) if (was_imm_dom)
set_immediate_dominator (CDI_DOMINATORS, exit_dest, new_loop->header); set_immediate_dominator (CDI_DOMINATORS, exit_dest, new_loop->header);
...@@ -888,6 +873,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop, edge e) ...@@ -888,6 +873,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop, edge e)
new_exit_e = EDGE_SUCC (new_loop->header, 1); new_exit_e = EDGE_SUCC (new_loop->header, 1);
redirect_edge_and_branch_force (new_exit_e, loop->header); redirect_edge_and_branch_force (new_exit_e, loop->header);
PENDING_STMT (new_exit_e) = NULL;
set_immediate_dominator (CDI_DOMINATORS, loop->header, set_immediate_dominator (CDI_DOMINATORS, loop->header,
new_exit_e->src); new_exit_e->src);
...@@ -901,6 +887,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop, edge e) ...@@ -901,6 +887,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop, edge e)
} }
redirect_edge_and_branch_force (entry_e, new_loop->header); redirect_edge_and_branch_force (entry_e, new_loop->header);
PENDING_STMT (entry_e) = NULL;
set_immediate_dominator (CDI_DOMINATORS, new_loop->header, preheader); set_immediate_dominator (CDI_DOMINATORS, new_loop->header, preheader);
} }
......
...@@ -630,6 +630,7 @@ extern struct loop *slpeel_tree_peel_loop_to_edge ...@@ -630,6 +630,7 @@ extern struct loop *slpeel_tree_peel_loop_to_edge
(struct loop *, edge, tree, tree, bool, unsigned int, bool); (struct loop *, edge, tree, tree, bool, unsigned int, bool);
extern void set_prologue_iterations (basic_block, tree, extern void set_prologue_iterations (basic_block, tree,
struct loop *, unsigned int); struct loop *, unsigned int);
struct loop *tree_duplicate_loop_on_edge (struct loop *, edge);
extern void slpeel_make_loop_iterate_ntimes (struct loop *, tree); extern void slpeel_make_loop_iterate_ntimes (struct loop *, tree);
extern bool slpeel_can_duplicate_loop_p (const struct loop *, const_edge); extern bool slpeel_can_duplicate_loop_p (const struct loop *, const_edge);
#ifdef ENABLE_CHECKING #ifdef ENABLE_CHECKING
......
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