This commit is contained in:
2025-03-12 12:37:19 +03:00
parent 1c851baa7e
commit 6a4040be3e
426 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
# in maple_interface.c include vfork.h
#SUN#CEXTRA=-DSUN=1
# Directory where sigma is installed (used to find include files and libraries)
# DEFINE sigma_prefix as the path to the directory containing sigma
sigma_prefix = ../../../sage/Beta/sigma
sigma_lib = $(sigma_prefix)/lib
# Directory where tool box is installed
# DEFINE sigma_prefix as the path to the directory containing sigma toolc++
toolc++_prefix = .
# Directory in which to put toolc++ library
toolc++_libdir = .
# Directory in which include file can be found
toolc++_include = .
#
CC = gcc
INCLUDE = -I./include -I.
# -w don't issue warning now.
CFLAGS = $(INCLUDE) -g
LDFLAGS =
OMEGA_SRC = add-assert.c cover.c ddomega-build.c ddomega.c kill.c affine.c sagedriver.c ddomega-use.c debug.c ip.c refine.c
OMEGA_HDR = ./include/add-assert.h ./include/ddomega-use.h ./include/kill.h ./include/refine.h ./include/affine.h ./include/ddomega.h ./include/cover.h ./include/debug.h ./include/lang-interf.h ./include/ddomega-build.h ./include/ip.h ./include/portable.h
OMEGA_OBJ = add-assert.o cover.o ddomega-build.o ddomega.o kill.o affine.o sagedriver.o ddomega-use.o debug.o ip.o refine.o
testq: $(OMEGA_OBJ)
# $(CC) $(OMEGA_OBJ) -o testdebug -lm -lcurses -ltermcap
add-assert.o : $(OMEGA_HDR)
$(CC) $(CFLAGS) -c add-assert.c
cover.o : $(OMEGA_HDR)
$(CC) $(CFLAGS) -c cover.c
ddomega-build.o : $(OMEGA_HDR)
$(CC) $(CFLAGS) -c ddomega-build.c
ddomega.o: $(OMEGA_HDR)
$(CC) $(CFLAGS) -c ddomega.c
kill.o : $(OMEGA_HDR)
$(CC) $(CFLAGS) -c kill.c
affine.o : $(OMEGA_HDR)
$(CC) $(CFLAGS) -c affine.c
sagedriver.o : $(OMEGA_HDR) sagedriver.c
$(CC) $(CFLAGS) -c sagedriver.c
ddomega-use.o : $(OMEGA_HDR)
$(CC) $(CFLAGS) -c ddomega-use.c
debug.o: $(OMEGA_HDR)
$(CC) $(CFLAGS) -c debug.c
ip.o : $(OMEGA_HDR)
$(CC) $(CFLAGS) -c ip.c
refine.o: $(OMEGA_HDR)
$(CC) $(CFLAGS) -c refine.c
clean:
rm -rf $(OMEGA_OBJ) testdebug

View File

@@ -0,0 +1,193 @@
This is the code for the Omega Test. The interface for sage consists
in the file sagedriver.c and the include file lang-interf.h.
This is a preliminary interface, It does not use yet all the capabilities
of the omega test. More should follow.
Foloowing the original README for the tiny/omega test distribution.
********************************************************************
README file for omega/tiny distribution
README,v 1.1 1993/09/17 22:13:45 fbodin Exp
********************************************************************
This is the readme file for version 3.0.0 of the distribution of the Omega
test, which is available via anonymous ftp from ftp.cs.umd.edu (128.8.128.8)
in the directory pub/omega.
This release consists of three components:
* The Omega test: A system for performing symbolic
manipulations of conjunctions of linear constraints
over integer variables. In particular, the operations
supported include:
* Checking if integer solutions exist
* Eliminating an existential quantifier. For example,
we can transform
{ Exists b s.t. 0 <= a <= 5; b < a <= 5b}
to
{ 2 <= a <= 5}
* Checking to see if one set of constraints implies
another. For example, we can check to see if:
{0 <= x <= 3; -3 <= 2y <= 3} => {0 <= x+y, x-y <= 3}
The interface to the Omega test is described
in the file doc/omega_interface.tex
* The Omega test dependence analyzer: A system built on top
of the Omega test to analyze array data dependences. This
system builds the appropriate problems and makes the appropriate
queries of the Omega test to analyze array-based data dependences
in programs. The analyzer computes data difference/direction
vectors, recognizes reduction dependences, analyzes array kills
(which enables array expansion and array privatization),
and determines when assertions can be used to eliminate dependences.
We have attempted to define an interface that allows other users
to make use of the Omega test dependence analyzer. This interface
is described in include/lang-interf.generic and Lang-Interf3.0
(keep in touch if you plan to use this interface; we are continuing
to refine it).
* Extended tiny. We have extended Michael Wolfe's tiny tool. The
major extensions are:
* Improved user interface (scrolling, dependence browsing
windows)
* Capabilities that improve the accuracy of data dependence
analysis (induction variable recognition, forward
substitution).
* Features that demonstrate the additional information we
collect (scalar/array expansion and privatization,
interactive dependence zapping)
* An semi-automatic procedure for converting FORTRAN programs
into tiny
* A prototype implementation of a unified framework
for reordering transformations. The framework
unifies loop interchange, skewing, distribution,
fusion, reversal, statement reordering, and some
cases of access normalization, loop alignment, loop
peeling and index set splitting.
The Omega test is implemented on top of the December 1990 version of
Michael Wolfe's tiny program, as well as in a stand-alone test driver.
The Omega test computes exact data dependence information, including checks
for array kills. The Omega test data dependence analyzer is substantially
more accurate than dependence analyzers in many existing research
and commercial systems.
Tiny is a research implementation of an interactive program
restructuring tool. Tiny computes data dependence relations
and interactively performs many restructuring transformations, such
as loop interchanging, distribution, skewing, ... . Michael Wolfe
has put his tiny tool into the public domain, which allowed
us to build on top of his software. We are very grateful for Michael's
contributions.
This implementation is a research prototype and has not been subjected
to rigorous testing. In other words:
THERE ARE BUGS IN THIS SOFTWARE
We don't know of any at the moment (other that the ones listed
under KNOWN BUGS/LIMITATIONS below), but we are sure that other,
undiscovered bugs remain in the software. This software has been
put into the public domain as a public service on an "as-is"
basis, without warranty or liability.
Since this version incorporates a large number of major new features,
there will almost certain be bug fixes that will be shortly released as
version 3.0.1.
If you register with us as someone who has a copy of the Omega test,
we will send you update notices. Send email to omega@cs.umd.edu to
be added to the list of registered users.
We are committed to continued distribution and support of the Omega
test for other researchers, and a number of research groups are already
incorporating the Omega test into their compilers and programming
environments. We welcome any additional researchers. Please stay
in contact with us if you plan to make serious us of the Omega test so
that we can provide you with updates and get feedback from your use.
The implementation of the Omega test and extensions to tiny have
been done by a number of people at the University of Maryland:
William Pugh
Dave Wonnacott
Udayan Borkar
Wayne Kelly
Jerry Sobieski
Vadim Maslov
This software is public domain, and no legal restrictions of any
kind whatsoever are placed on uses of it). You may do whatever you want
with it, and no guarantees of any kind are made about its performance or
lack of errors. You can copy it, use it, incorporate it or even sell it.
We request that any research or products that make use of this software
acknowledge that use and that you keep us informed of your use.
Please send mail to omega@cs.umd.edu if you wish to be added to a mailing
list for people interesting in using this software. We will notify
people on the mail list of bug fixes and new releases.
Also send mail to omega@cs.umd.edu if you have any trouble installing
the software, bug reports or questions.
Our work on this software has been supported by NSF grants CCR-8908900 and
CCR-9157384 and by a Packard Fellowship, as well as being based on
Michael Wolfe's original implementation of tiny.
FILES
-----
The following tar files can be ftp-ed from ftp.cs.umd.edu (128.8.128.8)
from the directory pub/omega:
* README This file
* WOLFE_README The readme file that originally accompanied Michael Wolfe's
distributing of tiny
* src.tar.Z Source for the omega test and our enhanced version of tiny
* sparc_demo.tar.Z Sun Sparc executable versions of the programs that can be
made from the src files, demo files, and documentation of
of how to use our extended version of tiny.
* dec3100_demo.tar.Z Decstations 3100 executable versions of the programs that
can be made from the src files. demo files, and documentation of
of how to use our extended version of tiny.
* demo.tar.Z Test files for demos
* rt.tar.Z Regression test files
* doc.tar.Z Documentation
* techReports A directory containing postscript and dvi copies of
relevant tech reports.
Together, these tar files constitute the entire tiny system, with the
following directories:
* include header files (from src.tar.Z)
* src source code (from src.tar.Z)
* obj makefile (from src.tar.Z), generated files (from sparc_bin.tar)
* doc documentation for tiny and for other drivers for the omega test
* demo sample files documented to show features of the Omega test and
extended tiny
* f2t A FORTRAN to tiny converter based on f2c
* rt regression test sample files and expected results
* misc shell scripts used for regression testing (rt.tar and src.tar)
The executable programs are:
* "t" the tiny environment, upgraded to use the omega test and
test for refinement, killing, and covering of dependences
* "f2t" A FORTRAN to tiny converter based on f2c

View File

@@ -0,0 +1,506 @@
/* add-assert.c,v 1.1 1993/09/17 22:13:46 fbodin Exp */
#include <assert.h>
#include <string.h>
#include <stdlib.h>
/* #include "portable.h"
#include "lang-interf.h"*/
#include "include/add-assert.h"
#include "include/ddomega.h"
#include "include/ddomega-build.h"
#include "include/ip.h"
#include "include/debug.h"
#include "include/flags.h"
//#include "include/screen.h"
#include "include/Exit.h"
/*
#include "message.h"
#include "getword.h"
#include "timeTrials.h"
*/
/*
zap problem description contains information needed
to associate variable accesses in the tiny program with
variables in the integer programming problem that is
used to try determine the gist of the dependence.
zap problems are very much like delta problems,
except that there are no deltas and the symbolic constants
are protected
*/
typedef struct {
range nonloops; /* symbolic constants */
range deltas; /* deltas for common indices */
range access1s; /* index variables for access 1 */
range access2s; /* index variables for access 2 */
range steps1; /* step constraints for a1 */
range steps2; /* step constraints for a1 */
var_id vars[maxVars];
} zap_prob_desc;
#define zap_Nvars(zpd) (r_last(&(zpd)->steps2))
#if !defined NDEBUG
static int is_step_expr(var_id n)
{
return n == 0;
}
static void zap_inv(zap_prob_desc *zpd, Problem *p)
{
int v;
assert(p->getVarsN() < maxVars);
assert(p->getVarsN() >= zap_Nvars(zpd));
assert(p->_safeVars == r_length(&zpd->nonloops));
assert(r_first(&zpd->nonloops) == 1);
assert(r_last(&zpd->nonloops) + 1 == r_first(&zpd->access1s));
assert(r_last(&zpd->access1s) + 1 == r_first(&zpd->access2s));
assert(r_last(&zpd->access2s) + 1 == r_first(&zpd->steps1));
assert(r_last(&zpd->steps1) + 1 == r_first(&zpd->steps2));
for (v = 0; v < r_length(&zpd->access1s); v++) {
assert(var_id_index_p(zpd->vars[v + r_first(&zpd->access1s)]));
assert(var_ids_loop_no(zpd->vars[v + r_first(&zpd->access1s)]) == v + 1);
}
for (v = 0; v < r_length(&zpd->access2s); v++) {
assert(var_id_index_p(zpd->vars[v + r_first(&zpd->access2s)]));
assert(var_ids_loop_no(zpd->vars[v + r_first(&zpd->access2s)]) == v + 1);
}
for (v = 0; v < r_length(&zpd->nonloops); v++) {
assert(var_id_const_p(zpd->vars[v + r_first(&zpd->nonloops)]));
assert((var_ids_tag(zpd->vars[v + r_first(&zpd->nonloops)]) ==
v + r_first(&zpd->nonloops)) ||
(var_ids_tag(zpd->vars[v + r_first(&zpd->nonloops)]) == UNTAGGED));
}
for (v = 0; v < r_length(&zpd->steps1); v++) {
assert(is_step_expr(zpd->vars[v + r_first(&zpd->steps1)]));
}
for (v = 0; v < r_length(&zpd->steps2); v++) {
assert(is_step_expr(zpd->vars[v + r_first(&zpd->steps2)]));
}
for (v = 0; v < p->getNumGEqs(); v++) {
assert(p->_GEQs[v].touched);
}
}
#endif
#define MaxNameLen 254
#define MaxSuffixLen 1
static char *zap_getVarName(uint v, void *args)
{
zap_prob_desc *zpd = (zap_prob_desc*)args;
static char name[MaxNameLen + MaxSuffixLen + 1];
assert(v <= zap_Nvars(zpd));
if (zpd->vars[v] &&
(var_id_index_p(zpd->vars[v]) || var_id_const_p(zpd->vars[v])))
{
strncpy(name, var_ids_name(zpd->vars[v]), MaxNameLen);
name[MaxNameLen] = 0;
}
else {
assert(is_step_expr(zpd->vars[v]));
strcpy(name, "<trip>");
}
if (r_in(&zpd->access1s, v) || r_in(&zpd->steps1, v))
strcat(name, "1");
else if (r_in(&zpd->access2s, v) || r_in(&zpd->steps2, v))
strcat(name, "2");
return name;
}
/*
set up all fields in zap_prob_desc
copy info from a1_vars, a2_vars, and sc_vars into "omega_vars"
a1_vars and a2_vars have been set by load_bounds_and_count_steps
that is, they run from element 1 to depth+Nsteps
sc_vars have been set up by the load_constants functions
it runs from 0 to Nconsts - 1
change tags on nodes for symbolic constants to be the
indices into "vars" -- that is, the indices in the IP variable array
change order of steps to be outer loop to inner and
adjust tags accordingly (this way the common loop steps
can (and will) be aligned)
add equalities for the definitions of the deltas to p
*/
static void zap_init(zap_prob_desc *zpd, Problem *p,
uint Na1, var_id a1_vars[],
uint Na2, var_id a2_vars[],
uint Nsc, var_id sc_vars[],
uint Ns1, var_id s1_vars[],
uint Ns2, var_id s2_vars[])
{
int v;
zpd->nonloops._first = 1;
zpd->nonloops._length = Nsc;
zpd->access1s._first = 1 + Nsc;
zpd->access1s._length = Na1;
zpd->access2s._first = 1 + Nsc + Na1;
zpd->access2s._length = Na2;
zpd->steps1._first = 1 + Nsc + Na1 + Na2;
zpd->steps1._length = Ns1;
zpd->steps2._first = 1 + Nsc + Na1 + Na2 + Ns1;
zpd->steps2._length = Ns2;
if (zap_Nvars(zpd) > maxVars) {
assert(0 && "Problem too big");
fprintf(stderr, "Too many variables for omega test\n");
Exit(2);
/* We really should add all possible dependencies here */
}
zpd->vars[0] = 0;
/* a1[1..Na1] and a2[1..Na2] are valid */
for (v = 0; v < r_length(&zpd->access1s); v++) {
assert(a1_vars[v + 1] != NIL);
zpd->vars[v + r_first(&zpd->access1s)] = a1_vars[v + 1];
}
for (v = 0; v < r_length(&zpd->access2s); v++) {
assert(a2_vars[v + 1] != NIL);
zpd->vars[v + r_first(&zpd->access2s)] = a2_vars[v + 1];
}
/* sc_vars[0..Nsc-1] are valid */
for (v = 0; v < Nsc; v++) {
assert(sc_vars[v] != NIL);
zpd->vars[v + r_first(&zpd->nonloops)] = sc_vars[v];
var_ids_tag(sc_vars[v]) = v + r_first(&zpd->nonloops);
}
/* s1_vars[0..Ns1] and s2_vars[0..Ns2] hold steps
FROM INNERMOST TO OUTERMOST LOOPS */
for (v = 0; v < Ns1; v++) {
assert(s1_vars[Ns1 - 1 - v] == NIL);
zpd->vars[v + r_first(&zpd->steps1)] = s1_vars[Ns1 - 1 - v];
}
for (v = 0; v < Ns2; v++) {
assert(s2_vars[Ns2 - 1 - v] == NIL);
zpd->vars[v + r_first(&zpd->steps2)] = s2_vars[Ns2 - 1 - v];
}
init_prob(p, zap_Nvars(zpd), Nsc, zap_getVarName, zpd);
#if ! defined NDEBUG
zap_inv(zpd, p);
#endif
}
/* clear the tags for symbolic constants */
static void zap_cleanup(zap_prob_desc *zpd)
{
int v;
for (v = 0; v < r_length(&zpd->nonloops); v++) {
var_ids_tag(zpd->vars[v + r_first(&zpd->nonloops)]) = UNTAGGED;
}
}
static char *geq_as_string(Problem *p, int geq)
{
static char buf[81];
sprintEqn(buf, p, &p->_GEQs[geq], 1, 0);
return buf;
}
static int find_reds(Problem *p, int reds[])
{
int i, n_reds = 0;
for (i = 0; i < p->getNumGEqs(); i++) {
if (p->_GEQs[i].color == red) {
reds[n_reds++] = i;
}
}
return n_reds;
}
/* find, and try to get rid of a red in p */
#if 0
static bool mccarthy(Problem *p, var_id vars[])
{
WINDOW *gist_w;
int Gist_Lines, Gist_Cols, Gist_Offset;
int reds[maxGEQs]; /* only handle GEQs now */
int y, x, i;
int n_reds, zappee;
bool check;
check = hasRedEquations(p, 1);
assert(check);
n_reds = find_reds(p, reds);
assert(n_reds > 0); /* this seems the right assertion for McCarthy */
Gist_Lines = n_reds + 5;
Gist_Cols = COLS;
Gist_Offset = 0;
gist_w = newwin(Gist_Lines, Gist_Cols, Gist_Offset, 0);
if (!gist_w) {
Message_Add("couldn't create window for equations.");
screen_update();
return 0;
}
for (x = 1; x < Gist_Cols; x++) screen_waddch(gist_w, 0, x, '-');
for (x = 1; x < Gist_Cols; x++) screen_waddch(gist_w, 2, x, '-');
for (y = 1; y < Gist_Lines; y++) screen_waddch(gist_w, y, 0, '|');
for (y = 1; y < Gist_Lines; y++) screen_waddch(gist_w, y, Gist_Cols - 1, '|');
for (x = 1; x < Gist_Cols; x++) screen_waddch(gist_w, Gist_Lines - 1, x, '-');
screen_waddch(gist_w, 0, 0, '+');
screen_waddch(gist_w, 0, Gist_Cols - 1, '+');
screen_waddch(gist_w, 2, 0, '+');
screen_waddch(gist_w, 2, Gist_Cols - 1, '+');
screen_waddch(gist_w, Gist_Lines - 1, 0, '+');
screen_waddch(gist_w, Gist_Lines - 1, Gist_Cols - 1, '+');
for (i = 0; i < n_reds; i++)
negateGEQ(p, reds[i]);
screen_wprint(gist_w, 1, 1, "%s",
"Which of the following is always true (0 for none)? ");
for (i = 0; i < n_reds; i++)
{
sint j, length;
char eqn_string[80];
strcpy(eqn_string, geq_as_string(p, reds[i]));
length = strlen(eqn_string);
for (j = 1; j < length - 1; j++)
eqn_string[j - 1] = eqn_string[j];
eqn_string[length - 2] = '\0';
screen_wprint(gist_w, i + 3, 1, "%2d: %-60s\n", i + 1, eqn_string);
}
do
zappee = getint(gist_w, 1, 53);
while (zappee < 0 || zappee > n_reds);
if (zappee != 0)
add_GEQ_assertion(p, vars, reds[zappee - 1]);
delwin(gist_w);
screen_touch();
#if ! defined NOT_TINY
print_tiny(Entry, 1, 0);
#endif
return zappee != 0;
}
#endif
/*
try to build the gist problem
return 1 if it has symbolic constants and there are red equations
NOTE that reduceWithSubs must be 0
*/
static elimination_possible
build_zap_problem(dd_current dd, Problem *p, zap_prob_desc *zpd)
{
var_id consts[maxVars],
a1vars[maxVars], a2vars[maxVars],
steps1[maxVars], steps2[maxVars];
int Nconsts, Nsteps1, Nsteps2;
a_access access1 = dd_current_src(dd), access2 = dd_current_dest(dd);
uint nest1 = accesss_depth(access1), nest2 = accesss_depth(access2);
int j;
assert(!reduceWithSubs);
if (omegaPrintResult == 1) {
fprintf(debug2, "\n\nZap: Finding Gist of dependence:\n");
fprintf(debug2, "%s\n", dd_current_as_string(dd));
}
#if defined newTimeTrials
if (storeResult) zapTests++;
#endif
/* BUILD PROBLEM "p": put things we know as black equations,
and things we know only if there is a dependence as red equations */
/* PART 1: find sets of variables to be used in problem */
Nsteps1 = Nsteps2 = Nconsts = 0;
load_bounds_and_count_steps(access1, a1vars, steps1, &Nsteps1);
load_bounds_and_count_steps(access2, a2vars, steps2, &Nsteps2);
load_constants_for_bounds(access1, consts, &Nconsts);
load_constants_for_bounds(access2, consts, &Nconsts);
load_constants_for_subscripts(access1, consts, &Nconsts);
load_constants_for_subscripts(access2, consts, &Nconsts);
/* PART 2: assign columns to variables */
zap_init(zpd, p,
nest1, a1vars, nest2, a2vars, Nconsts, consts,
Nsteps1, steps1, Nsteps2, steps2);
if (Nconsts == 0)
{
assert(p->_safeVars == 0);
zap_cleanup(zpd);
if (omegaPrintResult == 1) {
fprintf(debug2, "Zap: No symbolic constants, no way to zap.\n");
}
return impossible;
}
#if ! defined NDEBUG
zap_inv(zpd, p);
#endif
/* PART 3: build problem */
/* add what we know if dd exists as red equations */
equate_subscripts(p, &zpd->access1s, &zpd->access2s, &zpd->nonloops,
red, access1, access2);
/* we don't have to bail out if there are non-affine
subscript expressions - that just gives us fewer
(possibly 0) ways to kill */
/* black equations: things that aren't interesting: */
/* we're in bounds */
bound_indices_and_conditionals(p, &zpd->access1s, &zpd->steps1, &zpd->nonloops, black, access1);
bound_indices_and_conditionals(p, &zpd->access2s, &zpd->steps2, &zpd->nonloops, black, access2);
/* we're within dddir */
for (j = 1; j <= dd_current_nest(dd); j++) {
constrain_with_convex_dddir(p, &zpd->access2s, &zpd->access1s, &dd_current_dir(dd), j, black);
}
/* PART 4: clean up */
zap_cleanup(zpd);
/* PART 5: compute gist */
if (omegaPrintResult == 1) {
fprintf(debug2, "Zap: Finding gist of problem:\n");
printProblem(p);
}
#if defined newTimeTrials
if (storeResult) realZapTests++;
#endif
if (hasRedEquations(p, 0))
{
if (printing_zap_gists)
{
fprintf(debug2, "Got red equations:\n");
printRedEquations(p);
}
if (p->getVarsN() != p->_safeVars)
{
if (omegaPrintResult == 1 || printing_zap_gists) {
fprintf(debug2, "Can't handle splintered problems yet\n");
}
return too_hard;
}
else {
#if defined newTimeTrials
if (storeResult) realZappable++;
#endif
if (omegaPrintResult == 1)
fprintf(debug2, "Zap possible\n");
return possible;
}
}
else {
if (omegaPrintResult == 1 || printing_zap_gists)
fprintf(debug2, "Zap not possible\n");
return impossible;
}
}
/*bool try_to_eliminate(dd_current dd)
{
int old_reduceWithSubs;
Problem p;
zap_prob_desc zpd;
bool result; ?!
elimination_possible ep;
old_reduceWithSubs = reduceWithSubs;
reduceWithSubs = 0
if ((ep = build_zap_problem(dd, &p, &zpd)) == possible)
{
//result = mccarthy(&p, zpd.vars);
}
else {
switch (ep) {
case too_hard:
Message_Add("The Gist of this dependence is too complicated");
if (omegaPrintResult == 1) {
fprintf(debug2, "Zap: Gist contains wild cards - give up.\n");
}
break;
case impossible:
Message_Add("No interesting assertions zap the dependence");
if (omegaPrintResult == 1) {
fprintf(debug2, "Zap: Gist = \"True\" - don't bother asking if we should negate it.\n");
}
break;
case possible:
default:
assert(0 && "Can't get here.");
}
result = 0;
}
reduceWithSubs = old_reduceWithSubs;
return result;
}*/
elimination_possible possible_to_eliminate(dd_current dd)
{
int old_reduceWithSubs;
Problem p;
zap_prob_desc zpd;
elimination_possible result;
old_reduceWithSubs = reduceWithSubs;
reduceWithSubs = 0; /* to make combining problems easier */
result = build_zap_problem(dd, &p, &zpd);
reduceWithSubs = old_reduceWithSubs;
return result;
}

View File

@@ -0,0 +1,14 @@
/* affine.c,v 1.1 1993/09/17 22:13:47 fbodin Exp */
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "include/portable.h"
#include "include/debug.h"
#include "include/ip.h"
#include "include/affine.h"
/* done in sigma */

View File

