moved
This commit is contained in:
62
Sapfor/_src/SageAnalysisTool/OmegaForSage/Makefile
Normal file
62
Sapfor/_src/SageAnalysisTool/OmegaForSage/Makefile
Normal 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
|
||||
|
||||
|
||||
193
Sapfor/_src/SageAnalysisTool/OmegaForSage/README
Normal file
193
Sapfor/_src/SageAnalysisTool/OmegaForSage/README
Normal 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
|
||||
|
||||
|
||||
506
Sapfor/_src/SageAnalysisTool/OmegaForSage/add-assert.cpp
Normal file
506
Sapfor/_src/SageAnalysisTool/OmegaForSage/add-assert.cpp
Normal 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;
|
||||
}
|
||||
14
Sapfor/_src/SageAnalysisTool/OmegaForSage/affine.cpp
Normal file
14
Sapfor/_src/SageAnalysisTool/OmegaForSage/affine.cpp
Normal 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 */
|
||||
|
||||
|
||||
427
Sapfor/_src/SageAnalysisTool/OmegaForSage/cover.cpp
Normal file
427
Sapfor/_src/SageAnalysisTool/OmegaForSage/cover.cpp
Normal 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;
|
||||
}
|
||||
784
Sapfor/_src/SageAnalysisTool/OmegaForSage/ddomega-build.cpp
Normal file
784
Sapfor/_src/SageAnalysisTool/OmegaForSage/ddomega-build.cpp
Normal 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
|
||||
}
|
||||
865
Sapfor/_src/SageAnalysisTool/OmegaForSage/ddomega-use.cpp
Normal file
865
Sapfor/_src/SageAnalysisTool/OmegaForSage/ddomega-use.cpp
Normal 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);
|
||||
}
|
||||
371
Sapfor/_src/SageAnalysisTool/OmegaForSage/ddomega.cpp
Normal file
371
Sapfor/_src/SageAnalysisTool/OmegaForSage/ddomega.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
16
Sapfor/_src/SageAnalysisTool/OmegaForSage/debug.cpp
Normal file
16
Sapfor/_src/SageAnalysisTool/OmegaForSage/debug.cpp
Normal 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);
|
||||
}
|
||||
|
||||
14
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/Exit.h
Normal file
14
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/Exit.h
Normal 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)); }
|
||||
@@ -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
|
||||
52
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/affine.h
Normal file
52
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/affine.h
Normal 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) != ¬_affine )
|
||||
#define node_is_affine(NODE) ( (NODE)->nodeaffine != (void *)¬_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
|
||||
36
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/cover.h
Normal file
36
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/cover.h
Normal 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
|
||||
69
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/dddir.h
Normal file
69
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/dddir.h
Normal 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 */
|
||||
@@ -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
|
||||
@@ -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
|
||||
77
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/ddomega.h
Normal file
77
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/ddomega.h
Normal 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
|
||||
@@ -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);
|
||||
47
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/flags.h
Normal file
47
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/flags.h
Normal 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;
|
||||
273
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/ip.h
Normal file
273
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/ip.h
Normal 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
|
||||
|
||||
79
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/kill.h
Normal file
79
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/kill.h
Normal 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
|
||||
@@ -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) ;
|
||||
503
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/lang-interf.h
Normal file
503
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/lang-interf.h
Normal 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
|
||||
37
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/missing.h
Normal file
37
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/missing.h
Normal 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
|
||||
@@ -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
|
||||
57
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/portable.h
Normal file
57
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/portable.h
Normal 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
|
||||
@@ -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
|
||||
19
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/range.h
Normal file
19
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/range.h
Normal 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
|
||||
37
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/refine.h
Normal file
37
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/refine.h
Normal 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
|
||||
124
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/screen.h
Normal file
124
Sapfor/_src/SageAnalysisTool/OmegaForSage/include/screen.h
Normal 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
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
4112
Sapfor/_src/SageAnalysisTool/OmegaForSage/ip.cpp
Normal file
4112
Sapfor/_src/SageAnalysisTool/OmegaForSage/ip.cpp
Normal file
File diff suppressed because it is too large
Load Diff
730
Sapfor/_src/SageAnalysisTool/OmegaForSage/kill.cpp
Normal file
730
Sapfor/_src/SageAnalysisTool/OmegaForSage/kill.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
604
Sapfor/_src/SageAnalysisTool/OmegaForSage/refine.cpp
Normal file
604
Sapfor/_src/SageAnalysisTool/OmegaForSage/refine.cpp
Normal 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);
|
||||
}
|
||||
285
Sapfor/_src/SageAnalysisTool/OmegaForSage/sagedriver.cpp
Normal file
285
Sapfor/_src/SageAnalysisTool/OmegaForSage/sagedriver.cpp
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user