mirror of
https://gcc.gnu.org/git/gcc.git
synced 2025-01-01 16:34:06 +08:00
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:
parent
6569e71643
commit
3d8864c06f
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
5583
gcc/omega.c
Normal file
File diff suppressed because it is too large
Load Diff
340
gcc/omega.h
Normal file
340
gcc/omega.h
Normal 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 */
|
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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")
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user