@@ -0,0 +1,427 @@
/* cover.c,v 1.1 1993/09/17 22:13:48 fbodin Exp */
/*
coverage and termination tests
Naming convention: Many of these functions and structures
refer to "read iteration" or "write iteration" as if a
test were being performed on flow dependence(s), even when
the test works for other forms of dependence.
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "include/portable.h"
#include "include/debug.h"
#include "include/ip.h"
#include "include/lang-interf.h"
#include "include/ddomega-build.h"
#include "include/ddomega-use.h"
#include "include/kill.h"
#include "include/cover.h"
/*
#include "timeTrials.h"
*/
possible_reasons why_no_cover_or_terminator;
/*
test to see if a dependence covers its destination.
*/
int test_for_coverage(a_access write_acc, a_access read_acc,
uint write_nest, uint read_nest, uint common_nest,
dir_and_dist_info *dd, char *dd_as_string)
{
var_id sc_vars[maxVars], r_vars[maxVars], rs_vars[maxVars];
var_id w_vars[maxVars], ws_vars[maxVars];
int Nrs, Nws, Nsc, leading_0s;
read_prob_desc rpd; /* write1s = A[i]
write2s unused in coverage test
reads = B[j] */
Problem reads;
int j, red_complete, cover;
#if ! defined NDEBUG
int eqs, geqs;
#endif
if (access_update_p(write_acc)) {
set_reason(didnt_test);
return(0);
}
assert(write_acc == Entry || access_store_p(write_acc));
#if defined newTimeTrials
if (storeResult) coverTests++;
#endif
/* If this test is changed or removed, change ddomega-use.c
to reflect that we could have non-coverage due to some
reason other than "didnt_test" if we haven't got all 0's */
for (j = 1; j <= common_nest; j++) {
if (!dddirtest(dd->direction, ddeq, j)) {
if (omegaPrintResult) {
fprintf(debug2, "coverage unlikely, not bothering to test:\n");
fprintf(debug2, " %s\n", dd_as_string);
}
set_reason(didnt_test);
return 0;
}
}
leading_0s = leading_zeros(dd->direction, dd->nest);
/* PART 1: find sets of variables to be used in problem */
Nrs = Nws = Nsc = 0;
load_bounds_and_count_steps(read_acc, r_vars, rs_vars, &Nrs);
load_bounds_and_count_steps(write_acc, w_vars, ws_vars, &Nws);
load_constants_for_bounds(read_acc, sc_vars, &Nsc);
load_constants_for_bounds(write_acc, sc_vars, &Nsc);
load_constants_for_subscripts(read_acc, sc_vars, &Nsc);
load_constants_for_subscripts(write_acc, sc_vars, &Nsc);
/* PART 2: assign columns to variables
Protect variables representing symbolic constants and
read iteration values of loop indices, because
we wish to test if S implies T for all values of them.*/
read_init(&rpd, &reads, sc_and_r, Nsc, sc_vars,
read_nest, r_vars, Nrs, rs_vars,
write_nest, w_vars, Nws, ws_vars,
0, NIL, 0, NIL);
/* PART 3: build problem */
#if !defined NDEBUG
read_inv(&rpd, &reads);
assert(reads.getNumEqs() == 0);
assert(reads.getNumGEqs() == 0);
eqs = geqs = 0;
#endif
/* TRY TO SET UP RED "T" PROBLEM:
"i in [A] ^ A(i) << B(j) ^ A(i) sub= B(j)"
If we can't completely describe the red problem, we can't
test for cover - set red_complete to 0 to indicate this.
*/
/* i in [A] */
red_complete =
bound_inner_indices_and_conditionals(&reads, &rpd.write1s,
&rpd.w1steps, &rpd.nonloops,
leading_0s, read_acc,
red, write_acc);
if (!red_complete)
{
if (omegaPrintResult) {
fprintf(debug2, "not checking for COVER - incomplete red bounds\n");
fprintf(debug2, "of %s\n", dd_as_string);
}
read_cleanup(&rpd);
set_reason(non_affine_red_bound);
return 0;
}
#if ! defined NDEBUG
read_inv(&rpd, &reads);
#endif
/* A(i) sub= B(j) */
/* equate_sub won't be 0, or there would not be a dependence */
red_complete =
equate_subscripts(&reads, &rpd.reads, &rpd.write1s, &rpd.nonloops,
red, read_acc, write_acc) == complete;
#if ! defined NDEBUG
read_inv(&rpd, &reads);
#endif
if (!red_complete)
{
if (omegaPrintResult) {
fprintf(debug2, "not checking for COVER - incomplete red subscripts\n");
fprintf(debug2, "of %s\n", dd_as_string);
}
read_cleanup(&rpd);
set_reason(non_affine_red_sub);
return 0;
}
/* A(i) << B(j) */
constrain_with_dd(&reads, &rpd.reads, &rpd.write1s, dd, red);
#if !defined NDEBUG
read_inv(&rpd, &reads);
for (; eqs < reads.getNumEqs(); eqs++) {
assert(reads._EQs[eqs].color == red);
}
for (; geqs < reads.getNumGEqs(); geqs++) {
assert(reads._GEQs[geqs].color == red);
}
#endif
/* SET UP BLACK "S" PROBLEM: "j in [B]" */
bound_indices_and_conditionals(&reads, &rpd.reads, &rpd.rsteps,
&rpd.nonloops, black, read_acc);
#if ! defined NDEBUG
read_inv(&rpd, &reads);
for (; eqs < reads.getNumEqs(); eqs++) {
assert(reads._EQs[eqs].color == black);
}
for (; geqs < reads.getNumGEqs(); geqs++) {
assert(reads._GEQs[geqs].color == black);
}
#endif
/* PART 4: clean up */
#if ! defined NDEBUG
read_inv(&rpd, &reads);
#endif
read_cleanup(&rpd);
/* PART 5: CHECK FOR COVERAGE: Forall j, Sym, does S imply T? */
/* there must be a solution to the black equations,
since they represent only j in [B] - if this were not true,
there would be no flow dependencies at all */
if (omegaPrintResult) {
fprintf(debug2, "starting check for COVER\n");
fprintf(debug2, "of %s\n", dd_as_string);
printProblem(&reads);
}
cover = !hasRedEquations(&reads, 0);
if (omegaPrintResult) {
if (cover)
fprintf(debug2, "verified COVER:\n");
else
fprintf(debug2, "no COVER:\n");
printProblem(&reads);
}
#if defined newTimeTrials
if (storeResult) {
realCoverTests++;
if (cover) realCovers++;
}
#endif
set_reason((possible_reasons)cover);
return cover;
}
/*
test to see if dependence terminates its source
(ie an anti-dep from a read to a write termitates the read)
*/
int test_for_termination(a_access read_acc, a_access write_acc,
uint read_nest, uint write_nest, uint common_nest,
dir_and_dist_info *dd, char *dd_as_string)
{
var_id sc_vars[maxVars], r_vars[maxVars], rs_vars[maxVars];
var_id w_vars[maxVars], ws_vars[maxVars];
int Nrs, Nws, Nsc, leading_0s;
read_prob_desc rpd;
Problem reads;
int j, red_complete, termination;
#if ! defined NDEBUG
int eqs, geqs;
#endif
if (access_update_p(write_acc)) {
set_reason(didnt_test);
return(0);
}
assert(write_acc == Entry || access_store_p(write_acc));
#if defined newTimeTrials
if (storeResult) terminationTests++;
#endif
/* If this test is changed or removed, change ddomega-use.c
to reflect that we could have non-termination due to some
reason other than "didnt_test" if we haven't got all 0's */
for (j = 1; j <= common_nest; j++) {
if (!dddirtest(dd->direction, ddeq, j)) {
if (omegaPrintResult) {
fprintf(debug2,
"termination unlikely, not bothering to test:\n");
fprintf(debug2, " %s\n", dd_as_string);
}
set_reason(didnt_test);
return 0;
}
}
leading_0s = leading_zeros(dd->direction, dd->nest);
/* PART 1: find sets of variables to be used in problem */
Nrs = Nws = Nsc = 0;
load_bounds_and_count_steps(read_acc, r_vars, rs_vars, &Nrs);
load_bounds_and_count_steps(write_acc, w_vars, ws_vars, &Nws);
load_constants_for_bounds(read_acc, sc_vars, &Nsc);
load_constants_for_bounds(write_acc, sc_vars, &Nsc);
load_constants_for_subscripts(read_acc, sc_vars, &Nsc);
load_constants_for_subscripts(write_acc, sc_vars, &Nsc);
/* PART 2: assign columns to variables
Protect variables representing symbolic constants and
read iteration values of loop indices, because
we wish to test if S implies T for all values of them.*/
read_init(&rpd, &reads, sc_and_r, Nsc, sc_vars,
read_nest, r_vars, Nrs, rs_vars,
write_nest, w_vars, Nws, ws_vars,
0, NIL, 0, NIL);
/* PART 3: build problem */
#if !defined NDEBUG
read_inv(&rpd, &reads);
assert(reads.getNumEqs() == 0);
assert(reads.getNumGEqs() == 0);
eqs = geqs = 0;
#endif
/* TRY TO SET UP RED "T" PROBLEM:
"j in [B] ^ A(i) << B(j) ^ A(i) sub= B(j)"
If we can't completely describe the red problem, we can't
test for termination - set red_complete to 0 to indicate this.
*/
/* j in [B] */
red_complete =
bound_inner_indices_and_conditionals(&reads, &rpd.write1s,
&rpd.w1steps, &rpd.nonloops,
leading_0s, read_acc,
red, write_acc);
if (!red_complete)
{
if (omegaPrintResult) {
fprintf(debug2,
"not checking for TERMINATION - incomplete red bounds\n");
fprintf(debug2, "of %s\n", dd_as_string);
}
read_cleanup(&rpd);
set_reason(non_affine_red_bound);
return 0;
}
#if ! defined NDEBUG
read_inv(&rpd, &reads);
#endif
/* A(i) sub= B(j) */
/* equate_sub won't be 0, or there would not be a dependence */
red_complete =
equate_subscripts(&reads, &rpd.reads, &rpd.write1s, &rpd.nonloops,
red, read_acc, write_acc) == complete;
if (!red_complete)
{
if (omegaPrintResult) {
fprintf(debug2,
"not checking for TERMINATION - incomplete red subscript\n");
fprintf(debug2, "of %s\n", dd_as_string);
}
read_cleanup(&rpd);
set_reason(non_affine_red_sub);
return 0;
}
#if ! defined NDEBUG
read_inv(&rpd, &reads);
#endif
/* A(i) << B(j) */
constrain_with_dd(&reads, &rpd.write1s, &rpd.reads, dd, red);
#if !defined NDEBUG
read_inv(&rpd, &reads);
for (; eqs < reads.getNumEqs(); eqs++) {
assert(reads._EQs[eqs].color == red);
}
for (; geqs < reads.getNumGEqs(); geqs++) {
assert(reads._GEQs[geqs].color == red);
}
#endif
/* SET UP BLACK "S" PROBLEM: "i in [A]" */
bound_indices_and_conditionals(&reads, &rpd.reads, &rpd.rsteps,
&rpd.nonloops, black, read_acc);
#if ! defined NDEBUG
read_inv(&rpd, &reads);
for (; eqs < reads.getNumEqs(); eqs++) {
assert(reads._EQs[eqs].color == black);
}
for (; geqs < reads.getNumGEqs(); geqs++) {
assert(reads._GEQs[geqs].color == black);
}
#endif
/* PART 4: clean up */
#if ! defined NDEBUG
read_inv(&rpd, &reads);
#endif
read_cleanup(&rpd);
/* PART 5: CHECK FOR TERMINATION: Forall i, Sym, does S imply T? */
/* there must be a solution to the black equations,
since they represent only i in [A] - if this were not true,
there would be no flow dependencies at all */
if (omegaPrintResult) {
fprintf(debug2, "starting check for TERMINATION\n");
fprintf(debug2, "of %s\n", dd_as_string);
printProblem(&reads);
}
termination = !hasRedEquations(&reads, 0);
if (omegaPrintResult) {
if (termination)
fprintf(debug2, "verified TERMINATION.\n");
else
fprintf(debug2, "no TERMINATION.\n");
}
#if defined newTimeTrials
if (storeResult) {
realTerminationTests++;
if (termination) realTerminators++;
}
#endif
set_reason((possible_reasons)termination);
return termination;
}

View File

@@ -0,0 +1,784 @@
/* ddomega-build.c,v 1.1 1993/09/17 22:13:49 fbodin Exp */
/*
Functions that are used in the construction of
an omega test problem from a source program.
*/
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include "include/portable.h"
#include "include/debug.h"
/*
#include "lang-interf.h"
#include "ip.h"
*/
#include "include/affine.h"
#include "include/ddomega-build.h"
#include "include/Exit.h"
var_id *current_set_of_vars;
void init_prob(Problem *p, uint Nvars, uint Nprot,
char *(*getVarName)(unsigned int, void *),
void *getVarNameArgs)
{
initializeProblem(p);
assert(!(Nvars > maxVars));
p->setVarsN(Nvars);
p->_safeVars = Nprot;
p->setNumEqs(0);
p->setNumGEqs(0);
p->_getVarName = getVarName;
p->_getVarNameArgs = getVarNameArgs;
}
/* allocate a new _EQs with uninitialized co-efficients */
/* The touched flag only makes a difference on GEQ's */
uint prob_add_EQ(Problem *p, int color)
{
//++p->_numEQs;
p->addNumEqs(1);
assert(!(p->getNumEqs() > maxEQs));
p->_EQs[p->getNumEqs() - 1].color = color;
return p->getNumEqs() - 1;
}
/* allocate a new _EQs with all co-efficients 0 */
uint prob_add_zero_EQ(Problem *p, int color)
{
uint c;
//c = p->_numEQs++;
c = p->getNumEqs();
p->addNumEqs(1);
assert(!(p->getNumEqs() > maxEQs));
eqnnzero(&p->_EQs[c], p->getVarsN());
p->_EQs[c].color = color;
return c;
}
/* allocate a new _GEQs with uninitialized co-efficients */
uint prob_add_GEQ(Problem *p, int color)
{
p->addNumGEqs(1);
assert(!(p->getNumGEqs() > maxGEQs));
p->_GEQs[p->getNumGEqs() - 1].touched = 1;
p->_GEQs[p->getNumGEqs() - 1].color = color;
return p->getNumGEqs() - 1;
}
/* allocate a new _GEQs with all co-efficients 0 */
uint prob_add_zero_GEQ(Problem *p, int color)
{
uint c;
//c = p->_numGEQs++;
c = p->getNumGEqs();
p->addNumGEqs(1);
assert(!(p->getNumGEqs() > maxGEQs));
eqnnzero(&p->_GEQs[c], p->getVarsN());
p->_GEQs[c].touched = 1;
p->_GEQs[c].color = color;
return c;
}
/* delta = access1 - access2, so for flow dep, delta = write - read */
void set_deltas(Problem *p, int delta_color, range *deltas, range *a1, range *a2)
{
uint e, c;
assert(r_length(deltas) <= r_length(a1) && r_length(deltas) <= r_length(a2));
for (e = 0; e < r_length(deltas); e++) {
c = prob_add_zero_EQ(p, delta_color);
p->_EQs[c].coef[e + r_first(deltas)] = 1;
p->_EQs[c].coef[e + r_first(a1)] = 1;
p->_EQs[c].coef[e + r_first(a2)] = -1;
}
}
/*
Constrain a problem with the minimal constraints needed to
enforce the direction vector in dd.
Use restraint vector unless it is not convex
It is also tempting to use the or the direction vector instead
if it is "=", but that does not seem to speed things up (?)
The loss of speed is less significant if we test for eqs
in constrain_with_convex_dddir below.
*/
void constrain_with_dd(Problem *pr, range *dd_to, range *dd_from,
dir_and_dist_info *dd, int color)
{
int j;
for (j = 1; j <= dd->nest; j++) {
int thisr;
thisr = ddextract1(dd->restraint, j);
if (((thisr&ddgt) && (thisr&ddlt) && !(thisr&ddeq)) /* restr = "+-" */
|| (ddextract1(dd->direction, j) == ddeq)) /* direc = "0" */
{
constrain_with_convex_dddir(pr, dd_to, dd_from,
&dd->direction, j, color);
}
else {
constrain_with_convex_dddir(pr, dd_to, dd_from,
&dd->restraint, j, color);
}
}
}
/*
Constrain *pr with the DIRECTION vector in dd.
*/
void constrain_with_dddirs(Problem *pr, range *dd_to, range *dd_from,
dir_and_dist_info *dd, int color)
{
int j;
for (j = 1; j <= dd->nest; j++) {
constrain_with_convex_dddir(pr, dd_to, dd_from,
&dd->direction, j, color);
}
}
/*
Constrain *pr with dimension j of *dir.
Use equations of color "color".
*/
void constrain_with_convex_dddir(Problem *pr, range *dd_to, range *dd_from,
dddirection *dir, int j, int color)
{
int e;
if (ddextract1(*dir, j) == ddeq)
{
e = prob_add_zero_EQ(pr, color);
pr->_EQs[e].coef[r_first(dd_to) - 1 + j] = -1;
pr->_EQs[e].coef[r_first(dd_from) - 1 + j] = 1;
return;
}
if (!dddirtest(*dir, ddlt, j))
{
/* no +, so dd_to - dd_from <= 0 or < 0
ie, dd_from - dd_to >= 0 or > 0
ie, dd_from - dd_to >= 0 or ... -1 >= 0 */
e = prob_add_zero_GEQ(pr, color);
pr->_GEQs[e].coef[r_first(dd_to) - 1 + j] = -1;
pr->_GEQs[e].coef[r_first(dd_from) - 1 + j] = 1;
pr->_GEQs[e].coef[0] = -!dddirtest(*dir, ddeq, j);
}
if (!dddirtest(*dir, ddgt, j))
{
/* no -, so dd_to - dd_from >= 0 or > 0
ie, dd_to - dd_from >= 0 or ... -1 >= 0 */
e = prob_add_zero_GEQ(pr, color);
pr->_GEQs[e].coef[r_first(dd_to) - 1 + j] = 1;
pr->_GEQs[e].coef[r_first(dd_from) - 1 + j] = -1;
pr->_GEQs[e].coef[0] = -!dddirtest(*dir, ddeq, j);
}
}
/*
For each term in ae, add sign * its co-efficient to e.
Declarations of symbolic constants must have been tagged with
their column number already
Colunm numbers of indices are their depth + r_first(indices)
*/
static void add_coefficients(Eqn e, range *indices, int sign, affine_expr *ae)
{
int v;
assert(ae->terms[0].tiny_var == NIL);
e->coef[0] += sign * ae->terms[0].coefficient;
for (v = 1; v < ae->nterms; v++) {
if (var_id_index_p(ae->terms[v].tiny_var)) { /* index */
int loop = var_ids_loop_no(ae->terms[v].tiny_var);
e->coef[r_first(indices) - 1 + loop] +=
sign * ae->terms[v].coefficient;
}
else { /* sym. const */
assert(var_id_const_p(ae->terms[v].tiny_var));
e->coef[var_ids_tag(ae->terms[v].tiny_var)] +=
sign * ae->terms[v].coefficient;
}
}
}
/* for the lower bound, lb <= i === i - lb >= 0
for the upper bound, i <= ub === -i + ub >= 0
define bound types so that establish_one_bound works out...
*/
typedef enum { upper = 1, lower = -1 } which_bound;
/* return 1 if boundable, 0 if not affine */
static int
establish_one_bound(Problem *p, int color,
range *indices, which_bound b,
affine_expr *ae, uint depth)
{
if (!is_affine(ae))
return 0;
while (ae != NIL) {
uint c; /* new constraint */
assert(is_affine(ae));
c = prob_add_zero_GEQ(p, color);
add_coefficients(&p->_GEQs[c], indices, b, ae);
//assert(p->_GEQs[c].coef[r_first(indices) - 1 + depth] == 0);
if (p->_GEQs[c].coef[r_first(indices) - 1 + depth] != 0)
return 0;
p->_GEQs[c].coef[r_first(indices) - 1 + depth] = -b;
ae = ae->other_branch;
}
return 1;
}
/*
start_expr should point to the 1st expression taken on by the loop
return 1 if bound, 0 if not
*/
static int
handle_nonunit_increments(Problem *p, range *indices, int *which_step, int color, loop_context l, sint incr, uint depth)
{
affine_expr *start_expr = loop_start(l);
assert(incr >= 1); /* can't handle any others yet */
if (abs(incr) == 1)
return 1;
/* if lower bound is linear AND HAS NO "MAX"
add the constraint: index = lower_bound + gensym * step
otherwise, don't add any new constraints, unless color == red */
assert(start_expr != NIL);
if (is_affine(start_expr) && start_expr->other_branch == NIL)
{
int c, v, i2;
c = prob_add_zero_EQ(p, color);
add_coefficients(&p->_EQs[c], indices, 1, start_expr);
/* we now have the EQ "lower_bound = 0" */
//assert(p->_EQs[c].coef[r_first(indices) - 1 + depth] == 0);
if (p->_EQs[c].coef[r_first(indices) - 1 + depth] != 0)
return 0;
p->_EQs[c].coef[r_first(indices) - 1 + depth] = -1;
/* we now have the EQ "lower_bound - index = 0" */
/* we can reduce the co-efficients to their value mod(step),
since we're adding gensym()*step */
i2 = incr / 2;
for (v = 1; v <= p->getVarsN(); v++) {
int tmp = intMod(p->_EQs[c].coef[v], incr);
if (tmp > i2) tmp -= incr;
p->_EQs[c].coef[v] = tmp;
}
p->_EQs[c].coef[*which_step] = incr;
(*which_step)++;
return 1;
}
else {
return 0;
}
}
/* Create constraints in prob for the loop index whose dolimit
is pointed to by limits.
May add one or more(min or max) upper and lower constraints
May add an equality constraint if the increment != 0
return 1 if completely bound, 0 if we had any non-affine stuff
*/
static int bound_index(Problem *p, int color, loop_context limits, range *indices, range *non_i, int *which_step, uint depth)
{
sint incr;
bool known;
incr = 1; known = 1;
if (loop_has_step_p(limits)) {
/* there is an increment expression */
loops_step(limits, &incr, &known);
}
if (!(known && incr >= 1))
ErrAssert("DO loop step must be positive");
if (known) {
if (incr > 0) {
int l, u, i;
l = establish_one_bound(p, color, indices, lower, loop_start(limits), depth);
u = establish_one_bound(p, color, indices, upper, loop_end(limits), depth);
i = handle_nonunit_increments(p, indices, which_step, color, limits, incr, depth);
return l && u && i;
}
else if (incr < 0) {
/* assertion checking is off */
int l, u, i;
fprintf(stderr, "can't handle negative step yet\n");
Exit(2);
l = establish_one_bound(p, color, indices, lower, loop_end(limits), depth);
u = establish_one_bound(p, color, indices, upper, loop_start(limits), depth);
i = handle_nonunit_increments(p, indices, which_step, color, limits, incr, depth);
return l && u && i;
}
else {
/* assertion checking is off */
fprintf(stderr, "What do you mean by having a step of 0? What are you, stupid?\n");
Exit(1);
return 0;
}
}
else {
/* assertion checking is off */
fprintf(stderr, "can't handle unknown step\n");
Exit(2);
return 0;
}
}
/* Create constraints in problem for the conditional.
May add any number of GEQ or EQ constraints
return 1 if completely bound, 0 if we had any non-affine stuff
This initial version only works with the puny subset of conditionals
described in affine.c, and is tiny-specific.
A conservative tiny-free alternative is to just return 0.
*/
static struct {
int lhs_sign;
int rhs_sign;
int constant;
} conditionals[4] = {
{ 1, -1, -1 }, /* gt */
{ 1, -1, 0 }, /* ge */
{ -1, 1, -1 }, /* lt */
{ -1, 1, 0 } /* le */
};
#define N_ELEMENTS(ARRAY) ( sizeof(ARRAY)/sizeof(ARRAY[0]) )
static int
puny_bound_condition(Problem *p, int color, if_context cond,
range *indices, range *non_i)
{
if (if_condition_ok(cond))
{
int c, kind;
kind = if_compare_op(cond);
if (kind < 0 || kind >= N_ELEMENTS(conditionals)) {
assert(!"What the heck? How did that get to be affine?");
return 0;
}
if (if_else_branch(cond)) {
kind = N_ELEMENTS(conditionals) - kind;
}
else {
#if ! defined NOT_TINY
assert(cond->nodeop == op_then ||
cond->nodeparent->nodeop == op_assert);
#endif
}
c = prob_add_zero_GEQ(p, color);
add_coefficients(&p->_GEQs[c], indices, conditionals[kind].lhs_sign,
if_compare_left(cond));
add_coefficients(&p->_GEQs[c], indices, conditionals[kind].rhs_sign,
if_compare_right(cond));
p->_GEQs[c].coef[0] += conditionals[kind].constant;
#if ! defined NOT_TINY
assert(!cond->nodeparent->nodeaffine->other_branch->other_branch);
#endif
return 1;
}
else {
return 0;
}
}
/* Establish bounds for the loop indices and conditionals
that enclose node n.
If we come across a non-affine expression return 0.
If we successfully bound everything return 1.
Note that we finish doing all the bounds we can,
in either case, so zapping will work well.
Assume that "outer" outer loops have been taken care of
in some other way - i.e. that we are building the red
part of some problem which represents a dependence with
"outer" leading 0's, so we will take care of these
variables by setting them equal to the black loop indices.
If "skip_outer_ifs_containing_me" is non-nil, any ifs
that are within exactly "outer" loops and contain it.
This corresponds to the situation:
for1
for2
if1 then
if2a then
access a
endif
if2b then
access skip_outer_ifs_containing_me
endif
endif
endfor
endfor
in which we want to skip if1 when bounding a in the 0,0 dependence
from a to skip_outer_ifs_containing_me. Note that we don't have to
distinguish between the then & else parts, as we can't have a 0,0
if one access is is each.
*/
int
bound_inner_indices_and_conditionals(Problem *p,
range *indices, range *steps, range *non_i,
int outer, a_access skip_outer_ifs_containing_me,
int color, a_access a)
{
int result;
int which_step = r_first(steps);
context_iterator c;
if (a == Entry || a == ExitNode)
return(1);
c = cont_i_for_access(a);
result = 1;
while (!cont_i_done(c))
{
if (cont_i_cur_loop_p(c)) {
if (cont_i_cur_depth(c) <= outer)
return result;
#if ! defined NOT_TINY
assert(do_op(c->nodeparent->nodeop));
#endif
if (!bound_index(p, color, cont_i_cur_loop(c),
indices, non_i, &which_step,
cont_i_cur_depth(c)))
{
assert(which_step <= r_last(steps) + 1);
result = 0;
}
}
else {
assert(cont_i_cur_if_p(c));
#if ! defined NOT_TINY
assert(c->nodeparent->nodeop == op_if);
#endif
if (!(skip_outer_ifs_containing_me
&& cont_i_cur_depth(c) <= outer
&& access_is_in_then_or_else_of(skip_outer_ifs_containing_me, c))
&& !puny_bound_condition(p, color, cont_i_cur_if(c),
indices, non_i))
{
result = 0;
}
}
cont_i_next(c);
}
assert(which_step <= r_last(steps) + 1);
#if ! defined NOT_TINY
for (c = Assertions; c; c = c->nodelink)
{
assert(c->nodeop == op_assert);
if (!puny_bound_condition(p, color, c->nodechild, indices, non_i))
{
result = 0;
}
}
#endif
return result;
}
/* adjust the problem to include equality of subscript expressions at
nodes access1 and access2. Index variables for access1 are looked
up in range i1, and those for access2 in range i2. The non-index
variables are looked up in the range non_i.
returns 0 if subscripts could not possibly be equal.
In this case, we may not finish adding the equalities.
returns 1 if the conditions for their equality have been completely
described by the constraints added to p
returns 2 if there was a non-affine expression, in which case the
constraints added to p must be true for equality (but they
may also be true for some non-equal cases). If color==red,
we FINISH trying to bound subscripts (for zapping).
*/
equate_descr equate_subscripts(Problem *p, range *i1, range *i2, range *non_i,
int color, a_access access1, a_access access2)
{
sub_iterator sub1, sub2;
int is_complete = complete;
if (access1 == Entry || access1 == ExitNode ||
access2 == Entry || access2 == ExitNode)
return (equate_descr)1;
/* we assume children of the node are subscripts,
so scalars MUST have no nodechildren
assert(array_op(access1->nodeop) || access1->nodechild == NIL);
*/
sub1 = sub_i_for_access(access1);
sub2 = sub_i_for_access(access2);
while (!sub_i_done(sub1))
{
assert(!sub_i_done(sub2)); /* must have same # of subscripts */
assert(sub_i_cur_affine(sub1) != NIL && sub_i_cur_affine(sub2) != NIL);
if (sub_i_cur_is_affine(sub1) && sub_i_cur_is_affine(sub2)) {
uint c; /* new constraint # */
int i;
assert((sub_i_cur_affine(sub1)->other_branch == NIL) &&
(sub_i_cur_affine(sub2)->other_branch == NIL));
c = prob_add_zero_EQ(p, color);
add_coefficients(&p->_EQs[c], i1, 1, sub_i_cur_affine(sub1));
add_coefficients(&p->_EQs[c], i2, -1, sub_i_cur_affine(sub2));
for (i = p->getVarsN(); i > 0; i--)
if (p->_EQs[c].coef[i] != 0)
break;
if (i == 0) { /* linearity = 0 */
if (p->_EQs[c].coef[0] != 0)
return not_possible; /* never equal */
//p->_numEQs--; /* always equal: don't add equation */
p->addNumEqs(-1);
}
}
else {
is_complete = partial;
}
sub_i_next(sub1);
sub_i_next(sub2);
}
assert(sub_i_done(sub2)); /* must have same # of subscripts */
return (equate_descr)is_complete;
}
/* postcondition: n < maxVars */
static void NeedNVars(int n)
{
if (n >= maxVars) {
fprintf(debug2, "Out of Omega variables\n");
Exit(2);
}
}
/* set bounds[1...depth(n)] to point to the dolimits of the loops containing n
set *Nsteps to the # of loops that have step expressions
set steps[0 ... *Nsteps - 1] to NIL
*/
void load_bounds_and_count_steps(a_access a, var_id bounds[],
var_id steps[], int *Nsteps)
{
context_iterator c;
if (a == Entry || a == ExitNode)
return;
c = cont_i_for_access(a);
while (!cont_i_done(c))
{
if (cont_i_cur_loop_p(c)) {
bounds[cont_i_cur_depth(c)] = loop_var_id(cont_i_cur_loop(c));
if (loop_has_step_p(cont_i_cur_loop(c))) {
/* handle step */
NeedNVars(*Nsteps);
steps[*Nsteps] = 0;
(*Nsteps)++;
}
}
else {
assert(cont_i_cur_if_p(c));
/* handle if trivially - no new bounds or steps */
}
cont_i_next(c);
}
}
typedef struct {
var_id *consts;
int *Nconsts;
} const_stuff;
static void load_a_const(var_id v, void *args)
{
const_stuff *cs = (const_stuff *)args;
if (var_id_const_p(v)) {
/* not a loop index */
if (var_ids_tag(v) == UNTAGGED)
{
NeedNVars(*cs->Nconsts);
var_ids_tag(v) = *cs->Nconsts;
cs->consts[(*cs->Nconsts)++] = v;
}
else {
assert(cs->consts[var_ids_tag(v)] == v);
}
}
else {
assert(var_id_index_p(v));
}
}
#if 0
static void load_consts_for_expr(node *expr, var_id consts[], int *Nconsts)
{
node *nn;
for (nn = expr; nn != NIL; nn = nn->nodenext) {
assert(!array_op(nn->nodeop));
switch (nn->nodeop) {
case op_fetch:
case op_store:
if (get_nodevalue_node(nn)->nodeop == op_declare) {
/* not a loop index */
if (get_nodevalue_sym(get_nodevalue_node(nn))->symtag
== UNTAGGED)
{
NeedNVars(*Nconsts);
get_nodevalue_sym(get_nodevalue_node(nn))->symtag
= *Nconsts;
consts[(*Nconsts)++] =
get_nodevalue_sym(get_nodevalue_node(nn));
}
else {
assert(consts[get_nodevalue_sym(get_nodevalue_node(nn))
->symtag]
== get_nodevalue_sym(get_nodevalue_node(nn)));
}
}
else {
assert(get_nodevalue_node(nn)->nodeop == op_dolimit);
}
break;
default:
load_consts_for_expr(nn->nodechild, consts, Nconsts);
}
}
}
#endif
/* ensure that all symbolic constants used in affine subscript
expressions appear in consts[0..*Nconsts-1], and that they
are tagged with their indices.
If called with a scalar, do nothing
*/
void load_constants_for_subscripts(a_access a, var_id consts[], int *Nconsts)
{
const_stuff cs;
sub_iterator sub;
if (a == Entry || a == ExitNode)
return;
cs.consts = consts;
cs.Nconsts = Nconsts;
sub = sub_i_for_access(a);
while (!sub_i_done(sub)) {
sub_i_map_over_cur_vars(sub, &load_a_const, &cs);
sub_i_next(sub);
}
}
/* same for affine expressions used in loop bounds of loops surrounding n */
void load_constants_for_bounds(a_access a, var_id consts[], int *Nconsts)
{
const_stuff cs;
context_iterator c;
if (a == Entry || a == ExitNode)
return;
cs.consts = consts;
cs.Nconsts = Nconsts;
c = cont_i_for_access(a);
while (!cont_i_done(c))
{
if (cont_i_cur_loop_p(c)) {
loop_map_over_start_vars(cont_i_cur_loop(c), &load_a_const, &cs);
loop_map_over_end_vars(cont_i_cur_loop(c), &load_a_const, &cs);
}
else {
assert(cont_i_cur_if_p(c));
if_map_over_vars(cont_i_cur_if(c), &load_a_const, &cs);
}
cont_i_next(c);
}
#if ! defined NOT_TINY
for (c = Assertions; c; c = c->nodelink) {
if_map_over_vars(c->nodechild, &load_a_const, &cs);
}
#endif
}

