summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorspop <spop@138bc75d-0d04-0410-961f-82ee72b054a4>2008-09-02 16:31:04 +0000
committerspop <spop@138bc75d-0d04-0410-961f-82ee72b054a4>2008-09-02 16:31:04 +0000
commit255b6be72832e001a6aa896bada736ffc2735b19 (patch)
tree1f3fd1f9608de8f06cfa843f8a480d295f0665d1 /gcc
parentcd8171dd88ae95d9e06c4e9a22bf445ba14babd6 (diff)
downloadgcc-255b6be72832e001a6aa896bada736ffc2735b19.tar.gz
2008-09-02 Sebastian Pop <sebastian.pop@amd.com>
Tobias Grosser <grosser@fim.uni-passau.de> Jan Sjodin <jan.sjodin@amd.com> Harsha Jagasia <harsha.jagasia@amd.com> Dwarakanath Rajagopal <dwarak.rajagopal@amd.com> Konrad Trifunovic <konrad.trifunovic@inria.fr> Adrien Eliche <aeliche@isty.uvsq.fr> Merge from graphite branch. * configure: Regenerate. * Makefile.in: Regenerate. * configure.ac (host_libs): Add ppl and cloog. Add checks for PPL and CLooG. * Makefile.def (ppl, cloog): Added modules and dependences. * Makefile.tpl (PPLLIBS, PPLINC, CLOOGLIBS, CLOOGINC): New. (HOST_PPLLIBS, HOST_PPLINC, HOST_CLOOGLIBS, HOST_CLOOGINC): New. gcc/ * graphite.c: New. * graphite.h: New. * tree-loop-linear.c (perfect_loop_nest_depth): Export. * doc/invoke.texi (-floop-block, -floop-interchange, -floop-strip-mine): Document new flags. * tree-into-ssa.c (gimple_vec): Moved... * tree-loop-distribution.c (rdg_component): Moved... * cfgloopmanip.c: Include tree-flow.h. (update_dominators_in_loop): New. (create_empty_if_region_on_edge): New. (create_empty_loop_on_edge): New. (loopify): Use update_dominators_in_loop. * tree-pass.h (pass_graphite_transforms): Declared. * configure: Regenerate. * tree-phinodes.c (make_phi_node): Export. (add_phi_node_to_bb): New, split from create_phi_node. * tree-chrec.c (for_each_scev_op): New. * tree-chrec.h (for_each_scev_op): Declared. * tree-ssa-loop-ivopts.c (get_phi_with_result): New. (remove_statement): Call get_phi_with_result. * config.in (HAVE_cloog): Undef. * gdbinit.in (pgg): New. * timevar.def (TV_GRAPHITE_TRANSFORMS): New. * tree-ssa-loop.c (graphite_transforms): New. (gate_graphite_transforms): New. (pass_graphite_transforms): New. * configure.ac (PPLLIBS, PPLINC, CLOOGLIBS, CLOOGINC, HAVE_cloog): Defined. * tree-vectorizer.c (rename_variables_in_bb): Export. * tree-data-ref.c (dr_may_alias_p): Export. (stmt_simple_memref_p): New. (find_data_references_in_stmt): Export. (find_data_references_in_loop): Export. (create_rdg_edge_for_ddr): Initialize RDGE_RELATION. (create_rdg_edges_for_scalar): Initialize RDGE_RELATION. (create_rdg_vertices): Export. (build_empty_rdg): New. (build_rdg): Call build_empty_rdg. Free dependence_relations. * tree-data-ref.h (rdg_component): ... here. (scop_p): New. (struct data_reference): Add a field scop. (DR_SCOP): New. (find_data_references_in_loop): Declared. (find_data_references_in_stmt): Declared. (create_rdg_vertices): Declared. (dr_may_alias_p): Declared. (stmt_simple_memref_p): Declared. (struct rdg_edge): Add a field ddr_p relation. (build_empty_rdg): Declared. * lambda.h (lambda_matrix): Declare a VEC of. (find_induction_var_from_exit_cond): Declared. (lambda_vector_compare): New. * common.opt (fgraphite, floop-strip-mine, floop-interchange, floop-block): New flags. * lambda-code.c (find_induction_var_from_exit_cond): Export. * cfgloop.c (is_loop_exit): New. * cfgloop.h (is_loop_exit): Declared. (create_empty_if_region_on_edge): Declared. (create_empty_loop_on_edge): Declared. * tree-flow.h (add_phi_node_to_bb): Declared. (make_phi_node): Declared. (rename_variables_in_bb): Declared. (perfect_loop_nest_depth): Declared. (graphite_transform_loops): Declared. * Makefile.in (cfgloopmanip.o): Depend on TREE_FLOW_H. (graphite.o-warn): Add -Wno-error. (PPLLIBS, PPLINC, CLOOGLIBS, CLOOGINC): Declared. (LIBS): Add GMPLIBS, CLOOGLIBS, PPLLIBS. (INCLUDES): Add PPLINC, CLOOGINC. (OBJS-common): Add graphite.o. (graphite.o): Add rule. * gimple.h (gimple_vec): ... here. * tree-cfg.c (print_loops): Start printing at ENTRY_BLOCK_PTR. * passes.c (init_optimization_passes): Schedule pass_graphite_transforms. testsuite/ * gcc.dg/graphite/scop-{0,1,2,3,4,5,6,7,8,9, 10,11,12,13,14,15,16,17,18}.c: New. * gcc.dg/graphite/graphite.exp: New. * gcc.dg/graphite/scop-matmult.c: New. * gcc.dg/graphite/block-0.c: New. * lib/target-supports.exp (check_effective_target_fgraphite): New. * gfortran.dg/graphite/block-1.f90: New. * gfortran.dg/graphite/scop-{1,2}.f: New. * gfortran.dg/graphite/block-{1,3,4}.f90: New. * gfortran.dg/graphite/graphite.exp: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@139893 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/Makefile.in21
-rw-r--r--gcc/cfgloop.c15
-rw-r--r--gcc/cfgloop.h4
-rw-r--r--gcc/cfgloopmanip.c272
-rw-r--r--gcc/common.opt16
-rw-r--r--gcc/config.in6
-rwxr-xr-xgcc/configure70
-rw-r--r--gcc/configure.ac9
-rw-r--r--gcc/doc/invoke.texi76
-rw-r--r--gcc/gdbinit.in9
-rw-r--r--gcc/gimple.h6
-rw-r--r--gcc/graphite.c4806
-rw-r--r--gcc/graphite.h516
-rw-r--r--gcc/lambda-code.c3
-rw-r--r--gcc/lambda.h31
-rw-r--r--gcc/passes.c1
-rw-r--r--gcc/testsuite/ChangeLog20
-rw-r--r--gcc/testsuite/gcc.dg/graphite/block-0.c25
-rw-r--r--gcc/testsuite/gcc.dg/graphite/block-1.c31
-rw-r--r--gcc/testsuite/gcc.dg/graphite/graphite.exp48
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-0.c24
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-1.c33
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-10.c33
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-11.c34
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-12.c38
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-13.c43
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-14.c27
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-15.c52
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-16.c25
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-17.c24
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-18.c26
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-2.c41
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-3.c30
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-4.c31
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-5.c37
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-6.c33
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-7.c33
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-8.c33
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-9.c29
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-matmult.c20
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/block-1.f9014
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/block-2.f22
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/block-3.f9019
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/block-4.f9022
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/graphite.exp48
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/scop-1.f13
-rw-r--r--gcc/testsuite/lib/target-supports.exp9
-rw-r--r--gcc/timevar.def1
-rw-r--r--gcc/tree-cfg.c2
-rw-r--r--gcc/tree-chrec.c23
-rw-r--r--gcc/tree-chrec.h1
-rw-r--r--gcc/tree-data-ref.c56
-rw-r--r--gcc/tree-data-ref.h50
-rw-r--r--gcc/tree-flow.h7
-rw-r--r--gcc/tree-into-ssa.c6
-rw-r--r--gcc/tree-loop-distribution.c14
-rw-r--r--gcc/tree-loop-linear.c2
-rw-r--r--gcc/tree-pass.h1
-rw-r--r--gcc/tree-phinodes.c22
-rw-r--r--gcc/tree-ssa-loop-ivopts.c26
-rw-r--r--gcc/tree-ssa-loop.c43
-rw-r--r--gcc/tree-vectorizer.c2
62 files changed, 6930 insertions, 104 deletions
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index f5ee1e3fd1e..4a4bfc2f2ca 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -183,6 +183,8 @@ dfp.o-warn = -Wno-error
bitmap.o-warn = -Wno-error
# dominance.c contains a -Wc++compat warning.
dominance.o-warn = -Wno-error
+# graphite.c contains code calling cloog that has problems.
+graphite.o-warn = -Wno-error
# All warnings have to be shut off in stage1 if the compiler used then
# isn't gcc; configure determines that. WARN_CFLAGS will be either
@@ -281,6 +283,14 @@ ZLIBINC = @zlibinc@
GMPLIBS = @GMPLIBS@
GMPINC = @GMPINC@
+# How to find PPL
+PPLLIBS = @PPLLIBS@
+PPLINC = @PPLINC@
+
+# How to find CLOOG
+CLOOGLIBS = @CLOOGLIBS@
+CLOOGINC = @CLOOGINC@
+
CPPLIB = ../libcpp/libcpp.a
CPPINC = -I$(srcdir)/../libcpp/include
@@ -891,7 +901,8 @@ BUILD_LIBDEPS= $(BUILD_LIBIBERTY)
# How to link with both our special library facilities
# and the system's installed libraries.
-LIBS = @LIBS@ $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBIBERTY) $(LIBDECNUMBER)
+LIBS = @LIBS@ $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBIBERTY) $(LIBDECNUMBER) \
+ $(GMPLIBS) $(CLOOGLIBS) $(PPLLIBS)
# Any system libraries needed just for GNAT.
SYSLIBS = @GNAT_LIBEXC@
@@ -920,7 +931,8 @@ BUILD_ERRORS = build/errors.o
# libintl.h will be found in ../intl if we are using the included libintl.
INCLUDES = -I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) \
-I$(srcdir)/../include @INCINTL@ \
- $(CPPINC) $(GMPINC) $(DECNUMINC)
+ $(CPPINC) $(GMPINC) $(DECNUMINC) \
+ $(PPLINC) $(CLOOGINC)
.c.o:
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
@@ -1094,6 +1106,7 @@ OBJS-common = \
global.o \
graph.o \
graphds.o \
+ graphite.o \
gtype-desc.o \
haifa-sched.o \
hooks.o \
@@ -2340,6 +2353,10 @@ tree-data-ref.o: tree-data-ref.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(GGC_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) $(DIAGNOSTIC_H) \
$(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \
$(TREE_DATA_REF_H) $(SCEV_H) tree-pass.h tree-chrec.h langhooks.h
+graphite.o: graphite.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+ $(GGC_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) $(DIAGNOSTIC_H) $(TOPLEV_H) \
+ $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) $(GIMPLE_H) domwalk.h \
+ $(TREE_DATA_REF_H) $(SCEV_H) tree-pass.h tree-chrec.h graphite.h pointer-set.h
tree-vect-analyze.o: tree-vect-analyze.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(GGC_H) $(OPTABS_H) $(TREE_H) $(RECOG_H) $(BASIC_BLOCK_H) \
$(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \
diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c
index 0e95323008a..f6fe6239886 100644
--- a/gcc/cfgloop.c
+++ b/gcc/cfgloop.c
@@ -1620,3 +1620,18 @@ single_exit (const struct loop *loop)
else
return NULL;
}
+
+/* Returns true when BB has an edge exiting LOOP. */
+
+bool
+is_loop_exit (struct loop *loop, basic_block bb)
+{
+ edge e;
+ edge_iterator ei;
+
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ if (loop_exit_edge_p (loop, e))
+ return true;
+
+ return false;
+}
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index aa3e6118ed6..37bf9937bfa 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -228,6 +228,7 @@ extern int num_loop_insns (const struct loop *);
extern int average_num_loop_insns (const struct loop *);
extern unsigned get_loop_level (const struct loop *);
extern bool loop_exit_edge_p (const struct loop *, const_edge);
+extern bool is_loop_exit (struct loop *, basic_block);
extern void mark_loop_exit_edges (void);
/* Loops & cfg manipulation. */
@@ -284,6 +285,9 @@ extern bool can_duplicate_loop_p (const struct loop *loop);
#define DLTHE_FLAG_COMPLETTE_PEEL 4 /* Update frequencies expecting
a complete peeling. */
+extern edge create_empty_if_region_on_edge (edge, tree);
+extern struct loop *create_empty_loop_on_edge (edge, tree, tree, tree, tree,
+ tree *, struct loop *);
extern struct loop * duplicate_loop (struct loop *, struct loop *);
extern bool duplicate_loop_to_header_edge (struct loop *, edge,
unsigned, sbitmap, edge,
diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c
index 025b5be1052..d8979b44f4a 100644
--- a/gcc/cfgloopmanip.c
+++ b/gcc/cfgloopmanip.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfglayout.h"
#include "cfghooks.h"
#include "output.h"
+#include "tree-flow.h"
static void duplicate_subloops (struct loop *, struct loop *);
static void copy_loops_to (struct loop **, int,
@@ -466,6 +467,243 @@ scale_loop_frequencies (struct loop *loop, int num, int den)
free (bbs);
}
+/* Recompute dominance information for basic blocks outside LOOP. */
+
+static void
+update_dominators_in_loop (struct loop *loop)
+{
+ VEC (basic_block, heap) *dom_bbs = NULL;
+ sbitmap seen;
+ basic_block *body;
+ unsigned i;
+
+ seen = sbitmap_alloc (last_basic_block);
+ sbitmap_zero (seen);
+ body = get_loop_body (loop);
+
+ for (i = 0; i < loop->num_nodes; i++)
+ SET_BIT (seen, body[i]->index);
+
+ for (i = 0; i < loop->num_nodes; i++)
+ {
+ basic_block ldom;
+
+ for (ldom = first_dom_son (CDI_DOMINATORS, body[i]);
+ ldom;
+ ldom = next_dom_son (CDI_DOMINATORS, ldom))
+ if (!TEST_BIT (seen, ldom->index))
+ {
+ SET_BIT (seen, ldom->index);
+ VEC_safe_push (basic_block, heap, dom_bbs, ldom);
+ }
+ }
+
+ iterate_fix_dominators (CDI_DOMINATORS, dom_bbs, false);
+ free (body);
+ free (seen);
+ VEC_free (basic_block, heap, dom_bbs);
+}
+
+/* Creates an if region as shown above. CONDITION is used to create
+ the test for the if.
+
+ |
+ | ------------- -------------
+ | | pred_bb | | pred_bb |
+ | ------------- -------------
+ | | |
+ | | | ENTRY_EDGE
+ | | ENTRY_EDGE V
+ | | ====> -------------
+ | | | cond_bb |
+ | | | CONDITION |
+ | | -------------
+ | V / \
+ | ------------- e_false / \ e_true
+ | | succ_bb | V V
+ | ------------- ----------- -----------
+ | | false_bb | | true_bb |
+ | ----------- -----------
+ | \ /
+ | \ /
+ | V V
+ | -------------
+ | | join_bb |
+ | -------------
+ | | exit_edge (result)
+ | V
+ | -----------
+ | | succ_bb |
+ | -----------
+ |
+ */
+
+edge
+create_empty_if_region_on_edge (edge entry_edge, tree condition)
+{
+
+ basic_block succ_bb, cond_bb, true_bb, false_bb, join_bb;
+ edge e_true, e_false, exit_edge;
+ gimple cond_stmt;
+ tree simple_cond;
+ gimple_stmt_iterator gsi;
+
+ succ_bb = entry_edge->dest;
+ cond_bb = split_edge (entry_edge);
+
+ /* Insert condition in cond_bb. */
+ gsi = gsi_last_bb (cond_bb);
+ simple_cond =
+ force_gimple_operand_gsi (&gsi, condition, true, NULL,
+ false, GSI_NEW_STMT);
+ cond_stmt = gimple_build_cond_from_tree (simple_cond, NULL_TREE, NULL_TREE);
+ gsi = gsi_last_bb (cond_bb);
+ gsi_insert_after (&gsi, cond_stmt, GSI_NEW_STMT);
+
+ join_bb = split_edge (single_succ_edge (cond_bb));
+
+ e_true = single_succ_edge (cond_bb);
+ true_bb = split_edge (e_true);
+
+ e_false = make_edge (cond_bb, join_bb, 0);
+ false_bb = split_edge (e_false);
+
+ e_true->flags &= ~EDGE_FALLTHRU;
+ e_true->flags |= EDGE_TRUE_VALUE;
+ e_false->flags &= ~EDGE_FALLTHRU;
+ e_false->flags |= EDGE_FALSE_VALUE;
+
+ set_immediate_dominator (CDI_DOMINATORS, cond_bb, entry_edge->src);
+ set_immediate_dominator (CDI_DOMINATORS, true_bb, cond_bb);
+ set_immediate_dominator (CDI_DOMINATORS, false_bb, cond_bb);
+ set_immediate_dominator (CDI_DOMINATORS, join_bb, cond_bb);
+
+ exit_edge = single_succ_edge (join_bb);
+
+ if (single_pred_p (exit_edge->dest))
+ set_immediate_dominator (CDI_DOMINATORS, exit_edge->dest, join_bb);
+
+ return exit_edge;
+}
+
+/* create_empty_loop_on_edge
+ |
+ | ------------- ------------------------
+ | | pred_bb | | pred_bb |
+ | ------------- | IV_0 = INITIAL_VALUE |
+ | | ------------------------
+ | | ______ | ENTRY_EDGE
+ | | ENTRY_EDGE / V V
+ | | ====> | -----------------------------
+ | | | | IV_BEFORE = phi (IV_0, IV) |
+ | | | | loop_header |
+ | V | | IV_BEFORE <= UPPER_BOUND |
+ | ------------- | -----------------------\-----
+ | | succ_bb | | | \
+ | ------------- | | \ exit_e
+ | | V V---------
+ | | -------------- | succ_bb |
+ | | | loop_latch | ----------
+ | | |IV = IV_BEFORE + STRIDE
+ | | --------------
+ | \ /
+ | \ ___ /
+
+ Creates an empty loop as shown above, the IV_BEFORE is the SSA_NAME
+ that is used before the increment of IV. IV_BEFORE should be used for
+ adding code to the body that uses the IV. OUTER is the outer loop in
+ which the new loop should be inserted. */
+
+struct loop *
+create_empty_loop_on_edge (edge entry_edge,
+ tree initial_value,
+ tree stride, tree upper_bound,
+ tree iv,
+ tree *iv_before,
+ struct loop *outer)
+{
+ basic_block loop_header, loop_latch, succ_bb, pred_bb;
+ struct loop *loop;
+ int freq;
+ gcov_type cnt;
+ gimple_stmt_iterator gsi;
+ bool insert_after;
+ gimple_seq stmts;
+ gimple cond_expr;
+ tree exit_test;
+ edge exit_e;
+ int prob;
+ tree upper_bound_gimplified;
+
+ gcc_assert (entry_edge && initial_value && stride && upper_bound && iv);
+
+ /* Create header, latch and wire up the loop. */
+ pred_bb = entry_edge->src;
+ loop_header = split_edge (entry_edge);
+ loop_latch = split_edge (single_succ_edge (loop_header));
+ succ_bb = single_succ (loop_latch);
+ make_edge (loop_header, succ_bb, 0);
+ redirect_edge_succ_nodup (single_succ_edge (loop_latch), loop_header);
+
+ /* Set immediate dominator information. */
+ set_immediate_dominator (CDI_DOMINATORS, loop_header, pred_bb);
+ set_immediate_dominator (CDI_DOMINATORS, loop_latch, loop_header);
+ set_immediate_dominator (CDI_DOMINATORS, succ_bb, loop_header);
+
+ /* Initialize a loop structure and put it in a loop hierarchy. */
+ loop = alloc_loop ();
+ loop->header = loop_header;
+ loop->latch = loop_latch;
+ add_loop (loop, outer);
+
+ /* TODO: Fix frequencies and counts. */
+ freq = EDGE_FREQUENCY (entry_edge);
+ cnt = entry_edge->count;
+
+ prob = REG_BR_PROB_BASE / 2;
+
+ scale_loop_frequencies (loop, REG_BR_PROB_BASE - prob, REG_BR_PROB_BASE);
+
+ /* Update dominators. */
+ update_dominators_in_loop (loop);
+
+ /* Construct IV code in loop. */
+ initial_value = force_gimple_operand (initial_value, &stmts, true, iv);
+ if (stmts)
+ {
+ gsi_insert_seq_on_edge (loop_preheader_edge (loop), stmts);
+ gsi_commit_edge_inserts ();
+ }
+
+ standard_iv_increment_position (loop, &gsi, &insert_after);
+ create_iv (initial_value, stride, iv, loop, &gsi, insert_after,
+ iv_before, NULL);
+
+ /* Modify edge flags. */
+ exit_e = single_exit (loop);
+ exit_e->flags = EDGE_LOOP_EXIT | EDGE_FALSE_VALUE;
+ single_pred_edge (loop_latch)->flags = EDGE_TRUE_VALUE;
+
+ gsi = gsi_last_bb (exit_e->src);
+
+ upper_bound_gimplified =
+ force_gimple_operand_gsi (&gsi, upper_bound, true, NULL,
+ false, GSI_NEW_STMT);
+ gsi = gsi_last_bb (exit_e->src);
+
+ cond_expr = gimple_build_cond
+ (LE_EXPR, *iv_before, upper_bound_gimplified, NULL_TREE, NULL_TREE);
+
+ exit_test = gimple_cond_lhs (cond_expr);
+ exit_test = force_gimple_operand_gsi (&gsi, exit_test, true, NULL,
+ false, GSI_NEW_STMT);
+ gimple_cond_set_lhs (cond_expr, exit_test);
+ gsi = gsi_last_bb (exit_e->src);
+ gsi_insert_after (&gsi, cond_expr, GSI_NEW_STMT);
+
+ return loop;
+}
+
/* Make area between HEADER_EDGE and LATCH_EDGE a loop by connecting
latch to header and update loop tree and dominators
accordingly. Everything between them plus LATCH_EDGE destination must
@@ -483,10 +721,6 @@ loopify (edge latch_edge, edge header_edge,
{
basic_block succ_bb = latch_edge->dest;
basic_block pred_bb = header_edge->src;
- basic_block *body;
- VEC (basic_block, heap) *dom_bbs;
- unsigned i;
- sbitmap seen;
struct loop *loop = alloc_loop ();
struct loop *outer = loop_outer (succ_bb->loop_father);
int freq;
@@ -538,35 +772,7 @@ loopify (edge latch_edge, edge header_edge,
}
scale_loop_frequencies (loop, false_scale, REG_BR_PROB_BASE);
scale_loop_frequencies (succ_bb->loop_father, true_scale, REG_BR_PROB_BASE);
-
- /* Update dominators of blocks outside of LOOP. */
- dom_bbs = NULL;
- seen = sbitmap_alloc (last_basic_block);
- sbitmap_zero (seen);
- body = get_loop_body (loop);
-
- for (i = 0; i < loop->num_nodes; i++)
- SET_BIT (seen, body[i]->index);
-
- for (i = 0; i < loop->num_nodes; i++)
- {
- basic_block ldom;
-
- for (ldom = first_dom_son (CDI_DOMINATORS, body[i]);
- ldom;
- ldom = next_dom_son (CDI_DOMINATORS, ldom))
- if (!TEST_BIT (seen, ldom->index))
- {
- SET_BIT (seen, ldom->index);
- VEC_safe_push (basic_block, heap, dom_bbs, ldom);
- }
- }
-
- iterate_fix_dominators (CDI_DOMINATORS, dom_bbs, false);
-
- free (body);
- free (seen);
- VEC_free (basic_block, heap, dom_bbs);
+ update_dominators_in_loop (loop);
return loop;
}
diff --git a/gcc/common.opt b/gcc/common.opt
index 87824f524a7..e7f8159a161 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -547,6 +547,22 @@ Common Report Var(flag_gcse_after_reload) Optimization
Perform global common subexpression elimination after register allocation
has finished
+fgraphite
+Common Report Var(flag_graphite)
+Enable in and out of Graphite representation
+
+floop-strip-mine
+Common Report Var(flag_loop_strip_mine) Optimization
+Enable Loop Strip Mining transformation
+
+floop-interchange
+Common Report Var(flag_loop_interchange) Optimization
+Enable Loop Interchange transformation
+
+floop-block
+Common Report Var(flag_loop_block) Optimization
+Enable Loop Blocking transformation
+
fguess-branch-probability
Common Report Var(flag_guess_branch_prob) Optimization
Enable guessing of branch probabilities
diff --git a/gcc/config.in b/gcc/config.in
index f4604d25719..17bdeb44ae6 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -1327,6 +1327,12 @@
#endif
+/* Define if cloog is in use. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_cloog
+#endif
+
+
/* Define as const if the declaration of iconv() needs const. */
#ifndef USED_FOR_TARGET
#undef ICONV_CONST
diff --git a/gcc/configure b/gcc/configure
index 6605def3be4..aff51d69fcf 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -458,7 +458,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os target_noncanonical build_libsubdir build_subdir host_subdir target_subdir GENINSRC CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT GNATBIND ac_ct_GNATBIND GNATMAKE ac_ct_GNATMAKE NO_MINUS_C_MINUS_O OUTPUT_OPTION CPP EGREP loose_warn strict_warn warn_cflags nocommon_flag TREEBROWSER valgrind_path valgrind_path_defines valgrind_command coverage_flags enable_multilib enable_decimal_float enable_fixed_point enable_shared TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE CROSS_SYSTEM_HEADER_DIR onestep PKGVERSION REPORT_BUGS_TO REPORT_BUGS_TEXI datarootdir docdir htmldir SET_MAKE AWK LN_S LN RANLIB ac_ct_RANLIB ranlib_flags INSTALL INSTALL_PROGRAM INSTALL_DATA make_compare_target have_mktemp_command MAKEINFO BUILD_INFO GENERATED_MANPAGES FLEX BISON NM AR COLLECT2_LIBS GNAT_LIBEXC LDEXP_LIB TARGET_GETGROUPS_T LIBICONV LTLIBICONV LIBICONV_DEP manext objext gthread_flags extra_modes_file extra_opt_files USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT CROSS ALL SYSTEM_HEADER_DIR inhibit_libc CC_FOR_BUILD BUILD_CFLAGS BUILD_LDFLAGS STMP_FIXINC STMP_FIXPROTO collect2 LIBTOOL SED FGREP GREP LD DUMPBIN ac_ct_DUMPBIN ac_ct_AR STRIP ac_ct_STRIP lt_ECHO objdir enable_fast_install gcc_cv_as ORIGINAL_AS_FOR_TARGET gcc_cv_ld ORIGINAL_LD_FOR_TARGET gcc_cv_nm ORIGINAL_NM_FOR_TARGET gcc_cv_objdump libgcc_visibility GGC zlibdir zlibinc MAINT gcc_tooldir dollar slibdir subdirs srcdir all_compilers all_gtfiles all_lang_makefrags all_lang_makefiles all_languages all_selected_languages build_exeext build_install_headers_dir build_xm_file_list build_xm_include_list build_xm_defines build_file_translate check_languages cpp_install_dir xmake_file tmake_file extra_gcc_objs extra_headers_list extra_objs extra_parts extra_passes extra_programs float_h_file gcc_config_arguments gcc_gxx_include_dir host_exeext host_xm_file_list host_xm_include_list host_xm_defines out_host_hook_obj install lang_opt_files lang_specs_files lang_tree_files local_prefix md_file objc_boehm_gc out_file out_object_file thread_file tm_file_list tm_include_list tm_defines tm_p_file_list tm_p_include_list xm_file_list xm_include_list xm_defines c_target_objs cxx_target_objs fortran_target_objs target_cpu_default GMPLIBS GMPINC LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os target_noncanonical build_libsubdir build_subdir host_subdir target_subdir GENINSRC CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT GNATBIND ac_ct_GNATBIND GNATMAKE ac_ct_GNATMAKE NO_MINUS_C_MINUS_O OUTPUT_OPTION CPP EGREP loose_warn strict_warn warn_cflags nocommon_flag TREEBROWSER valgrind_path valgrind_path_defines valgrind_command coverage_flags enable_multilib enable_decimal_float enable_fixed_point enable_shared TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE CROSS_SYSTEM_HEADER_DIR onestep PKGVERSION REPORT_BUGS_TO REPORT_BUGS_TEXI datarootdir docdir htmldir SET_MAKE AWK LN_S LN RANLIB ac_ct_RANLIB ranlib_flags INSTALL INSTALL_PROGRAM INSTALL_DATA make_compare_target have_mktemp_command MAKEINFO BUILD_INFO GENERATED_MANPAGES FLEX BISON NM AR COLLECT2_LIBS GNAT_LIBEXC LDEXP_LIB TARGET_GETGROUPS_T LIBICONV LTLIBICONV LIBICONV_DEP manext objext gthread_flags extra_modes_file extra_opt_files USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT CROSS ALL SYSTEM_HEADER_DIR inhibit_libc CC_FOR_BUILD BUILD_CFLAGS BUILD_LDFLAGS STMP_FIXINC STMP_FIXPROTO collect2 LIBTOOL SED FGREP GREP LD DUMPBIN ac_ct_DUMPBIN ac_ct_AR STRIP ac_ct_STRIP lt_ECHO objdir enable_fast_install gcc_cv_as ORIGINAL_AS_FOR_TARGET gcc_cv_ld ORIGINAL_LD_FOR_TARGET gcc_cv_nm ORIGINAL_NM_FOR_TARGET gcc_cv_objdump libgcc_visibility GGC zlibdir zlibinc MAINT gcc_tooldir dollar slibdir subdirs srcdir all_compilers all_gtfiles all_lang_makefrags all_lang_makefiles all_languages all_selected_languages build_exeext build_install_headers_dir build_xm_file_list build_xm_include_list build_xm_defines build_file_translate check_languages cpp_install_dir xmake_file tmake_file extra_gcc_objs extra_headers_list extra_objs extra_parts extra_passes extra_programs float_h_file gcc_config_arguments gcc_gxx_include_dir host_exeext host_xm_file_list host_xm_include_list host_xm_defines out_host_hook_obj install lang_opt_files lang_specs_files lang_tree_files local_prefix md_file objc_boehm_gc out_file out_object_file thread_file tm_file_list tm_include_list tm_defines tm_p_file_list tm_p_include_list xm_file_list xm_include_list xm_defines c_target_objs cxx_target_objs fortran_target_objs target_cpu_default GMPLIBS GMPINC PPLLIBS PPLINC CLOOGLIBS CLOOGINC GRAPHITE LIBOBJS LTLIBOBJS'
ac_subst_files='language_hooks'
ac_pwd=`pwd`
@@ -928,6 +928,22 @@ ac_env_GMPINC_set=${GMPINC+set}
ac_env_GMPINC_value=$GMPINC
ac_cv_env_GMPINC_set=${GMPINC+set}
ac_cv_env_GMPINC_value=$GMPINC
+ac_env_PPLLIBS_set=${PPLLIBS+set}
+ac_env_PPLLIBS_value=$PPLLIBS
+ac_cv_env_PPLLIBS_set=${PPLLIBS+set}
+ac_cv_env_PPLLIBS_value=$PPLLIBS
+ac_env_PPLINC_set=${PPLINC+set}
+ac_env_PPLINC_value=$PPLINC
+ac_cv_env_PPLINC_set=${PPLINC+set}
+ac_cv_env_PPLINC_value=$PPLINC
+ac_env_CLOOGLIBS_set=${CLOOGLIBS+set}
+ac_env_CLOOGLIBS_value=$CLOOGLIBS
+ac_cv_env_CLOOGLIBS_set=${CLOOGLIBS+set}
+ac_cv_env_CLOOGLIBS_value=$CLOOGLIBS
+ac_env_CLOOGINC_set=${CLOOGINC+set}
+ac_env_CLOOGINC_value=$CLOOGINC
+ac_cv_env_CLOOGINC_set=${CLOOGINC+set}
+ac_cv_env_CLOOGINC_value=$CLOOGINC
#
# Report the --help message.
@@ -1117,6 +1133,10 @@ Some influential environment variables:
CPP C preprocessor
GMPLIBS How to link GMP
GMPINC How to find GMP include files
+ PPLLIBS How to link PPL
+ PPLINC How to find PPL include files
+ CLOOGLIBS How to link CLOOG
+ CLOOGINC How to find CLOOG include files
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
@@ -14721,13 +14741,13 @@ if test "${lt_cv_nm_interface+set}" = set; then
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
- (eval echo "\"\$as_me:14724: $ac_compile\"" >&5)
+ (eval echo "\"\$as_me:14744: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
- (eval echo "\"\$as_me:14727: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval echo "\"\$as_me:14747: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
- (eval echo "\"\$as_me:14730: output\"" >&5)
+ (eval echo "\"\$as_me:14750: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -15782,7 +15802,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 15785 "configure"' > conftest.$ac_ext
+ echo '#line 15805 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -16402,11 +16422,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:16405: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:16425: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:16409: \$? = $ac_status" >&5
+ echo "$as_me:16429: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -16724,11 +16744,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:16727: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:16747: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:16731: \$? = $ac_status" >&5
+ echo "$as_me:16751: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -16829,11 +16849,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:16832: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:16852: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:16836: \$? = $ac_status" >&5
+ echo "$as_me:16856: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -16884,11 +16904,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:16887: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:16907: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:16891: \$? = $ac_status" >&5
+ echo "$as_me:16911: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -19681,7 +19701,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 19684 "configure"
+#line 19704 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -19781,7 +19801,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 19784 "configure"
+#line 19804 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -23997,6 +24017,21 @@ fi
+
+
+
+
+
+if test "x${CLOOGLIBS}" != "x" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_cloog 1
+_ACEOF
+
+ GRAPHITE=graphite.o
+fi
+
+
# Configure the subdirectories
# AC_CONFIG_SUBDIRS($subdirs)
@@ -24825,6 +24860,11 @@ s,@fortran_target_objs@,$fortran_target_objs,;t t
s,@target_cpu_default@,$target_cpu_default,;t t
s,@GMPLIBS@,$GMPLIBS,;t t
s,@GMPINC@,$GMPINC,;t t
+s,@PPLLIBS@,$PPLLIBS,;t t
+s,@PPLINC@,$PPLINC,;t t
+s,@CLOOGLIBS@,$CLOOGLIBS,;t t
+s,@CLOOGINC@,$CLOOGINC,;t t
+s,@GRAPHITE@,$GRAPHITE,;t t
s,@LIBOBJS@,$LIBOBJS,;t t
s,@LTLIBOBJS@,$LTLIBOBJS,;t t
/@language_hooks@/r $language_hooks
diff --git a/gcc/configure.ac b/gcc/configure.ac
index a42ac5c6f1d..f4cff3d114c 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -3883,6 +3883,15 @@ fi
AC_ARG_VAR(GMPLIBS,[How to link GMP])
AC_ARG_VAR(GMPINC,[How to find GMP include files])
+AC_ARG_VAR(PPLLIBS,[How to link PPL])
+AC_ARG_VAR(PPLINC,[How to find PPL include files])
+
+AC_ARG_VAR(CLOOGLIBS,[How to link CLOOG])
+AC_ARG_VAR(CLOOGINC,[How to find CLOOG include files])
+if test "x${CLOOGLIBS}" != "x" ; then
+ AC_DEFINE(HAVE_cloog, 1, [Define if cloog is in use.])
+fi
+
# Configure the subdirectories
# AC_CONFIG_SUBDIRS($subdirs)
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index aa73f826b3e..5768f082026 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -338,6 +338,7 @@ Objective-C and Objective-C++ Dialects}.
-fira-coalesce -fno-ira-share-save-slots @gol
-fno-ira-share-spill-slots -fira-verbose=@var{n} @gol
-fivopts -fkeep-inline-functions -fkeep-static-consts @gol
+-floop-block -floop-interchange -floop-strip-mine @gol
-fmerge-all-constants -fmerge-constants -fmodulo-sched @gol
-fmodulo-sched-allow-regmoves -fmove-loop-invariants -fmudflap @gol
-fmudflapir -fmudflapth -fno-branch-count-reg -fno-default-inline @gol
@@ -6012,6 +6013,81 @@ at @option{-O} and higher.
Perform linear loop transformations on tree. This flag can improve cache
performance and allow further loop optimizations to take place.
+@item -floop-interchange
+Perform loop interchange transformations on loops. Interchanging two
+nested loops switches the inner and outer loops. For example, given a
+loop like:
+@smallexample
+DO J = 1, M
+ DO I = 1, N
+ A(J, I) = A(J, I) * C
+ ENDDO
+ENDDO
+@end smallexample
+loop interchange will transform the loop as if the user had written:
+@smallexample
+DO I = 1, N
+ DO J = 1, M
+ A(J, I) = A(J, I) * C
+ ENDDO
+ENDDO
+@end smallexample
+which can be beneficial when @code{N} is larger than the caches,
+because in Fortran, the elements of an array are stored in memory
+contiguously by column, and the original loop iterates over rows,
+potentially creating at each access a cache miss. This optimization
+applies to all the languages supported by GCC and is not limited to
+Fortran.
+
+@item -floop-strip-mine
+Perform loop strip mining transformations on loops. Strip mining
+splits a loop into two nested loops. The outer loop has strides
+equal to the strip size and the inner loop has strides of the
+original loop within a strip. For example, given a loop like:
+@smallexample
+DO I = 1, N
+ A(I) = A(I) + C
+ENDDO
+@end smallexample
+loop strip mining will transform the loop as if the user had written:
+@smallexample
+DO II = 1, N, 4
+ DO I = II, min (II + 4, N)
+ A(I) = A(I) + C
+ ENDDO
+ENDDO
+@end smallexample
+This optimization applies to all the languages supported by GCC and is
+not limited to Fortran.
+
+@item -floop-block
+Perform loop blocking transformations on loops. Blocking strip mines
+each loop in the loop nest such that the memory accesses of the
+element loops fit inside caches. For example, given a loop like:
+@smallexample
+DO I = 1, N
+ DO J = 1, M
+ A(J, I) = B(I) + C(J)
+ ENDDO
+ENDDO
+@end smallexample
+loop blocking will transform the loop as if the user had written:
+@smallexample
+DO II = 1, N, 64
+ DO JJ = 1, M, 64
+ DO I = II, min (II + 64, N)
+ DO J = JJ, min (JJ + 64, M)
+ A(J, I) = B(I) + C(J)
+ ENDDO
+ ENDDO
+ ENDDO
+ENDDO
+@end smallexample
+which can be beneficial when @code{M} is larger than the caches,
+because the innermost loop will iterate over a smaller amount of data
+that can be kept in the caches. This optimization applies to all the
+languages supported by GCC and is not limited to Fortran.
+
@item -fcheck-data-deps
@opindex fcheck-data-deps
Compare the results of several data dependence analyzers. This option
diff --git a/gcc/gdbinit.in b/gcc/gdbinit.in
index e8d10e236c4..9df289cb5dc 100644
--- a/gcc/gdbinit.in
+++ b/gcc/gdbinit.in
@@ -40,6 +40,15 @@ Print the tree that is $ in C syntax.
Works only when an inferior is executing.
end
+define pgg
+set debug_gimple_stmt ($)
+end
+
+document pgg
+Print the Gimple statement that is $ in C syntax.
+Works only when an inferior is executing.
+end
+
define pgs
set debug_generic_stmt ($)
end
diff --git a/gcc/gimple.h b/gcc/gimple.h
index e8c0ad61616..ca8e64404e2 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -38,6 +38,12 @@ DEF_VEC_P(gimple_seq);
DEF_VEC_ALLOC_P(gimple_seq,gc);
DEF_VEC_ALLOC_P(gimple_seq,heap);
+/* For each block, the PHI nodes that need to be rewritten are stored into
+ these vectors. */
+typedef VEC(gimple, heap) *gimple_vec;
+DEF_VEC_P (gimple_vec);
+DEF_VEC_ALLOC_P (gimple_vec, heap);
+
enum gimple_code {
#define DEFGSCODE(SYM, STRING, STRUCT) SYM,
#include "gimple.def"
diff --git a/gcc/graphite.c b/gcc/graphite.c
new file mode 100644
index 00000000000..86b0eae6f97
--- /dev/null
+++ b/gcc/graphite.c
@@ -0,0 +1,4806 @@
+/* Gimple Represented as Polyhedra.
+ Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
+ Contributed by Sebastian Pop <sebastian.pop@inria.fr>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* This pass converts GIMPLE to GRAPHITE, performs some loop
+ transformations and then converts the resulting representation back
+ to GIMPLE.
+
+ An early description of this pass can be found in the GCC Summit'06
+ paper "GRAPHITE: Polyhedral Analyses and Optimizations for GCC".
+ The wiki page http://gcc.gnu.org/wiki/Graphite contains pointers to
+ the related work.
+
+ One important document to read is CLooG's internal manual:
+ http://repo.or.cz/w/cloog-ppl.git?a=blob_plain;f=doc/cloog.texi;hb=HEAD
+ that describes the data structure of loops used in this file, and
+ the functions that are used for transforming the code. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "ggc.h"
+#include "tree.h"
+#include "rtl.h"
+#include "basic-block.h"
+#include "diagnostic.h"
+#include "tree-flow.h"
+#include "toplev.h"
+#include "tree-dump.h"
+#include "timevar.h"
+#include "cfgloop.h"
+#include "tree-chrec.h"
+#include "tree-data-ref.h"
+#include "tree-scalar-evolution.h"
+#include "tree-pass.h"
+#include "domwalk.h"
+#include "pointer-set.h"
+#include "gimple.h"
+
+#ifdef HAVE_cloog
+#include "cloog/cloog.h"
+#include "graphite.h"
+
+static VEC (scop_p, heap) *current_scops;
+
+/* Debug the list of old induction variables for this SCOP. */
+
+void
+debug_oldivs (scop_p scop)
+{
+ int i;
+ name_tree oldiv;
+
+ fprintf (stderr, "Old IVs:");
+
+ for (i = 0; VEC_iterate (name_tree, SCOP_OLDIVS (scop), i, oldiv); i++)
+ {
+ fprintf (stderr, "(");
+ print_generic_expr (stderr, oldiv->t, 0);
+ fprintf (stderr, ", %s, %d)\n", oldiv->name, oldiv->loop->num);
+ }
+ fprintf (stderr, "\n");
+}
+
+/* Debug the loops around basic block GB. */
+
+void
+debug_loop_vec (graphite_bb_p gb)
+{
+ int i;
+ loop_p loop;
+
+ fprintf (stderr, "Loop Vec:");
+
+ for (i = 0; VEC_iterate (loop_p, GBB_LOOPS (gb), i, loop); i++)
+ fprintf (stderr, "%d: %d, ", i, loop ? loop->num : -1);
+
+ fprintf (stderr, "\n");
+}
+
+/* Push (IV, NAME) on STACK. */
+
+static void
+loop_iv_stack_push (loop_iv_stack stack, tree iv, const char *name)
+{
+ name_tree named_iv = XNEW (struct name_tree);
+
+ named_iv->t = iv;
+ named_iv->name = name;
+ VEC_safe_push (name_tree, heap, *stack, named_iv);
+}
+
+/* Pops an element out of STACK. */
+
+static void
+loop_iv_stack_pop (loop_iv_stack stack)
+{
+ VEC_pop (name_tree, *stack);
+}
+
+/* Get the IV at INDEX in STACK. */
+
+static tree
+loop_iv_stack_get_iv (loop_iv_stack stack, int index)
+{
+ name_tree named_iv = VEC_index (name_tree, *stack, index);
+
+ return named_iv->t;
+}
+
+/* Get the IV from its NAME in STACK. */
+
+static tree
+loop_iv_stack_get_iv_from_name (loop_iv_stack stack, const char* name)
+{
+ int i;
+ name_tree iv;
+
+ for (i = 0; VEC_iterate (name_tree, *stack, i, iv); i++)
+ if (!strcmp (name, iv->name))
+ return iv->t;
+
+ return NULL;
+}
+
+/* Prints on stderr the contents of STACK. */
+
+void
+loop_iv_stack_debug (loop_iv_stack stack)
+{
+ int i;
+ name_tree iv;
+ bool first = true;
+
+ fprintf (stderr, "(");
+
+ for (i = 0; VEC_iterate (name_tree, *stack, i, iv); i++)
+ {
+ if (first)
+ first = false;
+ else
+ fprintf (stderr, " ");
+ fprintf (stderr, "%s:", iv->name);
+ print_generic_expr (stderr, iv->t, 0);
+ }
+
+ fprintf (stderr, ")\n");
+}
+
+/* In SCOP, get the induction variable from NAME. OLD is the original
+ loop that contained the definition of NAME. */
+
+static name_tree
+get_old_iv_from_ssa_name (scop_p scop, loop_p old, tree name)
+{
+ tree var = SSA_NAME_VAR (name);
+ int i;
+ name_tree oldiv;
+
+ for (i = 0; VEC_iterate (name_tree, SCOP_OLDIVS (scop), i, oldiv); i++)
+ {
+ loop_p current = old;
+
+ while (current)
+ {
+ if (var == oldiv->t
+ && oldiv->loop == current)
+ return oldiv;
+
+ current = loop_outer (current);
+ }
+ }
+ return NULL;
+
+}
+
+/* Returns a new loop_to_cloog_loop_str structure. */
+
+static inline struct loop_to_cloog_loop_str *
+new_loop_to_cloog_loop_str (int loop_num,
+ int loop_position,
+ CloogLoop *cloog_loop)
+{
+ struct loop_to_cloog_loop_str *result;
+
+ result = XNEW (struct loop_to_cloog_loop_str);
+ result->loop_num = loop_num;
+ result->cloog_loop = cloog_loop;
+ result->loop_position = loop_position;
+
+ return result;
+}
+
+/* Hash function for SCOP_LOOP2CLOOG_LOOP hash table. */
+
+static hashval_t
+hash_loop_to_cloog_loop (const void *elt)
+{
+ return ((const struct loop_to_cloog_loop_str *) elt)->loop_num;
+}
+
+/* Equality function for SCOP_LOOP2CLOOG_LOOP hash table. */
+
+static int
+eq_loop_to_cloog_loop (const void *el1, const void *el2)
+{
+ const struct loop_to_cloog_loop_str *elt1, *elt2;
+
+ elt1 = (const struct loop_to_cloog_loop_str *) el1;
+ elt2 = (const struct loop_to_cloog_loop_str *) el2;
+ return elt1->loop_num == elt2->loop_num;
+}
+
+/* Compares two graphite bbs and returns an integer less than, equal to, or
+ greater than zero if the first argument is considered to be respectively
+ less than, equal to, or greater than the second.
+ We compare using the lexicographic order of the static schedules. */
+
+static int
+gbb_compare (const void *p_1, const void *p_2)
+{
+ const struct graphite_bb *const gbb_1
+ = *(const struct graphite_bb *const*) p_1;
+ const struct graphite_bb *const gbb_2
+ = *(const struct graphite_bb *const*) p_2;
+
+ return lambda_vector_compare (GBB_STATIC_SCHEDULE (gbb_1),
+ gbb_nb_loops (gbb_1) + 1,
+ GBB_STATIC_SCHEDULE (gbb_2),
+ gbb_nb_loops (gbb_2) + 1);
+}
+
+/* Sort graphite bbs in SCOP. */
+
+static void
+graphite_sort_gbbs (scop_p scop)
+{
+ VEC (graphite_bb_p, heap) *bbs = SCOP_BBS (scop);
+
+ qsort (VEC_address (graphite_bb_p, bbs),
+ VEC_length (graphite_bb_p, bbs),
+ sizeof (graphite_bb_p), gbb_compare);
+}
+
+/* Dump conditions of a graphite basic block GBB on FILE. */
+
+static void
+dump_gbb_conditions (FILE *file, graphite_bb_p gbb)
+{
+ int i;
+ gimple stmt;
+ VEC (gimple, heap) *conditions = GBB_CONDITIONS (gbb);
+
+ if (VEC_empty (gimple, conditions))
+ return;
+
+ fprintf (file, "\tbb %d\t: cond = {", GBB_BB (gbb)->index);
+
+ for (i = 0; VEC_iterate (gimple, conditions, i, stmt); i++)
+ print_gimple_stmt (file, stmt, 0, 0);
+
+ fprintf (file, "}\n");
+}
+
+/* Converts the graphite scheduling function into a cloog scattering
+ matrix. This scattering matrix is used to limit the possible cloog
+ output to valid programs in respect to the scheduling function.
+
+ SCATTERING_DIMENSIONS specifies the dimensionality of the scattering
+ matrix. CLooG 0.14.0 and previous versions require, that all scattering
+ functions of one CloogProgram have the same dimensionality, therefore we
+ allow to specify it. (Should be removed in future versions) */
+
+static CloogMatrix *
+schedule_to_scattering (graphite_bb_p gb, int scattering_dimensions)
+{
+ int i;
+ scop_p scop = GBB_SCOP (gb);
+
+ int nb_iterators = gbb_nb_loops (gb);
+
+ /* The cloog scattering matrix consists of these colums:
+ 1 col = Eq/Inq,
+ scattering_dimensions cols = Scattering dimensions,
+ nb_iterators cols = bb's iterators,
+ scop_nb_params cols = Parameters,
+ 1 col = Constant 1.
+
+ Example:
+
+ scattering_dimensions = 5
+ max_nb_iterators = 2
+ nb_iterators = 1
+ scop_nb_params = 2
+
+ Schedule:
+ ? i
+ 4 5
+
+ Scattering Matrix:
+ s1 s2 s3 s4 s5 i p1 p2 1
+ 1 0 0 0 0 0 0 0 -4 = 0
+ 0 1 0 0 0 -1 0 0 0 = 0
+ 0 0 1 0 0 0 0 0 -5 = 0 */
+ int nb_params = scop_nb_params (scop);
+ int nb_cols = 1 + scattering_dimensions + nb_iterators + nb_params + 1;
+ int col_const = nb_cols - 1;
+ int col_iter_offset = 1 + scattering_dimensions;
+
+ CloogMatrix *scat = cloog_matrix_alloc (scattering_dimensions, nb_cols);
+
+ gcc_assert (scattering_dimensions >= nb_iterators * 2 + 1);
+
+ /* Initialize the identity matrix. */
+ for (i = 0; i < scattering_dimensions; i++)
+ value_set_si (scat->p[i][i + 1], 1);
+
+ /* Textual order outside the first loop */
+ value_set_si (scat->p[0][col_const], -GBB_STATIC_SCHEDULE (gb)[0]);
+
+ /* For all surrounding loops. */
+ for (i = 0; i < nb_iterators; i++)
+ {
+ int schedule = GBB_STATIC_SCHEDULE (gb)[i + 1];
+
+ /* Iterations of this loop. */
+ value_set_si (scat->p[2 * i + 1][col_iter_offset + i], -1);
+
+ /* Textual order inside this loop. */
+ value_set_si (scat->p[2 * i + 2][col_const], -schedule);
+ }
+
+ return scat;
+}
+
+/* Print the schedules of GB to FILE with INDENT white spaces before.
+ VERBOSITY determines how verbose the code pretty printers are. */
+
+void
+print_graphite_bb (FILE *file, graphite_bb_p gb, int indent, int verbosity)
+{
+ CloogMatrix *scattering;
+ int i;
+ loop_p loop;
+ fprintf (file, "\nGBB (\n");
+
+ print_loops_bb (file, GBB_BB (gb), indent+2, verbosity);
+
+ if (GBB_DOMAIN (gb))
+ {
+ fprintf (file, " (domain: \n");
+ cloog_matrix_print (dump_file, GBB_DOMAIN (gb));
+ fprintf (file, " )\n");
+ }
+
+ if (GBB_STATIC_SCHEDULE (gb))
+ {
+ fprintf (file, " (static schedule: ");
+ print_lambda_vector (file, GBB_STATIC_SCHEDULE (gb),
+ gbb_nb_loops (gb) + 1);
+ fprintf (file, " )\n");
+ }
+
+ if (GBB_LOOPS (gb))
+ {
+ fprintf (file, " (contained loops: \n");
+ for (i = 0; VEC_iterate (loop_p, GBB_LOOPS (gb), i, loop); i++)
+ if (loop == NULL)
+ fprintf (file, " iterator %d => NULL \n", i);
+ else
+ fprintf (file, " iterator %d => loop %d \n", i,
+ loop->num);
+ fprintf (file, " )\n");
+ }
+
+ if (GBB_DATA_REFS (gb))
+ dump_data_references (file, GBB_DATA_REFS (gb));
+
+ if (GBB_CONDITIONS (gb))
+ {
+ fprintf (file, " (conditions: \n");
+ dump_gbb_conditions (dump_file, gb);
+ fprintf (file, " )\n");
+ }
+
+ if (GBB_SCOP (gb)
+ && GBB_STATIC_SCHEDULE (gb))
+ {
+ fprintf (file, " (scattering: \n");
+ scattering = schedule_to_scattering (gb, 2 * gbb_nb_loops (gb) + 1);
+ cloog_matrix_print (file, scattering);
+ cloog_matrix_free (scattering);
+ fprintf (file, " )\n");
+ }
+
+ fprintf (file, ")\n");
+}
+
+/* Print to STDERR the schedules of GB with VERBOSITY level. */
+
+void
+debug_gbb (graphite_bb_p gb, int verbosity)
+{
+ print_graphite_bb (stderr, gb, 0, verbosity);
+}
+
+
+/* Print SCOP to FILE. VERBOSITY determines how verbose the pretty
+ printers are. */
+
+static void
+print_scop (FILE *file, scop_p scop, int verbosity)
+{
+ if (scop == NULL)
+ return;
+
+ fprintf (file, "\nSCoP_%d_%d (\n",
+ SCOP_ENTRY (scop)->index, SCOP_EXIT (scop)->index);
+
+ fprintf (file, " (cloog: \n");
+ cloog_program_print (file, SCOP_PROG (scop));
+ fprintf (file, " )\n");
+
+ if (SCOP_BBS (scop))
+ {
+ graphite_bb_p gb;
+ int i;
+
+ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++)
+ print_graphite_bb (file, gb, 0, verbosity);
+ }
+
+ fprintf (file, ")\n");
+}
+
+/* Print all the SCOPs to FILE. VERBOSITY determines how verbose the
+ code pretty printers are. */
+
+static void
+print_scops (FILE *file, int verbosity)
+{
+ int i;
+ scop_p scop;
+
+ for (i = 0; VEC_iterate (scop_p, current_scops, i, scop); i++)
+ print_scop (file, scop, verbosity);
+}
+
+/* Debug SCOP. VERBOSITY determines how verbose the code pretty
+ printers are. */
+
+void
+debug_scop (scop_p scop, int verbosity)
+{
+ print_scop (stderr, scop, verbosity);
+}
+
+/* Debug all SCOPs from CURRENT_SCOPS. VERBOSITY determines how
+ verbose the code pretty printers are. */
+
+void
+debug_scops (int verbosity)
+{
+ print_scops (stderr, verbosity);
+}
+
+/* Return true when BB is contained in SCOP. */
+
+static inline bool
+bb_in_scop_p (basic_block bb, scop_p scop)
+{
+ return bitmap_bit_p (SCOP_BBS_B (scop), bb->index);
+}
+
+/* Pretty print to FILE the SCOP in DOT format. */
+
+static void
+dot_scop_1 (FILE *file, scop_p scop)
+{
+ edge e;
+ edge_iterator ei;
+ basic_block bb;
+ basic_block entry = SCOP_ENTRY (scop);
+ basic_block exit = SCOP_EXIT (scop);
+
+ fprintf (file, "digraph SCoP_%d_%d {\n", entry->index,
+ exit->index);
+
+ FOR_ALL_BB (bb)
+ {
+ if (bb == entry)
+ fprintf (file, "%d [shape=triangle];\n", bb->index);
+
+ if (bb == exit)
+ fprintf (file, "%d [shape=box];\n", bb->index);
+
+ if (bb_in_scop_p (bb, scop))
+ fprintf (file, "%d [color=red];\n", bb->index);
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ fprintf (file, "%d -> %d;\n", bb->index, e->dest->index);
+ }
+
+ fputs ("}\n\n", file);
+}
+
+/* Display SCOP using dotty. */
+
+void
+dot_scop (scop_p scop)
+{
+ dot_scop_1 (stderr, scop);
+}
+
+/* Pretty print all SCoPs in DOT format and mark them with different colors.
+ If there are not enough colors, paint later SCoPs gray.
+ Special nodes:
+ - "*" after the node number: entry of a SCoP,
+ - "#" after the node number: exit of a SCoP,
+ - "()" entry or exit not part of SCoP. */
+
+static void
+dot_all_scops_1 (FILE *file)
+{
+ basic_block bb;
+ edge e;
+ edge_iterator ei;
+ scop_p scop;
+ const char* color;
+ int i;
+
+ /* Disable debugging while printing graph. */
+ int tmp_dump_flags = dump_flags;
+ dump_flags = 0;
+
+ fprintf (file, "digraph all {\n");
+
+ FOR_ALL_BB (bb)
+ {
+ int part_of_scop = false;
+
+ /* Use HTML for every bb label. So we are able to print bbs
+ which are part of two different SCoPs, with two different
+ background colors. */
+ fprintf (file, "%d [label=<\n <TABLE BORDER=\"0\" CELLBORDER=\"1\" ",
+ bb->index);
+ fprintf (file, "CELLSPACING=\"0\">\n");
+
+ /* Select color for SCoP. */
+ for (i = 0; VEC_iterate (scop_p, current_scops, i, scop); i++)
+ if (bb_in_scop_p (bb, scop)
+ || (SESE_EXIT (SCOP_REGION (scop)) && SCOP_EXIT (scop) == bb)
+ || (SESE_ENTRY (SCOP_REGION (scop)) && SCOP_ENTRY (scop) == bb))
+ {
+ switch (i % 17)
+ {
+ case 0: /* red */
+ color = "#e41a1c";
+ break;
+ case 1: /* blue */
+ color = "#377eb8";
+ break;
+ case 2: /* green */
+ color = "#4daf4a";
+ break;
+ case 3: /* purple */
+ color = "#984ea3";
+ break;
+ case 4: /* orange */
+ color = "#ff7f00";
+ break;
+ case 5: /* yellow */
+ color = "#ffff33";
+ break;
+ case 6: /* brown */
+ color = "#a65628";
+ break;
+ case 7: /* rose */
+ color = "#f781bf";
+ break;
+ case 8:
+ color = "#8dd3c7";
+ break;
+ case 9:
+ color = "#ffffb3";
+ break;
+ case 10:
+ color = "#bebada";
+ break;
+ case 11:
+ color = "#fb8072";
+ break;
+ case 12:
+ color = "#80b1d3";
+ break;
+ case 13:
+ color = "#fdb462";
+ break;
+ case 14:
+ color = "#b3de69";
+ break;
+ case 15:
+ color = "#fccde5";
+ break;
+ case 16:
+ color = "#bc80bd";
+ break;
+ default: /* gray */
+ color = "#999999";
+ }
+
+ fprintf (file, " <TR><TD WIDTH=\"50\" BGCOLOR=\"%s\">", color);
+
+ if (!bb_in_scop_p (bb, scop))
+ fprintf (file, " (");
+
+ if (SESE_ENTRY (SCOP_REGION (scop))
+ && SESE_EXIT (SCOP_REGION (scop))
+ && bb == SCOP_ENTRY (scop)
+ && bb == SCOP_EXIT (scop))
+ fprintf (file, " %d*# ", bb->index);
+ else if (SESE_ENTRY (SCOP_REGION (scop))
+ && bb == SCOP_ENTRY (scop))
+ fprintf (file, " %d* ", bb->index);
+ else if (SESE_EXIT (SCOP_REGION (scop))
+ && bb == SCOP_EXIT (scop))
+ fprintf (file, " %d# ", bb->index);
+ else
+ fprintf (file, " %d ", bb->index);
+
+ if (!bb_in_scop_p (bb, scop))
+ fprintf (file, ")");
+
+ fprintf (file, "</TD></TR>\n");
+
+ part_of_scop = true;
+ }
+
+ if (!part_of_scop)
+ {
+ fprintf (file, " <TR><TD WIDTH=\"50\" BGCOLOR=\"#ffffff\">");
+ fprintf (file, " %d </TD></TR>\n", bb->index);
+ }
+
+ fprintf (file, " </TABLE>>, shape=box, style=\"setlinewidth(0)\"]\n");
+ }
+
+ FOR_ALL_BB (bb)
+ {
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ fprintf (file, "%d -> %d;\n", bb->index, e->dest->index);
+ }
+
+ fputs ("}\n\n", file);
+
+ /* Enable debugging again. */
+ dump_flags = tmp_dump_flags;
+}
+
+/* Display all SCoPs using dotty. */
+
+void
+dot_all_scops (void)
+{
+ /* When debugging, enable the following code. This cannot be used
+ in production compilers because it calls "system". */
+#if 0
+ FILE *stream = fopen ("/tmp/allscops.dot", "w");
+ gcc_assert (stream);
+
+ dot_all_scops_1 (stream);
+ fclose (stream);
+
+ system ("dotty /tmp/allscops.dot");
+#else
+ dot_all_scops_1 (stderr);
+#endif
+}
+
+/* Returns true when LOOP is in SCOP. */
+
+static inline bool
+loop_in_scop_p (struct loop *loop, scop_p scop)
+{
+ return (bb_in_scop_p (loop->header, scop)
+ && bb_in_scop_p (loop->latch, scop));
+}
+
+/* Returns the outermost loop in SCOP that contains BB. */
+
+static struct loop *
+outermost_loop_in_scop (scop_p scop, basic_block bb)
+{
+ struct loop *nest;
+
+ nest = bb->loop_father;
+ while (loop_outer (nest) && loop_in_scop_p (loop_outer (nest), scop))
+ nest = loop_outer (nest);
+
+ return nest;
+}
+
+/* Return true when EXPR is an affine function in LOOP with parameters
+ instantiated relative to outermost_loop. */
+
+static bool
+loop_affine_expr (struct loop *outermost_loop, struct loop *loop, tree expr)
+{
+ int n = outermost_loop->num;
+ tree scev = analyze_scalar_evolution (loop, expr);
+
+ scev = instantiate_scev (outermost_loop, loop, scev);
+
+ return (evolution_function_is_invariant_p (scev, n)
+ || evolution_function_is_affine_multivariate_p (scev, n));
+}
+
+/* Return true if the operand OP is simple. */
+
+static bool
+is_simple_operand (loop_p loop, gimple stmt, tree op)
+{
+ /* It is not a simple operand when it is a declaration, */
+ if (DECL_P (op)
+ /* or a structure, */
+ || AGGREGATE_TYPE_P (TREE_TYPE (op))
+ /* or a memory access that cannot be analyzed by the data
+ reference analysis. */
+ || ((handled_component_p (op) || INDIRECT_REF_P (op))
+ && !stmt_simple_memref_p (loop, stmt, op)))
+ return false;
+
+ return true;
+}
+
+/* Return true only when STMT is simple enough for being handled by
+ Graphite. This depends on OUTERMOST_LOOP, as the parametetrs are
+ initialized relative to this loop. */
+
+static bool
+stmt_simple_for_scop_p (struct loop *outermost_loop, gimple stmt)
+{
+ basic_block bb = gimple_bb (stmt);
+ struct loop *loop = bb->loop_father;
+
+ /* GIMPLE_ASM and GIMPLE_CALL may embed arbitrary side effects.
+ Calls have side-effects, except those to const or pure
+ functions. */
+ if (gimple_has_volatile_ops (stmt)
+ || (gimple_code (stmt) == GIMPLE_CALL
+ && !(gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE)))
+ || (gimple_code (stmt) == GIMPLE_ASM))
+ return false;
+
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_RETURN:
+ case GIMPLE_LABEL:
+ return true;
+
+ case GIMPLE_COND:
+ {
+ tree op;
+ ssa_op_iter op_iter;
+ enum tree_code code = gimple_cond_code (stmt);
+
+ /* We can only handle this kind of conditional expressions.
+ For inequalities like "if (i != 3 * k)" we need unions of
+ polyhedrons. Expressions like "if (a)" or "if (a == 15)" need
+ them for the else branch. */
+ if (!(code == LT_EXPR
+ || code == GT_EXPR
+ || code == LE_EXPR
+ || code == GE_EXPR))
+ return false;
+
+ if (!outermost_loop)
+ return false;
+
+ FOR_EACH_SSA_TREE_OPERAND (op, stmt, op_iter, SSA_OP_ALL_USES)
+ if (!loop_affine_expr (outermost_loop, loop, op))
+ return false;
+
+ return true;
+ }
+
+ case GIMPLE_ASSIGN:
+ {
+ enum tree_code code = gimple_assign_rhs_code (stmt);
+
+ switch (get_gimple_rhs_class (code))
+ {
+ case GIMPLE_UNARY_RHS:
+ case GIMPLE_SINGLE_RHS:
+ return (is_simple_operand (loop, stmt, gimple_assign_lhs (stmt))
+ && is_simple_operand (loop, stmt, gimple_assign_rhs1 (stmt)));
+
+ case GIMPLE_BINARY_RHS:
+ return (is_simple_operand (loop, stmt, gimple_assign_lhs (stmt))
+ && is_simple_operand (loop, stmt, gimple_assign_rhs1 (stmt))
+ && is_simple_operand (loop, stmt, gimple_assign_rhs2 (stmt)));
+
+ case GIMPLE_INVALID_RHS:
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ case GIMPLE_CALL:
+ {
+ size_t i;
+ size_t n = gimple_call_num_args (stmt);
+ tree lhs = gimple_call_lhs (stmt);
+
+ for (i = 0; i < n; i++)
+ {
+ tree arg = gimple_call_arg (stmt, i);
+
+ if (!(is_simple_operand (loop, stmt, lhs)
+ && is_simple_operand (loop, stmt, arg)))
+ return false;
+ }
+
+ return true;
+ }
+
+ default:
+ /* These nodes cut a new scope. */
+ return false;
+ }
+
+ return false;
+}
+
+/* Returns the statement of BB that contains a harmful operation: that
+ can be a function call with side effects, data dependences that
+ cannot be computed in OUTERMOST_LOOP, the induction variables are
+ not linear with respect to OUTERMOST_LOOP, etc. The current open
+ scop should end before this statement. */
+
+static gimple
+harmful_stmt_in_bb (struct loop *outermost_loop, basic_block bb)
+{
+ gimple_stmt_iterator gsi;
+
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ if (!stmt_simple_for_scop_p (outermost_loop, gsi_stmt (gsi)))
+ return gsi_stmt (gsi);
+
+ return NULL;
+}
+
+/* Store the GRAPHITE representation of BB. */
+
+static void
+new_graphite_bb (scop_p scop, basic_block bb)
+{
+ struct graphite_bb *gbb = XNEW (struct graphite_bb);
+
+ bb->aux = gbb;
+ GBB_BB (gbb) = bb;
+ GBB_SCOP (gbb) = scop;
+ GBB_DATA_REFS (gbb) = NULL;
+ GBB_DOMAIN (gbb) = NULL;
+ GBB_CONDITIONS (gbb) = NULL;
+ GBB_CONDITION_CASES (gbb) = NULL;
+ GBB_LOOPS (gbb) = NULL;
+ VEC_safe_push (graphite_bb_p, heap, SCOP_BBS (scop), gbb);
+ bitmap_set_bit (SCOP_BBS_B (scop), bb->index);
+}
+
+/* Frees GBB. */
+
+static void
+free_graphite_bb (struct graphite_bb *gbb)
+{
+ if (GBB_DOMAIN (gbb))
+ cloog_matrix_free (GBB_DOMAIN (gbb));
+
+ free_data_refs (GBB_DATA_REFS (gbb));
+ VEC_free (gimple, heap, GBB_CONDITIONS (gbb));
+ VEC_free (gimple, heap, GBB_CONDITION_CASES (gbb));
+ VEC_free (loop_p, heap, GBB_LOOPS (gbb));
+
+ GBB_BB (gbb)->aux = 0;
+ XDELETE (gbb);
+}
+
+/* Creates a new scop starting with ENTRY. */
+
+static scop_p
+new_scop (edge entry)
+{
+ scop_p scop = XNEW (struct scop);
+
+ SCOP_REGION (scop) = XNEW (struct sese);
+ SESE_ENTRY (SCOP_REGION (scop)) = entry;
+ SESE_EXIT (SCOP_REGION (scop)) = NULL;
+ SCOP_BBS (scop) = VEC_alloc (graphite_bb_p, heap, 3);
+ SCOP_OLDIVS (scop) = VEC_alloc (name_tree, heap, 3);
+ SCOP_BBS_B (scop) = BITMAP_ALLOC (NULL);
+ SCOP_LOOPS (scop) = BITMAP_ALLOC (NULL);
+ SCOP_LOOP_NEST (scop) = VEC_alloc (loop_p, heap, 3);
+ SCOP_PARAMS (scop) = VEC_alloc (name_tree, heap, 3);
+ SCOP_PROG (scop) = cloog_program_malloc ();
+ cloog_program_set_names (SCOP_PROG (scop), cloog_names_malloc ());
+ SCOP_LOOP2CLOOG_LOOP (scop) = htab_create (10, hash_loop_to_cloog_loop,
+ eq_loop_to_cloog_loop,
+ free);
+ return scop;
+}
+
+/* Deletes SCOP. */
+
+static void
+free_scop (scop_p scop)
+{
+ int i;
+ name_tree p;
+ struct graphite_bb *gb;
+
+ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++)
+ free_graphite_bb (gb);
+
+ VEC_free (graphite_bb_p, heap, SCOP_BBS (scop));
+ BITMAP_FREE (SCOP_BBS_B (scop));
+ BITMAP_FREE (SCOP_LOOPS (scop));
+ VEC_free (loop_p, heap, SCOP_LOOP_NEST (scop));
+ VEC_free (name_tree, heap, SCOP_OLDIVS (scop));
+
+ for (i = 0; VEC_iterate (name_tree, SCOP_PARAMS (scop), i, p); i++)
+ free (p);
+
+ VEC_free (name_tree, heap, SCOP_PARAMS (scop));
+ cloog_program_free (SCOP_PROG (scop));
+ htab_delete (SCOP_LOOP2CLOOG_LOOP (scop));
+ XDELETE (SCOP_REGION (scop));
+ XDELETE (scop);
+}
+
+/* Deletes all scops in SCOPS. */
+
+static void
+free_scops (VEC (scop_p, heap) *scops)
+{
+ int i;
+ scop_p scop;
+
+ for (i = 0; VEC_iterate (scop_p, scops, i, scop); i++)
+ free_scop (scop);
+
+ VEC_free (scop_p, heap, scops);
+}
+
+typedef enum gbb_type {
+ GBB_UNKNOWN,
+ GBB_LOOP_SING_EXIT_HEADER,
+ GBB_LOOP_MULT_EXIT_HEADER,
+ GBB_LOOP_EXIT,
+ GBB_COND_HEADER,
+ GBB_SIMPLE,
+ GBB_LAST
+} gbb_type;
+
+/* Detect the type of BB. Loop headers are only marked, if they are
+ new. This means their loop_father is different to LAST_LOOP.
+ Otherwise they are treated like any other bb and their type can be
+ any other type. */
+
+static gbb_type
+get_bb_type (basic_block bb, struct loop *last_loop)
+{
+ VEC (basic_block, heap) *dom;
+ int nb_dom, nb_suc;
+ struct loop *loop = bb->loop_father;
+
+ /* Check, if we entry into a new loop. */
+ if (loop != last_loop)
+ {
+ if (single_exit (loop) != NULL)
+ return GBB_LOOP_SING_EXIT_HEADER;
+ else if (loop->num != 0)
+ return GBB_LOOP_MULT_EXIT_HEADER;
+ else
+ return GBB_COND_HEADER;
+ }
+
+ dom = get_dominated_by (CDI_DOMINATORS, bb);
+ nb_dom = VEC_length (basic_block, dom);
+ VEC_free (basic_block, heap, dom);
+ if (nb_dom == 0)
+ return GBB_LAST;
+
+ nb_suc = VEC_length (edge, bb->succs);
+ if (nb_dom == 1 && nb_suc == 1)
+ return GBB_SIMPLE;
+
+ return GBB_COND_HEADER;
+}
+
+/* Moves the scops from SOURCE to TARGET and clean up SOURCE. */
+
+static void
+move_scops (VEC (scop_p, heap) **source, VEC (scop_p, heap) **target)
+{
+ scop_p s;
+ int i;
+
+ for (i = 0; VEC_iterate (scop_p, *source, i, s); i++)
+ VEC_safe_push (scop_p, heap, *target, s);
+
+ VEC_free (scop_p, heap, *source);
+}
+
+/* Store information needed by scopdet_* functions. */
+
+struct scopdet_info
+{
+ /* Where the last open scop would stop if the current BB is harmful. */
+ edge last;
+
+ /* Where the next scop would start if the current BB is harmful. */
+ edge next;
+
+ /* The bb or one of its children contains open loop exits. That means
+ loop exit nodes that are not surrounded by a loop dominated by bb. */
+ bool exits;
+
+ /* The bb or one of its children contains only structures we can handle. */
+ bool difficult;
+};
+
+static struct scopdet_info build_scops_1 (edge, VEC (scop_p, heap) **,
+ loop_p, loop_p);
+
+/* Checks, if a bb can be added to a SCoP. */
+
+static struct scopdet_info
+scopdet_edge_info (edge ee, loop_p outermost_loop,
+ VEC (scop_p, heap) **scops, gbb_type type, gimple *stmt)
+
+{
+ basic_block bb = ee->dest;
+ struct loop *loop = bb->loop_father;
+ struct scopdet_info result;
+
+ *stmt = harmful_stmt_in_bb (outermost_loop, bb);
+ result.difficult = (*stmt != NULL);
+ result.last = NULL;
+
+ switch (type)
+ {
+ case GBB_LAST:
+ result.next = NULL;
+ result.exits = false;
+ result.last = ee;
+ break;
+
+ case GBB_SIMPLE:
+ result.next = single_succ_edge (bb);
+ result.exits = false;
+ result.last = ee;
+ break;
+
+ case GBB_LOOP_SING_EXIT_HEADER:
+ {
+ VEC (scop_p, heap) *tmp_scops = VEC_alloc (scop_p, heap, 3);
+ struct scopdet_info sinfo;
+
+ sinfo = build_scops_1 (ee, &tmp_scops, loop, outermost_loop);
+
+ result.last = single_exit (bb->loop_father);
+
+ if (single_succ_p (result.last->dest)
+ && get_bb_type (result.last->dest, loop) == GBB_SIMPLE)
+ result.next = single_succ_edge (result.last->dest);
+ else
+ result.next = split_block (result.last->dest, NULL);
+
+ /* If we do not dominate result.next, remove it. It's either
+ the EXIT_BLOCK_PTR, or another bb dominates it and will
+ call the scop detection for this bb. */
+ if (!dominated_by_p (CDI_DOMINATORS, result.next->dest, bb))
+ result.next = NULL;
+
+ if (TREE_CODE (number_of_latch_executions (loop))
+ == SCEV_NOT_KNOWN)
+ result.difficult = true;
+
+ if (sinfo.difficult)
+ move_scops (&tmp_scops, scops);
+ else
+ free_scops (tmp_scops);
+
+ result.exits = false;
+ result.difficult |= sinfo.difficult;
+ break;
+ }
+
+ case GBB_LOOP_MULT_EXIT_HEADER:
+ {
+ /* XXX: Handle loop nests with the same header. */
+ /* XXX: Handle iterative optimization of outermost_loop. */
+ /* XXX: For now we just do not join loops with multiple exits. If the
+ exits lead to the same bb it may be possible to join the loop. */
+ VEC (scop_p, heap) *tmp_scops = VEC_alloc (scop_p, heap, 3);
+ VEC (edge, heap) *exits = get_loop_exit_edges (loop);
+ edge e;
+ int i;
+ build_scops_1 (ee, &tmp_scops, loop, outermost_loop);
+
+ for (i = 0; VEC_iterate (edge, exits, i, e); i++)
+ if (dominated_by_p (CDI_DOMINATORS, e->dest, e->src)
+ && e->dest->loop_father == loop_outer (loop))
+ build_scops_1 (e, &tmp_scops, e->dest->loop_father,
+ outermost_loop);
+
+ result.next = NULL;
+ result.last = NULL;
+ result.difficult = true;
+ result.exits = false;
+ move_scops (&tmp_scops, scops);
+ VEC_free (edge, heap, exits);
+ break;
+ }
+ case GBB_COND_HEADER:
+ {
+ VEC (scop_p, heap) *tmp_scops = VEC_alloc (scop_p, heap, 3);
+ struct scopdet_info sinfo;
+ VEC (basic_block, heap) *dominated;
+ int i;
+ basic_block dom_bb;
+ basic_block last_bb = NULL;
+ edge last_e = NULL;
+ edge e;
+ result.exits = false;
+
+ /* First check the successors of BB, and check if it is possible to join
+ the different branches. */
+ for (i = 0; VEC_iterate (edge, bb->succs, i, e); i++)
+ {
+ /* Ignore loop exits. They will be handled after the loop body. */
+ if (is_loop_exit (loop, e->dest))
+ {
+ result.exits = true;
+ continue;
+ }
+
+ /* Do not follow edges that lead to the end of the
+ conditions block. For example, in
+
+ | 0
+ | /|\
+ | 1 2 |
+ | | | |
+ | 3 4 |
+ | \|/
+ | 6
+
+ the edge from 0 => 6. Only check if all paths lead to
+ the same node 6. */
+
+ if (!single_pred_p (e->dest))
+ {
+ /* Check, if edge leads directly to the end of this
+ condition. */
+ if (!last_bb)
+ {
+ last_bb = e->dest;
+ last_e = e;
+ }
+
+ if (e->dest != last_bb)
+ result.difficult = true;
+
+ continue;
+ }
+
+ if (!dominated_by_p (CDI_DOMINATORS, e->dest, bb))
+ {
+ result.difficult = true;
+ continue;
+ }
+
+ sinfo = build_scops_1 (e, &tmp_scops, loop, outermost_loop);
+
+ result.exits |= sinfo.exits;
+ result.last = sinfo.last;
+ result.difficult |= sinfo.difficult;
+
+ /* Checks, if all branches end at the same point.
+ If that is true, the condition stays joinable.
+ Have a look at the example above. */
+ if (sinfo.last && single_succ_p (sinfo.last->dest))
+ {
+ basic_block next_tmp = single_succ (sinfo.last->dest);
+
+ if (!last_bb)
+ {
+ last_bb = next_tmp;
+ last_e = single_succ_edge (sinfo.last->dest);
+ }
+
+ if (next_tmp != last_bb)
+ result.difficult = true;
+ }
+ else
+ result.difficult = true;
+ }
+
+ /* If the condition is joinable. */
+ if (!result.exits && !result.difficult)
+ {
+ /* Only return a next pointer if we dominate this pointer.
+ Otherwise it will be handled by the bb dominating it. */
+ if (dominated_by_p (CDI_DOMINATORS, last_bb, bb) && last_bb != bb)
+ result.next = last_e;
+ else
+ result.next = NULL;
+
+ move_scops (&tmp_scops, scops);
+ break;
+ }
+
+ /* Scan remaining bbs dominated by BB. */
+ dominated = get_dominated_by (CDI_DOMINATORS, bb);
+
+ for (i = 0; VEC_iterate (basic_block, dominated, i, dom_bb); i++)
+ {
+ /* Ignore loop exits: they will be handled after the loop body. */
+ if (is_loop_exit (loop, dom_bb))
+ {
+ result.exits = true;
+ continue;
+ }
+
+ /* Ignore the bbs processed above. */
+ if (single_pred_p (dom_bb) && single_pred (dom_bb) == bb)
+ continue;
+
+ if (single_pred_p (dom_bb))
+ e = single_pred_edge (dom_bb);
+ else
+ e = split_block (dom_bb, NULL);
+
+ if (loop_depth (loop) > loop_depth (dom_bb->loop_father))
+ sinfo = build_scops_1 (e, &tmp_scops, loop_outer (loop),
+ outermost_loop);
+ else
+ sinfo = build_scops_1 (e, &tmp_scops, loop, outermost_loop);
+
+
+ result.exits |= sinfo.exits;
+ result.difficult = true;
+ result.last = NULL;
+ }
+
+ VEC_free (basic_block, heap, dominated);
+
+ result.next = NULL;
+ move_scops (&tmp_scops, scops);
+
+ break;
+ }
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return result;
+}
+
+/* Split EXIT before STMT when STMT is non NULL. */
+
+static edge
+split_difficult_bb (basic_block exit, edge *last, gimple stmt)
+{
+ if (stmt && VEC_length (edge, exit->preds) == 1)
+ {
+ edge e;
+
+ if (stmt == gsi_stmt (gsi_after_labels (exit)))
+ stmt = NULL;
+ else
+ {
+ gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+ gsi_prev (&gsi);
+ stmt = gsi_stmt (gsi);
+ }
+
+ e = split_block (exit, stmt);
+ set_immediate_dominator (CDI_DOMINATORS, e->dest, e->src);
+ set_immediate_dominator (CDI_POST_DOMINATORS, e->src, e->dest);
+ exit = e->dest;
+
+ if (last)
+ *last = e;
+
+ return e;
+ }
+
+ return NULL;
+}
+
+/* End SCOP with edge EXIT. */
+
+static void
+end_scop (scop_p scop, edge exit, bool split_entry)
+{
+ if (split_entry
+ && !single_pred_p (SCOP_ENTRY (scop))
+ && exit->dest->loop_father == SCOP_ENTRY (scop)->loop_father)
+ SESE_ENTRY (SCOP_REGION (scop)) = split_block (SCOP_ENTRY (scop), NULL);
+
+ SESE_EXIT (SCOP_REGION (scop)) = exit;
+}
+
+/* Creates the SCoPs and writes entry and exit points for every SCoP. */
+
+static struct scopdet_info
+build_scops_1 (edge start, VEC (scop_p, heap) **scops, loop_p loop,
+ loop_p outermost_loop)
+{
+ edge current = start;
+
+ bool in_scop = false;
+ scop_p open_scop = NULL;
+ gimple stmt;
+ struct scopdet_info sinfo;
+
+ /* Initialize result. */
+ struct scopdet_info result;
+ result.exits = false;
+ result.difficult = false;
+ result.next = NULL;
+ result.last = NULL;
+
+ /* Loop over the dominance tree. If we meet a difficult bb, close
+ the current SCoP. Loop and condition header start a new layer,
+ and can only be added if all bbs in deeper layers are simple. */
+ while (current != NULL)
+ {
+ sinfo = scopdet_edge_info (current, outermost_loop, scops,
+ get_bb_type (current->dest, loop), &stmt);
+
+ if (!in_scop && !(sinfo.exits || sinfo.difficult))
+ {
+ open_scop = new_scop (current);
+
+ VEC_safe_push (scop_p, heap, *scops, open_scop);
+ in_scop = true;
+ }
+ else if (in_scop && (sinfo.exits || sinfo.difficult))
+ {
+ edge exit = split_difficult_bb (current->dest, &sinfo.last, stmt);
+
+ if (!exit)
+ exit = current;
+
+ end_scop (open_scop, exit, sinfo.difficult);
+ in_scop = false;
+ }
+
+ result.difficult |= sinfo.difficult;
+ result.exits |= sinfo.exits;
+
+ current = sinfo.next;
+ }
+
+ /* Finish the SCOP, if it is left open. The exit is the bb, that
+ postdominates sinfo.last. If no such bb exists, we use info.last
+ or delete the scop. */
+ if (in_scop)
+ {
+ int i;
+ edge e;
+
+ for (i = 0; VEC_iterate (edge, sinfo.last->dest->succs, i, e); i++)
+ if (dominated_by_p (CDI_POST_DOMINATORS, sinfo.last->dest, e->dest))
+ {
+ edge exit = split_difficult_bb (e->dest, &sinfo.last, stmt);
+
+ if (exit)
+ end_scop (open_scop, exit, sinfo.difficult);
+ else
+ end_scop (open_scop, e, sinfo.difficult);
+
+ goto done;
+ }
+
+ if (SCOP_ENTRY (open_scop) != sinfo.last->dest)
+ {
+ edge exit = split_difficult_bb (sinfo.last->dest, NULL, stmt);
+
+ if (exit)
+ end_scop (open_scop, exit, sinfo.difficult);
+ else
+ end_scop (open_scop, sinfo.last, sinfo.difficult);
+ }
+ else
+ {
+ VEC_pop (scop_p, *scops);
+ free_scop (open_scop);
+ }
+ }
+
+ done:
+ result.last = sinfo.last;
+
+ return result;
+}
+
+/* Find static control parts. */
+
+static void
+build_scops (void)
+{
+ struct loop *loop = current_loops->tree_root;
+ build_scops_1 (single_succ_edge (ENTRY_BLOCK_PTR), &current_scops, loop, loop);
+}
+
+/* Gather the basic blocks belonging to the SCOP. */
+
+static void
+build_scop_bbs (scop_p scop)
+{
+ basic_block *stack = XNEWVEC (basic_block, n_basic_blocks + 1);
+ sbitmap visited = sbitmap_alloc (last_basic_block);
+ int sp = 0;
+
+ sbitmap_zero (visited);
+ stack[sp++] = SCOP_ENTRY (scop);
+
+ while (sp)
+ {
+ basic_block bb = stack[--sp];
+ int depth = loop_depth (bb->loop_father);
+ int num = bb->loop_father->num;
+ edge_iterator ei;
+ edge e;
+
+ /* Scop's exit is not in the scop. Exclude also bbs, which are
+ dominated by the SCoP exit. These are e.g. loop latches. */
+ if (TEST_BIT (visited, bb->index)
+ || dominated_by_p (CDI_DOMINATORS, bb, SCOP_EXIT (scop))
+ /* Every block in the scop is dominated by scop's entry. */
+ || !dominated_by_p (CDI_DOMINATORS, bb, SCOP_ENTRY (scop)))
+ continue;
+
+ new_graphite_bb (scop, bb);
+ SET_BIT (visited, bb->index);
+
+ /* First push the blocks that have to be processed last. Note
+ that this means that the order in which the code is organized
+ below is important: do not reorder the following code. */
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (! TEST_BIT (visited, e->dest->index)
+ && (int) loop_depth (e->dest->loop_father) < depth)
+ stack[sp++] = e->dest;
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (! TEST_BIT (visited, e->dest->index)
+ && (int) loop_depth (e->dest->loop_father) == depth
+ && e->dest->loop_father->num != num)
+ stack[sp++] = e->dest;
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (! TEST_BIT (visited, e->dest->index)
+ && (int) loop_depth (e->dest->loop_father) == depth
+ && e->dest->loop_father->num == num
+ && EDGE_COUNT (e->dest->preds) > 1)
+ stack[sp++] = e->dest;
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (! TEST_BIT (visited, e->dest->index)
+ && (int) loop_depth (e->dest->loop_father) == depth
+ && e->dest->loop_father->num == num
+ && EDGE_COUNT (e->dest->preds) == 1)
+ stack[sp++] = e->dest;
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (! TEST_BIT (visited, e->dest->index)
+ && (int) loop_depth (e->dest->loop_father) > depth)
+ stack[sp++] = e->dest;
+ }
+
+ free (stack);
+ sbitmap_free (visited);
+}
+
+
+/* Record LOOP as occuring in SCOP. */
+
+static void
+scop_record_loop (scop_p scop, struct loop *loop)
+{
+ loop_p parent;
+ tree induction_var;
+
+ if (bitmap_bit_p (SCOP_LOOPS (scop), loop->num))
+ return;
+
+ parent = loop_outer (loop);
+ induction_var = find_induction_var_from_exit_cond (loop);
+
+ if (!bb_in_scop_p (parent->latch, scop))
+ parent = NULL;
+
+ if (induction_var != NULL_TREE)
+ {
+ name_tree oldiv = XNEW (struct name_tree);
+ oldiv->t = SSA_NAME_VAR (induction_var);
+ if (DECL_NAME (oldiv->t))
+ oldiv->name = IDENTIFIER_POINTER (DECL_NAME (oldiv->t));
+ else
+ {
+ char *n = XNEWVEC (char, 16);
+ sprintf (n, "D.%u", DECL_UID (oldiv->t));
+ oldiv->name = n;
+ }
+ oldiv->loop = loop;
+
+ VEC_safe_push (name_tree, heap, SCOP_OLDIVS (scop), oldiv);
+ }
+
+ bitmap_set_bit (SCOP_LOOPS (scop), loop->num);
+ VEC_safe_push (loop_p, heap, SCOP_LOOP_NEST (scop), loop);
+}
+
+/* Build the loop nests contained in SCOP. */
+
+static void
+build_scop_loop_nests (scop_p scop)
+{
+ unsigned i;
+ graphite_bb_p gb;
+ struct loop *loop0, *loop1;
+
+ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++)
+ {
+ struct loop *loop = gbb_loop (gb);
+
+ /* Only add loops, if they are completely contained in the SCoP. */
+ if (loop->header == GBB_BB (gb)
+ && bb_in_scop_p (loop->latch, scop))
+ scop_record_loop (scop, gbb_loop (gb));
+ }
+
+ /* Make sure that the loops in the SCOP_LOOP_NEST are ordered. It
+ can be the case that an inner loop is inserted before an outer
+ loop. To avoid this, semi-sort once. */
+ for (i = 0; VEC_iterate (loop_p, SCOP_LOOP_NEST (scop), i, loop0); i++)
+ {
+ if (VEC_length (loop_p, SCOP_LOOP_NEST (scop)) == i + 1)
+ break;
+
+ loop1 = VEC_index (loop_p, SCOP_LOOP_NEST (scop), i + 1);
+ if (loop0->num > loop1->num)
+ {
+ VEC_replace (loop_p, SCOP_LOOP_NEST (scop), i, loop1);
+ VEC_replace (loop_p, SCOP_LOOP_NEST (scop), i + 1, loop0);
+ }
+ }
+}
+
+/* Calculate the number of loops around GB in the current SCOP. */
+
+static inline int
+nb_loops_around_gb (graphite_bb_p gb)
+{
+ scop_p scop = GBB_SCOP (gb);
+ struct loop *l = gbb_loop (gb);
+ int d = 0;
+
+ for (; loop_in_scop_p (l, scop); d++, l = loop_outer (l));
+
+ return d;
+}
+
+/* Build for BB the static schedule.
+
+ The STATIC_SCHEDULE is defined like this:
+
+ A
+ for (i: ...)
+ {
+ for (j: ...)
+ {
+ B
+ C
+ }
+
+ for (k: ...)
+ {
+ D
+ E
+ }
+ }
+ F
+
+ Static schedules for A to F:
+
+ DEPTH
+ 0 1 2
+ A 0
+ B 1 0 0
+ C 1 0 1
+ D 1 1 0
+ E 1 1 1
+ F 2
+*/
+
+static void
+build_scop_canonical_schedules (scop_p scop)
+{
+ int i, j;
+ graphite_bb_p gb;
+ int nb = scop_nb_loops (scop) + 1;
+
+ SCOP_STATIC_SCHEDULE (scop) = lambda_vector_new (nb);
+
+ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++)
+ {
+ int offset = nb_loops_around_gb (gb);
+
+ /* After leaving a loop, it is possible that the schedule is not
+ set at zero. This loop reinitializes components located
+ after OFFSET. */
+
+ for (j = offset + 1; j < nb; j++)
+ if (SCOP_STATIC_SCHEDULE (scop)[j])
+ {
+ memset (&(SCOP_STATIC_SCHEDULE (scop)[j]), 0,
+ sizeof (int) * (nb - j));
+ ++SCOP_STATIC_SCHEDULE (scop)[offset];
+ break;
+ }
+
+ GBB_STATIC_SCHEDULE (gb) = lambda_vector_new (offset + 1);
+ lambda_vector_copy (SCOP_STATIC_SCHEDULE (scop),
+ GBB_STATIC_SCHEDULE (gb), offset + 1);
+
+ ++SCOP_STATIC_SCHEDULE (scop)[offset];
+ }
+}
+
+/* Build the LOOPS vector for all bbs in SCOP. */
+
+static void
+build_bb_loops (scop_p scop)
+{
+ graphite_bb_p gb;
+ int i;
+
+ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++)
+ {
+ loop_p loop;
+ int depth;
+
+ depth = nb_loops_around_gb (gb) - 1;
+
+ GBB_LOOPS (gb) = VEC_alloc (loop_p, heap, 3);
+ VEC_safe_grow_cleared (loop_p, heap, GBB_LOOPS (gb), depth + 1);
+
+ loop = GBB_BB (gb)->loop_father;
+
+ while (scop_contains_loop (scop, loop))
+ {
+ VEC_replace (loop_p, GBB_LOOPS (gb), depth, loop);
+ loop = loop_outer (loop);
+ depth--;
+ }
+ }
+}
+
+/* Get the index for parameter VAR in SCOP. */
+
+static int
+param_index (tree var, scop_p scop)
+{
+ int i;
+ name_tree p;
+ name_tree nvar;
+
+ gcc_assert (TREE_CODE (var) == SSA_NAME);
+
+ for (i = 0; VEC_iterate (name_tree, SCOP_PARAMS (scop), i, p); i++)
+ if (p->t == var)
+ return i;
+
+ nvar = XNEW (struct name_tree);
+ nvar->t = var;
+ nvar->name = NULL;
+ VEC_safe_push (name_tree, heap, SCOP_PARAMS (scop), nvar);
+ return VEC_length (name_tree, SCOP_PARAMS (scop)) - 1;
+}
+
+/* Scan EXPR and translate it to an inequality vector INEQ that will
+ be added, or subtracted, in the constraint domain matrix C at row
+ R. K is the number of columns for loop iterators in C. */
+
+static void
+scan_tree_for_params (scop_p s, tree e, CloogMatrix *c, int r, Value k,
+ bool subtract)
+{
+ int cst_col, param_col;
+
+ if (e == chrec_dont_know)
+ return;
+
+ switch (TREE_CODE (e))
+ {
+ case POLYNOMIAL_CHREC:
+ {
+ tree left = CHREC_LEFT (e);
+ tree right = CHREC_RIGHT (e);
+ int var = CHREC_VARIABLE (e);
+
+ if (TREE_CODE (right) != INTEGER_CST)
+ return;
+
+ if (c)
+ {
+ int loop_col = scop_gimple_loop_depth (s, get_loop (var)) + 1;
+
+ if (subtract)
+ value_sub_int (c->p[r][loop_col], c->p[r][loop_col],
+ int_cst_value (right));
+ else
+ value_add_int (c->p[r][loop_col], c->p[r][loop_col],
+ int_cst_value (right));
+ }
+
+ switch (TREE_CODE (left))
+ {
+ case POLYNOMIAL_CHREC:
+ scan_tree_for_params (s, left, c, r, k, subtract);
+ return;
+
+ case INTEGER_CST:
+ /* Constant part. */
+ if (c)
+ {
+ int v = int_cst_value (left);
+ cst_col = c->NbColumns - 1;
+
+ if (v < 0)
+ {
+ v = -v;
+ subtract = subtract ? false : true;
+ }
+
+ if (subtract)
+ value_sub_int (c->p[r][cst_col], c->p[r][cst_col], v);
+ else
+ value_add_int (c->p[r][cst_col], c->p[r][cst_col], v);
+ }
+ return;
+
+ default:
+ scan_tree_for_params (s, left, c, r, k, subtract);
+ return;
+ }
+ }
+ break;
+
+ case MULT_EXPR:
+ if (chrec_contains_symbols (TREE_OPERAND (e, 0)))
+ {
+ Value val;
+
+ gcc_assert (host_integerp (TREE_OPERAND (e, 1), 0));
+
+ value_init (val);
+ value_set_si (val, int_cst_value (TREE_OPERAND (e, 1)));
+ value_multiply (k, k, val);
+ value_clear (val);
+ scan_tree_for_params (s, TREE_OPERAND (e, 0), c, r, k, subtract);
+ }
+ else
+ {
+ Value val;
+
+ gcc_assert (host_integerp (TREE_OPERAND (e, 0), 0));
+
+ value_init (val);
+ value_set_si (val, int_cst_value (TREE_OPERAND (e, 0)));
+ value_multiply (k, k, val);
+ value_clear (val);
+ scan_tree_for_params (s, TREE_OPERAND (e, 1), c, r, k, subtract);
+ }
+ break;
+
+ case PLUS_EXPR:
+ scan_tree_for_params (s, TREE_OPERAND (e, 0), c, r, k, subtract);
+ scan_tree_for_params (s, TREE_OPERAND (e, 1), c, r, k, subtract);
+ break;
+
+ case MINUS_EXPR:
+ scan_tree_for_params (s, TREE_OPERAND (e, 0), c, r, k, subtract);
+ value_oppose (k, k);
+ scan_tree_for_params (s, TREE_OPERAND (e, 1), c, r, k, subtract);
+ break;
+
+ case NEGATE_EXPR:
+ value_oppose (k, k);
+ scan_tree_for_params (s, TREE_OPERAND (e, 0), c, r, k, subtract);
+ break;
+
+ case SSA_NAME:
+ param_col = param_index (e, s);
+
+ if (c)
+ {
+ param_col += c->NbColumns - scop_nb_params (s) - 1;
+
+ if (subtract)
+ value_subtract (c->p[r][param_col], c->p[r][param_col], k);
+ else
+ value_addto (c->p[r][param_col], c->p[r][param_col], k);
+ }
+ break;
+
+ case INTEGER_CST:
+ if (c)
+ {
+ int v = int_cst_value (e);
+ cst_col = c->NbColumns - 1;
+
+ if (v < 0)
+ {
+ v = -v;
+ subtract = subtract ? false : true;
+ }
+
+ if (subtract)
+ value_sub_int (c->p[r][cst_col], c->p[r][cst_col], v);
+ else
+ value_add_int (c->p[r][cst_col], c->p[r][cst_col], v);
+ }
+ break;
+
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
+ scan_tree_for_params (s, TREE_OPERAND (e, 0), c, r, k, subtract);
+ break;
+
+ default:
+ gcc_unreachable ();
+ break;
+ }
+}
+
+/* Data structure for idx_record_params. */
+
+struct irp_data
+{
+ struct loop *loop;
+ scop_p scop;
+};
+
+/* For a data reference with an ARRAY_REF as its BASE, record the
+ parameters occurring in IDX. DTA is passed in as complementary
+ information, and is used by the automatic walker function. This
+ function is a callback for for_each_index. */
+
+static bool
+idx_record_params (tree base, tree *idx, void *dta)
+{
+ struct irp_data *data = (struct irp_data *) dta;
+
+ if (TREE_CODE (base) != ARRAY_REF)
+ return true;
+
+ if (TREE_CODE (*idx) == SSA_NAME)
+ {
+ tree scev;
+ scop_p scop = data->scop;
+ struct loop *loop = data->loop;
+
+ scev = analyze_scalar_evolution (loop, *idx);
+ scev = instantiate_scev (outermost_loop_in_scop (scop, loop->header),
+ loop, scev);
+
+ {
+ Value one;
+
+ value_init (one);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, scev, NULL, 0, one, false);
+ value_clear (one);
+ }
+ }
+
+ return true;
+}
+
+/* Find parameters with respect to SCOP in BB. We are looking in memory
+ access functions, conditions and loop bounds. */
+
+static void
+find_params_in_bb (scop_p scop, basic_block bb)
+{
+ int i;
+ data_reference_p dr;
+ VEC (data_reference_p, heap) *drs;
+ gimple_stmt_iterator gsi;
+ struct loop *nest = outermost_loop_in_scop (scop, bb);
+
+ /* Find the parameters used in the memory access functions. */
+ drs = VEC_alloc (data_reference_p, heap, 5);
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ find_data_references_in_stmt (nest, gsi_stmt (gsi), &drs);
+
+ for (i = 0; VEC_iterate (data_reference_p, drs, i, dr); i++)
+ {
+ struct irp_data irp;
+
+ irp.loop = bb->loop_father;
+ irp.scop = scop;
+ for_each_index (&dr->ref, idx_record_params, &irp);
+ free_data_ref (dr);
+ }
+
+ VEC_free (data_reference_p, heap, drs);
+
+ /* Find parameters in conditional statements. */
+ gsi = gsi_last_bb (bb);
+ if (!gsi_end_p (gsi))
+ {
+ gimple stmt = gsi_stmt (gsi);
+
+ if (gimple_code (stmt) == GIMPLE_COND)
+ {
+ Value one;
+ loop_p loop = bb->loop_father;
+
+ tree lhs, rhs;
+
+ lhs = gimple_cond_lhs (stmt);
+ lhs = analyze_scalar_evolution (loop, lhs);
+ lhs = instantiate_scev (nest, loop, lhs);
+
+ rhs = gimple_cond_rhs (stmt);
+ rhs = analyze_scalar_evolution (loop, rhs);
+ rhs = instantiate_scev (nest, loop, rhs);
+
+ value_init (one);
+ scan_tree_for_params (scop, lhs, NULL, 0, one, false);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, rhs, NULL, 0, one, false);
+ value_clear (one);
+ }
+ }
+}
+
+/* Saves in NV the name of variable P->T. */
+
+static void
+save_var_name (char **nv, int i, name_tree p)
+{
+ const char *name = get_name (SSA_NAME_VAR (p->t));
+
+ if (name)
+ {
+ nv[i] = XNEWVEC (char, strlen (name) + 12);
+ sprintf (nv[i], "%s_%12d", name, SSA_NAME_VERSION (p->t));
+ }
+ else
+ {
+ nv[i] = XNEWVEC (char, 12);
+ sprintf (nv[i], "T_%12d", SSA_NAME_VERSION (p->t));
+ }
+
+ p->name = nv[i];
+}
+
+/* Return the maximal loop depth in SCOP. */
+
+static int
+scop_max_loop_depth (scop_p scop)
+{
+ int i;
+ graphite_bb_p gbb;
+ int max_nb_loops = 0;
+
+ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gbb); i++)
+ {
+ int nb_loops = gbb_nb_loops (gbb);
+ if (max_nb_loops < nb_loops)
+ max_nb_loops = nb_loops;
+ }
+
+ return max_nb_loops;
+}
+
+/* Initialize Cloog's parameter names from the names used in GIMPLE.
+ Initialize Cloog's iterator names, using 'graphite_iterator_%d'
+ from 0 to scop_nb_loops (scop). */
+
+static void
+initialize_cloog_names (scop_p scop)
+{
+ int i, nb_params = VEC_length (name_tree, SCOP_PARAMS (scop));
+ char **params = XNEWVEC (char *, nb_params);
+ int nb_iterators = scop_max_loop_depth (scop);
+ int nb_scattering= cloog_program_nb_scattdims (SCOP_PROG (scop));
+ char **iterators = XNEWVEC (char *, nb_iterators * 2);
+ char **scattering = XNEWVEC (char *, nb_scattering);
+ name_tree p;
+
+ for (i = 0; VEC_iterate (name_tree, SCOP_PARAMS (scop), i, p); i++)
+ save_var_name (params, i, p);
+
+ cloog_names_set_nb_parameters (cloog_program_names (SCOP_PROG (scop)),
+ nb_params);
+ cloog_names_set_parameters (cloog_program_names (SCOP_PROG (scop)),
+ params);
+
+ for (i = 0; i < nb_iterators; i++)
+ {
+ iterators[i] = XNEWVEC (char, 18 + 12);
+ sprintf (iterators[i], "graphite_iterator_%d", i);
+ }
+
+ cloog_names_set_nb_iterators (cloog_program_names (SCOP_PROG (scop)),
+ nb_iterators);
+ cloog_names_set_iterators (cloog_program_names (SCOP_PROG (scop)),
+ iterators);
+
+ for (i = 0; i < nb_scattering; i++)
+ {
+ scattering[i] = XNEWVEC (char, 2 + 12);
+ sprintf (scattering[i], "s_%d", i);
+ }
+
+ cloog_names_set_nb_scattering (cloog_program_names (SCOP_PROG (scop)),
+ nb_scattering);
+ cloog_names_set_scattering (cloog_program_names (SCOP_PROG (scop)),
+ scattering);
+}
+
+/* Record the parameters used in the SCOP. A variable is a parameter
+ in a scop if it does not vary during the execution of that scop. */
+
+static void
+find_scop_parameters (scop_p scop)
+{
+ graphite_bb_p gb;
+ unsigned i;
+ struct loop *loop;
+ Value one;
+
+ value_init (one);
+ value_set_si (one, 1);
+
+ /* Find the parameters used in the loop bounds. */
+ for (i = 0; VEC_iterate (loop_p, SCOP_LOOP_NEST (scop), i, loop); i++)
+ {
+ tree nb_iters = number_of_latch_executions (loop);
+
+ if (!chrec_contains_symbols (nb_iters))
+ continue;
+
+ nb_iters = analyze_scalar_evolution (loop, nb_iters);
+ nb_iters = instantiate_scev (outermost_loop_in_scop (scop, loop->header),
+ loop, nb_iters);
+ scan_tree_for_params (scop, nb_iters, NULL, 0, one, false);
+ }
+
+ value_clear (one);
+
+ /* Find the parameters used in data accesses. */
+ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++)
+ find_params_in_bb (scop, GBB_BB (gb));
+}
+
+/* Build the context constraints for SCOP: constraints and relations
+ on parameters. */
+
+static void
+build_scop_context (scop_p scop)
+{
+ int nb_params = scop_nb_params (scop);
+ CloogMatrix *matrix = cloog_matrix_alloc (1, nb_params + 2);
+
+ /* Insert '0 >= 0' in the context matrix, as it is not allowed to be
+ empty. */
+
+ value_set_si (matrix->p[0][0], 1);
+
+ value_set_si (matrix->p[0][nb_params + 1], 0);
+
+ cloog_program_set_context (SCOP_PROG (scop),
+ cloog_domain_matrix2domain (matrix));
+ cloog_matrix_free (matrix);
+}
+
+/* Returns a graphite_bb from BB. */
+
+static inline graphite_bb_p
+gbb_from_bb (basic_block bb)
+{
+ return (graphite_bb_p) bb->aux;
+}
+
+/* Add DOMAIN to all the basic blocks in LOOP. */
+
+static void
+add_bb_domains (struct loop *loop, CloogMatrix *domain)
+{
+ basic_block *bbs = get_loop_body (loop);
+ unsigned i;
+
+ for (i = 0; i < loop->num_nodes; i++)
+ if (bbs[i]->loop_father == loop)
+ {
+ graphite_bb_p gbb = gbb_from_bb (bbs[i]);
+ GBB_DOMAIN (gbb) = cloog_matrix_copy (domain);
+ }
+
+ free (bbs);
+}
+
+/* Builds the constraint matrix for LOOP in SCOP. NB_OUTER_LOOPS is the
+ number of loops surrounding LOOP in SCOP. OUTER_CSTR gives the
+ constraints matrix for the surrounding loops. */
+
+static void
+build_loop_iteration_domains (scop_p scop, struct loop *loop,
+ CloogMatrix *outer_cstr, int nb_outer_loops)
+{
+ int i, j, row;
+ CloogMatrix *cstr;
+
+ int nb_rows = outer_cstr->NbRows + 1;
+ int nb_cols = outer_cstr->NbColumns + 1;
+
+ /* Last column of CSTR is the column of constants. */
+ int cst_col = nb_cols - 1;
+
+ /* The column for the current loop is just after the columns of
+ other outer loops. */
+ int loop_col = nb_outer_loops + 1;
+
+ tree nb_iters = number_of_latch_executions (loop);
+
+ /* When the number of iterations is a constant or a parameter, we
+ add a constraint for the upper bound of the loop. So add a row
+ to the constraint matrix before allocating it. */
+ if (TREE_CODE (nb_iters) == INTEGER_CST
+ || !chrec_contains_undetermined (nb_iters))
+ nb_rows++;
+
+ cstr = cloog_matrix_alloc (nb_rows, nb_cols);
+
+ /* Copy the outer constraints. */
+ for (i = 0; i < outer_cstr->NbRows; i++)
+ {
+ /* Copy the eq/ineq and loops columns. */
+ for (j = 0; j < loop_col; j++)
+ value_assign (cstr->p[i][j], outer_cstr->p[i][j]);
+
+ /* Leave an empty column in CSTR for the current loop, and then
+ copy the parameter columns. */
+ for (j = loop_col; j < outer_cstr->NbColumns; j++)
+ value_assign (cstr->p[i][j + 1], outer_cstr->p[i][j]);
+ }
+
+ /* 0 <= loop_i */
+ row = outer_cstr->NbRows;
+ value_set_si (cstr->p[row][0], 1);
+ value_set_si (cstr->p[row][loop_col], 1);
+
+ /* loop_i <= nb_iters */
+ if (TREE_CODE (nb_iters) == INTEGER_CST)
+ {
+ row++;
+ value_set_si (cstr->p[row][0], 1);
+ value_set_si (cstr->p[row][loop_col], -1);
+
+ value_set_si (cstr->p[row][cst_col],
+ int_cst_value (nb_iters));
+ }
+ else if (!chrec_contains_undetermined (nb_iters))
+ {
+ /* Otherwise nb_iters contains parameters: scan the nb_iters
+ expression and build its matrix representation. */
+ Value one;
+
+ row++;
+ value_set_si (cstr->p[row][0], 1);
+ value_set_si (cstr->p[row][loop_col], -1);
+ nb_iters = analyze_scalar_evolution (loop, nb_iters);
+ nb_iters =
+ instantiate_scev (outermost_loop_in_scop (scop, loop->header),
+ loop, nb_iters);
+ value_init (one);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, nb_iters, cstr, row, one, false);
+ value_clear (one);
+ }
+ else
+ gcc_unreachable ();
+
+ if (loop->inner && loop_in_scop_p (loop->inner, scop))
+ build_loop_iteration_domains (scop, loop->inner, cstr, nb_outer_loops + 1);
+
+ /* Only go to the next loops, if we are not at the outermost layer. These
+ have to be handled seperately, as we can be sure, that the chain at this
+ layer will be connected. */
+ if (nb_outer_loops != 0 && loop->next && loop_in_scop_p (loop->next, scop))
+ build_loop_iteration_domains (scop, loop->next, outer_cstr, nb_outer_loops);
+
+ add_bb_domains (loop, cstr);
+
+ cloog_matrix_free (cstr);
+}
+
+/* Add conditions to the domain of GB. */
+
+static void
+add_conditions_to_domain (graphite_bb_p gb)
+{
+ unsigned int i,j;
+ gimple stmt;
+ VEC (gimple, heap) *conditions = GBB_CONDITIONS (gb);
+ CloogMatrix *domain = GBB_DOMAIN (gb);
+ scop_p scop = GBB_SCOP (gb);
+
+ unsigned nb_rows;
+ unsigned nb_cols;
+ unsigned nb_new_rows = 0;
+ unsigned row;
+
+ if (VEC_empty (gimple, conditions))
+ return;
+
+ if (domain)
+ {
+ nb_rows = domain->NbRows;
+ nb_cols = domain->NbColumns;
+ }
+ else
+ {
+ nb_rows = 0;
+ nb_cols = scop_nb_params (scop) + 2;
+ }
+
+ /* Count number of necessary new rows to add the conditions to the
+ domain. */
+ for (i = 0; VEC_iterate (gimple, conditions, i, stmt); i++)
+ {
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_COND:
+ {
+ enum tree_code code = gimple_cond_code (stmt);
+
+ switch (code)
+ {
+ case NE_EXPR:
+ case EQ_EXPR:
+ /* NE and EQ statements are not supported right know. */
+ gcc_unreachable ();
+ break;
+ case LT_EXPR:
+ case GT_EXPR:
+ case LE_EXPR:
+ case GE_EXPR:
+ nb_new_rows++;
+ break;
+ default:
+ gcc_unreachable ();
+ break;
+ }
+ break;
+ }
+ case SWITCH_EXPR:
+ /* Switch statements are not supported right know. */
+ gcc_unreachable ();
+ break;
+
+ default:
+ gcc_unreachable ();
+ break;
+ }
+ }
+
+
+ /* Enlarge the matrix. */
+ {
+ CloogMatrix *new_domain;
+ new_domain = cloog_matrix_alloc (nb_rows + nb_new_rows, nb_cols);
+
+ for (i = 0; i < nb_rows; i++)
+ for (j = 0; j < nb_cols; j++)
+ value_assign (new_domain->p[i][j], domain->p[i][j]);
+
+ cloog_matrix_free (domain);
+ domain = new_domain;
+ GBB_DOMAIN (gb) = new_domain;
+ }
+
+ /* Add the conditions to the new enlarged domain matrix. */
+ row = nb_rows;
+ for (i = 0; VEC_iterate (gimple, conditions, i, stmt); i++)
+ {
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_COND:
+ {
+ Value one;
+ enum tree_code code;
+ tree left;
+ tree right;
+ loop_p loop = GBB_BB (gb)->loop_father;
+ loop_p outermost = outermost_loop_in_scop (scop, GBB_BB (gb));
+
+ left = gimple_cond_lhs (stmt);
+ right = gimple_cond_rhs (stmt);
+
+ left = analyze_scalar_evolution (loop, left);
+ right = analyze_scalar_evolution (loop, right);
+ left = instantiate_scev (outermost, loop, left);
+ right = instantiate_scev (outermost, loop, right);
+
+ code = gimple_cond_code (stmt);
+
+ /* The conditions for ELSE-branches are inverted. */
+ if (VEC_index (gimple, gb->condition_cases, i) == NULL)
+ code = invert_tree_comparison (code, false);
+
+ switch (code)
+ {
+ case NE_EXPR:
+ /* NE statements are not supported right know. */
+ gcc_unreachable ();
+ break;
+ case EQ_EXPR:
+ value_set_si (domain->p[row][0], 1);
+ value_init (one);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, left, domain, row, one, true);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, right, domain, row, one, false);
+ row++;
+ value_set_si (domain->p[row][0], 1);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, left, domain, row, one, false);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, right, domain, row, one, true);
+ value_clear (one);
+ row++;
+ break;
+ case LT_EXPR:
+ value_set_si (domain->p[row][0], 1);
+ value_init (one);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, left, domain, row, one, true);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, right, domain, row, one, false);
+ value_sub_int (domain->p[row][nb_cols - 1],
+ domain->p[row][nb_cols - 1], 1);
+ value_clear (one);
+ row++;
+ break;
+ case GT_EXPR:
+ value_set_si (domain->p[row][0], 1);
+ value_init (one);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, left, domain, row, one, false);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, right, domain, row, one, true);
+ value_sub_int (domain->p[row][nb_cols - 1],
+ domain->p[row][nb_cols - 1], 1);
+ value_clear (one);
+ row++;
+ break;
+ case LE_EXPR:
+ value_set_si (domain->p[row][0], 1);
+ value_init (one);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, left, domain, row, one, true);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, right, domain, row, one, false);
+ value_clear (one);
+ row++;
+ break;
+ case GE_EXPR:
+ value_set_si (domain->p[row][0], 1);
+ value_init (one);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, left, domain, row, one, false);
+ value_set_si (one, 1);
+ scan_tree_for_params (scop, right, domain, row, one, true);
+ value_clear (one);
+ row++;
+ break;
+ default:
+ gcc_unreachable ();
+ break;
+ }
+ break;
+ }
+ case GIMPLE_SWITCH:
+ /* Switch statements are not supported right know. */
+ gcc_unreachable ();
+ break;
+
+ default:
+ gcc_unreachable ();
+ break;
+ }
+ }
+}
+
+/* Helper recursive function. */
+
+static void
+build_scop_conditions_1 (VEC (gimple, heap) **conditions,
+ VEC (gimple, heap) **cases, basic_block bb,
+ scop_p scop)
+{
+ int i, j;
+ graphite_bb_p gbb;
+ gimple_stmt_iterator gsi;
+ basic_block bb_child, bb_iter;
+ VEC (basic_block, heap) *dom;
+
+ /* Make sure we are in the SCoP. */
+ if (!bb_in_scop_p (bb, scop))
+ return;
+
+ /* Record conditions in graphite_bb. */
+ gbb = gbb_from_bb (bb);
+ GBB_CONDITIONS (gbb) = VEC_copy (gimple, heap, *conditions);
+ GBB_CONDITION_CASES (gbb) = VEC_copy (gimple, heap, *cases);
+
+ add_conditions_to_domain (gbb);
+
+ dom = get_dominated_by (CDI_DOMINATORS, bb);
+
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple stmt = gsi_stmt (gsi);
+ VEC (edge, gc) *edges;
+ edge e;
+
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_COND:
+ edges = bb->succs;
+ for (i = 0; VEC_iterate (edge, edges, i, e); i++)
+ if ((dominated_by_p (CDI_DOMINATORS, e->dest, bb))
+ && VEC_length (edge, e->dest->preds) == 1)
+ {
+ /* Remove the scanned block from the dominator successors. */
+ for (j = 0; VEC_iterate (basic_block, dom, j, bb_iter); j++)
+ if (bb_iter == e->dest)
+ {
+ VEC_unordered_remove (basic_block, dom, j);
+ break;
+ }
+
+ /* Recursively scan the then or else part. */
+ if (e->flags & EDGE_TRUE_VALUE)
+ VEC_safe_push (gimple, heap, *cases, stmt);
+ else if (e->flags & EDGE_FALSE_VALUE)
+ VEC_safe_push (gimple, heap, *cases, NULL);
+ else
+ gcc_unreachable ();
+
+ VEC_safe_push (gimple, heap, *conditions, stmt);
+ build_scop_conditions_1 (conditions, cases, e->dest, scop);
+ VEC_pop (gimple, *conditions);
+ VEC_pop (gimple, *cases);
+ }
+ break;
+
+ case GIMPLE_SWITCH:
+ {
+ unsigned i;
+ gimple_stmt_iterator gsi_search_gimple_label;
+
+ for (i = 0; i < gimple_switch_num_labels (stmt); ++i)
+ {
+ basic_block bb_iter;
+ size_t k;
+ size_t n_cases = VEC_length (gimple, *conditions);
+ unsigned n = gimple_switch_num_labels (stmt);
+
+ bb_child = label_to_block
+ (CASE_LABEL (gimple_switch_label (stmt, i)));
+
+ /* Do not handle multiple values for the same block. */
+ for (k = 0; k < n; k++)
+ if (i != k
+ && label_to_block
+ (CASE_LABEL (gimple_switch_label (stmt, k))) == bb_child)
+ break;
+
+ if (k != n)
+ continue;
+
+ /* Switch cases with more than one predecessor are not
+ handled. */
+ if (VEC_length (edge, bb_child->preds) != 1)
+ continue;
+
+ /* Recursively scan the corresponding 'case' block. */
+
+ for (gsi_search_gimple_label = gsi_start_bb (bb_child);
+ !gsi_end_p (gsi_search_gimple_label);
+ gsi_next (&gsi_search_gimple_label))
+ {
+ gimple stmt_gimple_label
+ = gsi_stmt (gsi_search_gimple_label);
+
+ if (gimple_code (stmt_gimple_label) == GIMPLE_LABEL)
+ {
+ tree t = gimple_label_label (stmt_gimple_label);
+
+ if (t == gimple_switch_label (stmt, i))
+ VEC_replace (gimple, *cases, n_cases,
+ stmt_gimple_label);
+ else
+ gcc_unreachable ();
+ }
+ }
+
+ build_scop_conditions_1 (conditions, cases, bb_child, scop);
+
+ /* Remove the scanned block from the dominator successors. */
+ for (j = 0; VEC_iterate (basic_block, dom, j, bb_iter); j++)
+ if (bb_iter == bb_child)
+ {
+ VEC_unordered_remove (basic_block, dom, j);
+ break;
+ }
+ }
+
+ VEC_pop (gimple, *conditions);
+ VEC_pop (gimple, *cases);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ /* Scan all immediate dominated successors. */
+ for (i = 0; VEC_iterate (basic_block, dom, i, bb_child); i++)
+ build_scop_conditions_1 (conditions, cases, bb_child, scop);
+
+ VEC_free (basic_block, heap, dom);
+}
+
+/* Record all 'if' and 'switch' conditions in each gbb of SCOP. */
+
+static void
+build_scop_conditions (scop_p scop)
+{
+ VEC (gimple, heap) *conditions = NULL;
+ VEC (gimple, heap) *cases = NULL;
+
+ build_scop_conditions_1 (&conditions, &cases, SCOP_ENTRY (scop), scop);
+
+ VEC_free (gimple, heap, conditions);
+ VEC_free (gimple, heap, cases);
+}
+
+/* Build the current domain matrix: the loops belonging to the current
+ SCOP, and that vary for the execution of the current basic block.
+ Returns false if there is no loop in SCOP. */
+
+static bool
+build_scop_iteration_domain (scop_p scop)
+{
+ struct loop *loop;
+ CloogMatrix *outer_cstr;
+ int i;
+
+ /* Build cloog loop for all loops, that are in the uppermost loop layer of
+ this SCoP. */
+ for (i = 0; VEC_iterate (loop_p, SCOP_LOOP_NEST (scop), i, loop); i++)
+ if (!loop_in_scop_p (loop_outer (loop), scop))
+ {
+ /* The outermost constraints is a matrix that has:
+ -first column: eq/ineq boolean
+ -last column: a constant
+ -scop_nb_params columns for the parameters used in the scop. */
+ outer_cstr = cloog_matrix_alloc (0, scop_nb_params (scop) + 2);
+ build_loop_iteration_domains (scop, loop, outer_cstr, 0);
+ cloog_matrix_free (outer_cstr);
+ }
+
+ return (i != 0);
+}
+
+/* Initializes an equation CY of the access matrix using the
+ information for a subscript from ACCESS_FUN, relatively to the loop
+ indexes from LOOP_NEST and parameter indexes from PARAMS. NDIM is
+ the dimension of the array access, i.e. the number of
+ subscripts. Returns true when the operation succeeds. */
+
+static bool
+build_access_matrix_with_af (tree access_fun, lambda_vector cy,
+ scop_p scop, int ndim)
+{
+ switch (TREE_CODE (access_fun))
+ {
+ case POLYNOMIAL_CHREC:
+ {
+ tree left = CHREC_LEFT (access_fun);
+ tree right = CHREC_RIGHT (access_fun);
+ int var;
+
+ if (TREE_CODE (right) != INTEGER_CST)
+ return false;
+
+ var = loop_iteration_vector_dim (CHREC_VARIABLE (access_fun), scop);
+ cy[var] = int_cst_value (right);
+
+ switch (TREE_CODE (left))
+ {
+ case POLYNOMIAL_CHREC:
+ return build_access_matrix_with_af (left, cy, scop, ndim);
+
+ case INTEGER_CST:
+ cy[ndim - 1] = int_cst_value (left);
+ return true;
+
+ default:
+ /* FIXME: access_fn can have parameters. */
+ return false;
+ }
+ }
+ case INTEGER_CST:
+ cy[ndim - 1] = int_cst_value (access_fun);
+ return true;
+
+ default:
+ /* FIXME: access_fn can have parameters. */
+ return false;
+ }
+}
+
+/* Initialize the access matrix in the data reference REF with respect
+ to the loop nesting LOOP_NEST. Return true when the operation
+ succeeded. */
+
+static bool
+build_access_matrix (data_reference_p ref, graphite_bb_p gb)
+{
+ int i, ndim = DR_NUM_DIMENSIONS (ref);
+ struct access_matrix *am = GGC_NEW (struct access_matrix);
+
+ AM_MATRIX (am) = VEC_alloc (lambda_vector, heap, ndim);
+ DR_SCOP (ref) = GBB_SCOP (gb);
+
+ for (i = 0; i < ndim; i++)
+ {
+ lambda_vector v = lambda_vector_new (ref_nb_loops (ref));
+ scop_p scop = GBB_SCOP (gb);
+ tree af = DR_ACCESS_FN (ref, i);
+
+ if (!build_access_matrix_with_af (af, v, scop, ref_nb_loops (ref)))
+ return false;
+
+ VEC_safe_push (lambda_vector, heap, AM_MATRIX (am), v);
+ }
+
+ DR_ACCESS_MATRIX (ref) = am;
+ return true;
+}
+
+/* Build the access matrices for the data references in the SCOP. */
+
+static void
+build_scop_data_accesses (scop_p scop)
+{
+ int i;
+ graphite_bb_p gb;
+
+ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++)
+ {
+ int j;
+ gimple_stmt_iterator gsi;
+ data_reference_p dr;
+ struct loop *nest = outermost_loop_in_scop (scop, GBB_BB (gb));
+
+ /* On each statement of the basic block, gather all the occurences
+ to read/write memory. */
+ GBB_DATA_REFS (gb) = VEC_alloc (data_reference_p, heap, 5);
+ for (gsi = gsi_start_bb (GBB_BB (gb)); !gsi_end_p (gsi); gsi_next (&gsi))
+ find_data_references_in_stmt (nest, gsi_stmt (gsi),
+ &GBB_DATA_REFS (gb));
+
+ /* FIXME: Construction of access matrix is disabled until some
+ pass, like the data dependence analysis, is using it. */
+ continue;
+
+ /* Construct the access matrix for each data ref, with respect to
+ the loop nest of the current BB in the considered SCOP. */
+ for (j = 0;
+ VEC_iterate (data_reference_p, GBB_DATA_REFS (gb), j, dr);
+ j++)
+ {
+ bool res = build_access_matrix (dr, gb);
+
+ /* FIXME: At this point the DRs should always have an affine
+ form. For the moment this fails as build_access_matrix
+ does not build matrices with parameters. */
+ gcc_assert (res);
+ }
+ }
+}
+
+/* Converts a GMP constant value to a tree and returns it. */
+
+static tree
+gmp_cst_to_tree (Value v)
+{
+ return build_int_cst (integer_type_node, value_get_si (v));
+}
+
+/* Returns the tree variable from the name NAME that was given in
+ Cloog representation. All the parameters are stored in PARAMS, and
+ all the loop induction variables are stored in IVSTACK.
+
+ FIXME: This is a hack, and Cloog should be fixed to not work with
+ variable names represented as "char *string", but with void
+ pointers that could be casted back to a tree. The only problem in
+ doing that is that Cloog's pretty printer still assumes that
+ variable names are char *strings. The solution would be to have a
+ function pointer for pretty-printing that can be redirected to be
+ print_generic_stmt in our case, or fprintf by default.
+ ??? Too ugly to live. */
+
+static tree
+clast_name_to_gcc (const char *name, VEC (name_tree, heap) *params,
+ loop_iv_stack ivstack)
+{
+ int i;
+ name_tree t;
+ tree iv;
+
+ for (i = 0; VEC_iterate (name_tree, params, i, t); i++)
+ if (!strcmp (name, t->name))
+ return t->t;
+
+ iv = loop_iv_stack_get_iv_from_name (ivstack, name);
+ if (iv)
+ return iv;
+
+ gcc_unreachable ();
+}
+
+/* Converts a Cloog AST expression E back to a GCC expression tree. */
+
+static tree
+clast_to_gcc_expression (struct clast_expr *e,
+ VEC (name_tree, heap) *params,
+ loop_iv_stack ivstack)
+{
+ tree type = integer_type_node;
+
+ gcc_assert (e);
+
+ switch (e->type)
+ {
+ case expr_term:
+ {
+ struct clast_term *t = (struct clast_term *) e;
+
+ if (t->var)
+ {
+ if (value_one_p (t->val))
+ return clast_name_to_gcc (t->var, params, ivstack);
+
+ else if (value_mone_p (t->val))
+ return fold_build1 (NEGATE_EXPR, type,
+ clast_name_to_gcc (t->var, params, ivstack));
+ else
+ return fold_build2 (MULT_EXPR, type,
+ gmp_cst_to_tree (t->val),
+ clast_name_to_gcc (t->var, params, ivstack));
+ }
+ else
+ return gmp_cst_to_tree (t->val);
+ }
+
+ case expr_red:
+ {
+ struct clast_reduction *r = (struct clast_reduction *) e;
+ tree left, right;
+
+ switch (r->type)
+ {
+ case clast_red_sum:
+ if (r->n == 1)
+ return clast_to_gcc_expression (r->elts[0], params, ivstack);
+
+ else
+ {
+ gcc_assert (r->n >= 1
+ && r->elts[0]->type == expr_term
+ && r->elts[1]->type == expr_term);
+
+ left = clast_to_gcc_expression (r->elts[0], params, ivstack);
+ right = clast_to_gcc_expression (r->elts[1], params, ivstack);
+ return fold_build2 (PLUS_EXPR, type, left, right);
+ }
+
+ break;
+
+ case clast_red_min:
+ if (r->n == 1)
+ return clast_to_gcc_expression (r->elts[0], params, ivstack);
+
+ else if (r->n == 2)
+ {
+ left = clast_to_gcc_expression (r->elts[0], params, ivstack);
+ right = clast_to_gcc_expression (r->elts[1], params, ivstack);
+ return fold_build2 (MIN_EXPR, type, left, right);
+ }
+
+ else
+ gcc_unreachable();
+
+ break;
+
+ case clast_red_max:
+ if (r->n == 1)
+ return clast_to_gcc_expression (r->elts[0], params, ivstack);
+
+ else if (r->n == 2)
+ {
+ left = clast_to_gcc_expression (r->elts[0], params, ivstack);
+ right = clast_to_gcc_expression (r->elts[1], params, ivstack);
+ return fold_build2 (MAX_EXPR, type, left, right);
+ }
+
+ else
+ gcc_unreachable();
+
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ }
+
+ case expr_bin:
+ {
+ struct clast_binary *b = (struct clast_binary *) e;
+ struct clast_expr *lhs = (struct clast_expr *) b->LHS;
+ struct clast_expr *rhs = (struct clast_expr *) b->RHS;
+ tree tl = clast_to_gcc_expression (lhs, params, ivstack);
+
+ /* FIXME: The next statement produces a warning: Cloog assumes
+ that the RHS is a constant, but this is a "void *" pointer
+ that should be casted into a Value, but this cast cannot be
+ done as Value is a GMP type, that is an array. Cloog must
+ be fixed for removing this warning. */
+ tree tr = gmp_cst_to_tree (rhs);
+
+ switch (b->type)
+ {
+ case clast_bin_fdiv:
+ return fold_build2 (FLOOR_DIV_EXPR, type, tl, tr);
+
+ case clast_bin_cdiv:
+ return fold_build2 (CEIL_DIV_EXPR, type, tl, tr);
+
+ case clast_bin_div:
+ return fold_build2 (EXACT_DIV_EXPR, type, tl, tr);
+
+ case clast_bin_mod:
+ return fold_build2 (TRUNC_MOD_EXPR, type, tl, tr);
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return NULL_TREE;
+}
+
+/* Translates a clast equation CLEQ to a tree. */
+
+static tree
+graphite_translate_clast_equation (scop_p scop,
+ struct clast_equation *cleq,
+ loop_iv_stack ivstack)
+{
+ enum tree_code comp;
+ tree lhs = clast_to_gcc_expression (cleq->LHS, SCOP_PARAMS (scop), ivstack);
+ tree rhs = clast_to_gcc_expression (cleq->RHS, SCOP_PARAMS (scop), ivstack);
+
+ if (cleq->sign == 0)
+ comp = EQ_EXPR;
+
+ else if (cleq->sign > 0)
+ comp = GE_EXPR;
+
+ else
+ comp = LE_EXPR;
+
+ return fold_build2 (comp, integer_type_node, lhs, rhs);
+}
+
+/* Creates the test for the condition in STMT. */
+
+static tree
+graphite_create_guard_cond_expr (scop_p scop, struct clast_guard *stmt,
+ loop_iv_stack ivstack)
+{
+ tree cond = NULL;
+ int i;
+
+ for (i = 0; i < stmt->n; i++)
+ {
+ tree eq = graphite_translate_clast_equation (scop, &stmt->eq[i], ivstack);
+
+ if (cond)
+ cond = fold_build2 (TRUTH_AND_EXPR, integer_type_node, cond, eq);
+ else
+ cond = eq;
+ }
+
+ return cond;
+}
+
+/* Creates a new if region corresponding to Cloog's guard. */
+
+static edge
+graphite_create_new_guard (scop_p scop, edge entry_edge,
+ struct clast_guard *stmt,
+ loop_iv_stack ivstack)
+{
+ tree cond_expr = graphite_create_guard_cond_expr (scop, stmt, ivstack);
+ edge exit_edge = create_empty_if_region_on_edge (entry_edge, cond_expr);
+ return exit_edge;
+}
+
+
+/* Creates a new LOOP corresponding to Cloog's STMT. Inserts an induction
+ variable for the new LOOP. New LOOP is attached to CFG starting at
+ ENTRY_EDGE. LOOP is inserted into the loop tree and becomes the child
+ loop of the OUTER_LOOP. */
+
+static struct loop *
+graphite_create_new_loop (scop_p scop, edge entry_edge,
+ struct clast_for *stmt, loop_iv_stack ivstack,
+ loop_p outer)
+{
+ struct loop *loop;
+ tree ivvar;
+ tree stride, lowb, upb;
+ tree iv_before;
+
+ gcc_assert (stmt->LB
+ && stmt->UB);
+
+ stride = gmp_cst_to_tree (stmt->stride);
+ lowb = clast_to_gcc_expression (stmt->LB, SCOP_PARAMS (scop), ivstack);
+ ivvar = create_tmp_var (integer_type_node, "graphiteIV");
+ add_referenced_var (ivvar);
+
+ upb = clast_to_gcc_expression (stmt->UB, SCOP_PARAMS (scop), ivstack);
+ loop = create_empty_loop_on_edge (entry_edge, lowb, stride, upb, ivvar,
+ &iv_before, outer ? outer
+ : entry_edge->src->loop_father);
+
+ loop_iv_stack_push (ivstack, iv_before, stmt->iterator);
+
+ return loop;
+}
+
+/* Remove all the edges from EDGES except the edge KEEP. */
+
+static void
+remove_all_edges_1 (VEC (edge, gc) *edges, edge keep)
+{
+ edge e;
+ edge_iterator ei;
+
+ for (ei = ei_start (edges); (e = ei_safe_edge (ei)); )
+ {
+ if (e != keep)
+ {
+ remove_edge (e);
+ e = ei_safe_edge (ei);
+ }
+ else
+ ei_next (&ei);
+ }
+}
+
+/* Remove all the edges from BB except the edge KEEP. */
+
+static void
+remove_all_edges (basic_block bb, edge keep)
+{
+ remove_all_edges_1 (bb->succs, keep);
+ remove_all_edges_1 (bb->preds, keep);
+}
+
+/* Rename the SSA_NAMEs used in STMT and that appear in IVSTACK. */
+
+static void
+graphite_rename_ivs_stmt (gimple stmt, graphite_bb_p gbb, scop_p scop,
+ loop_p old, loop_iv_stack ivstack)
+{
+ ssa_op_iter iter;
+ use_operand_p use_p;
+
+ FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
+ {
+ tree use = USE_FROM_PTR (use_p);
+ tree new_iv = NULL;
+ name_tree old_iv = get_old_iv_from_ssa_name (scop, old, use);
+
+ if (old_iv)
+ new_iv = loop_iv_stack_get_iv (ivstack,
+ gbb_loop_index (gbb, old_iv->loop));
+
+ if (new_iv)
+ SET_USE (use_p, new_iv);
+ }
+}
+
+/* Returns true if SSA_NAME is a parameter of SCOP. */
+
+static bool
+is_parameter (scop_p scop, tree ssa_name)
+{
+ int i;
+ VEC (name_tree, heap) *params = SCOP_PARAMS (scop);
+ name_tree param;
+
+ for (i = 0; VEC_iterate (name_tree, params, i, param); i++)
+ if (param->t == ssa_name)
+ return true;
+
+ return false;
+}
+
+/* Returns true if NAME is an old induction variable in SCOP. OLD is
+ the original loop that contained the definition of NAME. */
+
+static bool
+is_old_iv (scop_p scop, loop_p old, tree name)
+{
+ return get_old_iv_from_ssa_name (scop, old, name) != NULL;
+
+}
+
+static void expand_scalar_variables_stmt (gimple, graphite_bb_p, scop_p, loop_p,
+ loop_iv_stack);
+
+/* Constructs a tree which only contains old_ivs and parameters. Any
+ other variables that are defined outside GBB will be eliminated by
+ using their definitions in the constructed tree. OLD_LOOP_FATHER
+ is the original loop that contained GBB. */
+
+static tree
+expand_scalar_variables_expr (tree type, tree op0, enum tree_code code,
+ tree op1, graphite_bb_p gbb, scop_p scop,
+ loop_p old_loop_father, loop_iv_stack ivstack)
+{
+ if (TREE_CODE_CLASS (code) == tcc_constant
+ && code == INTEGER_CST)
+ return op0;
+
+ if (TREE_CODE_CLASS (code) == tcc_unary)
+ {
+ tree op0_type = TREE_TYPE (op0);
+ enum tree_code op0_code = TREE_CODE (op0);
+ tree op0_expr =
+ expand_scalar_variables_expr (op0_type, op0, op0_code,
+ NULL, gbb, scop, old_loop_father,
+ ivstack);
+
+ return fold_build1 (code, type, op0_expr);
+ }
+
+ if (TREE_CODE_CLASS (code) == tcc_binary)
+ {
+ tree op0_type = TREE_TYPE (op0);
+ enum tree_code op0_code = TREE_CODE (op0);
+ tree op0_expr =
+ expand_scalar_variables_expr (op0_type, op0, op0_code,
+ NULL, gbb, scop, old_loop_father,
+ ivstack);
+ tree op1_type = TREE_TYPE (op1);
+ enum tree_code op1_code = TREE_CODE (op1);
+ tree op1_expr =
+ expand_scalar_variables_expr (op1_type, op1, op1_code,
+ NULL, gbb, scop, old_loop_father,
+ ivstack);
+
+ return fold_build2 (code, type, op0_expr, op1_expr);
+ }
+
+ if (code == SSA_NAME)
+ {
+ tree var0, var1;
+ gimple def_stmt;
+ enum tree_code subcode;
+
+ if(is_parameter (scop, op0) ||
+ is_old_iv (scop, old_loop_father, op0))
+ return op0;
+
+ def_stmt = SSA_NAME_DEF_STMT (op0);
+
+ if (gimple_bb (def_stmt) == GBB_BB (gbb))
+ {
+ /* If the defining statement is in the basic block already
+ we do not need to create a new expression for it, we
+ only need to ensure its operands are expanded. */
+ expand_scalar_variables_stmt (def_stmt, gbb, scop,
+ old_loop_father, ivstack);
+ return op0;
+
+ }
+ else
+ {
+ if (gimple_code (def_stmt) != GIMPLE_ASSIGN)
+ return op0;
+
+ var0 = gimple_assign_rhs1 (def_stmt);
+ subcode = gimple_assign_rhs_code (def_stmt);
+ var1 = gimple_assign_rhs2 (def_stmt);
+
+ return expand_scalar_variables_expr (type, var0, subcode, var1,
+ gbb, scop, old_loop_father,
+ ivstack);
+ }
+ }
+
+ gcc_unreachable ();
+ return NULL;
+}
+
+/* Replicates any uses of non-parameters and non-old-ivs variablesthat
+ are defind outside GBB with code that is inserted in GBB.
+ OLD_LOOP_FATHER is the original loop that contained STMT. */
+
+static void
+expand_scalar_variables_stmt (gimple stmt, graphite_bb_p gbb, scop_p scop,
+ loop_p old_loop_father, loop_iv_stack ivstack)
+{
+ ssa_op_iter iter;
+ use_operand_p use_p;
+ basic_block bb = GBB_BB (gbb);
+
+ FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
+ {
+ tree use = USE_FROM_PTR (use_p);
+ tree type = TREE_TYPE (use);
+ enum tree_code code = TREE_CODE (use);
+ tree use_expr = expand_scalar_variables_expr (type, use, code, NULL,
+ gbb, scop, old_loop_father,
+ ivstack);
+ if (use_expr != use)
+ {
+ gimple_stmt_iterator gsi = gsi_after_labels (bb);
+ tree new_use =
+ force_gimple_operand_gsi (&gsi, use_expr, true, NULL,
+ true, GSI_NEW_STMT);
+ SET_USE (use_p, new_use);
+ }
+ }
+}
+
+/* Copies the definitions outside of GBB of variables that are not
+ induction variables nor parameters. GBB must only contain
+ "external" references to these types of variables. OLD_LOOP_FATHER
+ is the original loop that contained GBB. */
+
+static void
+expand_scalar_variables (graphite_bb_p gbb, scop_p scop,
+ loop_p old_loop_father, loop_iv_stack ivstack)
+{
+ basic_block bb = GBB_BB (gbb);
+ gimple_stmt_iterator gsi;
+
+ for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi);)
+ {
+ gimple stmt = gsi_stmt (gsi);
+ expand_scalar_variables_stmt (stmt, gbb, scop, old_loop_father,
+ ivstack);
+ gsi_next (&gsi);
+ }
+}
+
+/* Rename all the SSA_NAMEs from block GBB that appear in IVSTACK in
+ terms of new induction variables. OLD_LOOP_FATHER is the original
+ loop that contained GBB. */
+
+static void
+graphite_rename_ivs (graphite_bb_p gbb, scop_p scop, loop_p old_loop_father,
+ loop_iv_stack ivstack)
+{
+ basic_block bb = GBB_BB (gbb);
+ gimple_stmt_iterator gsi;
+
+ for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi);)
+ {
+ gimple stmt = gsi_stmt (gsi);
+
+ if (gimple_get_lhs (stmt)
+ && TREE_CODE (gimple_get_lhs (stmt)) == SSA_NAME
+ && get_old_iv_from_ssa_name (scop, old_loop_father,
+ gimple_get_lhs (stmt)))
+ gsi_remove (&gsi, false);
+ else
+ {
+ graphite_rename_ivs_stmt (stmt, gbb, scop, old_loop_father, ivstack);
+ gsi_next (&gsi);
+ }
+ }
+}
+
+/* Move all the PHI nodes from block FROM to block TO.
+ OLD_LOOP_FATHER is the original loop that contained FROM. */
+
+static void
+move_phi_nodes (scop_p scop, loop_p old_loop_father, basic_block from,
+ basic_block to)
+{
+ gimple_stmt_iterator gsi;
+
+ for (gsi = gsi_start_phis (from); !gsi_end_p (gsi);)
+ {
+ gimple phi = gsi_stmt (gsi);
+ tree op = gimple_phi_result (phi);
+
+ if (get_old_iv_from_ssa_name (scop, old_loop_father, op) == NULL)
+ {
+ gimple new_phi = make_phi_node (op, 0);
+ add_phi_node_to_bb (new_phi, to);
+ }
+ remove_phi_node (&gsi, false);
+ }
+}
+
+/* Remove condition from BB. */
+
+static void
+remove_condition (basic_block bb)
+{
+ gimple last = last_stmt (bb);
+
+ if (last && gimple_code (last) == GIMPLE_COND)
+ {
+ gimple_stmt_iterator gsi = gsi_last_bb (bb);
+ gsi_remove (&gsi, true);
+ }
+}
+
+/* Returns the first successor edge of BB with EDGE_TRUE_VALUE flag set. */
+
+static edge
+get_true_edge_from_guard_bb (basic_block bb)
+{
+ edge e;
+ edge_iterator ei;
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (e->flags & EDGE_TRUE_VALUE)
+ return e;
+
+ gcc_unreachable ();
+ return NULL;
+}
+
+/* Translates a CLAST statement STMT to GCC representation. NEXT_E is
+ the edge where new generated code should be attached. BB_EXIT is the last
+ basic block that defines the scope of code generation. CONTEXT_LOOP is the
+ loop in which the generated code will be placed (might be NULL). */
+
+static edge
+translate_clast (scop_p scop, struct loop *context_loop,
+ struct clast_stmt *stmt, edge next_e, loop_iv_stack ivstack)
+{
+ if (!stmt)
+ return next_e;
+
+ if (CLAST_STMT_IS_A (stmt, stmt_root))
+ return translate_clast (scop, context_loop, stmt->next, next_e, ivstack);
+
+ if (CLAST_STMT_IS_A (stmt, stmt_user))
+ {
+ CloogStatement *cs = ((struct clast_user_stmt *) stmt)->statement;
+ graphite_bb_p gbb = (graphite_bb_p) cloog_statement_usr (cs);
+ basic_block bb = gbb->bb;
+ loop_p old_loop_father = bb->loop_father;
+
+ if (bb == ENTRY_BLOCK_PTR)
+ return next_e;
+
+ remove_condition (bb);
+ expand_scalar_variables (gbb, scop, old_loop_father, ivstack);
+ remove_all_edges (bb, next_e);
+ move_phi_nodes (scop, old_loop_father, bb, next_e->src);
+ redirect_edge_succ_nodup (next_e, bb);
+
+ if (context_loop)
+ {
+ remove_bb_from_loops (bb);
+ add_bb_to_loop (bb, context_loop);
+ }
+
+ set_immediate_dominator (CDI_DOMINATORS, next_e->dest, next_e->src);
+ mark_virtual_ops_in_bb (bb);
+ next_e = make_edge (bb,
+ context_loop ? context_loop->latch : EXIT_BLOCK_PTR,
+ EDGE_FALLTHRU);;
+ graphite_rename_ivs (gbb, scop, old_loop_father, ivstack);
+ return translate_clast (scop, context_loop, stmt->next, next_e, ivstack);
+ }
+
+ if (CLAST_STMT_IS_A (stmt, stmt_for))
+ {
+ struct loop *loop
+ = graphite_create_new_loop (scop, next_e, (struct clast_for *) stmt,
+ ivstack, context_loop ? context_loop
+ : get_loop (0));
+ edge last_e = single_exit (loop);
+
+ next_e = translate_clast (scop, loop, ((struct clast_for *) stmt)->body,
+ single_pred_edge (loop->latch), ivstack);
+ redirect_edge_succ_nodup (next_e, loop->latch);
+
+ set_immediate_dominator (CDI_DOMINATORS, next_e->dest, next_e->src);
+ loop_iv_stack_pop (ivstack);
+
+ return translate_clast (scop, context_loop, stmt->next, last_e, ivstack);
+ }
+
+ if (CLAST_STMT_IS_A (stmt, stmt_guard))
+ {
+ edge last_e = graphite_create_new_guard (scop, next_e,
+ ((struct clast_guard *) stmt),
+ ivstack);
+ edge true_e = get_true_edge_from_guard_bb (next_e->dest);
+ next_e = translate_clast (scop, context_loop,
+ ((struct clast_guard *) stmt)->then,
+ true_e, ivstack);
+ redirect_edge_succ_nodup (next_e, last_e->src);
+ return translate_clast (scop, context_loop, stmt->next, last_e, ivstack);
+ }
+
+ if (CLAST_STMT_IS_A (stmt, stmt_block))
+ {
+ next_e = translate_clast (scop, context_loop,
+ ((struct clast_block *) stmt)->body,
+ next_e, ivstack);
+ return translate_clast (scop, context_loop, stmt->next, next_e, ivstack);
+ }
+
+ gcc_unreachable ();
+}
+
+/* Build cloog program for SCoP. */
+
+static void
+build_cloog_prog (scop_p scop)
+{
+ int i;
+ int max_nb_loops = scop_max_loop_depth (scop);
+ graphite_bb_p gbb;
+ CloogLoop *loop_list = NULL;
+ CloogBlockList *block_list = NULL;
+ CloogDomainList *scattering = NULL;
+ CloogProgram *prog = SCOP_PROG (scop);
+ int nbs = 2 * max_nb_loops + 1;
+ int *scaldims = (int *) xmalloc (nbs * (sizeof (int)));
+
+ cloog_program_set_nb_scattdims (prog, nbs);
+ initialize_cloog_names (scop);
+
+ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gbb); i++)
+ {
+ /* Build new block. */
+ CloogMatrix *domain = GBB_DOMAIN (gbb);
+ CloogStatement *stmt = cloog_statement_alloc (GBB_BB (gbb)->index);
+ CloogBlock *block = cloog_block_alloc (stmt, 0, NULL,
+ nb_loops_around_gb (gbb));
+ cloog_statement_set_usr (stmt, gbb);
+
+ /* Add empty domain to all bbs, which do not yet have a domain, as they
+ are not part of any loop. */
+ if (domain == NULL)
+ {
+ domain = cloog_matrix_alloc (0, scop_nb_params (scop) + 2);
+ GBB_DOMAIN (gbb) = domain;
+ }
+
+ /* Build loop list. */
+ {
+ CloogLoop *new_loop_list = cloog_loop_malloc ();
+ cloog_loop_set_next (new_loop_list, loop_list);
+ cloog_loop_set_domain (new_loop_list,
+ cloog_domain_matrix2domain (domain));
+ cloog_loop_set_block (new_loop_list, block);
+ loop_list = new_loop_list;
+ }
+
+ /* Build block list. */
+ {
+ CloogBlockList *new_block_list = cloog_block_list_malloc ();
+
+ cloog_block_list_set_next (new_block_list, block_list);
+ cloog_block_list_set_block (new_block_list, block);
+ block_list = new_block_list;
+ }
+
+ /* Build scattering list. */
+ {
+ /* XXX: Replace with cloog_domain_list_alloc(), when available. */
+ CloogDomainList *new_scattering
+ = (CloogDomainList *) xmalloc (sizeof (CloogDomainList));
+ CloogMatrix *scat_mat = schedule_to_scattering (gbb, nbs);
+
+ cloog_set_next_domain (new_scattering, scattering);
+ cloog_set_domain (new_scattering,
+ cloog_domain_matrix2domain (scat_mat));
+ scattering = new_scattering;
+ cloog_matrix_free (scat_mat);
+ }
+ }
+
+ cloog_program_set_loop (prog, loop_list);
+ cloog_program_set_blocklist (prog, block_list);
+
+ for (i = 0; i < nbs; i++)
+ scaldims[i] = 0 ;
+
+ cloog_program_set_scaldims (prog, scaldims);
+
+ /* Extract scalar dimensions to simplify the code generation problem. */
+ cloog_program_extract_scalars (prog, scattering);
+
+ /* Apply scattering. */
+ cloog_program_scatter (prog, scattering);
+
+ /* Iterators corresponding to scalar dimensions have to be extracted. */
+ cloog_names_scalarize (cloog_program_names (prog), nbs,
+ cloog_program_scaldims (prog));
+
+ /* Free blocklist. */
+ {
+ CloogBlockList *next = cloog_program_blocklist (prog);
+
+ while (next)
+ {
+ CloogBlockList *toDelete = next;
+ next = cloog_block_list_next (next);
+ cloog_block_list_set_next (toDelete, NULL);
+ cloog_block_list_set_block (toDelete, NULL);
+ cloog_block_list_free (toDelete);
+ }
+ cloog_program_set_blocklist (prog, NULL);
+ }
+}
+
+/* Return the options that will be used in GLOOG. */
+
+static CloogOptions *
+set_cloog_options (void)
+{
+ CloogOptions *options = cloog_options_malloc ();
+
+ /* Change cloog output language to C. If we do use FORTRAN instead, cloog
+ will stop e.g. with "ERROR: unbounded loops not allowed in FORTRAN.", if
+ we pass an incomplete program to cloog. */
+ options->language = LANGUAGE_C;
+
+ /* Enable complex equality spreading: removes dummy statements
+ (assignments) in the generated code which repeats the
+ substitution equations for statements. This is useless for
+ GLooG. */
+ options->esp = 1;
+
+ /* Enable C pretty-printing mode: normalizes the substitution
+ equations for statements. */
+ options->cpp = 1;
+
+ /* Allow cloog to build strides with a stride width different to one.
+ This example has stride = 4:
+
+ for (i = 0; i < 20; i += 4)
+ A */
+ options->strides = 1;
+
+ /* Disable optimizations and make cloog generate source code closer to the
+ input. This is useful for debugging, but later we want the optimized
+ code.
+
+ XXX: We can not disable optimizations, as loop blocking is not working
+ without them. */
+ if (0)
+ {
+ options->f = -1;
+ options->l = INT_MAX;
+ }
+
+ return options;
+}
+
+/* Prints STMT to STDERR. */
+
+void
+debug_clast_stmt (struct clast_stmt *stmt)
+{
+ CloogOptions *options = set_cloog_options ();
+
+ pprint (stderr, stmt, 0, options);
+}
+
+/* Find the right transform for the SCOP, and return a Cloog AST
+ representing the new form of the program. */
+
+static struct clast_stmt *
+find_transform (scop_p scop)
+{
+ CloogProgram *prog;
+ struct clast_stmt *stmt;
+ CloogOptions *options = set_cloog_options ();
+
+ /* Connect new cloog prog generation to graphite. */
+ build_cloog_prog (scop);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Cloog Input [\n");
+ cloog_program_print (dump_file, SCOP_PROG(scop));
+ fprintf (dump_file, "]\n");
+ }
+
+ prog = cloog_program_generate (SCOP_PROG (scop), options);
+ stmt = cloog_clast_create (prog, options);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Cloog Output[\n");
+ pprint (dump_file, stmt, 0, options);
+ cloog_program_dump_cloog (dump_file, prog);
+ fprintf (dump_file, "]\n");
+ }
+
+ cloog_options_free (options);
+ return stmt;
+}
+
+/* Return a vector of all the virtual phi nodes in the current
+ function. */
+
+static VEC (gimple, heap) *
+collect_virtual_phis (void)
+{
+ gimple_stmt_iterator si;
+ gimple_vec phis = VEC_alloc (gimple, heap, 3);
+ basic_block bb;
+
+ FOR_EACH_BB (bb)
+ for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
+ /* The phis we moved will have 0 arguments because the
+ original edges were removed. */
+ if (gimple_phi_num_args (gsi_stmt (si)) == 0)
+ VEC_safe_push (gimple, heap, phis, gsi_stmt (si));
+
+ /* Deallocate if we did not find any. */
+ if (VEC_length (gimple, phis) == 0)
+ {
+ VEC_free (gimple, heap, phis);
+ phis = NULL;
+ }
+
+ return phis;
+}
+
+/* Find a virtual definition for variable VAR in BB. */
+
+static tree
+find_vdef_for_var_in_bb (basic_block bb, tree var)
+{
+ gimple_stmt_iterator gsi;
+ gimple phi;
+ def_operand_p def_var;
+ vuse_vec_p vv;
+ ssa_op_iter op_iter;
+
+ for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
+ FOR_EACH_SSA_VDEF_OPERAND (def_var, vv, gsi_stmt (gsi), op_iter)
+ if (SSA_NAME_VAR (*def_var) == var)
+ return *def_var;
+
+ for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
+ FOR_EACH_SSA_DEF_OPERAND (def_var, gsi_stmt (gsi), op_iter, SSA_OP_DEF)
+ if (SSA_NAME_VAR (*def_var) == var)
+ return *def_var;
+
+ for (gsi = gsi_start_phis (bb); !gsi_end_p(gsi); gsi_next (&gsi))
+ {
+ phi = gsi_stmt (gsi);
+ if (SSA_NAME_VAR (PHI_RESULT (phi)) == var)
+ return PHI_RESULT (phi);
+ }
+
+ return NULL;
+}
+
+/* Recursive helper. */
+
+static tree
+find_vdef_for_var_1 (basic_block bb, struct pointer_set_t *visited, tree var)
+{
+ tree result = NULL;
+ edge_iterator ei;
+ edge pred_edge;
+
+ if (pointer_set_contains (visited, bb))
+ return NULL;
+
+ pointer_set_insert (visited, bb);
+ result = find_vdef_for_var_in_bb (bb, var);
+
+ if (!result)
+ FOR_EACH_EDGE (pred_edge, ei, bb->preds)
+ if (!result)
+ result = find_vdef_for_var_1 (pred_edge->src, visited, var);
+
+ return result;
+}
+
+/* Finds a virtual definition for variable VAR. */
+
+static tree
+find_vdef_for_var (basic_block bb, tree var)
+{
+ struct pointer_set_t *visited = pointer_set_create ();
+ tree def = find_vdef_for_var_1 (bb, visited, var);
+
+ pointer_set_destroy (visited);
+ return def;
+}
+
+/* Update the virtual phis after loop bodies are moved to new
+ loops. */
+
+static void
+patch_phis_for_virtual_defs (void)
+{
+ int i;
+ gimple phi;
+ VEC (gimple, heap) *virtual_phis = collect_virtual_phis ();
+
+ for (i = 0; VEC_iterate (gimple, virtual_phis, i, phi); i++)
+ {
+ basic_block bb = gimple_bb (phi);
+ edge_iterator ei;
+ edge pred_edge;
+ gimple_stmt_iterator gsi;
+ gimple new_phi;
+ tree phi_result = PHI_RESULT (phi);
+ tree var = SSA_NAME_VAR (phi_result);
+
+ new_phi = create_phi_node (phi_result, bb);
+ SSA_NAME_DEF_STMT (phi_result) = new_phi;
+
+ FOR_EACH_EDGE (pred_edge, ei, bb->preds)
+ {
+ tree def = find_vdef_for_var (pred_edge->src, var);
+
+ if (def)
+ add_phi_arg (new_phi, def, pred_edge);
+ else
+ add_phi_arg (new_phi, gimple_default_def (cfun, var), pred_edge);
+ }
+
+ gsi = gsi_for_stmt (phi);
+ remove_phi_node (&gsi, false);
+ }
+}
+
+/* Mark the original loops of SCOP for removal, replacing their header
+ field with NULL. */
+
+static void
+mark_old_loops (scop_p scop)
+{
+ int i;
+ struct loop *loop;
+
+ for (i = 0; VEC_iterate (loop_p, SCOP_LOOP_NEST (scop), i, loop); i++)
+ {
+ loop->header = NULL;
+ loop->latch = NULL;
+ }
+}
+
+/* Scan the loops and remove the ones that have been marked for
+ removal. */
+
+static void
+remove_dead_loops (void)
+{
+ struct loop *loop, *ploop;
+ loop_iterator li;
+
+ FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST)
+ {
+ /* Remove only those loops that we marked to be removed with
+ mark_old_loops. */
+ if (loop->header)
+ continue;
+
+ while (loop->inner)
+ {
+ ploop = loop->inner;
+ flow_loop_tree_node_remove (ploop);
+ flow_loop_tree_node_add (loop_outer (loop), ploop);
+ }
+
+ /* Remove the loop and free its data. */
+ delete_loop (loop);
+ }
+}
+
+/* Returns true when it is possible to generate code for this STMT.
+ For the moment we cannot generate code when Cloog decides to
+ duplicate a statement, as we do not do a copy, but a move.
+ USED_BASIC_BLOCKS records the blocks that have already been seen.
+ We return false if we have to generate code twice for the same
+ block. */
+
+static bool
+can_generate_code_stmt (struct clast_stmt *stmt,
+ struct pointer_set_t *used_basic_blocks)
+{
+ if (!stmt)
+ return true;
+
+ if (CLAST_STMT_IS_A (stmt, stmt_root))
+ return can_generate_code_stmt (stmt->next, used_basic_blocks);
+
+ if (CLAST_STMT_IS_A (stmt, stmt_user))
+ {
+ CloogStatement *cs = ((struct clast_user_stmt *) stmt)->statement;
+ graphite_bb_p gbb = (graphite_bb_p) cloog_statement_usr (cs);
+
+ if (pointer_set_contains (used_basic_blocks, gbb))
+ return false;
+ pointer_set_insert (used_basic_blocks, gbb);
+ return can_generate_code_stmt (stmt->next, used_basic_blocks);
+ }
+
+ if (CLAST_STMT_IS_A (stmt, stmt_for))
+ return can_generate_code_stmt (((struct clast_for *) stmt)->body,
+ used_basic_blocks)
+ && can_generate_code_stmt (stmt->next, used_basic_blocks);
+
+ if (CLAST_STMT_IS_A (stmt, stmt_guard))
+ return can_generate_code_stmt (((struct clast_guard *) stmt)->then,
+ used_basic_blocks);
+
+ if (CLAST_STMT_IS_A (stmt, stmt_block))
+ return can_generate_code_stmt (((struct clast_block *) stmt)->body,
+ used_basic_blocks)
+ && can_generate_code_stmt (stmt->next, used_basic_blocks);
+
+ return false;
+}
+
+/* Returns true when it is possible to generate code for this STMT. */
+
+static bool
+can_generate_code (struct clast_stmt *stmt)
+{
+ bool result;
+ struct pointer_set_t *used_basic_blocks = pointer_set_create ();
+
+ result = can_generate_code_stmt (stmt, used_basic_blocks);
+ pointer_set_destroy (used_basic_blocks);
+ return result;
+}
+
+/* Skip any definition that is a phi node with a single phi def. */
+
+static tree
+skip_phi_defs (tree ssa_name)
+{
+ tree result = ssa_name;
+ gimple def_stmt = SSA_NAME_DEF_STMT (ssa_name);
+
+ if (gimple_code (def_stmt) == GIMPLE_PHI
+ && gimple_phi_num_args (def_stmt) == 1)
+ result = skip_phi_defs (gimple_phi_arg(def_stmt,0)->def);
+
+ return result;
+}
+
+/* Returns a VEC containing the phi-arg defs coming from SCOP_EXIT in
+ the destination block of SCOP_EXIT. */
+
+static VEC (tree, heap) *
+collect_scop_exit_phi_args (edge scop_exit)
+{
+ VEC (tree, heap) *phi_args = VEC_alloc (tree, heap, 1);
+ gimple_stmt_iterator gsi;
+
+ for (gsi = gsi_start_phis (scop_exit->dest); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple phi = gsi_stmt (gsi);
+ tree phi_arg = skip_phi_defs(PHI_ARG_DEF_FROM_EDGE (phi, scop_exit));
+
+ VEC_safe_push (tree, heap, phi_args, phi_arg);
+ }
+
+ return phi_args;
+}
+
+/* Patches (adds) PHI_ARGS to the phi nodes in SCOP_EXIT destination. */
+
+static void
+patch_scop_exit_phi_args (edge scop_exit,
+ VEC (tree, heap) *phi_args)
+{
+ int i = 0;
+ gimple_stmt_iterator gsi;
+
+ for (gsi = gsi_start_phis (scop_exit->dest); !gsi_end_p (gsi);
+ gsi_next (&gsi), i++)
+ {
+ tree def = VEC_index (tree, phi_args, i);
+ gimple phi = gsi_stmt (gsi);
+
+ gcc_assert (PHI_ARG_DEF_FROM_EDGE (phi, scop_exit) == NULL);
+
+ add_phi_arg (phi, def, scop_exit);
+ }
+}
+
+/* GIMPLE Loop Generator: generates loops from STMT in GIMPLE form for
+ the given SCOP. */
+
+static void
+gloog (scop_p scop, struct clast_stmt *stmt)
+{
+ edge new_scop_exit_edge = NULL;
+ basic_block scop_exit = SCOP_EXIT (scop);
+ VEC (tree, heap)* phi_args =
+ collect_scop_exit_phi_args (SESE_EXIT (SCOP_REGION (scop)));
+ VEC (name_tree, heap) *ivstack = VEC_alloc (name_tree, heap, 10);
+ edge construction_edge = SESE_ENTRY (SCOP_REGION (scop));
+ basic_block old_scop_exit_idom = get_immediate_dominator (CDI_DOMINATORS,
+ scop_exit);
+
+ if (!can_generate_code (stmt))
+ {
+ cloog_clast_free (stmt);
+ return;
+ }
+
+ new_scop_exit_edge = translate_clast (scop,
+ construction_edge->src->loop_father,
+ stmt, construction_edge, &ivstack);
+ redirect_edge_succ (new_scop_exit_edge, scop_exit);
+ if (!old_scop_exit_idom
+ || !dominated_by_p (CDI_DOMINATORS, SCOP_ENTRY (scop),
+ old_scop_exit_idom)
+ || SCOP_ENTRY (scop) == old_scop_exit_idom)
+ set_immediate_dominator (CDI_DOMINATORS,
+ new_scop_exit_edge->dest,
+ new_scop_exit_edge->src);
+
+ cloog_clast_free (stmt);
+
+ if (new_scop_exit_edge->dest == EXIT_BLOCK_PTR)
+ new_scop_exit_edge->flags = 0;
+
+ find_unreachable_blocks ();
+ delete_unreachable_blocks ();
+ patch_phis_for_virtual_defs ();
+ patch_scop_exit_phi_args (new_scop_exit_edge, phi_args);
+ mark_old_loops (scop);
+ remove_dead_loops ();
+ rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
+
+#ifdef ENABLE_CHECKING
+ verify_loop_structure ();
+ verify_dominators (CDI_DOMINATORS);
+ verify_ssa (false);
+#endif
+}
+
+/* Returns the number of data references in SCOP. */
+
+static int
+nb_data_refs_in_scop (scop_p scop)
+{
+ int i;
+ graphite_bb_p gbb;
+ int res = 0;
+
+ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gbb); i++)
+ res += VEC_length (data_reference_p, GBB_DATA_REFS (gbb));
+
+ return res;
+}
+
+/* Check if a graphite bb can be ignored in graphite. We ignore all
+ bbs, that only contain code, that will be eliminated later.
+
+ TODO: - Move PHI nodes and scalar variables out of these bbs, that only
+ remain conditions and induction variables. */
+
+static bool
+gbb_can_be_ignored (graphite_bb_p gb)
+{
+ gimple_stmt_iterator gsi;
+ scop_p scop = GBB_SCOP (gb);
+ loop_p loop = GBB_BB (gb)->loop_father;
+
+ if (VEC_length (data_reference_p, GBB_DATA_REFS(gb)))
+ return false;
+
+ /* Check statements. */
+ for (gsi = gsi_start_bb (GBB_BB (gb)); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple stmt = gsi_stmt (gsi);
+ switch (gimple_code (stmt))
+ {
+ /* Control flow expressions can be ignored, as they are
+ represented in the iteration domains and will be
+ regenerated by graphite. */
+ case GIMPLE_COND:
+ case GIMPLE_GOTO:
+ case GIMPLE_SWITCH:
+ break;
+
+ /* Scalar variables can be ignored, if we can regenerate
+ them later using their scalar evolution function.
+ XXX: Just a heuristic, that needs further investigation. */
+ case GIMPLE_ASSIGN:
+ {
+ tree var = gimple_assign_lhs (stmt);
+ var = analyze_scalar_evolution (loop, var);
+ var = instantiate_scev (outermost_loop_in_scop (scop,
+ GBB_BB (gb)),
+ loop, var);
+ if (TREE_CODE (var) == SCEV_NOT_KNOWN)
+ return false;
+ break;
+ }
+ /* Otherwise not ignoreable. */
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Remove all ignoreable gbbs from SCOP. */
+
+static void
+scop_remove_ignoreable_gbbs (scop_p scop)
+{
+ graphite_bb_p gb;
+ int i;
+
+ int max_schedule = scop_max_loop_depth (scop) + 1;
+ lambda_vector last_schedule = lambda_vector_new (max_schedule);
+ lambda_vector_clear (last_schedule, max_schedule);
+
+ /* Update schedules. */
+ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++)
+ {
+ int nb_loops = gbb_nb_loops (gb);
+
+ if (GBB_STATIC_SCHEDULE (gb) [nb_loops] == 0)
+ last_schedule [nb_loops] = 0;
+
+ if (gbb_can_be_ignored (gb))
+ {
+ /* Mark gbb for remove. */
+ bitmap_clear_bit (SCOP_BBS_B (scop), gb->bb->index);
+ GBB_SCOP (gb) = NULL;
+ last_schedule [nb_loops]--;
+ }
+ else
+ lambda_vector_add (GBB_STATIC_SCHEDULE (gb), last_schedule,
+ GBB_STATIC_SCHEDULE (gb), nb_loops + 1);
+ }
+
+ /* Remove gbbs. */
+ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++)
+ if (GBB_SCOP (gb) == NULL)
+ {
+ VEC_unordered_remove (graphite_bb_p, SCOP_BBS (scop), i);
+ free_graphite_bb (gb);
+ /* XXX: Hackish? But working. */
+ i--;
+ }
+
+ graphite_sort_gbbs (scop);
+}
+
+/* Move the loop at index LOOP and insert it before index NEW_LOOP_POS.
+ This transformartion is only valid, if the loop nest between i and k is
+ perfectly nested. Therefore we do not need to change the static schedule.
+
+ Example:
+
+ for (i = 0; i < 50; i++)
+ for (j ...)
+ for (k = 5; k < 100; k++)
+ A
+
+ To move k before i use:
+
+ graphite_trans_bb_move_loop (A, 2, 0)
+
+ for (k = 5; k < 100; k++)
+ for (i = 0; i < 50; i++)
+ for (j ...)
+ A
+
+ And to move k back:
+
+ graphite_trans_bb_move_loop (A, 0, 2)
+
+ This function does not check the validity of interchanging loops.
+ This should be checked before calling this function. */
+
+static void
+graphite_trans_bb_move_loop (graphite_bb_p gb, int loop,
+ int new_loop_pos)
+{
+ CloogMatrix *domain = GBB_DOMAIN (gb);
+ int row, j;
+ loop_p tmp_loop_p;
+
+ gcc_assert (loop < gbb_nb_loops (gb)
+ && new_loop_pos < gbb_nb_loops (gb));
+
+ /* Update LOOPS vector. */
+ tmp_loop_p = VEC_index (loop_p, GBB_LOOPS (gb), loop);
+ VEC_ordered_remove (loop_p, GBB_LOOPS (gb), loop);
+ VEC_safe_insert (loop_p, heap, GBB_LOOPS (gb), new_loop_pos, tmp_loop_p);
+
+ /* Move the domain columns. */
+ if (loop < new_loop_pos)
+ for (row = 0; row < domain->NbRows; row++)
+ {
+ Value tmp;
+ value_init (tmp);
+ value_assign (tmp, domain->p[row][loop + 1]);
+
+ for (j = loop ; j < new_loop_pos - 1; j++)
+ value_assign (domain->p[row][j + 1], domain->p[row][j + 2]);
+
+ value_assign (domain->p[row][new_loop_pos], tmp);
+ value_clear (tmp);
+ }
+ else
+ for (row = 0; row < domain->NbRows; row++)
+ {
+ Value tmp;
+ value_init (tmp);
+ value_assign (tmp, domain->p[row][loop + 1]);
+
+ for (j = loop ; j > new_loop_pos; j--)
+ value_assign (domain->p[row][j + 1], domain->p[row][j]);
+
+ value_assign (domain->p[row][new_loop_pos + 1], tmp);
+ value_clear (tmp);
+ }
+}
+
+/* Get the index of the column representing constants in the DOMAIN
+ matrix. */
+
+static int
+const_column_index (CloogMatrix *domain)
+{
+ return domain->NbColumns - 1;
+}
+
+
+/* Get the first index that is positive or negative, determined
+ following the value of POSITIVE, in matrix DOMAIN in COLUMN. */
+
+static int
+get_first_matching_sign_row_index (CloogMatrix *domain, int column,
+ bool positive)
+{
+ int row;
+
+ for (row = 0; row < domain->NbRows; row++)
+ {
+ int val = value_get_si (domain->p[row][column]);
+
+ if (val > 0 && positive)
+ return row;
+
+ else if (val < 0 && !positive)
+ return row;
+ }
+
+ gcc_unreachable ();
+}
+
+/* Get the lower bound of COLUMN in matrix DOMAIN. */
+
+static int
+get_lower_bound_row (CloogMatrix *domain, int column)
+{
+ return get_first_matching_sign_row_index (domain, column, true);
+}
+
+/* Get the upper bound of COLUMN in matrix DOMAIN. */
+
+static int
+get_upper_bound_row (CloogMatrix *domain, int column)
+{
+ return get_first_matching_sign_row_index (domain, column, false);
+}
+
+/* Get the lower bound of LOOP. */
+
+static void
+get_lower_bound (CloogMatrix *domain, int loop, Value lower_bound_result)
+{
+ int lower_bound_row = get_lower_bound_row (domain, loop);
+ value_init (lower_bound_result);
+ value_assign (lower_bound_result,
+ domain->p[lower_bound_row][const_column_index(domain)]);
+}
+
+/* Get the upper bound of LOOP. */
+
+static void
+get_upper_bound (CloogMatrix *domain, int loop, Value upper_bound_result)
+{
+ int upper_bound_row = get_upper_bound_row (domain, loop);
+ value_init (upper_bound_result);
+ value_assign (upper_bound_result,
+ domain->p[upper_bound_row][const_column_index(domain)]);
+}
+
+/* Strip mines the loop of BB at the position LOOP_DEPTH with STRIDE.
+ Always valid, but not always a performance improvement. */
+
+static void
+graphite_trans_bb_strip_mine (graphite_bb_p gb, int loop_depth, int stride)
+{
+ int row, col;
+
+ CloogMatrix *domain = GBB_DOMAIN (gb);
+ CloogMatrix *new_domain = cloog_matrix_alloc (domain->NbRows + 3,
+ domain->NbColumns + 1);
+
+ int col_loop_old = loop_depth + 2;
+ int col_loop_strip = col_loop_old - 1;
+
+ Value old_lower_bound;
+ Value old_upper_bound;
+
+
+ gcc_assert (loop_depth <= gbb_nb_loops (gb) - 1);
+
+ VEC_safe_insert (loop_p, heap, GBB_LOOPS (gb), loop_depth, NULL);
+
+ GBB_DOMAIN (gb) = new_domain;
+
+ /*
+ nrows = 4, ncols = 4
+ eq i j c
+ 1 1 0 0
+ 1 -1 0 99
+ 1 0 1 0
+ 1 0 -1 99
+ */
+
+ /* Move domain. */
+ for (row = 0; row < domain->NbRows; row++)
+ for (col = 0; col < domain->NbColumns; col++)
+ if (col <= loop_depth)
+ {
+ value_assign (new_domain->p[row][col], domain->p[row][col]);
+ }
+ else
+ {
+ value_assign (new_domain->p[row][col + 1], domain->p[row][col]);
+ }
+
+
+ /*
+ nrows = 6, ncols = 5
+ outer inner
+ eq i jj j c
+ 1 1 0 0 0
+ 1 -1 0 0 99
+ 1 0 0 1 0
+ 1 0 0 -1 99
+ 0 0 0 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+ */
+
+ row = domain->NbRows;
+
+ /* Add outer loop. */
+
+ get_lower_bound (new_domain, col_loop_old, old_lower_bound);
+ get_upper_bound (new_domain, col_loop_old, old_upper_bound);
+
+ /* Set Lower Bound */
+ value_set_si (new_domain->p[row][0], 1);
+ value_set_si (new_domain->p[row][col_loop_strip], 1);
+ value_assign (new_domain->p[row][const_column_index (new_domain)],
+ old_lower_bound);
+ row++;
+
+
+ /*
+ 6 5
+ eq i jj j c
+ 1 1 0 0 0
+ 1 -1 0 0 99
+ 1 0 0 1 0 -
+ 1 0 0 -1 99 | copy old lower bound
+ 1 0 1 0 0 <-
+ 0 0 0 0 0
+ 0 0 0 0 0
+ */
+
+ {
+ Value new_upper_bound;
+ Value strip_size_value;
+
+ value_init (new_upper_bound);
+
+ value_init (strip_size_value);
+ value_set_si (strip_size_value, (int) stride);
+
+
+ value_pdivision(new_upper_bound,old_upper_bound,strip_size_value);
+ value_add_int (new_upper_bound, new_upper_bound, 1);
+
+ /* Set Upper Bound */
+ value_set_si (new_domain->p[row][0], 1);
+ value_set_si (new_domain->p[row][col_loop_strip], -1);
+ value_assign (new_domain->p[row][const_column_index (new_domain)],
+ new_upper_bound);
+ row++;
+ }
+ /*
+ 6 5
+ eq i jj j c
+ 1 1 0 0 0
+ 1 -1 0 0 99
+ 1 0 0 1 0
+ 1 0 0 -1 99
+ 1 0 1 0 0
+ 1 0 -1 0 25 (divide old upper bound with stride)
+ 0 0 0 0 0
+ */
+
+ {
+ row = get_lower_bound_row (new_domain, col_loop_old);
+ /* Add local variable to keep linear representation. */
+ value_set_si (new_domain->p[row][0], 1);
+ value_set_si (new_domain->p[row][const_column_index (new_domain)],0);
+ value_set_si (new_domain->p[row][col_loop_old], 1);
+ value_set_si (new_domain->p[row][col_loop_strip], -1*((int)stride));
+ }
+
+ /*
+ 6 5
+ eq i jj j c
+ 1 1 0 0 0
+ 1 -1 0 0 99
+ 1 0 -1 1 0
+ 1 0 0 -1 99
+ 1 0 1 0 0
+ 1 0 -1 0 25 (divide old upper bound with stride)
+ 0 0 0 0 0
+ */
+
+ {
+ row = new_domain->NbRows-1;
+
+ value_set_si (new_domain->p[row][0], 1);
+ value_set_si (new_domain->p[row][col_loop_old], -1);
+ value_set_si (new_domain->p[row][col_loop_strip], stride);
+ value_set_si (new_domain->p[row][const_column_index (new_domain)],
+ stride-1);
+ }
+
+ /*
+ 6 5
+ eq i jj j c
+ 1 1 0 0 0 i >= 0
+ 1 -1 0 0 99 99 >= i
+ 1 0 -4 1 0 j >= 4*jj
+ 1 0 0 -1 99 99 >= j
+ 1 0 1 0 0 jj >= 0
+ 1 0 -1 0 25 25 >= jj
+ 0 0 4 -1 3 jj+3 >= j
+ */
+
+ cloog_matrix_free (domain);
+
+ /* Update static schedule. */
+ {
+ int i;
+ int nb_loops = gbb_nb_loops (gb);
+ lambda_vector new_schedule = lambda_vector_new (nb_loops + 1);
+
+ for (i = 0; i <= loop_depth; i++)
+ new_schedule[i] = GBB_STATIC_SCHEDULE (gb)[i];
+
+ for (i = loop_depth + 1; i <= nb_loops - 2; i++)
+ new_schedule[i + 2] = GBB_STATIC_SCHEDULE (gb)[i];
+
+ GBB_STATIC_SCHEDULE (gb) = new_schedule;
+ }
+}
+
+/* Returns true when the strip mining of LOOP_INDEX by STRIDE is
+ profitable or undecidable. GB is the statement around which the
+ loops will be strip mined. */
+
+static bool
+strip_mine_profitable_p (graphite_bb_p gb, int stride,
+ int loop_index)
+{
+ bool res = true;
+ edge exit = NULL;
+ tree niter;
+ loop_p loop;
+ long niter_val;
+
+ loop = VEC_index (loop_p, GBB_LOOPS (gb), loop_index);
+ exit = single_exit (loop);
+
+ niter = find_loop_niter (loop, &exit);
+ if (niter == chrec_dont_know
+ || TREE_CODE (niter) != INTEGER_CST)
+ return true;
+
+ niter_val = int_cst_value (niter);
+
+ if (niter_val < stride)
+ {
+ res = false;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nStrip Mining is not profitable for loop %d:",
+ loop_index);
+ fprintf (dump_file, "number of iterations is too low.\n");
+ }
+ }
+
+ return res;
+}
+
+/* Determines when the interchange of LOOP_A and LOOP_B belonging to
+ SCOP is legal. */
+
+static bool
+is_interchange_valid (scop_p scop, int loop_a, int loop_b)
+{
+ bool res;
+ VEC (ddr_p, heap) *dependence_relations;
+ VEC (data_reference_p, heap) *datarefs;
+
+ struct loop *nest = VEC_index (loop_p, SCOP_LOOP_NEST (scop), loop_a);
+ int depth = perfect_loop_nest_depth (nest);
+ lambda_trans_matrix trans;
+
+ gcc_assert (loop_a < loop_b);
+
+ dependence_relations = VEC_alloc (ddr_p, heap, 10 * 10);
+ datarefs = VEC_alloc (data_reference_p, heap, 10);
+
+ if (!compute_data_dependences_for_loop (nest, true, &datarefs,
+ &dependence_relations))
+ return false;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ dump_ddrs (dump_file, dependence_relations);
+
+ trans = lambda_trans_matrix_new (depth, depth);
+ lambda_matrix_id (LTM_MATRIX (trans), depth);
+
+ lambda_matrix_row_exchange (LTM_MATRIX (trans), 0, loop_b - loop_a);
+
+ if (!lambda_transform_legal_p (trans, depth, dependence_relations))
+ {
+ lambda_matrix_row_exchange (LTM_MATRIX (trans), 0, loop_b - loop_a);
+ res = false;
+ }
+ else
+ res = true;
+
+ free_dependence_relations (dependence_relations);
+ free_data_refs (datarefs);
+ return res;
+}
+
+/* Loop block the LOOPS innermost loops of GB with stride size STRIDE.
+
+ Example
+
+ for (i = 0; i <= 50; i++=4)
+ for (k = 0; k <= 100; k++=4)
+ for (l = 0; l <= 200; l++=4)
+ A
+
+ To strip mine the two inner most loops with stride = 4 call:
+
+ graphite_trans_bb_block (A, 4, 2)
+
+ for (i = 0; i <= 50; i++)
+ for (kk = 0; kk <= 100; kk+=4)
+ for (ll = 0; ll <= 200; ll+=4)
+ for (k = kk; k <= min (100, kk + 3); k++)
+ for (l = ll; l <= min (200, ll + 3); l++)
+ A
+*/
+
+static bool
+graphite_trans_bb_block (graphite_bb_p gb, int stride, int loops)
+{
+ int i, j;
+ int nb_loops = gbb_nb_loops (gb);
+ int start = nb_loops - loops;
+ scop_p scop = GBB_SCOP (gb);
+
+ gcc_assert (scop_contains_loop (scop, gbb_loop (gb)));
+
+ for (i = start ; i < nb_loops; i++)
+ for (j = i + 1; j < nb_loops; j++)
+ if (!is_interchange_valid (scop, i, j))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file,
+ "\nInterchange not valid for loops %d and %d:\n", i, j);
+ return false;
+ }
+ else if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file,
+ "\nInterchange valid for loops %d and %d:\n", i, j);
+
+ /* Check if strip mining is profitable for every loop. */
+ for (i = 0; i < nb_loops - start; i++)
+ if (!strip_mine_profitable_p (gb, stride, start + i))
+ return false;
+
+ /* Strip mine loops. */
+ for (i = 0; i < nb_loops - start; i++)
+ graphite_trans_bb_strip_mine (gb, start + 2 * i, stride);
+
+ /* Interchange loops. */
+ for (i = 1; i < nb_loops - start; i++)
+ graphite_trans_bb_move_loop (gb, start + 2 * i, start + i);
+
+ return true;
+}
+
+/* Loop block LOOPS innermost loops of a loop nest. BBS represent the
+ basic blocks that belong to the loop nest to be blocked. */
+
+static bool
+graphite_trans_loop_block (VEC (graphite_bb_p, heap) *bbs, int loops)
+{
+ graphite_bb_p gb;
+ int i;
+ bool transform_done = false;
+
+ /* TODO: - Calculate the stride size automatically. */
+ int stride_size = 64;
+
+ for (i = 0; VEC_iterate (graphite_bb_p, bbs, i, gb); i++)
+ transform_done |= graphite_trans_bb_block (gb, stride_size, loops);
+
+ return transform_done;
+}
+
+/* Loop block all basic blocks of SCOP. */
+
+static bool
+graphite_trans_scop_block (scop_p scop)
+{
+ graphite_bb_p gb;
+ int i, j;
+ int last_nb_loops;
+ int nb_loops;
+ bool perfect = true;
+ bool transform_done = false;
+
+ VEC (graphite_bb_p, heap) *bbs = VEC_alloc (graphite_bb_p, heap, 3);
+ int max_schedule = scop_max_loop_depth (scop) + 1;
+ lambda_vector last_schedule = lambda_vector_new (max_schedule);
+
+ if (VEC_length (graphite_bb_p, SCOP_BBS (scop)) == 0)
+ return transform_done;
+
+ /* Get the data of the first bb. */
+ gb = VEC_index (graphite_bb_p, SCOP_BBS (scop), 0);
+ last_nb_loops = gbb_nb_loops (gb);
+ lambda_vector_copy (GBB_STATIC_SCHEDULE (gb), last_schedule,
+ last_nb_loops + 1);
+ VEC_safe_push (graphite_bb_p, heap, bbs, gb);
+
+ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++)
+ {
+ /* We did the first bb before. */
+ if (i == 0)
+ continue;
+
+ nb_loops = gbb_nb_loops (gb);
+
+ /* If the number of loops is unchanged and only the last element of the
+ schedule changes, we stay in the loop nest. */
+ if (nb_loops == last_nb_loops
+ && (last_schedule [nb_loops + 1]
+ != GBB_STATIC_SCHEDULE (gb)[nb_loops + 1]))
+ {
+ VEC_safe_push (graphite_bb_p, heap, bbs, gb);
+ continue;
+ }
+
+ /* Otherwise, we left the innermost loop. So check, if the last bb was in
+ a perfect loop nest and how many loops are contained in this perfect
+ loop nest.
+
+ Count the number of zeros from the end of the schedule. They are the
+ number of surrounding loops.
+
+ Example:
+ last_bb 2 3 2 0 0 0 0 3
+ bb 2 4 0
+ <------ j = 4
+
+ last_bb 2 3 2 0 0 0 0 3
+ bb 2 3 2 0 1
+ <-- j = 2
+
+ If there is no zero, there were other bbs in outer loops and the loop
+ nest is not perfect. */
+ for (j = last_nb_loops - 1; j >= 0; j--)
+ {
+ if (last_schedule [j] != 0
+ || (j <= nb_loops && GBB_STATIC_SCHEDULE (gb)[j] == 1))
+ {
+ j--;
+ break;
+ }
+ }
+
+ j++;
+
+ /* Found perfect loop nest. */
+ if (perfect && last_nb_loops - j > 0)
+ transform_done |= graphite_trans_loop_block (bbs, last_nb_loops - j);
+
+ /* Check if we start with a new loop.
+
+ Example:
+
+ last_bb 2 3 2 0 0 0 0 3
+ bb 2 3 2 0 0 1 0
+
+ Here we start with the loop "2 3 2 0 0 1"
+
+ last_bb 2 3 2 0 0 0 0 3
+ bb 2 3 2 0 0 1
+
+ But here not, so the loop nest can never be perfect. */
+
+ perfect = (GBB_STATIC_SCHEDULE (gb)[nb_loops] == 0);
+
+ /* Update the last_bb infos. We do not do that for the bbs in the same
+ loop, as the data we use is not changed. */
+ last_nb_loops = nb_loops;
+ lambda_vector_copy (GBB_STATIC_SCHEDULE (gb), last_schedule,
+ nb_loops + 1);
+ VEC_truncate (graphite_bb_p, bbs, 0);
+ VEC_safe_push (graphite_bb_p, heap, bbs, gb);
+ }
+
+ /* Check if the last loop nest was perfect. It is the same check as above,
+ but the comparison with the next bb is missing. */
+ for (j = last_nb_loops - 1; j >= 0; j--)
+ if (last_schedule [j] != 0)
+ {
+ j--;
+ break;
+ }
+
+ j++;
+
+ /* Found perfect loop nest. */
+ if (last_nb_loops - j > 0)
+ transform_done |= graphite_trans_loop_block (bbs, last_nb_loops - j);
+ VEC_free (graphite_bb_p, heap, bbs);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\nLoop blocked.\n");
+
+ return transform_done;
+}
+
+/* Apply graphite transformations to all the basic blocks of SCOP. */
+
+static bool
+graphite_apply_transformations (scop_p scop)
+{
+ bool transform_done = false;
+
+ /* Sort the list of bbs. Keep them always sorted. */
+ graphite_sort_gbbs (scop);
+ scop_remove_ignoreable_gbbs (scop);
+
+ if (flag_loop_block)
+ transform_done = graphite_trans_scop_block (scop);
+
+#if 0 && ENABLE_CHECKING
+ /* When the compiler is configured with ENABLE_CHECKING, always
+ generate code, even if we did not apply any transformation. This
+ provides better code coverage of the backend code generator.
+
+ This also allows to check the performance for an identity
+ transform: GIMPLE -> GRAPHITE -> GIMPLE; and the output of CLooG
+ is never an identity: if CLooG optimizations are not disabled,
+ the CLooG output is always optimized in control flow. */
+ transform_done = true;
+#endif
+
+ return transform_done;
+}
+
+/* We limit all SCoPs to SCoPs, that are completely surrounded by a loop.
+
+ Example:
+
+ for (i |
+ { |
+ for (j | SCoP 1
+ for (k |
+ } |
+
+ * SCoP frontier, as this line is not surrounded by any loop. *
+
+ for (l | SCoP 2
+
+ This is necessary as scalar evolution and parameter detection need a
+ outermost loop to initialize parameters correctly.
+
+ TODO: FIX scalar evolution and parameter detection to allow mor flexible
+ SCoP frontiers. */
+
+static void
+limit_scops (void)
+{
+ VEC (scop_p, heap) *new_scops = VEC_alloc (scop_p, heap, 3);
+ int i;
+ scop_p scop;
+
+ for (i = 0; VEC_iterate (scop_p, current_scops, i, scop); i++)
+ {
+ int j;
+ loop_p loop;
+ build_scop_bbs (scop);
+ build_scop_loop_nests (scop);
+
+ for (j = 0; VEC_iterate (loop_p, SCOP_LOOP_NEST (scop), j, loop); j++)
+ if (!loop_in_scop_p (loop_outer (loop), scop))
+ {
+ scop_p n_scop = new_scop (loop_preheader_edge (loop));
+ end_scop (n_scop, single_exit (loop), false);
+ VEC_safe_push (scop_p, heap, new_scops, n_scop);
+ }
+ }
+
+ free_scops (current_scops);
+ current_scops = new_scops;
+}
+
+/* Perform a set of linear transforms on the loops of the current
+ function. */
+
+void
+graphite_transform_loops (void)
+{
+ int i;
+ scop_p scop;
+
+ if (number_of_loops () <= 1)
+ return;
+
+ current_scops = VEC_alloc (scop_p, heap, 3);
+
+ calculate_dominance_info (CDI_DOMINATORS);
+ calculate_dominance_info (CDI_POST_DOMINATORS);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Graphite loop transformations \n");
+
+ cloog_initialize ();
+ build_scops ();
+ limit_scops ();
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\nnumber of SCoPs: %d\n",
+ VEC_length (scop_p, current_scops));
+
+ for (i = 0; VEC_iterate (scop_p, current_scops, i, scop); i++)
+ {
+ build_scop_bbs (scop);
+ build_scop_loop_nests (scop);
+ build_scop_canonical_schedules (scop);
+ build_bb_loops (scop);
+ find_scop_parameters (scop);
+ build_scop_context (scop);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\n(In SCoP %d:\n", i);
+ fprintf (dump_file, "\nnumber of bbs: %d\n",
+ VEC_length (graphite_bb_p, SCOP_BBS (scop)));
+ fprintf (dump_file, "\nnumber of loops: %d)\n",
+ VEC_length (loop_p, SCOP_LOOP_NEST (scop)));
+ }
+
+ if (!build_scop_iteration_domain (scop))
+ continue;
+
+ build_scop_conditions (scop);
+ build_scop_data_accesses (scop);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ int nbrefs = nb_data_refs_in_scop (scop);
+ fprintf (dump_file, "\nnumber of data refs: %d\n", nbrefs);
+ }
+
+ if (graphite_apply_transformations (scop))
+ gloog (scop, find_transform (scop));
+ }
+
+ /* Cleanup. */
+ free_scops (current_scops);
+ cloog_finalize ();
+}
+
+#else /* If Cloog is not available: #ifndef HAVE_cloog. */
+
+void
+graphite_transform_loops (void)
+{
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Graphite loop optimizations cannot be used.\n");
+ fprintf (dump_file, "GCC has not been configured with the required "
+ "libraries for Graphite loop optimizations.");
+ }
+ sorry ("Graphite loop optimizations cannot be used");
+}
+
+#endif
diff --git a/gcc/graphite.h b/gcc/graphite.h
new file mode 100644
index 00000000000..1a3cf6ccc65
--- /dev/null
+++ b/gcc/graphite.h
@@ -0,0 +1,516 @@
+/* Gimple Represented as Polyhedra.
+ Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
+ Contributed by Sebastian Pop <sebastian.pop@inria.fr>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "tree-data-ref.h"
+
+typedef struct graphite_bb *graphite_bb_p;
+DEF_VEC_P(graphite_bb_p);
+DEF_VEC_ALLOC_P (graphite_bb_p, heap);
+
+DEF_VEC_P(scop_p);
+DEF_VEC_ALLOC_P (scop_p, heap);
+
+static inline int scop_nb_loops (scop_p scop);
+static inline unsigned scop_nb_params (scop_p scop);
+static inline bool scop_contains_loop (scop_p scop, struct loop *loop);
+
+struct graphite_bb
+{
+ basic_block bb;
+ scop_p scop;
+
+ /* The static schedule contains the textual order for every loop layer.
+
+ Example:
+
+ S0
+ for (i ...)
+ {
+ S1
+ for (j ...)
+ {
+ S2
+ S3
+ }
+ S4
+ }
+ S5
+ for (k ...)
+ {
+ S6
+ S7
+ for (l ...)
+ {
+ S8
+ }
+ S9
+ }
+ S10
+
+ Schedules:
+
+ | Depth
+ BB | 0 1 2
+ ------------
+ S0 | 0
+ S1 | 1, 0
+ S2 | 1, 1, 0
+ S3 | 1, 1, 1
+ S4 | 1, 2
+ S5 | 2
+ S6 | 3, 0
+ S7 | 3, 1
+ S8 | 3, 2, 0
+ S9 | 3, 3
+ S10| 4
+
+ Normalization rules:
+ - One SCoP can never contain two bbs with the same schedule timestamp.
+ - All bbs at the same loop depth have a consecutive ordering (no gaps). */
+ lambda_vector static_schedule;
+
+ /* The iteration domain of this bb. It contains this columns:
+ - In/Eq: If this line is a equation or inequation.
+ - For every loop iterator one column.
+ - One column for every parameter in this SCoP.
+ - The constant column to add integers to the (in)equations.
+
+ Example:
+
+ for (i = a - 7*b + 8; i <= 3*a + 13*b + 20; i++)
+ for (j = 2; j <= 2*i + 5; j++)
+ for (k = 0; k <= 5; k++)
+ S (i,j,k)
+
+ Loop iterators: i, j, k
+ Parameters: a, b
+
+ (I)eq i j k a b 1
+
+ 1 1 0 0 -1 7 -8 # i >= a - 7b + 8
+ 1 -1 0 0 3 13 20 # i <= 3a + 13b + 20
+ 1 0 1 0 0 0 -2 # j >= 2
+ 1 2 -1 0 0 0 5 # j <= 2i + 5
+ 1 0 0 1 0 0 0 # k >= 0
+ 1 0 0 -1 0 0 5 # k <= 5
+
+ The number of loop iterators may change and is not connected to the
+ number of loops, that surrounded this bb in the gimple code. */
+ CloogMatrix *domain;
+
+ /* Lists containing the restrictions of the conditional statements
+ dominating this bb. This bb can only be executed, if all conditions
+ are true.
+
+ Example:
+
+ for (i = 0; i <= 20; i++)
+ {
+ A
+
+ if (2i <= 8)
+ B
+ }
+
+ So for B there is a additional condition (2i <= 8).
+
+ TODO: Add this restrictions to the domain matrix.
+
+ List of COND_EXPR and SWITCH_EXPR. A COND_EXPR is true only if the
+ corresponding element in CONDITION_CASES is not NULL_TREE. For a
+ SWITCH_EXPR the corresponding element in CONDITION_CASES is a
+ CASE_LABEL_EXPR. */
+ VEC (gimple, heap) *conditions;
+ VEC (gimple, heap) *condition_cases;
+
+ /* LOOPS contains for every column in the graphite domain the corresponding
+ gimple loop. If there exists no corresponding gimple loop LOOPS contains
+ NULL.
+
+ Example:
+
+ Original code:
+
+ for (i = 0; i <= 20; i++)
+ for (j = 5; j <= 10; j++)
+ A
+
+ Original domain:
+
+ (I)eq i j 1
+ 1 1 0 0 # i >= 0
+ 1 -1 0 20 # i <= 20
+ 1 0 1 0 # j >= 0
+ 1 0 -1 10 # j <= 10
+
+ Original loops vector:
+ 0 1
+ Loop i Loop j
+
+ After some changes (Exchange i and j, strip-mine i):
+
+ Domain:
+
+ (I)eq j ii i k 1
+ 1 0 0 1 0 0 # i >= 0
+ 1 0 0 -1 0 20 # i <= 20
+ 1 1 0 0 0 0 # j >= 0
+ 1 -1 0 0 0 10 # j <= 10
+ 1 0 -1 1 0 0 # ii <= i
+ 1 0 1 -1 0 1 # ii + 1 >= i
+ 1 0 -1 0 2 0 # ii <= 2k
+ 1 0 1 0 -2 0 # ii >= 2k
+
+ Iterator vector:
+ 0 1 2 3
+ Loop j NULL Loop i NULL
+
+ Means the original loop i is now at column two of the domain and
+ loop j in the original loop nest is now at column 0. Column 1 and
+ 3 are emtpy. */
+ VEC (loop_p, heap) *loops;
+
+ lambda_vector compressed_alpha_matrix;
+ CloogMatrix *dynamic_schedule;
+ VEC (data_reference_p, heap) *data_refs;
+};
+
+#define GBB_BB(GBB) GBB->bb
+#define GBB_SCOP(GBB) GBB->scop
+#define GBB_STATIC_SCHEDULE(GBB) GBB->static_schedule
+#define GBB_DATA_REFS(GBB) GBB->data_refs
+#define GBB_ALPHA(GBB) GBB->compressed_alpha_matrix
+#define GBB_DYNAMIC_SCHEDULE(GBB) GBB->dynamic_schedule
+#define GBB_DOMAIN(GBB) GBB->domain
+#define GBB_CONDITIONS(GBB) GBB->conditions
+#define GBB_CONDITION_CASES(GBB) GBB->condition_cases
+#define GBB_LOOPS(GBB) GBB->loops
+
+/* Return the loop that contains the basic block GBB. */
+
+static inline struct loop *
+gbb_loop (struct graphite_bb *gbb)
+{
+ return GBB_BB (gbb)->loop_father;
+}
+
+/* Calculate the number of loops around GB in the current SCOP. Only
+ works if GBB_DOMAIN is built. */
+
+static inline int
+gbb_nb_loops (const struct graphite_bb *gb)
+{
+ scop_p scop = GBB_SCOP (gb);
+
+ if (GBB_DOMAIN (gb) == NULL)
+ return 0;
+
+ return GBB_DOMAIN (gb)->NbColumns - scop_nb_params (scop) - 2;
+}
+
+/* Returns the gimple loop, that corresponds to the loop_iterator_INDEX.
+ If there is no corresponding gimple loop, we return NULL. */
+
+static inline loop_p
+gbb_loop_at_index (graphite_bb_p gb, int index)
+{
+ return VEC_index (loop_p, GBB_LOOPS (gb), index);
+}
+
+/* Returns the corresponding loop iterator index for a gimple loop. */
+
+static inline int
+gbb_loop_index (graphite_bb_p gb, loop_p loop)
+{
+ int i;
+ loop_p l;
+
+ for (i = 0; VEC_iterate (loop_p, GBB_LOOPS (gb), i, l); i++)
+ if (loop == l)
+ return i;
+
+ gcc_unreachable();
+}
+
+struct loop_to_cloog_loop_str
+{
+ unsigned int loop_num;
+ unsigned int loop_position; /* The column that represents this loop. */
+ CloogLoop *cloog_loop;
+};
+
+typedef struct name_tree
+{
+ tree t;
+ const char *name;
+ struct loop* loop;
+} *name_tree;
+
+DEF_VEC_P(name_tree);
+DEF_VEC_ALLOC_P (name_tree, heap);
+
+/* A Single Entry, Single Exit region is a part of the CFG delimited
+ by two edges. */
+typedef struct sese
+{
+ edge entry, exit;
+} *sese;
+
+#define SESE_ENTRY(S) (S->entry)
+#define SESE_EXIT(S) (S->exit)
+
+/* A SCOP is a Static Control Part of the program, simple enough to be
+ represented in polyhedral form. */
+struct scop
+{
+ /* A SCOP is defined as a SESE region. */
+ sese region;
+
+ /* All the basic blocks in this scop. They have extra information
+ attached to them, in the graphite_bb structure. */
+ VEC (graphite_bb_p, heap) *bbs;
+
+ /* Set for a basic block index when it belongs to this SCOP. */
+ bitmap bbs_b;
+
+ lambda_vector static_schedule;
+
+ /* Parameters used within the SCOP. */
+ VEC (name_tree, heap) *params;
+
+ /* A collection of old induction variables*/
+ VEC (name_tree, heap) *old_ivs;
+
+ /* Loops completely contained in the SCOP. */
+ bitmap loops;
+ VEC (loop_p, heap) *loop_nest;
+
+ /* ??? It looks like a global mapping loop_id -> cloog_loop would work. */
+ htab_t loop2cloog_loop;
+
+ /* CLooG representation of this SCOP. */
+ CloogProgram *program;
+};
+
+#define SCOP_BBS(S) S->bbs
+#define SCOP_BBS_B(S) S->bbs_b
+#define SCOP_REGION(S) S->region
+/* SCOP_ENTRY bb dominates all the bbs of the scop. SCOP_EXIT bb
+ post-dominates all the bbs of the scop. SCOP_EXIT potentially
+ contains non affine data accesses, side effect statements or
+ difficult constructs, and thus is not considered part of the scop,
+ but just a boundary. SCOP_ENTRY is considered part of the scop. */
+#define SCOP_ENTRY(S) (SESE_ENTRY (SCOP_REGION (S))->dest)
+#define SCOP_EXIT(S) (SESE_EXIT (SCOP_REGION (S))->dest)
+#define SCOP_STATIC_SCHEDULE(S) S->static_schedule
+#define SCOP_LOOPS(S) S->loops
+#define SCOP_LOOP_NEST(S) S->loop_nest
+#define SCOP_PARAMS(S) S->params
+#define SCOP_OLDIVS(S) S->old_ivs
+#define SCOP_PROG(S) S->program
+#define SCOP_LOOP2CLOOG_LOOP(S) S->loop2cloog_loop
+#define SCOP_LOOPS_MAPPING(S) S->loops_mapping
+
+extern void debug_scop (scop_p, int);
+extern void debug_scops (int);
+extern void print_graphite_bb (FILE *, graphite_bb_p, int, int);
+extern void debug_gbb (graphite_bb_p, int);
+extern void dot_scop (scop_p);
+extern void dot_all_scops (void);
+extern void debug_clast_stmt (struct clast_stmt *);
+
+
+extern void debug_loop_vec (graphite_bb_p gb);
+extern void debug_oldivs (scop_p);
+
+typedef VEC(name_tree, heap) **loop_iv_stack;
+extern void loop_iv_stack_debug (loop_iv_stack);
+
+
+/* Return the number of gimple loops contained in SCOP. */
+
+static inline int
+scop_nb_loops (scop_p scop)
+{
+ return VEC_length (loop_p, SCOP_LOOP_NEST (scop));
+}
+
+/* Returns the number of parameters for SCOP. */
+
+static inline unsigned
+scop_nb_params (scop_p scop)
+{
+ return VEC_length (name_tree, SCOP_PARAMS (scop));
+}
+
+/* Return the dimension of the domains for SCOP. */
+
+static inline int
+scop_dim_domain (scop_p scop)
+{
+ return scop_nb_loops (scop) + scop_nb_params (scop) + 1;
+}
+
+/* Return the dimension of the domains for GB. */
+
+static inline int
+gbb_dim_domain (graphite_bb_p gb)
+{
+ return scop_dim_domain (GBB_SCOP (gb));
+}
+
+/* Returns the dimensionality of a loop iteration domain for a given
+ loop, identified by LOOP_NUM, with respect to SCOP. */
+
+static inline int
+loop_domain_dim (unsigned int loop_num, scop_p scop)
+{
+ struct loop_to_cloog_loop_str tmp, *slot;
+ htab_t tab = SCOP_LOOP2CLOOG_LOOP (scop);
+
+ tmp.loop_num = loop_num;
+ slot = (struct loop_to_cloog_loop_str *) htab_find (tab, &tmp);
+
+ /* The loop containing the entry of the scop is not always part of
+ the SCoP, and it is not registered in SCOP_LOOP2CLOOG_LOOP. */
+ if (!slot)
+ return scop_nb_params (scop) + 2;
+
+ return cloog_domain_dim (cloog_loop_domain (slot->cloog_loop)) + 2;
+}
+
+/* Returns the dimensionality of an enclosing loop iteration domain
+ with respect to enclosing SCoP for a given data reference REF. */
+
+static inline int
+ref_nb_loops (data_reference_p ref)
+{
+ return loop_domain_dim (loop_containing_stmt (DR_STMT (ref))->num, DR_SCOP (ref));
+}
+
+/* Returns the dimensionality of a loop iteration vector in a loop
+ iteration domain for a given loop (identified by LOOP_NUM) with
+ respect to SCOP. */
+
+static inline int
+loop_iteration_vector_dim (unsigned int loop_num, scop_p scop)
+{
+ return loop_domain_dim (loop_num, scop) - 2 - scop_nb_params (scop);
+}
+
+/* Checks, if SCOP contains LOOP. */
+
+static inline bool
+scop_contains_loop (scop_p scop, struct loop *loop)
+{
+ return bitmap_bit_p (SCOP_LOOPS (scop), loop->num);
+}
+
+/* Returns the index of LOOP in the domain matrix for the SCOP. */
+
+static inline int
+scop_loop_index (scop_p scop, struct loop *loop)
+{
+ unsigned i;
+ struct loop *l;
+
+ gcc_assert (scop_contains_loop (scop, loop));
+
+ for (i = 0; VEC_iterate (loop_p, SCOP_LOOP_NEST (scop), i, l); i++)
+ if (l == loop)
+ return i;
+
+ gcc_unreachable();
+}
+
+/* Return the index of innermost loop that contains the basic block
+ GBB. */
+
+static inline int
+gbb_inner_most_loop_index (scop_p scop, graphite_bb_p gb)
+{
+ return scop_loop_index(scop, gbb_loop (gb));
+}
+
+/* Return the outermost loop that contains the loop LOOP. The outer
+ loops are searched until a sibling for the outer loop is found. */
+
+static struct loop *
+outer_most_loop_1 (scop_p scop, struct loop* loop, struct loop* current_outer)
+{
+ return (!scop_contains_loop (scop, loop)) ? current_outer :
+ (loop->next != NULL) ? loop :
+ outer_most_loop_1 (scop, loop_outer (loop), loop);
+}
+
+/* Return the outermost loop that contains the loop LOOP. */
+
+static struct loop *
+outer_most_loop (scop_p scop, struct loop *loop)
+{
+ return outer_most_loop_1 (scop, loop, NULL);
+}
+
+/* Return the index of the outermost loop that contains the basic
+ block BB. */
+
+static inline int
+gbb_outer_most_loop_index (scop_p scop, graphite_bb_p gb)
+{
+ return scop_loop_index (scop, outer_most_loop (scop, gbb_loop (gb)));
+}
+
+/* Return the loop depth of LOOP in SCOP. */
+
+static inline unsigned int
+scop_gimple_loop_depth (scop_p scop, loop_p loop)
+{
+ unsigned int depth = 0;
+
+ loop = loop_outer (loop);
+
+ while (scop_contains_loop (scop, loop))
+ {
+ depth++;
+ loop = loop_outer (loop);
+ }
+
+ return depth;
+}
+
+/* Associate a POLYHEDRON dependence description to two data
+ references A and B. */
+struct data_dependence_polyhedron
+{
+ struct data_reference *a;
+ struct data_reference *b;
+ bool reversed_p;
+ bool loop_carried; /*TODO:konrad get rid of this, make level signed */
+ signed level;
+ CloogDomain *polyhedron;
+};
+
+#define RDGE_DDP(E) ((struct data_dependence_polyhedron*) ((E)->data))
+
+typedef struct data_dependence_polyhedron *ddp_p;
+
+DEF_VEC_P(ddp_p);
+DEF_VEC_ALLOC_P(ddp_p,heap);
+
diff --git a/gcc/lambda-code.c b/gcc/lambda-code.c
index 21bc1846a73..2fdd898f064 100644
--- a/gcc/lambda-code.c
+++ b/gcc/lambda-code.c
@@ -147,7 +147,6 @@ static lambda_lattice lambda_lattice_new (int, int, struct obstack *);
static lambda_lattice lambda_lattice_compute_base (lambda_loopnest,
struct obstack *);
-static tree find_induction_var_from_exit_cond (struct loop *);
static bool can_convert_to_perfect_nest (struct loop *);
/* Create a new lambda body vector. */
@@ -1434,7 +1433,7 @@ gcc_loop_to_lambda_loop (struct loop *loop, int depth,
/* Given a LOOP, find the induction variable it is testing against in the exit
condition. Return the induction variable if found, NULL otherwise. */
-static tree
+tree
find_induction_var_from_exit_cond (struct loop *loop)
{
gimple expr = get_loop_exit_condition (loop);
diff --git a/gcc/lambda.h b/gcc/lambda.h
index 66fbac74bd5..2d321fbab6d 100644
--- a/gcc/lambda.h
+++ b/gcc/lambda.h
@@ -39,6 +39,9 @@ DEF_VEC_ALLOC_P (lambda_vector_vec_p, heap);
all vectors are the same length). */
typedef lambda_vector *lambda_matrix;
+DEF_VEC_P (lambda_matrix);
+DEF_VEC_ALLOC_P (lambda_matrix, heap);
+
/* A transformation matrix, which is a self-contained ROWSIZE x COLSIZE
matrix. Rather than use floats, we simply keep a single DENOMINATOR that
represents the denominator for every element in the matrix. */
@@ -213,6 +216,7 @@ void lambda_loopnest_to_gcc_loopnest (struct loop *,
lambda_loopnest, lambda_trans_matrix,
struct obstack *);
void remove_iv (gimple);
+tree find_induction_var_from_exit_cond (struct loop *);
static inline void lambda_vector_negate (lambda_vector, lambda_vector, int);
static inline void lambda_vector_mult_const (lambda_vector, lambda_vector, int, int);
@@ -374,6 +378,33 @@ lambda_vector_matrix_mult (lambda_vector vect, int m, lambda_matrix mat,
dest[i] += mat[j][i] * vect[j];
}
+/* Compare two vectors returning an integer less than, equal to, or
+ greater than zero if the first argument is considered to be respectively
+ less than, equal to, or greater than the second.
+ We use the lexicographic order. */
+
+static inline int
+lambda_vector_compare (lambda_vector vec1, int length1, lambda_vector vec2,
+ int length2)
+{
+ int min_length;
+ int i;
+
+ if (length1 < length2)
+ min_length = length1;
+ else
+ min_length = length2;
+
+ for (i = 0; i < min_length; i++)
+ if (vec1[i] < vec2[i])
+ return -1;
+ else if (vec1[i] > vec2[i])
+ return 1;
+ else
+ continue;
+
+ return length1 - length2;
+}
/* Print out a vector VEC of length N to OUTFILE. */
diff --git a/gcc/passes.c b/gcc/passes.c
index 7c76747b971..36c107e852a 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -655,6 +655,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_check_data_deps);
NEXT_PASS (pass_loop_distribution);
NEXT_PASS (pass_linear_transform);
+ NEXT_PASS (pass_graphite_transforms);
NEXT_PASS (pass_iv_canon);
NEXT_PASS (pass_if_conversion);
NEXT_PASS (pass_vectorize);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index fa07075d089..5c75e1fde36 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,23 @@
+2008-09-02 Sebastian Pop <sebastian.pop@amd.com>
+ Tobias Grosser <grosser@fim.uni-passau.de>
+ Jan Sjodin <jan.sjodin@amd.com>
+ Harsha Jagasia <harsha.jagasia@amd.com>
+ Dwarakanath Rajagopal <dwarak.rajagopal@amd.com>
+ Konrad Trifunovic <konrad.trifunovic@inria.fr>
+ Adrien Eliche <aeliche@isty.uvsq.fr>
+
+ Merge from graphite branch.
+ * gcc.dg/graphite/scop-{0,1,2,3,4,5,6,7,8,9,
+ 10,11,12,13,14,15,16,17,18}.c: New.
+ * gcc.dg/graphite/graphite.exp: New.
+ * gcc.dg/graphite/scop-matmult.c: New.
+ * gcc.dg/graphite/block-0.c: New.
+ * lib/target-supports.exp (check_effective_target_fgraphite): New.
+ * gfortran.dg/graphite/block-1.f90: New.
+ * gfortran.dg/graphite/scop-{1,2}.f: New.
+ * gfortran.dg/graphite/block-{1,3,4}.f90: New.
+ * gfortran.dg/graphite/graphite.exp: New.
+
2008-09-02 Richard Guenther <rguenther@suse.de>
PR tree-optimization/37327
diff --git a/gcc/testsuite/gcc.dg/graphite/block-0.c b/gcc/testsuite/gcc.dg/graphite/block-0.c
new file mode 100644
index 00000000000..f277f05fb06
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/block-0.c
@@ -0,0 +1,25 @@
+/* { dg-options "-O -floop-block -fdump-tree-graphite-all" } */
+
+#define N 1000
+
+int toto()
+{
+ int j;
+ int i;
+ int a[N];
+ int b[N];
+
+ for (i = 0; i < N; i++)
+ for (j = 0; j < N; j++)
+ a[j] = a[i] + 1;
+
+ return a[0];
+}
+
+main()
+{
+ return toto();
+}
+
+/* { dg-final { scan-tree-dump-times "Loop blocked" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/block-1.c b/gcc/testsuite/gcc.dg/graphite/block-1.c
new file mode 100644
index 00000000000..039b974fdae
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/block-1.c
@@ -0,0 +1,31 @@
+/* { dg-options "-O2 -floop-block -fdump-tree-graphite-all" } */
+
+#define MAX 8192
+
+int main()
+{
+ int i, j;
+ int sum = 0;
+ int A[MAX * MAX];
+ int B[MAX * MAX];
+
+ for (i = 0; i < MAX; i++)
+ for (j = 0; j < MAX; j++)
+ {
+ A[i*MAX + j] = j;
+ B[i*MAX + j] = j;
+ }
+
+ for (i = 0; i < MAX; i++)
+ for (j = 0; j < MAX; j++)
+ A[i*MAX + j] += B[j*MAX + i];
+
+ for(i = 0; i < MAX; i++)
+ for(j = 0; j < MAX; j++)
+ sum += A[i*MAX + j];
+
+ return sum;
+}
+
+/* { dg-final { scan-tree-dump-times "Loop blocked" 3 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/graphite.exp b/gcc/testsuite/gcc.dg/graphite/graphite.exp
new file mode 100644
index 00000000000..a1257177f55
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/graphite.exp
@@ -0,0 +1,48 @@
+# Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+if ![check_effective_target_fgraphite] {
+ return
+}
+
+# The default action for a test is 'compile'. Save current default.
+global dg-do-what-default
+set save-dg-do-what-default ${dg-do-what-default}
+set dg-do-what-default compile
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+ set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \
+ "" $DEFAULT_CFLAGS
+
+# Clean up.
+set dg-do-what-default ${save-dg-do-what-default}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-0.c b/gcc/testsuite/gcc.dg/graphite/scop-0.c
new file mode 100644
index 00000000000..ea3ae065a0b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-0.c
@@ -0,0 +1,24 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+int foo (void);
+void bar (void);
+
+int toto()
+{
+ /* Scop 1. */
+ int i, j, k;
+ int a[100][100];
+ int b[100];
+ int N = foo ();
+
+ for (i = 0; i < 2*N+ 100; i++)
+ for (j = 0; j < 200; j++)
+ a[j][i] = a[j+1][10] + 2;
+
+ return a[3][5] + b[1];
+ /* End scop 1. */
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 1" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
+
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-1.c b/gcc/testsuite/gcc.dg/graphite/scop-1.c
new file mode 100644
index 00000000000..ed6159fb365
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-1.c
@@ -0,0 +1,33 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+void bar (void);
+
+int toto()
+{
+ int i, j, k;
+ int a[100][100];
+ int b[100];
+
+ for (i = 1; i < 100; i++)
+ {
+ for (j = 1; j < 100; j++)
+ a[j][i] = a[j+1][i-1] + 2;
+
+ b[i] = b[i-1] + 2;
+
+ bar ();
+
+ for (j = 1; j < 100; j++)
+ a[j][i] = a[j+1][i-1] + 2;
+
+ b[i] = a[i-1][i] + 2;
+
+ for (j = 1; j < 100; j++)
+ a[j][i] = a[j+1][i-1] + 2;
+ }
+
+ return a[3][5] + b[1];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 3" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-10.c b/gcc/testsuite/gcc.dg/graphite/scop-10.c
new file mode 100644
index 00000000000..8aff2c74302
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-10.c
@@ -0,0 +1,33 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+void bar (void);
+
+int toto()
+{
+ int i, j, k;
+ int a[100][100];
+ int b[100];
+
+ for (i = 1; i < 100; i++)
+ {
+ for (j = 1; j < 100; j++)
+ b[i+j] = b[i+j-1] + 2;
+
+ if (i * 2 == i + 8)
+ bar ();
+ else
+ {
+ for (j = 1; j < 100; j++)
+ b[i+j] = b[i+j-1] + 2;
+ a[i][i] = 2;
+ }
+
+ for (k = 1; k < 100; k++)
+ b[i+k] = b[i+k-5] + 2;
+ }
+
+ return a[3][5] + b[1];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 3" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-11.c b/gcc/testsuite/gcc.dg/graphite/scop-11.c
new file mode 100644
index 00000000000..e5a0fdb3904
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-11.c
@@ -0,0 +1,34 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+void bar ();
+
+int toto()
+{
+ int i,j, b;
+ int a[100];
+
+ if (i == 20)
+ {
+ for (j = 0; j <= 20; j++)
+ a[j] = b + i;
+ b = 3;
+ bar();
+ }
+ else
+ {
+ if (i == 30)
+ {
+ for (j = 0; j <= 20; j++)
+ a[j] = b + i;
+ b = 5;
+ }
+ }
+
+ for (j = 0; j <= 20; j++)
+ a[j] = b + i;
+
+ return a[b];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 3" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-12.c b/gcc/testsuite/gcc.dg/graphite/scop-12.c
new file mode 100644
index 00000000000..0c130330ccd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-12.c
@@ -0,0 +1,38 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+void bar ();
+
+int toto()
+{
+ int i,j, b;
+ int a[100];
+
+ switch (i)
+ {
+
+ case 5:
+ for (j = 0; j <= 20; j++)
+ a[j] = b + i + 12;
+ break;
+ case 8:
+ for (j = 0; j <= 20; j++)
+ a[j] = b + i + 122;
+ break;
+ case 15:
+ for (j = 0; j <= 20; j++)
+ a[j] = b + i + 12;
+ break;
+ case 18:
+ for (j = 0; j <= 20; j++)
+ a[j] = b + i + 4;
+ break;
+ default:
+ for (j = 0; j <= 20; j++)
+ a[j] = b + i + 3;
+ }
+
+ return a[b];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 5" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-13.c b/gcc/testsuite/gcc.dg/graphite/scop-13.c
new file mode 100644
index 00000000000..aa55e10f3f4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-13.c
@@ -0,0 +1,43 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+void bar ();
+
+int toto()
+{
+ int i,j, b;
+ int a[100];
+
+ if (i == 20)
+ {
+ b = 3;
+ goto B;
+ }
+ else
+ {
+ if (i == 30)
+ {
+ a[i] = b;
+
+
+ for (j = 0; j <= 20; j++)
+ a[j] = b + i;
+
+ B:
+
+ for (j = 0; j <= 20; j++)
+ a[j+b] = b + i;
+
+ bar ();
+ }
+ else
+ {
+ a[i] = b + 3;
+ }
+ }
+
+
+ return a[b];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 2" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-14.c b/gcc/testsuite/gcc.dg/graphite/scop-14.c
new file mode 100644
index 00000000000..a707b01d450
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-14.c
@@ -0,0 +1,27 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+void bar ();
+
+int toto()
+{
+ int i,j, b;
+ int a[100];
+
+ for (j = 0; j <= 20; j++)
+ {
+ a[j] = b + i;
+
+ if (j * i == b)
+ break;
+
+ a[j+b] = b + i;
+ }
+
+ a[i] = b + 3;
+
+
+ return a[b];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 0" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-15.c b/gcc/testsuite/gcc.dg/graphite/scop-15.c
new file mode 100644
index 00000000000..7e242537315
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-15.c
@@ -0,0 +1,52 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+# define EXTERN(type, array) extern type array[]
+typedef unsigned char uch;
+typedef unsigned short ush;
+EXTERN(uch, window);
+EXTERN(ush, prev);
+#ifndef WSIZE
+# define WSIZE 0x8000
+#endif
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
+#define near
+typedef unsigned IPos;
+unsigned near max_chain_length;
+extern unsigned near strstart;
+unsigned int near prev_length;
+#define NIL 0
+unsigned near good_match;
+int near nice_match;
+#define WMASK (WSIZE-1)
+int longest_match(IPos cur_match)
+{
+ unsigned chain_length = max_chain_length;
+ register uch *scan = window + strstart;
+ register uch *match;
+ register int len;
+ int best_len = prev_length;
+ IPos limit = strstart > (IPos)MAX_DIST ? strstart - (IPos)MAX_DIST : NIL;
+ register uch *strend = window + strstart + MAX_MATCH;
+ register uch scan_end = scan[best_len];
+ if (prev_length >= good_match) {
+ }
+ do {
+ if (match[best_len] != scan_end ||
+ *++match != scan[1]) continue;
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ scan < strend);
+ len = MAX_MATCH - (int)(strend - scan);
+ if (len > best_len) {
+ best_len = len;
+ if (len >= nice_match) break;
+ }
+ } while ((cur_match = prev[cur_match & WMASK]) > limit
+ && --chain_length != 0);
+ return best_len;
+}
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 0" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-16.c b/gcc/testsuite/gcc.dg/graphite/scop-16.c
new file mode 100644
index 00000000000..42f7b6aade3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-16.c
@@ -0,0 +1,25 @@
+/* { dg-options "-O2 -floop-block -fdump-tree-graphite-all" } */
+#define N 10000
+void foo (int);
+int test ()
+{
+ int a[N][N];
+ int b[N][N];
+ unsigned i, j;
+
+ for (i = 0; i < N; i++)
+ for (j = 0; j < N; j++)
+ a[i][j] = i*j;
+
+ for (j = 1; j < N; j++)
+ for (i = 0; i < N; i++)
+ a[i][j] = a[i][j-1] + b[i][j];
+
+ for (i = 0; i < N; i++)
+ for (j = 0; j < N; j++)
+ foo (a[i][j]);
+}
+
+/* Interchange is legal for loops 0 and 1 of the first two SCoPs */
+/* { dg-final { scan-tree-dump-times "Interchange valid for loops 0 and 1:" 2 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-17.c b/gcc/testsuite/gcc.dg/graphite/scop-17.c
new file mode 100644
index 00000000000..4c1b0ca2993
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-17.c
@@ -0,0 +1,24 @@
+/* { dg-options "-O2 -floop-block -fdump-tree-graphite-all" } */
+#define N 10000
+void foo (int);
+int test ()
+{
+ int a[N][N];
+ unsigned i, j;
+
+ for (i = 0; i < N; i++)
+ for (j = 0; j < N; j++)
+ a[i][j] = i*j;
+
+ for (i = 1; i < N; i++)
+ for (j = 1; j < (N-1) ; j++)
+ a[i][j] = a[i-1][j+1] * a[i-1][j+1]/2;
+
+ for (i = 0; i < N; i++)
+ for (j = 0; j < N; j++)
+ foo (a[i][j]);
+}
+
+/* Interchange is not legal for loops 0 and 1 of SCoP 2. */
+/* { dg-final { scan-tree-dump-times "Interchange not valid for loops 0 and 1:" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-18.c b/gcc/testsuite/gcc.dg/graphite/scop-18.c
new file mode 100644
index 00000000000..fe2d5f4a412
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-18.c
@@ -0,0 +1,26 @@
+/* { dg-options "-O2 -floop-block -fdump-tree-graphite-all" } */
+
+#define N 24
+#define M 1000
+
+float A[1000][1000], B[1000][1000], C[1000][1000];
+
+void test (void)
+{
+ int i, j, k;
+
+ /* These loops contain too few iterations for being strip-mined by 64. */
+ for (i = 0; i < 24; i++)
+ for (j = 0; j < 24; j++)
+ for (k = 0; k < 24; k++)
+ A[i][j] += B[i][k] * C[k][j];
+
+ /* These loops should still be strip mined. */
+ for (i = 0; i < 1000; i++)
+ for (j = 0; j < 1000; j++)
+ for (k = 0; k < 1000; k++)
+ A[i][j] += B[i][k] * C[k][j];
+}
+
+/* { dg-final { scan-tree-dump-times "Strip Mining is not profitable" 3 "graphite" } } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-2.c b/gcc/testsuite/gcc.dg/graphite/scop-2.c
new file mode 100644
index 00000000000..cf25dcdaf09
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-2.c
@@ -0,0 +1,41 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+void bar (void);
+
+int toto()
+{
+ int i, j, k;
+ int a[100][100];
+ int b[100];
+
+ for (i = 1; i < 100; i++)
+ {
+ for (j = 1; j < 100; j++)
+ for (k = 1; k < 100; k++)
+ a[j][k] = a[j+1][i-1] + 2;
+
+ b[i] = b[i-1] + 2;
+
+ bar ();
+
+ for (j = 1; j < 100; j++)
+ a[j][i] = a[j+1][i-1] + 2;
+
+ b[i] = b[i-1] + 2;
+
+ bar ();
+
+ for (j = 1; j < 100; j++)
+ a[j][i] = a[j+1][i-1] + 2;
+
+ b[i] = a[i-1][i] + 2;
+
+ for (j = 1; j < 100; j++)
+ a[j][i] = a[j+1][i-1] + 2;
+ }
+
+ return a[3][5] + b[1];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 4" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-3.c b/gcc/testsuite/gcc.dg/graphite/scop-3.c
new file mode 100644
index 00000000000..1789e6b6c5a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-3.c
@@ -0,0 +1,30 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+int toto()
+{
+ int i, j, k;
+ int a[100][100];
+ int b[100];
+
+ for (i = 1; i < 100; i++)
+ {
+ for (j = 1; j < 80; j++)
+ a[j][i] = a[j+1][2*i-1*j] + 12;
+
+ b[i] = b[i-1] + 10;
+
+ for (j = 1; j < 60; j++)
+ a[j][i] = a[j+1][i-1] + 8;
+
+ if (i == 23)
+ b[i] = a[i-1][i] + 6;
+
+ for (j = 1; j < 40; j++)
+ a[j][i] = a[j+1][i-1] + 4;
+ }
+
+ return a[3][5] + b[1];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 3" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-4.c b/gcc/testsuite/gcc.dg/graphite/scop-4.c
new file mode 100644
index 00000000000..515c53ad592
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-4.c
@@ -0,0 +1,31 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+void bar ();
+
+int toto()
+{
+ int i, j, k;
+ int a[100][100];
+ int b[100];
+
+ for (i = 1; i < 100; i++)
+ {
+ for (j = 1; j < 80; j++)
+ a[j][i] = a[j+1][2*i-1*j] + 12;
+
+ b[i] = b[i-1] + 10;
+
+ for (j = 1; j < 60; j++)
+ a[j][i] = a[j+1][i-1] + 8;
+
+ bar ();
+
+ if (i == 23)
+ b[i] = a[i-1][i] + 6;
+ }
+
+ return a[3][5] + b[1];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 2" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-5.c b/gcc/testsuite/gcc.dg/graphite/scop-5.c
new file mode 100644
index 00000000000..697a28ea168
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-5.c
@@ -0,0 +1,37 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+void bar ();
+
+int toto()
+{
+ int i,j, b;
+ int a[100];
+
+ if (i == 20)
+ {
+ for (j = 0; j <= 20; j++)
+ a[j] = b + i;
+ b = 3;
+ bar();
+ }
+ else
+ {
+ if (i == 30)
+ {
+ for (j = 0; j <= 20; j++)
+ a[j] = b + i;
+ b = 5;
+ }
+ else
+ {
+ for (j = 0; j <= 20; j++)
+ a[j] = b + i;
+ b = 8;
+ }
+ }
+
+ return a[b];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 3" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-6.c b/gcc/testsuite/gcc.dg/graphite/scop-6.c
new file mode 100644
index 00000000000..d2623204735
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-6.c
@@ -0,0 +1,33 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+void bar (void);
+
+int toto()
+{
+ int i, j, k;
+ int a[100][100];
+ int b[100];
+
+ for (i = 1; i < 100; i++)
+ {
+ for (j = 1; j < 100; j++)
+ b[i+j] = b[i+j-1] + 2;
+
+ if (i * 2 == i + 8)
+ b[i+k] = b[i+k-1] + 2;
+ else
+ {
+ for (k = 1; k < 100; k++)
+ b[i+k] = b[i+k-1] + 2;
+ bar ();
+ }
+
+ for (k = 1; k < 100; k++)
+ b[i+k] = b[i+k-5] + 2;
+ }
+
+ return a[3][5] + b[1];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 3" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-7.c b/gcc/testsuite/gcc.dg/graphite/scop-7.c
new file mode 100644
index 00000000000..1187ce104ec
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-7.c
@@ -0,0 +1,33 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+void bar (void);
+
+int toto()
+{
+ int i, j, k;
+ int a[100][100];
+ int b[100];
+
+ for (i = 1; i < 100; i++)
+ {
+ for (j = 1; j < 100; j++)
+ b[i+j] = b[i+j-1] + 2;
+
+ if (i * 2 == i + 8)
+ {
+ bar ();
+ for (j = 1; j < 100; j++)
+ b[i+j] = b[i+j-1] + 2;
+ }
+ else
+ a[i][i] = 2;
+
+ for (k = 1; k < 100; k++)
+ b[i+k] = b[i+k-5] + 2;
+ }
+
+ return a[3][5] + b[1];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 3" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-8.c b/gcc/testsuite/gcc.dg/graphite/scop-8.c
new file mode 100644
index 00000000000..491ad372feb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-8.c
@@ -0,0 +1,33 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+int bar (void);
+
+int toto()
+{
+ int i, j, k;
+ int a[100][100];
+ int b[100];
+
+ for (i = 1; i < 100; i++)
+ {
+ for (j = 1; j < 100; j++)
+ b[i+j] = b[i+j-1] + 2;
+
+ if (i * 2 == i + 8)
+ {
+ for (j = 1; j < 100; j++)
+ if (bar ())
+ b[i+j] = b[i+j-1] + 2;
+ }
+ else
+ a[i][i] = 2;
+
+ for (k = 1; k < 100; k++)
+ b[i+k] = b[i+k-5] + 2;
+ }
+
+ return a[3][5] + b[1];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 2" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-9.c b/gcc/testsuite/gcc.dg/graphite/scop-9.c
new file mode 100644
index 00000000000..871b86b8bd4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-9.c
@@ -0,0 +1,29 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+void bar (void);
+
+int toto()
+{
+ int i, j, k;
+ int a[100][100];
+ int b[100];
+
+ for (i = 1; i < 100; i++)
+ {
+ for (j = 1; j < 100; j++)
+ b[i+j] = b[i+j-1] + 2;
+
+ if (i * 2 == i + 8)
+ bar ();
+ else
+ a[i][i] = 2;
+
+ for (k = 1; k < 100; k++)
+ b[i+k] = b[i+k-5] + 2;
+ }
+
+ return a[3][5] + b[1];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 2" 1 "graphite"} } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-matmult.c b/gcc/testsuite/gcc.dg/graphite/scop-matmult.c
new file mode 100644
index 00000000000..61a5be1fd21
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-matmult.c
@@ -0,0 +1,20 @@
+/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */
+
+float A[1000][1000], B[1000][1000], C[1000][1000];
+
+/* Multiply two n x n matrices A and B and store the result in C. */
+
+void matmult (int n)
+{
+ int i,j,k;
+
+ for (i = 0; i < n; i++)
+ for (j = 0; j < n; j++)
+ for (k = 0; k < n; k++)
+ A[i][j] += B[i][k] * C[k][j];
+}
+
+/* This one fails because the number of iterations cannot be
+ determined anymore for the outermost loop. */
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 1" 1 "graphite" { xfail *-*-* } } } */
+/* { dg-final { cleanup-tree-dump "graphite" } } */
diff --git a/gcc/testsuite/gfortran.dg/graphite/block-1.f90 b/gcc/testsuite/gfortran.dg/graphite/block-1.f90
new file mode 100644
index 00000000000..124f06d16eb
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/graphite/block-1.f90
@@ -0,0 +1,14 @@
+! { dg-options "-O2 -floop-block -fdump-tree-graphite-all" }
+
+subroutine matrix_multiply(a,b,c,n)
+
+real(8), dimension(n,n) :: a,b,c
+
+! The following code is disabled for the moment.
+! c=0.d0
+
+end subroutine matrix_multiply
+
+! { dg-final { scan-tree-dump-times "Loop blocked" 2 "graphite" { xfail *-*-* } } }
+! { dg-final { cleanup-tree-dump "graphite" } }
+
diff --git a/gcc/testsuite/gfortran.dg/graphite/block-2.f b/gcc/testsuite/gfortran.dg/graphite/block-2.f
new file mode 100644
index 00000000000..af966ec5f97
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/graphite/block-2.f
@@ -0,0 +1,22 @@
+! { dg-options "-O2 -floop-block -fdump-tree-graphite-all" }
+
+ SUBROUTINE MATRIX_MUL_UNROLLED (A, B, C, L, M, N)
+ DIMENSION A(L,M), B(M,N), C(L,N)
+
+ DO 100 K = 1, N
+ DO 100 I = 1, L
+ C(I,K) = 0.
+100 CONTINUE
+ DO 110 J = 1, M, 4
+ DO 110 K = 1, N
+ DO 110 I = 1, L
+ C(I,K) = C(I,K) + A(I,J) * B(J,K)
+ $ + A(I,J+1) * B(J+1,K) + A(I,J+2) * B(J+2,K)
+ $ + A(I,J+3) * B(J+3,K)
+110 CONTINUE
+
+ RETURN
+ END
+
+! { dg-final { scan-tree-dump-times "Loop blocked" 3 "graphite" { xfail { "*-*-*" } } } }
+! { dg-final { cleanup-tree-dump "graphite" } }
diff --git a/gcc/testsuite/gfortran.dg/graphite/block-3.f90 b/gcc/testsuite/gfortran.dg/graphite/block-3.f90
new file mode 100644
index 00000000000..c7809d3431b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/graphite/block-3.f90
@@ -0,0 +1,19 @@
+! { dg-options "-O2 -floop-block -fdump-tree-graphite-all" }
+
+subroutine matrix_multiply(a,b,c,n)
+
+real(8), dimension(n,n) :: a,b,c
+
+do i = 1,n
+ do j = 1,n
+ do k = 1,n
+ c(j,i) = c(j,i) + a(k,i) * b(j,k)
+ enddo
+ enddo
+enddo
+
+end subroutine matrix_multiply
+
+! { dg-final { scan-tree-dump-times "Loop blocked" 2 "graphite" { xfail *-*-* } } }
+! { dg-final { cleanup-tree-dump "graphite" } }
+
diff --git a/gcc/testsuite/gfortran.dg/graphite/block-4.f90 b/gcc/testsuite/gfortran.dg/graphite/block-4.f90
new file mode 100644
index 00000000000..586a7772512
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/graphite/block-4.f90
@@ -0,0 +1,22 @@
+! { dg-options "-O2 -floop-block -fdump-tree-graphite-all" }
+
+subroutine matrix_multiply(a,b,c,n)
+
+real(8), dimension(n,n) :: a,b,c
+
+! The following code is disabled for the moment.
+! c=0.d0
+
+do i = 1,n
+ do j = 1,n
+ do k = 1,n
+ c(j,i) = c(j,i) + a(k,i) * b(j,k)
+ enddo
+ enddo
+enddo
+
+end subroutine matrix_multiply
+
+! { dg-final { scan-tree-dump-times "Loop blocked" 2 "graphite" { xfail *-*-* } } }
+! { dg-final { cleanup-tree-dump "graphite" } }
+
diff --git a/gcc/testsuite/gfortran.dg/graphite/graphite.exp b/gcc/testsuite/gfortran.dg/graphite/graphite.exp
new file mode 100644
index 00000000000..a9fdb2c508f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/graphite/graphite.exp
@@ -0,0 +1,48 @@
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gfortran-dg.exp
+
+if ![check_effective_target_fgraphite] {
+ return
+}
+
+# The default action for a test is 'compile'. Save current default.
+global dg-do-what-default
+set save-dg-do-what-default ${dg-do-what-default}
+set dg-do-what-default compile
+
+# If a testcase doesn't have special options, use these.
+set DEFAULT_GRAPHITE_FLAGS ""
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+gfortran-dg-runtest [lsort \
+ [glob -nocomplain $srcdir/$subdir/*.\[fF\]{,90,95,03,08} ] ] $DEFAULT_GRAPHITE_FLAGS
+
+gfortran-dg-runtest [lsort \
+ [glob -nocomplain $srcdir/$subdir/g77/*.\[fF\] ] ] $DEFAULT_GRAPHITE_FLAGS
+
+# Clean up.
+set dg-do-what-default ${save-dg-do-what-default}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gfortran.dg/graphite/scop-1.f b/gcc/testsuite/gfortran.dg/graphite/scop-1.f
new file mode 100644
index 00000000000..a279abaf9c2
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/graphite/scop-1.f
@@ -0,0 +1,13 @@
+C { dg-options "-O2 -fgraphite" }
+
+ dimension p1(2),t(6,4),b1(2),b2(2),al1(2),al2(2),g1(2),g2(2)
+ save
+ if(nlin.eq.0) then
+ do 20 l=1,2
+ ll=2*l
+ b2(l)=t(6-ll,ll-1)*t(6-ll,ll-1)+t(7-ll,ll-1)*t(7-ll,ll-1)
+ write(*,*) b2(l)
+ 20 continue
+ endif
+ end
+
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index c9512b257b6..527d277051a 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -562,6 +562,15 @@ proc check_effective_target_tls_runtime {} {
}]
}
+# Return 1 if compilation with -fgraphite is error-free for trivial
+# code, 0 otherwise.
+
+proc check_effective_target_fgraphite {} {
+ return [check_no_compiler_messages fgraphite object {
+ void foo (void) { }
+ } "-fgraphite"]
+}
+
# Return 1 if compilation with -fopenmp is error-free for trivial
# code, 0 otherwise.
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 94fa087754e..4351f17e4b5 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -125,6 +125,7 @@ DEFTIMEVAR (TV_TREE_LOOP_UNSWITCH , "tree loop unswitching")
DEFTIMEVAR (TV_COMPLETE_UNROLL , "complete unrolling")
DEFTIMEVAR (TV_TREE_PARALLELIZE_LOOPS, "tree parallelize loops")
DEFTIMEVAR (TV_TREE_VECTORIZATION , "tree vectorization")
+DEFTIMEVAR (TV_GRAPHITE_TRANSFORMS , "GRAPHITE loop transforms")
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")
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index c485027354c..f63e6762104 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -6140,7 +6140,7 @@ print_loops (FILE *file, int verbosity)
{
basic_block bb;
- bb = BASIC_BLOCK (NUM_FIXED_BLOCKS);
+ bb = ENTRY_BLOCK_PTR;
if (bb && bb->loop_father)
print_loop_and_siblings (file, bb->loop_father, 0, verbosity);
}
diff --git a/gcc/tree-chrec.c b/gcc/tree-chrec.c
index da359529e4c..26ae9b408a7 100644
--- a/gcc/tree-chrec.c
+++ b/gcc/tree-chrec.c
@@ -1407,3 +1407,26 @@ scev_direction (const_tree chrec)
else
return EV_DIR_GROWS;
}
+
+/* Iterates over all the components of SCEV, and calls CBCK. */
+
+void
+for_each_scev_op (tree *scev, bool (*cbck) (tree *, void *), void *data)
+{
+ switch (TREE_CODE_LENGTH (TREE_CODE (*scev)))
+ {
+ case 3:
+ for_each_scev_op (&TREE_OPERAND (*scev, 2), cbck, data);
+
+ case 2:
+ for_each_scev_op (&TREE_OPERAND (*scev, 1), cbck, data);
+
+ case 1:
+ for_each_scev_op (&TREE_OPERAND (*scev, 0), cbck, data);
+
+ default:
+ cbck (scev, data);
+ break;
+ }
+}
+
diff --git a/gcc/tree-chrec.h b/gcc/tree-chrec.h
index 9000fb7dab4..d35dcd3064c 100644
--- a/gcc/tree-chrec.h
+++ b/gcc/tree-chrec.h
@@ -70,6 +70,7 @@ extern tree evolution_part_in_loop_num (tree, unsigned);
extern tree hide_evolution_in_other_loops_than_loop (tree, unsigned);
extern tree reset_evolution_in_loop (unsigned, tree, tree);
extern tree chrec_merge (tree, tree);
+extern void for_each_scev_op (tree *, bool (*) (tree *, void *), void *);
/* Observers. */
extern bool eq_evolutions_p (const_tree, const_tree);
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index 85d0977bce9..af1146c7fef 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -1224,7 +1224,7 @@ disjoint_objects_p (tree a, tree b)
/* Returns false if we can prove that data references A and B do not alias,
true otherwise. */
-static bool
+bool
dr_may_alias_p (const struct data_reference *a, const struct data_reference *b)
{
const_tree addr_a = DR_BASE_ADDRESS (a);
@@ -3303,6 +3303,21 @@ access_functions_are_affine_or_constant_p (const struct data_reference *a,
return true;
}
+/* Return true if we can create an affine data-ref for OP in STMT. */
+
+bool
+stmt_simple_memref_p (struct loop *loop, gimple stmt, tree op)
+{
+ data_reference_p dr;
+
+ dr = create_data_ref (loop, op, stmt, true);
+ if (!access_functions_are_affine_or_constant_p (dr, loop))
+ return false;
+
+ free_data_ref (dr);
+ return true;
+}
+
/* Initializes an equation for an OMEGA problem using the information
contained in the ACCESS_FUN. Returns true when the operation
succeeded.
@@ -4069,9 +4084,9 @@ get_references_in_stmt (gimple stmt, VEC (data_ref_loc, heap) **references)
/* Stores the data references in STMT to DATAREFS. If there is an unanalyzable
reference, returns false, otherwise returns true. NEST is the outermost
- loop of the loop nest in that the references should be analyzed. */
+ loop of the loop nest in which the references should be analyzed. */
-static bool
+bool
find_data_references_in_stmt (struct loop *nest, gimple stmt,
VEC (data_reference_p, heap) **datarefs)
{
@@ -4116,7 +4131,7 @@ find_data_references_in_stmt (struct loop *nest, gimple stmt,
TODO: This function should be made smarter so that it can handle address
arithmetic as if they were array accesses, etc. */
-static tree
+tree
find_data_references_in_loop (struct loop *loop,
VEC (data_reference_p, heap) **datarefs)
{
@@ -4644,6 +4659,7 @@ create_rdg_edge_for_ddr (struct graph *rdg, ddr_p ddr)
e->data = XNEW (struct rdg_edge);
RDGE_LEVEL (e) = level;
+ RDGE_RELATION (e) = ddr;
/* Determines the type of the data dependence. */
if (DR_IS_READ (dra) && DR_IS_READ (drb))
@@ -4676,6 +4692,7 @@ create_rdg_edges_for_scalar (struct graph *rdg, tree def, int idef)
e = add_edge (rdg, idef, use);
e->data = XNEW (struct rdg_edge);
RDGE_TYPE (e) = flow_dd;
+ RDGE_RELATION (e) = NULL;
}
}
@@ -4701,7 +4718,7 @@ create_rdg_edges (struct graph *rdg, VEC (ddr_p, heap) *ddrs)
/* Build the vertices of the reduced dependence graph RDG. */
-static void
+void
create_rdg_vertices (struct graph *rdg, VEC (gimple, heap) *stmts)
{
int i, j;
@@ -4826,6 +4843,21 @@ hash_stmt_vertex_del (void *e)
scalar dependence. */
struct graph *
+build_empty_rdg (int n_stmts)
+{
+ int nb_data_refs = 10;
+ struct graph *rdg = new_graph (n_stmts);
+
+ rdg->indices = htab_create (nb_data_refs, hash_stmt_vertex_info,
+ eq_stmt_vertex_info, hash_stmt_vertex_del);
+ return rdg;
+}
+
+/* Build the Reduced Dependence Graph (RDG) with one vertex per
+ statement of the loop nest, and one edge per data dependence or
+ scalar dependence. */
+
+struct graph *
build_rdg (struct loop *loop)
{
int nb_data_refs = 10;
@@ -4842,21 +4874,23 @@ build_rdg (struct loop *loop)
&dependence_relations);
if (!known_dependences_p (dependence_relations))
- goto end_rdg;
+ {
+ free_dependence_relations (dependence_relations);
+ free_data_refs (datarefs);
+ VEC_free (gimple, heap, stmts);
+
+ return rdg;
+ }
stmts_from_loop (loop, &stmts);
- rdg = new_graph (VEC_length (gimple, stmts));
+ rdg = build_empty_rdg (VEC_length (gimple, stmts));
rdg->indices = htab_create (nb_data_refs, hash_stmt_vertex_info,
eq_stmt_vertex_info, hash_stmt_vertex_del);
create_rdg_vertices (rdg, stmts);
create_rdg_edges (rdg, dependence_relations);
- end_rdg:
- free_dependence_relations (dependence_relations);
- free_data_refs (datarefs);
VEC_free (gimple, heap, stmts);
-
return rdg;
}
diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
index 639a32bf82b..ee514c5ee92 100644
--- a/gcc/tree-data-ref.h
+++ b/gcc/tree-data-ref.h
@@ -96,6 +96,8 @@ struct dr_alias
bitmap vops;
};
+typedef struct scop *scop_p;
+
/* Each vector of the access matrix represents a linear access
function for a subscript. First elements correspond to the
leftmost indices, ie. for a[i][j] the first vector corresponds to
@@ -170,16 +172,20 @@ struct data_reference
/* Behavior of the memory reference in the innermost loop. */
struct innermost_loop_behavior innermost;
- /* Decomposition to indices for alias analysis. */
+ /* Subscripts of this data reference. */
struct indices indices;
/* Alias information for the data reference. */
struct dr_alias alias;
+ /* The SCoP in which the data reference was analyzed. */
+ scop_p scop;
+
/* Matrix representation for the data access functions. */
struct access_matrix *access_matrix;
};
+#define DR_SCOP(DR) (DR)->scop
#define DR_STMT(DR) (DR)->stmt
#define DR_REF(DR) (DR)->ref
#define DR_BASE_OBJECT(DR) (DR)->indices.base_object
@@ -373,6 +379,8 @@ void dr_analyze_innermost (struct data_reference *);
extern bool compute_data_dependences_for_loop (struct loop *, bool,
VEC (data_reference_p, heap) **,
VEC (ddr_p, heap) **);
+extern tree find_data_references_in_loop (struct loop *,
+ VEC (data_reference_p, heap) **);
extern void print_direction_vector (FILE *, lambda_vector, int);
extern void print_dir_vectors (FILE *, VEC (lambda_vector, heap) *, int);
extern void print_dist_vectors (FILE *, VEC (lambda_vector, heap) *, int);
@@ -392,10 +400,18 @@ extern void free_dependence_relation (struct data_dependence_relation *);
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 bool find_data_references_in_stmt (struct loop *, gimple,
+ VEC (data_reference_p, heap) **);
struct data_reference *create_data_ref (struct loop *, tree, gimple, bool);
-bool find_loop_nest (struct loop *, VEC (loop_p, heap) **);
-void compute_all_dependences (VEC (data_reference_p, heap) *,
- VEC (ddr_p, heap) **, VEC (loop_p, heap) *, bool);
+extern bool find_loop_nest (struct loop *, VEC (loop_p, heap) **);
+extern void compute_all_dependences (VEC (data_reference_p, heap) *,
+ VEC (ddr_p, heap) **, VEC (loop_p, heap) *,
+ bool);
+
+extern void create_rdg_vertices (struct graph *, VEC (gimple, heap) *);
+extern bool dr_may_alias_p (const struct data_reference *,
+ const struct data_reference *);
+extern bool stmt_simple_memref_p (struct loop *, gimple, tree);
/* Return true when the DDR contains two data references that have the
same access functions. */
@@ -511,15 +527,21 @@ typedef struct rdg_edge
/* Type of the dependence. */
enum rdg_dep_type type;
- /* Levels of the dependence: the depth of the loops that
- carry the dependence. */
+ /* Levels of the dependence: the depth of the loops that carry the
+ dependence. */
unsigned level;
+
+ /* Dependence relation between data dependences, NULL when one of
+ the vertices is a scalar. */
+ ddr_p relation;
} *rdg_edge_p;
#define RDGE_TYPE(E) ((struct rdg_edge *) ((E)->data))->type
#define RDGE_LEVEL(E) ((struct rdg_edge *) ((E)->data))->level
+#define RDGE_RELATION(E) ((struct rdg_edge *) ((E)->data))->relation
struct graph *build_rdg (struct loop *);
+struct graph *build_empty_rdg (int);
void free_rdg (struct graph *);
/* Return the index of the variable VAR in the LOOP_NEST array. */
@@ -561,7 +583,21 @@ void lambda_collect_parameters (VEC (data_reference_p, heap) *,
bool lambda_compute_access_matrices (VEC (data_reference_p, heap) *,
VEC (tree, heap) *, int);
-/* In tree-data-refs.c */
+/* In tree-data-ref.c */
void split_constant_offset (tree , tree *, tree *);
+/* Strongly connected components of the reduced data dependence graph. */
+
+typedef struct rdg_component
+{
+ int num;
+ VEC (int, heap) *vertices;
+} *rdgc;
+
+DEF_VEC_P (rdgc);
+DEF_VEC_ALLOC_P (rdgc, heap);
+
+DEF_VEC_P (bitmap);
+DEF_VEC_ALLOC_P (bitmap, heap);
+
#endif /* GCC_TREE_DATA_REF_H */
diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h
index eec48d9183e..c75afb0d839 100644
--- a/gcc/tree-flow.h
+++ b/gcc/tree-flow.h
@@ -786,6 +786,8 @@ extern gimple get_single_def_stmt_with_phi (tree, gimple);
/* In tree-phinodes.c */
extern void reserve_phi_args_for_new_edge (basic_block);
+extern void add_phi_node_to_bb (gimple phi, basic_block bb);
+extern gimple make_phi_node (tree var, int len);
extern gimple create_phi_node (tree, basic_block);
extern void add_phi_arg (gimple, tree, edge);
extern void remove_phi_args (edge);
@@ -1023,6 +1025,7 @@ bool gimple_duplicate_loop_to_header_edge (struct loop *, edge,
int);
struct loop *slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *, edge);
void rename_variables_in_loop (struct loop *);
+void rename_variables_in_bb (basic_block bb);
struct loop *tree_ssa_loop_version (struct loop *, tree,
basic_block *);
tree expand_simple_operations (tree);
@@ -1116,6 +1119,10 @@ bool sra_type_can_be_decomposed_p (tree);
/* In tree-loop-linear.c */
extern void linear_transform_loops (void);
+extern unsigned perfect_loop_nest_depth (struct loop *);
+
+/* In graphite.c */
+extern void graphite_transform_loops (void);
/* In tree-data-ref.c */
extern void tree_check_data_deps (void);
diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c
index f0c55905060..928333ba4ba 100644
--- a/gcc/tree-into-ssa.c
+++ b/gcc/tree-into-ssa.c
@@ -130,12 +130,6 @@ static bitmap mem_syms_to_rename;
released after we finish updating the SSA web. */
static bitmap names_to_release;
-/* For each block, the PHI nodes that need to be rewritten are stored into
- these vectors. */
-typedef VEC(gimple, heap) *gimple_vec;
-DEF_VEC_P (gimple_vec);
-DEF_VEC_ALLOC_P (gimple_vec, heap);
-
static VEC(gimple_vec, heap) *phis_to_rewrite;
/* The bitmap of non-NULL elements of PHIS_TO_REWRITE. */
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index d86391e2af3..ed54cf32730 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -710,17 +710,6 @@ rdg_flag_loop_exits (struct graph *rdg, bitmap loops, bitmap partition,
}
}
-/* Strongly connected components of the reduced data dependence graph. */
-
-typedef struct rdg_component
-{
- int num;
- VEC (int, heap) *vertices;
-} *rdgc;
-
-DEF_VEC_P (rdgc);
-DEF_VEC_ALLOC_P (rdgc, heap);
-
/* Flag all the nodes of RDG containing memory accesses that could
potentially belong to arrays already accessed in the current
PARTITION. */
@@ -864,9 +853,6 @@ rdg_build_components (struct graph *rdg, VEC (int, heap) *starting_vertices,
BITMAP_FREE (saved_components);
}
-DEF_VEC_P (bitmap);
-DEF_VEC_ALLOC_P (bitmap, heap);
-
/* Aggregate several components into a useful partition that is
registered in the PARTITIONS vector. Partitions will be
distributed in different loops. */
diff --git a/gcc/tree-loop-linear.c b/gcc/tree-loop-linear.c
index 66d25ec1beb..7e5f298be16 100644
--- a/gcc/tree-loop-linear.c
+++ b/gcc/tree-loop-linear.c
@@ -272,7 +272,7 @@ try_interchange_loops (lambda_trans_matrix trans,
/* Return the number of nested loops in LOOP_NEST, or 0 if the loops
are not perfectly nested. */
-static unsigned int
+unsigned int
perfect_loop_nest_depth (struct loop *loop_nest)
{
struct loop *temp;
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index a3c9b26813f..7fe1510089a 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -322,6 +322,7 @@ extern struct gimple_opt_pass pass_iv_canon;
extern struct gimple_opt_pass pass_scev_cprop;
extern struct gimple_opt_pass pass_empty_loop;
extern struct gimple_opt_pass pass_record_bounds;
+extern struct gimple_opt_pass pass_graphite_transforms;
extern struct gimple_opt_pass pass_if_conversion;
extern struct gimple_opt_pass pass_loop_distribution;
extern struct gimple_opt_pass pass_vectorize;
diff --git a/gcc/tree-phinodes.c b/gcc/tree-phinodes.c
index 511e84bf9b9..7fd5a8f30cc 100644
--- a/gcc/tree-phinodes.c
+++ b/gcc/tree-phinodes.c
@@ -202,10 +202,9 @@ ideal_phi_node_len (int len)
return new_len;
}
-
/* Return a PHI node with LEN argument slots for variable VAR. */
-static gimple
+gimple
make_phi_node (tree var, int len)
{
gimple phi;
@@ -348,15 +347,12 @@ reserve_phi_args_for_new_edge (basic_block bb)
}
}
+/* Adds PHI to BB. */
-/* Create a new PHI node for variable VAR at basic block BB. */
-
-gimple
-create_phi_node (tree var, basic_block bb)
+void
+add_phi_node_to_bb (gimple phi, basic_block bb)
{
gimple_stmt_iterator gsi;
- gimple phi = make_phi_node (var, EDGE_COUNT (bb->preds));
-
/* Add the new PHI node to the list of PHI nodes for block BB. */
if (phi_nodes (bb) == NULL)
set_phi_nodes (bb, gimple_seq_alloc ());
@@ -367,6 +363,16 @@ create_phi_node (tree var, basic_block bb)
/* Associate BB to the PHI node. */
gimple_set_bb (phi, bb);
+}
+
+/* Create a new PHI node for variable VAR at basic block BB. */
+
+gimple
+create_phi_node (tree var, basic_block bb)
+{
+ gimple phi = make_phi_node (var, EDGE_COUNT (bb->preds));
+
+ add_phi_node_to_bb (phi, bb);
return phi;
}
diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c
index 8fbb27a5667..341f41cea52 100644
--- a/gcc/tree-ssa-loop-ivopts.c
+++ b/gcc/tree-ssa-loop-ivopts.c
@@ -5021,18 +5021,38 @@ create_new_ivs (struct ivopts_data *data, struct iv_ca *set)
}
}
+/* Returns the phi-node in BB with result RESULT. */
+
+static gimple
+get_phi_with_result (basic_block bb, tree result)
+{
+ gimple_stmt_iterator i = gsi_start_phis (bb);
+
+ for (; !gsi_end_p (i); gsi_next (&i))
+ if (gimple_phi_result (gsi_stmt (i)) == result)
+ return gsi_stmt (i);
+
+ gcc_unreachable ();
+ return NULL;
+}
+
+
/* Removes statement STMT (real or a phi node). If INCLUDING_DEFINED_NAME
is true, remove also the ssa name defined by the statement. */
static void
remove_statement (gimple stmt, bool including_defined_name)
{
- gimple_stmt_iterator bsi = gsi_for_stmt (stmt);
-
if (gimple_code (stmt) == GIMPLE_PHI)
- remove_phi_node (&bsi, including_defined_name);
+ {
+ gimple bb_phi = get_phi_with_result (gimple_bb (stmt),
+ gimple_phi_result (stmt));
+ gimple_stmt_iterator bsi = gsi_for_stmt (bb_phi);
+ remove_phi_node (&bsi, including_defined_name);
+ }
else
{
+ gimple_stmt_iterator bsi = gsi_for_stmt (stmt);
gsi_remove (&bsi, true);
release_defs (stmt);
}
diff --git a/gcc/tree-ssa-loop.c b/gcc/tree-ssa-loop.c
index ec3782a5450..51fc07c558a 100644
--- a/gcc/tree-ssa-loop.c
+++ b/gcc/tree-ssa-loop.c
@@ -287,6 +287,49 @@ struct gimple_opt_pass pass_linear_transform =
}
};
+/* GRAPHITE optimizations. */
+
+static unsigned int
+graphite_transforms (void)
+{
+ if (!current_loops)
+ return 0;
+
+ graphite_transform_loops ();
+
+ return 0;
+}
+
+static bool
+gate_graphite_transforms (void)
+{
+ /* Enable -fgraphite pass if any one of the graphite optimization flags
+ is turned on. */
+ if (flag_loop_block || flag_loop_interchange || flag_loop_strip_mine)
+ flag_graphite = 1;
+
+ return flag_graphite != 0;
+}
+
+struct gimple_opt_pass pass_graphite_transforms =
+{
+ {
+ GIMPLE_PASS,
+ "graphite", /* name */
+ gate_graphite_transforms, /* gate */
+ graphite_transforms, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_GRAPHITE_TRANSFORMS, /* tv_id */
+ PROP_cfg | PROP_ssa, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_verify_loops /* todo_flags_finish */
+ }
+};
+
/* Check the correctness of the data dependence analyzers. */
static unsigned int
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 474860adedb..40d1302c723 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -201,7 +201,7 @@ rename_use_op (use_operand_p op_p)
/* Renames the variables in basic block BB. */
-static void
+void
rename_variables_in_bb (basic_block bb)
{
gimple_stmt_iterator gsi;