loop.texi: Document the Omega linear constraints solver.

* doc/loop.texi: Document the Omega linear constraints solver.
	* doc/invoke.texi: Document -fcheck-data-deps, omega-max-vars,
	omega-max-geqs, omega-max-eqs, omega-max-wild-cards, 
	omega-hash-table-size, omega-max-keys, and 
	omega-eliminate-redundant-constraints.
	* tree-pass.h (pass_check_data_deps): Declared.
	* omega.c: New.
	* omega.h: New.
	* timevar.def (TV_CHECK_DATA_DEPS): Declared.
	* tree-ssa-loop.c (check_data_deps, gate_check_data_deps, 
	pass_check_data_deps): New.
	* tree-data-ref.c (init_data_ref): Remove declaration.
	(dump_data_dependence_relation): Dump DDR_INNER_LOOP.
	(analyze_array): Renamed init_array_ref, move up initializations.
	(init_data_ref): Renamed init_pointer_ref.  Moved before its call.
	Removed arguments that are set to NULL.
	(analyze_indirect_ref): Correct indentation, correct call to 
	init_pointer_ref.
	(object_analysis): Call init_array_ref instead of analyze_array.
	(initialize_data_dependence_relation): Initialize DDR_INNER_LOOP.
	(access_functions_are_affine_or_constant_p): Use DR_ACCESS_FNS instead
	of DR_ACCESS_FNS_ADDR.
	(init_omega_eq_with_af, omega_extract_distance_vectors, 
	omega_setup_subscript, init_omega_for_ddr_1, init_omega_for_ddr,
	ddr_consistent_p): New.
	(compute_affine_dependence): Check consistency of ddrs when 
	flag_check_data_deps is passed.
	(analyze_all_data_dependences): Uncomment.
	(tree_check_data_deps): New.
	* tree-data-ref.h: Include omega.h.
	(DR_ACCESS_FNS_ADDR): Removed.
	(data_dependence_relation): Add inner_loop.
	(DDR_INNER_LOOP): New.
	* common.opt (fcheck-data-deps): New.
	* tree-flow.h (tree_check_data_deps): Declare.
	* Makefile.in (TREE_DATA_REF_H): Depend on omega.h.
	(OBJS-common): Depend on omega.o.
	(omega.o): Define.
	* passes.c (pass_check_data_deps): Scheduled.
	* params.def (PARAM_OMEGA_MAX_VARS, PARAM_OMEGA_MAX_GEQS, 
	PARAM_OMEGA_MAX_EQS, PARAM_OMEGA_MAX_WILD_CARDS,
	PARAM_OMEGA_HASH_TABLE_SIZE, PARAM_OMEGA_MAX_KEYS,
	PARAM_VECT_MAX_VERSION_CHECKS,
	PARAM_OMEGA_ELIMINATE_REDUNDANT_CONSTRAINTS): New.

From-SVN: r122749
This commit is contained in:
Sebastian Pop 2007-03-09 13:39:49 +01:00 committed by Sebastian Pop
parent 6569e71643
commit 3d8864c06f
15 changed files with 6773 additions and 93 deletions

View File

@ -1,3 +1,50 @@
2007-03-09 Sebastian Pop <sebastian.pop@inria.fr>
* doc/loop.texi: Document the Omega linear constraints solver.
* doc/invoke.texi: Document -fcheck-data-deps, omega-max-vars,
omega-max-geqs, omega-max-eqs, omega-max-wild-cards,
omega-hash-table-size, omega-max-keys, and
omega-eliminate-redundant-constraints.
* tree-pass.h (pass_check_data_deps): Declared.
* omega.c: New.
* omega.h: New.
* timevar.def (TV_CHECK_DATA_DEPS): Declared.
* tree-ssa-loop.c (check_data_deps, gate_check_data_deps,
pass_check_data_deps): New.
* tree-data-ref.c (init_data_ref): Remove declaration.
(dump_data_dependence_relation): Dump DDR_INNER_LOOP.
(analyze_array): Renamed init_array_ref, move up initializations.
(init_data_ref): Renamed init_pointer_ref. Moved before its call.
Removed arguments that are set to NULL.
(analyze_indirect_ref): Correct indentation, correct call to
init_pointer_ref.
(object_analysis): Call init_array_ref instead of analyze_array.
(initialize_data_dependence_relation): Initialize DDR_INNER_LOOP.
(access_functions_are_affine_or_constant_p): Use DR_ACCESS_FNS instead
of DR_ACCESS_FNS_ADDR.
(init_omega_eq_with_af, omega_extract_distance_vectors,
omega_setup_subscript, init_omega_for_ddr_1, init_omega_for_ddr,
ddr_consistent_p): New.
(compute_affine_dependence): Check consistency of ddrs when
flag_check_data_deps is passed.
(analyze_all_data_dependences): Uncomment.
(tree_check_data_deps): New.
* tree-data-ref.h: Include omega.h.
(DR_ACCESS_FNS_ADDR): Removed.
(data_dependence_relation): Add inner_loop.
(DDR_INNER_LOOP): New.
* common.opt (fcheck-data-deps): New.
* tree-flow.h (tree_check_data_deps): Declare.
* Makefile.in (TREE_DATA_REF_H): Depend on omega.h.
(OBJS-common): Depend on omega.o.
(omega.o): Define.
* passes.c (pass_check_data_deps): Scheduled.
* params.def (PARAM_OMEGA_MAX_VARS, PARAM_OMEGA_MAX_GEQS,
PARAM_OMEGA_MAX_EQS, PARAM_OMEGA_MAX_WILD_CARDS,
PARAM_OMEGA_HASH_TABLE_SIZE, PARAM_OMEGA_MAX_KEYS,
PARAM_VECT_MAX_VERSION_CHECKS,
PARAM_OMEGA_ELIMINATE_REDUNDANT_CONSTRAINTS): New.
2007-03-09 Richard Guenther <rguenther@suse.de>
PR tree-optimization/30904

View File

@ -785,7 +785,7 @@ DIAGNOSTIC_H = diagnostic.h diagnostic.def $(PRETTY_PRINT_H) options.h
C_PRETTY_PRINT_H = c-pretty-print.h $(PRETTY_PRINT_H) $(C_COMMON_H) $(TREE_H)
SCEV_H = tree-scalar-evolution.h $(GGC_H) tree-chrec.h $(PARAMS_H)
LAMBDA_H = lambda.h $(TREE_H) vec.h $(GGC_H)
TREE_DATA_REF_H = tree-data-ref.h $(LAMBDA_H)
TREE_DATA_REF_H = tree-data-ref.h $(LAMBDA_H) omega.h
VARRAY_H = varray.h $(MACHMODE_H) $(SYSTEM_H) coretypes.h $(TM_H)
TREE_INLINE_H = tree-inline.h $(VARRAY_H) $(SPLAY_TREE_H)
REAL_H = real.h $(MACHMODE_H)
@ -1028,6 +1028,7 @@ OBJS-common = \
lower-subreg.o \
mode-switching.o \
modulo-sched.o \
omega.o \
omp-low.o \
optabs.o \
options.o \
@ -2191,6 +2192,8 @@ omp-low.o : omp-low.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \
$(TREE_H) $(TREE_INLINE_H) $(DIAGNOSTIC_H) $(HASHTAB_H) \
$(TM_H) coretypes.h
omega.o : omega.c omega.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
errors.h $(GGC_H) $(TREE_H) diagnostic.h varray.h tree-pass.h
tree-chrec.o: tree-chrec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(GGC_H) $(TREE_H) $(REAL_H) $(SCEV_H) tree-pass.h $(PARAMS_H) \
$(DIAGNOSTIC_H) $(CFGLOOP_H) $(TREE_FLOW_H)