View File

@@ -0,0 +1,865 @@
/* ddomega-use.c,v 1.1 1993/09/17 22:13:50 fbodin Exp */
/*
calls to omega test to determine data dependencies from a problem
(as defined in ddomega.c & built by the code in ddomega-build.c)
*/
#include <assert.h>
#include "include/portable.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "include/debug.h"
#include "include/lang-interf.h"
#include "include/ip.h"
#include "include/ddomega-build.h"
#include "include/ddomega-use.h"
#include "include/ddomega.h"
#include "include/omega2flags.h"
#include "include/refine.h"
#include "include/cover.h"
#include "include/missing.h"
#include "include/Exit.h"
#include "include/timeTrials.h"
/* information about nodes involved in dependence */
typedef struct {
a_access access1, access2;
ddnature oitype, iotype;
uint nest1, nest2, commonNesting;
} situation;
void out_of_memory()
{
fprintf(debug2, "Memory Allocation failed\n");
Exit(2);
}
static dddirection dd_convert[] = { ddgt, ddeq, ddlt };
/* dd_convert(i+1) is dddirection for i */
#if !defined SPEED
static char *dir_and_dist_as_str(dir_and_dist_info *d_info, ddnature type, a_access from_access, a_access to_access)
{
static char buf[TINYBUFSIZ];
char f[TINYBUFSIZ];
uint n, l, l0;
char ch;
dddirection thisdd;
strcpy(f, access_as_string(from_access));
{ char *ss;
switch (type) {
case ddflow: ss = "flow"; break;
case ddanti: ss = "anti"; break;
case ddoutput: ss = "output"; break;
case ddreduce: ss = "reduce"; break;
default: ss = ""; /* make compiler happy */
ErrAssert("dir_and_dist_as_str: wrong dependence type");
}
sprintf(buf, "%-6s %3ld: %-15.15s --> %3ld: %-15.15s ", ss,
accesss_lineno(from_access), f,
accesss_lineno(to_access), access_as_string(to_access));
}
l0 = l = strlen(buf);
ch = '(';
for (n = 1; n <= d_info->nest; ++n) {
buf[l++] = ch;
ch = ',';
thisdd = ddextract1(d_info->direction, n);
if (d_info->distanceKnown[n]) {
sprintf(&(buf[l]), "%ld", d_info->distance[n]);
l = strlen(buf);
}
else if (thisdd == ddlt + ddeq + ddgt) {
buf[l++] = '*';
}
else {
if (ddtest1(thisdd, ddeq)) buf[l++] = '0';
if (ddtest1(thisdd, ddlt)) buf[l++] = '+';
if (ddtest1(thisdd, ddgt)) buf[l++] = '-';
}
}
if (d_info->nest > 0)
buf[l++] = ')';
while (l < l0 + 18)
buf[l++] = ' ';
buf[l] = 0;
append_dd_flags(buf, d_info->direction);
return buf;
}
#endif
/*
do refinement, cover, and termination tests, set appropriate flags,
then store dependence.
*/
static void
flag_and_store_dependence(ddnature nature,
a_access from_access, a_access to_access,
dir_and_dist_info *d_info)
{
store_dependence(nature, from_access, to_access, d_info);
if (!skipping_omega2) {
#if !defined SPEED
char *str = dir_and_dist_as_str(d_info, nature, from_access, to_access);
#else
char *str = "Tiny must be compiled without -DSPEED for debug2 output";
#endif
if ((nature == ddflow || nature == ddoutput) &&
from_access != Entry && to_access != ExitNode)
{
int covers, j;
covers = test_for_coverage(from_access, to_access,
accesss_depth(from_access),
accesss_depth(to_access),
d_info->nest, d_info, str);
assert(covers < 2);
if (!covers && because(non_affine_red_bound)) {
/* see if all 0's covers */
dir_and_dist_info new_info = *d_info;
#if !defined SPEED
char *str2 = dir_and_dist_as_str(d_info, nature,
from_access, to_access);
#else
char *str2 = "Tiny must be compiled without -DSPEED for debug2 output";
#endif
new_info.nest = d_info->nest;
for (j = 1; j <= new_info.nest; j++)
{
assert(dddirtest(d_info->direction, ddeq, j));
/* otherwise we would have no cover because 'didnt_test' */
dddirsetonly(new_info.direction, ddeq, j);
dddirsetonly(new_info.restraint, ddeq, j);
new_info.distanceKnown[j] = 1;
new_info.distance[j] = 0;
}
if (test_for_coverage(from_access, to_access,
accesss_depth(from_access),
accesss_depth(to_access),
new_info.nest, &new_info, str2))
{
if (!(d_info->direction & ddrefined))
clone_dd_graph_node_for_refinement(d_info->dd_graph_node_to_be_cloned);
*d_info = new_info;
d_info->direction |= ddrefined;
covers = 2;
}
}
if (covers)
{
d_info->direction |= ddcovers;
if (covers != 2 && !skipping_all_tightening &&
(!skipping_o_a_tightening || nature == ddflow))
{
tighten_cover(from_access, to_access, d_info, str);
}
accesss_cover_depth(to_access) = MAX(accesss_cover_depth(to_access), dd_carried_by(d_info->direction, d_info->nest) - 1);
}
}
if ((nature == ddoutput || nature == ddanti) &&
from_access != ExitNode && to_access != Entry)
{
int terminates, j;
terminates = test_for_termination(from_access, to_access,
accesss_depth(from_access),
accesss_depth(to_access),
d_info->nest, d_info, str);
assert(terminates < 2);
if (!terminates && because(non_affine_red_bound)) {
/* see if all 0's terminates */
dir_and_dist_info new_info = *d_info;
#if !defined SPEED
char *str2 = dir_and_dist_as_str(d_info, nature, from_access, to_access);
#else
char *str2 = "Tiny must be compiled without -DSPEED for debug2 output";
#endif
new_info.nest = d_info->nest;
for (j = 1; j <= new_info.nest; j++)
{
assert(dddirtest(d_info->direction, ddeq, j));
/* otherwise we would have no cover because 'didnt_test' */
dddirsetonly(new_info.direction, ddeq, j);
dddirsetonly(new_info.restraint, ddeq, j);
new_info.distanceKnown[j] = 1;
new_info.distance[j] = 0;
}
if (test_for_termination(from_access, to_access,
accesss_depth(from_access),
accesss_depth(to_access),
new_info.nest, &new_info, str2))
{
if (!(d_info->direction & ddrefined))
clone_dd_graph_node_for_refinement(d_info->dd_graph_node_to_be_cloned);
*d_info = new_info;
d_info->direction |= ddrefined;
terminates = 2;
}
}
if (terminates)
{
d_info->direction |= ddterminates;
if (terminates != 2 && !skipping_o_a_tightening &&
!skipping_all_tightening)
{
tighten_terminator(from_access, to_access, d_info, str);
}
accesss_terminator_depth(from_access) = MAX(accesss_terminator_depth(from_access), dd_carried_by(d_info->direction, d_info->nest) - 1);
}
}
#if !defined NDEBUG
d_info_inv(d_info);
#endif
/* copy all the changes into the ddnode */
#if defined newTimeTrials
if (storeResult)
dir_and_dist_into_ddnode(d_info,
d_info->dd_graph_node_to_be_cloned);
#else
dir_and_dist_into_ddnode(d_info, d_info->dd_graph_node_to_be_cloned);
#endif
}
#if defined newTimeTrials
if (!storeResult)
return;
else
stores++;
#endif
}
/* split a set of flow, anti, or output dependencies into
pieces that are all forward in time
if we have a situation with an exposed 0+ followed
by an exposed -,
then filterValid will call itself recursively to split
the 0+ into 0 and + (eliminating the 0...- case)
else filterValid will store only one dependency
these dependeces are passed to flag_and_store_dependence.
*/
static void
filterValid(ddnature nature, a_access from_access, a_access to_access,
int commonNesting, dir_and_dist_info *d_info, int allEQallowed)
{
int less_at, j;
int forbidden;
/*
* For private variables: -- vadik 11/05/92
* dependencies can not be carried by loops-privatizers
*/
if (from_access != Entry && from_access != ExitNode &&
to_access != ExitNode && to_access != Entry &&
access_private_var_p(from_access))
{
int PrivLev = access_private_var_level(from_access);
assert(PrivLev <= commonNesting);
for (j = 1; j <= PrivLev; j++) {
dddirreset(d_info->direction, ddlt | ddgt, j);
if (!dddirtest(d_info->direction, ddgt | ddlt | ddeq, j))
return;
dddirreset(d_info->restraint, ddlt | ddgt, j);
d_info->distance[j] = 0;
d_info->distanceKnown[j] = 1;
}
}
#if 0
/*
* Reduction dependences aren't forward or backward in time,
* so they all are valid by default ??? -- vadik
* However, we have to ignore (0,0,...,0) reduction dependences.
*/
if (nature == ddreduce) {
for (j = 1; j <= commonNesting; ++j) {
if (dddirtest(d_info->direction, ddlt | ddgt, j))
break;
}
if (j <= commonNesting || from_access != to_access) {
flag_and_store_dependence(nature, from_access, to_access, d_info);
}
return;
}
#endif
/* remove all -'s before 1st + */
for (j = 1; j <= commonNesting; ++j) {
if (!dddirtest(d_info->direction, ddlt | ddeq, j))
return;
if (dddirtest(d_info->direction, ddgt, j)) {
dddirreset(d_info->direction, ddgt, j);
d_info_do_eq(d_info, j);
dddirreset(d_info->restraint, ddgt, j);
}
if (dddirtest(d_info->direction, ddlt, j)) break;
}
/* check for all 0's or no common Nesting */
less_at = j;
if (less_at > commonNesting) {
if (allEQallowed) {
flag_and_store_dependence(nature, from_access, to_access, d_info);
}
return;
}
/* if we start with 0+ rather than just +, check for possible all 0's */
if (dddirtest(d_info->direction, ddeq, less_at)) {
for (j = less_at + 1;
j <= commonNesting && !dddirtest(d_info->direction, ddlt | ddgt, j);
j++);
if (j <= commonNesting && !dddirtest(d_info->direction, ddlt | ddeq, j))
{
/* we have some 0's, a 0+, more 0's, then a - so, 0+ -> just + */
dddirreset(d_info->direction, ddeq, less_at);
dddirreset(d_info->restraint, ddeq, less_at);
}
else {
/* we have some 0's, a 0+, more 0's,
then either 0- or something with a + */
forbidden = !allEQallowed;
for (j = commonNesting; j >= less_at; j--) {
forbidden = dddirtest(d_info->direction, ddgt, j) ||
(dddirtest(d_info->direction, ddeq, j) && forbidden);
/* "forbidden" = some loop outside j must
force this dependence to go strictly forward in time */
}
if (forbidden) {
/* split into leading 0 vs. leading + */
dir_and_dist_info plus, zero;
plus = zero = *d_info;
dddirreset(plus.direction, ddeq, less_at);
dddirreset(plus.restraint, ddeq, less_at);
dddirreset(zero.direction, ddlt, less_at);
dddirreset(zero.restraint, ddlt, less_at);
zero.distance[less_at] = 0;
zero.distanceKnown[less_at] = 1;
filterValid(nature, from_access, to_access, commonNesting,
&plus, allEQallowed);
filterValid(nature, from_access, to_access, commonNesting,
&zero, allEQallowed);
return;
}
}
}
flag_and_store_dependence(nature, from_access, to_access, d_info);
if (omegaPrintResult == 1) {
fprintf(debug2, ">>>>>>>>>>>>>>>>>>>>>>>> (");
for (j = 1; j <= commonNesting; j++) {
if (dddirtest(d_info->restraint, ddeq, j)) fprintf(debug2, "0");
if (dddirtest(d_info->restraint, ddlt, j)) fprintf(debug2, "+");
if (dddirtest(d_info->restraint, ddgt, j)) fprintf(debug2, "-");
if (j < commonNesting) fprintf(debug2, ",");
}
fprintf(debug2, ")\n");
fprintf(debug2, "------------------------ (");
for (j = 1; j <= commonNesting; j++) {
if (dddirtest(d_info->direction, ddeq, j)) fprintf(debug2, "0");
if (dddirtest(d_info->direction, ddlt, j)) fprintf(debug2, "+");
if (dddirtest(d_info->direction, ddgt, j)) fprintf(debug2, "-");
if (j < commonNesting) fprintf(debug2, ",");
}
fprintf(debug2, ")\n");
}
}
static void dd_to_debug(dir_and_dist_info *d_info)
{
int j;
fprintf(debug2, "(");
for (j = 1; j <= d_info->nest; j++) {
if (d_info->distanceKnown[j])
fprintf(debug2, "%d", d_info->distance[j]);
else if (ddextract1(d_info->direction, j) == ddall)
fprintf(debug2, "*");
else {
if (dddirtest(d_info->direction, ddeq, j)) fprintf(debug2, "0");
if (dddirtest(d_info->direction, ddlt, j)) fprintf(debug2, "+");
if (dddirtest(d_info->direction, ddgt, j)) fprintf(debug2, "-");
}
if (j < d_info->nest) fprintf(debug2, ",");
}
fprintf(debug2, ") restraint = (");
for (j = 1; j <= d_info->nest; j++) {
if (ddextract1(d_info->restraint, j) == ddall)
fprintf(debug2, "*");
else {
if (dddirtest(d_info->restraint, ddeq, j)) fprintf(debug2, "0");
if (dddirtest(d_info->restraint, ddlt, j)) fprintf(debug2, "+");
if (dddirtest(d_info->restraint, ddgt, j)) fprintf(debug2, "-");
}
if (j < d_info->nest) fprintf(debug2, ",");
}
fprintf(debug2, ")");
}
/*
call filterValid for the dependence from access1 to access2,
and if they are distinct, for the dependence the other way.
*/
static void noteDependence(situation *sit, dir_and_dist_info *d_info)
{
dddirection deq, dgt, dlt, req, rgt, rlt;
dir_and_dist_info backward;
int j;
backward.dd_graph_node_to_be_cloned = 0;
deq = ddfilter(d_info->direction, ddeq);
dlt = ddfilter(d_info->direction, ddlt);
dgt = ddfilter(d_info->direction, ddgt);
req = ddfilter(d_info->restraint, ddeq);
rlt = ddfilter(d_info->restraint, ddlt);
rgt = ddfilter(d_info->restraint, ddgt);
if (sit->access1 != sit->access2) {
backward.direction = backward.restraint = 0;
ddsetfilter(backward.direction, deq, ddeq);
ddsetfilter(backward.direction, dlt, ddgt);
ddsetfilter(backward.direction, dgt, ddlt);
ddsetfilter(backward.restraint, req, ddeq);
ddsetfilter(backward.restraint, rlt, ddgt);
ddsetfilter(backward.restraint, rgt, ddlt);
backward.nest = d_info->nest;
for (j = 1; j <= sit->commonNesting; ++j) {
backward.distanceKnown[j] = d_info->distanceKnown[j];
if (backward.distanceKnown[j])
backward.distance[j] = -d_info->distance[j];
}
}
filterValid(sit->oitype, sit->access1, sit->access2,
sit->commonNesting, d_info,
access_lexically_preceeds(sit->access1, sit->access2));
if (omegaPrintResult == 1) {
fprintf(debug2, "%%%%%%%%%%%%%%%%%%%%%%%% ");
dd_to_debug(d_info);
fprintf(debug2, "\n");
}
if (sit->access1 != sit->access2) {
filterValid(sit->iotype, sit->access2, sit->access1,
sit->commonNesting, &backward,
access_lexically_preceeds(sit->access2, sit->access1));
if (omegaPrintResult == 1) {
fprintf(debug2, "%%%%%%%% backward %%%%%% ");
dd_to_debug(&backward);
fprintf(debug2, "\n");
}
}
} /* noteDependence */
/* info used during construction */
typedef struct {
int unknownDirection[maxCommonNest];
int unknownDirections;
} unknowns;
/*
process the omega test problem into dependence vectors
if dependencies are not coupled, just read them out.
else break into cases for each possible dependence in (+,0,-)
in each dimension by doing a recursive call
each time a dependence vector is found, call noteDependence to store it
*/
static void
findDirectionVector(Problem * prob, situation *sit,
dir_and_dist_info *d_info, unknowns *u_info)
{
int i, j;
int l, u, coupled;
int l2, u2, best, score, bestScore;
int unprotectThese[maxCommonNest];
int numToUnprotect = 0;
int simplificationNeeded = u_info->unknownDirections == 0;
int initialUnknownDirections = u_info->unknownDirections;
u2 = 2;
l2 = -2;
bestScore = 10000;
best = -1; /* keep compiler from complaining, allow later assertion */
for (i = 0; i < u_info->unknownDirections; i++) {
j = u_info->unknownDirection[i];
d_info->distanceKnown[j] = 0;
coupled = queryVariable(prob, j, &l, &u);
if (l == u) {
d_info->distanceKnown[j] = 1;
d_info->distance[j] = l;
}
else {
if (l > 1) l = 1;
else if (l < -1) l = -1;
if (u < -1) u = -1;
else if (u > 1) u = 1;
}
if (!coupled || l == u) {
dddirsetonly(d_info->direction, 0, j);
if (l < 0) dddirset(d_info->direction, ddgt, j);
if (l <= 0 && 0 <= u) dddirset(d_info->direction, ddeq, j);
if (0 < u) dddirset(d_info->direction, ddlt, j);
d_info_do_eq(d_info, j);
unprotectThese[numToUnprotect++] = j;
u_info->unknownDirection[i] =
u_info->unknownDirection[--u_info->unknownDirections];
i--;
if (coupled) simplificationNeeded = 1;
}
else if (coupled && initialUnknownDirections == 1
&& prob->getVarsN() + prob->getNumSUBs() == 2
&& prob->getNumEqs() + prob->getNumSUBs() == 1)
{
dddirsetonly(d_info->direction,
queryVariableSigns(prob, j,
ddlt, ddeq, ddgt,
negInfinity, posInfinity,
&(d_info->distanceKnown[j]),
&(d_info->distance[j])),
j);
d_info_do_eq(d_info, j);
noteDependence(sit, d_info);
return;
}
else {
score = 2 * (u - l) + j;
if (prob->getVarsN() > 1 && prob->forwardingAddress[j] > 0)
score -= 3;
if (score <= bestScore) {
u2 = u;
l2 = l;
best = j;
bestScore = score;
}
}
}
if (u_info->unknownDirections == 0) {
prob->_safeVars = 0;
prob->setNumSUBs(0);
if (!simplificationNeeded || solve(prob, UNKNOWN))
noteDependence(sit, d_info);
}
else {
for (i = 0; i < numToUnprotect; i++) {
j = unprotectThese[i];
unprotectVariable(prob, j);
}
if (simplificationNeeded ||
(u_info->unknownDirections == 1 && initialUnknownDirections > 1))
{
simplifyProblem(prob);
findDirectionVector(prob, sit, d_info, u_info);
}
else {
int s;
int oldUnknownDirections;
int oldUnknownDirection[maxCommonNest];
if (u_info->unknownDirections == 2
&& prob->getVarsN() == 1
&& prob->getNumSUBs() == 1)
{
i = u_info->unknownDirection[0];
j = u_info->unknownDirection[1];
if (prob->forwardingAddress[i] != -1) {
int t;
t = i;
i = j;
j = t;
}
if (prob->forwardingAddress[i] == -1
&& prob->forwardingAddress[j] == 1)
{
int j1, j2, j3, i1, i2, i3;
j1 = ddlt;
i1 = queryVariableSigns(prob, i,
ddlt, ddeq, ddgt, 1, posInfinity,
&(d_info->distanceKnown[i]),
&(d_info->distance[i]));
if (d_info->distanceKnown[i]) {
dddirsetonly(d_info->direction, i1, i);
dddirsetonly(d_info->direction, j1, j);
/* dddirsetonly(d_info->restraint, i1, i);not needed */
dddirsetonly(d_info->restraint, j1, j);
noteDependence(sit, d_info);
i1 = 0;
}
j2 = ddeq;
i2 = queryVariableSigns(prob, i, ddlt, ddeq, ddgt, 0, 0,
&(d_info->distanceKnown[i]),
&(d_info->distance[i]));
if (d_info->distanceKnown[i]) {
int oldDistj = d_info->distance[j];
bool oldDistKj = d_info->distanceKnown[j];
dddirsetonly(d_info->direction, i2, i);
dddirsetonly(d_info->direction, j2, j);
assert(j2 == ddeq);
d_info->distanceKnown[j] = 1;
d_info->distance[j] = 0;
/* dddirsetonly(d_info->restraint, i2, i);not needed */
dddirsetonly(d_info->restraint, j2, j);
noteDependence(sit, d_info);
i2 = 0;
d_info->distanceKnown[j] = oldDistKj;
d_info->distance[j] = oldDistj;
}
j3 = ddgt;
i3 = queryVariableSigns(prob, i,
ddlt, ddeq, ddgt, negInfinity, -1,
&(d_info->distanceKnown[i]),
&(d_info->distance[i]));
if (d_info->distanceKnown[i]) {
dddirsetonly(d_info->direction, i3, i);
dddirsetonly(d_info->direction, j3, j);
/* dddirsetonly(d_info->restraint, i3, i);not needed */
dddirsetonly(d_info->restraint, j3, j);
noteDependence(sit, d_info);
i3 = 0;
}
d_info->distanceKnown[i] = 0;
if (i3 == i2) {
j2 |= j3;
i3 = 0;
}
if (i2 == i1) {
j1 |= j2;
i2 = 0;
}
if (i3 == i1) {
j1 |= j3;
i3 = 0;
}
if (i1) {
bool oldDisti = d_info->distance[i];
bool oldDistKi = d_info->distanceKnown[i];
bool oldDistj = d_info->distance[j];
bool oldDistKj = d_info->distanceKnown[j];
dddirsetonly(d_info->direction, i1, i);
dddirsetonly(d_info->direction, j1, j);
/* dddirsetonly(d_info->restraint, i1, i);not needed */
dddirsetonly(d_info->restraint, j1, j);
d_info_do_eq(d_info, i);
d_info_do_eq(d_info, j);
noteDependence(sit, d_info);
d_info->distanceKnown[i] = oldDistKi;
if (oldDistKi) d_info->distance[i] = oldDisti;
d_info->distanceKnown[j] = oldDistKj;
if (oldDistKj) d_info->distance[j] = oldDistj;
}
if (i2) {
bool oldDisti = d_info->distance[i];
bool oldDistKi = d_info->distanceKnown[i];
bool oldDistj = d_info->distance[j];
bool oldDistKj = d_info->distanceKnown[j];
dddirsetonly(d_info->direction, i2, i);
dddirsetonly(d_info->direction, j2, j);
/* dddirsetonly(d_info->restraint, i2, i);not needed */
dddirsetonly(d_info->restraint, j2, j);
d_info_do_eq(d_info, i);
d_info_do_eq(d_info, j);
noteDependence(sit, d_info);
d_info->distanceKnown[i] = oldDistKi;
if (oldDistKi) d_info->distance[i] = oldDisti;
d_info->distanceKnown[j] = oldDistKj;
if (oldDistKj) d_info->distance[j] = oldDistj;
}
if (i3) {
bool oldDisti = d_info->distance[i];
bool oldDistKi = d_info->distanceKnown[i];
bool oldDistj = d_info->distance[j];
bool oldDistKj = d_info->distanceKnown[j];
dddirsetonly(d_info->direction, i3, i);
dddirsetonly(d_info->direction, j3, j);
/* dddirsetonly(d_info->restraint, i3, i);not needed */
dddirsetonly(d_info->restraint, j3, j);
d_info_do_eq(d_info, i);
d_info_do_eq(d_info, j);
noteDependence(sit, d_info);
d_info->distanceKnown[i] = oldDistKi;
if (oldDistKi) d_info->distance[i] = oldDisti;
d_info->distanceKnown[j] = oldDistKj;
if (oldDistKj) d_info->distance[j] = oldDistj;
}
return;
}
}
assert(best >= 0);
if (omegaPrintResult == 1)
fprintf(debug2,
"doing recursive analysis of %d..%d on var %s (#%d)\n",
l2, u2,
(*prob->_getVarName)(best, prob->_getVarNameArgs), best);
j = best;
i = 0;
while (u_info->unknownDirection[i] != j)
i++;
u_info->unknownDirection[i] =
u_info->unknownDirection[--u_info->unknownDirections];
oldUnknownDirections = u_info->unknownDirections;
for (i = 0; i < u_info->unknownDirections; i++)
oldUnknownDirection[i] = u_info->unknownDirection[i];
for (s = l2; s <= u2; s++) {
Problem tmpProblem;
dddirection oldDirection = d_info->direction;
dddirection oldRestraint = d_info->restraint;
int oldDistj = d_info->distance[j];
int oldDistKj = d_info->distanceKnown[j];
problemcpy(&tmpProblem, prob);
if (omegaPrintResult == 1)
fprintf(debug2, "considering sign = %d of %s (%d)\n", s,
(*prob->_getVarName)(best, prob->_getVarNameArgs),
best);
if (s == 0) {
d_info->distance[j] = 0;
d_info->distanceKnown[j] = 1;
}
else {
d_info->distanceKnown[j] = 0;
}
dddirsetonly(d_info->direction, dd_convert[s + 1], j);
dddirsetonly(d_info->restraint, dd_convert[s + 1], j);
d_info_inv(d_info);
if (constrainVariableSign(&tmpProblem, black, j, s))
findDirectionVector(&tmpProblem, sit, d_info, u_info);
if (s < u2) {
d_info->direction = oldDirection;
d_info->restraint = oldRestraint;
d_info->distance[j] = oldDistj;
d_info->distanceKnown[j] = oldDistKj;
d_info->dd_graph_node_to_be_cloned = 0;
u_info->unknownDirections = oldUnknownDirections;
for (i = 0; i < u_info->unknownDirections; i++)
u_info->unknownDirection[i] = oldUnknownDirection[i];
}
}
}
}
} /* findDirectionVector */
/*
calculateDDVectors just calls findDirectionVector now.
The arrays dddir[] and dddist[] need to have at least
maxnest+1 spaces allocated
*/
extern int nonConvex;
void calculateDDVectors(Problem *problemPtr, a_access access1, a_access access2,
ddnature oitype, ddnature iotype,
uint nest1, uint nest2, uint bnest, uint nonloops)
{
int i;
situation sit;
unknowns u_info;
dir_and_dist_info d_info;
d_info.dd_graph_node_to_be_cloned = 0;
d_info.nest = bnest;
u_info.unknownDirections = bnest;
for (i = 0; i < u_info.unknownDirections; i++)
u_info.unknownDirection[i] = i + 1;
#if defined newTimeTrials
if (storeResult) {
int e;
int reducable = ((problemPtr->_safeVars) == 1);
int coupledSubstitutions = 0;
int coupled = 0;
int nonUnary = 0;
for (e = problemPtr->_numSUBs - 1; e >= 0; e--)
if (problemPtr->_SUBs[e].coef[0] != 0)
reducable = 0;
for (e = problemPtr->_numGEQs - 1; e >= 0; e--) {
if (!singleVarGEQ(problemPtr->_GEQs[e], problemPtr->_nVars))
coupled = 1;
for (i = problemPtr->_nVars; i > 0; i--)
if (problemPtr->_GEQs[e].coef[i] > 1
|| problemPtr->_GEQs[e].coef[i] < -1)
nonUnary = 1;
};
for (e = problemPtr->_numSUBs - 1; e >= 0; e--) {
for (i = problemPtr->_nVars; i > 0; i--)
if (problemPtr->_SUBs[e].coef[i] != 0)
coupledSubstitutions = 1;
};
ddCategory[0] = 0;
if (reducable)
strncat(ddCategory, "r ", TINYBUFSIZ);
if (coupledSubstitutions)
strncat(ddCategory, "s ", TINYBUFSIZ);
if (coupled)
strncat(ddCategory, "c ", TINYBUFSIZ);
if (nonUnary)
strncat(ddCategory, "u ", TINYBUFSIZ);
if (nonConvex)
strncat(ddCategory, "v ", TINYBUFSIZ);
}
#endif
sit.access1 = access1;
sit.access2 = access2;
sit.oitype = oitype;
sit.iotype = iotype;
sit.nest1 = nest1;
sit.nest2 = nest2;
sit.commonNesting = bnest;
d_info.direction = 0;
d_info.restraint = -1;
/* d_info built by findDirectionVector */
findDirectionVector(problemPtr, &sit, &d_info, &u_info);
}

View File

@@ -0,0 +1,371 @@
/* ddomega.c,v 1.1 1993/09/17 22:13:51 fbodin Exp */
/*
Basic data dependence test using the omega test -
dd_omega_test determines if two array accesses might access the same element
Also, functions to manipulate the structures used to
represent various sorts of problems that we pass to the
omega test.
Naming convention: Many of these functions and structures
refer to "read iteration" or "write iteration" as if a
test were being performed on flow dependence(s), even when
the test works for other forms of dependence.
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "include/flags.h"
#include "include/portable.h"
#include "include/debug.h"
#include "include/ip.h"
#include "include/lang-interf.h"
#include "include/ddomega-build.h"
#include "include/ddomega-use.h"
#include "include/ddomega.h"
#include "include/Exit.h"
#include "include/timeTrials.h"
Problem deltas; /* original problem -- needed in refine */
/*
perform the omega test on the array accesses access1 and access2
see dddriver.h for a description of arguments.
* Entry -> fetch/update dependencies.
* write/update -> ExitNode dependencies.
* Added by vadik 11/08/92.
*/
PROC void dd_omega_test(a_access access1, a_access access2, ddnature oitype, ddnature iotype, uint nest1, uint nest2, uint bnest)
{
Problem prob;
delta_prob_desc dpd; /* must have extent >= that of "prob" */
int subs_may_equal;
#if defined newTimeTrials
if (storeResult) omegaTests++;
#endif
assert(access1 == Entry || access2 == ExitNode ||
accesss_sym(access2) == accesss_sym(access1)); /* same var */
assert(!(access_fetch_p(access1) && access_store_p(access2)));
assert(oitype != ddanti);
/* if omitTopLevel, we are only interested in parallelizing loops,
and thus don't care about data dependencies between things
that don't share any common loops */
if (omitTopLevel && bnest == 0)
{
dir_and_dist_info d_info;
d_info.nest = 0;
d_info.dd_graph_node_to_be_cloned = 0;
if (access_lexically_preceeds(access1, access2))
{
store_dependence(oitype, access1, access2, &d_info);
}
else if (access_lexically_preceeds(access2, access1))
{
store_dependence(iotype, access2, access1, &d_info);
}
/* else access1 == access2 or they're in different branches of an if */
return;
}
subs_may_equal = build_delta_prob_desc(&dpd, &prob, access1, access2,
nest1, nest2, bnest);
if (omegaPrintResult == 1) {
fprintf(debug2, "\n\nconsidering dependency:\n");
fprintf(debug2, "\tfrom a %s of %s at statement %d\n",
access_store_p(access1) || access1 == Entry ? "store" :
(access_fetch_p(access1) ? "read" : "update"),
access_as_string(access1), accesss_lineno(access1));
fprintf(debug2, "\tto a %s of %s at statement %d\n",
access_store_p(access2) ? "store" :
(access_fetch_p(access2) || access2 == ExitNode ? "read" : "update"),
access_as_string(access2), accesss_lineno(access2));
printProblem(&prob);
}
if (subs_may_equal && simplifyProblem(&prob)) {
/* call omega test to add directions */
calculateDDVectors(&prob, access1, access2, oitype, iotype,
nest1, nest2, bnest, r_length(&dpd.nonloops));
}
#if defined newTimeTrials
if (storeResult) realOmegaTests++;
#endif
}/* dd_omega_test */
/* functions used to build "delta problem description" */
int build_delta_prob_desc(delta_prob_desc *dpd, Problem *prob,
a_access access1, a_access access2,
int nest1, int nest2, int bnest)
{
var_id consts[maxVars],
vars1[maxVars], vars2[maxVars],
steps1[maxVars], steps2[maxVars];
int Nconsts, Nsteps1, Nsteps2, subs_may_equal;
/* PART 1: find sets of variables to be used in problem */
Nsteps1 = Nsteps2 = Nconsts = 0;
load_bounds_and_count_steps(access1, vars1, steps1, &Nsteps1);
load_bounds_and_count_steps(access2, vars2, steps2, &Nsteps2);
load_constants_for_bounds(access1, consts, &Nconsts);
load_constants_for_bounds(access2, consts, &Nconsts);
load_constants_for_subscripts(access1, consts, &Nconsts);
load_constants_for_subscripts(access2, consts, &Nconsts);
/* PART 2: assign columns to variables */
delta_init(dpd, prob, black, bnest,
nest1, vars1, nest2, vars2, Nconsts, consts,
Nsteps1, steps1, Nsteps2, steps2);
assert(bnest == prob->_safeVars);
/* PART 3: build problem */
bound_indices_and_conditionals(prob, &dpd->access1s, &dpd->steps1,
&dpd->nonloops,
black, access1);
bound_indices_and_conditionals(prob, &dpd->access2s, &dpd->steps2,
&dpd->nonloops,
black, access2);
subs_may_equal = equate_subscripts(prob, &dpd->access1s, &dpd->access2s,
&dpd->nonloops,
black, access1, access2);
/* PART 4: clean up */
#if ! defined NDEBUG
delta_inv(dpd, prob);
#endif
delta_cleanup(dpd);
return subs_may_equal;
}
/* name information for buffers in getVarName fns */
#define MaxNameLen 254
#define MaxSuffixLen 1
#if ! defined NDEBUG
static int var_id_is_step_expr(var_id n)
{
return n == 0;
}
void delta_inv(delta_prob_desc *dpd, Problem *p)
{
int v;
assert(p->getVarsN() < maxVars);
assert(p->getVarsN() >= delta_Nvars(dpd));
assert(p->_safeVars == r_length(&dpd->deltas));
assert(r_length(&dpd->deltas) <= r_length(&dpd->access1s));
assert(r_length(&dpd->deltas) <= r_length(&dpd->access2s));
assert(r_first(&dpd->deltas) == 1);
assert(r_last(&dpd->deltas) + 1 == r_first(&dpd->access1s));
assert(r_last(&dpd->access1s) + 1 == r_first(&dpd->access2s));
assert(r_last(&dpd->access2s) + 1 == r_first(&dpd->nonloops));
assert(r_last(&dpd->nonloops) + 1 == r_first(&dpd->steps1));
assert(r_last(&dpd->steps1) + 1 == r_first(&dpd->steps2));
for (v = 0; v < r_length(&dpd->deltas); v++) {
assert(var_id_index_p(dpd->vars[v + r_first(&dpd->deltas)]));
assert(var_ids_loop_no(dpd->vars[v + r_first(&dpd->deltas)]) == v + 1);
assert(var_id_index_p(dpd->vars[v + r_first(&dpd->access1s)]));
assert(var_ids_loop_no(dpd->vars[v + r_first(&dpd->access1s)]) == v + 1);
assert(var_id_index_p(dpd->vars[v + r_first(&dpd->access2s)]));
assert(var_ids_loop_no(dpd->vars[v + r_first(&dpd->access2s)]) == v + 1);
}
for (v = r_length(&dpd->deltas); v < r_length(&dpd->access1s); v++) {
assert(var_id_index_p(dpd->vars[v + r_first(&dpd->access1s)]));
assert(var_ids_loop_no(dpd->vars[v + r_first(&dpd->access1s)]) == v + 1);
}
for (v = r_length(&dpd->deltas); v < r_length(&dpd->access2s); v++) {
assert(var_id_index_p(dpd->vars[v + r_first(&dpd->access2s)]));
assert(var_ids_loop_no(dpd->vars[v + r_first(&dpd->access2s)]) == v + 1);
}
for (v = 0; v < r_length(&dpd->nonloops); v++) {
assert(var_id_const_p(dpd->vars[v + r_first(&dpd->nonloops)]));
assert((var_ids_tag(dpd->vars[v + r_first(&dpd->nonloops)]) ==
v + r_first(&dpd->nonloops)) ||
(var_ids_tag(dpd->vars[v + r_first(&dpd->nonloops)]) == UNTAGGED));
}
for (v = 0; v < r_length(&dpd->steps1); v++) {
assert(var_id_is_step_expr(dpd->vars[v + r_first(&dpd->steps1)]));
}
for (v = 0; v < r_length(&dpd->steps2); v++) {
assert(var_id_is_step_expr(dpd->vars[v + r_first(&dpd->steps2)]));
}
for (v = 0; v < p->getNumGEqs(); v++) {
assert(p->_GEQs[v].touched);
}
}
#endif
static char *delta_getVarName(uint v, void *args)
{
delta_prob_desc *dpd = (delta_prob_desc*)args;
static char name[MaxNameLen + MaxSuffixLen + 1];
assert(v <= delta_Nvars(dpd));
if (dpd->vars[v] &&
(var_id_index_p(dpd->vars[v]) || var_id_const_p(dpd->vars[v])))
{
strncpy(name, var_ids_name(dpd->vars[v]), MaxNameLen);
name[MaxNameLen] = 0;
}
else {
assert(var_id_is_step_expr(dpd->vars[v]));
strcpy(name, "<trip>");
}
if (r_in(&dpd->deltas, v))
strcat(name, "^");
else if (r_in(&dpd->access1s, v) || r_in(&dpd->steps1, v))
strcat(name, "1");
else if (r_in(&dpd->access2s, v) || r_in(&dpd->steps2, v))
strcat(name, "2");
return name;
}
/*
set up all fields in delta_prob_desc
copy info from a1_vars, a2_vars, and sc_vars into "omega_vars"
a1_vars and a2_vars have been set by load_bounds_and_count_steps
that is, they run from element 1 to depth+Nsteps
sc_vars have been set up by the load_constants functions
it runs from 0 to Nconsts - 1
change tags on nodes for symbolic constants to be the
indices into "vars" -- that is, the indices in the IP variable array
change order of steps to be outer loop to inner and
adjust tags accordingly (this way the common loop steps
can (and will) be aligned)
add equalities for the definitions of the deltas to p
*/
void delta_init(delta_prob_desc *dpd, Problem *p,
int delta_color, uint Nd,
uint Na1, var_id a1_vars[],
uint Na2, var_id a2_vars[],
uint Nsc, var_id sc_vars[],
uint Ns1, var_id s1_vars[],
uint Ns2, var_id s2_vars[])
{
int v;
dpd->deltas._first = 1;
dpd->deltas._length = Nd;
dpd->access1s._first = 1 + Nd;
dpd->access1s._length = Na1;
dpd->access2s._first = 1 + Nd + Na1;
dpd->access2s._length = Na2;
dpd->nonloops._first = 1 + Nd + Na1 + Na2;
dpd->nonloops._length = Nsc;
dpd->steps1._first = 1 + Nd + Na1 + Na2 + Nsc;
dpd->steps1._length = Ns1;
dpd->steps2._first = 1 + Nd + Na1 + Na2 + Nsc + Ns1;
dpd->steps2._length = Ns2;
if (delta_Nvars(dpd) > maxVars) {
assert(0 && "Problem too big");
fprintf(stderr, "Too many variables for omega test\n");
Exit(2);
/* We really should add all possible dependencies here */
}
dpd->vars[0] = 0;
/* a1[1..Na1] and a2[1..Na2] are valid */
for (v = 0; v < r_length(&dpd->deltas); v++) {
assert(a1_vars[v + 1] == a2_vars[v + 1]);
assert(a1_vars[v + 1] != NIL);
dpd->vars[v + r_first(&dpd->deltas)] =
dpd->vars[v + r_first(&dpd->access1s)] =
dpd->vars[v + r_first(&dpd->access2s)] = a1_vars[v + 1];
}
for (v = r_length(&dpd->deltas); v < r_length(&dpd->access1s); v++) {
assert(a1_vars[v + 1] != NIL);
dpd->vars[v + r_first(&dpd->access1s)] = a1_vars[v + 1];
}
for (v = r_length(&dpd->deltas); v < r_length(&dpd->access2s); v++) {
assert(a2_vars[v + 1] != NIL);
dpd->vars[v + r_first(&dpd->access2s)] = a2_vars[v + 1];
}
/* sc_vars[0..Nsc-1] are valid */
for (v = 0; v < Nsc; v++) {
assert(sc_vars[v] != NIL);
dpd->vars[v + r_first(&dpd->nonloops)] = sc_vars[v];
var_ids_tag(sc_vars[v]) = v + r_first(&dpd->nonloops);
}
/* s1_vars[0..Ns1] and s2_vars[0..Ns2] hold steps
FROM INNERMOST TO OUTERMOST LOOPS */
for (v = 0; v < Ns1; v++) {
assert(s1_vars[Ns1 - 1 - v] == NIL);
dpd->vars[v + r_first(&dpd->steps1)] = s1_vars[Ns1 - 1 - v];
}
for (v = 0; v < Ns2; v++) {
assert(s2_vars[Ns2 - 1 - v] == NIL);
dpd->vars[v + r_first(&dpd->steps2)] = s2_vars[Ns2 - 1 - v];
}
init_prob(p, delta_Nvars(dpd), r_length(&dpd->deltas), delta_getVarName, dpd);
set_deltas(p, delta_color, &dpd->deltas, &dpd->access1s, &dpd->access2s);
#if ! defined NDEBUG
delta_inv(dpd, p);
#endif
}
/* clear the tags for symbolic constants */
void delta_cleanup(delta_prob_desc *dpd)
{
int v;
for (v = 0; v < r_length(&dpd->nonloops); v++) {
var_ids_tag(dpd->vars[v + r_first(&dpd->nonloops)]) = UNTAGGED;
}
}

View File

@@ -0,0 +1,16 @@
/* debug.c,v 1.1.1.2 1992/07/10 02:42:51 davew Exp */
#include "include/portable.h"
#include <stdio.h>
#include "include/debug.h"
#include "include/missing.h"
int n_strange_occurances = 0;
FILE *debug2;
void strange_occurance(char *message)
{
n_strange_occurances++;
fprintf(debug2, message);
}

View File

@@ -0,0 +1,14 @@
void Message_Add(char * str);
void Exit(int c);
void ErrAssert(char *t);
#ifdef MIN
#undef MIN
#endif
#ifdef MAX
#undef MAX
#endif
static int inline MIN(int X, int Y) { return ((X) < (Y) ? (X) : (Y)); }
static int inline MAX(int X, int Y) { return ((X) > (Y) ? (X) : (Y)); }

View File

@@ -0,0 +1,12 @@
/* add-assert.h,v 1.1 1993/09/17 22:14:04 fbodin Exp */
#ifndef Already_Included_AddAssert
#define Already_Included_AddAssert 1
#include "portable.h"
#include "lang-interf.h"
typedef enum { impossible, possible, too_hard } elimination_possible;
elimination_possible possible_to_eliminate(dd_current dd);
#endif

View File

@@ -0,0 +1,52 @@
/* affine.h,v 1.1 1993/09/17 22:14:06 fbodin Exp */
#ifndef Already_Included_Affine
#define Already_Included_Affine 1
#include "lang-interf.h"
#include "ip.h"
/* This file defines the affine_expr structure and macros & functions
that are independent of tiny - that is, code that examines existing
affine expressions. Code that builds affine expressions from the
parse tree, or part of the parse tree, is in find_affine.h, as that
code is tiny-specific.
*/
typedef struct {
var_id tiny_var; /* pointer to symbol table entry */
int coefficient; /* co-efficient */
} affine_term;
typedef struct _affine_expr {
int nterms;
affine_term terms[maxVars]; /* 1st entry var is always 0 */
struct _affine_expr *other_branch; /* if min or max */
} affine_expr;
#define is_affine(AE) ( (AE) != &not_affine )
#define node_is_affine(NODE) ( (NODE)->nodeaffine != (void *)&not_affine )
extern bool nodes_subs_are_affine(a_access A);
/* the above is needed only for one assertion - for some
array access A, return true iff all subscripts of A are affine */
#ifdef __cplusplus
extern "C" affine_expr not_affine;
#else
extern affine_expr not_affine;
#endif
/* affine_expr should point to not_affine if expression is not affine */
/* compare 2 affine exprs.
return 1 if different, 0 if same
*/
int CmpAffineExprs(affine_expr *, affine_expr *);
/* return a copy allocated with malloc */
affine_expr *CopyAffineExpr(affine_expr *);
void FreeAffineExpr(affine_expr *);
#endif

View File

@@ -0,0 +1,36 @@
/* cover.h,v 1.1 1993/09/17 22:14:07 fbodin Exp */
#ifndef Already_Included_cover
#define Already_Included_cover
/*
test to see if a dependence covers to_acc
can be used for flow or output dependences
*/
int test_for_coverage(a_access from_acc, a_access to_acc,
uint from_nest, uint to_nest, uint common_nest,
dir_and_dist_info *dd, char *dd_as_string);
/*
test to see if a dependence terminates from_acc
can be used for output or anti dependences
*/
int test_for_termination(a_access from_acc, a_access to_acc,
uint from_nest, uint to_nest, uint common_nest,
dir_and_dist_info *dd, char *dd_as_string);
typedef enum { really_not_there = 0,
really_there = 1,
didnt_test,
non_affine_red_bound,
non_affine_red_sub } possible_reasons;
extern possible_reasons why_no_cover_or_terminator;
#define set_reason(X) (why_no_cover_or_terminator = (X))
#define because(X) (why_no_cover_or_terminator == (X))
/* use: if (!cover(...))
if(because(non_affine_red)) ...
*/
#endif

View File

@@ -0,0 +1,69 @@
typedef long unsigned int dddirection;
/* directions: */
#define ddlt (dddirection)0x1
#define ddeq (dddirection)0x2
#define ddgt (dddirection)0x4
#define ddall (dddirection)0x7
#define ddrr (dddirection)0x8
#define ddne (dddirection)0xd
#define ddanydir (dddirection)0xf
/* #define ddeqeq (dddirection)0x10000000 unused */
#define ddallnone (dddirection)0
#define ddcovers (dddirection)0x80000000
#define ddterminates (dddirection)0x40000000
#define ddrefined (dddirection)0x20000000
#define ddisCovered (dddirection)0x10000000
#define ddisTerminated (dddirection)0x08000000
#define ddisRefined (dddirection)0x04000000 /* what dd was before refine */
#define ddkilled (dddirection)0x02000000
#define ddzappableWC (dddirection)0x01000000
#define ddzappable (dddirection)0x00800000
#define dddirBits (dddirection)0x00777777
/* added new flags 2/92 - 3/92 davew@cs.umd.edu */
/* test to see if a dd has been killed by a kill or cover */
#define ddisDead(d) ((d) & (ddkilled | ddisCovered | ddisTerminated| ddisRefined))
/* shift a direction 'd' to appropriate position for nest 'n' */
#define dddirnest(d,n) ((d)<<(((n)-1)*4))
/* test if direction vector 'dv' has direction 'd' set at nest 'n' */
#define dddirtest(dv,d,n) ((dv)&dddirnest(d,n))
/* test if direction vector 'dv' all-equal bit set */
#define ddeqtest(dv) ((dv)&(ddallequal))
/* return direction vector except for direction n */
#define ddallBut(dv,n) ((dv)&(dddirBits & ~dddirnest(ddall,n)))
/* set direction 'd' at nest 'dv' for nest 'n' */
#define dddirset(dv,d,n) (dv|=dddirnest(d,n))
/* reset all directions at nest 'n' in 'dv' except for 'd' */
#define dddironly(dv,d,n) (dv=(((dv)&~dddirnest(ddanydir,n))|((dv)&dddirnest(d,n))))
/* reset all directions at nest 'n' in 'dv', then set 'd' */
#define dddirsetonly(dv,d,n) (dv=(((dv)&~dddirnest(ddanydir,n))|(dddirnest(d,n))))
/* set all-equal bit in 'dv' */
#define ddeqset(dv) (dv|=(ddallequal))
/* reset direction 'd' at nest 'n' in 'dv' */
#define dddirreset(dv,d,n) (dv&=(~dddirnest(d,n)))
/* reset all-equal bit in 'dv' */
#define ddeqreset(dv) (dv&=(~(ddallequal)))
/* extract direction vector element at nest 'n' from 'dv' */
#define ddextract1(dv,n) (((dv)>>(((n)-1)*4))&0xF)
/* test direction 'd' in extracted direction vector element 'dv' */
#define ddtest1(dv,d) ((dv)&(d))
/* reset direction 'd' in extracted direction vector element 'dv' */
#define ddreset1(dv,d) (dv&=(~(d)))
/* set direction 'd' in extracted direction vector element 'dv' */
#define ddset1(dv,d) (dv|=(d))
/* filter all direction vector elements with direction 'd' set in 'dv' */
#define ddfilter(dv,d) (((dv)&((d)|(d<<4)|(d<<8)|(d<<12)|(d<<16)|(d<<20)|(d<<24)))/d)
/* set all filtered direction vector elements to direction 'd' */
#define ddsetfilter(dv,f,d) (dv|=((f)*(d)))
/* unknown distance */
#define ddunknown (dddirection)0x80000000
/* return the depth of the loop that carries dv, or the length+1 for loop ind.
dv has only the 0 bit set at levels [1 .. dd_carried_by(dv, length(dv))]
*/
extern int dd_carried_by(dddirection dv, int length);
extern int leading_zeros(dddirection dv, int length);
extern void append_dd_flags(char *, dddirection dv);
/* code for the above is currently in ddodriver.c */

View File