View File

@ -352,6 +352,10 @@ fcaller-saves
Common Report Var(flag_caller_saves) Optimization
Save registers around function calls
fcheck-data-deps
Common Report Var(flag_check_data_deps)
Compare the results of several data dependence analyzers.
fcommon
Common Report Var(flag_no_common,0) Optimization
Do not put uninitialized globals in the common section

View File

@ -350,6 +350,7 @@ Objective-C and Objective-C++ Dialects}.
-fvariable-expansion-in-unroller @gol
-ftree-pre -ftree-ccp -ftree-dce -ftree-loop-optimize @gol
-ftree-loop-linear -ftree-loop-im -ftree-loop-ivcanon -fivopts @gol
-fcheck-data-deps @gol
-ftree-dominator-opts -ftree-dse -ftree-copyrename -ftree-sink @gol
-ftree-ch -ftree-sra -ftree-ter -ftree-fre -ftree-vectorize @gol
-ftree-vect-loop-version -ftree-salias -fipa-pta -fweb @gol
@ -5447,6 +5448,10 @@ 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 -fcheck-data-deps
Compare the results of several data dependence analyzers. This option
is used for debugging the data dependence analyzers.
@item -ftree-loop-im
Perform loop invariant motion on trees. This pass moves only invariants that
would be hard to handle at RTL level (function calls, operations that expand to
@ -6450,6 +6455,34 @@ optimization when a new iv is added to the set.
Bound on size of expressions used in the scalar evolutions analyzer.
Large expressions slow the analyzer.
@item omega-max-vars
The maximum number of variables in an Omega constraint system.
The default value is 128.
@item omega-max-geqs
The maximum number of inequalities in an Omega constraint system.
The default value is 256.
@item omega-max-eqs
The maximum number of equalities in an Omega constraint system.
The default value is 128.
@item omega-max-wild-cards
The maximum number of wildcard variables that the Omega solver will
be able to insert. The default value is 18.
@item omega-hash-table-size
The size of the hash table in the Omega solver. The default value is
550.
@item omega-max-keys
The maximal number of keys used by the Omega solver. The default
value is 500.
@item omega-eliminate-redundant-constraints
When set to 1, use expensive methods to eliminate all redundant
constraints. The default value is 0.
@item vect-max-version-checks
The maximum number of runtime checks that can be performed when doing
loop versioning in the vectorizer. See option ftree-vect-loop-version

View File

@ -26,6 +26,7 @@ variable analysis and number of iterations analysis).
* Number of iterations:: Number of iterations analysis.
* Dependency analysis:: Data dependency analysis.
* Lambda:: Linear loop transformations framework.
* Omega:: A solver for linear programming problems.
@end menu
@node Loop representation
@ -623,3 +624,32 @@ Given a transformed loopnest, conversion back into gcc IR is done by
@code{lambda_loopnest_to_gcc_loopnest}. This function will modify the
loops so that they match the transformed loopnest.
@node Omega
@section Omega a solver for linear programming problems
@cindex Omega a solver for linear programming problems
The data dependence analysis contains several solvers triggered
sequentially from the less complex ones to the more sophisticated.
For ensuring the consistency of the results of these solvers, a data
dependence check pass has been implemented based on two different
solvers. The second method that has been integrated to GCC is based
on the Omega dependence solver, written in the 1990's by William Pugh
and David Wonnacott. Data dependence tests can be formulated using a
subset of the Presburger arithmetics that can be translated to linear
constraint systems. These linear constraint systems can then be
solved using the Omega solver.
The Omega solver is using Fourier-Motzkin's algorithm for variable
elimination: a linear constraint system containing @code{n} variables
is reduced to a linear constraint system with @code{n-1} variables.
The Omega solver can also be used for solving other problems that can
be expressed under the form of a system of linear equalities and
inequalities. The Omega solver is known to have an exponential worst
case, also known under the name of ``omega nightmare'' in the
literature, but in practice, the omega test is known to be efficient
for the common data dependence tests.
The interface used by the Omega solver for describing the linear
programming problems is described in @file{omega.h}, and the solver is
@code{omega_solve_problem}.

5583
gcc/omega.c Normal file

File diff suppressed because it is too large Load Diff

340
gcc/omega.h Normal file
View File