@@ -0,0 +1,148 @@
/* ddomega-build.h,v 1.1 1993/09/17 22:14:08 fbodin Exp */
#ifndef Already_Included_DDOmega_Build
#define Already_Included_DDOmega_Build
#include "range.h"
#include "ip.h"
/* adjust the problem to include equality of subscript expressions at
nodes access1 and access2. Index variables for access1 are looked
up in range i1, and those for access2 in range i2. The non-index
variables are looked up in the range non_i.
returns 0 if subscripts could not possibly be equal
returns 1 if the conditions for their equality have been completely
described by the constraints added to p
returns 2 if there was a non-affine expression, in which case the
constraints added to p must be true for equality (but they
may also be true for some non-equal cases). If color==red,
we stop trying to bound subscripts immediately.
*/
typedef enum { not_possible = 0, complete = 1, partial = 2 } equate_descr;
equate_descr equate_subscripts(Problem *p, range *i1, range *i2, range *non_i,
int color, a_access access1, a_access access2);
/* Establish bounds for the loop indices and conditionals
that enclose node n.
If we come across a non-affine expression return 0.
If we successfully bound everything return 1.
Note that we finish doing all the bounds we can,
in either case, so zapping will work well.
Assume that "outer" outer loops have been taken care of
in some other way - i.e. that we are building the red
part of some problem which represents a dependence with
"outer" leading 0's, so we will take care of these
variables by setting them equal to the black loop indices.
If "skip_outer_ifs_containing_me" is non-nil, any ifs
that are within exactly "outer" loops and contain it in
either the "then" or "else" code.
This corresponds to the situation:
for1
for2
if1 then
if2a then
access a
endif
if2b then
access skip_outer_ifs_containing_me
endif
endif
endfor
endfor
in which we want to skip if1 when bounding a in the 0,0 dependence
from a to skip_outer_ifs_containing_me. Note that we don't have to
distinguish between the then & else parts, as we can't have a 0,0
if one access is is each.
*/
int
bound_inner_indices_and_conditionals(Problem *p,
range *indices,range *steps,range *non_i,
int outer, a_access skip_outer_ifs_containing_me,
int color, a_access a);
#define bound_indices_and_conditionals(P,IND,ST,NONI,COL,A) \
bound_inner_indices_and_conditionals(P,IND,ST,NONI,0,NULL,COL,A)
/* in the functions below,
var_id points to op_declare for symbolic constants,
op_dolimit for index variables
or some sort of expression for iteration #'s
in 1st & 2nd cases, node's value points to S.T. entry */
/* set bounds[1...depth(n)] to point to the dolimits of the loops containing n
set *Nsteps to the # of loops that have step expressions
set steps[0 ... *Nsteps - 1] to point to these step expressions
also set the nodetag field of any step expressions to their index
into the steps array. Steps for inner loops come first in "steps".
*/
void load_bounds_and_count_steps(a_access n, var_id bounds[],
var_id steps[], int *Nsteps);
/* ensure that all symbolic constants used in affine subscript
expressions appear in consts[0..*Nconsts-1], and that they
are tagged with their indices.
*Nconsts should be set before calling this function
*/
void load_constants_for_subscripts(a_access access,
var_id consts[], int *Nconsts);
/* same for affine expressions used in loop bounds of loops surrounding n
*Nconsts should be set before calling this function
*/
void load_constants_for_bounds(a_access n, var_id consts[], int *Nconsts);
/* low-level more problem manipulation functions */
void init_prob(Problem *p, uint Nvars, uint Nprot,
char *(*getVarName)(unsigned int, void *),
void *getVarNameArgs);
uint prob_add_EQ(Problem *p, int color);
uint prob_add_zero_EQ(Problem *p, int color);
uint prob_add_GEQ(Problem *p, int color);
uint prob_add_zero_GEQ(Problem *p, int color);
/* delta = access1 - access2, so for flow dep, delta = write - read */
void set_deltas(Problem *p, int delta_color,
range *deltas, range *a1, range *a2);
/*
Constrain a problem with the minimal constraints needed to
enforce the direction vector in dd.
Use restraint vector unless it is not convex or the direction
vector is "=".
*/
void constrain_with_dd(Problem *pr, range *dd_to, range *dd_from,
dir_and_dist_info *dd, int color);
/*
Constrain *pr with the direction vector in dd.
*/
void constrain_with_dddirs(Problem *pr, range *dd_to, range *dd_from,
dir_and_dist_info *dd, int color);
/*
*dir MUST NOT BE +-
Constrain *pr with dimension j of *dir.
Use equations of color "color".
It handles 0 by adding both var[j] >= 0 and var[j] <= 0,
which is not bad, because red equalities are just converted back
to pairs of inequalities anyway. Perhaps it would be better to
add special case code for black 0's.
*/
void constrain_with_convex_dddir(Problem *pr, range *dd_to, range *dd_from,
dddirection *dir, int j, int color);
#endif

View File

@@ -0,0 +1,12 @@
/* ddomega-use.h,v 1.1 1993/09/17 22:14:09 fbodin Exp */
#ifndef Already_Included_DDOmega_Use
#define Already_Included_DDOmega_Use
/* compute DD vectors, add them to nodes */
void calculateDDVectors(Problem *problemPtr, a_access access1,a_access access2,
ddnature oitype, ddnature iotype,
uint nest1, uint nest2, uint bnest, uint nonloops);
#endif

View File

@@ -0,0 +1,77 @@
/* ddomega.h,v 1.1 1993/09/17 22:14:10 fbodin Exp */
/*
This file now contains only the main dependence test function.
see refine.h, cover.h, and kill.h for the other functions that
used to be declared here.
The structures used in these functions are now also declared here.
*/
#ifndef Already_Included_DDOmega
#define Already_Included_DDOmega
/*
perform the omega test on the array accesses access1 and access2
see dddriver.h for a description of "dd" arguments.
*/
void dd_omega_test(a_access access1, a_access access2,
ddnature oitype, ddnature iotype,
uint nest1, uint nest2, uint bnest);
#include "range.h"
#include "ip.h"
extern var_id *current_set_of_vars; /* used in getVarName fns */
/*
delta problem description contains information needed
to associate variable accesses in the tiny program with
variables in the integer programming problem.
The different ranges show which part of the array of
variables in the IP problem correspond to different
accesses in the tiny program.
*/
typedef struct {
range deltas; /* deltas for common indices */
range access1s; /* index variables for access 1 */
range access2s; /* index variables for access 2 */
range nonloops; /* symbolic constants */
range steps1; /* step constraints for a1 */
range steps2; /* step constraints for a1 */
var_id vars[maxVars];
} delta_prob_desc;
/*
build a delta_prob_desc for the dependence from access1 to access2,
return 0 if it obviously can't have solutions because
the subscripts obviously can't be equal.
Note that *dpd should be allocated at least as long as *prob,
since the _getVarNameArgs filed of *prob will point to it.
*/
int build_delta_prob_desc(delta_prob_desc *dpd, Problem *prob,
a_access access1, a_access access2,
int nest1, int nest2, int bnest);
/* the following are used by build_delta_prob_desc */
void delta_init(delta_prob_desc *dpd, Problem *p,
int delta_color, uint Nd,
uint Na1, var_id a1_vars[],
uint Na2, var_id a2_vars[],
uint Nsc, var_id sc_vars[],
uint Ns1, var_id s1_vars[],
uint Ns2, var_id s2_vars[]);
void delta_inv(delta_prob_desc *dpd, Problem *p);
void delta_cleanup(delta_prob_desc *dpd);
#define delta_Nvars(dpd) (r_last(&(dpd)->steps2))
#endif

View File

@@ -0,0 +1,5 @@
/* debug.h,v 1.1.1.2 1992/07/10 02:40:09 davew Exp */
extern int n_strange_occurances;
extern FILE *debug2;
extern void strange_occurance(char *message);

View File

@@ -0,0 +1,47 @@
/*
* Global flag variables
*/
#if !defined(GLOB)
#define GLOB extern
#endif
GLOB int quiet;
GLOB int AllowComments;
GLOB int ivr_on;
GLOB int ivr_debug;
GLOB int ivr_ElimUnused;
GLOB int ivr_DepAnalysis;
GLOB int ivr_Assert;
GLOB int ivr_RepAffine;
GLOB int ivr_DefEntryClass;
GLOB int ivr_SubstScalars;
GLOB int makeReductionOps;
GLOB int doArrayExpn;
GLOB int repeatArrayExpn;
GLOB int doPrivatization;
GLOB int arrDefInOut;
GLOB int doEEdeps;
#if defined OMIT_DDS_FOR_TOPLEVEL
#define omitScalars 1
#else
GLOB int omitScalars;
#endif
GLOB int debugLevel;
GLOB int omegaPrintResult;
GLOB int printing_zap_gists;
#if ! defined SKIP_OMEGA2
GLOB int skipping_omega2;
#endif
#if defined OMIT_DDS_FOR_TOPLEVEL
#define omitTopLevel 1
#else
GLOB int omitTopLevel;
#endif
GLOB char **Argv;
GLOB int Argc;

View File

@@ -0,0 +1,273 @@
#ifndef Already_Included_IP
#define Already_Included_IP 1
#include <stdio.h>
#include <vector>
#include <algorithm>
#define maxVars 50
#define maxGEQs 150
#define maxEQs 27
typedef int EqnKey;
typedef struct _eqn
{
/*_eqn()
{
coef.resize(maxVars + 1);
std::fill(coef.begin(), coef.end(), 0);
key = 0;
touched = 0;
color = 0;
}*/
EqnKey key;
int touched;
int color;
std::vector<int> coef;
//int coef[maxVars + 1];
} *Eqn;
#define headerWords 3
typedef struct _problem
{
private:
int _nVars;
int _numEQs, _numGEQs, _numSUBs;
void resizeEqs()
{
//printf("%d %d %d -> %d\n", _numEQs, _numGEQs, _numSUBs, _nVars + 2);
for (int z = 0; z < _numEQs; ++z)
_EQs[z].coef.resize(_nVars + 2);
for (int z = 0; z < _numGEQs; ++z)
_GEQs[z].coef.resize(_nVars + 2);
for (int z = 0; z < _numSUBs; ++z)
_SUBs[z].coef.resize(_nVars + 2);
}
public:
_problem()
{
_numEQs = _numGEQs = 0;
_numSUBs = 1;
forwardingAddress.resize(maxVars + 2);
_var.resize(maxVars + 2);
_GEQs.resize(maxGEQs);
_EQs.resize(maxEQs);
_SUBs.resize(maxVars + 1);
}
void _init()
{
forwardingAddress.resize(maxVars + 2);
_var.resize(maxVars + 2);
_GEQs.resize(maxGEQs);
_EQs.resize(maxEQs);
_SUBs.resize(maxVars + 1);
}
void _init(int eqs, int ges, int subs, int nvars)
{
_nVars = nvars;
_numEQs = eqs;
_numGEQs = ges;
_numSUBs = subs;
resizeEqs();
}
int getVarsN() const { return _nVars; }
void setVarsN(const int nvars)
{
_nVars = nvars;
resizeEqs();
}
void addToVarsN(const int nvars)
{
_nVars += nvars;
resizeEqs();
}
int getNumEqs() const { return _numEQs; }
int getNumGEqs() const { return _numGEQs; }
int getNumSUBs() const { return _numSUBs; }
void setNumEqs(const int val)
{
_numEQs = val;
//printf("EQ %d -> %d\n", _numEQs, _nVars + 2);
for (int z = 0; z < _numEQs; ++z)
_EQs[z].coef.resize(_nVars + 2);
}
void setNumGEqs(const int val)
{
_numGEQs = val;
//printf("GEQ %d -> %d\n", _numGEQs, _nVars + 2);
for (int z = 0; z < _numGEQs; ++z)
_GEQs[z].coef.resize(_nVars + 2);
}
void setNumSUBs(const int val)
{
_numSUBs = val;
//printf("SUB %d -> %d\n", _numSUBs, _nVars + 2);
for (int z = 0; z < _numSUBs; ++z)
_SUBs[z].coef.resize(_nVars + 2);
}
void addNumEqs(const int val)
{
_numEQs += val;
//printf("EQ %d -> %d\n", _numEQs, _nVars + 2);
for (int z = 0; z < _numEQs; ++z)
_EQs[z].coef.resize(_nVars + 2);
}
void addNumGEqs(const int val)
{
_numGEQs += val;
//printf("GEQ %d -> %d\n", _numGEQs, _nVars + 2);
for (int z = 0; z < _numGEQs; ++z)
_GEQs[z].coef.resize(_nVars + 2);
}
void addNumSUBs(const int val)
{
_numSUBs += val;
//printf("SUB %d -> %d\n", _numSUBs, _nVars + 2);
for (int z = 0; z < _numSUBs; ++z)
_SUBs[z].coef.resize(_nVars + 2);
}
int _safeVars;
int hashVersion;
int variablesInitialized;
int variablesFreed;
std::vector<int> _var;
//int _var[maxVars + 2];
std::vector<int> forwardingAddress;
//int forwardingAddress[maxVars + 2];
char *(*_getVarName)(unsigned int var, void *args);
void *_getVarNameArgs;
std::vector<_eqn> _GEQs;
//_eqn _GEQs [maxGEQs];
std::vector<_eqn> _EQs;
//_eqn _EQs[maxEQs];
std::vector<_eqn> _SUBs;
//_eqn _SUBs[maxVars + 1];
} Problem;
#define UNKNOWN 2
#define SIMPLIFY 3
#define posInfinity (0x7ffffff)
#define negInfinity (-0x7ffffff)
#define red 1
#define black 0
//#define eqnncpy(e1,e2,s) {int *p00,*q00,*r00; p00 = (int *)(e1); q00 = (int *)(e2); r00 = &p00[headerWords+1+s]; while(p00 < r00) *p00++ = *q00++; }
static void eqnncpy(_eqn *dst, const _eqn *src, const int s)
{
dst->color = src->color;
dst->key = src->key;
dst->touched = src->touched;
dst->coef.resize((src->coef.size() > s + 2) ? src->coef.size() : s + 2);
std::fill(dst->coef.begin(), dst->coef.end(), 0);
for (int z = 0; z < ((src->coef.size() < s + 1) ? src->coef.size() : s + 1); ++z)
dst->coef[z] = src->coef[z];
}
#define eqncpy(e1,e2) eqnncpy(e1, e2, nVars)
//#define eqnnzero(e,s) { int *p00,*r00; p00 = (int *)(e); r00 = &p00[headerWords+1+(s)]; while(p00 < r00) *p00++ = 0;}
static void eqnnzero(_eqn *dst, const int s)
{
dst->color = 0;
dst->key = 0;
dst->touched = 0;
dst->coef.resize(s + 2);
for (int z = 0; z < s + 2; ++z)
dst->coef[z] = 0;
}
#define eqnzero(e) eqnnzero(e,nVars)
#define intDiv(a,b) ((1024 * b + a)/b - 1024)
#define intMod(a,b) ((a)-(b)*intDiv(a,b))
#define singleVarGEQ(e,nV) ((e).key != 0 && -maxVars <= (e).key && (e).key <= maxVars)
extern void initializeOmega();
extern void initializeProblem(Problem *);
extern void problemcpy(Problem *, Problem *);
extern void printProblem(Problem *);
extern void printRedEquations(Problem *);
extern void prettyPrintProblem(Problem *);
extern int simplifyProblem(Problem *);
extern int simplifyApproximate(Problem *);
extern void unprotectVariable(Problem *, int var);
extern void negateGEQ(Problem *, int);
/* set extra to 0 for normal use */
extern void printEqn (Problem *p, Eqn e, int is_geq, int extra);
extern void sprintEqn (char *str, Problem *p, Eqn e, int is_geq, int extra);
/*
Return 1 if red equations constrain the set of possible solutions.
We assume that there are solutions to the black equations by themselves,
so if there is no solution to the combined problem, we return 1.
*/
extern int hasRedEquations(Problem * problemPtr, bool expensive);
extern int eliminateRedundant (Problem *problemPtr, bool expensive);
extern void eliminateRed (Problem *problemPtr, bool eliminateAll);
/* constrainVariableSign also unprotects var & simplifies the problem */
extern int
constrainVariableSign(Problem *, int color, int var, int sign);
/* constrainVariableValue adds an EQ that makes variable var have
value "value", even if variable i has been substituted out */
extern void
constrainVariableValue(Problem *problemPtr, int color, int var, int value);
extern int
queryVariable(Problem *, int var, int *lowerBound, int *upperBound);
extern int
queryVariableSigns(Problem *, int, int, int, int, int,
int,
bool *,
int*);
extern int
queryVariableBounds(Problem * problemPtr, int i, int *l, int *u);
extern int solve(Problem *problemPtr, int desiredResult);
extern void setOutputFile(FILE *file);
/* set "file" to the file to which the output of printProblem should go */
extern int reduceWithSubs;
extern int omegaPrintResult;
/* set to non-zero to have constrainVariableSign and simplifyProblem
print the resulting simplified problems */
extern int firstCheckForRedundantEquations;
extern void (*whenReduced)(Problem *problemPtr);
extern void noProcedure(Problem *problemPtr);
extern void Exit(int c);
#endif

View File

@@ -0,0 +1,79 @@
/* kill.h,v 1.1 1993/09/17 22:14:14 fbodin Exp */
#ifndef Already_Included_kill
#define Already_Included_kill
/*
Do quick but possibly indecisive kill tests to see
if dependence dd (from from_acc to to_acc) is killed.
If dd is obviously killed by an intervening write that
covers its destination or terminaties its source,
return ddisCovered or ddisTerminated.
Otherwise, return 0 (is which case dd may or may not be killed -
call accurate_test_for_kill to find out).
this_dep identifies the dependence being tested, so that we will
not try to kill a dependence with itself. this_dep will be
passed to dd_i_i_cur_is and dd_o_i_cur_is.
This function may update dd if dd is partly killed.
In this case, dd's ddrefined bit will be set.
Quick test for kill works for flow, output, or anti dependences
*/
dddirection
quick_test_for_kill(dir_and_dist_info *dd, char *dd_as_string,
a_access from_acc, a_access to_acc,
dd_current this_dep);
/*
Test to see if flow dependence dd (from from_acc to to_acc)
can be killed. If so, return ddisKilled.
This should be called if quick_test_for_kill returns 0.
Works for flow and output dependences - why not anti?
*/
dddirection
accurate_test_for_kill(dir_and_dist_info *dd, char *dd_as_string,
a_access from_acc, a_access to_acc,
dd_current this_dep);
/*
for "READS" type problems,
non-index vars and reads are protected
This type of problem is used in killing, cover & termination testing,
and in refinement
*/
typedef struct {
range nonloops;
range reads; /* index variables @ time of read */
range rsteps;
range write1s; /* index variables @ time of write #1 */
range w1steps;
range write2s; /* index variables @ time of write #2 */
range w2steps;
var_id vars[maxVars];
} read_prob_desc;
/* there is no equivalent to build_delta_prob_desc, as the various
functions that build read_prob_desc's do so in different ways. */
typedef enum { sc_and_r, sc_r_and_w1 } protect_in_read;
void read_init(read_prob_desc *rpd, Problem *p,
protect_in_read protect_which, uint Nsc, var_id sc_vars[],
uint Nr, var_id r_vars[], uint Nrs, var_id rs_vars[],
uint Nw1, var_id w1_vars[], uint Nw1s, var_id w1s_vars[],
uint Nw2, var_id w2_vars[], uint Nw2s, var_id w2s_vars[]);
void read_inv(read_prob_desc *rpd, Problem *p);
void read_cleanup(read_prob_desc *rpd);
#define read_Nvars(rpd) (r_last(&(rpd)->w2steps))
#endif

View File

@@ -0,0 +1,373 @@
/* lang-interf.generic,v 1.1 1993/09/17 22:14:15 fbodin Exp */
/*
Omega-test to programming language interface spec
To adapt the omega test to do data dependence for some language other
than tiny, use the files ip.[hc], ddomega.[hc], ddomega-use.[hc],
ddomega-build.[hc], cover.[ch], kill.[ch], refine.[ch], add-assert.[ch],
debug.[hc], and portable.h unchanged.
Modify affine.c to create affine_expr structures for each expression
that may be relevent to the omega test (loop bounds and array
subscripts). You may or may not need to modify affine.h.
Modify ddodriver.c, or provide your own code, to call the omega test
for all the array pairs where you need to test for dependence, and
call the test_for_cover, test_for_termination, quick_test_for_kill
and accurate_test_for_kill if you wish to use them. If you are
feeling bold, you may even want to try to get the "zap" functions
"possible_to_eliminate" and "try_to_eliminate" (in add-assert.c) to
work.
The flags in omega2flags.h control some of the optional behaviors
that can be obtained from the dependence killing & refining code.
They affect both ddodriver.c and the files that you do not need to
change.
If you want to have debugging output, make sure you open the debug
file and set omegaPrintResult to 1.
Create a file lang-interf.h, defining numerous macros that the
omega test needs to access the parsed program. Your lang-interf.h
can be based on this generic version, or the lang-interf.h that we
wrote for tiny, depending on whether you prefer to read my cryptic
comments here or my even more cryptic code there. In the generic
version, the macros are defined to produce a meaningless result of
the right type, so that ddomega.c, ddomega-use.c, and ddomega-build.c
can all be compiled.
In case of trouble, please feel free to contact me at:
davew@cs.umd.edu
Department of Computer Science
A. V. Williams Building
University of Maryland
College Park, Maryland 20742
Remember that it is a federal crime to send explosives or certain
other dangerous materials in the U.S. Mail.
David Wonnacott
*/
#define NOT_TINY 1
/* Note:
The omega test data dependence functions, and the macros defined
here, often require strings giving the printed representations of
data dependences or array accesses, etc. These strings are used
only for generating debugging output in trace.out. If you don't
care about debugging output, you can just make anything with the
word "string" in it = "".
*/
/* define the maximum length of a data dependence vector */
#define maxCommonNest 6 /* (32 bits - 6 used in dddir.h) / 4 bits per dd */
typedef enum { ddflow, ddanti, ddoutput, ddreduce } ddnature;
/* define the type "a_access", which identifies an array access,
and provides access to information about the access (such as
its depth, line number, the symbol accessed, and the type of
access (read or write)).
It must also be possible to extract information about the
subscript expressions used in the access, with "sub_i_for_access",
information about the "context" of an access (the enclosing reads
& writes), with "cont_i_for_access", and information about the
dependences to or from an access, as per the stuff later in this file.
accesss_cover_depth and accesss_terminator_depth must be lvalues
where we can store the depth at which the access is covered or
terminated. These should both be initialized to -1.
accesss_shared_depth must give the number of loops contianing both
A1 and A2.
Two a_accesses must be equal in a self-dependence test
If there is no existing structure that provides all this information,
you may need to create an aggregate with pointers to the different
structures you use.
*/
typedef void *a_access;
#define access_as_string(A) ("a[i]") /* only used in debugging output */
#define accesss_sym(A) (void *)0 /* currently only used in 1 assertion */
#define accesss_lineno(A) 42 /* currently only in debugging output */
#define accesss_cover_depth(A) ( *((int *) 0) )
#define accesss_terminator_depth(A) ( *((int *) 0) )
#define accesss_depth(A) 7
#define accesss_shared_depth(A1,A2) 6
/* does A access a private var - if so, at what level is it private? */
#define access_private_var_p(A) 0
#define access_private_var_level(A) 3
#define access_fetch_p(A) 1
#define access_store_p(A) 1
#define access_update_p(A) 1
/* Are A1 and A2 updates of the same kind (ie both += or both *=) */
#define access_same_update_type_p(A1, A2) 1
/* can we execute A1 and then A2 without going to another iteration */
#define access_lexically_preceeds(A1, A2) 1
/* pointers to Entry and Exit node for testing for dependence to
points before or after the routine being analyzed. It must
be possible to compare these to a variable of type a_access */
#define Entry ((a_access)0)
#define ExitNode ((a_access)0)
/* define the type "sub_iterator" - an iterator over the
subscripts of an array access. We need to test these
subscripts to see if they are affine expressions of the
loop index variables and symbolic constants, and if so,
find the associated affine_expr structure.
We also need to have access to all the variables used in
the expression (for the purpose of building the set of
variables used), via the function sub_i_map_over_cur_vars,
which calls F(V,ARGS) for each variable V in the expression.
*/
typedef void *sub_iterator;
#define sub_i_for_access(A) ((sub_iterator *) 0)
#define sub_i_next(SUBI)
#define sub_i_done(SUBI) (1)
#define sub_i_cur_is_affine(SUBI) (1)
#define sub_i_cur_affine(SUBI) ((affine_expr *) 0)
#define sub_i_map_over_cur_vars(SUBI,F,ARGS)
/* define the type "sub_iterator" - an iterator over the
enclosing contexts of an array access. Each cont_i_next
operation must select the next enclosing loop or if.
We must be able to tell which we have selected, and
get a "loop_context" or "if_context" object from it.
*/
typedef void *context_iterator;
extern context_iterator cont_i_for_access(a_access a);
#define cont_i_next(C)
#define cont_i_done(C) 1
#define cont_i_cur_loop_p(C) 1
#define cont_i_cur_if_p(C) 0
#define cont_i_cur_if(C) (C)
#define cont_i_cur_loop(C) (C)
#define cont_i_cur_depth(C) 7
/* cur_depth valid for loops - # of loops around stmts in this loop */
/* cur_depth is also needed for ifs as of release 3.0 */
#define access_is_in_then_or_else_of(A,C) 0
/* access A is in the then or the else part of C,
where cont_i_cur_if_p must be true of C */
#define cont_i_cur_lineno(C) 42
/* a "loop_context" provides information about a loop.
We need to be able to find affine_exprs for the start
and end bounds (if a bound is not affine, we should
get a result for which "is_affine" is false).
We also need to know if there is a step expression,
and whether it is known at compile time, and if so,
what it is. These last two must be answered by the
function "loops_step(LOOP,S,KNOWN)", which sets *KNOWN
to true if the step is known at compile time, and sets
*S to the step if it is known.
We must also be able to map a function over all the
variables used in the start and end bounds (as we did
for the variables used in the step expressions).
*/
typedef void *loop_context;
#define loop_var_id(LOOP) ((var_id *) 0)
#define loop_start(LOOP) ((affine_expr *) 0)
#define loop_end(LOOP) ((affine_expr *) 0)
#define loop_has_step_p(LOOP) 1
#define loops_step(LOOP,S,KNOWN) { *S = 2; *KNOWN = 1; }
#define loop_map_over_start_vars(LOOP,F,ARGS)
#define loop_map_over_end_vars(LOOP,F,ARGS)
/* an "if context" provides information about the conditions
surrounding an array access.
The current code can handle ifs with single >, >=, <, or <= conditions.
Note that it is not OK to just leave this out - it will prevent the
refinement, cover, termination, and kill tests from determining whether
or not they have exact information.
If, for some reason, you can not supply this information,
make sure that the context iterator for an array access in an if
yeilds one if_context for which if_condition_ok is false
*/
typedef void *if_context;
typedef enum { greater = 0, greater_eq = 1, less = 2, less_eq = 3 }
if_compare_operators;
#define if_condition_ok(IC) (0)
#define if_compare_op(IC) (greater) /* one of if_compare_operators */
#define if_compare_left(IC) ((affine_expr *) 0) /* lhs of compare op */
#define if_compare_right(IC) ((affine_expr *) 0) /* rhs of compare op */
#define if_else_branch(IC) (0) /* true in body of "else" clause */
#define if_map_over_vars(IC,F,ARGS)
/* define the type used to identify a variable (typically
a pointer into the symbol table or some such).
It must be possible to tell the difference between a loop
index and a symbolic constant, and for a loop index, we must
be able to find the depth of the loop.
We must also be able to associate a integer "tag" with each
variable - all tags must start out with the value UNTAGGED.
*/
typedef void *var_id;
#define var_id_const_p(AE_VAR) (1)
#define var_id_index_p(AE_VAR) (1)
#define var_ids_loop_no(AE_VAR) (7 /* depth of associated loop */ )
#define var_ids_tag(AE_VAR) (*(int *)0)
#define var_ids_name(AE_VAR) ("a variable name") /* only for debug */
#define UNTAGGED -1
/* representations of Data Dependences follow -
You probably should not change these, but simply convert from
this format into whatever you use, and vice versa, when getting
information from/to the omega test
*/
/* information about dd direction vectors.
works only if unsigned long int has at least 32 bits */
#include "dddir.h"
/*
A dir_and_dist_info structure contains information about a dependence
This is the form in which some of the omega test functions expect
dependence information.
*/
typedef struct {
uint nest;
dddirection direction;
dddirection restraint;
bool distanceKnown[maxCommonNest];
int distance[maxCommonNest];
void * dd_graph_node_to_be_cloned;
/* dd_graph_node_to_be_cloned points to the structure
that must be duplicated when we need to make a copy
of an existing entry in the dependence graph using
the function clone_dd_graph_node_for_refinement */
} dir_and_dist_info;
/* Duplicate the dd graph node, setting "isRefined" in the copy.
This bit will hopefully get cleaner in the next release */
void clone_dd_graph_node_for_refinement(void *dd_graph_node_to_be_cloned);
#define d_info_do_eq(D_INFO, J) \
if (ddextract1((D_INFO)->direction,(J)) == ddeq) \
{ \
(D_INFO)->distanceKnown[(J)] = 1; \
(D_INFO)->distance[(J)] = 0; \
}
#if ! defined NDEBUG
#define d_info_inv(D_INFO) \
{ \
int i; \
for (i=1; i<=(D_INFO)->nest; i++) { \
if (ddextract1((D_INFO)->direction,i) == ddeq) { \
assert((D_INFO)->distanceKnown[i] && \
(D_INFO)->distance[i] == 0); \
} \
} \
}
#else
#define d_info_inv(X)
#endif
/*
odd_iterators are now obsolete.
they have been replaced.
*/
/* dd_in_iterators and dd_out_iterators allow iteration thru all the
dependences into a given access or out of a given access.
We may need to find the source or destination node of the current
dependence, or find out whether it is a flow or output dependence,
and whether it covers or terminates.
We must also be able to identify a dependence, so that we don't
test it against itself in certain circumstances
For either type, we must be able to select the current dependence,
which we identify with the type dd_current.
From this current element, we may determine the nesting level, or
information about the dependence distances or directions or the
restraint vector.
*/
typedef void *dd_in_iterator; /* iterate thru dds in to an access */
typedef void *dd_out_iterator; /* iterate thru dds out from an access */
typedef void *dd_current; /* point to the dd the iterator is on */
#define dd_current_nest(DDC) (3)
#define dd_current_dist(DDC) ((int *)0) /* distance array */
#define dd_current_dist_known(DDC,j) 1 /* dd_current_dist(DDC)[j] meaningful?*/
#define dd_current_dir(DDC) (*((dddirection *)0)) /* direction */
#define dd_current_restr(DDC) (*((dddirection *)0)) /* restraint */
#define dd_current_as_string(DDC) "a dependence"
#define dd_current_src(DDC) ((a_access) 0)
#define dd_current_dest(DDC) ((a_access) 0)
#define dd_i_i_for_access(ACC) ((dd_in_iterator) 0)
#define dd_i_i_done(DD_I_I) (1)
#define dd_i_i_next(DD_I_I)
#define dd_i_i_current(DD_I_I) ((dd_current) 0)
#define dd_i_i_cur_src(DD_I_I) ((a_access) 0)
#define dd_i_i_cur_dest(DD_I_I) ((a_access) 0)
#define dd_i_i_cur_flow_p(DD_I_I) 0
#define dd_i_i_cur_output_p(DD_I_I) 0
#define dd_i_i_cur_cover_p(DD_I_I) 0
#define dd_i_i_cur_is(DD_I_I, DEP) (dd_i_i_current(DD_I_I) == (DEP))
#define dd_o_i_for_access(ACC) ((dd_out_iterator) 0)
#define dd_o_i_done(DD_O_I) 1
#define dd_o_i_next(DD_O_I)
#define dd_o_i_current(DD_O_I) ((dd_current) 0)
#define dd_o_i_cur_src(DD_O_I) ((a_access) 0)
#define dd_o_i_cur_dest(DD_O_I) ((a_access) 0)
#define dd_o_i_cur_output_p(DD_O_I) 0
#define dd_o_i_cur_terminate_p(DD_O_I) 0
#define dd_o_i_cur_is(DD_O_I, DEP) (dd_o_i_current(DD_O_I) == (DEP))
/* the function "store_dependence" will be called when the omega test
has detected a data dependence. It should convert from the
dir_and_dist_info into whatever form is used by the rest of the system */
void store_dependence(ddnature nature, a_access from_access,
a_access to_access, dir_and_dist_info *d_info);
/* convert dd nodes into stuff our functions can handle */
void ddnode_to_dir_and_dist(dd_current, dir_and_dist_info *);
/* copy info from a dir_and_dist_info into an existing dd node */
void dir_and_dist_into_ddnode(const dir_and_dist_info *ddi, dd_current);
/* take inequality number GEQ, and turn it into an assertion */
#define add_GEQ_assertion(P, VARS, GEQ) ;

View File

@@ -0,0 +1,503 @@
/* lang-interf.h,v 1.2 1994/07/05 15:34:09 fbodin Exp */
#ifndef Already_Included_Lang_Interf
#define Already_Included_Lang_Interf 1
/*
Omega-test to programming language interface spec
To adapt the omega test to do data dependence for some language other
than tiny, use the files ip.[hc], ddomega.[hc], ddomega-use.[hc],
ddomega-build.[hc], cover.[ch], kill.[ch], refine.[ch], add-assert.[ch],
debug.[hc], and portable.h unchanged.
Modify affine.c to create affine_expr structures for each expression
that may be relevent to the omega test (loop bounds and array
subscripts). You may or may not need to modify affine.h.
Modify ddodriver.c, or provide your own code, to call the omega test
for all the array pairs where you need to test for dependence, and
call the test_for_cover, test_for_termination, quick_test_for_kill
and accurate_test_for_kill if you wish to use them. If you are
feeling bold, you may even want to try to get the "zap" functions
"possible_to_eliminate" and "try_to_eliminate" (in add-assert.c) to
work.
The flags in omega2flags.h control some of the optional behaviors
that can be obtained from the dependence killing & refining code.
They affect both ddodriver.c and the files that you do not need to
change.
If you want to have debugging output, make sure you open the debug
file and set omegaPrintResult to 1.
Create a file lang-interf.h, defining numerous macros that the
omega test needs to access the parsed program. Your lang-interf.h
can be based on this generic version, or the lang-interf.h that we
wrote for tiny, depending on whether you prefer to read my cryptic
comments here or my even more cryptic code there. In the generic
version, the macros are defined to produce a meaningless result of
the right type, so that ddomega.c, ddomega-use.c, and ddomega-build.c
can all be compiled.
In case of trouble, please feel free to contact me at:
davew@cs.umd.edu
Department of Computer Science
A. V. Williams Building
University of Maryland
College Park, Maryland 20742
Remember that it is a federal crime to send explosives or certain
other dangerous materials in the U.S. Mail.
David Wonnacott
*/
#define NOT_TINY 1
/* include for the sage macro */
/* #include "macro.h"*/
struct _affine_expr; /* define later in affine.h */
struct omegaIterator ; /* define later in this file */
struct omegaLoop; /* define later in this file */
struct omegaIf; /* define later in this file */
struct omegaVar; /* define later in this file */
struct omegaContIter;
/* Note:
The omega test data dependence functions, and the macros defined
here, often require strings giving the printed representations of
data dependences or array accesses, etc. These strings are used
only for generating debugging output in trace.out. If you don't
care about debugging output, you can just make anything with the
word "string" in it = "".
*/
/* define the maximum length of a data dependence vector */
#define maxCommonNest 10 /* (32 bits - 6 used in dddir.h) / 4 bits per dd */
typedef enum { ddflow, ddanti, ddoutput, ddreduce, dd_unknown, ddnovalue } ddnature;
/* define the type "a_access", which identifies an array access,
and provides access to information about the access (such as
its depth, line number, the symbol accessed, and the type of
access (read or write)).
It must also be possible to extract information about the
subscript expressions used in the access, with "sub_i_for_access",
information about the "context" of an access (the enclosing reads
& writes), with "cont_i_for_access", and information about the
dependences to or from an access, as per the stuff later in this file.
accesss_cover_depth and accesss_terminator_depth must be lvalues
where we can store the depth at which the access is covered or
terminated. These should both be initialized to -1.
accesss_shared_depth must give the number of loops contianing both
A1 and A2.
Two a_accesses must be equal in a self-dependence test
If there is no existing structure that provides all this information,
you may need to create an aggregate with pointers to the different
structures you use.
*/
struct omegaAccess {
char *str;
struct omegaVar *symb;
struct omegaIterator *subiter;
struct omegaContIter *context;
int inIfStmt;
int line,cdepth,tdepth;
int depth;
int idforsage;
int shareddepth;
int pri;
int level;
int fetch;
int store;
int update;
int lexord;
};
typedef struct omegaAccess *a_access;
#define access_as_string(A) (A->str) /* only used in debugging output */
#define accesss_sym(A) (A->symb) /* currently only used in 1 assertion */
#define accesss_lineno(A) (A->line) /* currently only in debugging output */
#define accesss_cover_depth(A) (A->cdepth)
#define accesss_terminator_depth(A) (A->tdepth)
#define accesss_depth(A) (A->depth)
#define accesss_shared_depth(A1,A2) (A1->shareddepth)
/* this is wrong
#define accesss_shared_depth(A1,A2) ((A1->depth > A2->depth)?(A1->depth - A2->depth):(A2->depth > A1->depth))
*/
/* does A access a private var - if so, at what level is it private? */
#define access_private_var_p(A) (A->pri)
#define access_private_var_level(A) (A->level)
#define access_fetch_p(A) (A->fetch)
#define access_store_p(A) (A->store)
#define access_update_p(A) (A->update)
/* Are A1 and A2 updates of the same kind (ie both += or both *=) */
#define access_same_update_type_p(A1, A2) 0
/* can we execute A1 and then A2 without going to another iteration */
#define access_lexically_preceeds(A1, A2) (A1->lexord > A2->lexord)
/* pointers to Entry and Exit node for testing for dependence to
points before or after the routine being analyzed. It must
be possible to compare these to a variable of type a_access */
#define Entry ((a_access)0)
#define ExitNode ((a_access)0)
/* define the type "sub_iterator" - an iterator over the
subscripts of an array access. We need to test these
subscripts to see if they are affine expressions of the
loop index variables and symbolic constants, and if so,
find the associated affine_expr structure.
We also need to have access to all the variables used in
the expression (for the purpose of building the set of
variables used), via the function sub_i_map_over_cur_vars,
which calls F(V,ARGS) for each variable V in the expression.
*/
struct omegaIterator {
struct omegaIterator *next;
int isaffine;
struct _affine_expr *affine;
struct omegaVar *constante;
int cstvalue;
} ;
typedef struct omegaIterator *sub_iterator;
#define sub_i_for_access(A) ((A)->subiter)
#define sub_i_next(SUBI) (SUBI = SUBI->next)
#define sub_i_done(SUBI) (SUBI == NULL)
#define sub_i_cur_is_affine(SUBI) (SUBI->isaffine)
#define sub_i_cur_affine(SUBI) (SUBI->affine)
/*
#define sub_i_map_over_cur_vars(SUBI,F,ARGS) {(F)(SUBI->constante,ARGS);}
*/
#define sub_i_map_over_cur_vars(SUBI,F,ARGS)
/* define the type "sub_iterator" - an iterator over the
enclosing contexts of an array access. Each cont_i_next
operation must select the next enclosing loop or if.
We must be able to tell which we have selected, and
get a "loop_context" or "if_context" object from it.
*/
struct omegaContIter {
struct omegaContIter *next;
int depth;
int line;
struct omegaLoop *loop;
struct omegaIf *ifstmt;
int loopiter;
};
typedef struct omegaContIter *context_iterator;
/*extern context_iterator cont_i_for_access(a_access a);*/
#define cont_i_for_access(A) (A->context)
#define cont_i_next(C) (C = C->next)
#define cont_i_done(C) (C == NULL)
#define cont_i_cur_loop_p(C) (C->loopiter)
#define cont_i_cur_if_p(C) (!(C->loopiter))
#define cont_i_cur_if(C) (C->ifstmt)
#define cont_i_cur_loop(C) (C->loop)
#define cont_i_cur_depth(C) (C->depth)
/* cur_depth valid for loops - # of loops around stmts in this loop */
/* cur_depth is also needed for ifs as of release 3.0 */
/* #define access_is_in_then_or_else_of(A,C) ((A)->inIfStmt)*/
extern int access_is_in_then_or_else_of(a_access A,context_iterator C);
/* access A is in the then or the else part of C,
where cont_i_cur_if_p must be true of C */
#define cont_i_cur_lineno(C) (C->line)
/* a "loop_context" provides information about a loop.
We need to be able to find affine_exprs for the start
and end bounds (if a bound is not affine, we should
get a result for which "is_affine" is false).
We also need to know if there is a step expression,
and whether it is known at compile time, and if so,
what it is. These last two must be answered by the
function "loops_step(LOOP,S,KNOWN)", which sets *KNOWN
to true if the step is known at compile time, and sets
*S to the step if it is known.
We must also be able to map a function over all the
variables used in the start and end bounds (as we did
for the variables used in the step expressions).
*/
struct omegaLoop {
struct omegaVar *symb;
struct _affine_expr *startl;
struct _affine_expr *endl;
int hasstep;
int stepl;
int knownstep;
struct omegaVar *constantestart;
int cstvaluestart;
struct omegaVar *constanteend;
int cstvaluesend;
};
typedef struct omegaLoop *loop_context;
#define loop_var_id(LOOP) (LOOP->symb)
#define loop_start(LOOP) (LOOP->startl)
#define loop_end(LOOP) (LOOP->endl)
#define loop_has_step_p(LOOP) (LOOP->hasstep)
#define loops_step(LOOP,S,KNOWN) { *S = LOOP->stepl; *KNOWN = LOOP->knownstep; }
/*
#define loop_map_over_start_vars(LOOP,F,ARGS) {(F)(LOOP->constantestart,ARGS);}
#define loop_map_over_end_vars(LOOP,F,ARGS) {(F)(LOOP->constanteend,ARGS);}
*/
#define loop_map_over_start_vars(LOOP,F,ARGS)
#define loop_map_over_end_vars(LOOP,F,ARGS)
/* an "if context" provides information about the conditions
surrounding an array access.
The current code can handle ifs with single >, >=, <, or <= conditions.
Note that it is not OK to just leave this out - it will prevent the
refinement, cover, termination, and kill tests from determining whether
or not they have exact information.
If, for some reason, you can not supply this information,
make sure that the context iterator for an array access in an if
yeilds one if_context for which if_condition_ok is false
*/
typedef enum { greater = 0, greater_eq = 1, less = 2, less_eq = 3 }
if_compare_operators;
struct omegaIf {
int condOK;
int ident;
if_compare_operators oper;
struct _affine_expr *left;
struct _affine_expr *right;
int partelse;
};
typedef struct omegaIf *if_context;
#define if_condition_ok(IC) (IC->condOK)
#define if_compare_op(IC) (IC->oper) /* one of if_compare_operators */
#define if_compare_left(IC) (IC->left) /* lhs of compare op */
#define if_compare_right(IC) (IC->right) /* rhs of compare op */
#define if_else_branch(IC) (IC->partelse) /* true in body of "else" clause */
#define if_map_over_vars(IC,F,ARGS)
/* define the type used to identify a variable (typically
a pointer into the symbol table or some such).
It must be possible to tell the difference between a loop
index and a symbolic constant, and for a loop index, we must
be able to find the depth of the loop.
We must also be able to associate a integer "tag" with each
variable - all tags must start out with the value UNTAGGED.
*/
struct omegaVar {
int loop;
int constp;
int indexp;
int tag;
char *name;
};
typedef struct omegaVar *var_id;
#define var_id_const_p(AE_VAR) (AE_VAR->constp)
#define var_id_index_p(AE_VAR) (AE_VAR->indexp)
#define var_ids_loop_no(AE_VAR) (AE_VAR->loop)
#define var_ids_tag(AE_VAR) (AE_VAR->tag)
#define var_ids_name(AE_VAR) (AE_VAR->name) /* only for debug */
#define UNTAGGED -1
/* representations of Data Dependences follow -
You probably should not change these, but simply convert from
this format into whatever you use, and vice versa, when getting
information from/to the omega test
*/
/* information about dd direction vectors.
works only if unsigned long int has at least 32 bits */
#include "dddir.h"
/*
A dir_and_dist_info structure contains information about a dependence
This is the form in which some of the omega test functions expect
dependence information.
*/
#include "portable.h"
typedef struct DD_info {
uint nest;
dddirection direction;
dddirection restraint;
bool distanceKnown[maxCommonNest];
int distance[maxCommonNest];
void * dd_graph_node_to_be_cloned;
/* dd_graph_node_to_be_cloned points to the structure
that must be duplicated when we need to make a copy
of an existing entry in the dependence graph using
the function clone_dd_graph_node_for_refinement */
DD_info()
{
nest = 0;
direction = 0;
restraint = 0;
for (int z = 0; z < maxCommonNest; ++z)
{
distanceKnown[z] = false;
distance[z] = 0;
}
dd_graph_node_to_be_cloned = NULL;
}
} dir_and_dist_info;
/* Duplicate the dd graph node, setting "isRefined" in the copy.
This bit will hopefully get cleaner in the next release */
void clone_dd_graph_node_for_refinement(void *dd_graph_node_to_be_cloned);
#define d_info_do_eq(D_INFO, J) \
if (ddextract1((D_INFO)->direction,(J)) == ddeq) \
{ \
(D_INFO)->distanceKnown[(J)] = 1; \
(D_INFO)->distance[(J)] = 0; \
}
#if ! defined NDEBUG
#define d_info_inv(D_INFO) \
{ \
int i; \
for (i=1; i<=(D_INFO)->nest; i++) { \
if (ddextract1((D_INFO)->direction,i) == ddeq) { \
if (!((D_INFO)->distanceKnown[i] && (D_INFO)->distance[i] == 0))\
{\
printf("%lld %lld %lld\n", (D_INFO)->nest, (D_INFO)->direction, (D_INFO)->restraint);\
for (int z = 0; z < maxCommonNest; ++z)\
printf("[%d]: %d %d\n", z, (D_INFO)->distanceKnown[z], (D_INFO)->distance[z]);\
}\
assert((D_INFO)->distanceKnown[i] && (D_INFO)->distance[i] == 0); \
} \
} \
}
#else
#define d_info_inv(X)
#endif
/*
odd_iterators are now obsolete.
they have been replaced.
*/
/* dd_in_iterators and dd_out_iterators allow iteration thru all the
dependences into a given access or out of a given access.
We may need to find the source or destination node of the current
dependence, or find out whether it is a flow or output dependence,
and whether it covers or terminates.
We must also be able to identify a dependence, so that we don't
test it against itself in certain circumstances
For either type, we must be able to select the current dependence,
which we identify with the type dd_current.
From this current element, we may determine the nesting level, or
information about the dependence distances or directions or the
restraint vector.
*/
typedef void *dd_in_iterator; /* iterate thru dds in to an access */
typedef void *dd_out_iterator; /* iterate thru dds out from an access */
typedef void *dd_current; /* point to the dd the iterator is on */
#define dd_current_nest(DDC) (3)
#define dd_current_dist(DDC) ((int *)0) /* distance array */
#define dd_current_dist_known(DDC,j) 1 /* dd_current_dist(DDC)[j] meaningful?*/
#define dd_current_dir(DDC) (*((dddirection *)0)) /* direction */
#define dd_current_restr(DDC) (*((dddirection *)0)) /* restraint */
#define dd_current_as_string(DDC) "a dependence"
#define dd_current_src(DDC) ((a_access) 0)
#define dd_current_dest(DDC) ((a_access) 0)
#define dd_i_i_for_access(ACC) ((dd_in_iterator) 0)
#define dd_i_i_done(DD_I_I) (1)
#define dd_i_i_next(DD_I_I)
#define dd_i_i_current(DD_I_I) ((dd_current) 0)
#define dd_i_i_cur_src(DD_I_I) ((a_access) 0)
#define dd_i_i_cur_dest(DD_I_I) ((a_access) 0)
#define dd_i_i_cur_flow_p(DD_I_I) 0
#define dd_i_i_cur_output_p(DD_I_I) 0
#define dd_i_i_cur_cover_p(DD_I_I) 0
#define dd_i_i_cur_is(DD_I_I, DEP) (dd_i_i_current(DD_I_I) == (DEP))
#define dd_o_i_for_access(ACC) ((dd_out_iterator) 0)
#define dd_o_i_done(DD_O_I) 1
#define dd_o_i_next(DD_O_I)
#define dd_o_i_current(DD_O_I) ((dd_current) 0)
#define dd_o_i_cur_src(DD_O_I) ((a_access) 0)
#define dd_o_i_cur_dest(DD_O_I) ((a_access) 0)
#define dd_o_i_cur_output_p(DD_O_I) 0
#define dd_o_i_cur_terminate_p(DD_O_I) 0
#define dd_o_i_cur_is(DD_O_I, DEP) (dd_o_i_current(DD_O_I) == (DEP))
/* the function "store_dependence" will be called when the omega test
has detected a data dependence. It should convert from the
dir_and_dist_info into whatever form is used by the rest of the system */
void store_dependence(ddnature nature, a_access from_access,
a_access to_access, dir_and_dist_info *d_info);
/* convert dd nodes into stuff our functions can handle */
void ddnode_to_dir_and_dist(dd_current, dir_and_dist_info *);
/* copy info from a dir_and_dist_info into an existing dd node */
void dir_and_dist_into_ddnode(const dir_and_dist_info *ddi, dd_current);
/* take inequality number GEQ, and turn it into an assertion */
#define add_GEQ_assertion(P, VARS, GEQ) ;
#endif

View File

@@ -0,0 +1,37 @@
/* missing.h,v 1.1.1.2 1992/07/10 02:40:55 davew Exp */
#ifndef Already_Included_Missing
#define Already_Included_Missing
/* You may need to comment these out */
extern int delwin();
extern int touchwin();
extern int waddch();
extern int waddstr();
extern int wclear();
extern int wclrtoeol();
extern int wdeleteln();
extern int wgetch();
extern int wgetstr();
extern int winsch();
extern int winsertln();
extern int wmove();
extern int wrefresh();
extern int wstandend();
extern int wstandout();
extern int printw();
extern int wprintw();
extern int mvwprintw();
extern int endwin();
extern int stty();
extern char *getwd();
extern int wait3();
extern int mkdir();
extern int getrusage();
#endif

View File

@@ -0,0 +1,50 @@
/* omega2flags.h,v 1.1 1993/09/17 22:14:18 fbodin Exp */
/* compile time and run time flags that control the behavior of the
code that eliminates dead dependences */
#ifndef Already_Included_Omega2flags
#define Already_Included_Omega2flags
#if defined SKIP_OMEGA2
#define skipping_omega2 1
#else
extern int skipping_omega2;
#endif
#if defined SKIP_ZAPPABLE
#define skipping_zappable 1
#else
#define skipping_zappable 0
#endif
#if defined ONLY_CHANGE_FLOW_LEVEL
#define skipping_plus_refinement 1
#define skipping_o_a_tightening 1
#else
#define skipping_plus_refinement 0
#define skipping_o_a_tightening 0
#endif
#if ! defined skipping_all_tightening
#define skipping_all_tightening 0
#endif
#if ! defined skipping_bailout
#define skipping_bailout 0
#endif
#if defined EXTRAVAGANT
#define doing_all_accurate_kills 1
/* do refinement of all kinds of dds: "skipping_plus_refinement" still works */
#define doing_all_refines 1
#else
#define doing_all_accurate_kills 0
/* do refinement of all kinds of dds: "skipping_plus_refinement" still works */
#define doing_all_refines 0
#endif
#endif

View File

@@ -0,0 +1,57 @@
/* portable.h,v 1.1 1993/09/17 22:14:20 fbodin Exp */
#ifndef Already_Included_Portable
#define Already_Included_Portable
/* define integer type names for portability */
/* use 'sint' and 'uint' unless space is at a premium */
typedef long int sint;
typedef char sint8;
typedef short int sint16;
typedef long int sint32;
typedef unsigned char uint8;
typedef unsigned short int uint16;
typedef unsigned long int uint32;
#ifndef __cplusplus
typedef unsigned char bool;
#endif
/* tiny uses arrays of characters to buffer I/O at various points.
These really should be dynamically sized strings, but since that
is a pain in C, we just make arrays of the following size.
In many cases, the size is not tested, so, for example, running
tiny on a file with a really long name can cause a core dump.
This ought to be at least 256, as thats the largest constant that
we replaced with TINYBUFSIZ. This is in portable.h for irony */
#define TINYBUFSIZ 256
#ifndef __TURBOC__
#include <sys/types.h>
#endif
#define uint unsigned int
#ifndef NIL
#define NIL 0L
#endif
#define ANSI_libraries
#define TYPEPROCPTR typedef
#define EXPROC extern
#define PROC
#define SWAP(TYPE, V1, V2) \
{ TYPE TMP; \
TMP = V1; \
V1 = V2; \
V2 = TMP; \
}
/*
#define MIN(X,Y) ((X)<(Y)?(X):(Y))
#define MAX(X,Y) ((X)>(Y)?(X):(Y))
*/
#endif

View File

@@ -0,0 +1,53 @@
/* portable.h.origine,v 1.1 1993/09/17 22:14:21 fbodin Exp */
#ifndef Already_Included_Portable
#define Already_Included_Portable
/* define integer type names for portability */
/* use 'sint' and 'uint' unless space is at a premium */
typedef long int sint;
typedef char sint8;
typedef short int sint16;
typedef long int sint32;
typedef unsigned char uint8;
typedef unsigned short int uint16;
typedef unsigned long int uint32;
typedef unsigned char bool;
/* tiny uses arrays of characters to buffer I/O at various points.
These really should be dynamically sized strings, but since that
is a pain in C, we just make arrays of the following size.
In many cases, the size is not tested, so, for example, running
tiny on a file with a really long name can cause a core dump.
This ought to be at least 256, as thats the largest constant that
we replaced with TINYBUFSIZ. This is in portable.h for irony */
#define TINYBUFSIZ 256
#ifndef __TURBOC__
#include <sys/types.h>
#endif
#define uint unsigned int
#ifndef NIL
#define NIL 0L
#endif
#define ANSI_libraries
#define TYPEPROCPTR typedef
#define EXPROC extern
#define PROC
#define SWAP(TYPE, V1, V2) \
{ TYPE TMP; \
TMP = V1; \
V1 = V2; \
V2 = TMP; \
}
#define MIN(X,Y) ((X)<(Y)?(X):(Y))
#define MAX(X,Y) ((X)>(Y)?(X):(Y))
#endif

View File

@@ -0,0 +1,19 @@
/* range.h,v 1.1.1.1 1992/07/10 02:41:06 davew Exp */
#ifndef Already_Included_Range
#define Already_Included_Range
typedef struct {
uint _first;
uint _length;
} range;
#define r_first(r) ((r)->_first)
#define r_last(r) ((r)->_first + (r)->_length - 1)
#define r_length(r) ((r)->_length)
#define r_in(r, i) ((i) >= r_first(r) && (i) <= r_last(r))
/* #define r_grow(r) (++(r)->_length)
grow is no longer allowed, as variables after the last region are
used for iteration number counts */
#endif

View File

@@ -0,0 +1,37 @@
/* refine.h,v 1.1 1993/09/17 22:14:23 fbodin Exp */
#ifndef Already_Included_refine
#define Already_Included_refine
/*
if from_acc is a write, try to refine the source
if to_acc is a write, try to refine the destination
(If both are writes, I think we could get a bit more refinement
by having a refine_both, which tries to refine either the source
or the destination at each loop nest. I also think this would be
so rare that its not worth writing the code.)
*d_info will be updated if refinement is successful
can be used for flow, output, or anti dependences
*/
void refine_dependence(a_access from, a_access to,
dir_and_dist_info *d_info);
/*
try to refine a covers leading 0+'s into 0's.
can be used for output or flow dependences
*/
void tighten_cover(a_access from_acc, a_access to_acc,
dir_and_dist_info *d_info,
char *dd_as_string);
/*
try to refine a terminators leading 0+'s into 0's.
can be used for output or anti dependences
*/
void tighten_terminator(a_access from_acc, a_access to_acc,
dir_and_dist_info *d_info,
char *dd_as_string);
#endif

View File