@ -0,0 +1,340 @@
/* Source code for an implementation of the Omega test, a integer
programming algorithm for dependence analysis, by William Pugh,
appeared in Supercomputing '91 and CACM Aug 92.
This code has no license restrictions, and is considered public
domain.
Changes copyright (C) 2005, 2006, 2007 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 2, 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 COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include "config.h"
#include "params.h"
#ifndef GCC_OMEGA_H
#define GCC_OMEGA_H
#define OMEGA_MAX_VARS PARAM_VALUE (PARAM_OMEGA_MAX_VARS)
#define OMEGA_MAX_GEQS PARAM_VALUE (PARAM_OMEGA_MAX_GEQS)
#define OMEGA_MAX_EQS PARAM_VALUE (PARAM_OMEGA_MAX_EQS)
#define pos_infinity (0x7ffffff)
#define neg_infinity (-0x7ffffff)
/* Results of the Omega solver. */
enum omega_result {
omega_false = 0,
omega_true = 1,
/* Value returned when the solver is unable to determine an
answer. */
omega_unknown = 2,
/* Value used for asking the solver to simplify the system. */
omega_simplify = 3
};
/* Values used for labeling equations. Private (not used outside the
solver). */
enum omega_eqn_color {
omega_black = 0,
omega_red = 1
};
/* Structure for equations. */
typedef struct eqn
{
int key;
int touched;
enum omega_eqn_color color;
/* Array of coefficients for the equation. The layout of the data
is as follows: coef[0] is the constant, coef[i] for 1 <= i <=
OMEGA_MAX_VARS, are the coefficients for each dimension. Examples:
the equation 0 = 9 + x + 0y + 5z is encoded as [9 1 0 5], the
inequality 0 <= -8 + x + 2y + 3z is encoded as [-8 1 2 3]. */
int *coef;
} *eqn;
typedef struct omega_pb
{
/* The number of variables in the system of equations. */
int num_vars;
/* Safe variables are not eliminated during the Fourier-Motzkin
simplification of the system. Safe variables are all those
variables that are placed at the beginning of the array of
variables: PB->var[1, ..., SAFE_VARS]. PB->var[0] is not used,
as PB->eqs[x]->coef[0] represents the constant of the equation. */
int safe_vars;
/* Number of elements in eqs[]. */
int num_eqs;
/* Number of elements in geqs[]. */
int num_geqs;
/* Number of elements in subs[]. */
int num_subs;
int hash_version;
bool variables_initialized;
bool variables_freed;
/* Index or name of variables. Negative integers are reserved for
wildcard variables. Maps the index of variables in the original
problem to the new index of the variable. The index for a
variable in the coef array of an equation can change as some
variables are eliminated. */
int *var;
int *forwarding_address;
/* Inequalities in the system of constraints. */
eqn geqs;
/* Equations in the system of constraints. */
eqn eqs;
/* A map of substituted variables. */
eqn subs;
} *omega_pb;
extern void omega_initialize (void);
extern omega_pb omega_alloc_problem (int, int);
extern enum omega_result omega_solve_problem (omega_pb, enum omega_result);
extern enum omega_result omega_simplify_problem (omega_pb);
extern enum omega_result omega_simplify_approximate (omega_pb);
extern enum omega_result omega_constrain_variable_sign (omega_pb,
enum omega_eqn_color,
int, int);
extern void debug_omega_problem (omega_pb);
extern void omega_print_problem (FILE *, omega_pb);
extern void omega_print_red_equations (FILE *, omega_pb);
extern int omega_count_red_equations (omega_pb);
extern void omega_pretty_print_problem (FILE *, omega_pb);
extern void omega_unprotect_variable (omega_pb, int var);
extern void omega_negate_geq (omega_pb, int);
extern void omega_convert_eq_to_geqs (omega_pb, int eq);
extern void omega_print_eqn (FILE *, omega_pb, eqn, bool, int);
extern bool omega_problem_has_red_equations (omega_pb);
extern enum omega_result omega_eliminate_redundant (omega_pb, bool);
extern void omega_eliminate_red (omega_pb, bool);
extern void omega_constrain_variable_value (omega_pb, enum omega_eqn_color,
int, int);
extern bool omega_query_variable (omega_pb, int, int *, int *);
extern int omega_query_variable_signs (omega_pb, int, int, int, int,
int, int, bool *, int *);
extern bool omega_query_variable_bounds (omega_pb, int, int *, int *);
extern void (*omega_when_reduced) (omega_pb);
extern void omega_no_procedure (omega_pb);
/* Return true when variable I in problem PB is a wildcard. */
static inline bool
omega_wildcard_p (omega_pb pb, int i)
{
return (pb->var[i] < 0);
}
/* Return true when variable I in problem PB is a safe variable. */
static inline bool
omega_safe_var_p (omega_pb pb, int i)
{
/* The constant of an equation is not a variable. */
gcc_assert (0 < i);
return (i <= pb->safe_vars);
}
/* Print to FILE equality E from PB. */
static inline void
omega_print_eq (FILE *file, omega_pb pb, eqn e)
{
omega_print_eqn (file, pb, e, false, 0);
}
/* Print to FILE inequality E from PB. */
static inline void
omega_print_geq (FILE *file, omega_pb pb, eqn e)
{
omega_print_eqn (file, pb, e, true, 0);
}
/* Print to FILE inequality E from PB. */
static inline void
omega_print_geq_extra (FILE *file, omega_pb pb, eqn e)
{
omega_print_eqn (file, pb, e, true, 1);
}
/* E1 = E2, make a copy of E2 into E1. Equations contain S variables. */
static inline void
omega_copy_eqn (eqn e1, eqn e2, int s)
{
e1->key = e2->key;
e1->touched = e2->touched;
e1->color = e2->color;
memcpy (e1->coef, e2->coef, (s + 1) * sizeof (int));
}
/* Intialize E = 0. Equation E contains S variables. */
static inline void
omega_init_eqn_zero (eqn e, int s)
{
e->key = 0;
e->touched = 0;
e->color = omega_black;
memset (e->coef, 0, (s + 1) * sizeof (int));
}
/* Allocate N equations with S variables. */
static inline eqn
omega_alloc_eqns (int s, int n)
{
int i;
eqn res = (eqn) (xcalloc (n, sizeof (struct eqn)));
for (i = n - 1; i >= 0; i--)
{
res[i].coef = (int *) (xcalloc (OMEGA_MAX_VARS + 1, sizeof (int)));
omega_init_eqn_zero (&res[i], s);
}
return res;
}
/* Free N equations from array EQ. */
static inline void
omega_free_eqns (eqn eq, int n)
{
int i;
for (i = n - 1; i >= 0; i--)
free (eq[i].coef);
free (eq);
}
/* Returns true when E is an inequality with a single variable. */
static inline bool
single_var_geq (eqn e, int nv ATTRIBUTE_UNUSED)
{
return (e->key != 0
&& -OMEGA_MAX_VARS <= e->key && e->key <= OMEGA_MAX_VARS);
}
/* Allocate a new equality with all coefficients 0, and tagged with
COLOR. Return the index of this equality in problem PB. */
static inline int
omega_add_zero_eq (omega_pb pb, enum omega_eqn_color color)
{
int idx = pb->num_eqs++;
gcc_assert (pb->num_eqs <= OMEGA_MAX_EQS);
omega_init_eqn_zero (&pb->eqs[idx], pb->num_vars);
pb->eqs[idx].color = color;
return idx;
}
/* Allocate a new inequality with all coefficients 0, and tagged with
COLOR. Return the index of this inequality in problem PB. */
static inline int
omega_add_zero_geq (omega_pb pb, enum omega_eqn_color color)
{
int idx = pb->num_geqs;
pb->num_geqs++;
gcc_assert (pb->num_geqs <= OMEGA_MAX_GEQS);
omega_init_eqn_zero (&pb->geqs[idx], pb->num_vars);
pb->geqs[idx].touched = 1;
pb->geqs[idx].color = color;
return idx;
}
/* Initialize variables for problem PB. */
static inline void
omega_initialize_variables (omega_pb pb)
{
int i;
for (i = pb->num_vars; i >= 0; i--)
pb->forwarding_address[i] = pb->var[i] = i;
pb->variables_initialized = true;
}
/* Free problem PB. */
static inline void
omega_free_problem (omega_pb pb)
{
free (pb->var);
free (pb->forwarding_address);
omega_free_eqns (pb->geqs, OMEGA_MAX_GEQS);
omega_free_eqns (pb->eqs, OMEGA_MAX_EQS);
omega_free_eqns (pb->subs, OMEGA_MAX_VARS + 1);
free (pb);
}
/* Copy omega problems: P1 = P2. */
static inline void
omega_copy_problem (omega_pb p1, omega_pb p2)
{
int e, i;
p1->num_vars = p2->num_vars;
p1->hash_version = p2->hash_version;
p1->variables_initialized = p2->variables_initialized;
p1->variables_freed = p2->variables_freed;
p1->safe_vars = p2->safe_vars;
p1->num_eqs = p2->num_eqs;
p1->num_subs = p2->num_subs;
p1->num_geqs = p2->num_geqs;
for (e = p2->num_eqs - 1; e >= 0; e--)
omega_copy_eqn (&(p1->eqs[e]), &(p2->eqs[e]), p2->num_vars);
for (e = p2->num_geqs - 1; e >= 0; e--)
omega_copy_eqn (&(p1->geqs[e]), &(p2->geqs[e]), p2->num_vars);
for (e = p2->num_subs - 1; e >= 0; e--)
omega_copy_eqn (&(p1->subs[e]), &(p2->subs[e]), p2->num_vars);
for (i = p2->num_vars; i >= 0; i--)
p1->var[i] = p2->var[i];
for (i = OMEGA_MAX_VARS; i >= 0; i--)
p1->forwarding_address[i] = p2->forwarding_address[i];
}
#endif /* GCC_OMEGA_H */

View File