@@ -0,0 +1,124 @@
/* screen.h,v 1.1.1.2 1992/07/10 02:41:20 davew Exp */
#ifndef Already_Included_Screen
#define Already_Included_Screen
/* Define 6 screen primitives:
screen_init() what to call to initialize the graphics system.
screen_print like 'printf' to write to the virtual screen
screen_move(line,col) to move to an (line,col) position on the virtual screen
screen_where(line,col) get the current (line,col) position
screen_highlight() print with reverse video
screen_lowlight() end reverse-video printing
screen_getchar(ch,line,col) get the char at position (line,col)
[may move cursor]
screen_clear() how to clear the screen
screen_clrline(line) move to the start of line 'line' and clear it
screen_clreol() clear to end of this line from current pos
screen_clrrest() clear to end of screen from this line
screen_update() after _print, how to update the actual screen
screen_fini() what to call when done with graphics.
two variables:
COLS : number of columns on screen
LINES: number of lines on screen
0 <= line < LINES
0 <= col < COLS
*/
#ifdef __TURBOC__
/* no good way to use Turbo C to detect number of lines/cols on screen */
#define LINES 25
#define COLS 80
#include <conio.h>
/* #define screen_init() textattr((BLUE<<4)+LIGHTGRAY) */
#define screen_init() textattr((BLACK<<4)+LIGHTGRAY), 1
/* added ,1 to make it return TRUE. 3.21.91 davew@panache.cs.umd.edu */
#define screen_print cprintf
#define screen_move(line,col) gotoxy(col+1,line+1)
#define screen_where(line,col) line=wherey()-1;col=wherex()-1
/* #define screen_highlight() textattr((LIGHTGRAY<<4)+BLUE) */
/* #define screen_lowlight() textattr((BLUE<<4)+LIGHTGRAY) */
#define screen_highlight() textattr((LIGHTGRAY<<4)+BLACK)
#define screen_lowlight() textattr((BLACK<<4)+LIGHTGRAY)
#define screen_getchar(ch,line,col) \
{ char c[2];\
gettext(col+1,line+1,col+1,line+1,c);\
ch = c[2]; }
#define screen_clear() clrscr()
#define screen_clrline(line) gotoxy(1,line+1);clreol()
#define screen_clreol() clreol()
#define screen_clrrest() { uint l;\
for(l=wherey();l<=LINES-2;++l){\
gotoxy(1,l);\
clreol();\
}\
}
#define screen_update()
#define screen_fini()
#else
#include <curses.h>
#include "missing.h"
#undef bool
/* #define screen_init() initscr();refresh() */
/* Three new functions for use with scrolling */
#define screen_putchar mvaddch
#define screen_waddch mvwaddch
#define screen_insertln insertln
#define screen_deleteln deleteln
#define screen_print printw
#define screen_wprint mvwprintw
#define screen_move(line,col) move(line,col)
#define screen_where(line,col) getyx(stdscr,line,col)
#define screen_highlight() standout()
#define screen_lowlight() standend()
#define screen_dhighlight() wstandout(depend)
#define screen_dlowlight() wstandend(depend)
#define screen_touch() touchwin(stdscr)
#define screen_dtouch() touchwin(depend)
#define screen_dclose() delwin(depend)
/* get the character directly from the curses data structure so that the */
/* attribute bit is not stripped off */
#define screen_getchar(ch,line,col) ch=stdscr->_y[line][col]
#define screen_clear() { clear();\
if (depend_shown)\
wclear(depend);\
}
#define screen_clrline(line) {move(line,0);clrtoeol();}
#define screen_clreol() clrtoeol()
#define screen_clrrest() { uint l,c;\
getyx(stdscr,l,c);\
for(l=l;l<LINES-2;++l){\
move(l,0);\
clrtoeol();\
}\
}
#define screen_update() { refresh();\
if (depend_shown){\
wrefresh(depend);\
}\
}
#define screen_touch_and_update() { touchwin(stdscr); refresh();\
if (depend_shown){\
touchwin(depend); wrefresh(depend);\
}\
}
extern int screen_init();
extern void screen_fini();
/* changed to functions for better results from curses
3/20/91 davew@panache.cs.umd.edu */
#endif
WINDOW *depend;
int depend_shown;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,730 @@
/* kill.c,v 1.1 1993/09/17 22:13:59 fbodin Exp */
/*
Dependence kill tests ("quick" and "accurate")
Naming convention: Many of these functions and structures
refer to "read iteration" or "write iteration" as if a
test were being performed on flow dependence(s), even when
the test works for other forms of dependence.
*/
#include <assert.h>
#include <string.h>
#include "include/portable.h"
#include <stdio.h>
#include <stdlib.h>
#include "include/debug.h"
#include "include/ip.h"
#include "include/lang-interf.h"
#include "include/ddomega-build.h"
#include "include/ddomega-use.h"
#include "include/kill.h"
#include "include/missing.h"
#include "include/timeTrials.h"
#include "include/Exit.h"
/* The following table shows the possible results
of combining two direction vectors:
! + 0 0+ - +- 0- *
! ! ! ! ! ! ! ! !
+ ! + + + * * * *
0 ! + 0 0+ - +- 0- *
0+ ! + 0+ 0+ * * * *
- ! * - * - * - *
+- ! * +- * * * * *
0- ! * 0- * - * 0- *
* ! * * * * * * *
*/
static int ddCombine[8][8] =
{ 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 7, 7, 7, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 3, 3, 7, 7, 7, 7,
0, 7, 4, 7, 4, 7, 4, 7,
0, 7, 5, 7, 7, 7, 7, 7,
0, 7, 6, 7, 4, 7, 6, 7,
0, 7, 7, 7, 7, 7, 7, 7 };
/*
Test to see if flow dependence f (from middle_acc to to_acc) kills
the flow dependence dd (from from_acc to to_acc)
via the output dependence o (from from_acc to middle_acc).
*/
static dddirection
do_test_for_kill_via(dir_and_dist_info *dd, char *dd_as_string,
a_access from_acc, a_access middle_acc, a_access to_acc,
dd_current f, dd_current o,
int commonDepth)
{
read_prob_desc rpd; /* write1s = A[i]
write2s = B[j]
reads = C[k]
we project onto i and k, so it doesn't
matter that either A or C or neither
could be the read */
Problem reads;
dir_and_dist_info tmp_ddi;
var_id sc_vars[maxVars], r_vars[maxVars], rs_vars[maxVars];
var_id w1_vars[maxVars], w1s_vars[maxVars];
var_id w2_vars[maxVars], w2s_vars[maxVars];
int from_depth, middle_depth, to_depth;
int Nrs, Nw1s, Nw2s, Nsc;
int j, red_complete;
#if ! defined NDEBUG
int eqs, geqs;
#endif
assert(access_store_p(middle_acc) || access_update_p(middle_acc));
from_depth = accesss_depth(from_acc);
middle_depth = accesss_depth(middle_acc);
to_depth = accesss_depth(to_acc);
#if defined newTimeTrials
if (storeResult) killTests++;
#endif
#ifndef SPEED
if (omegaPrintResult) {
fprintf(debug2, "continuing check for KILL\n");
fprintf(debug2, "Does %s\n", dd_current_as_string(f));
fprintf(debug2, "Kill %s\n", dd_as_string);
fprintf(debug2, "via %s\n", dd_current_as_string(o));
}
#endif
/* Quick check to see if direction vectors are feasible */
assert(commonDepth <= dd_current_nest(o));
for (j = 1; j <= commonDepth; j++) {
if (dd->distanceKnown[j] &&
dd_current_dist_known(f, j) &&
dd_current_dist_known(o, j))
{
if (dd_current_dist(f)[j] + dd_current_dist(o)[j] !=
dd->distance[j])
break;
}
else {
int m = ddCombine[ddextract1(dd_current_dir(f), j)]
[ddextract1(dd_current_dir(o), j)];
int t = ddextract1(dd->direction, j);
if ((m & t) != t) break;
}
}
if (j <= commonDepth) { /* break occured */
if (omegaPrintResult) {
fprintf(debug2,
"kill not feasible because of dddir at level %d\n",
j);
}
return 0;
}
/* PART 1: find sets of variables to be used in problem */
Nrs = Nw1s = Nw2s = Nsc = 0;
load_bounds_and_count_steps(to_acc, r_vars, rs_vars, &Nrs);
load_bounds_and_count_steps(from_acc, w1_vars, w1s_vars, &Nw1s);
load_bounds_and_count_steps(middle_acc, w2_vars, w2s_vars, &Nw2s);
load_constants_for_bounds(to_acc, sc_vars, &Nsc);
load_constants_for_bounds(from_acc, sc_vars, &Nsc);
load_constants_for_bounds(middle_acc, sc_vars, &Nsc);
load_constants_for_subscripts(to_acc, sc_vars, &Nsc);
load_constants_for_subscripts(from_acc, sc_vars, &Nsc);
load_constants_for_subscripts(middle_acc, sc_vars, &Nsc);
/* PART 2: assign columns to variables
Protect variables representing symbolic constants,
read iteration and 1st write values of loop indices,
because we wish to test if S implies T
for all values of them. */
read_init(&rpd, &reads, sc_r_and_w1, Nsc, sc_vars,
to_depth, r_vars, Nrs, rs_vars,
from_depth, w1_vars, Nw1s, w1s_vars,
middle_depth, w2_vars, Nw2s, w2s_vars);
/* PART 3: build problem */
#if !defined NDEBUG
read_inv(&rpd, &reads);
assert(reads.getNumEqs() == 0);
assert(reads.getNumGEqs() == 0);
eqs = geqs = 0;
#endif
/* TRY TO SET UP RED "T" PROBLEM:
"j in [B] ^ A(i) << B(j) << C(k) ^ A(i) sub= B(j) sub= C(k)"
If C is not exit, we can omit A(i) sub= B(j), as it is
redundant with B(j) sub= C(k) and A(i) sub= C(k)
IF WE CAN'T ESTABLISH COMPLETE RED BOUNDS, DON'T KILL */
/* j in [B] */
red_complete =
bound_indices_and_conditionals(&reads, &rpd.write2s,
&rpd.w2steps, &rpd.nonloops,
red, middle_acc);
if (to_acc != ExitNode) {
/* B(j) sub= C(k) */
/* equate_subs can't return 0 */
red_complete = red_complete &&
equate_subscripts(&reads, &rpd.reads, &rpd.write2s,
&rpd.nonloops,
red, to_acc, middle_acc) == complete;
}
else {
/* B(j) sub= A(i) */
/* equate_subs can't return 0 */
red_complete = red_complete &&
equate_subscripts(&reads, &rpd.write1s, &rpd.write2s,
&rpd.nonloops,
red, from_acc, middle_acc) == complete;
}
if (!red_complete)
{
if (omegaPrintResult) {
fprintf(debug2, "not checking KILL - incomplete red bounds \n");
}
read_cleanup(&rpd);
return 0;
}
/* B(j) << C(k) */
ddnode_to_dir_and_dist(f, &tmp_ddi);
constrain_with_dd(&reads, &rpd.reads, &rpd.write2s, &tmp_ddi, red);
/* A(i) << B(j) */
ddnode_to_dir_and_dist(o, &tmp_ddi);
constrain_with_dd(&reads, &rpd.write2s, &rpd.write1s, &tmp_ddi, red);
#if !defined NDEBUG
read_inv(&rpd, &reads);
for ( /* eqs as it is */; eqs < reads.getNumEqs(); eqs++)
{
assert(reads._EQs[eqs].color == red);
}
for ( /* geqs as it is */; geqs < reads.getNumGEqs(); geqs++)
{
assert(reads._GEQs[geqs].color == red);
}
#endif
/* SET UP BLACK "S" PROBLEM:
"i in [A] ^ k in [C] ^ A(i) << C(k) ^ A(i) sub= C(k)" */
/* i in [A] */
bound_indices_and_conditionals(&reads, &rpd.write1s, &rpd.w1steps,
&rpd.nonloops, black, from_acc);
/* k in [C] */
bound_indices_and_conditionals(&reads, &rpd.reads, &rpd.rsteps,
&rpd.nonloops, black, to_acc);
/* A(i) sub= C(k) */
/* this must be possible, or there would not be a dependence */
equate_subscripts(&reads, &rpd.reads, &rpd.write1s, &rpd.nonloops,
black, to_acc, from_acc);
/* A(i) << C(k) */
constrain_with_dd(&reads, &rpd.reads, &rpd.write1s, dd, black);
#if !defined NDEBUG
for (/* eqs as it is */; eqs < reads.getNumEqs(); eqs++) {
assert(reads._EQs[eqs].color == black);
}
for (/* geqs as it is */; geqs < reads.getNumGEqs(); geqs++) {
assert(reads._GEQs[geqs].color == black);
}
#endif
/* PART 4: clean up */
#if ! defined NDEBUG
read_inv(&rpd, &reads);
#endif
read_cleanup(&rpd);
/* PART 5: CHECK FOR KILL: Forall i,k,Sym, does S imply T? */
if (omegaPrintResult) {
fprintf(debug2, "checking for KILL in: \n");
printProblem(&reads);
}
#if defined newTimeTrials
if (storeResult) realKillTests++;
#endif
/* There must be a solution to the black equations,
because they describe a flow dependence from A to C */
if (!hasRedEquations(&reads, 0)) {
if (omegaPrintResult) {
fprintf(debug2, "verified KILL:\n");
printProblem(&reads);
}
#if defined newTimeTrials
if (storeResult) realKills++;
#endif
return ddkilled;
}
else {
if (omegaPrintResult) {
fprintf(debug2, "no KILL:\n");
printProblem(&reads);
}
return 0;
}
}
/*
Test to see if flow dependence dd2 (from write_acc2 to read_acc) kills
the flow dependence dd1 (frow write_acc1 to read_acc).
This should be called if quick_test_for_kill returns 0.
*/
dddirection
accurate_test_for_kill(dir_and_dist_info *dd, char *dd_as_string,
a_access from_acc, a_access to_acc,
dd_current this_dep)
{
dd_in_iterator potential_killers;
#ifndef SPEED
if (omegaPrintResult) {
fprintf(debug2, "starting check for KILL of dependence:\n");
fprintf(debug2, "%s\n", dd_as_string);
}
#endif
potential_killers = dd_i_i_for_access(to_acc);
while (!dd_i_i_done(potential_killers))
{
/* search for intervening writes or different updates */
if ((access_store_p(dd_i_i_cur_src(potential_killers)) ||
(access_update_p(dd_i_i_cur_src(potential_killers)) &&
!access_same_update_type_p(dd_i_i_cur_src(potential_killers),
to_acc) &&
!access_same_update_type_p(dd_i_i_cur_src(potential_killers),
from_acc))) &&
!dd_i_i_cur_is(potential_killers, this_dep))
{
dd_out_iterator o;
int commonDepth;
commonDepth = MIN(dd->nest, dd_current_nest(dd_i_i_current(potential_killers)));
o = dd_o_i_for_access(from_acc);
while (!dd_o_i_done(o))
{
if (dd_i_i_cur_src(potential_killers) == dd_o_i_cur_dest(o))
{
/* test for kill with output dep "o" */
dddirection d;
d = do_test_for_kill_via(dd, dd_as_string,
from_acc, dd_o_i_cur_dest(o),
to_acc,
dd_i_i_current(potential_killers),
dd_o_i_current(o), commonDepth);
if (d)
return d;
}
dd_o_i_next(o);
}
}
dd_i_i_next(potential_killers);
}
return 0;
}
/* The following table shows whether dd1 is strictly < dd2,
strictly <= dd2,
or possibly > dd2.
It is used in dd_is_shorter
If + in dd1, dd1 p> dd2
else if 0 in dd1, if - in dd2, dd1 p> dd2
else if dd2 == +, dd1 < dd2
else (0 or 0+) dd1 <= dd2
else (dd1 == -) if - in dd2, dd1 p> dd2
else dd1 < dd2
*/
typedef enum { pg = 0, le, lt } ddComparison;
/* compare[dd1][dd2] */
ddComparison ddCompare[8][8] =
{
/* DD2 + 0 0+ - +- 0- * */
/* DD1 */
/* */ { pg, pg, pg, pg, pg, pg, pg, pg },
/* + */ { pg, pg, pg, pg, pg, pg, pg, pg },
/* 0 */ { pg, lt, le, le, pg, pg, pg, pg },
/* 0+ */ { pg, pg, pg, pg, pg, pg, pg, pg },
/* - */ { pg, lt, lt, lt, pg, pg, pg, pg },
/* +- */ { pg, pg, pg, pg, pg, pg, pg, pg },
/* 0- */ { pg, lt, le, le, pg, pg, pg, pg },
/* * */ { pg, pg, pg, pg, pg, pg, pg, pg }
};
/* if possibly_shorter is strictly shorter than possibly_longer, return true
if possibly_shorter might be scum than possibly_longer, return false
if possibly_shorter is shorter or of equal length, return what_if_equal
possibly_shorter is assumed to be a covering dependence to the
same destination as possibly_longer, and thus possibly_longer
may be "partially refined".
*/
static int
dd_is_shorter(dd_current possibly_shorter,
dir_and_dist_info *possibly_longer,
int what_if_equal)
{
ddComparison c;
int j;
int minLength = MIN(possibly_longer->nest, dd_current_nest(possibly_shorter));
for (j = 1; j <= minLength; j++)
{
if (dd_current_dist_known(possibly_shorter, j) &&
possibly_longer->distanceKnown[j])
{
c = dd_current_dist(possibly_shorter)[j] < possibly_longer->distance[j] ? lt :
(dd_current_dist(possibly_shorter)[j] == possibly_longer->distance[j] ? le : pg);
}
else {
c = ddCompare[ddextract1(dd_current_dir(possibly_shorter), j)]
[ddextract1(possibly_longer->direction, j)];
}
switch (c) {
case lt:
return 1;
case pg:
return 0;
break;
case le:
if (!dddirtest(dd_current_dir(possibly_shorter), ddlt, j)) {
if (dddirtest(possibly_longer->direction, ddlt, j)) {
if (!(possibly_longer->direction & ddrefined))
{
clone_dd_graph_node_for_refinement(possibly_longer->dd_graph_node_to_be_cloned);
possibly_longer->direction |= ddrefined;
}
dddirreset(possibly_longer->direction, ddlt, j);
d_info_do_eq(possibly_longer, j);
};
if (!dddirtest(dd_current_dir(possibly_shorter), ddeq, j)
&& dddirtest(possibly_longer->direction, ddeq, j))
{
if (!(possibly_longer->direction & ddrefined))
{
clone_dd_graph_node_for_refinement(possibly_longer->dd_graph_node_to_be_cloned);
possibly_longer->direction |= ddrefined;
}
dddirreset(possibly_longer->direction, ddeq, j);
};
};
break;
}
}
/* le in all directions if we get here. */
return what_if_equal;
}
/*
Do quick but possibly indecisive kill tests to see
if dependence dd (from write_acc2 to read_acc) kills
the flow dependence dd1 (frow write_acc1 to read_acc).
If dd1 is obviously killed by dd2, this function will return
either ddiscovered or ddisterminated.
Otherwise, this function returns 0 (is which case dd2 may
or may not be killed - call accurate_test_for_kill to find out).
This function may update dd1 if dd1 is partly killed by dd2.
In this case, dd1's ddrefined bit will be set.
*/
dddirection
quick_test_for_kill(dir_and_dist_info *dd, char *dd_as_string,
a_access from_acc, a_access to_acc,
dd_current this_dep)
{
dd_in_iterator covers_dest; /* search for a dd that covers to_acc */
dd_out_iterator terms_src; /* search for a dd that terminates from_acc */
dddirection oldDirection = dd->direction;
assert(!ddisDead(dd->direction));
#ifndef SPEED
if (omegaPrintResult) {
fprintf(debug2, "starting quick kill check for:\n");
fprintf(debug2, "%s\n", dd_as_string);
}
#endif
covers_dest = dd_i_i_for_access(to_acc);
while (!dd_i_i_done(covers_dest))
{
a_access cur_src = dd_i_i_cur_src(covers_dest);
#if ! defined NOT_TINY
assert(covers_dest->ddsucc == to_acc);
#endif
if (!dd_i_i_cur_is(covers_dest, this_dep) &&
dd_i_i_cur_cover_p(covers_dest) &&
dd_is_shorter(dd_i_i_current(covers_dest), dd,
(accesss_shared_depth(from_acc, cur_src)
== dd->nest) &&
access_lexically_preceeds(from_acc, cur_src)))
{
if (omegaPrintResult) {
fprintf(debug2,
"Yes: there is a closer cover of the destination:\n");
fprintf(debug2, "%s\n",
dd_current_as_string(dd_i_i_current(covers_dest)));
}
return ddisCovered;
}
dd_i_i_next(covers_dest);
}
terms_src = dd_o_i_for_access(from_acc);
while (!dd_i_i_done(terms_src))
{
a_access cur_dest = dd_o_i_cur_dest(terms_src);
#if ! defined NOT_TINY
assert(terms_src->ddpred == from_acc);
#endif
if (!dd_o_i_cur_is(terms_src, this_dep) &&
dd_o_i_cur_terminate_p(terms_src) &&
dd_is_shorter(dd_o_i_current(terms_src), dd,
(accesss_shared_depth(to_acc, cur_dest)
== dd->nest) &&
access_lexically_preceeds(cur_dest, to_acc)))
{
if (omegaPrintResult) {
fprintf(debug2,
"Yes: there is a closer terminator of the source:\n");
fprintf(debug2, "%s\n",
dd_current_as_string(dd_i_i_current(terms_src)));
}
return ddisTerminated;
}
dd_o_i_next(terms_src);
}
if (omegaPrintResult) {
if (oldDirection != dd->direction)
fprintf(debug2, "direction vector refined but not killed\n");
else fprintf(debug2, "quick kill check indecisive\n");
}
return 0;
}
/* functions for manipulating "read problem descriptions" */
/* name information for buffers in getVarName fns */
#define MaxNameLen 254
#define MaxSuffixLen 1
#if !defined NDEBUG
static int var_id_is_step_expr(var_id n)
{
return n == 0;
}
void read_inv(read_prob_desc *rpd, Problem *p)
{
int v;
assert(p->getVarsN() < maxVars);
assert(p->getVarsN() >= read_Nvars(rpd));
assert(r_first(&rpd->nonloops) == 1);
assert(r_last(&rpd->nonloops) + 1 == r_first(&rpd->reads));
assert(r_last(&rpd->reads) + 1 == r_first(&rpd->rsteps));
assert(r_last(&rpd->rsteps) + 1 == r_first(&rpd->write1s));
assert(r_last(&rpd->write1s) + 1 == r_first(&rpd->w1steps));
assert(r_last(&rpd->w1steps) + 1 == r_first(&rpd->write2s));
assert(r_last(&rpd->write2s) + 1 == r_first(&rpd->w2steps));
for (v = 0; v < r_length(&rpd->nonloops); v++) {
assert(rpd->vars[v + r_first(&rpd->nonloops)] != NIL);
assert(var_id_const_p(rpd->vars[v + 1]));
assert(var_ids_tag(rpd->vars[v + 1]) == v + 1);
}
for (v = 0; v < r_length(&rpd->reads); v++) {
assert(rpd->vars[v + r_first(&rpd->reads)] != NIL);
assert(var_id_index_p(rpd->vars[v + r_first(&rpd->reads)]));
assert(var_ids_loop_no(rpd->vars[v + r_first(&rpd->reads)]) == v + 1);
}
for (v = 0; v < r_length(&rpd->rsteps); v++) {
assert(var_id_is_step_expr(rpd->vars[v + r_first(&rpd->rsteps)]));
}
for (v = 0; v < r_length(&rpd->write1s); v++) {
assert(rpd->vars[v + r_first(&rpd->write1s)] != NIL);
assert(var_id_index_p(rpd->vars[v + r_first(&rpd->write1s)]));
assert(var_ids_loop_no(rpd->vars[v + r_first(&rpd->write1s)]) == v + 1);
}
for (v = 0; v < r_length(&rpd->w1steps); v++) {
assert(var_id_is_step_expr(rpd->vars[v + r_first(&rpd->w1steps)]));
}
for (v = 0; v < r_length(&rpd->write2s); v++) {
assert(rpd->vars[v + r_first(&rpd->write2s)] != NIL);
assert(var_id_index_p(rpd->vars[v + r_first(&rpd->write2s)]));
assert(var_ids_loop_no(rpd->vars[v + r_first(&rpd->write2s)]) == v + 1);
}
for (v = 0; v < r_length(&rpd->w2steps); v++) {
assert(var_id_is_step_expr(rpd->vars[v + r_first(&rpd->w2steps)]));
}
for (v = 0; v < p->getNumGEqs(); v++) {
assert(p->_GEQs[v].touched);
}
}
#endif
static char *read_getVarName(uint v, void *args)
{
read_prob_desc *rpd = (read_prob_desc*)args;
static char name[MaxNameLen + MaxSuffixLen + 1];
assert(v <= read_Nvars(rpd));
if (rpd->vars[v] &&
(var_id_const_p(rpd->vars[v]) || var_id_index_p(rpd->vars[v]))) {
strncpy(name, var_ids_name(rpd->vars[v]), MaxNameLen);
name[MaxNameLen] = 0;
}
else {
assert(var_id_is_step_expr(rpd->vars[v]));
strcpy(name, "<trip>");
}
if (r_in(&rpd->reads, v) || r_in(&rpd->rsteps, v))
strcat(name, "0");
else if (r_in(&rpd->write1s, v) || r_in(&rpd->w1steps, v))
strcat(name, "1");
else if (r_in(&rpd->write2s, v) || r_in(&rpd->w2steps, v))
strcat(name, "2");
return name;
}
void read_init(read_prob_desc *rpd, Problem *p,
protect_in_read protect_which, uint Nsc, var_id sc_vars[],
uint Nr, var_id r_vars[], uint Nrs, var_id rs_vars[],
uint Nw1, var_id w1_vars[], uint Nw1s, var_id w1s_vars[],
uint Nw2, var_id w2_vars[], uint Nw2s, var_id w2s_vars[])
{
int v;
rpd->nonloops._first = 1;
rpd->nonloops._length = Nsc;
rpd->reads._first = 1 + Nsc;
rpd->reads._length = Nr;
rpd->rsteps._first = 1 + Nsc + Nr;
rpd->rsteps._length = Nrs;
rpd->write1s._first = 1 + Nsc + Nr + Nrs;
rpd->write1s._length = Nw1;
rpd->w1steps._first = 1 + Nsc + Nr + Nrs + Nw1;
rpd->w1steps._length = Nw1s;
rpd->write2s._first = 1 + Nsc + Nr + Nrs + Nw1 + Nw1s;
rpd->write2s._length = Nw2;
rpd->w2steps._first = 1 + Nsc + Nr + Nrs + Nw1 + Nw1s + Nw2;
rpd->w2steps._length = Nw2s;
if (read_Nvars(rpd) > maxVars) {
assert(0 && "Problem too big");
fprintf(stderr, "Too many variables for omega test\n");
Exit(2);
/* Could we handle this by not doing r/k/c? */
}
rpd->vars[0] = 0;
/* sc_vars[0..Nsc-1] are valid */
for (v = 0; v < Nsc; v++) {
assert(sc_vars[v] != NIL);
rpd->vars[v + r_first(&rpd->nonloops)] = sc_vars[v];
var_ids_tag(sc_vars[v]) = v + r_first(&rpd->nonloops);
}
/* r_vars[1..Nr] are valid */
for (v = 0; v < r_length(&rpd->reads); v++) {
assert(r_vars[v + 1] != NIL);
rpd->vars[v + r_first(&rpd->reads)] = r_vars[v + 1];
}
for (v = 0; v < r_length(&rpd->write1s); v++) {
assert(w1_vars[v + 1] != NIL);
rpd->vars[v + r_first(&rpd->write1s)] = w1_vars[v + 1];
}
for (v = 0; v < r_length(&rpd->write2s); v++) {
assert(w2_vars[v + 1] != NIL);
rpd->vars[v + r_first(&rpd->write2s)] = w2_vars[v + 1];
}
/* rs_vars[0..Nrs] hold steps FROM INNERMOST TO OUTERMOST LOOPS */
for (v = 0; v < Nrs; v++) {
assert(rs_vars[Nrs - 1 - v] == NIL);
rpd->vars[v + r_first(&rpd->rsteps)] = rs_vars[Nrs - 1 - v];
}
for (v = 0; v < Nw1s; v++) {
assert(w1s_vars[Nw1s - 1 - v] == NIL);
rpd->vars[v + r_first(&rpd->w1steps)] = w1s_vars[Nw1s - 1 - v];
}
for (v = 0; v < Nw2s; v++) {
assert(w2s_vars[Nw2s - 1 - v] == NIL);
rpd->vars[v + r_first(&rpd->w2steps)] = w2s_vars[Nw2s - 1 - v];
}
init_prob(p, read_Nvars(rpd),
protect_which == sc_and_r ? Nsc + Nr + Nrs : Nsc + Nr + Nrs + Nw1 + Nw1s,
read_getVarName, rpd);
}
/* clear the tags for symbolic constants */
void read_cleanup(read_prob_desc *rpd)
{
int v;
for (v = 0; v < r_length(&rpd->nonloops); v++) {
var_ids_tag(rpd->vars[v + r_first(&rpd->nonloops)]) = UNTAGGED;
}
}