@ -1,5 +1,6 @@
/* params.def - Run-time parameters.
Copyright (C) 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>.
This file is part of GCC.
@ -452,6 +453,41 @@ DEFPARAM(PARAM_SCEV_MAX_EXPR_SIZE,
"Bound on size of expressions used in the scalar evolutions analyzer",
20, 0, 0)
DEFPARAM(PARAM_OMEGA_MAX_VARS,
"omega-max-vars",
"Bound on the number of variables in Omega constraint systems",
128, 0, 0)
DEFPARAM(PARAM_OMEGA_MAX_GEQS,
"omega-max-geqs",
"Bound on the number of inequalities in Omega constraint systems",
256, 0, 0)
DEFPARAM(PARAM_OMEGA_MAX_EQS,
"omega-max-eqs",
"Bound on the number of equalities in Omega constraint systems",
128, 0, 0)
DEFPARAM(PARAM_OMEGA_MAX_WILD_CARDS,
"omega-max-wild-cards",
"Bound on the number of wild cards in Omega constraint systems",
18, 0, 0)
DEFPARAM(PARAM_OMEGA_HASH_TABLE_SIZE,
"omega-hash-table-size",
"Bound on the size of the hash table in Omega constraint systems",
550, 0, 0)
DEFPARAM(PARAM_OMEGA_MAX_KEYS,
"omega-max-keys",
"Bound on the number of keys in Omega constraint systems",
500, 0, 0)
DEFPARAM(PARAM_OMEGA_ELIMINATE_REDUNDANT_CONSTRAINTS,
"omega-eliminate-redundant-constraints",
"When set to 1, use expensive methods to eliminate all redundant constraints",
0, 0, 1)
DEFPARAM(PARAM_VECT_MAX_VERSION_CHECKS,
"vect-max-version-checks",
"Bound on number of runtime checks inserted by the vectorizer's loop versioning",

View File

@ -590,6 +590,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_scev_cprop);
NEXT_PASS (pass_empty_loop);
NEXT_PASS (pass_record_bounds);
NEXT_PASS (pass_check_data_deps);
NEXT_PASS (pass_linear_transform);
NEXT_PASS (pass_iv_canon);
NEXT_PASS (pass_if_conversion);

View File

@ -109,6 +109,7 @@ DEFTIMEVAR (TV_TREE_LOOP_UNSWITCH , "tree loop unswitching")
DEFTIMEVAR (TV_COMPLETE_UNROLL , "complete unrolling")
DEFTIMEVAR (TV_TREE_VECTORIZATION , "tree vectorization")
DEFTIMEVAR (TV_TREE_LINEAR_TRANSFORM , "tree loop linear")
DEFTIMEVAR (TV_CHECK_DATA_DEPS , "tree check data dependences")
DEFTIMEVAR (TV_TREE_PREFETCH , "tree prefetching")
DEFTIMEVAR (TV_TREE_LOOP_IVOPTS , "tree iv optimization")
DEFTIMEVAR (TV_TREE_LOOP_INIT , "tree loop init")

View File

@ -1,5 +1,5 @@
/* Data references and dependences detectors.
Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
Contributed by Sebastian Pop <pop@cri.ensmp.fr>
This file is part of GCC.
@ -125,10 +125,6 @@ static struct datadep_stats
static tree object_analysis (tree, tree, bool, struct data_reference **,
tree *, tree *, tree *, tree *, tree *,
struct ptr_info_def **, subvar_t *);
static struct data_reference * init_data_ref (tree, tree, tree, tree, bool,
tree, tree, tree, tree, tree,
struct ptr_info_def *,
enum data_ref_type);
static bool subscript_dependence_tester_1 (struct data_dependence_relation *,
struct data_reference *,
struct data_reference *);
@ -832,6 +828,7 @@ dump_data_dependence_relation (FILE *outf,
dump_subscript (outf, DDR_SUBSCRIPT (ddr, i));
}
fprintf (outf, " inner loop index: %d\n", DDR_INNER_LOOP (ddr));
fprintf (outf, " loop nest: (");
for (i = 0; VEC_iterate (loop_p, DDR_LOOP_NEST (ddr), i, loopi); i++)
fprintf (outf, "%d ", loopi->num);
@ -985,27 +982,24 @@ analyze_array_indexes (struct loop *loop,
set to true when REF is in the right hand side of an
assignment. */
struct data_reference *
analyze_array (tree stmt, tree ref, bool is_read)
static struct data_reference *
init_array_ref (tree stmt, tree ref, bool is_read)
{
struct data_reference *res;
VEC(tree,heap) *acc_fns;
struct loop *loop = loop_containing_stmt (stmt);
VEC(tree,heap) *acc_fns = VEC_alloc (tree, heap, 3);
struct data_reference *res = XNEW (struct data_reference);;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "(analyze_array \n");
fprintf (dump_file, "(init_array_ref \n");
fprintf (dump_file, " (ref = ");
print_generic_stmt (dump_file, ref, 0);
fprintf (dump_file, ")\n");
}
res = XNEW (struct data_reference);
DR_STMT (res) = stmt;
DR_REF (res) = ref;
acc_fns = VEC_alloc (tree, heap, 3);
DR_BASE_OBJECT (res) = analyze_array_indexes
(loop_containing_stmt (stmt), &acc_fns, ref, stmt);
DR_BASE_OBJECT (res) = analyze_array_indexes (loop, &acc_fns, ref, stmt);
DR_TYPE (res) = ARRAY_REF_TYPE;
DR_SET_ACCESS_FNS (res, acc_fns);
DR_IS_READ (res) = is_read;
@ -1023,6 +1017,45 @@ analyze_array (tree stmt, tree ref, bool is_read)
return res;
}
/* For a data reference REF contained in the statement STMT, initialize
a DATA_REFERENCE structure, and return it. */
static struct data_reference *
init_pointer_ref (tree stmt, tree ref, tree access_fn, bool is_read,
tree base_address, tree step, struct ptr_info_def *ptr_info)
{
struct data_reference *res = XNEW (struct data_reference);
VEC(tree,heap) *acc_fns = VEC_alloc (tree, heap, 3);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "(init_pointer_ref \n");
fprintf (dump_file, " (ref = ");
print_generic_stmt (dump_file, ref, 0);
fprintf (dump_file, ")\n");
}
DR_STMT (res) = stmt;
DR_REF (res) = ref;
DR_BASE_OBJECT (res) = NULL_TREE;
DR_TYPE (res) = POINTER_REF_TYPE;
DR_SET_ACCESS_FNS (res, acc_fns);
VEC_quick_push (tree, DR_ACCESS_FNS (res), access_fn);
DR_IS_READ (res) = is_read;
DR_BASE_ADDRESS (res) = base_address;
DR_OFFSET (res) = NULL_TREE;
DR_INIT (res) = NULL_TREE;
DR_STEP (res) = step;
DR_OFFSET_MISALIGNMENT (res) = NULL_TREE;
DR_MEMTAG (res) = NULL_TREE;
DR_PTR_INFO (res) = ptr_info;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, ")\n");
return res;
}
/* Analyze an indirect memory reference, REF, that comes from STMT.
IS_READ is true if this is an indirect load, and false if it is
an indirect store.
@ -1063,7 +1096,7 @@ analyze_indirect_ref (tree stmt, tree ref, bool is_read)
if (!expr_invariant_in_loop_p (loop, init))
{
if (dump_file && (dump_flags & TDF_DETAILS))
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\ninitial condition is not loop invariant.\n");
}
else
@ -1087,61 +1120,8 @@ analyze_indirect_ref (tree stmt, tree ref, bool is_read)
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nunknown evolution of ptr.\n");
}
return init_data_ref (stmt, ref, NULL_TREE, access_fn, is_read, base_address,
NULL_TREE, step, NULL_TREE, NULL_TREE,
ptr_info, POINTER_REF_TYPE);
}
/* For a data reference REF contained in the statement STMT, initialize
a DATA_REFERENCE structure, and return it. */
struct data_reference *
init_data_ref (tree stmt,
tree ref,
tree base,
tree access_fn,
bool is_read,
tree base_address,
tree init_offset,
tree step,
tree misalign,
tree memtag,
struct ptr_info_def *ptr_info,
enum data_ref_type type)
{
struct data_reference *res;
VEC(tree,heap) *acc_fns;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "(init_data_ref \n");
fprintf (dump_file, " (ref = ");
print_generic_stmt (dump_file, ref, 0);
fprintf (dump_file, ")\n");
}
res = XNEW (struct data_reference);
DR_STMT (res) = stmt;
DR_REF (res) = ref;
DR_BASE_OBJECT (res) = base;
DR_TYPE (res) = type;
acc_fns = VEC_alloc (tree, heap, 3);
DR_SET_ACCESS_FNS (res, acc_fns);
VEC_quick_push (tree, DR_ACCESS_FNS (res), access_fn);
DR_IS_READ (res) = is_read;
DR_BASE_ADDRESS (res) = base_address;
DR_OFFSET (res) = init_offset;
DR_INIT (res) = NULL_TREE;
DR_STEP (res) = step;
DR_OFFSET_MISALIGNMENT (res) = misalign;
DR_MEMTAG (res) = memtag;
DR_PTR_INFO (res) = ptr_info;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, ")\n");
return res;
return init_pointer_ref (stmt, ref, access_fn, is_read, base_address,
step, ptr_info);
}
/* Function strip_conversions
@ -1598,7 +1578,7 @@ object_analysis (tree memref, tree stmt, bool is_read,
if (!(*dr))
{
if (TREE_CODE (memref) == ARRAY_REF)
*dr = analyze_array (stmt, memref, is_read);
*dr = init_array_ref (stmt, memref, is_read);
else if (TREE_CODE (memref) == COMPONENT_REF)
comp_ref = memref;
else
@ -1671,7 +1651,7 @@ object_analysis (tree memref, tree stmt, bool is_read,
{
if (comp_ref && TREE_CODE (TREE_OPERAND (comp_ref, 0)) == ARRAY_REF)
{
*dr = analyze_array (stmt, TREE_OPERAND (comp_ref, 0), is_read);
*dr = init_array_ref (stmt, TREE_OPERAND (comp_ref, 0), is_read);
if (DR_NUM_DIMENSIONS (*dr) != 1)
{
if (dump_file && (dump_flags & TDF_DETAILS))
@ -2302,6 +2282,7 @@ initialize_data_dependence_relation (struct data_reference *a,
DDR_ARE_DEPENDENT (res) = NULL_TREE;
DDR_SUBSCRIPTS (res) = VEC_alloc (subscript_p, heap, DR_NUM_DIMENSIONS (a));
DDR_LOOP_NEST (res) = loop_nest;
DDR_INNER_LOOP (res) = 0;
DDR_DIR_VECTS (res) = NULL;
DDR_DIST_VECTS (res) = NULL;
@ -4176,10 +4157,10 @@ static bool
access_functions_are_affine_or_constant_p (struct data_reference *a)
{
unsigned int i;
VEC(tree,heap) **fns = DR_ACCESS_FNS_ADDR (a);
VEC(tree,heap) *fns = DR_ACCESS_FNS (a);
tree t;
for (i = 0; VEC_iterate (tree, *fns, i, t); i++)
for (i = 0; VEC_iterate (tree, fns, i, t); i++)
if (!evolution_function_is_constant_p (t)
&& !evolution_function_is_affine_multivariate_p (t))
return false;
@ -4187,6 +4168,530 @@ access_functions_are_affine_or_constant_p (struct data_reference *a)
return true;
}
/* Initializes an equation for an OMEGA problem using the information
contained in the ACCESS_FUN. Returns true when the operation
succeeded.
PB is the omega constraint system.
EQ is the number of the equation to be initialized.
OFFSET is used for shifting the variables names in the constraints:
a constrain is composed of 2 * the number of variables surrounding
dependence accesses. OFFSET is set either to 0 for the first n variables,
then it is set to n.
ACCESS_FUN is expected to be an affine chrec. */
static bool
init_omega_eq_with_af (omega_pb pb, unsigned eq,
unsigned int offset, tree access_fun,
struct data_dependence_relation *ddr)
{
switch (TREE_CODE (access_fun))
{
case POLYNOMIAL_CHREC:
{
tree left = CHREC_LEFT (access_fun);
tree right = CHREC_RIGHT (access_fun);
int var = CHREC_VARIABLE (access_fun);
unsigned var_idx;
if (TREE_CODE (right) != INTEGER_CST)
return false;
var_idx = index_in_loop_nest (var, DDR_LOOP_NEST (ddr));
pb->eqs[eq].coef[offset + var_idx + 1] = int_cst_value (right);
/* Compute the innermost loop index. */
DDR_INNER_LOOP (ddr) = MAX (DDR_INNER_LOOP (ddr), var_idx);
if (offset == 0)
pb->eqs[eq].coef[var_idx + DDR_NB_LOOPS (ddr) + 1]
+= int_cst_value (right);
switch (TREE_CODE (left))
{
case POLYNOMIAL_CHREC:
return init_omega_eq_with_af (pb, eq, offset, left, ddr);
case INTEGER_CST:
pb->eqs[eq].coef[0] += int_cst_value (left);
return true;
default:
return false;
}
}
case INTEGER_CST:
pb->eqs[eq].coef[0] += int_cst_value (access_fun);
return true;
default:
return false;
}
}
/* As explained in the comments preceding init_omega_for_ddr, we have
to set up a system for each loop level, setting outer loops
variation to zero, and current loop variation to positive or zero.
Save each lexico positive distance vector. */
static void
omega_extract_distance_vectors (omega_pb pb,
struct data_dependence_relation *ddr)
{
int eq, geq;
unsigned i, j;
struct loop *loopi, *loopj;
enum omega_result res;
/* Set a new problem for each loop in the nest. The basis is the
problem that we have initialized until now. On top of this we
add new constraints. */
for (i = 0; i <= DDR_INNER_LOOP (ddr)
&& VEC_iterate (loop_p, DDR_LOOP_NEST (ddr), i, loopi); i++)
{
int dist = 0;
omega_pb copy = omega_alloc_problem (2 * DDR_NB_LOOPS (ddr),
DDR_NB_LOOPS (ddr));
omega_copy_problem (copy, pb);
/* For all the outer loops "loop_j", add "dj = 0". */
for (j = 0;
j < i && VEC_iterate (loop_p, DDR_LOOP_NEST (ddr), j, loopj); j++)
{
eq = omega_add_zero_eq (copy, omega_black);
copy->eqs[eq].coef[j + 1] = 1;
}
/* For "loop_i", add "0 <= di". */
geq = omega_add_zero_geq (copy, omega_black);
copy->geqs[geq].coef[i + 1] = 1;
/* Reduce the constraint system, and test that the current
problem is feasible. */
res = omega_simplify_problem (copy);
if (res == omega_false
|| res == omega_unknown
|| copy->num_geqs > (int) DDR_NB_LOOPS (ddr))
goto next_problem;
for (eq = 0; eq < copy->num_subs; eq++)
if (copy->subs[eq].key == (int) i + 1)
{
dist = copy->subs[eq].coef[0];
goto found_dist;
}
if (dist == 0)
{
/* Reinitialize problem... */
omega_copy_problem (copy, pb);
for (j = 0;
j < i && VEC_iterate (loop_p, DDR_LOOP_NEST (ddr), j, loopj); j++)
{
eq = omega_add_zero_eq (copy, omega_black);
copy->eqs[eq].coef[j + 1] = 1;
}
/* ..., but this time "di = 1". */
eq = omega_add_zero_eq (copy, omega_black);
copy->eqs[eq].coef[i + 1] = 1;
copy->eqs[eq].coef[0] = -1;
res = omega_simplify_problem (copy);
if (res == omega_false
|| res == omega_unknown
|| copy->num_geqs > (int) DDR_NB_LOOPS (ddr))
goto next_problem;
for (eq = 0; eq < copy->num_subs; eq++)
if (copy->subs[eq].key == (int) i + 1)
{
dist = copy->subs[eq].coef[0];
goto found_dist;
}
}
found_dist:;
/* Save the lexicographically positive distance vector. */
if (dist >= 0)
{
lambda_vector dist_v = lambda_vector_new (DDR_NB_LOOPS (ddr));
lambda_vector dir_v = lambda_vector_new (DDR_NB_LOOPS (ddr));
dist_v[i] = dist;
for (eq = 0; eq < copy->num_subs; eq++)
if (copy->subs[eq].key > 0)
{
dist = copy->subs[eq].coef[0];
dist_v[copy->subs[eq].key - 1] = dist;
}
for (j = 0; j < DDR_NB_LOOPS (ddr); j++)
dir_v[j] = dir_from_dist (dist_v[j]);
save_dist_v (ddr, dist_v);
save_dir_v (ddr, dir_v);
}
next_problem:;
omega_free_problem (copy);
}
}
/* This is called for each subscript of a tuple of data references:
insert an equality for representing the conflicts. */
static bool
omega_setup_subscript (tree access_fun_a, tree access_fun_b,
struct data_dependence_relation *ddr,
omega_pb pb, bool *maybe_dependent)
{
int eq;
tree fun_a = chrec_convert (integer_type_node, access_fun_a, NULL_TREE);
tree fun_b = chrec_convert (integer_type_node, access_fun_b, NULL_TREE);
tree difference = chrec_fold_minus (integer_type_node, fun_a, fun_b);
/* When the fun_a - fun_b is not constant, the dependence is not
captured by the classic distance vector representation. */
if (TREE_CODE (difference) != INTEGER_CST)
return false;
/* ZIV test. */
if (ziv_subscript_p (fun_a, fun_b) && !integer_zerop (difference))
{
/* There is no dependence. */
*maybe_dependent = false;
return true;
}
fun_b = chrec_fold_multiply (integer_type_node, fun_b,
integer_minus_one_node);
eq = omega_add_zero_eq (pb, omega_black);
if (!init_omega_eq_with_af (pb, eq, DDR_NB_LOOPS (ddr), fun_a, ddr)
|| !init_omega_eq_with_af (pb, eq, 0, fun_b, ddr))
/* There is probably a dependence, but the system of
constraints cannot be built: answer "don't know". */
return false;
/* GCD test. */
if (DDR_NB_LOOPS (ddr) != 0 && pb->eqs[eq].coef[0]
&& !int_divides_p (lambda_vector_gcd
((lambda_vector) &(pb->eqs[eq].coef[1]),
2 * DDR_NB_LOOPS (ddr)),
pb->eqs[eq].coef[0]))
{
/* There is no dependence. */
*maybe_dependent = false;
return true;
}
return true;
}
/* Helper function, same as init_omega_for_ddr but specialized for
data references A and B. */
static bool
init_omega_for_ddr_1 (struct data_reference *dra, struct data_reference *drb,
struct data_dependence_relation *ddr,
omega_pb pb, bool *maybe_dependent)
{
unsigned i;
int ineq;
struct loop *loopi;
unsigned nb_loops = DDR_NB_LOOPS (ddr);
/* Insert an equality per subscript. */
for (i = 0; i < DDR_NUM_SUBSCRIPTS (ddr); i++)
{
if (!omega_setup_subscript (DR_ACCESS_FN (dra, i), DR_ACCESS_FN (drb, i),
ddr, pb, maybe_dependent))
return false;
else if (*maybe_dependent == false)
{
/* There is no dependence. */
DDR_ARE_DEPENDENT (ddr) = chrec_known;
return true;
}
}
/* Insert inequalities: constraints corresponding to the iteration
domain, i.e. the loops surrounding the references "loop_x" and
the distance variables "dx". The layout of the OMEGA
representation is as follows:
- coef[0] is the constant
- coef[1..nb_loops] are the protected variables that will not be
removed by the solver: the "dx"
- coef[nb_loops + 1, 2*nb_loops] are the loop variables: "loop_x".
*/
for (i = 0; i <= DDR_INNER_LOOP (ddr)
&& VEC_iterate (loop_p, DDR_LOOP_NEST (ddr), i, loopi); i++)
{
HOST_WIDE_INT nbi = estimated_loop_iterations_int (loopi, true);
/* 0 <= loop_x */
ineq = omega_add_zero_geq (pb, omega_black);
pb->geqs[ineq].coef[i + nb_loops + 1] = 1;
/* 0 <= loop_x + dx */
ineq = omega_add_zero_geq (pb, omega_black);
pb->geqs[ineq].coef[i + nb_loops + 1] = 1;
pb->geqs[ineq].coef[i + 1] = 1;
if (nbi != -1)
{
/* loop_x <= nb_iters */
ineq = omega_add_zero_geq (pb, omega_black);
pb->geqs[ineq].coef[i + nb_loops + 1] = -1;
pb->geqs[ineq].coef[0] = nbi;
/* loop_x + dx <= nb_iters */
ineq = omega_add_zero_geq (pb, omega_black);
pb->geqs[ineq].coef[i + nb_loops + 1] = -1;
pb->geqs[ineq].coef[i + 1] = -1;
pb->geqs[ineq].coef[0] = nbi;
/* A step "dx" bigger than nb_iters is not feasible, so
add "0 <= nb_iters + dx", */
ineq = omega_add_zero_geq (pb, omega_black);
pb->geqs[ineq].coef[i + 1] = 1;
pb->geqs[ineq].coef[0] = nbi;
/* and "dx <= nb_iters". */
ineq = omega_add_zero_geq (pb, omega_black);
pb->geqs[ineq].coef[i + 1] = -1;
pb->geqs[ineq].coef[0] = nbi;
}
}
omega_extract_distance_vectors (pb, ddr);
return true;
}
/* Sets up the Omega dependence problem for the data dependence
relation DDR. Returns false when the constraint system cannot be
built, ie. when the test answers "don't know". Returns true
otherwise, and when independence has been proved (using one of the
trivial dependence test), set MAYBE_DEPENDENT to false, otherwise
set MAYBE_DEPENDENT to true.
Example: for setting up the dependence system corresponding to the
conflicting accesses
| loop_i
| loop_j
| A[i, i+1] = ...
| ... A[2*j, 2*(i + j)]
| endloop_j
| endloop_i
the following constraints come from the iteration domain:
0 <= i <= Ni
0 <= i + di <= Ni
0 <= j <= Nj
0 <= j + dj <= Nj
where di, dj are the distance variables. The constraints
representing the conflicting elements are:
i = 2 * (j + dj)
i + 1 = 2 * (i + di + j + dj)
For asking that the resulting distance vector (di, dj) be
lexicographically positive, we insert the constraint "di >= 0". If
"di = 0" in the solution, we fix that component to zero, and we
look at the inner loops: we set a new problem where all the outer
loop distances are zero, and fix this inner component to be
positive. When one of the components is positive, we save that
distance, and set a new problem where the distance on this loop is
zero, searching for other distances in the inner loops. Here is
the classic example that illustrates that we have to set for each
inner loop a new problem:
| loop_1
| loop_2
| A[10]
| endloop_2
| endloop_1
we have to save two distances (1, 0) and (0, 1).
Given two array references, refA and refB, we have to set the
dependence problem twice, refA vs. refB and refB vs. refA, and we
cannot do a single test, as refB might occur before refA in the
inner loops, and the contrary when considering outer loops: ex.
| loop_0
| loop_1
| loop_2
| T[{1,+,1}_2][{1,+,1}_1] // refA
| T[{2,+,1}_2][{0,+,1}_1] // refB
| endloop_2
| endloop_1
| endloop_0
refB touches the elements in T before refA, and thus for the same
loop_0 refB precedes refA: ie. the distance vector (0, 1, -1)
but for successive loop_0 iterations, we have (1, -1, 1)
The Omega solver expects the distance variables ("di" in the
previous example) to come first in the constraint system (as
variables to be protected, or "safe" variables), the constraint
system is built using the following layout:
"cst | distance vars | index vars".
*/
static bool
init_omega_for_ddr (struct data_dependence_relation *ddr,
bool *maybe_dependent)
{
omega_pb pb;
bool res = false;
*maybe_dependent = true;
if (same_access_functions (ddr))
{
unsigned j;
lambda_vector dir_v;
/* Save the 0 vector. */
save_dist_v (ddr, lambda_vector_new (DDR_NB_LOOPS (ddr)));
dir_v = lambda_vector_new (DDR_NB_LOOPS (ddr));
for (j = 0; j < DDR_NB_LOOPS (ddr); j++)
dir_v[j] = dir_equal;
save_dir_v (ddr, dir_v);
/* Save the dependences carried by outer loops. */
pb = omega_alloc_problem (2 * DDR_NB_LOOPS (ddr), DDR_NB_LOOPS (ddr));
res = init_omega_for_ddr_1 (DDR_A (ddr), DDR_B (ddr), ddr, pb,
maybe_dependent);
omega_free_problem (pb);
return res;
}
/* Omega expects the protected variables (those that have to be kept
after elimination) to appear first in the constraint system.
These variables are the distance variables. In the following
initialization we declare NB_LOOPS safe variables, and the total
number of variables for the constraint system is 2*NB_LOOPS. */
pb = omega_alloc_problem (2 * DDR_NB_LOOPS (ddr), DDR_NB_LOOPS (ddr));
res = init_omega_for_ddr_1 (DDR_A (ddr), DDR_B (ddr), ddr, pb,
maybe_dependent);
omega_free_problem (pb);
/* Stop computation if not decidable, or no dependence. */
if (res == false || *maybe_dependent == false)
return res;
pb = omega_alloc_problem (2 * DDR_NB_LOOPS (ddr), DDR_NB_LOOPS (ddr));
res = init_omega_for_ddr_1 (DDR_B (ddr), DDR_A (ddr), ddr, pb,
maybe_dependent);
omega_free_problem (pb);
return res;
}
/* Return true when DDR contains the same information as that stored
in DIR_VECTS and in DIST_VECTS, return false otherwise. */
static bool
ddr_consistent_p (FILE *file,
struct data_dependence_relation *ddr,
VEC (lambda_vector, heap) *dist_vects,
VEC (lambda_vector, heap) *dir_vects)
{
unsigned int i, j;
/* If dump_file is set, output there. */
if (dump_file && (dump_flags & TDF_DETAILS))
file = dump_file;
if (VEC_length (lambda_vector, dist_vects) != DDR_NUM_DIST_VECTS (ddr))
{
lambda_vector b_dist_v;
fprintf (file, "\n(Number of distance vectors differ: Banerjee has %d, Omega has %d.\n",
VEC_length (lambda_vector, dist_vects),
DDR_NUM_DIST_VECTS (ddr));
fprintf (file, "Banerjee dist vectors:\n");
for (i = 0; VEC_iterate (lambda_vector, dist_vects, i, b_dist_v); i++)
print_lambda_vector (file, b_dist_v, DDR_NB_LOOPS (ddr));
fprintf (file, "Omega dist vectors:\n");
for (i = 0; i < DDR_NUM_DIST_VECTS (ddr); i++)
print_lambda_vector (file, DDR_DIST_VECT (ddr, i), DDR_NB_LOOPS (ddr));
fprintf (file, "data dependence relation:\n");
dump_data_dependence_relation (file, ddr);
fprintf (file, ")\n");
return false;
}
if (VEC_length (lambda_vector, dir_vects) != DDR_NUM_DIR_VECTS (ddr))
{
fprintf (file, "\n(Number of direction vectors differ: Banerjee has %d, Omega has %d.)\n",
VEC_length (lambda_vector, dir_vects),
DDR_NUM_DIR_VECTS (ddr));
return false;
}
for (i = 0; i < DDR_NUM_DIST_VECTS (ddr); i++)
{
lambda_vector a_dist_v;
lambda_vector b_dist_v = DDR_DIST_VECT (ddr, i);
/* Distance vectors are not ordered in the same way in the DDR
and in the DIST_VECTS: search for a matching vector. */
for (j = 0; VEC_iterate (lambda_vector, dist_vects, j, a_dist_v); j++)
if (lambda_vector_equal (a_dist_v, b_dist_v, DDR_NB_LOOPS (ddr)))
break;
if (j == VEC_length (lambda_vector, dist_vects))
{
fprintf (file, "\n(Dist vectors from the first dependence analyzer:\n");
print_dist_vectors (file, dist_vects, DDR_NB_LOOPS (ddr));
fprintf (file, "not found in Omega dist vectors:\n");
print_dist_vectors (file, DDR_DIST_VECTS (ddr), DDR_NB_LOOPS (ddr));
fprintf (file, "data dependence relation:\n");
dump_data_dependence_relation (file, ddr);
fprintf (file, ")\n");
}
}
for (i = 0; i < DDR_NUM_DIR_VECTS (ddr); i++)
{
lambda_vector a_dir_v;
lambda_vector b_dir_v = DDR_DIR_VECT (ddr, i);
/* Direction vectors are not ordered in the same way in the DDR
and in the DIR_VECTS: search for a matching vector. */
for (j = 0; VEC_iterate (lambda_vector, dir_vects, j, a_dir_v); j++)
if (lambda_vector_equal (a_dir_v, b_dir_v, DDR_NB_LOOPS (ddr)))
break;
if (j == VEC_length (lambda_vector, dist_vects))
{
fprintf (file, "\n(Dir vectors from the first dependence analyzer:\n");
print_dir_vectors (file, dir_vects, DDR_NB_LOOPS (ddr));
fprintf (file, "not found in Omega dir vectors:\n");
print_dir_vectors (file, DDR_DIR_VECTS (ddr), DDR_NB_LOOPS (ddr));
fprintf (file, "data dependence relation:\n");
dump_data_dependence_relation (file, ddr);
fprintf (file, ")\n");
}
}
return true;
}
/* This computes the affine dependence relation between A and B.
CHREC_KNOWN is used for representing the independence between two
accesses, while CHREC_DONT_KNOW is used for representing the unknown
@ -4219,13 +4724,57 @@ compute_affine_dependence (struct data_dependence_relation *ddr)
if (access_functions_are_affine_or_constant_p (dra)
&& access_functions_are_affine_or_constant_p (drb))
subscript_dependence_tester (ddr);
{
if (flag_check_data_deps)
{
/* Compute the dependences using the first algorithm. */
subscript_dependence_tester (ddr);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\n\nBanerjee Analyzer\n");
dump_data_dependence_relation (dump_file, ddr);
}
if (DDR_ARE_DEPENDENT (ddr) == NULL_TREE)
{
bool maybe_dependent;
VEC (lambda_vector, heap) *dir_vects, *dist_vects;
/* Save the result of the first DD analyzer. */
dist_vects = DDR_DIST_VECTS (ddr);
dir_vects = DDR_DIR_VECTS (ddr);
/* Reset the information. */
DDR_DIST_VECTS (ddr) = NULL;
DDR_DIR_VECTS (ddr) = NULL;
/* Compute the same information using Omega. */
if (!init_omega_for_ddr (ddr, &maybe_dependent))
goto csys_dont_know;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Omega Analyzer\n");
dump_data_dependence_relation (dump_file, ddr);
}
/* Check that we get the same information. */
if (maybe_dependent)
gcc_assert (ddr_consistent_p (stderr, ddr, dist_vects,
dir_vects));
}
}
else
subscript_dependence_tester (ddr);
}
/* As a last case, if the dependence cannot be determined, or if
the dependence is considered too difficult to determine, answer
"don't know". */
else
{
csys_dont_know:;
dependence_stats.num_dependence_undetermined++;
if (dump_file && (dump_flags & TDF_DETAILS))
@ -4584,7 +5133,7 @@ compute_data_dependences_for_loop (struct loop *loop,
}
/* Entry point (for testing only). Analyze all the data references
and the dependence relations.
and the dependence relations in LOOP.
The data references are computed first.
@ -4604,9 +5153,8 @@ compute_data_dependences_for_loop (struct loop *loop,
recompute the same information. The implementation of this KB is
transparent to the optimizer, and thus the KB can be changed with a
more efficient implementation, or the KB could be disabled. */
#if 0
static void
analyze_all_data_dependences (struct loops *loops)
analyze_all_data_dependences (struct loop *loop)
{
unsigned int i;
int nb_data_refs = 10;
@ -4616,8 +5164,8 @@ analyze_all_data_dependences (struct loops *loops)
VEC_alloc (ddr_p, heap, nb_data_refs * nb_data_refs);
/* Compute DDs on the whole function. */
compute_data_dependences_for_loop (loops->parray[0], false,
&datarefs, &dependence_relations);
compute_data_dependences_for_loop (loop, false, &datarefs,
&dependence_relations);
if (dump_file)
{
@ -4666,7 +5214,19 @@ analyze_all_data_dependences (struct loops *loops)
free_dependence_relations (dependence_relations);
free_data_refs (datarefs);
}
#endif
/* Computes all the data dependences and check that the results of
several analyzers are the same. */
void
tree_check_data_deps (void)
{
loop_iterator li;
struct loop *loop_nest;
FOR_EACH_LOOP (li, loop_nest, 0)
analyze_all_data_dependences (loop_nest);
}
/* Free the memory used by a data dependence relation DDR. */

View File

@ -1,5 +1,5 @@
/* Data references and dependences detectors.
Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
Contributed by Sebastian Pop <pop@cri.ensmp.fr>
This file is part of GCC.
@ -23,6 +23,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#define GCC_TREE_DATA_REF_H
#include "lambda.h"
#include "omega.h"
/*
The first location accessed by data-ref in the loop is the address of data-ref's
@ -160,10 +161,6 @@ DEF_VEC_ALLOC_P (data_reference_p, heap);
#define DR_OFFSET_MISALIGNMENT(DR) (DR)->misalignment
#define DR_PTR_INFO(DR) (DR)->ptr_info
#define DR_SUBVARS(DR) (DR)->subvars
#define DR_ACCESS_FNS_ADDR(DR) \
(DR_TYPE(DR) == ARRAY_REF_TYPE ? \
&((DR)->object_info.access_fns) : &((DR)->first_location.access_fns))
#define DR_SET_ACCESS_FNS(DR, ACC_FNS) \
{ \
if (DR_TYPE(DR) == ARRAY_REF_TYPE) \
@ -281,6 +278,10 @@ struct data_dependence_relation
/* The analyzed loop nest. */
VEC (loop_p, heap) *loop_nest;
/* An index in loop_nest for the innermost loop that varies for
this data dependence relation. */
unsigned inner_loop;
/* The classic direction vector. */
VEC (lambda_vector, heap) *dir_vects;
@ -304,6 +305,7 @@ DEF_VEC_ALLOC_P(ddr_p,heap);
/* The size of the direction/distance vectors: the number of loops in
the loop nest. */
#define DDR_NB_LOOPS(DDR) (VEC_length (loop_p, DDR_LOOP_NEST (DDR)))
#define DDR_INNER_LOOP(DDR) DDR->inner_loop
#define DDR_DIST_VECTS(DDR) ((DDR)->dist_vects)
#define DDR_DIR_VECTS(DDR) ((DDR)->dir_vects)

View File

@ -1,5 +1,6 @@
/* Data and Control Flow Analysis for Trees.
Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>
This file is part of GCC.
@ -993,6 +994,9 @@ bool sra_type_can_be_decomposed_p (tree);
/* In tree-loop-linear.c */
extern void linear_transform_loops (void);
/* In tree-data-ref.c */
extern void tree_check_data_deps (void);
/* In tree-ssa-loop-ivopts.c */
bool expr_invariant_in_loop_p (struct loop *, tree);
bool multiplier_allowed_in_address_p (HOST_WIDE_INT, enum machine_mode);

View File

@ -298,6 +298,7 @@ extern struct tree_opt_pass pass_rest_of_compilation;
extern struct tree_opt_pass pass_sink_code;
extern struct tree_opt_pass pass_fre;
extern struct tree_opt_pass pass_linear_transform;
extern struct tree_opt_pass pass_check_data_deps;
extern struct tree_opt_pass pass_copy_prop;
extern struct tree_opt_pass pass_store_ccp;
extern struct tree_opt_pass pass_store_copy_prop;

View File

@ -1,5 +1,5 @@
/* Loop optimizations over tree-ssa.
Copyright (C) 2003, 2005 Free Software Foundation, Inc.
Copyright (C) 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GCC.
@ -241,6 +241,41 @@ struct tree_opt_pass pass_linear_transform =
0 /* letter */
};
/* Check the correctness of the data dependence analyzers. */
static unsigned int
check_data_deps (void)
{
if (!current_loops)
return 0;
tree_check_data_deps ();
return 0;
}
static bool
gate_check_data_deps (void)
{
return flag_check_data_deps != 0;
}
struct tree_opt_pass pass_check_data_deps =
{
"ckdd", /* name */
gate_check_data_deps, /* gate */
check_data_deps, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
TV_CHECK_DATA_DEPS, /* tv_id */
PROP_cfg | PROP_ssa, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
0 /* letter */
};
/* Canonical induction variable creation pass. */
static unsigned int