View File

@@ -0,0 +1,604 @@
/* refine.c,v 1.1 1993/09/17 22:14:00 fbodin Exp */
/*
Refinement tests
Naming convention: Many of these functions and structures
refer to "read iteration" or "write iteration" as if a
test were being performed on flow dependence(s), even when
the test works for other forms of dependence.
*/
#include <assert.h>
#include <string.h>
#include "include/portable.h"
#include <stdio.h>
#include <stdlib.h>
#include "include/debug.h"
#include "include/ip.h"
#include "include/lang-interf.h"
#include "include/ddomega-build.h"
#include "include/ddomega-use.h"
#include "include/ddomega.h"
#include "include/omega2flags.h"
#include "include/kill.h"
#include "include/cover.h"
#include "include/refine.h"
#include "include/missing.h"
#include "include/timeTrials.h"
/*
check to see if a data dependence can be refined at the source,
and change d_info if so
*/
typedef enum { source, dest } which_end;
static void refine_end(a_access access_A, a_access access_B, which_end which,
dir_and_dist_info *d_info)
{
uint access_B_nest = accesss_depth(access_B),
access_A_nest = accesss_depth(access_A);
read_prob_desc rpd; /* write1s = A[i]
write2s = A[j] (or B[j] if which == dest)
reads = B[k] */
delta_prob_desc dpd; /* original dependence: A[i] --> B[k] */
Problem reads, new_deltas;
bool red_complete;
var_id sc_vars[maxVars], B_indices[maxVars], B_steps[maxVars];
var_id A_indices[maxVars], A_steps[maxVars];
int NBsteps, NAsteps, Nsc;
int l, u, j;
dd_in_iterator o;
int anyRefinementPossible = 0;
int refinementPossible[maxCommonNest];
#if ! defined NDEBUG
bool possible_dependence, simplified;
#endif
#if defined newTimeTrials
if (storeResult) refineTests++;
#endif
assert(!(which == source) || !access_fetch_p(access_A));
assert(!(which == dest) || !access_fetch_p(access_B));
if (omegaPrintResult) {
fprintf(debug2, "attempting refinement of %s of dependence\n",
which == source ? "source" : "destination");
fprintf(debug2, "\tfrom a store of %s at statement %d\n",
access_as_string(access_A), accesss_lineno(access_A));
fprintf(debug2, "\tto a read of %s at statement %d\n",
access_as_string(access_B), accesss_lineno(access_B));
fprintf(debug2, "\tdddir = %x, ", d_info->direction);
fprintf(debug2, "\trestraint = %x\n", d_info->restraint);
}
/* First, verify that the dependence isn't constant */
for (j = 1; j <= d_info->nest; j++)
if (!d_info->distanceKnown[j]) break;
/* if all constant or d_info->nest == 0, no need to refine */
if (j > d_info->nest) {
if (omegaPrintResult) {
fprintf(debug2, "no non-constant distances to refine\n");
}
return;
}
/* Check which dimensions refinement is feasible in */
for (j = 1; j <= d_info->nest; j++)
refinementPossible[j] = 0;
o = dd_i_i_for_access((which == source) ? access_A : access_B);
while (!dd_i_i_done(o))
{
if (dd_i_i_cur_src(o) == ((which == source) ? access_A : access_B))
{
/* self output/reduction dependence to end we're refining */
assert(dd_i_i_cur_dest(o) == dd_i_i_cur_src(o));
for (j = 1; j <= d_info->nest; j++) {
if (!d_info->distanceKnown[j] &&
dddirtest(dd_current_dir(dd_i_i_current(o)),
ddlt | ddgt, j))
{
refinementPossible[j] = 1;
anyRefinementPossible = 1;
}
}
}
dd_i_i_next(o);
}
if (!anyRefinementPossible) {
if (omegaPrintResult)
fprintf(debug2, "Fast break out of refinement\n");
return;
}
/* BUILD BLACK PROBLEM IN "new_deltas" :
i in [A] ^ k in [B] ^ A(i) << B(k) ^ A(i) sub= B(k) */
#if ! defined NDEBUG
possible_dependence =
#endif
build_delta_prob_desc(&dpd, &new_deltas, access_A, access_B,
access_A_nest, access_B_nest, d_info->nest);
assert(possible_dependence);
/* The A(i) << B(k) part */
constrain_with_dd(&new_deltas, &dpd.access2s, &dpd.access1s, d_info, black);
/* PART 1: find sets of variables to be used in problem */
NBsteps = NAsteps = Nsc = 0;
load_bounds_and_count_steps(access_B, B_indices, B_steps, &NBsteps);
load_bounds_and_count_steps(access_A, A_indices, A_steps, &NAsteps);
load_constants_for_bounds(access_B, sc_vars, &Nsc);
load_constants_for_bounds(access_A, sc_vars, &Nsc);
load_constants_for_subscripts(access_B, sc_vars, &Nsc);
load_constants_for_subscripts(access_A, sc_vars, &Nsc);
if (which == source)
{
/* PART 2: assign columns to variables */
read_init(&rpd, &reads, sc_and_r, Nsc, sc_vars,
access_B_nest, B_indices, NBsteps, B_steps,
access_A_nest, A_indices, NAsteps, A_steps,
access_A_nest, A_indices, NAsteps, A_steps);
#if ! defined NDEBUG
read_inv(&rpd, &reads);
#endif
/* PART 3: set up equations in "reads" */
/* SET UP BLACK PROBLEM IN "reads", IDENTICAL TO THAT IN "new_deltas":
i in [A] ^ k in [B] ^ A(i) << B(k) ^ A(i) sub= B(k) */
/* SET UP i in [A] */
bound_indices_and_conditionals(&reads, &rpd.write1s, &rpd.w1steps,
&rpd.nonloops, black, access_A);
/* SET UP k in [B] */
bound_indices_and_conditionals(&reads, &rpd.reads, &rpd.rsteps,
&rpd.nonloops, black, access_B);
/* SET UP A(i) sub= B(k) (this can not return 0) */
#if ! defined NDEBUG
possible_dependence =
#endif
equate_subscripts(&reads, &rpd.write1s, &rpd.reads, &rpd.nonloops,
black, access_A, access_B);
assert(possible_dependence);
constrain_with_dd(&reads, &rpd.reads, &rpd.write1s, d_info, black);
/* TRY TO SET UP RED PROBLEM IN "reads", EXCEPT REFINEMENT VECTOR PART.
IF WE CAN'T ESTABLISH COMPLETE RED BOUNDS, DON'T REFINE
IF which == source, RED PROBLEM = j in [A] ^ A(j) sub= B(k)
*/
red_complete = /* j in [A] ^ A(j) sub= B(k) */
((equate_subscripts(&reads, &rpd.reads, &rpd.write2s, &rpd.nonloops,
red, access_B, access_A) == complete) &&
(bound_inner_indices_and_conditionals(&reads, &rpd.write2s,
&rpd.w2steps, &rpd.nonloops,
leading_zeros(d_info->direction,
d_info->nest),
access_B,
red, access_A)));
}
else {
/* PART 2: assign columns to variables */
read_init(&rpd, &reads, sc_and_r, Nsc, sc_vars,
access_A_nest, A_indices, NBsteps, A_steps,
access_B_nest, B_indices, NBsteps, B_steps,
access_B_nest, B_indices, NBsteps, B_steps);
#if ! defined NDEBUG
read_inv(&rpd, &reads);
#endif
/* PART 3: set up equations in "reads" */
/* SET UP BLACK PROBLEM IN "reads", IDENTICAL TO THAT IN "new_deltas":
i in [A] ^ k in [B] ^ A(i) << B(k) ^ A(i) sub= B(k) */
/* SET UP i in [A] */
bound_indices_and_conditionals(&reads, &rpd.reads, &rpd.rsteps,
&rpd.nonloops, black, access_A);
/* SET UP k in [B] */
bound_indices_and_conditionals(&reads, &rpd.write2s, &rpd.w2steps,
&rpd.nonloops, black, access_B);
/* SET UP A(i) sub= B(k) (this can not return 0) */
#if ! defined NDEBUG
possible_dependence =
#endif
equate_subscripts(&reads, &rpd.reads, &rpd.write2s, &rpd.nonloops,
black, access_A, access_B);
assert(possible_dependence);
constrain_with_dd(&reads, &rpd.write2s, &rpd.reads, d_info, black);
/* TRY TO SET UP RED PROBLEM IN "reads", EXCEPT REFINEMENT VECTOR PART.
IF WE CAN'T ESTABLISH COMPLETE RED BOUNDS, DON'T REFINE
IF which == dest, RED PROBLEM = j in [B] ^ A(i) sub= B(j)
*/
red_complete = /* j in [B] ^ A(i) sub= B(j) */
((equate_subscripts(&reads, &rpd.write1s, &rpd.write2s, &rpd.nonloops,
red, access_B, access_A) == complete) &&
(bound_inner_indices_and_conditionals(&reads, &rpd.write2s,
&rpd.w2steps, &rpd.nonloops,
leading_zeros(d_info->direction,
d_info->nest),
access_A,
red, access_B)));
}
if (!red_complete)
{
if (omegaPrintResult) {
fprintf(debug2,
"not checking for refinement - incomplete red bounds\n");
}
read_cleanup(&rpd);
return;
}
/* START WITH REFINEMENT VECTOR = DEPENDENCE VECTOR,
THEN IN REFINEMENT, WE'LL SHORTEN IT */
if (which == source) {
/* SET UP A(j) << B(k) */
constrain_with_dd(&reads, &rpd.reads, &rpd.write2s, d_info, red);
}
else {
/* SET UP A(i) << B(j) */
constrain_with_dd(&reads, &rpd.write1s, &rpd.reads, d_info, red);
}
/* PART 4: clean up */
#if ! defined NDEBUG
read_inv(&rpd, &reads);
#endif
read_cleanup(&rpd);
/* PART 5: TRY TO REFINE DEPENDENCE */
#if ! defined NDEBUG
simplified =
#endif
simplifyProblem(&new_deltas);
assert(simplified && "new_deltas can be simplified"); /* ferd */
#if defined newTimeTrials
if (storeResult) semiRealRefineTests++;
#endif
/* go from outer to inner loops, trying to change + to its minimum */
for (j = 1; j <= d_info->nest; j++) {
uint e;
/* if dddist is unknown, try to refine:
see if min distance will cancel out all others */
if (!d_info->distanceKnown[j]) {
int fiendish;
if (!refinementPossible[j]) break;
fiendish = queryVariableBounds(&new_deltas,
r_first(&dpd.deltas) - 1 + j,
&l, &u);
if (fiendish)
if (ddextract1(d_info->direction, j) == (ddeq | ddlt)) {
l = 0;
u = posInfinity;
}
else
{
int k;
Problem new_new_deltas;
problemcpy(&new_new_deltas, &new_deltas);
for (k = 1; k <= d_info->nest; k++) {
if (k != j) {
unprotectVariable(&new_new_deltas,
r_first(&dpd.deltas) - 1 + k);
}
}
#if ! defined NDEBUG
simplified =
#endif
simplifyProblem(&new_new_deltas);
assert(simplified && "new_new_deltas can be simplified"); /*ferd*/
fiendish = queryVariableBounds(&new_new_deltas,
r_first(&dpd.deltas) - 1 + j,
&l, &u);
if (fiendish) {
eliminateRedundant(&new_new_deltas, 0);
simplifyProblem(&new_new_deltas);
fiendish = queryVariableBounds(&new_new_deltas,
r_first(&dpd.deltas) - 1 + j,
&l, &u);
};
if (fiendish) {
eliminateRedundant(&new_new_deltas, 1);
simplifyProblem(&new_new_deltas);
fiendish = queryVariableBounds(&new_new_deltas,
r_first(&dpd.deltas) - 1 + j,
&l, &u);
};
if (fiendish) {
#if defined newTimeTrials
if (storeResult) {
#endif
strange_occurance("Problem still fiendish in refine:\n");
/* debug2 and outputFile should always be the same */
printProblem(&new_new_deltas);
#if defined newTimeTrials
}
#endif
break; /* just stop refining */
}
}
if (l == u) { /* no need to refine, distance is known */
if (l == 0) {
dddironly(d_info->direction, ddeq, j);
d_info_do_eq(d_info, j)
}
else if (l > 0) {
dddironly(d_info->direction, ddlt, j);
}
else {
dddironly(d_info->direction, ddgt, j);
}
d_info->distanceKnown[j] = 1;
d_info->distance[j] = l;
}
else if (l != negInfinity && !(skipping_plus_refinement && l > 0))
{
int result;
Problem tmpProb;
problemcpy(&tmpProb, &reads);
/* Try to constrain delta index variable #j to exactly l
in red equations
That is, try to strengthen D in "A(j) <<D B(k)"
(or, if refining dest, in "A(i) <<D B(j)") */
if (which == source) {
int varj, vark; /* variable[k] - variable[j] = l */
vark = r_first(&rpd.reads) - 1 + j;
varj = r_first(&rpd.write2s) - 1 + j;
e = prob_add_zero_EQ(&tmpProb, red);
tmpProb._EQs[e].coef[varj] = -1;
tmpProb._EQs[e].coef[vark] = 1;
tmpProb._EQs[e].coef[0] = -l;
}
else {
int vari, varj; /* variable[j] - variable[i] = l */
vari = r_first(&rpd.reads) - 1 + j;
varj = r_first(&rpd.write1s) - 1 + j;
e = prob_add_zero_EQ(&tmpProb, red);
tmpProb._EQs[e].coef[vari] = -1;
tmpProb._EQs[e].coef[varj] = 1;
tmpProb._EQs[e].coef[0] = -l;
}
/* if there are remaining red equations,
then ! (black problem in red problem), and
we can't refine delta j to u, so stop refining */
/* the black equations represent the write1 - read
flow dependence, so they must have a solution,
(if the dep. has not been refined, we wouldn't
be here unless there were a dependence. And
refinement can't eliminate all the solutions,
since we only restrict the black equations to
values that don't constrain the solutions.)
Thus, it is ok to call hasRedEquations here. */
result = hasRedEquations(&tmpProb, 0);
#if defined newTimeTrials
if (storeResult) realRefineTests++;
#endif
if (omegaPrintResult) {
if (result && !refinementPossible[j])
fprintf(debug2, "fast test could have saved refinement check\n");
if (!result && !refinementPossible[j])
fprintf(debug2, "fast test didn't think refinement was possible\n");
}
if (result) break;
#if defined newTimeTrials
if (storeResult) realRefines++;
#endif
/* else, refine delta j to u in delta and read */
/* deltas must be constrained in terms of deltas:
read - write = l --> delta = -l --> delta + l = 0 */
constrainVariableValue(&new_deltas, black,
r_first(&dpd.deltas) - 1 + j,
l);
if (which == source)
{
/* reads must be constrained in terms of read & write */
e = prob_add_zero_EQ(&reads, black);
reads._EQs[e].coef[r_first(&rpd.reads) - 1 + j] = 1;
reads._EQs[e].coef[r_first(&rpd.write1s) - 1 + j] = -1;
reads._EQs[e].coef[0] = -l;
e = prob_add_zero_EQ(&reads, red);
reads._EQs[e].coef[r_first(&rpd.reads) - 1 + j] = 1;
reads._EQs[e].coef[r_first(&rpd.write2s) - 1 + j] = -1;
reads._EQs[e].coef[0] = -l;
}
else {
/* reads must be constrained in terms of read & write */
e = prob_add_zero_EQ(&reads, black);
reads._EQs[e].coef[r_first(&rpd.write2s) - 1 + j] = 1;
reads._EQs[e].coef[r_first(&rpd.reads) - 1 + j] = -1;
reads._EQs[e].coef[0] = -l;
e = prob_add_zero_EQ(&reads, red);
reads._EQs[e].coef[r_first(&rpd.write1s) - 1 + j] = 1;
reads._EQs[e].coef[r_first(&rpd.reads) - 1 + j] = -1;
reads._EQs[e].coef[0] = -l;
}
if (!(d_info->direction & ddrefined))
{
clone_dd_graph_node_for_refinement(d_info->dd_graph_node_to_be_cloned);
d_info->direction |= ddrefined;
}
if (l == 0) {
dddironly(d_info->direction, ddeq, j);
d_info_do_eq(d_info, j);
}
else if (l > 0) {
dddironly(d_info->direction, ddlt, j);
}
else {
dddironly(d_info->direction, ddgt, j);
}
d_info->distanceKnown[j] = 1;
d_info->distance[j] = l;
}
else break; /* minimum distance in loop is neg Infinity */
}
}
}
/*
if from_acc is a write, call refine_source
if to_acc is a write, call refine_dest
(If both are writes, I think we could get a bit more refinement
by having a refine_both, which tries to refine either the source
or the destination at each loop nest. I also think this would be
so rare that its not worth writing the code.)
*d_info will be updated if refinement is successful
*/
void refine_dependence(a_access from, a_access to,
dir_and_dist_info *d_info)
{
/* Read accesses, update operations of the same type as
one end of the dependence, and the Entry & Exit nodes
can not kill dependences. Thus, avoid refining with them. */
if (!access_fetch_p(from) && !access_update_p(from) && from != Entry)
{
assert(access_store_p(from));
refine_end(from, to, source, d_info);
}
if (!access_fetch_p(to) && !access_update_p(to) && to != ExitNode)
{
assert(access_store_p(to));
refine_end(from, to, dest, d_info);
}
}
/*
try to refine a cover or terminator's leading 0+'s into 0's.
*/
typedef int(*test_for_one)(a_access, a_access,
uint, uint, uint, dir_and_dist_info *,
char *);
static void tighten_cover_or_terminator(a_access from_acc, a_access to_acc,
dir_and_dist_info *d_info,
char *dd_as_string,
test_for_one which_test)
{
int i;
#if ! defined SPEED
char str[TINYBUFSIZ + sizeof("tightening of ")];
strcpy(str, "tightening of ");
strcat(str, dd_as_string);
#else
char *str = "Tiny must be compiled without -DSPEED for debugging info";
#endif
assert((*which_test)(from_acc, to_acc,
accesss_depth(from_acc),
accesss_depth(to_acc),
accesss_shared_depth(from_acc, to_acc),
d_info, dd_as_string));
#if defined newTimeTrials
if (storeResult) tightenTests++;
#endif
/* prototype version - build & solve problem again and again
profiling suggests that we don't waste significant time here. */
/* go from outer loops to inner, changing 0+ to 0 */
for (i = 1; i <= d_info->nest; i++)
{
if (ddextract1(d_info->direction, i) == (ddeq | ddlt))
{
/* we have a 0+ */
dir_and_dist_info new_info = *d_info;
dddirreset(new_info.direction, ddlt, i);
dddirreset(new_info.restraint, ddlt, i);
#if defined newTimeTrials
if (storeResult) realTightenTests++;
#endif
if ((*which_test)(from_acc, to_acc,
accesss_depth(from_acc),
accesss_depth(to_acc),
accesss_shared_depth(from_acc, to_acc),
&new_info, str))
{
if (!(d_info->direction & ddrefined)) {
clone_dd_graph_node_for_refinement(d_info->dd_graph_node_to_be_cloned);
}
d_info->direction = new_info.direction | ddrefined;
d_info->restraint = new_info.restraint;
d_info->distanceKnown[i] = 1;
d_info->distance[i] = 0;
}
}
if (ddextract1(d_info->direction, i) != ddeq)
break;
}
}
void tighten_cover(a_access from_acc, a_access to_acc,
dir_and_dist_info *d_info,
char *dd_as_string)
{
assert(d_info->direction & ddcovers);
tighten_cover_or_terminator(from_acc, to_acc, d_info, dd_as_string,
test_for_coverage);
}
void tighten_terminator(a_access from_acc, a_access to_acc,
dir_and_dist_info *d_info,
char *dd_as_string)
{
assert(d_info->direction & ddterminates);
tighten_cover_or_terminator(from_acc, to_acc, d_info, dd_as_string,
test_for_termination);
}

View File

@@ -0,0 +1,285 @@
/* sagedriver.c,v 1.2 1994/07/05 15:34:07 fbodin Exp */
/*
Driver routine for dependence testing with the omega test.
A different driver is used for several reasons:
- we use coverage information to decide whether or not to check for
a flow dependence
- we don't want the funky values for the loop nesting
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#define DEBUG 0
#include "include/portable.h"
#include "include/ip.h"
#include "include/affine.h" /* for an assertion about node_is_affine */
#include "include/lang-interf.h"
#define GLOB
#include "include/flags.h"
/* to be define later */
affine_expr not_affine = { -1, { 0 }, 0 };
extern int toBeCalledByOmegaTest(int tdep, int kdep, int *dist, int *kdist, int le, int from, int to);
/*
* Do closing procedures
*/
extern void ExitFromOmegaTest(const int c);
void Exit(int c)
{
switch (c) {
case 0:
break;
case 1:
fprintf(stderr, "Exit apparently due to user error (exit code 1)\n");
break;
case 2:
case -2:
fprintf(stderr, "Exit apparently due to system limitation or error (exit code %d)\n", c);
break;
default:
fprintf(stderr, "Something really bad happened (exit code %d)\n", c);
break;
}
ExitFromOmegaTest(c);
}
/*
* Assertion failed
*/
void ErrAssert(char *t) {
if (Argv)
fprintf(stderr, "\n%s: %s\n", &Argv[0][0], t);
else
fprintf(stderr, " %s\n", t);
Exit(-2);
}
int dd_carried_by(dddirection dv, int length)
{
int depth;
for (depth = 1; (depth <= length && ddextract1(dv, depth) == ddeq); depth++)
;
/* dd dirs [1..depth-1] are 0 */
return depth;
}
int leading_zeros(dddirection dv, int length)
{
int depth;
for (depth = 1; (depth <= length && ddextract1(dv, depth) == ddeq); depth++)
;
/* dd dirs [1..depth-1] are 0 */
return depth - 1;
}
void append_dd_flags(char *line, dddirection dv)
{
if (dv & ddkilled ||
dv & ddisCovered || dv & ddisTerminated || dv & ddisRefined ||
dv & ddrefined || dv & ddcovers || dv & ddterminates ||
dv & ddzappable || dv & ddzappableWC)
{
strcat(line, " [");
if (dv & ddcovers) strcat(line, "C");
if (dv & ddterminates) strcat(line, "T");
if (dv & ddrefined) strcat(line, "R");
if (!(dv & ddcovers) &&
!(dv & ddterminates) &&
!(dv & ddrefined)) strcat(line, " ");
if (dv & ddkilled) strcat(line, "k");
if (dv & ddisCovered) strcat(line, "c");
if (dv & ddisTerminated) strcat(line, "t");
if (dv & ddisRefined) strcat(line, "r");
if (dv & ddzappable) strcat(line, "Z");
if (dv & ddzappableWC) strcat(line, "?");
strcat(line, "]");
}
}
/* some temporary definition of functions, to be modified later */
void ddnode_to_dir_and_dist(dd_current a, dir_and_dist_info *b)
{
printf(" Calling ddnode_to_dir_and_dist\n");
}
/* coming from the sage part */
#define MAXNESTEDLOOP 100
#define DEPZERO 1
#define DEPGREATER 2
#define DEPLESS 4
#define WRONGDEP 0
#define ARRAYDEP 1
#define PRIVATEDEP 2
#define REDUCTIONDEP 3
#define SCALARDEP 4
void store_dependence(ddnature nature, a_access from_access, a_access to_access, dir_and_dist_info *d_info)
{
int i;
int tdep;
int kdep;
int dist[MAXNESTEDLOOP];
int kdist[MAXNESTEDLOOP];
tdep = ARRAYDEP;
if (d_info)
{
switch (nature)
{
case ddflow:
if (DEBUG)
printf("Omega test found a FLOW dependence: (");
kdep = ddflow;
break;
case ddanti:
if (DEBUG)
printf("Omega test found a ANTI dependence: (");
kdep = ddanti;
break;
case ddoutput:
if (DEBUG)
printf("Omega test found a OUTPUT dependence: (");
kdep = ddoutput;
break;
case ddreduce:
if (DEBUG)
printf("Omega test found a REDUCE dependence: (");
kdep = ddreduce;
break;
default:
printf("Omega test found an UNKNOWN dependence: (");
kdep = ddflow;
tdep = WRONGDEP;
break;
}
for (i = 1; i <= d_info->nest; i++)
{
if (d_info->distanceKnown[i])
{
if (DEBUG)
printf("%d", d_info->distance[i]);
kdist[i] = DEPZERO;
dist[i] = d_info->distance[i];
}
else
{
kdist[i] = 0;
dist[i] = 0;
if (dddirtest(d_info->direction, ddeq, i))
{
dist[i] = dist[i] + 1; /* temporary */
if (DEBUG)
printf("0");
}
if (dddirtest(d_info->direction, ddlt, i))
{
dist[i] = dist[i] + DEPGREATER; /* temporary */
if (DEBUG)
printf("+");
}
if (dddirtest(d_info->direction, ddgt, i))
{
dist[i] = dist[i] + DEPLESS; /* temporary */
if (DEBUG)
printf("-");
}
}
if (i < d_info->nest)
if (DEBUG)
printf(", ");
}
if (DEBUG)
printf(")\n"); /* if (from_access->lexord > to_access->lexord)*/
toBeCalledByOmegaTest(tdep, kdep, dist, kdist, d_info->nest, from_access->idforsage, to_access->idforsage);
/*else
toBeCalledByOmegaTest(tdep,kdep,dist,kdist,d_info->nest,-1);*/
}
else
{
if (DEBUG)
printf("Omega Test Found no Dependence\n");
}
}
void dir_and_dist_into_ddnode(const dir_and_dist_info *ddi, dd_current b)
{
/* printf(" Calling dir_and_dist_into_ddnode\n");*/
}
void Message_Add(char *str)
{
printf("Message_Add %s\n", str);
}
void clone_dd_graph_node_for_refinement(void *dd_graph_node_to_be_cloned)
{
/* printf(" Calling clone_dd_graph_node_for_refinement\n");*/
}
void SetOmegaDebug()
{
extern FILE *debug2;
debugLevel = 3;
setOutputFile(stdout);
omegaPrintResult = 1;
debug2 = stdout;
}
void SetSTuff()
{
extern FILE *debug2;
/* debugLevel = 3;
setOutputFile(stdout);
omegaPrintResult = 1;
debug2 = stdout; */
initializeOmega();
}
int access_is_in_then_or_else_of(a_access A, context_iterator C)
{
context_iterator it1, it2;
if (!C || !A)
return 0;
it1 = A->context;
it2 = C;
if (!cont_i_cur_loop_p(it2))
return 0;
while (!cont_i_done(it1))
{
if (!cont_i_cur_loop_p(it1))
{
if (cont_i_cur_if(it1)->ident == cont_i_cur_if(it2)->ident)
return 1;
}
cont_i_next(it1);
}
return 0;
}