moved
This commit is contained in:
101
Sapfor/_src/SageAnalysisTool/Makefile
Normal file
101
Sapfor/_src/SageAnalysisTool/Makefile
Normal file
@@ -0,0 +1,101 @@
|
||||
#######################################################################
|
||||
## pC++/Sage++ Copyright (C) 1993 ##
|
||||
## Indiana University University of Oregon University of Rennes ##
|
||||
#######################################################################
|
||||
|
||||
SAGEROOT = ../../..
|
||||
CONFIG_ARCH=default
|
||||
|
||||
LIBDIR = $(SAGEROOT)/lib/$(CONFIG_ARCH)
|
||||
LIBINCLUDE = $(SAGEROOT)/lib/include
|
||||
HINCLUDE = $(SAGEROOT)/h
|
||||
INSTALLDEST = $(SAGEROOT)/bin/$(CONFIG_ARCH)
|
||||
INSTALL = /bin/cp
|
||||
|
||||
#HP-ALLOCA#LDLIBS = -lPW#ENDIF#
|
||||
#HP_CFLAGS#CEXTRA = -Aa#ENDIF#
|
||||
|
||||
CC = gcc
|
||||
#USE_CC#CC=cc#ENDIF#
|
||||
|
||||
CXX = g++
|
||||
#USE_CFRONT#CXX=CC#ENDIF#
|
||||
|
||||
LOADER = $(CXX)
|
||||
|
||||
INCLUDE = -I$(LIBINCLUDE) -I$(HINCLUDE) -I./OmegaForSage/include
|
||||
|
||||
CFLAGS = $(INCLUDE) -g # $(CEXTRA)
|
||||
LDFLAGS =
|
||||
|
||||
LIBS =
|
||||
#LIBS = $(LIBDIR)/libann.a $(LIBDIR)/libsage.a $(LIBDIR)/libdb.a $(LIBDIR)/libSage++.a
|
||||
|
||||
OMEGATEST_OBJ = OmegaForSage/add-assert.o OmegaForSage/cover.o OmegaForSage/ddomega-build.o OmegaForSage/ddomega.o OmegaForSage/kill.o OmegaForSage/affine.o OmegaForSage/sagedriver.o OmegaForSage/ddomega-use.o OmegaForSage/debug.o OmegaForSage/ip.o OmegaForSage/refine.o
|
||||
|
||||
HFILE = annotationDriver.h constanteSet.h depGraph.h inducVar.h set.h arrayRef.h definitionSet.h dependence.h intrinsic.h depInterface.h definesValues.h
|
||||
|
||||
|
||||
PROGRAM = libDep.a
|
||||
|
||||
OBJS = set.o controlFlow.o flowAnalysis.o defUse.o constanteProp.o computeInducVar.o arrayRef.o dependence.o invariant.o depGraph.o intrinsic.o loopTransform.o annotationDriver.o depInterface.o
|
||||
|
||||
SRCS = set.C controlFlow.C flowAnalysis.C defUse.C constanteProp.C computeInducVar.C arrayRef.C dependence.C invariant.C depGraph.C intrinsic.C loopTransform.C annotationDriver.C depInterface.C
|
||||
|
||||
|
||||
|
||||
|
||||
all: $(PROGRAM)
|
||||
|
||||
$(PROGRAM): $(OBJS)
|
||||
/bin/rm -f libDep.a
|
||||
ar qc $(PROGRAM) $(OBJS) $(LIBS) $(OMEGATEST_OBJ)
|
||||
ranlib libDep.a
|
||||
|
||||
set.o: set.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c set.C
|
||||
|
||||
controlFlow.o: controlFlow.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c controlFlow.C
|
||||
|
||||
flowAnalysis.o: flowAnalysis.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c flowAnalysis.C
|
||||
|
||||
defUse.o: defUse.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c defUse.C
|
||||
|
||||
constanteProp.o: constanteProp.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c constanteProp.C
|
||||
|
||||
computeInducVar.o: computeInducVar.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c computeInducVar.C
|
||||
|
||||
arrayRef.o: arrayRef.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c arrayRef.C
|
||||
|
||||
dependence.o: dependence.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c dependence.C
|
||||
|
||||
invariant.o: invariant.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c invariant.C
|
||||
|
||||
depGraph.o: depGraph.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c depGraph.C
|
||||
|
||||
intrinsic.o: intrinsic.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c intrinsic.C
|
||||
|
||||
|
||||
loopTransform.o: loopTransform.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c loopTransform.C
|
||||
|
||||
annotationDriver.o : annotationDriver.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c annotationDriver.C
|
||||
|
||||
depInterface.o : depInterface.C $(HFILE)
|
||||
$(CXX) $(CFLAGS) -c depInterface.C
|
||||
|
||||
clean:
|
||||
/bin/rm -f *.o *.dep a.out libDep.a
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
52
Sapfor/_src/SageAnalysisTool/README
Normal file
52
Sapfor/_src/SageAnalysisTool/README
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
***************************** PRELIMINARY ***************************
|
||||
|
||||
This file contains PRELIMINARY extensions to the basic sage system.
|
||||
It mainly consists in an interface with the Omega test.
|
||||
A demo program using the functionnalities of this library is given in
|
||||
DemoDataDep. Documentation for this library is not yet available.
|
||||
|
||||
|
||||
This directory contains the following files:
|
||||
|
||||
|
||||
Makefile : just do make: create the library libDep.a
|
||||
|
||||
OmegaForSage : directory containing the Omega test src code
|
||||
|
||||
annotationDriver.C/.h : Interface in sage with the annotation system
|
||||
|
||||
arrayRef.C/.h : routine to create sets of array references (no yet completed)
|
||||
give the index in affine form when possible
|
||||
|
||||
computeInducVar.C : Induction variable computation (no yet completed)
|
||||
inducVar.h : structure for Induction variables
|
||||
|
||||
constanteProp.C : constante propagation routine (no yet completed)
|
||||
constanteSet.h : constante data structure
|
||||
|
||||
controlFlow.C : routine to get the control flow in program (no yet completed)
|
||||
|
||||
defUse.C : compute for each statement the set of variables defined and used
|
||||
(no yet completed)
|
||||
definitionSet.h : for defUse.C
|
||||
|
||||
depGraph.C : data dependence graph (no yet completed)
|
||||
depGraph.h : class declaration of the data dep graph
|
||||
|
||||
dependence.C : Interface with the omega test (no yet completed).
|
||||
dependence.h :
|
||||
|
||||
flowAnalysis.C : support for data flow analysis (no yet completed)
|
||||
|
||||
intrinsic.C : list of intrinsic functions (no yet completed)
|
||||
intrinsic.h :
|
||||
|
||||
invariant.C : (no yet completed)
|
||||
|
||||
loopTransform.C : simple loop transformations for sage (no yet completed)
|
||||
|
||||
set.C : basic class for dealing with object sets.
|
||||
set.h :
|
||||
|
||||
|
||||
329
Sapfor/_src/SageAnalysisTool/annotationDriver.cpp
Normal file
329
Sapfor/_src/SageAnalysisTool/annotationDriver.cpp
Normal file
@@ -0,0 +1,329 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sage++user.h"
|
||||
#include "annotationDriver.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// set of functions in the library
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __SPF
|
||||
extern "C" void addToCollection(const int line, const char *file, void *pointer, int type);
|
||||
extern "C" void removeFromCollection(void *pointer);
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
int initAnnotation();
|
||||
PTR_LLND Get_Define_Field(...);
|
||||
char *Get_Define_Label_Field(...);
|
||||
char *Get_Label_Field(...);
|
||||
PTR_LLND Get_ApplyTo_Field(...);
|
||||
PTR_LLND Get_ApplyToIf_Field(...);
|
||||
PTR_LLND Get_LocalVar_Field(...);
|
||||
PTR_LLND Get_Annotation_Field(...);
|
||||
char *Get_Annotation_Field_Label(...);
|
||||
char *Unparse_Annotation(...);
|
||||
char *Does_Annotation_Defines(...);
|
||||
int Get_Annotation_With_Label(...);
|
||||
int Get_Scope_Of_Annotation(...);
|
||||
PTR_LLND Does_Annotation_Apply(...);
|
||||
PTR_LLND Get_Annotation_Field_List_For_Stmt(...);
|
||||
PTR_LLND Get_Annotation_List_For_Stmt(...);
|
||||
int Get_Number_of_Annotation();
|
||||
PTR_BFND Get_Annotation_Bif(...);
|
||||
PTR_LLND Get_Annotation_Expr(...);
|
||||
char *Get_String_of_Annotation(...);
|
||||
PTR_CMNT Get_Annotation_Comment(...);
|
||||
int Is_Annotation_Defined(...);
|
||||
char *Annotation_Defines_string(...);
|
||||
int Annotation_Defines_string_Value(...);
|
||||
int isItInSection(...);
|
||||
}
|
||||
extern "C" int TRACEANN;
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Link with the Sage: maps it in sage space.
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
extern SgExpression * LlndMapping(PTR_LLND pt);
|
||||
extern SgStatement *BfndMapping(PTR_BFND st);
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// The interface. method of class annotations
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SgAnnotation::SgAnnotation(int ident)
|
||||
{
|
||||
PTR_BFND first, last;
|
||||
SgFunctionCallExp *cal;
|
||||
|
||||
if ((ident < 0) || (ident >= Get_Number_of_Annotation()))
|
||||
{
|
||||
Message("Invalid annotation", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// the id of the annotation;
|
||||
id = ident;
|
||||
theannotation = LlndMapping(Get_Annotation_Expr(id));
|
||||
//the statement it is attached on;
|
||||
stmt = BfndMapping(Get_Annotation_Bif(id));
|
||||
Get_Scope_Of_Annotation(id, &first, &last);
|
||||
scopebegin = BfndMapping(first);
|
||||
scopeend = BfndMapping(last);
|
||||
defined = Is_Annotation_Defined(id);
|
||||
thedirective = LlndMapping(Get_Annotation_Field(Get_Annotation_Expr(id)));
|
||||
directiveName = Get_Annotation_Field_Label(Get_Annotation_Expr(id));
|
||||
directiveFields = NULL;
|
||||
nbDirectiveFields = 0;
|
||||
if (cal = isSgFunctionCallExp(thedirective))
|
||||
{
|
||||
int i;
|
||||
nbDirectiveFields = cal->numberOfArgs();
|
||||
if (nbDirectiveFields)
|
||||
{
|
||||
directiveFields = new SgExpression *[nbDirectiveFields];
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, directiveFields, 2);
|
||||
#endif
|
||||
for (i = 0; i < nbDirectiveFields; i++)
|
||||
{
|
||||
directiveFields[i] = cal->arg(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message("Fail to recognize annotation format", 0);
|
||||
}
|
||||
next = NULL;
|
||||
}
|
||||
|
||||
|
||||
SgAnnotation::~SgAnnotation()
|
||||
{
|
||||
if (directiveFields)
|
||||
{
|
||||
#ifdef __SPF
|
||||
removeFromCollection(directiveFields);
|
||||
#endif
|
||||
delete[] directiveFields;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char * SgAnnotation::unparse()
|
||||
{
|
||||
return Unparse_Annotation(Get_Annotation_Expr(id));
|
||||
}
|
||||
|
||||
|
||||
int SgAnnotation::applyToStatement(SgStatement *stat)
|
||||
{
|
||||
SgStatement *temp;
|
||||
|
||||
if (!stat)
|
||||
return 0;
|
||||
|
||||
for (temp = scopebegin; temp; temp = temp->lexNext())
|
||||
{
|
||||
if (temp == stat)
|
||||
return 1;
|
||||
|
||||
if (temp == scopeend)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// non method functions to get the annotation
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// create the list of annotations that applies to a statements
|
||||
// only the defined one
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SgAnnotation *
|
||||
getTheAnnotationThatApply(SgStatement *stmt, char *kind)
|
||||
{
|
||||
int i;
|
||||
PTR_BFND first, last;
|
||||
SgAnnotation *listann = NULL;
|
||||
SgAnnotation *lastann = NULL;
|
||||
PTR_BFND bif;
|
||||
|
||||
if (!stmt)
|
||||
return NULL;
|
||||
bif = stmt->thebif;
|
||||
|
||||
for (i = 0; i < Get_Number_of_Annotation(); i++)
|
||||
{
|
||||
if (Is_Annotation_Defined(i))
|
||||
{
|
||||
if (kind)
|
||||
{
|
||||
if (Get_Annotation_Field_Label(Get_Annotation_Expr(i)) &&
|
||||
(strcmp(Get_Annotation_Field_Label(Get_Annotation_Expr(i)), kind) == 0))
|
||||
{
|
||||
if (Get_Scope_Of_Annotation(i, &first, &last))
|
||||
{
|
||||
if (isItInSection(first, last, bif))
|
||||
{
|
||||
if (!listann)
|
||||
{
|
||||
listann = new SgAnnotation(i);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, listann, 1);
|
||||
#endif
|
||||
lastann = listann;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastann->next = new SgAnnotation(i);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, listann->next, 1);
|
||||
#endif
|
||||
lastann = lastann->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Get_Scope_Of_Annotation(i, &first, &last))
|
||||
{
|
||||
if (isItInSection(first, last, bif))
|
||||
{
|
||||
if (!listann)
|
||||
{
|
||||
listann = new SgAnnotation(i);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, listann, 1);
|
||||
#endif
|
||||
lastann = listann;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastann->next = new SgAnnotation(i);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, listann->next, 1);
|
||||
#endif
|
||||
lastann = lastann->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return listann;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SgAnnotation *
|
||||
getTheAnnotationWithString(char *kind)
|
||||
{
|
||||
int i;
|
||||
PTR_BFND first, last;
|
||||
SgAnnotation *listann = NULL;
|
||||
SgAnnotation *lastann = NULL;
|
||||
PTR_BFND bif;
|
||||
|
||||
|
||||
for (i = 0; i < Get_Number_of_Annotation(); i++)
|
||||
{
|
||||
if (Is_Annotation_Defined(i))
|
||||
{
|
||||
if (kind)
|
||||
{
|
||||
if (Get_Annotation_Field_Label(Get_Annotation_Expr(i)) &&
|
||||
(strncmp(Get_Annotation_Field_Label(Get_Annotation_Expr(i)),
|
||||
kind, strlen(kind)) == 0))
|
||||
if (!listann)
|
||||
{
|
||||
listann = new SgAnnotation(i);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, listann, 1);
|
||||
#endif
|
||||
lastann = listann;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastann->next = new SgAnnotation(i);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, listann->next, 1);
|
||||
#endif
|
||||
lastann = lastann->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return listann;
|
||||
}
|
||||
|
||||
int
|
||||
isAnnotationWithString(SgStatement *stmt, char *kind, int len)
|
||||
{
|
||||
int i;
|
||||
PTR_BFND first, last;
|
||||
SgAnnotation *listann = NULL;
|
||||
SgAnnotation *lastann = NULL;
|
||||
PTR_BFND bif;
|
||||
|
||||
if (!stmt)
|
||||
return 0;
|
||||
bif = stmt->thebif;
|
||||
|
||||
for (i = 0; i < Get_Number_of_Annotation(); i++)
|
||||
{
|
||||
if (Is_Annotation_Defined(i))
|
||||
{
|
||||
if (kind)
|
||||
{
|
||||
if (Get_Annotation_Field_Label(Get_Annotation_Expr(i)) &&
|
||||
(strncmp(Get_Annotation_Field_Label(Get_Annotation_Expr(i)),
|
||||
kind, len) == 0))
|
||||
{
|
||||
if (Get_Scope_Of_Annotation(i, &first, &last))
|
||||
{
|
||||
if (isItInSection(first, last, bif))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void initAnnotationSystem(int printann)
|
||||
{
|
||||
int i;
|
||||
SgExpression *exp;
|
||||
SgStatement *stmt;
|
||||
if (printann)
|
||||
{
|
||||
TRACEANN = 1;
|
||||
}
|
||||
initAnnotation();
|
||||
// add also the annotation expression for the garbage collection attributes;
|
||||
|
||||
for (i = 0; i < Get_Number_of_Annotation(); i++)
|
||||
{
|
||||
exp = LlndMapping(Get_Annotation_Expr(i));
|
||||
stmt = BfndMapping(Get_Annotation_Bif(i));
|
||||
if (stmt && exp)
|
||||
{
|
||||
stmt->addAttribute(ANNOTATION_EXPR_ATTRIBUTE, (void *)exp, 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
31
Sapfor/_src/SageAnalysisTool/annotationDriver.h
Normal file
31
Sapfor/_src/SageAnalysisTool/annotationDriver.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// interface to the annotations
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
class SgAnnotation
|
||||
{
|
||||
public:
|
||||
// the id of the annotation;
|
||||
int id;
|
||||
// the annotation itself;
|
||||
SgExpression *theannotation;
|
||||
//the statement it is attached on;
|
||||
SgStatement *stmt;
|
||||
SgStatement *scopebegin;
|
||||
SgStatement *scopeend;
|
||||
int defined;
|
||||
SgExpression *thedirective;
|
||||
char *directiveName;
|
||||
// pointer to the next annotation for a statement;
|
||||
SgAnnotation *next;
|
||||
SgAnnotation(int id);
|
||||
~SgAnnotation();
|
||||
char * unparse();
|
||||
int applyToStatement(SgStatement *stat);
|
||||
SgExpression **directiveFields;
|
||||
int nbDirectiveFields;
|
||||
};
|
||||
|
||||
726
Sapfor/_src/SageAnalysisTool/arrayRef.cpp
Normal file
726
Sapfor/_src/SageAnalysisTool/arrayRef.cpp
Normal file
@@ -0,0 +1,726 @@
|
||||
#include <stdio.h>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "sage++user.h"
|
||||
#include "definesValues.h"
|
||||
#include "set.h"
|
||||
#include "definitionSet.h"
|
||||
#include "inducVar.h"
|
||||
|
||||
#include "arrayRef.h"
|
||||
|
||||
#ifdef __SPF
|
||||
extern "C" void addToCollection(const int line, const char *file, void *pointer, int type);
|
||||
extern "C" void removeFromCollection(void *pointer);
|
||||
#endif
|
||||
|
||||
int NbLinearRef = 0;
|
||||
int NbNonLinearRef = 0;
|
||||
|
||||
extern Set *genSet[MAXNODE];
|
||||
extern Set *killSet[MAXNODE];
|
||||
extern Set *inSet[MAXNODE];
|
||||
extern Set *outSet[MAXNODE];
|
||||
|
||||
|
||||
extern Set* getAllInductionVar(SgStatement *func, SgStatement *stmt, int level, int *num, int include);
|
||||
|
||||
using std::set;
|
||||
using std::string;
|
||||
//
|
||||
// for an array ref build the linear representation
|
||||
// return 0 if failed
|
||||
//
|
||||
|
||||
int linearRepArray(SgExpression *ex1, SgSymbol **symb, int size, int linear[MAXDIMARRAY][MAXNESTEDLOOP], int *cst, int isLinear[MAXDIMARRAY])
|
||||
{
|
||||
SgArrayRefExp *ar;
|
||||
SgExpression *lin;
|
||||
int i;
|
||||
int returnVal;
|
||||
|
||||
if (!ex1 || !symb || !cst)
|
||||
return 0;
|
||||
|
||||
if (!(ar = isSgArrayRefExp(ex1)))
|
||||
return 0;
|
||||
returnVal = 1;
|
||||
for (i = 0; i < ar->numberOfSubscripts(); i++)
|
||||
{
|
||||
lin = ar->subscript(i);
|
||||
isLinear[i] = 1;
|
||||
if (!lin)
|
||||
{
|
||||
returnVal = 0;
|
||||
isLinear[i] = 0;
|
||||
}
|
||||
else
|
||||
if (!lin->linearRepresentation(linear[i], symb, &cst[i], size))
|
||||
{
|
||||
returnVal = 0;
|
||||
isLinear[i] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Set Operations
|
||||
//
|
||||
int arrayEqual(void *e1, void *e2)
|
||||
{
|
||||
SgExpression *ex1, *ex2;
|
||||
SgSymbol *s1, *s2;
|
||||
PT_ACCESSARRAY el1, el2;
|
||||
int i;
|
||||
if (!e1 && !e2)
|
||||
return 1;
|
||||
if (!e1 || !e2)
|
||||
return 0;
|
||||
|
||||
el1 = (PT_ACCESSARRAY)e1;
|
||||
el2 = (PT_ACCESSARRAY)e2;
|
||||
|
||||
ex1 = el1->var;
|
||||
ex2 = el2->var;
|
||||
|
||||
if (el1->type != el2->type)
|
||||
return 0;
|
||||
|
||||
if (ex1 && ex2 && (s1 = ex1->symbol()) && (s2 = ex2->symbol()))
|
||||
{
|
||||
if (s1 != s2)
|
||||
return 0;
|
||||
// need to check more, at which condition, two sections are equal;
|
||||
// pattern matching should be ok;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void arrayPrint(void *e1)
|
||||
{
|
||||
SgExpression *ex1;
|
||||
PT_ACCESSARRAY el1;
|
||||
int i, j;
|
||||
if (!e1)
|
||||
return;
|
||||
el1 = (PT_ACCESSARRAY)e1;
|
||||
ex1 = el1->var;
|
||||
printf("%d :", el1->level);
|
||||
ex1->unparsestdout();
|
||||
printf("\n");
|
||||
if (el1->scalar)
|
||||
printf("scalar variable\n");
|
||||
if (el1->rw)
|
||||
printf("written\n");
|
||||
else
|
||||
printf("read\n");
|
||||
if (el1->type)
|
||||
printf("Linear\n");
|
||||
for (i = 0; i < MAXDIMARRAY; i++)
|
||||
{
|
||||
if (el1->isLinear[i])
|
||||
{
|
||||
printf("Linear (%d) :", i);
|
||||
for (j = 0; j < el1->size; j++)
|
||||
printf("%d ", el1->linear[i][j]);
|
||||
printf(" cst = %d", el1->cst[i]);
|
||||
printf("\n");
|
||||
}
|
||||
else
|
||||
printf("NonLinear (%d) \n", i);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
// this function should be extended to handle non loop statement...
|
||||
Set *loopArrayAccessAnalysis(SgStatement *func, SgStatement *stmt, SgSymbol **tsymb, Set **induc, const set<string> &privVars)
|
||||
{
|
||||
Set *inducvar, *cstset, *tpt, *arset;
|
||||
SgStatement *temp1, *temp2, *last;
|
||||
SgExpression *def1, *def2, *use1, *use2;
|
||||
SgExpression *ex1, *ex2, *r1, *r2;
|
||||
int linear1[MAXDIMARRAY][MAXNESTEDLOOP];
|
||||
int i, j, size, res1, res2, cst1[MAXDIMARRAY];
|
||||
int level, ptstack = 0, LevStack[MAXNESTEDLOOP], nbloop;
|
||||
PT_INDUCVAR ind;
|
||||
PT_ACCESSARRAY el;
|
||||
int numloop = 0;
|
||||
int isLinear[MAXDIMARRAY];
|
||||
|
||||
if (!isSgForStmt(stmt) || !func)
|
||||
return NULL;
|
||||
last = stmt->lastNodeOfStmt();
|
||||
// get induction variables;
|
||||
|
||||
inducvar = getAllInductionVar(func, stmt, 1, &numloop, -1);
|
||||
|
||||
// add the constante to the induction set variable;
|
||||
// cstset = computeConstanteInStmt(func,stmt);
|
||||
// if (cstset)
|
||||
// cstset->printSet();
|
||||
// inducvar->unionSet(cstset);
|
||||
// delete cstset;
|
||||
if (!inducvar)
|
||||
{
|
||||
Message("no induction variables", stmt->lineNumber());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// load the array of symbol with induction var;
|
||||
if (inducvar->size() >= MAXNESTEDLOOP)
|
||||
{
|
||||
Message("Too many induction variables\n", stmt->lineNumber());
|
||||
return NULL;
|
||||
}
|
||||
tpt = inducvar;
|
||||
inducvar = inducvar->compact();
|
||||
#ifdef __SPF
|
||||
removeFromCollection(tpt);
|
||||
#endif
|
||||
delete tpt;
|
||||
*induc = inducvar;
|
||||
arset = new Set(arrayEqual, NULL, arrayPrint);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, arset, 1);
|
||||
#endif
|
||||
size = inducvar->size();
|
||||
for (i = 0; i < inducvar->size(); i++)
|
||||
{
|
||||
ind = (PT_INDUCVAR)inducvar->getElement(i);
|
||||
if (ex2 = ind->var)
|
||||
{
|
||||
tsymb[i] = ex2->symbol();
|
||||
}
|
||||
}
|
||||
// get all array references, there are contained in the Defined Used set;
|
||||
level = 0;
|
||||
nbloop = 0;
|
||||
for (temp1 = stmt; temp1 && (temp1 != last); temp1 = temp1->lexNext())
|
||||
{
|
||||
if (isSgForStmt(temp1))
|
||||
{
|
||||
nbloop++;
|
||||
ptstack++;
|
||||
if (ptstack >= MAXNESTEDLOOP)
|
||||
Message("Stack out of bound in loopArrayAccessAnalysis", 0);
|
||||
LevStack[ptstack] = nbloop;
|
||||
level = nbloop;
|
||||
}
|
||||
|
||||
if (isSgControlEndStmt(temp1) || isSgContinueStmt(temp1))
|
||||
{
|
||||
if (temp1->controlParent() && (temp1->controlParent()->variant() == FOR_NODE) && (temp1->controlParent()->lastNodeOfStmt() == temp1))
|
||||
{
|
||||
ptstack--;
|
||||
if (ptstack <= 0)
|
||||
Message("Stack out of bound in loopArrayAccessAnalysis", 0);
|
||||
level = LevStack[ptstack];
|
||||
}
|
||||
}
|
||||
|
||||
for (def1 = (SgExpression *)temp1->attributeValue(0, DEFINEDLIST_ATTRIBUTE); def1; def1 = def1->rhs())
|
||||
//Defined[temp1->id()]; def1; def1 = def1->rhs())
|
||||
{
|
||||
for (i = 0; i < MAXDIMARRAY; i++)
|
||||
{
|
||||
cst1[i] = 0;
|
||||
isLinear[i] = 1;
|
||||
for (j = 0; j < MAXNESTEDLOOP; j++)
|
||||
linear1[i][j] = 0;
|
||||
}
|
||||
ex1 = def1->lhs();
|
||||
if (isSgArrayRefExp(ex1))
|
||||
{
|
||||
if (privVars.find(ex1->symbol()->identifier()) == privVars.end())
|
||||
{
|
||||
res1 = linearRepArray(ex1, tsymb, size, linear1, cst1, isLinear);
|
||||
el = new struct arrayAccess;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, el, 1);
|
||||
#endif
|
||||
for (i = 0; i < MAXDIMARRAY; i++)
|
||||
{
|
||||
el->isLinear[i] = isLinear[i];
|
||||
for (j = 0; j < MAXNESTEDLOOP; j++)
|
||||
el->linear[i][j] = linear1[i][j];
|
||||
el->cst[i] = cst1[i];
|
||||
}
|
||||
// add the ref;
|
||||
el->stmt = temp1;
|
||||
el->nbdim = MAXDIMARRAY;
|
||||
el->var = ex1;
|
||||
el->type = res1;
|
||||
if (res1)
|
||||
NbLinearRef++;
|
||||
else
|
||||
NbNonLinearRef++;
|
||||
el->size = size;
|
||||
el->rw = 1; // this is a write;
|
||||
el->scalar = 0; // not a scalar var;
|
||||
el->level = level;
|
||||
arset->addElement((void *)el);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SgSymbol *ssy;
|
||||
int l, trouve;
|
||||
// if non induction var ;
|
||||
if (!isSgTypeExp(ex1))
|
||||
{
|
||||
ssy = ex1->symbol();
|
||||
trouve = 0;
|
||||
for (l = 0; l < size; l++)
|
||||
{
|
||||
if (ssy == tsymb[l])
|
||||
{
|
||||
trouve = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
trouve = 1;
|
||||
if (!trouve)
|
||||
{
|
||||
el = new struct arrayAccess;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, el, 1);
|
||||
#endif
|
||||
// add the ref;
|
||||
el->stmt = temp1;
|
||||
el->var = ex1;
|
||||
el->nbdim = 0;
|
||||
el->type = 0;
|
||||
el->size = 0;
|
||||
el->rw = 1; // this is a write;
|
||||
el->level = level;
|
||||
el->scalar = 1; // not a scalar var;
|
||||
arset->addElement((void *)el);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (use1 = (SgExpression *)temp1->attributeValue(0, USEDLIST_ATTRIBUTE); use1; use1 = use1->rhs())
|
||||
// Used[temp1->id()]; use1; use1 = use1->rhs())
|
||||
{
|
||||
for (i = 0; i < MAXDIMARRAY; i++)
|
||||
{
|
||||
cst1[i] = 0;
|
||||
isLinear[i] = 1;
|
||||
for (j = 0; j < MAXNESTEDLOOP; j++)
|
||||
linear1[i][j] = 0;
|
||||
}
|
||||
|
||||
ex1 = use1->lhs();
|
||||
if (isSgArrayRefExp(ex1))
|
||||
{
|
||||
if (privVars.find(ex1->symbol()->identifier()) == privVars.end())
|
||||
{
|
||||
res1 = linearRepArray(ex1, tsymb, size, linear1, cst1, isLinear);
|
||||
|
||||
el = new struct arrayAccess;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, el, 1);
|
||||
#endif
|
||||
for (i = 0; i < MAXDIMARRAY; i++)
|
||||
{
|
||||
el->isLinear[i] = isLinear[i];
|
||||
for (j = 0; j < MAXNESTEDLOOP; j++)
|
||||
el->linear[i][j] = linear1[i][j];
|
||||
el->cst[i] = cst1[i];
|
||||
}
|
||||
// add the ref;
|
||||
el->stmt = temp1;
|
||||
el->var = ex1;
|
||||
el->nbdim = MAXDIMARRAY;
|
||||
el->type = res1;
|
||||
if (res1)
|
||||
NbLinearRef++;
|
||||
else
|
||||
NbNonLinearRef++;
|
||||
el->size = size;
|
||||
el->rw = 0; // this is a read;
|
||||
el->scalar = 0; // not a scalar var;
|
||||
el->level = level;
|
||||
arset->addElement((void *)el);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SgSymbol *ssy;
|
||||
int l, trouve;
|
||||
if (!isSgTypeExp(ex1))
|
||||
{
|
||||
// if non induction var ;
|
||||
ssy = ex1->symbol();
|
||||
trouve = 0;
|
||||
for (l = 0; l < size; l++)
|
||||
{
|
||||
if (ssy == tsymb[l])
|
||||
{
|
||||
trouve = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
trouve = 1;
|
||||
if (!trouve)
|
||||
{
|
||||
el = new struct arrayAccess;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, el, 1);
|
||||
#endif
|
||||
// add the ref;
|
||||
el->stmt = temp1;
|
||||
el->var = ex1;
|
||||
el->nbdim = 0;
|
||||
el->type = 0;
|
||||
el->size = 0;
|
||||
el->level = level;
|
||||
el->rw = 0; // this is a read;
|
||||
el->scalar = 1; // not a scalar var;
|
||||
arset->addElement((void *)el);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return arset;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
projectoPermut(PT_ACCESSARRAY el1)
|
||||
{
|
||||
SgSymbol *inducsy;
|
||||
int i, j, k;
|
||||
PT_INDUCVAR ind, cur;
|
||||
int temp;
|
||||
|
||||
if (!el1)
|
||||
return 0;
|
||||
if (!el1->type)
|
||||
return 0; // non linear;
|
||||
for (j = 0; j < el1->size; j++)
|
||||
{
|
||||
temp = 0;
|
||||
for (k = 0; k < MAXDIMARRAY; k++)
|
||||
{
|
||||
if (el1->linear[k][j] != 0)
|
||||
{
|
||||
if (temp)
|
||||
return 0;
|
||||
temp = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (k = 0; k < MAXDIMARRAY; k++)
|
||||
{
|
||||
temp = 0;
|
||||
for (j = 0; j < el1->size; j++)
|
||||
{
|
||||
if (el1->linear[k][j] != 0)
|
||||
{
|
||||
if (temp)
|
||||
return 0;
|
||||
temp = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Between two references is there temporal locality. Limited to permutation o projection
|
||||
//
|
||||
|
||||
int
|
||||
temporalLocality(PT_ACCESSARRAY el1, SgSymbol **tsymb, Set *induc)
|
||||
{
|
||||
SgSymbol *inducsy;
|
||||
int j, k;
|
||||
PT_INDUCVAR ind, cur;
|
||||
int loopnum;
|
||||
int temporal, temp;
|
||||
|
||||
if (!el1 || !induc || !tsymb)
|
||||
return 0;
|
||||
inducsy = NULL;
|
||||
loopnum = el1->level;
|
||||
for (j = 0; j < induc->size(); j++)
|
||||
{
|
||||
ind = (PT_INDUCVAR)induc->getElement(j);
|
||||
if (ind && (ind->loopnum == loopnum))
|
||||
{
|
||||
inducsy = ind->var->symbol();
|
||||
cur = ind;
|
||||
break;
|
||||
}
|
||||
}
|
||||
temporal = 0;
|
||||
// this is the induction var of the loop.
|
||||
if (inducsy)
|
||||
{
|
||||
while (cur)
|
||||
{
|
||||
for (j = 0; j < el1->size; j++)
|
||||
{
|
||||
if (tsymb[j] == inducsy)
|
||||
break;
|
||||
} // we have the symbol;
|
||||
if (j < el1->size)
|
||||
{
|
||||
temp = 1;
|
||||
for (k = 0; k < MAXDIMARRAY; k++)
|
||||
{
|
||||
if (el1->linear[k][j] != 0)
|
||||
{
|
||||
temp = 0;
|
||||
}
|
||||
}
|
||||
if (temp)
|
||||
temporal = 1;
|
||||
|
||||
}
|
||||
if (cur->include == -1)
|
||||
break;
|
||||
// compute the next one;
|
||||
for (j = 0; j < induc->size(); j++)
|
||||
{
|
||||
ind = (PT_INDUCVAR)induc->getElement(j);
|
||||
|
||||
if (ind && (ind->loopnum == cur->include))
|
||||
{
|
||||
inducsy = ind->var->symbol();
|
||||
cur = ind;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return temporal;
|
||||
}
|
||||
|
||||
int
|
||||
spatialLocality(PT_ACCESSARRAY el1, SgSymbol **tsymb, Set *induc, int CacheLIneSize)
|
||||
{
|
||||
SgSymbol *inducsy;
|
||||
int j, k;
|
||||
PT_INDUCVAR ind, cur;
|
||||
int loopnum;
|
||||
int spatial, temp;
|
||||
|
||||
if (!el1 || !induc || !tsymb)
|
||||
return 0;
|
||||
inducsy = NULL;
|
||||
loopnum = el1->level;
|
||||
for (j = 0; j < induc->size(); j++)
|
||||
{
|
||||
ind = (PT_INDUCVAR)induc->getElement(j);
|
||||
if (ind && (ind->loopnum == loopnum))
|
||||
{
|
||||
inducsy = ind->var->symbol();
|
||||
cur = ind;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spatial = 0;
|
||||
// this is the induction var of the loop.
|
||||
if (inducsy)
|
||||
{
|
||||
// look at in the dimension where the variable appear;
|
||||
spatial = 1;
|
||||
// the first dimension is fine where is the column of the symbole;
|
||||
for (j = 0; j < el1->size; j++)
|
||||
{
|
||||
if (tsymb[j] == inducsy)
|
||||
break;
|
||||
}
|
||||
if (j < el1->size)
|
||||
{
|
||||
for (k = 1; k < MAXDIMARRAY; k++)
|
||||
{
|
||||
if (el1->linear[k][j] != 0)
|
||||
{
|
||||
spatial = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (el1->linear[0][j] > CacheLIneSize)
|
||||
spatial = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
spatial = 0;
|
||||
}
|
||||
}
|
||||
return spatial;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
spatialNonSelfLocality(PT_ACCESSARRAY el1, PT_ACCESSARRAY el2, SgSymbol **tsymb, Set *induc, int CacheLIneSize)
|
||||
{
|
||||
SgSymbol *inducsy;
|
||||
int j, k;
|
||||
PT_INDUCVAR ind, cur;
|
||||
int loopnum;
|
||||
int spatial, temp;
|
||||
|
||||
if (!el1 || !el2 || !induc || !tsymb)
|
||||
return 0;
|
||||
inducsy = NULL;
|
||||
if (el1->level != el2->level)
|
||||
return 0;
|
||||
if (!el1->var || !el2->var)
|
||||
return 0;
|
||||
if (el1->var->symbol() != el2->var->symbol())
|
||||
return 0;
|
||||
// do they have the same function
|
||||
for (k = 0; k < MAXDIMARRAY; k++)
|
||||
{
|
||||
for (j = 0; j < el1->size; j++)
|
||||
{
|
||||
if (el1->linear[k][j] != el2->linear[k][j])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (k = 1; k < MAXDIMARRAY; k++)
|
||||
{
|
||||
if (el1->cst[k] != el2->cst[k])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
spatial = el1->cst[0] - el2->cst[0];
|
||||
if (spatial < 0)
|
||||
spatial = -spatial;
|
||||
if (spatial >= CacheLIneSize)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
TemporalNonSelfLocality(PT_ACCESSARRAY el1, PT_ACCESSARRAY el2, SgSymbol **tsymb, Set *induc)
|
||||
{
|
||||
SgSymbol *inducsy;
|
||||
int j, k;
|
||||
PT_INDUCVAR ind, cur;
|
||||
int loopnum;
|
||||
int spatial, temp;
|
||||
int flag;
|
||||
if (!el1 || !el2 || !induc || !tsymb)
|
||||
return 0;
|
||||
inducsy = NULL;
|
||||
if (el1->level != el2->level)
|
||||
return 0;
|
||||
if (!el1->var || !el2->var)
|
||||
return 0;
|
||||
if (el1->var->symbol() != el2->var->symbol())
|
||||
return 0;
|
||||
// do they have the same function
|
||||
for (k = 0; k < MAXDIMARRAY; k++)
|
||||
{
|
||||
for (j = 0; j < el1->size; j++)
|
||||
{
|
||||
if (el1->linear[k][j] != el2->linear[k][j])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// is there one reference with only one constant different
|
||||
flag = 0;
|
||||
for (k = 0; k < MAXDIMARRAY; k++)
|
||||
{
|
||||
if (el1->cst[k] != el2->cst[k])
|
||||
{
|
||||
if (flag)
|
||||
return 0;
|
||||
flag = k + 1;
|
||||
}
|
||||
}
|
||||
if (flag)
|
||||
{
|
||||
// check first that the coefficient is not NULL;
|
||||
for (j = 0; j < el1->size; j++)
|
||||
{
|
||||
if (el1->linear[flag - 1][j] != 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0; // that case is considered elsewhere
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
isLinearEqual(int size1, int size2, int linear1[MAXDIMARRAY][MAXNESTEDLOOP], int *cst1, int linear2[MAXDIMARRAY][MAXNESTEDLOOP], int *cst2)
|
||||
{
|
||||
int i, j;
|
||||
if (!linear1 || !linear2 || !cst1 || !cst2)
|
||||
return 0;
|
||||
if (size1 != size2)
|
||||
return 0;
|
||||
for (i = 0; i < MAXDIMARRAY; i++)
|
||||
{
|
||||
if (cst1[i] != cst2[i])
|
||||
return 0;
|
||||
for (j = 0; j < size1; j++)
|
||||
{
|
||||
if (linear1[i][j] != linear2[i][j])
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
isLinearEqualNoCst(int size1, int size2, int linear1[MAXDIMARRAY][MAXNESTEDLOOP], int linear2[MAXDIMARRAY][MAXNESTEDLOOP])
|
||||
{
|
||||
int i, j;
|
||||
if (!linear1 || !linear2)
|
||||
return 0;
|
||||
if (size1 != size2)
|
||||
return 0;
|
||||
for (i = 0; i < MAXDIMARRAY; i++)
|
||||
{
|
||||
for (j = 0; j < size1; j++)
|
||||
{
|
||||
if (linear1[i][j] != linear2[i][j])
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
isNull(int size, int linear[MAXNESTEDLOOP])
|
||||
{
|
||||
int i;
|
||||
if (!linear)
|
||||
return 1;
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
if (linear[i] != 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
18
Sapfor/_src/SageAnalysisTool/arrayRef.h
Normal file
18
Sapfor/_src/SageAnalysisTool/arrayRef.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
struct arrayAccess {
|
||||
SgStatement *stmt;
|
||||
SgExpression *var; // this is var;
|
||||
int linear[MAXDIMARRAY][MAXNESTEDLOOP];
|
||||
int isLinear[MAXDIMARRAY];
|
||||
int cst[MAXNESTEDLOOP];
|
||||
int nbdim;
|
||||
int size;
|
||||
int type;
|
||||
int rw;
|
||||
int scalar;
|
||||
int level; // give the loop number
|
||||
};
|
||||
|
||||
typedef struct arrayAccess *PT_ACCESSARRAY;
|
||||
|
||||
365
Sapfor/_src/SageAnalysisTool/computeInducVar.cpp
Normal file
365
Sapfor/_src/SageAnalysisTool/computeInducVar.cpp
Normal file
@@ -0,0 +1,365 @@
|
||||
#include <stdio.h>
|
||||
#include "sage++user.h"
|
||||
#include "definesValues.h"
|
||||
#include "set.h"
|
||||
#include "definitionSet.h"
|
||||
#include "inducVar.h"
|
||||
|
||||
extern Set *genSet[MAXNODE];
|
||||
extern Set *killSet[MAXNODE];
|
||||
extern Set *inSet[MAXNODE];
|
||||
extern Set *outSet[MAXNODE];
|
||||
|
||||
#ifdef __SPF
|
||||
extern "C" void addToCollection(const int line, const char *file, void *pointer, int type);
|
||||
extern "C" void removeFromCollection(void *pointer);
|
||||
#endif
|
||||
//
|
||||
// Here we compute the induction variables for a loop
|
||||
// this use the result of recheing analysis and invariant computation in loop.
|
||||
// we use as element of sets the following structure.
|
||||
//
|
||||
|
||||
//
|
||||
// Set Operation
|
||||
//
|
||||
int inducVarEqual(void *e1, void *e2)
|
||||
{
|
||||
SgExpression *ex1, *ex2;
|
||||
SgSymbol *s1, *s2;
|
||||
PT_INDUCVAR el1, el2;
|
||||
if (!e1 && !e2)
|
||||
return 1;
|
||||
if (!e1 || !e2)
|
||||
return 0;
|
||||
|
||||
el1 = (PT_INDUCVAR)e1;
|
||||
el2 = (PT_INDUCVAR)e2;
|
||||
if (el1->level != el2->level)
|
||||
return 0;
|
||||
if (el1->include != el2->include)
|
||||
return 0;
|
||||
if (el1->loopnum != el2->loopnum)
|
||||
return 0;
|
||||
if (el1->constante != el2->constante)
|
||||
return 0;
|
||||
|
||||
ex1 = el1->var;
|
||||
ex2 = el2->var;
|
||||
|
||||
if ((s1 = ex1->symbol()) && (s2 = ex2->symbol()))
|
||||
{
|
||||
if (s1 == s2)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void inducVarPrint(void *e1)
|
||||
{
|
||||
SgExpression *ex1;
|
||||
PT_INDUCVAR el1;
|
||||
if (!e1)
|
||||
return;
|
||||
el1 = (PT_INDUCVAR)e1;
|
||||
ex1 = el1->var;
|
||||
if (el1->constante)
|
||||
printf("Constante ");
|
||||
if (ex1->symbol())
|
||||
printf("%s (%d-%d-%d)", ex1->symbol()->identifier(), el1->level, el1->loopnum, el1->include);
|
||||
else
|
||||
ex1->unparsestdout();
|
||||
printf(" = ");
|
||||
ex1 = el1->lbound;
|
||||
if (ex1)
|
||||
ex1->unparsestdout();
|
||||
printf(",");
|
||||
ex1 = el1->ubound;
|
||||
if (ex1)
|
||||
ex1->unparsestdout();
|
||||
printf(",");
|
||||
ex1 = el1->stride;
|
||||
if (ex1)
|
||||
ex1->unparsestdout();
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Indicate if a variable is subject to modification in a stmt
|
||||
// Based on the Definition for each statement....
|
||||
// defvar is a varref;
|
||||
//
|
||||
|
||||
int definitionInStmt(SgStatement *func, SgStatement *stmtin, SgExpression *defvar)
|
||||
{
|
||||
SgStatement *last, *stmt;
|
||||
SgExpression *def, *expr;
|
||||
|
||||
if (!stmtin || !func)
|
||||
return FALSE;
|
||||
|
||||
last = stmtin->lastNodeOfStmt();
|
||||
|
||||
for (stmt = stmtin; stmt; stmt = stmt->lexNext())
|
||||
{
|
||||
def = (SgExpression *)stmt->attributeValue(0, DEFINEDLIST_ATTRIBUTE);
|
||||
//Defined[stmt->id()];
|
||||
while (def)
|
||||
{
|
||||
expr = def->lhs();
|
||||
if (expr && expr->symbol() && defvar->symbol() &&
|
||||
(expr->symbol() == defvar->symbol()))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
def = def->rhs();
|
||||
}
|
||||
if (stmt == last)
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
//same as before but avoid the first statement (for instance the loop header)
|
||||
// so can be used fo checking the basic induction variable;
|
||||
int definitionOnlyInsideStmt(SgStatement *func, SgStatement *stmtin, SgExpression *defvar)
|
||||
{
|
||||
SgStatement *last, *stmt;
|
||||
SgExpression *def, *expr;
|
||||
|
||||
if (!stmtin || !func)
|
||||
return FALSE;
|
||||
|
||||
last = stmtin->lastNodeOfStmt();
|
||||
|
||||
for (stmt = stmtin->lexNext(); stmt; stmt = stmt->lexNext())
|
||||
{
|
||||
def = (SgExpression *)stmt->attributeValue(0, DEFINEDLIST_ATTRIBUTE);
|
||||
// Defined[stmt->id()];
|
||||
while (def)
|
||||
{
|
||||
expr = def->lhs();
|
||||
if (expr && expr->symbol() && defvar->symbol() &&
|
||||
(expr->symbol() == defvar->symbol()))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
def = def->rhs();
|
||||
}
|
||||
if (stmt == last)
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// For a statement create an induction var set that contains the SCALAR constante
|
||||
// based on the use set which have to be defined later
|
||||
//
|
||||
Set* computeConstanteInStmt(SgStatement *func, SgStatement *stmtin)
|
||||
{
|
||||
SgStatement *last, *stmt;
|
||||
SgExpression *use, *expr;
|
||||
Set *constante;
|
||||
PT_INDUCVAR elin;
|
||||
int cst;
|
||||
|
||||
if (!stmtin || !func)
|
||||
return NULL;
|
||||
last = stmtin->lastNodeOfStmt();
|
||||
constante = new Set(inducVarEqual, NULL, inducVarPrint);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, constante, 1);
|
||||
#endif
|
||||
for (stmt = stmtin; stmt; stmt = stmt->lexNext())
|
||||
{
|
||||
use = (SgExpression *)stmt->attributeValue(0, USEDLIST_ATTRIBUTE);
|
||||
// Used[stmt->id()];
|
||||
while (use)
|
||||
{
|
||||
expr = use->lhs();
|
||||
if (definitionInStmt(func, stmtin, expr))
|
||||
cst = 0;
|
||||
else
|
||||
cst = 1;
|
||||
if (cst)
|
||||
{
|
||||
elin = new struct inducvar;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, elin, 1);
|
||||
#endif
|
||||
elin->constante = TRUE;
|
||||
elin->stmt = stmtin;
|
||||
elin->var = use->lhs();
|
||||
elin->lbound = NULL;
|
||||
elin->ubound = NULL;
|
||||
elin->stride = NULL;
|
||||
elin->level = 0;
|
||||
elin->loopnum = 0;
|
||||
constante->addElement((void *)elin);
|
||||
}
|
||||
use = use->rhs();
|
||||
}
|
||||
if (stmt == last)
|
||||
break;
|
||||
}
|
||||
if (constante)
|
||||
constante->compact();
|
||||
return constante;
|
||||
}
|
||||
|
||||
//
|
||||
// compute effectively induction variables (limited to basic induction variable for now)
|
||||
//
|
||||
Set* computeInductionVariables(SgStatement *func, SgStatement *stmt)
|
||||
{
|
||||
SgStatement *last, *first, *defreach, *temp, *cp;
|
||||
SgForStmt *loop;
|
||||
Set *induc, *reachdef;
|
||||
SgExpression *use, *def, *pt, *defvar, *expr;
|
||||
int change, id, inloop, inv, step;
|
||||
PT_ELSET el;
|
||||
PT_INDUCVAR elin;
|
||||
int i, inducF;
|
||||
if (!stmt || !func)
|
||||
return NULL;
|
||||
|
||||
if (!(loop = isSgForStmt(stmt)))
|
||||
return NULL;
|
||||
|
||||
induc = new Set(inducVarEqual, NULL, inducVarPrint);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, induc, 1);
|
||||
#endif
|
||||
def = (SgExpression *)stmt->attributeValue(0, DEFINEDLIST_ATTRIBUTE);
|
||||
// Defined[stmt->id()];
|
||||
if (def)
|
||||
{ // basic induction var;
|
||||
defvar = def->lhs(); // the loop modify the induction var only;
|
||||
// check if it is constant;
|
||||
if (!definitionOnlyInsideStmt(func, loop, defvar))
|
||||
inducF = 1;
|
||||
else
|
||||
{
|
||||
inducF = 1;
|
||||
Message("Induction variable may be defined", stmt->lineNumber());
|
||||
}
|
||||
if (inducF)
|
||||
{
|
||||
elin = new struct inducvar;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, elin, 1);
|
||||
#endif
|
||||
elin->constante = FALSE;
|
||||
elin->stmt = stmt;
|
||||
elin->var = def->lhs();
|
||||
elin->lbound = loop->start();
|
||||
elin->ubound = loop->end();
|
||||
elin->stride = loop->step();
|
||||
elin->level = 0;
|
||||
elin->loopnum = 0;
|
||||
induc->addElement((void *)elin);
|
||||
}
|
||||
else
|
||||
Message("Basic Induction Var not Found: dependence Test will abort", loop->lineNumber());
|
||||
// limited to basic induction variable for the moment...;
|
||||
}
|
||||
return induc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//Get all induction var;
|
||||
Set* getAllInductionVar(SgStatement *func, SgStatement *stmt, int level, int *num, int include)
|
||||
{
|
||||
SgStatement *temp, *child;
|
||||
int i, newlevel;
|
||||
Set *induc, *tpt;
|
||||
PT_INDUCVAR el;
|
||||
int tmpincl;
|
||||
if (!stmt)
|
||||
return NULL;
|
||||
induc = NULL;
|
||||
if (isSgForStmt(stmt))
|
||||
{
|
||||
*num = *num + 1;
|
||||
tmpincl = *num;
|
||||
induc = computeInductionVariables(func, stmt);
|
||||
if (induc)
|
||||
{
|
||||
for (i = 0; i < induc->size(); i++)
|
||||
{
|
||||
el = (PT_INDUCVAR)induc->getElement(i);
|
||||
if (el)
|
||||
{
|
||||
el->level = level;
|
||||
el->loopnum = *num;
|
||||
el->include = include;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
tmpincl = include;
|
||||
|
||||
i = 1;
|
||||
temp = stmt;
|
||||
child = temp->childList1(0);
|
||||
while (child)
|
||||
{
|
||||
if (isSgForStmt(child))
|
||||
newlevel = level + 1;
|
||||
else
|
||||
newlevel = level;
|
||||
if (induc)
|
||||
{
|
||||
induc->unionSet(tpt = getAllInductionVar(func, child, newlevel, num, tmpincl));
|
||||
if (tpt)
|
||||
{
|
||||
#ifdef __SPF
|
||||
removeFromCollection(tpt);
|
||||
#endif
|
||||
delete tpt;
|
||||
}
|
||||
}
|
||||
else
|
||||
induc = getAllInductionVar(func, child, newlevel, num, tmpincl);
|
||||
child = temp->childList1(i);
|
||||
i++;
|
||||
}
|
||||
|
||||
i = 1;
|
||||
temp = stmt;
|
||||
child = temp->childList2(0);
|
||||
while (child)
|
||||
{
|
||||
if (isSgForStmt(child))
|
||||
newlevel = level + 1;
|
||||
else
|
||||
newlevel = level;
|
||||
if (induc)
|
||||
{
|
||||
induc->unionSet(tpt = getAllInductionVar(func, child, newlevel, num, tmpincl));
|
||||
if (tpt)
|
||||
{
|
||||
#ifdef __SPF
|
||||
removeFromCollection(tpt);
|
||||
#endif
|
||||
delete tpt;
|
||||
}
|
||||
}
|
||||
else
|
||||
induc = getAllInductionVar(func, child, newlevel, num, tmpincl);
|
||||
child = temp->childList2(i);
|
||||
i++;
|
||||
}
|
||||
return induc;
|
||||
}
|
||||
279
Sapfor/_src/SageAnalysisTool/constanteProp.cpp
Normal file
279
Sapfor/_src/SageAnalysisTool/constanteProp.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sage++user.h"
|
||||
#include "definesValues.h"
|
||||
#include "set.h"
|
||||
#include "definitionSet.h"
|
||||
#include "constanteSet.h"
|
||||
|
||||
#ifdef __SPF
|
||||
extern "C" void addToCollection(const int line, const char *file, void *pointer, int type);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Program part for constant propagation.
|
||||
//
|
||||
|
||||
//
|
||||
// Set Operation
|
||||
//
|
||||
int constPropEqual(void *e1, void *e2)
|
||||
{
|
||||
SgExpression *ex1, *ex2;
|
||||
SgSymbol *s1, *s2;
|
||||
PT_CONSTPROP el1, el2;
|
||||
if (!e1 && !e2)
|
||||
return 1;
|
||||
if (!e1 || !e2)
|
||||
return 0;
|
||||
|
||||
el1 = (PT_CONSTPROP)e1;
|
||||
el2 = (PT_CONSTPROP)e2;
|
||||
|
||||
ex1 = el1->var;
|
||||
ex2 = el2->var;
|
||||
|
||||
if ((s1 = ex1->symbol()) && (s2 = ex2->symbol()))
|
||||
{
|
||||
if ((s1 == s2) && (el1->flag == el2->flag) && (el1->value == el2->value))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void constPropPrint(void *e1)
|
||||
{
|
||||
SgExpression *ex1;
|
||||
PT_CONSTPROP el1;
|
||||
if (!e1)
|
||||
return;
|
||||
el1 = (PT_CONSTPROP)e1;
|
||||
ex1 = el1->var;
|
||||
if (ex1->symbol())
|
||||
{
|
||||
printf("%s (from stmt %d):", ex1->symbol()->identifier(), el1->stmt->lineNumber());
|
||||
switch (el1->flag)
|
||||
{
|
||||
case UNDEFFLAG:
|
||||
printf("undefined\n");
|
||||
break;
|
||||
case NONCONSTFLAG:
|
||||
printf("non constant\n");
|
||||
break;
|
||||
case CONSTFLAG:
|
||||
printf("%d\n", el1->value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
printf("Bizarre\n");
|
||||
}
|
||||
|
||||
//
|
||||
// Here we need th combine operation, combine two elements
|
||||
// return NULL if combine possible
|
||||
//
|
||||
void *
|
||||
constPropCombine(void *e1, void *e2)
|
||||
{
|
||||
SgExpression *ex1, *ex2;
|
||||
SgSymbol *s1, *s2;
|
||||
PT_CONSTPROP el1, el2;
|
||||
|
||||
if (!e1)
|
||||
return e2;
|
||||
if (!e2)
|
||||
return e1;
|
||||
|
||||
el1 = (PT_CONSTPROP)e1;
|
||||
el2 = (PT_CONSTPROP)e2;
|
||||
|
||||
ex1 = el1->var;
|
||||
ex2 = el2->var;
|
||||
|
||||
if ((s1 = ex1->symbol()) && (s2 = ex2->symbol()))
|
||||
{
|
||||
if (s1 == s2)
|
||||
{
|
||||
if (el1->flag == UNDEFFLAG)
|
||||
return e1;
|
||||
if (el2->flag == UNDEFFLAG)
|
||||
return e2;
|
||||
if (el1->flag == NONCONSTFLAG)
|
||||
return e1;
|
||||
if (el2->flag == NONCONSTFLAG)
|
||||
return e2;
|
||||
|
||||
if (el1->value == el2->value)
|
||||
return e1;
|
||||
else
|
||||
{
|
||||
el1->flag = NONCONSTFLAG;
|
||||
return e1;
|
||||
}
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// this function evaluate the value of the
|
||||
//
|
||||
// some functions from the low_level are used for that function so that Evaluate Expression can use
|
||||
// the value of some variables
|
||||
//
|
||||
|
||||
// extern "C" void resetPresetEvaluate();
|
||||
// extern "C" void addElementEvaluate(...);
|
||||
|
||||
Set *transConstante(SgStatement *func, SgStatement *stmt, Set *setin)
|
||||
{
|
||||
Set *outset;
|
||||
SgExpression *def, *defvar, *expr;
|
||||
SgSymbol *symb;
|
||||
int val;
|
||||
int i;
|
||||
PT_CONSTPROP el = NULL;
|
||||
PT_CONSTPROP el1 = NULL;
|
||||
if (!func || !stmt)
|
||||
{
|
||||
Message("transConstante some parameters are null", 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (isSgCallStmt(stmt) || isSgInputOutputStmt(stmt))
|
||||
{
|
||||
if (!setin)
|
||||
return NULL;
|
||||
else
|
||||
{
|
||||
outset = new Set(constPropEqual, constPropCombine, constPropPrint);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, outset, 1);
|
||||
#endif
|
||||
for (i = 0; i < setin->size(); i++)
|
||||
{
|
||||
el = (PT_CONSTPROP)setin->getElement(i);
|
||||
if (el)
|
||||
{ // create new one otherwise side effect can appear;
|
||||
el1 = new struct constprop;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, el1, 1);
|
||||
#endif
|
||||
el1->flag = UNDEFFLAG;
|
||||
el1->var = el->var;
|
||||
el1->value = 0;
|
||||
el1->stmt = el->stmt;
|
||||
el1->expr = el->expr;
|
||||
outset->addElement((void *)el1);
|
||||
}
|
||||
}
|
||||
// should add the parameter list with undefined;
|
||||
|
||||
// this has been completly copied so allow to deallocate element too;
|
||||
// setin->setDealllocateElem(); other element need also to be copied
|
||||
return outset;
|
||||
}
|
||||
}
|
||||
if (!isSgAssignStmt(stmt))
|
||||
{
|
||||
if (!setin)
|
||||
return NULL;
|
||||
else
|
||||
return setin->copy();
|
||||
}
|
||||
if (setin)
|
||||
outset = setin->copy();
|
||||
else
|
||||
{
|
||||
outset = new Set(constPropEqual, constPropCombine, constPropPrint);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, outset, 1);
|
||||
#endif
|
||||
}
|
||||
// before evaluating the expression set the Value set ;
|
||||
if (setin)
|
||||
{
|
||||
for (i = 0; i < setin->size(); i++)
|
||||
{
|
||||
el = (PT_CONSTPROP)setin->getElement(i);
|
||||
if (el)
|
||||
{
|
||||
if ((el->flag == CONSTFLAG) &&
|
||||
el->var &&
|
||||
el->var->symbol())
|
||||
{
|
||||
addElementEvaluate(el->var->symbol()->thesymb, el->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// just call Evaluate Expression ;
|
||||
def = (SgExpression *)stmt->attributeValue(0, DEFINEDLIST_ATTRIBUTE);
|
||||
//Defined[stmt->id()];
|
||||
if (def)
|
||||
{
|
||||
defvar = def->lhs();
|
||||
if (isSgVarRefExp(defvar))
|
||||
{
|
||||
symb = defvar->symbol();
|
||||
if (symb && symb->type() && (symb->type()->variant() == T_INT))
|
||||
{
|
||||
if (setin)
|
||||
{
|
||||
// remove all definition to the symbol;
|
||||
for (i = 0; i < outset->size(); i++)
|
||||
{
|
||||
el = (PT_CONSTPROP)outset->getElement(i);
|
||||
if (el)
|
||||
{
|
||||
if (el->var->symbol() == symb)
|
||||
outset->rmElement(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
expr = stmt->expr(1);
|
||||
el = new struct constprop;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, el, 1);
|
||||
#endif
|
||||
if (!el)
|
||||
{
|
||||
Message("No more Memory", 0);
|
||||
exit(1);
|
||||
}
|
||||
if (expr && expr->isInteger())
|
||||
{
|
||||
val = expr->valueInteger();
|
||||
el->flag = CONSTFLAG;
|
||||
el->var = defvar;
|
||||
el->value = val;
|
||||
el->stmt = stmt;
|
||||
el->expr = expr;
|
||||
outset->addElement((void *)el);
|
||||
}
|
||||
else
|
||||
{
|
||||
el->flag = UNDEFFLAG;
|
||||
el->var = defvar;
|
||||
el->value = 0;
|
||||
el->stmt = stmt;
|
||||
el->expr = expr;
|
||||
outset->addElement((void *)el);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
resetPresetEvaluate();
|
||||
// printf("intermediate print line %d\n", stmt->lineNumber());
|
||||
// outset->printSet();
|
||||
return outset;
|
||||
}
|
||||
19
Sapfor/_src/SageAnalysisTool/constanteSet.h
Normal file
19
Sapfor/_src/SageAnalysisTool/constanteSet.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Here we compute the induction variables for a loop
|
||||
// this use the result of recheing analysis and invariant computation in loop.
|
||||
// we use as element of sets the following structure.
|
||||
//
|
||||
|
||||
struct constprop
|
||||
{
|
||||
int flag; // can be UNDEFFLAG, NONCONSTFLAG, CONSTFLAG
|
||||
SgExpression *var; // this is a var ref;
|
||||
int value;
|
||||
SgStatement *stmt;
|
||||
SgExpression *expr;
|
||||
};
|
||||
|
||||
typedef struct constprop *PT_CONSTPROP;
|
||||
|
||||
237
Sapfor/_src/SageAnalysisTool/controlFlow.cpp
Normal file
237
Sapfor/_src/SageAnalysisTool/controlFlow.cpp
Normal file
@@ -0,0 +1,237 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "sage++user.h"
|
||||
#include "definesValues.h"
|
||||
|
||||
|
||||
//
|
||||
// Control Flow functions -------> should become a method of the statement class
|
||||
// return an array of successor and predecessor
|
||||
// the function compute the control flow.
|
||||
// this is assumed to be applied on a function.
|
||||
// func is the function we are in
|
||||
//
|
||||
|
||||
|
||||
void
|
||||
controlFlow(SgStatement *stmt, SgStatement *func, SgStatement **pred, SgStatement **suc, int *predin, int *sucint)
|
||||
{
|
||||
SgLabel *lab, *labtemp;
|
||||
SgStatement *last, *cp, *temp;
|
||||
SgGotoStmt *gt;
|
||||
SgLabelListStmt *gtl;
|
||||
SgExpression *expr, *te;
|
||||
SgLabelRefExp *le;
|
||||
int nbpred, nbsuc;
|
||||
if (!stmt || !func)
|
||||
return;
|
||||
|
||||
nbpred = 0;
|
||||
nbsuc = 0;
|
||||
|
||||
if (lab = stmt->label())
|
||||
{ // there is a label, look at the goto on it;
|
||||
last = func->lastNodeOfStmt();
|
||||
// look at the goto statement going to the statement;
|
||||
for (temp = func; temp && (temp != last); temp = temp->lexNext())
|
||||
{
|
||||
if (gt = isSgGotoStmt(temp))
|
||||
{
|
||||
labtemp = gt->label();
|
||||
if (labtemp && (labtemp->id() == lab->id()))
|
||||
{
|
||||
pred[nbpred] = temp;
|
||||
nbpred++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gtl = isSgLabelListStmt(temp))
|
||||
{
|
||||
expr = gtl->labelList();
|
||||
for (te = expr; te; te = te->rhs())
|
||||
{
|
||||
if (le = isSgLabelRefExp(te->lhs()))
|
||||
{
|
||||
labtemp = le->label();
|
||||
if (labtemp && (labtemp->id() == lab->id()))
|
||||
{
|
||||
pred[nbpred] = temp;
|
||||
nbpred++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// there is no label;
|
||||
// depending on the statement we compute the predecessors;
|
||||
// and the successor;
|
||||
// here we use a big case;
|
||||
switch (stmt->variant())
|
||||
{
|
||||
case CONT_STAT:
|
||||
case CONTROL_END:
|
||||
cp = stmt->controlParent();
|
||||
if (cp)
|
||||
{
|
||||
switch (cp->variant())
|
||||
{
|
||||
case WHILE_NODE:
|
||||
case FOR_NODE:
|
||||
pred[nbpred] = stmt->nodeBefore();
|
||||
nbpred++;
|
||||
suc[nbsuc] = stmt->lexNext();
|
||||
nbsuc++;
|
||||
suc[nbsuc] = cp;
|
||||
nbsuc++;
|
||||
break;
|
||||
default:
|
||||
pred[nbpred] = stmt->nodeBefore();
|
||||
suc[nbsuc] = stmt->lexNext();
|
||||
nbpred++;
|
||||
nbsuc++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pred[nbpred] = stmt->nodeBefore();
|
||||
suc[nbsuc] = stmt->lexNext();
|
||||
nbpred++;
|
||||
nbsuc++;
|
||||
}
|
||||
break;
|
||||
case IF_NODE:
|
||||
suc[nbsuc] = stmt->childList1(0);
|
||||
nbsuc++;
|
||||
if (stmt->childList2(0))
|
||||
{
|
||||
suc[nbsuc] = stmt->childList2(0);
|
||||
nbsuc++;
|
||||
}
|
||||
else
|
||||
{
|
||||
suc[nbsuc] = stmt->lastNodeOfStmt()->lexNext();
|
||||
nbsuc++;
|
||||
}
|
||||
pred[nbpred] = stmt->nodeBefore();
|
||||
nbpred++;
|
||||
break;
|
||||
case WHILE_NODE:
|
||||
case FOR_NODE:
|
||||
pred[nbpred] = stmt->nodeBefore();
|
||||
nbpred++;
|
||||
pred[nbpred] = stmt->lastNodeOfStmt();
|
||||
nbpred++;
|
||||
suc[nbsuc] = stmt->lexNext();
|
||||
nbsuc++;
|
||||
suc[nbsuc] = stmt->lastNodeOfStmt()->lexNext();
|
||||
nbsuc++;
|
||||
break;
|
||||
case DO_WHILE_NODE:
|
||||
pred[nbpred] = stmt->nodeBefore();
|
||||
nbpred++;
|
||||
pred[nbpred] = stmt->lastNodeOfStmt();
|
||||
nbpred++;
|
||||
suc[nbsuc] = stmt->lexNext();
|
||||
nbsuc++;
|
||||
break;
|
||||
case GOTO_NODE:
|
||||
if (gt = isSgGotoStmt(stmt))
|
||||
{
|
||||
if (lab = gt->label())
|
||||
{ // there is a label, look at the goto on it;
|
||||
last = func->lastNodeOfStmt();
|
||||
// look at the goto statement going to the statement;
|
||||
for (temp = func; temp && (temp != last); temp = temp->lexNext())
|
||||
{
|
||||
labtemp = temp->label();
|
||||
if (labtemp && (labtemp->id() == lab->id()))
|
||||
{
|
||||
suc[nbsuc] = temp;
|
||||
nbsuc++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LOGIF_NODE:
|
||||
suc[nbsuc] = stmt->childList1(0);
|
||||
nbsuc++;
|
||||
suc[nbsuc] = stmt->lastNodeOfStmt()->lexNext();
|
||||
nbsuc++;
|
||||
pred[nbpred] = stmt->nodeBefore();
|
||||
nbpred++;
|
||||
break;
|
||||
case STOP_STAT:
|
||||
case RETURN_STAT:
|
||||
case RETURN_NODE:
|
||||
pred[nbpred] = stmt->nodeBefore();
|
||||
nbpred++;
|
||||
suc[nbsuc] = func->lastNodeOfStmt();
|
||||
nbsuc++;
|
||||
break;
|
||||
case ELSEIF_NODE:
|
||||
// case ARITHIF_NODE:
|
||||
case WHERE_NODE:
|
||||
case WHERE_BLOCK_STMT:
|
||||
case SWITCH_NODE:
|
||||
case CASE_NODE:
|
||||
case BREAK_NODE:
|
||||
case EXIT_STMT:
|
||||
case ASSGOTO_NODE:
|
||||
case COMGOTO_NODE:
|
||||
printf("Statement line %d not implemented for control flow\n", stmt->lineNumber());
|
||||
break;
|
||||
default:
|
||||
// cas du if a voir ici...
|
||||
cp = stmt->controlParent();
|
||||
if (cp)
|
||||
{
|
||||
switch (cp->variant())
|
||||
{
|
||||
case IF_NODE:
|
||||
if (cp->childList1(0) == stmt)
|
||||
{
|
||||
pred[nbpred] = cp;
|
||||
nbpred++;
|
||||
suc[nbsuc] = stmt->lexNext();
|
||||
nbsuc++;
|
||||
}
|
||||
else
|
||||
if (cp->childList2(0) == stmt)
|
||||
{
|
||||
pred[nbpred] = cp;
|
||||
nbpred++;
|
||||
suc[nbsuc] = stmt->lexNext();
|
||||
nbsuc++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pred[nbpred] = stmt->nodeBefore();
|
||||
suc[nbsuc] = stmt->lexNext();
|
||||
nbpred++;
|
||||
nbsuc++;
|
||||
}
|
||||
break;
|
||||
// for node should also be taken into account
|
||||
default:
|
||||
pred[nbpred] = stmt->nodeBefore();
|
||||
suc[nbsuc] = stmt->lexNext();
|
||||
nbpred++;
|
||||
nbsuc++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pred[nbpred] = stmt->nodeBefore();
|
||||
suc[nbsuc] = stmt->lexNext();
|
||||
nbpred++;
|
||||
nbsuc++;
|
||||
}
|
||||
}
|
||||
*predin = nbpred;
|
||||
*sucint = nbsuc;
|
||||
}
|
||||
789
Sapfor/_src/SageAnalysisTool/defUse.cpp
Normal file
789
Sapfor/_src/SageAnalysisTool/defUse.cpp
Normal file
@@ -0,0 +1,789 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "../GraphCall/graph_calls.h"
|
||||
#include "../Utils/errors.h"
|
||||
#include "../Utils/utils.h"
|
||||
#include "sage++user.h"
|
||||
#include "definesValues.h"
|
||||
#include "set.h"
|
||||
#include "definitionSet.h"
|
||||
|
||||
|
||||
using std::map;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::wstring;
|
||||
|
||||
#ifdef __SPF
|
||||
extern "C" void addToCollection(const int line, const char *file, void *pointer, int type);
|
||||
extern "C" void removeFromCollection(void *pointer);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Global table to store the use and def
|
||||
//
|
||||
|
||||
// Not used anymore, replaced by attributes;
|
||||
// SgExpression *Used[MAXNODE];
|
||||
// SgExpression *Defined[MAXNODE];
|
||||
|
||||
//
|
||||
// declaration for the data flow framework
|
||||
//
|
||||
|
||||
extern Set *genSet[MAXNODE];
|
||||
extern Set *killSet[MAXNODE];
|
||||
extern Set *inSet[MAXNODE];
|
||||
extern Set *outSet[MAXNODE];
|
||||
|
||||
extern void iterativeForwardFlowAnalysis(SgFile *file,
|
||||
SgStatement *func,
|
||||
Set *(*giveGenSet)(SgStatement *func, SgStatement *stmt),
|
||||
Set *(*giveKillSet)(SgStatement *func, SgStatement *stmt),
|
||||
int(*feq)(void *e1, void *e2),
|
||||
void *(*fcomb)(void *e1, void *e2),
|
||||
void(*fp)(void *e1));
|
||||
|
||||
extern void generalIterativeFlowAnalysis(SgFile *file,
|
||||
SgStatement *func,
|
||||
Set *(*transfertSet)(SgStatement *func, SgStatement *stmt, Set *setin),
|
||||
int(*feq)(void *e1, void *e2),
|
||||
void* (*fcomb)(void *e1, void *e2),
|
||||
void(*fp)(void *e1));
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// from the intrinsic.C file
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern int isSymbolIntrinsic(SgSymbol *symb);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// computes the definition for each file;
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline bool isVarRef(SgExpression *ex)
|
||||
{
|
||||
const int var = ex->variant();
|
||||
return (var == ARRAY_REF || var == VAR_REF || var == ARRAY_OP);
|
||||
}
|
||||
|
||||
static void fillDef(SgExpression *ex, vector<SgExpression*> &useL, vector<SgExpression*> &defL,
|
||||
const map<string, FuncInfo*> &funcs, vector<Messages> &messagesForFile, const int currLine);
|
||||
|
||||
static void fillUse(SgExpression *ex, vector<SgExpression*> &useL, vector<SgExpression*> &defL,
|
||||
const map<string, FuncInfo*> &funcs, vector<Messages> &messagesForFile, const int currLine)
|
||||
{
|
||||
if (ex)
|
||||
{
|
||||
if (isVarRef(ex))
|
||||
{
|
||||
useL.push_back(ex);
|
||||
fillUse(ex->lhs(), useL, defL, funcs, messagesForFile, currLine);
|
||||
fillUse(ex->rhs(), useL, defL, funcs, messagesForFile, currLine);
|
||||
}
|
||||
else if (ex->variant() == FUNC_CALL)
|
||||
fillDef(ex, useL, defL, funcs, messagesForFile, currLine);
|
||||
else
|
||||
{
|
||||
fillUse(ex->lhs(), useL, defL, funcs, messagesForFile, currLine);
|
||||
fillUse(ex->rhs(), useL, defL, funcs, messagesForFile, currLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fillDef(SgExpression *ex, vector<SgExpression*> &useL, vector<SgExpression*> &defL,
|
||||
const map<string, FuncInfo*> &funcs, vector<Messages> &messagesForFile, const int currLine)
|
||||
{
|
||||
if (ex)
|
||||
{
|
||||
if (ex->variant() == FUNC_CALL)
|
||||
{
|
||||
bool isIntrinsic = isSymbolIntrinsic(ex->symbol());
|
||||
SgFunctionCallExp *call = (SgFunctionCallExp*)ex;
|
||||
|
||||
FuncInfo *currInfo = NULL;
|
||||
auto it = funcs.find(call->funName()->identifier());
|
||||
if (funcs.end() != it)
|
||||
{
|
||||
currInfo = it->second;
|
||||
if (currInfo->funcParams.countOfPars != call->numberOfArgs())
|
||||
{
|
||||
wstring bufE, bufR;
|
||||
__spf_printToLongBuf(bufE, L"Count of formal and actual parameters are not equal for function call '%s'", to_wstring(currInfo->funcName).c_str());
|
||||
__spf_printToLongBuf(bufR, R82, to_wstring(currInfo->funcName).c_str());
|
||||
|
||||
messagesForFile.push_back(Messages(ERROR, currLine, bufR, bufE, 1046));
|
||||
throw -991;
|
||||
}
|
||||
}
|
||||
|
||||
for (int z = 0; z < call->numberOfArgs(); ++z)
|
||||
{
|
||||
SgExpression *arg = call->arg(z);
|
||||
if (isVarRef(arg))
|
||||
{
|
||||
if (currInfo)
|
||||
{
|
||||
if (currInfo->funcParams.isArgOut(z))
|
||||
defL.push_back(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isIntrinsic)
|
||||
defL.push_back(arg);
|
||||
}
|
||||
useL.push_back(arg);
|
||||
}
|
||||
|
||||
fillUse(arg->lhs(), useL, defL, funcs, messagesForFile, currLine);
|
||||
fillUse(arg->rhs(), useL, defL, funcs, messagesForFile, currLine);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fillUse(ex->lhs(), useL, defL, funcs, messagesForFile, currLine);
|
||||
fillUse(ex->rhs(), useL, defL, funcs, messagesForFile, currLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SgExpression* makeList(const std::vector<SgExpression*> &vec)
|
||||
{
|
||||
if (vec.size() == 0)
|
||||
return NULL;
|
||||
|
||||
SgExpression *list = new SgExpression(EXPR_LIST);
|
||||
SgExpression *r_list = list;
|
||||
for (int i = 0; i < vec.size(); ++i)
|
||||
{
|
||||
list->setLhs(vec[i]);
|
||||
if (i != vec.size() - 1)
|
||||
{
|
||||
list->setRhs(new SgExpression(EXPR_LIST));
|
||||
list = list->rhs();
|
||||
}
|
||||
}
|
||||
|
||||
return r_list;
|
||||
}
|
||||
|
||||
static void defUseVar(SgStatement *stmt, SgStatement *func, SgExpression **def, SgExpression **use,
|
||||
const map<string, FuncInfo*> &allFuncs, vector<Messages> &messagesForFile)
|
||||
{
|
||||
SgExpression *expr1, *expr2;
|
||||
SgExpression *temp, *pt, *pt1;
|
||||
SgArrayRefExp *aref;
|
||||
SgExprListExp *exprli;
|
||||
SgFunctionCallExp *fc;
|
||||
SgInputOutputStmt *iostmt;
|
||||
SgCallStmt *callStat;
|
||||
if (!stmt || !func)
|
||||
return;
|
||||
|
||||
*def = NULL;
|
||||
*use = NULL;
|
||||
|
||||
switch (stmt->variant())
|
||||
{
|
||||
case ASSIGN_STAT:
|
||||
expr1 = stmt->expr(0);
|
||||
expr2 = stmt->expr(1);
|
||||
// need to be recursively applied later;
|
||||
if (expr1)
|
||||
*def = expr1->symbRefs();
|
||||
else
|
||||
*def = NULL;
|
||||
if (expr2)
|
||||
*use = expr2->symbRefs();
|
||||
else
|
||||
*use = NULL;
|
||||
for (temp = *def; temp; temp = temp->rhs())
|
||||
{
|
||||
if (aref = isSgArrayRefExp(temp->lhs()))
|
||||
{
|
||||
pt = aref->subscripts();
|
||||
if (pt)
|
||||
{
|
||||
pt1 = pt->symbRefs();
|
||||
// we add it to the end of use;
|
||||
if (*use)
|
||||
{
|
||||
if (pt1 && (exprli = isSgExprListExp(*use)))
|
||||
{
|
||||
exprli->linkToEnd(*pt1);
|
||||
}
|
||||
}
|
||||
else
|
||||
*use = pt1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (temp = *use; temp; temp = temp->rhs())
|
||||
{
|
||||
if (aref = isSgArrayRefExp(temp->lhs()))
|
||||
{
|
||||
pt = aref->subscripts();
|
||||
if (pt)
|
||||
{
|
||||
pt1 = pt->symbRefs();
|
||||
// we add it to the end of use;
|
||||
if (pt1 && (exprli = isSgExprListExp(*use)))
|
||||
{
|
||||
exprli->linkToEnd(*pt1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fc = isSgFunctionCallExp(temp->lhs()))
|
||||
{
|
||||
FuncInfo *currInfo = NULL;
|
||||
auto it = allFuncs.find(fc->funName()->identifier());
|
||||
if (allFuncs.end() != it)
|
||||
{
|
||||
currInfo = it->second;
|
||||
if (currInfo->funcParams.countOfPars != fc->numberOfArgs())
|
||||
{
|
||||
wstring bufE, bufR;
|
||||
__spf_printToLongBuf(bufE, L"Count of formal and actual parameters are not equal for function call '%s'", to_wstring(currInfo->funcName).c_str());
|
||||
__spf_printToLongBuf(bufR, R83, to_wstring(currInfo->funcName).c_str());
|
||||
|
||||
messagesForFile.push_back(Messages(ERROR, stmt->lineNumber(), bufR, bufE, 1046));
|
||||
throw -991;
|
||||
}
|
||||
}
|
||||
|
||||
pt = fc->args();
|
||||
if (pt)
|
||||
{
|
||||
pt1 = pt->symbRefs();
|
||||
// we add it to the end of use;
|
||||
if (pt1 && (exprli = isSgExprListExp(*use)))
|
||||
{
|
||||
exprli->linkToEnd(*pt1);
|
||||
}
|
||||
|
||||
//new algo
|
||||
if (currInfo)
|
||||
{
|
||||
vector<SgExpression*> defL;
|
||||
vector<SgExpression*> useL;
|
||||
fillDef(fc, useL, defL, allFuncs, messagesForFile, stmt->lineNumber());
|
||||
if (defL.size())
|
||||
{
|
||||
SgExpression *list = makeList(defL);
|
||||
if (exprli = isSgExprListExp(*def))
|
||||
exprli->linkToEnd(*list);
|
||||
else
|
||||
*def = list;
|
||||
}
|
||||
} //old algo
|
||||
else
|
||||
{
|
||||
// if not an intrinsic, needs to be added to the def list;
|
||||
if (!isSymbolIntrinsic(fc->funName()))
|
||||
{
|
||||
pt1 = pt->symbRefs();
|
||||
if (pt1 && (exprli = isSgExprListExp(*def)))
|
||||
{
|
||||
exprli->linkToEnd(*pt1);
|
||||
}
|
||||
else
|
||||
*def = pt1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FOR_NODE:
|
||||
{
|
||||
SgExprListExp *el;
|
||||
SgVarRefExp *vr;
|
||||
if (stmt->symbol())
|
||||
{
|
||||
vr = new SgVarRefExp(*(stmt->symbol()));
|
||||
*def = new SgExprListExp(*vr);
|
||||
*use = new SgExprListExp(*vr);
|
||||
}
|
||||
else
|
||||
{
|
||||
*use = NULL;
|
||||
*def = NULL;
|
||||
}
|
||||
// Borne inf and sup are also sunject to use;
|
||||
expr1 = stmt->expr(0);
|
||||
expr2 = stmt->expr(1);
|
||||
// need to be recursively applied later;
|
||||
if (expr1)
|
||||
{
|
||||
pt1 = expr1->symbRefs();
|
||||
if (*use)
|
||||
{
|
||||
if (pt1 && (exprli = isSgExprListExp(*use)))
|
||||
{
|
||||
exprli->linkToEnd(*pt1);
|
||||
}
|
||||
}
|
||||
else
|
||||
*use = pt1;
|
||||
}
|
||||
if (expr2)
|
||||
{
|
||||
pt1 = expr2->symbRefs();
|
||||
if (*use)
|
||||
{
|
||||
if (pt1 && (exprli = isSgExprListExp(*use)))
|
||||
{
|
||||
exprli->linkToEnd(*pt1);
|
||||
}
|
||||
}
|
||||
else
|
||||
*use = pt1;
|
||||
}
|
||||
for (temp = *use; temp; temp = temp->rhs())
|
||||
{
|
||||
if (aref = isSgArrayRefExp(temp->lhs()))
|
||||
{
|
||||
pt = aref->subscripts();
|
||||
if (pt)
|
||||
{
|
||||
pt1 = pt->symbRefs();
|
||||
// we add it to the end of use;
|
||||
if (pt1 && (exprli = isSgExprListExp(*use)))
|
||||
{
|
||||
exprli->linkToEnd(*pt1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fc = isSgFunctionCallExp(temp->lhs()))
|
||||
{
|
||||
pt = fc->args();
|
||||
if (pt)
|
||||
{
|
||||
pt1 = pt->symbRefs();
|
||||
// we add it to the end of use;
|
||||
if (pt1 && (exprli = isSgExprListExp(*use)))
|
||||
{
|
||||
exprli->linkToEnd(*pt1);
|
||||
}
|
||||
// if not an intrinsic, needs to be added to the def list;
|
||||
if (!isSymbolIntrinsic(fc->funName()))
|
||||
{
|
||||
pt1 = pt->symbRefs();
|
||||
if (pt1 && (exprli = isSgExprListExp(*def)))
|
||||
{
|
||||
exprli->linkToEnd(*pt1);
|
||||
}
|
||||
else
|
||||
*def = pt1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LOGIF_NODE:
|
||||
case CONT_STAT:
|
||||
case CONTROL_END: // here we should check if loop...
|
||||
case IF_NODE:
|
||||
case WHILE_NODE:
|
||||
case DO_WHILE_NODE:
|
||||
expr2 = stmt->expr(0);
|
||||
// need to be recursively applied later;
|
||||
if (expr2)
|
||||
*use = expr2->symbRefs();
|
||||
else
|
||||
*use = NULL;
|
||||
*def = NULL;
|
||||
for (temp = *use; temp; temp = temp->rhs())
|
||||
{
|
||||
if (aref = isSgArrayRefExp(temp->lhs()))
|
||||
{
|
||||
pt = aref->subscripts();
|
||||
if (pt)
|
||||
{
|
||||
pt1 = pt->symbRefs();
|
||||
// we add it to the end of use;
|
||||
if (pt1 && (exprli = isSgExprListExp(*use)))
|
||||
{
|
||||
exprli->linkToEnd(*pt1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fc = isSgFunctionCallExp(temp->lhs()))
|
||||
{
|
||||
pt = fc->args();
|
||||
if (pt)
|
||||
{
|
||||
pt1 = pt->symbRefs();
|
||||
// we add it to the end of use;
|
||||
if (pt1 && (exprli = isSgExprListExp(*use)))
|
||||
{
|
||||
exprli->linkToEnd(*pt1);
|
||||
}
|
||||
// if not an intrinsic, needs to be added to the def list;
|
||||
if (!isSymbolIntrinsic(fc->funName()))
|
||||
{
|
||||
pt1 = pt->symbRefs();
|
||||
if (pt1 && (exprli = isSgExprListExp(*def)))
|
||||
{
|
||||
exprli->linkToEnd(*pt1);
|
||||
}
|
||||
else
|
||||
*def = pt1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case READ_STAT:
|
||||
iostmt = isSgInputOutputStmt(stmt);
|
||||
if (iostmt)
|
||||
{
|
||||
if (iostmt->itemList())
|
||||
*def = iostmt->itemList()->symbRefs();
|
||||
else
|
||||
*def = NULL;
|
||||
*use = NULL;
|
||||
}
|
||||
else
|
||||
Message("internal error : IO statements not found\n", 0);
|
||||
break;
|
||||
|
||||
case WRITE_STAT:
|
||||
case PRINT_STAT:
|
||||
iostmt = isSgInputOutputStmt(stmt);
|
||||
if (iostmt)
|
||||
{
|
||||
if (iostmt->itemList())
|
||||
*use = iostmt->itemList()->symbRefs();
|
||||
else
|
||||
*use = NULL;
|
||||
*def = NULL;
|
||||
}
|
||||
else
|
||||
Message("internal error : IO statements not found\n", 0);
|
||||
break;
|
||||
case PROC_STAT:
|
||||
callStat = (SgCallStmt*)stmt;
|
||||
|
||||
pt = callStat->expr(0);
|
||||
if (pt)
|
||||
{
|
||||
/**use = pt->symbRefs();
|
||||
// if not an intrinsic, needs to be added to the def list;
|
||||
if (!isSymbolIntrinsic(callStat->name()))
|
||||
*def = pt->symbRefs();
|
||||
printf("old use:\n");
|
||||
recExpressionPrint(*use);
|
||||
printf("old def:\n");
|
||||
recExpressionPrint(*def);*/
|
||||
|
||||
vector<SgExpression*> defL;
|
||||
vector<SgExpression*> useL;
|
||||
|
||||
FuncInfo *currInfo = NULL;
|
||||
auto it = allFuncs.find(callStat->name()->identifier());
|
||||
if (allFuncs.end() != it)
|
||||
{
|
||||
currInfo = it->second;
|
||||
if (currInfo->funcParams.countOfPars != callStat->numberOfArgs())
|
||||
{
|
||||
wstring bufE, bufR;
|
||||
__spf_printToLongBuf(bufE, L"Count of formal and actual parameters are not equal for function call '%s'", to_wstring(currInfo->funcName).c_str());
|
||||
__spf_printToLongBuf(bufR, R84, to_wstring(currInfo->funcName).c_str());
|
||||
|
||||
messagesForFile.push_back(Messages(ERROR, stmt->lineNumber(), bufR, bufE, 1046));
|
||||
throw -991;
|
||||
}
|
||||
}
|
||||
|
||||
for (int z = 0; z < callStat->numberOfArgs(); ++z)
|
||||
{
|
||||
SgExpression *arg = callStat->arg(z);
|
||||
if (isVarRef(arg))
|
||||
{
|
||||
if (currInfo)
|
||||
{
|
||||
if (currInfo->funcParams.isArgOut(z))
|
||||
defL.push_back(arg);
|
||||
}
|
||||
else
|
||||
defL.push_back(arg);
|
||||
useL.push_back(arg);
|
||||
}
|
||||
|
||||
fillUse(arg->lhs(), useL, defL, allFuncs, messagesForFile, callStat->lineNumber());
|
||||
fillUse(arg->rhs(), useL, defL, allFuncs, messagesForFile, callStat->lineNumber());
|
||||
}
|
||||
|
||||
*use = makeList(useL);
|
||||
*def = makeList(defL);
|
||||
|
||||
/*printf("new use:\n");
|
||||
recExpressionPrint(*use);
|
||||
printf("new def:\n");
|
||||
recExpressionPrint(*def);
|
||||
printf("");*/
|
||||
}
|
||||
else
|
||||
{
|
||||
*def = NULL;
|
||||
*use = NULL;
|
||||
}
|
||||
break;
|
||||
case GOTO_NODE:
|
||||
case STOP_STAT:
|
||||
case RETURN_STAT:
|
||||
case RETURN_NODE:
|
||||
case ELSEIF_NODE:
|
||||
case ARITHIF_NODE:
|
||||
case WHERE_NODE:
|
||||
case WHERE_BLOCK_STMT:
|
||||
case SWITCH_NODE:
|
||||
case CASE_NODE:
|
||||
case BREAK_NODE:
|
||||
case EXIT_STMT:
|
||||
case ASSGOTO_NODE:
|
||||
case COMGOTO_NODE:
|
||||
default:
|
||||
*def = NULL;
|
||||
*use = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void initDefUseTable(SgStatement *func, const map<string, FuncInfo*> &allFuncs, vector<Messages> &messagesForFile)
|
||||
{
|
||||
SgStatement *last, *first, *lastfunc, *temp;
|
||||
SgExpression *def, *use, *pt;
|
||||
int i;
|
||||
int nbatt, typeat, j;
|
||||
|
||||
if (!func)
|
||||
return;
|
||||
|
||||
lastfunc = func->lastNodeOfStmt();
|
||||
|
||||
|
||||
for (temp = func; temp; temp = temp->lexNext())
|
||||
{
|
||||
if (isSgExecutableStatement(temp))
|
||||
{
|
||||
nbatt = temp->numberOfAttributes();
|
||||
for (j = 0; j < nbatt; j++)
|
||||
{
|
||||
typeat = temp->attributeType(j);
|
||||
if ((typeat == USEDLIST_ATTRIBUTE) ||
|
||||
(typeat == DEFINEDLIST_ATTRIBUTE))
|
||||
{
|
||||
temp->deleteAttribute(j);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (temp == lastfunc)
|
||||
break;
|
||||
}
|
||||
|
||||
for (temp = func; temp; temp = temp->lexNext())
|
||||
{
|
||||
if (isSgExecutableStatement(temp))
|
||||
{
|
||||
defUseVar(temp, func, &def, &use, allFuncs, messagesForFile);
|
||||
temp->addAttribute(USEDLIST_ATTRIBUTE, (void*)use, 0);
|
||||
temp->addAttribute(DEFINEDLIST_ATTRIBUTE, (void*)def, 0);
|
||||
}
|
||||
if (temp == lastfunc)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Example of functions for flow analysis
|
||||
//
|
||||
int symbRefEqual(void *e1, void *e2)
|
||||
{
|
||||
SgExpression *ex1, *ex2;
|
||||
SgSymbol *s1, *s2;
|
||||
PT_ELSET el1, el2;
|
||||
if (!e1 && !e2)
|
||||
return 1;
|
||||
if (!e1 || !e2)
|
||||
return 0;
|
||||
|
||||
el1 = (PT_ELSET)e1;
|
||||
el2 = (PT_ELSET)e2;
|
||||
|
||||
ex1 = el1->expr;
|
||||
ex2 = el2->expr;
|
||||
|
||||
if ((s1 = ex1->symbol()) && (s2 = ex2->symbol()))
|
||||
{
|
||||
if (s1 == s2)
|
||||
{
|
||||
if (el1->stmt == el2->stmt)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void myPrint(void *e1)
|
||||
{
|
||||
SgExpression *ex1;
|
||||
PT_ELSET el1;
|
||||
if (!e1)
|
||||
return;
|
||||
el1 = (PT_ELSET)e1;
|
||||
ex1 = el1->expr;
|
||||
if (el1->stmt)
|
||||
printf("(id = %d, line = %d, ", el1->stmt->id(), el1->stmt->lineNumber());
|
||||
else
|
||||
printf("(id = -, line = -, ");
|
||||
if (ex1->symbol())
|
||||
printf("%s", ex1->symbol()->identifier());
|
||||
else
|
||||
ex1->unparsestdout();
|
||||
printf(")");
|
||||
printf(",");
|
||||
}
|
||||
|
||||
//
|
||||
// Example of function to compute gen and kill sets for Reaching Definition.
|
||||
// NOARRAYREF indicate if we want array ref in
|
||||
|
||||
Set *makeGenSet(SgStatement *func, SgStatement *stmt)
|
||||
{
|
||||
SgExpression *def, *use, *pt;
|
||||
PT_ELSET el;
|
||||
Set *defset, *pts;
|
||||
|
||||
if (!func || !stmt)
|
||||
return NULL;
|
||||
|
||||
def = (SgExpression *)stmt->attributeValue(0, DEFINEDLIST_ATTRIBUTE);
|
||||
// Defined[stmt->id()];
|
||||
defset = new Set(symbRefEqual, NULL, myPrint);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, defset, 1);
|
||||
#endif
|
||||
if (def)
|
||||
{
|
||||
for (pt = def; pt; pt = pt->rhs())
|
||||
{
|
||||
if (!isSgTypeExp(pt->lhs()))
|
||||
{
|
||||
if (!NOARRAYREF || !isSgArrayRefExp(pt->lhs()))
|
||||
{
|
||||
el = new struct elset;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, el, 1);
|
||||
#endif
|
||||
el->stmt = stmt;
|
||||
el->expr = pt->lhs();
|
||||
defset->addElement((void *)el);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pts = defset;
|
||||
// printf("Printing defset:\n");
|
||||
// defset->printSet();
|
||||
defset = defset->compact();
|
||||
if (pts)
|
||||
{
|
||||
#ifdef __SPF
|
||||
removeFromCollection(pts);
|
||||
#endif
|
||||
delete pts;
|
||||
}
|
||||
// defset->printSet();
|
||||
return defset;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Set *makeKillSet(SgStatement *func, SgStatement *stmt)
|
||||
{
|
||||
|
||||
SgExpression *def, *use, *pt, *defstmt, *expr1, *pt1;
|
||||
PT_ELSET el;
|
||||
Set *killset, *pts;
|
||||
SgStatement *last, *first, *lastfunc, *temp;
|
||||
int trouve;
|
||||
if (!func || !stmt)
|
||||
return NULL;
|
||||
|
||||
killset = new Set(symbRefEqual, NULL, myPrint);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, killset, 1);
|
||||
#endif
|
||||
last = func->lastNodeOfStmt();
|
||||
defstmt = (SgExpression *)stmt->attributeValue(0, DEFINEDLIST_ATTRIBUTE);
|
||||
//Defined[stmt->id()];
|
||||
if (defstmt)
|
||||
{
|
||||
for (pt1 = defstmt; pt1; pt1 = pt1->rhs())
|
||||
{
|
||||
expr1 = pt1->lhs();
|
||||
if (!isSgArrayRefExp(expr1) && !isSgTypeExp(expr1))
|
||||
{ // cannot kill an array ref;
|
||||
for (temp = func; temp; temp = temp->lexNext())
|
||||
{
|
||||
if (temp != stmt)
|
||||
{
|
||||
if (def = (SgExpression *)temp->attributeValue(0, DEFINEDLIST_ATTRIBUTE))
|
||||
//Defined[temp->id()])
|
||||
{
|
||||
for (pt = def; pt; pt = pt->rhs())
|
||||
{
|
||||
if (pt->lhs())
|
||||
{
|
||||
if (pt->lhs()->symbol() == expr1->symbol())
|
||||
{
|
||||
el = new struct elset;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, el, 1);
|
||||
#endif
|
||||
el->stmt = temp;
|
||||
el->expr = pt->lhs();
|
||||
killset->addElement((void *)el);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (temp == last)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pts = killset;
|
||||
// printf("Printing killset:\n");
|
||||
// killset->printSet();
|
||||
killset = killset->compact();
|
||||
// killset->printSet();
|
||||
if (pts)
|
||||
{
|
||||
#ifdef __SPF
|
||||
removeFromCollection(pts);
|
||||
#endif
|
||||
delete pts;
|
||||
}
|
||||
return killset;
|
||||
}
|
||||
66
Sapfor/_src/SageAnalysisTool/definesValues.h
Normal file
66
Sapfor/_src/SageAnalysisTool/definesValues.h
Normal file
@@ -0,0 +1,66 @@
|
||||
|
||||
// set of the defined values used for the data dependence analsysis;
|
||||
// for most of the files
|
||||
|
||||
#define MAXITDATAFLOW 100
|
||||
// needs to be bigger than real loop, symbols may appear twice.
|
||||
#define MAXNESTEDLOOP 40
|
||||
#define MAXDIMARRAY 7
|
||||
#define MAXP 100
|
||||
#define MAXNODE 10000
|
||||
#define NOARRAYREF 0
|
||||
#define NO_STEP 10000
|
||||
|
||||
|
||||
//constanteSet.C
|
||||
#define UNDEFFLAG 1
|
||||
#define NONCONSTFLAG 2
|
||||
#define CONSTFLAG 3
|
||||
|
||||
//depGraph.C
|
||||
#define WRONGDEP 0
|
||||
#define ARRAYDEP 1
|
||||
#define PRIVATEDEP 2
|
||||
#define REDUCTIONDEP 3
|
||||
#define SCALARDEP 4
|
||||
#define DEPZERO 1
|
||||
#define DEPGREATER 2
|
||||
#define DEPLESS 4
|
||||
|
||||
//dependence.C
|
||||
#define OUTDEP 1
|
||||
#define FLOWDEP 2
|
||||
#define ANTIDEP 3
|
||||
#define UNKNOWNDEP 4
|
||||
|
||||
//reductionCode.C
|
||||
#define UNKNOWREDUCTION 0
|
||||
//SUM
|
||||
#define SADDREDUCTION 2
|
||||
#define DADDREDUCTION 3
|
||||
#define IADDREDUCTION 4
|
||||
//MULT
|
||||
#define SMULREDUCTION 5
|
||||
#define DMULREDUCTION 6
|
||||
#define IMULREDUCTION 7
|
||||
//DIV
|
||||
#define SDIVREDUCTION 8
|
||||
#define DDIVREDUCTION 9
|
||||
#define IDIVREDUCTION 10
|
||||
//MAX
|
||||
#define SMAXREDUCTION 11
|
||||
#define DMAXREDUCTION 12
|
||||
#define IMAXREDUCTION 13
|
||||
//MIN
|
||||
#define SMINREDUCTION 14
|
||||
#define DMINREDUCTION 15
|
||||
#define IMINREDUCTION 16
|
||||
//LOGICAL
|
||||
#define ANDREDUCTION 17
|
||||
#define ORREDUCTION 18
|
||||
#define EQVREDUCTION 19
|
||||
#define NEQVREDUCTION 20
|
||||
|
||||
// set.C
|
||||
#define MAXELEMENT 10000000
|
||||
#define ALLOCATECHUNKSET 10000
|
||||
10
Sapfor/_src/SageAnalysisTool/definitionSet.h
Normal file
10
Sapfor/_src/SageAnalysisTool/definitionSet.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
struct elset
|
||||
{
|
||||
SgStatement *stmt;
|
||||
SgExpression *expr;
|
||||
};
|
||||
|
||||
typedef struct elset *PT_ELSET;
|
||||
|
||||
1387
Sapfor/_src/SageAnalysisTool/depGraph.cpp
Normal file
1387
Sapfor/_src/SageAnalysisTool/depGraph.cpp
Normal file
File diff suppressed because it is too large
Load Diff
73
Sapfor/_src/SageAnalysisTool/depGraph.h
Normal file
73
Sapfor/_src/SageAnalysisTool/depGraph.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "set.h"
|
||||
////////////////////////////////////////////////////////////
|
||||
// to deal with data dep, scalar are considered apart
|
||||
// but included as special nodes in the dep grap...
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// class dep graph used for restructuring
|
||||
// two classes, the graph and the graph node
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
class depNode {
|
||||
public:
|
||||
SgStatement *stmtin;
|
||||
SgStatement *stmtout;
|
||||
SgExpression *varin; // this is var;
|
||||
SgExpression *varout; // this is var;
|
||||
int typedep; // WRONGDEP something wrong happend, ARRAYDEP array dependence, > 1 SCALAR DEP
|
||||
int kinddep; // ddflow, ddanti, ddoutput
|
||||
int lenghtvect;
|
||||
std::vector<signed short> distance;
|
||||
std::vector<signed short> knowndist;
|
||||
|
||||
depNode(SgStatement *sin,SgStatement *sout, SgExpression *vin, SgExpression *vout, int tdep, int kdep, int *dist, int *kdist, int le);
|
||||
~depNode();
|
||||
void displayDep(bool onlyDifferentLines) const;
|
||||
std::string displayDepToStr() const;
|
||||
std::pair<std::string, std::string> createDepMessagebetweenArrays() const;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// The graph is represented by
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
class depGraph {
|
||||
std::vector<depNode*> nodes;
|
||||
public:
|
||||
const std::set<std::string> privVars;
|
||||
SgFile *file;
|
||||
Set *arrayRef;
|
||||
Set *induc;
|
||||
SgSymbol *tsymb[40/*MAXNESTEDLOOP*/];
|
||||
int loopnum;
|
||||
SgStatement *func;
|
||||
SgStatement *loop;
|
||||
int perfectNestedLevel;
|
||||
int nbstmt;
|
||||
SgStatement **tabstat;
|
||||
int *tabtag;
|
||||
depGraph(SgFile *fi, SgStatement *f, SgStatement *l, const std::set<std::string> &privVars);
|
||||
~depGraph();
|
||||
void addAnEdge(SgStatement *sin, SgStatement *sout, SgExpression *vin, SgExpression *vout, int tdep, int kdep, int *dist, int *kdist, int le);
|
||||
|
||||
void display(bool onlyDifferentLines = false);
|
||||
void scalarRefAnalysis(SgStatement *loop);
|
||||
void redoScalarRefAnalysis(SgStatement *loop);
|
||||
depNode *firstNode();
|
||||
int isLoopCarryingTheDep(SgStatement *loop, depNode *node);
|
||||
depNode *isThereAnEdge(SgStatement *s1, SgStatement *s2);
|
||||
int isThereAnEdgeSCC(SgStatement *s1, SgStatement *s2, SgStatement *doloop);
|
||||
void depthTraversal(int stmtid, SgStatement *doloop);
|
||||
int getHigherMark();
|
||||
int getZeroMark();
|
||||
int computeSCC(SgStatement *stmtin);
|
||||
const std::vector<depNode*>& getNodes() const;
|
||||
// ... much more here
|
||||
};
|
||||
291
Sapfor/_src/SageAnalysisTool/depInterface.cpp
Normal file
291
Sapfor/_src/SageAnalysisTool/depInterface.cpp
Normal file
@@ -0,0 +1,291 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////// Interface for data dependence analysis using the attributes mechanisn///////////
|
||||
///// FB. July 94 Indiana University ///////////////////////////////////////////////////
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "sage++user.h"
|
||||
#include "depInterfaceExt.h"
|
||||
|
||||
//////////////////////////////////// A set of routines for interfacing the dep analysis //////////////////////////////////
|
||||
|
||||
static int initializeTheAnnotationSystem = 1;
|
||||
|
||||
void initAnnotationsSysExt(const int printannotation)
|
||||
{
|
||||
if (initializeTheAnnotationSystem)
|
||||
{
|
||||
if (printannotation)
|
||||
initAnnotationSystem(1);
|
||||
else
|
||||
initAnnotationSystem(0);
|
||||
initializeTheAnnotationSystem = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void doDependenceAnalysisOnTheFullFile(SgFile *file, int printdep, int printannotation, int verbose)
|
||||
{
|
||||
SgForStmt *doloop;
|
||||
int i, j, nbfunc;
|
||||
SgStatement *func, *temp, *last;
|
||||
depGraph *depg;
|
||||
depNode *datadep;
|
||||
int nbatt, typeat;
|
||||
|
||||
if (!file)
|
||||
return;
|
||||
initAnnotationsSysExt(printannotation);
|
||||
|
||||
// delete the attributes first;
|
||||
nbfunc = file->numberOfFunctions();
|
||||
for (i = 0; i < nbfunc; i++)
|
||||
{
|
||||
func = file->functions(i);
|
||||
if (func)
|
||||
{
|
||||
last = func->lastNodeOfStmt();
|
||||
for (temp = func; temp && (temp != last); temp = temp->lexNext())
|
||||
{
|
||||
nbatt = temp->numberOfAttributes();
|
||||
for (j = 0; j < nbatt; j++)
|
||||
{
|
||||
typeat = temp->attributeType(j);
|
||||
if ((typeat == DEPGRAPH_ATTRIBUTE) ||
|
||||
(typeat == INDUCTION_ATTRIBUTE) ||
|
||||
(typeat == ACCESS_ATTRIBUTE) ||
|
||||
(typeat == DEPENDENCE_ATTRIBUTE))
|
||||
{
|
||||
temp->deleteAttribute(j);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nbfunc = file->numberOfFunctions();
|
||||
for (i = 0; i < nbfunc; i++)
|
||||
{
|
||||
func = file->functions(i);
|
||||
doDependenceAnalysisForAFunction(file, func, printdep, printannotation, verbose);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void doDependenceAnalysisForAFunction(SgFile *file, SgStatement *func, int printdep, int printannotation, int verbose)
|
||||
{
|
||||
SgForStmt *doloop;
|
||||
int i, j, nbfunc;
|
||||
SgStatement *temp, *last;
|
||||
depGraph *depg;
|
||||
depNode *datadep;
|
||||
int nbatt, typeat;
|
||||
|
||||
if (!file || !func)
|
||||
return;
|
||||
initAnnotationsSysExt(printannotation);
|
||||
|
||||
last = func->lastNodeOfStmt();
|
||||
for (temp = func; temp && (temp != last); temp = temp->lexNext())
|
||||
{
|
||||
nbatt = temp->numberOfAttributes();
|
||||
for (j = 0; j < nbatt; j++)
|
||||
{
|
||||
typeat = temp->attributeType(j);
|
||||
if ((typeat == DEPGRAPH_ATTRIBUTE) ||
|
||||
(typeat == INDUCTION_ATTRIBUTE) ||
|
||||
(typeat == ACCESS_ATTRIBUTE) ||
|
||||
(typeat == DEPENDENCE_ATTRIBUTE))
|
||||
{
|
||||
temp->deleteAttribute(j);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf(" -init dependence for function %s\n", func->symbol()->identifier());
|
||||
|
||||
//!!!!!!
|
||||
//TODO: add allFuncs if needed, now it does not work!
|
||||
throw(-991);
|
||||
//initializeDepAnalysisForFunction(file, func);
|
||||
|
||||
//!!!!!!
|
||||
|
||||
// now compute the dependence graph for each loop;
|
||||
last = func->lastNodeOfStmt();
|
||||
for (temp = func; temp && (temp != last); temp = temp->lexNext())
|
||||
{
|
||||
if (doloop = isSgForStmt(temp))
|
||||
{
|
||||
depg = new depGraph(file, func, temp, std::set<std::string>());
|
||||
if (depg)
|
||||
{
|
||||
if (printdep)
|
||||
depg->display();
|
||||
|
||||
const std::vector<depNode*> &nodes = depg->getNodes();
|
||||
|
||||
//printf("data dep for loop on line %d is = %d\n", doloop->lineNumber(), nodes.size());
|
||||
// add the attributes here;
|
||||
/*doloop->addAttribute(DEPGRAPH_ATTRIBUTE, (void *)depg, 0);
|
||||
doloop->addAttribute(INDUCTION_ATTRIBUTE, (void *)depg->induc, 0);
|
||||
doloop->addAttribute(ACCESS_ATTRIBUTE, (void *)depg->arrayRef, 0);
|
||||
|
||||
const std::vector<depNode*> &nodes = depg->getNodes();
|
||||
for (int i = 0; i < nodes.size(); ++i)
|
||||
{
|
||||
datadep = nodes[i];
|
||||
doloop->addAttribute(DEPENDENCE_ATTRIBUTE, (void *)datadep, 0);
|
||||
}*/
|
||||
|
||||
//TODO: save needed info
|
||||
delete depg;
|
||||
}
|
||||
else
|
||||
if (verbose)
|
||||
Message("no data dependence graph found", temp->lineNumber());
|
||||
// skip the loop;
|
||||
temp = doloop->lastNodeOfStmt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Look in the subroutine if there is equivalence statement (drop it if yes for now)
|
||||
//
|
||||
|
||||
int isThereEquivalenceStatement(SgStatement *func)
|
||||
{
|
||||
SgStatement *temp, *last;
|
||||
|
||||
if (!func)
|
||||
return FALSE;
|
||||
|
||||
last = func->lastNodeOfStmt();
|
||||
for (temp = func; temp && (temp != last); temp = temp->lexNext())
|
||||
{
|
||||
if (EQUI_STAT == temp->variant())
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int isWriteToSymbolInStatement(SgSymbol *symb, SgStatement *loop, depGraph *depg)
|
||||
{
|
||||
int i;
|
||||
PT_ACCESSARRAY access1;
|
||||
|
||||
for (i = 0; i < depg->arrayRef->size(); i++)
|
||||
{
|
||||
access1 = (PT_ACCESSARRAY)depg->arrayRef->getElement(i);
|
||||
if (loop->isIncludedInStmt(*(access1->stmt)))
|
||||
{
|
||||
if (access1 && access1->scalar && access1->rw)
|
||||
{
|
||||
if (access1->var->symbol() == symb)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// take a data dep and return the first dimension with a non zero distance
|
||||
//
|
||||
|
||||
int leadingDimension(depNode *datadep, int entryLevel)
|
||||
{
|
||||
int i, j;
|
||||
int carried;
|
||||
if (!datadep)
|
||||
return 0;
|
||||
|
||||
|
||||
if (datadep->typedep == ARRAYDEP)
|
||||
{
|
||||
if (entryLevel)
|
||||
{ // check that the dependence is not carried by the outer loops first
|
||||
for (i = 1; (i <= datadep->lenghtvect) && (i <= entryLevel); i++)
|
||||
{
|
||||
if (datadep->knowndist[i])
|
||||
{
|
||||
if (datadep->distance[i] != 0)
|
||||
{
|
||||
return datadep->lenghtvect;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(datadep->distance[i] & DEPZERO))
|
||||
{
|
||||
return datadep->lenghtvect;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 1 + entryLevel; i <= datadep->lenghtvect; i++)
|
||||
{
|
||||
if (datadep->knowndist[i])
|
||||
{
|
||||
if (datadep->distance[i] != 0)
|
||||
{
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((datadep->distance[i] & DEPGREATER) ||
|
||||
(datadep->distance[i] & DEPLESS))
|
||||
{
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return datadep->lenghtvect;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int numberOfOuterParallelLoops(SgStatement *loop, depGraph *depg, int entryLevel)
|
||||
{
|
||||
depNode *datadep;
|
||||
int Min, t;
|
||||
|
||||
if (!loop)
|
||||
return 0;
|
||||
Min = MAXNESTEDLOOP;
|
||||
|
||||
const std::vector<depNode*> &nodes = depg->getNodes();
|
||||
for (int i = 0; i < nodes.size(); ++i)
|
||||
{
|
||||
datadep = nodes[i];
|
||||
if (datadep->typedep == ARRAYDEP)
|
||||
{
|
||||
// source and sink must be included in the loop;
|
||||
if (datadep->stmtin && datadep->stmtout &&
|
||||
loop->isIncludedInStmt(*(datadep->stmtin)) &&
|
||||
loop->isIncludedInStmt(*(datadep->stmtout)))
|
||||
{
|
||||
t = leadingDimension(datadep, entryLevel);
|
||||
if (t < Min)
|
||||
Min = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Min - entryLevel;
|
||||
}
|
||||
|
||||
|
||||
134
Sapfor/_src/SageAnalysisTool/depInterface.h
Normal file
134
Sapfor/_src/SageAnalysisTool/depInterface.h
Normal file
@@ -0,0 +1,134 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////// includes for data dep information ////////////////////////
|
||||
////// FB July 94 Indiana University ///////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// the set class
|
||||
#include "set.h"
|
||||
|
||||
#include "definesValues.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// external for the anotation system
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
#include "annotationDriver.h"
|
||||
extern SgAnnotation *getTheAnnotationThatApply(SgStatement *stmt, char *kind);
|
||||
extern SgAnnotation * getTheAnnotationWithString(char *kind);
|
||||
extern int isAnnotationWithString(SgStatement *stmt, char *kind, int len);
|
||||
extern void initAnnotationSystem(int printann);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// some external from loop transformations
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern int tileLoops(SgStatement *func, SgStatement *b, int *size, int nb);
|
||||
extern int distributeLoopSCC(SgStatement *b, int *sccTable, int leadingdim, int numSCC);
|
||||
extern int loopFusion(SgStatement *loop1,SgStatement *loop2);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Control FLOW part of declaration
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern void controlFlow(SgStatement *stmt, SgStatement *func,
|
||||
SgStatement **pred, SgStatement **suc,
|
||||
int *predin,int *sucint);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// declaration for the data flow framework
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern Set *genSet[MAXNODE];
|
||||
extern Set *killSet[MAXNODE];
|
||||
extern Set *inSet[MAXNODE];
|
||||
extern Set *outSet[MAXNODE];
|
||||
|
||||
extern void iterativeForwardFlowAnalysis(SgFile *file,
|
||||
SgStatement *func,
|
||||
Set *(*giveGenSet)(SgStatement *func,SgStatement *stmt),
|
||||
Set *(*giveKillSet)(SgStatement *func,SgStatement *stmt),
|
||||
int (*feq)(void *e1, void *e2),
|
||||
void *(*fcomb)(void *e1, void *e2),
|
||||
void (*fp)(void *e1));
|
||||
|
||||
extern void generalIterativeFlowAnalysis(SgFile *file,
|
||||
SgStatement *func,
|
||||
Set *(*transfertSet)(SgStatement *func,SgStatement *stmt, Set *setin),
|
||||
int (*feq)(void *e1, void *e2),
|
||||
void* (*fcomb)(void *e1, void *e2),
|
||||
void (*fp)(void *e1));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// declaration for defuse and reaching definition
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "definitionSet.h"
|
||||
extern Set *makeGenSet(SgStatement *func,SgStatement *stmt);
|
||||
extern Set *makeKillSet(SgStatement *func,SgStatement *stmt);
|
||||
extern int symbRefEqual(void *e1, void *e2);
|
||||
extern void myPrint(void *e1);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Part for constante propagation.....
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "constanteSet.h"
|
||||
extern int constPropEqual(void *e1, void *e2);
|
||||
extern void constPropPrint(void *e1);
|
||||
extern void * constPropCombine(void *e1, void *e2);
|
||||
extern Set *transConstante(SgStatement *func,SgStatement *stmt, Set *setin);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Part for induction variable
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "inducVar.h"
|
||||
extern int inducVarEqual(void *e1, void *e2);
|
||||
extern void inducVarPrint(void *e1);
|
||||
extern int definitionInStmt(SgStatement *func,SgStatement *stmtin, SgExpression *defvar);
|
||||
extern Set *computeConstanteInStmt(SgStatement *func,SgStatement *stmtin);
|
||||
extern Set *computeInductionVariables(SgStatement *func,SgStatement *stmt);
|
||||
extern Set *getAllInductionVar(SgStatement *func,
|
||||
SgStatement *stmt,int level, int *num,int include);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Part for computing array reference
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "arrayRef.h"
|
||||
extern int NbLinearRef;
|
||||
extern int NbNonLinearRef;
|
||||
extern int linearRepArray(SgExpression *ex1, SgSymbol **symb,
|
||||
int size,
|
||||
int linear[MAXDIMARRAY][MAXNESTEDLOOP],
|
||||
int *cst);
|
||||
extern int arrayEqual(void *e1, void *e2);
|
||||
extern void arrayPrint(void *e1);
|
||||
extern Set *loopArrayAccessAnalysis(SgStatement *func,SgStatement *stmt,
|
||||
SgSymbol **tsymb, Set **induc);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// for data dependence computation (uses omega Test)
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "dependence.h"
|
||||
extern Set *computeLoopDependencies(SgStatement *func,Set *inset, SgSymbol **tsymb, Set *induc);
|
||||
extern "C" void SetOmegaDebug();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// for data dependence computation (uses omega Test)
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "depGraph.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// from intrinsic.C
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern int isStmtCallToFuncNotIntrinsic(SgStatement *stmt);
|
||||
extern int isSymbolIntrinsic(SgSymbol *symb);
|
||||
extern int isExprCallToFuncNotIntrinsic(SgExpression *exp);
|
||||
|
||||
|
||||
|
||||
14
Sapfor/_src/SageAnalysisTool/depInterfaceExt.h
Normal file
14
Sapfor/_src/SageAnalysisTool/depInterfaceExt.h
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
/////////////////// TO BE INCLUDED FOR USING DATA DEPENDENCE ///////////////////////
|
||||
|
||||
#include "depInterface.h"
|
||||
|
||||
// initialize for a full file;
|
||||
|
||||
extern void doDependenceAnalysisOnTheFullFile(SgFile *file, int printdep, int printannotation, int verbose);
|
||||
extern void doDependenceAnalysisForAFunction(SgFile *file, SgStatement *func, int printdep, int printannotation, int verbose);
|
||||
extern int isThereEquivalenceStatement(SgStatement *func);
|
||||
extern int isWriteToSymbolInStatement(SgSymbol *symb, SgStatement *loop, depGraph *depg);
|
||||
extern int leadingDimension(depNode *datadep,int entryLevel);
|
||||
extern int numberOfOuterParallelLoops(SgStatement *loop, depGraph *depg,int entryLevel);
|
||||
extern void initAnnotationsSysExt(const int printannotation);
|
||||
758
Sapfor/_src/SageAnalysisTool/dependence.cpp
Normal file
758
Sapfor/_src/SageAnalysisTool/dependence.cpp
Normal file
@@ -0,0 +1,758 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __SPF
|
||||
extern "C" void addToCollection(const int line, const char *file, void *pointer, int type);
|
||||
extern "C" void removeFromCollection(void *pointer);
|
||||
#endif
|
||||
|
||||
#if __SPF && NDEBUG && __BOOST
|
||||
#include <boost/thread.hpp>
|
||||
#endif
|
||||
extern int passDone;
|
||||
|
||||
#include "sage++user.h"
|
||||
#include "definesValues.h"
|
||||
#include "set.h"
|
||||
#include "definitionSet.h"
|
||||
#include "inducVar.h"
|
||||
|
||||
#include "arrayRef.h"
|
||||
#include "dependence.h"
|
||||
|
||||
/* to link with the omega Test */
|
||||
#include "OmegaForSage/include/portable.h"
|
||||
#include "OmegaForSage/include/affine.h"
|
||||
|
||||
extern void SetSTuff();
|
||||
extern "C" void SetOmegaDebug();
|
||||
extern "C" void initAnnotation();
|
||||
extern "C" void Look_For_Align_Declaration();
|
||||
extern void dd_omega_test(a_access access1, a_access access2, ddnature oitype, ddnature iotype, uint nest1, uint nest2, uint bnest);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Some global declaration
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SgStatement *currentStmtIn = NULL;
|
||||
SgStatement *currentStmtOut = NULL;
|
||||
SgExpression *currentVarIn = NULL;
|
||||
SgExpression *currentVarOut = NULL;
|
||||
int WarningOutForNegativeStep = 0;
|
||||
int TurnIfConstructionOf = 0;
|
||||
|
||||
// Kolganov A.S. 31.07.2017
|
||||
// try to process loop with negative step: inverse the iteration space
|
||||
#define PROCESS_LOOPS_WITH_NEG_STEP 1
|
||||
|
||||
// Needs to provide dummy function
|
||||
int dummyEqual(void *e1, void *e2)
|
||||
{
|
||||
return (e1 == e2);
|
||||
}
|
||||
|
||||
void dummyPrint(void *e1)
|
||||
{
|
||||
printf("Dummy print\n");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// comming from depGraph.c
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
#include "depGraph.h"
|
||||
#include "../VisualizerCalls/get_information.h"
|
||||
extern depGraph *currentDepGraph;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// here we call the omega test routine.... First some routine to do the job
|
||||
// compute the data dependencies using the Omega Test....
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
affine_expr *makeOmegaAffine(int size, var_id *induc, int *linear, int cst, int notaffine, Set *setForDealocatingMemory)
|
||||
{
|
||||
int i, finalsize;
|
||||
affine_expr *ptaff, *init;
|
||||
if (!induc || !linear)
|
||||
return ¬_affine;
|
||||
if (!notaffine)
|
||||
return ¬_affine;
|
||||
if (WarningOutForNegativeStep)
|
||||
return ¬_affine;
|
||||
ptaff = new affine_expr;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, ptaff, 1);
|
||||
#endif
|
||||
setForDealocatingMemory->addElement((void *)ptaff);
|
||||
ptaff->nterms = size + 1;
|
||||
ptaff->other_branch = NULL;
|
||||
(ptaff->terms[0]).tiny_var = NULL;
|
||||
(ptaff->terms[0]).coefficient = cst;
|
||||
if (size >= maxVars)
|
||||
{
|
||||
Message("Too many variable in makeOmegaAffine\n");
|
||||
return NULL;
|
||||
}
|
||||
finalsize = 0;
|
||||
for (i = 1; i <= size; i++)
|
||||
{
|
||||
if (linear[i - 1] != 0)
|
||||
{
|
||||
finalsize++;
|
||||
(ptaff->terms[finalsize]).tiny_var = induc[i - 1];
|
||||
(ptaff->terms[finalsize]).coefficient = linear[i - 1];
|
||||
}
|
||||
}
|
||||
ptaff->nterms = finalsize + 1;
|
||||
return ptaff;
|
||||
}
|
||||
|
||||
int fillOmegaAccess(PT_ACCESSARRAY el1, a_access access1, const Set *induc, var_id *inducom,
|
||||
context_iterator firstcontiter, char *name, int inif, Set *setForDealocatingMemory)
|
||||
{
|
||||
int i, j;
|
||||
sub_iterator itern = NULL;
|
||||
sub_iterator firstiter;
|
||||
PT_INDUCVAR ind, cur;
|
||||
firstiter = NULL;
|
||||
for (j = 0; j < el1->nbdim; j++)
|
||||
{
|
||||
if (firstiter)
|
||||
{
|
||||
itern->next = new struct omegaIterator;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, itern->next, 1);
|
||||
#endif
|
||||
setForDealocatingMemory->addElement((void *)itern->next);
|
||||
itern = itern->next;
|
||||
itern->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
itern = new struct omegaIterator;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, itern, 1);
|
||||
#endif
|
||||
setForDealocatingMemory->addElement((void *)itern);
|
||||
firstiter = itern;
|
||||
itern->next = NULL;
|
||||
}
|
||||
if (el1->isLinear[j] && !el1->scalar)
|
||||
{
|
||||
itern->isaffine = TRUE;
|
||||
itern->affine = makeOmegaAffine(induc->size(), inducom, el1->linear[j], el1->cst[j], el1->isLinear[j], setForDealocatingMemory);
|
||||
}
|
||||
else
|
||||
{
|
||||
itern->isaffine = FALSE;
|
||||
itern->affine = ¬_affine;
|
||||
}
|
||||
itern->cstvalue = 0;
|
||||
itern->constante = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
access1->str = new char[256];
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, access1->str, 2);
|
||||
#endif
|
||||
setForDealocatingMemory->addElement((void *)access1->str);
|
||||
strcpy(access1->str, name);
|
||||
access1->symb = NULL;
|
||||
access1->subiter = firstiter;
|
||||
access1->context = firstcontiter;
|
||||
access1->line = el1->stmt->lineNumber();
|
||||
access1->cdepth = -1;
|
||||
access1->tdepth = -1;
|
||||
access1->idforsage = el1->var->id();
|
||||
access1->inIfStmt = inif;
|
||||
// look at for the level;
|
||||
cur = NULL;
|
||||
for (j = 0; j < induc->size(); j++)
|
||||
{
|
||||
ind = (PT_INDUCVAR)induc->getElement(j);
|
||||
if (ind && (ind->loopnum == el1->level))
|
||||
{
|
||||
cur = ind;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cur)
|
||||
{
|
||||
access1->depth = cur->level;
|
||||
}
|
||||
else
|
||||
access1->depth = 0;
|
||||
access1->pri = 0;
|
||||
access1->level = el1->level; // temporary setting;
|
||||
if (el1->rw)
|
||||
{
|
||||
access1->fetch = FALSE;
|
||||
access1->store = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
access1->fetch = TRUE;
|
||||
access1->store = FALSE;
|
||||
}
|
||||
access1->update = 0;
|
||||
access1->lexord = 1; // temporary setting;
|
||||
return access1->depth;
|
||||
}
|
||||
|
||||
|
||||
// answer yes if el1 >> el2; to be optimize by checking procedure control_end
|
||||
int lexOrder(PT_ACCESSARRAY el1, PT_ACCESSARRAY el2)
|
||||
{
|
||||
SgStatement *stmt;
|
||||
if (!el1 || !el2)
|
||||
return FALSE;
|
||||
if (el1->stmt == el2->stmt)
|
||||
return FALSE;
|
||||
if (!el1->stmt || !el2->stmt)
|
||||
return FALSE;
|
||||
stmt = el1->stmt;
|
||||
while (stmt)
|
||||
{
|
||||
if (stmt == el2->stmt)
|
||||
return TRUE;
|
||||
stmt = stmt->lexNext();
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
context_iterator makeOmegaIf(int depth, SgStatement *stmt, context_iterator next, int brelse, Set *setForDealocatingMemory)
|
||||
{
|
||||
if_context ifstat;
|
||||
context_iterator contiter;
|
||||
|
||||
if (!stmt)
|
||||
return NULL;
|
||||
// dealing with the conditions later...
|
||||
contiter = new struct omegaContIter;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, contiter, 1);
|
||||
#endif
|
||||
setForDealocatingMemory->addElement((void *)contiter);
|
||||
contiter->next = next;
|
||||
contiter->depth = depth;
|
||||
contiter->loopiter = FALSE;
|
||||
contiter->line = stmt->lineNumber();
|
||||
contiter->loop = NULL;
|
||||
ifstat = new struct omegaIf;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, ifstat, 1);
|
||||
#endif
|
||||
setForDealocatingMemory->addElement((void *)ifstat);
|
||||
ifstat->oper = greater_eq;
|
||||
ifstat->ident = stmt->id();
|
||||
ifstat->left = ¬_affine;
|
||||
ifstat->right = ¬_affine;
|
||||
ifstat->condOK = FALSE;
|
||||
ifstat->partelse = brelse;
|
||||
contiter->ifstmt = ifstat;
|
||||
return contiter;
|
||||
}
|
||||
|
||||
// try to manage non nested loops;;;
|
||||
context_iterator fillOmegaLoop(PT_ACCESSARRAY el1, const Set *induc, var_id *inducom, SgSymbol **tsymb, int *inif, Set *setForDealocatingMemory)
|
||||
{
|
||||
int i, j, inbrelse, k;
|
||||
PT_INDUCVAR ind, cur;
|
||||
context_iterator contiter, firstcontiter;
|
||||
loop_context loop;
|
||||
if_context ifstat;
|
||||
int linear[MAXNESTEDLOOP];
|
||||
int cst, loopnum, curnum;
|
||||
var_id tempvar;
|
||||
SgExpression *step;
|
||||
SgForStmt *stloop;
|
||||
SgStatement *currentstmt, *cp, *tmp;
|
||||
|
||||
if (!el1 || !induc || !tsymb)
|
||||
return NULL;
|
||||
// look for the induction variable corresponding to the loop...;
|
||||
// examine for duplicate symbols first so the linear loop bounds are set right;
|
||||
loopnum = el1->level;
|
||||
while (loopnum != -1)
|
||||
{
|
||||
cur = NULL;
|
||||
for (j = 0; j < induc->size(); j++)
|
||||
{
|
||||
ind = (PT_INDUCVAR)induc->getElement(j);
|
||||
if (ind && (!ind->constante) && (ind->loopnum == loopnum))
|
||||
{
|
||||
cur = ind;
|
||||
// check if there is multiple uses of the same variable;
|
||||
// to set curnum to the righ symbol;
|
||||
// the first one has to be taken;
|
||||
// this is related to the linear expression;
|
||||
for (k = 0; k < j; k++)
|
||||
{
|
||||
ind = (PT_INDUCVAR)induc->getElement(k);
|
||||
if (ind->var->symbol() == cur->var->symbol())
|
||||
{
|
||||
// switch the position in inducom so the;
|
||||
// linear expression for the loops bound are right;
|
||||
tempvar = inducom[k];
|
||||
inducom[k] = inducom[j];
|
||||
inducom[j] = tempvar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!cur)
|
||||
break;
|
||||
loopnum = cur->include;
|
||||
}
|
||||
loopnum = el1->level;
|
||||
firstcontiter = NULL;
|
||||
contiter = NULL;
|
||||
curnum = -1;
|
||||
currentstmt = el1->stmt;
|
||||
*inif = FALSE;
|
||||
while (loopnum != -1)
|
||||
{
|
||||
cur = NULL;
|
||||
for (j = 0; j < induc->size(); j++)
|
||||
{
|
||||
ind = (PT_INDUCVAR)induc->getElement(j);
|
||||
if (ind && (!ind->constante) && (ind->loopnum == loopnum))
|
||||
{
|
||||
cur = ind;
|
||||
curnum = j;
|
||||
// check if there is multiple uses of the same variable;
|
||||
// to set curnum to the righ symbol;
|
||||
// the first one has to be taken;
|
||||
// this is related to the linear expression;
|
||||
for (k = 0; k < j; k++)
|
||||
{
|
||||
ind = (PT_INDUCVAR)induc->getElement(k);
|
||||
if (ind->var->symbol() == cur->var->symbol())
|
||||
{
|
||||
curnum = k; // position has been switch before;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cur)
|
||||
{
|
||||
if (TurnIfConstructionOf)
|
||||
{
|
||||
// is in IF Statement; problems with the ELSE IF STUFF;
|
||||
if (currentstmt && currentstmt->controlParent() &&
|
||||
((currentstmt->controlParent()->variant() == IF_NODE) ||
|
||||
(currentstmt->controlParent()->variant() == ELSEIF_NODE)))
|
||||
{
|
||||
// which branch of the IF???;
|
||||
cp = currentstmt->controlParent();
|
||||
inbrelse = TRUE;
|
||||
if (!(currentstmt->controlParent()->variant() == ELSEIF_NODE))
|
||||
{
|
||||
for (i = 0; i < cp->numberOfChildrenList1(); i++)
|
||||
{
|
||||
tmp = cp->childList1(i);
|
||||
if (tmp == currentstmt)
|
||||
{
|
||||
inbrelse = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*inif = TRUE;
|
||||
firstcontiter = makeOmegaIf(cur->level, currentstmt->controlParent(), firstcontiter, inbrelse, setForDealocatingMemory);
|
||||
}
|
||||
}
|
||||
// end of if statement;
|
||||
}
|
||||
|
||||
|
||||
contiter = new struct omegaContIter;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, contiter, 1);
|
||||
#endif
|
||||
setForDealocatingMemory->addElement((void *)contiter);
|
||||
contiter->next = firstcontiter;
|
||||
firstcontiter = contiter;
|
||||
contiter->depth = cur->level;
|
||||
contiter->loopiter = TRUE;
|
||||
contiter->line = cur->stmt->lineNumber();
|
||||
currentstmt = cur->stmt;
|
||||
contiter->loop = new struct omegaLoop;
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, contiter->loop, 1);
|
||||
#endif
|
||||
setForDealocatingMemory->addElement((void *)contiter->loop);
|
||||
loop = contiter->loop;
|
||||
// for different non perfectly nested loop
|
||||
// the index variable must be the same, so there is a pb here;
|
||||
loop->symb = inducom[curnum];
|
||||
// build the linear rep ;
|
||||
cst = 0;
|
||||
for (i = 0; i < MAXNESTEDLOOP; i++)
|
||||
linear[i] = 0;
|
||||
if (cur->lbound->linearRepresentation(linear, tsymb, &cst, induc->size()))
|
||||
{
|
||||
loop->startl = makeOmegaAffine(induc->size(), inducom, linear, cst, 1, setForDealocatingMemory);
|
||||
}
|
||||
else
|
||||
{
|
||||
loop->startl = ¬_affine;
|
||||
// if (VeryVerbose)
|
||||
// Message("Non Linear Starting Bound of Loop",cur->stmt->lineNumber());
|
||||
}
|
||||
loop->cstvaluestart = 0;
|
||||
loop->constantestart = NULL;
|
||||
cst = 0;
|
||||
for (i = 0; i < MAXNESTEDLOOP; i++)
|
||||
linear[i] = 0;
|
||||
if (cur->ubound->linearRepresentation(linear, tsymb, &cst, induc->size()))
|
||||
{
|
||||
loop->endl = makeOmegaAffine(induc->size(), inducom, linear, cst, 1, setForDealocatingMemory);
|
||||
}
|
||||
else
|
||||
{
|
||||
loop->endl = ¬_affine;
|
||||
// if (VeryVerbose)
|
||||
// Message("Non Linear Ending Bound of Loop",cur->stmt->lineNumber());
|
||||
}
|
||||
|
||||
loop->cstvaluesend = 0;
|
||||
loop->constanteend = NULL;
|
||||
// deal with the step of the loop;
|
||||
if (stloop = isSgForStmt(cur->stmt))
|
||||
{
|
||||
if (step = stloop->step())
|
||||
{
|
||||
if (step->isInteger())
|
||||
{
|
||||
loop->hasstep = TRUE;
|
||||
loop->stepl = step->valueInteger();
|
||||
loop->knownstep = TRUE;
|
||||
if (loop->stepl < 0)
|
||||
{
|
||||
#if PROCESS_LOOPS_WITH_NEG_STEP
|
||||
loop->stepl = -loop->stepl;
|
||||
std::swap(loop->startl, loop->endl);
|
||||
#else
|
||||
loop->hasstep = FALSE;
|
||||
loop->stepl = 1;
|
||||
loop->knownstep = FALSE;
|
||||
|
||||
loop->startl = ¬_affine;
|
||||
loop->endl = ¬_affine;
|
||||
if (!WarningOutForNegativeStep)
|
||||
{
|
||||
Message("Negative Steps found: Ignored loop bounds", stloop->lineNumber());
|
||||
WarningOutForNegativeStep = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
loop->hasstep = FALSE;
|
||||
loop->stepl = 1;
|
||||
loop->knownstep = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
loop->hasstep = FALSE;
|
||||
loop->stepl = 1;
|
||||
loop->knownstep = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
loop->hasstep = FALSE;
|
||||
loop->stepl = 1;
|
||||
loop->knownstep = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
loopnum = cur->include;
|
||||
}
|
||||
return firstcontiter;
|
||||
}
|
||||
|
||||
int commonDepth(context_iterator iti1, context_iterator iti2)
|
||||
{
|
||||
context_iterator it1, it2;
|
||||
it1 = iti1;
|
||||
it2 = iti2;
|
||||
int depth = 0;
|
||||
while (!cont_i_done(it1) && !cont_i_done(it2))
|
||||
{
|
||||
if (cont_i_cur_loop_p(it1) && cont_i_cur_loop_p(it2))
|
||||
{
|
||||
if (loop_var_id(cont_i_cur_loop(it1)) != loop_var_id(cont_i_cur_loop(it2)))
|
||||
return depth;
|
||||
depth++;
|
||||
}
|
||||
// common depth does not go in If (I guess);
|
||||
// else
|
||||
// {
|
||||
// if (cont_i_cur_if_p(it1) && cont_i_cur_if_p(it2))
|
||||
// {
|
||||
// if (cont_i_cur_if(it1)->ident != cont_i_cur_if(it2)->ident)
|
||||
// return depth;
|
||||
// depth++;
|
||||
// }
|
||||
// }
|
||||
cont_i_next(it1);
|
||||
cont_i_next(it2);
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
//from dep_analyzer.cpp
|
||||
extern bool isRemovableDependence(const depNode *toCheck, const std::set<std::string> &privVars);
|
||||
|
||||
static int isDependent(PT_ACCESSARRAY el1, PT_ACCESSARRAY el2, const Set *induc, int &countOfNodes)
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// deallocation Set
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// in that set we store everything that must be deallocated at some
|
||||
// point in the program
|
||||
|
||||
Set *setForDealocatingMemory = NULL;
|
||||
|
||||
int i, j;
|
||||
PT_INDUCVAR ind;
|
||||
SgExpression *ex2;
|
||||
SgSymbol *tsymb[MAXNESTEDLOOP];
|
||||
a_access access1, access2, access3;
|
||||
ddnature oitype, iotype;
|
||||
uint nest1, nest2, nest3, bnest;
|
||||
context_iterator firstcontiter, firstcontiter1;
|
||||
var_id inducom1[MAXNESTEDLOOP];
|
||||
var_id inducom2[MAXNESTEDLOOP];
|
||||
var_id ptvar;
|
||||
int inif;
|
||||
|
||||
if (!el1 || !el2)
|
||||
return -2;
|
||||
// do not accept scalar variables here
|
||||
if (el1->scalar || el2->scalar)
|
||||
{
|
||||
// not treated here but in depGraph.C
|
||||
// if (!currentDepGraph)
|
||||
// {
|
||||
// Message("No current Dep Graph",0);
|
||||
// return -2;
|
||||
// }
|
||||
// currentDepGraph->addAnEdge(el1->stmt,el2->stmt,
|
||||
// el1->var,el2->var,
|
||||
// SCALARDEP,0,NULL,NULL,0);
|
||||
return 0;
|
||||
}
|
||||
// create the set for deallocation of memory;
|
||||
setForDealocatingMemory = new Set(dummyEqual, NULL, dummyPrint);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, setForDealocatingMemory, 1);
|
||||
#endif
|
||||
setForDealocatingMemory->setDealllocateElem();
|
||||
|
||||
// we have to prepare the data structure for the omega test
|
||||
|
||||
SetSTuff(); // initialize the omega test
|
||||
|
||||
// format the variable for the omega test;
|
||||
|
||||
for (j = 0; j < induc->size(); j++)
|
||||
{
|
||||
ind = (PT_INDUCVAR)induc->getElement(j);
|
||||
ptvar = (omegaVar*)malloc(sizeof(omegaVar));
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, ptvar, 0);
|
||||
#endif
|
||||
setForDealocatingMemory->addElement((void *)ptvar);
|
||||
inducom1[j] = ptvar;
|
||||
inducom2[j] = ptvar;
|
||||
// ptvar->loop = ind->loopnum;
|
||||
ptvar->loop = ind->level; // seems to be more correct...
|
||||
if (ind->constante)
|
||||
{
|
||||
ptvar->indexp = FALSE; // constante variable;
|
||||
ptvar->constp = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptvar->indexp = TRUE; // index variable;
|
||||
ptvar->constp = FALSE;
|
||||
}
|
||||
ptvar->tag = UNTAGGED;
|
||||
ptvar->name = ind->var->symbol()->identifier();
|
||||
}
|
||||
inducom1[induc->size()] = NULL;
|
||||
inducom2[induc->size()] = NULL;
|
||||
for (i = 0; i < induc->size(); i++)
|
||||
{
|
||||
ind = (PT_INDUCVAR)induc->getElement(i);
|
||||
if (ex2 = ind->var)
|
||||
{
|
||||
tsymb[i] = ex2->symbol();
|
||||
}
|
||||
}
|
||||
|
||||
access1 = (omegaAccess*)malloc(sizeof(omegaAccess));
|
||||
setForDealocatingMemory->addElement((void *)access1);
|
||||
access2 = (omegaAccess*)malloc(sizeof(omegaAccess));
|
||||
setForDealocatingMemory->addElement((void *)access2);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, access1, 0);
|
||||
addToCollection(__LINE__, __FILE__, access2, 0);
|
||||
#endif
|
||||
firstcontiter = fillOmegaLoop(el1, induc, inducom1, tsymb, &inif, setForDealocatingMemory);
|
||||
firstcontiter1 = firstcontiter;
|
||||
nest1 = fillOmegaAccess(el1, access1, induc, inducom1, firstcontiter, "Access1", inif, setForDealocatingMemory);
|
||||
firstcontiter = fillOmegaLoop(el2, induc, inducom2, tsymb, &inif, setForDealocatingMemory);
|
||||
nest2 = fillOmegaAccess(el2, access2, induc, inducom2, firstcontiter, "Access2", inif, setForDealocatingMemory);
|
||||
access1->lexord = 2;
|
||||
access2->lexord = 1;
|
||||
if (!lexOrder(el1, el2))
|
||||
{
|
||||
access1->lexord = 1;
|
||||
access2->lexord = 2;
|
||||
}
|
||||
if (!el1->rw)
|
||||
{ // swapp the reference;
|
||||
int ts;
|
||||
access3 = access1;
|
||||
access1 = access2;
|
||||
access2 = access3;
|
||||
nest3 = nest1;
|
||||
nest1 = nest2;
|
||||
nest2 = nest3;
|
||||
}
|
||||
bnest = commonDepth(firstcontiter1, firstcontiter); // should be the common nests see ddnests;
|
||||
access1->shareddepth = bnest;
|
||||
access2->shareddepth = bnest;
|
||||
if (el1->rw && el2->rw)
|
||||
{
|
||||
oitype = ddoutput;
|
||||
iotype = ddoutput;
|
||||
}
|
||||
else
|
||||
{
|
||||
oitype = ddflow;
|
||||
iotype = ddanti;
|
||||
}
|
||||
|
||||
|
||||
// printf("Testing dependence Using Omega Test between ");
|
||||
// el1->var->unparsestdout();
|
||||
// printf(" line %d and ", el1->stmt->lineNumber());
|
||||
// el2->var->unparsestdout();
|
||||
// printf(" line %d \n", el2->stmt->lineNumber());
|
||||
|
||||
currentStmtIn = el1->stmt;
|
||||
currentStmtOut = el2->stmt;
|
||||
currentVarIn = el1->var;
|
||||
currentVarOut = el2->var;
|
||||
|
||||
dd_omega_test(access1, access2, oitype, iotype, nest1, nest2, bnest);
|
||||
|
||||
//check if dependensices is known;
|
||||
int result = 0;
|
||||
const std::vector<depNode*> &nodes = currentDepGraph->getNodes();
|
||||
for (int z = countOfNodes; z < nodes.size(); ++z)
|
||||
{
|
||||
if (isRemovableDependence(nodes[z], currentDepGraph->privVars) == false)
|
||||
{
|
||||
result = 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
countOfNodes = nodes.size();
|
||||
// should delete all allocated space;
|
||||
#ifdef __SPF
|
||||
removeFromCollection(setForDealocatingMemory);
|
||||
#endif
|
||||
delete setForDealocatingMemory;
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// indicates if a statement is before in a loop body stmt1 is assumed to be the first one
|
||||
//
|
||||
|
||||
|
||||
int beforeInText(SgStatement *func, SgStatement *stmt1, SgStatement *stmt2)
|
||||
{
|
||||
SgStatement *temp, *last;
|
||||
|
||||
if (!func || !stmt1 || !stmt2)
|
||||
return -1;
|
||||
last = func->lastNodeOfStmt();
|
||||
for (temp = func; temp && (temp != last); temp = temp->lexNext())
|
||||
{
|
||||
if (temp == stmt1)
|
||||
return 1;
|
||||
if (temp == stmt2)
|
||||
return 0;
|
||||
}
|
||||
Message("None of the statement where found in beforeInText", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
Set *computeLoopDependencies(SgStatement *func, Set *inset, SgSymbol **tsymb, Set *induc)
|
||||
{
|
||||
|
||||
PT_INDUCVAR ind;
|
||||
PT_ACCESSARRAY el1, el2;
|
||||
int i, j, k;
|
||||
int found;
|
||||
int loopnum;
|
||||
PT_DEPENDENCE el;
|
||||
Set *depset;
|
||||
int datadep;
|
||||
int typedep;
|
||||
|
||||
if (!inset || !tsymb || !induc)
|
||||
return NULL;
|
||||
// not needed anymore
|
||||
// depset = new Set(dependenceEqual, NULL, dependencePrint);
|
||||
WarningOutForNegativeStep = 0;
|
||||
|
||||
int countOfNodes = currentDepGraph->getNodes().size();
|
||||
for (i = 0; i < inset->size(); i++)
|
||||
{
|
||||
createNeededException();
|
||||
|
||||
el1 = (PT_ACCESSARRAY)inset->getElement(i);
|
||||
if (el1)
|
||||
{
|
||||
for (j = i; j < inset->size(); j++)
|
||||
{
|
||||
datadep = 0;
|
||||
el2 = (PT_ACCESSARRAY)inset->getElement(j);
|
||||
if (el2)
|
||||
{
|
||||
if (el1->var && el2->var &&
|
||||
(el1->rw || el2->rw) &&
|
||||
(el1->var->symbol() == el2->var->symbol()))
|
||||
{
|
||||
int res = isDependent(el1, el2, induc, countOfNodes);
|
||||
if (res == 5)
|
||||
{
|
||||
printf("Sapfor: return from computeLoopDependencies with 5 status with %d graph\n", countOfNodes);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (countOfNodes > 1000)
|
||||
printf("Sapfor: return from computeLoopDependencies with %d graph\n", countOfNodes);
|
||||
return NULL;
|
||||
}
|
||||
19
Sapfor/_src/SageAnalysisTool/dependence.h
Normal file
19
Sapfor/_src/SageAnalysisTool/dependence.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
//
|
||||
// for computing loop dependencies
|
||||
//
|
||||
|
||||
struct datadep
|
||||
{
|
||||
SgStatement *loop;
|
||||
int loopnum;
|
||||
SgStatement *stmtin;
|
||||
SgStatement *stmtout;
|
||||
SgExpression *varin; // this is var;
|
||||
SgExpression *varout; // this is var;
|
||||
int typedep;
|
||||
int kinddep;
|
||||
int distance[MAXNESTEDLOOP];
|
||||
};
|
||||
|
||||
typedef struct datadep *PT_DEPENDENCE;
|
||||
280
Sapfor/_src/SageAnalysisTool/flowAnalysis.cpp
Normal file
280
Sapfor/_src/SageAnalysisTool/flowAnalysis.cpp
Normal file
@@ -0,0 +1,280 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "sage++user.h"
|
||||
#include "definesValues.h"
|
||||
#include "set.h"
|
||||
|
||||
#ifdef __SPF
|
||||
extern "C" void addToCollection(const int line, const char *file, void *pointer, int type);
|
||||
extern "C" void removeFromCollection(void *pointer);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Control FLOW part of declaration
|
||||
//
|
||||
|
||||
extern void controlFlow(SgStatement *stmt, SgStatement *func,
|
||||
SgStatement **pred, SgStatement **suc,
|
||||
int *predin, int *sucint);
|
||||
|
||||
Set *genSet[MAXNODE];
|
||||
Set *killSet[MAXNODE];
|
||||
Set *inSet[MAXNODE];
|
||||
Set *outSet[MAXNODE];
|
||||
|
||||
//
|
||||
// Main function for data flow analysis, take some functions as a parameter
|
||||
//
|
||||
|
||||
|
||||
void iterativeForwardFlowAnalysis(SgFile *file,
|
||||
SgStatement *func,
|
||||
Set *(*giveGenSet)(SgStatement *func, SgStatement *stmt),
|
||||
Set *(*giveKillSet)(SgStatement *func, SgStatement *stmt),
|
||||
int(*feq)(void *e1, void *e2),
|
||||
void *(*fcomb)(void *e1, void *e2),
|
||||
void(*fp)(void *e1))
|
||||
{
|
||||
SgStatement *last, *first, *lastfunc, *temp;
|
||||
SgStatement *pred[MAXP], *suc[MAXP];
|
||||
int nbpred, nbsuc;
|
||||
int size, i, j;
|
||||
Set *tps, *oldout, *tpt, *pt1, *pt2, *comb;
|
||||
int change, step;
|
||||
int cid;
|
||||
if (!file || !func || !giveGenSet || !giveKillSet)
|
||||
{
|
||||
Message("iterativeForwardFlowAnalysis: Some Argument are NULL", 0);
|
||||
return;
|
||||
}
|
||||
lastfunc = func->lastNodeOfStmt();
|
||||
// should use the max id instead;
|
||||
for (i = 0; i < MAXNODE; i++)
|
||||
{
|
||||
genSet[i] = NULL;
|
||||
killSet[i] = NULL;
|
||||
outSet[i] = NULL;
|
||||
inSet[i] = NULL;
|
||||
}
|
||||
// initialize the gen and kill set;
|
||||
for (temp = func; temp; temp = temp->lexNext())
|
||||
{
|
||||
if (temp->id() > MAXNODE)
|
||||
{
|
||||
Message("Too many nodes in program: Fatal", 0);
|
||||
exit(1);
|
||||
}
|
||||
genSet[temp->id()] = (*giveGenSet)(func, temp);
|
||||
killSet[temp->id()] = (*giveKillSet)(func, temp);
|
||||
if (temp == lastfunc)
|
||||
break;
|
||||
}
|
||||
// initialize the out set;
|
||||
for (temp = func; temp; temp = temp->lexNext())
|
||||
{
|
||||
if (genSet[temp->id()])
|
||||
{
|
||||
pt2 = genSet[temp->id()];
|
||||
outSet[temp->id()] = pt2->copy();
|
||||
}
|
||||
else
|
||||
outSet[temp->id()] = NULL;
|
||||
inSet[temp->id()] = NULL;
|
||||
if (temp == lastfunc)
|
||||
break;
|
||||
}
|
||||
change = 1;
|
||||
step = 0;
|
||||
while (change)
|
||||
{
|
||||
step++;
|
||||
change = 0;
|
||||
for (temp = func; temp; temp = temp->lexNext())
|
||||
{
|
||||
cid = temp->id();
|
||||
controlFlow(temp, func, pred, suc, &nbpred, &nbsuc);
|
||||
if (inSet[cid])
|
||||
{
|
||||
#ifdef __SPF
|
||||
removeFromCollection(inSet[cid]);
|
||||
#endif
|
||||
delete inSet[cid];
|
||||
}
|
||||
tps = new Set(feq, fcomb, fp);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, tps, 1);
|
||||
#endif
|
||||
for (i = 0; i < nbpred; i++)
|
||||
{
|
||||
tps->unionSet(outSet[pred[i]->id()]);
|
||||
}
|
||||
|
||||
inSet[cid] = tps;
|
||||
|
||||
oldout = outSet[cid];
|
||||
outSet[cid] = new Set(feq, fcomb, fp);
|
||||
tpt = new Set(feq, fcomb, fp);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, outSet[cid], 1);
|
||||
addToCollection(__LINE__, __FILE__, tpt, 1);
|
||||
#endif
|
||||
tpt->diffSet(inSet[cid], killSet[cid]);
|
||||
|
||||
outSet[cid]->unionSet(genSet[cid]);
|
||||
outSet[cid]->unionSet(tpt);
|
||||
pt1 = outSet[cid];
|
||||
outSet[cid] = pt1->compact();
|
||||
#ifdef __SPF
|
||||
removeFromCollection(pt1);
|
||||
#endif
|
||||
delete pt1;
|
||||
if (!oldout && outSet[cid])
|
||||
change = 1;
|
||||
else
|
||||
if (!oldout->equalSet(outSet[cid]))
|
||||
change = 1;
|
||||
if (oldout)
|
||||
{
|
||||
#ifdef __SPF
|
||||
removeFromCollection(oldout);
|
||||
#endif
|
||||
delete oldout;
|
||||
}
|
||||
if (tpt)
|
||||
{
|
||||
#ifdef __SPF
|
||||
removeFromCollection(tpt);
|
||||
#endif
|
||||
delete tpt;
|
||||
}
|
||||
|
||||
if (temp == lastfunc)
|
||||
break;
|
||||
}
|
||||
if (step > MAXITDATAFLOW)
|
||||
{
|
||||
Message("data flow analysis not converging", 0);
|
||||
return;
|
||||
}
|
||||
printf("Data flow analysis at step %d\n", step);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Iterative Algorithme for General Frameworks page 690 Aho Ullman
|
||||
// out is initialise to transfertSet(NULL). in is initialized to NULL (this is T).
|
||||
// combineSet() is the meet operator (take as input the union or output...)
|
||||
//
|
||||
|
||||
void generalIterativeFlowAnalysis(SgFile *file,
|
||||
SgStatement *func,
|
||||
Set *(*transfertSet)(SgStatement *func, SgStatement *stmt, Set *setin),
|
||||
int(*feq)(void *e1, void *e2),
|
||||
void* (*fcomb)(void *e1, void *e2),
|
||||
void(*fp)(void *e1))
|
||||
{
|
||||
SgStatement *last, *first, *lastfunc, *temp;
|
||||
SgStatement *pred[MAXP], *suc[MAXP];
|
||||
int nbpred, nbsuc;
|
||||
int size, i, j;
|
||||
Set *tps, *oldout, *tpt, *pt1, *pt2, *comb;
|
||||
int change, step;
|
||||
int cid;
|
||||
if (!file || !func || !transfertSet)
|
||||
{
|
||||
Message("generalIterativeFlowAnalysis: Some Arguments are NULL", 0);
|
||||
return;
|
||||
}
|
||||
lastfunc = func->lastNodeOfStmt();
|
||||
// should use the max id instead;
|
||||
for (i = 0; i < MAXNODE; i++)
|
||||
{
|
||||
genSet[i] = NULL;
|
||||
killSet[i] = NULL;
|
||||
outSet[i] = NULL;
|
||||
inSet[i] = NULL;
|
||||
}
|
||||
// initialize the out Set
|
||||
for (temp = func; temp; temp = temp->lexNext())
|
||||
{
|
||||
if (temp->id() > MAXNODE)
|
||||
{
|
||||
Message("Too many nodes in program: Fatal", 0);
|
||||
exit(1);
|
||||
}
|
||||
outSet[temp->id()] = (*transfertSet)(func, temp, NULL);
|
||||
if (temp == lastfunc)
|
||||
break;
|
||||
}
|
||||
change = 1;
|
||||
step = 0;
|
||||
while (change)
|
||||
{
|
||||
step++;
|
||||
change = 0;
|
||||
for (temp = func; temp; temp = temp->lexNext())
|
||||
{
|
||||
cid = temp->id();
|
||||
controlFlow(temp, func, pred, suc, &nbpred, &nbsuc);
|
||||
if (inSet[cid])
|
||||
{
|
||||
#ifdef __SPF
|
||||
removeFromCollection(inSet[cid]);
|
||||
#endif
|
||||
delete inSet[cid];
|
||||
}
|
||||
tps = new Set(feq, fcomb, fp);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, tps, 1);
|
||||
#endif
|
||||
for (i = 0; i < nbpred; i++)
|
||||
{
|
||||
tps->unionSet(outSet[pred[i]->id()]);
|
||||
}
|
||||
tpt = tps;
|
||||
tps = tps->combineSet();
|
||||
inSet[cid] = tps;
|
||||
if (tpt)
|
||||
{
|
||||
#ifdef __SPF
|
||||
removeFromCollection(tpt);
|
||||
#endif
|
||||
delete tpt;
|
||||
}
|
||||
|
||||
oldout = outSet[cid];
|
||||
outSet[cid] = (*transfertSet)(func, temp, inSet[cid]);
|
||||
if (!oldout && outSet[cid])
|
||||
{
|
||||
change = 1;
|
||||
// printf ("old out is NULL (line %d)\n", temp->lineNumber());
|
||||
}
|
||||
else
|
||||
if (!oldout->equalSet(outSet[cid]))
|
||||
{
|
||||
// printf ("-------debug ouput (line %d)-----------: \n", temp->lineNumber());
|
||||
// printf ("oldout: \n");
|
||||
// oldout->printSet();
|
||||
// printf ("out: \n");
|
||||
// if (outSet[cid])
|
||||
// outSet[cid]->printSet();
|
||||
change = 1;
|
||||
}
|
||||
if (oldout)
|
||||
{
|
||||
#ifdef __SPF
|
||||
removeFromCollection(oldout);
|
||||
#endif
|
||||
delete oldout;
|
||||
}
|
||||
if (temp == lastfunc)
|
||||
break;
|
||||
}
|
||||
if (step > MAXITDATAFLOW)
|
||||
{
|
||||
Message("data flow analysis not converging", 0);
|
||||
return;
|
||||
}
|
||||
printf("Data flow analysis at step %d\n", step);
|
||||
}
|
||||
}
|
||||
18
Sapfor/_src/SageAnalysisTool/inducVar.h
Normal file
18
Sapfor/_src/SageAnalysisTool/inducVar.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
struct inducvar
|
||||
{
|
||||
int constante; // indicate if constante or induction
|
||||
SgStatement *stmt;
|
||||
SgExpression *var; // this is a var ref;
|
||||
SgExpression *stride;
|
||||
SgExpression *lbound;
|
||||
SgExpression *ubound;
|
||||
Set *reachdef;
|
||||
int level;
|
||||
int loopnum;
|
||||
int include;
|
||||
};
|
||||
|
||||
typedef struct inducvar *PT_INDUCVAR;
|
||||
|
||||
92
Sapfor/_src/SageAnalysisTool/intrinsic.cpp
Normal file
92
Sapfor/_src/SageAnalysisTool/intrinsic.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// To deals with the intrinsics function call
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sage++user.h"
|
||||
#include "definesValues.h"
|
||||
#include "intrinsic.h"
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
|
||||
extern std::set<std::string> intrinsicF;
|
||||
extern void initIntrinsicFunctionNames();
|
||||
|
||||
// return TRUE if OK and FALSE otherwise
|
||||
int isSymbolIntrinsic(SgSymbol *symb)
|
||||
{
|
||||
initIntrinsicFunctionNames();
|
||||
|
||||
SgFunctionSymb *fs;
|
||||
char *ident;
|
||||
if (fs = isSgFunctionSymb(symb))
|
||||
{
|
||||
ident = fs->identifier();
|
||||
if (!ident)
|
||||
return FALSE;
|
||||
if (intrinsicF.find(ident) == intrinsicF.end())
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int isExprCallToFuncNotIntrinsic(SgExpression *exp)
|
||||
{
|
||||
SgFunctionCallExp *fc;
|
||||
|
||||
if (!exp)
|
||||
return FALSE;
|
||||
|
||||
if (fc = isSgFunctionCallExp(exp))
|
||||
{
|
||||
if (!isSymbolIntrinsic(fc->funName()))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (isExprCallToFuncNotIntrinsic(exp->lhs()))
|
||||
return TRUE;
|
||||
if (isExprCallToFuncNotIntrinsic(exp->rhs()))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int isStmtCallToFuncNotIntrinsic(SgStatement *stmt)
|
||||
{
|
||||
int i;
|
||||
SgStatement *child;
|
||||
|
||||
if (!stmt)
|
||||
return FALSE;
|
||||
|
||||
if (isExprCallToFuncNotIntrinsic(stmt->expr(0)))
|
||||
return TRUE;
|
||||
if (isExprCallToFuncNotIntrinsic(stmt->expr(1)))
|
||||
return TRUE;
|
||||
if (isExprCallToFuncNotIntrinsic(stmt->expr(2)))
|
||||
return TRUE;
|
||||
|
||||
i = 1;
|
||||
child = stmt->childList1(0);
|
||||
while (child)
|
||||
{
|
||||
if (isStmtCallToFuncNotIntrinsic(child))
|
||||
return TRUE;
|
||||
child = stmt->childList1(i);
|
||||
i++;
|
||||
}
|
||||
i = 1;
|
||||
child = stmt->childList2(0);
|
||||
while (child)
|
||||
{
|
||||
if (isStmtCallToFuncNotIntrinsic(child))
|
||||
return TRUE;
|
||||
child = stmt->childList2(i);
|
||||
i++;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
26
Sapfor/_src/SageAnalysisTool/intrinsic.h
Normal file
26
Sapfor/_src/SageAnalysisTool/intrinsic.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// To deals with the intrisics function call
|
||||
// Declare the sets of function considered as intrinsic
|
||||
// in fortran 77
|
||||
// indicate also if side effect
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// see definesValues.h files
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
169
Sapfor/_src/SageAnalysisTool/invariant.cpp
Normal file
169
Sapfor/_src/SageAnalysisTool/invariant.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
#include <stdio.h>
|
||||
#include "sage++user.h"
|
||||
#include "definesValues.h"
|
||||
#include "set.h"
|
||||
#include "definitionSet.h"
|
||||
|
||||
#ifdef __SPF
|
||||
extern "C" void addToCollection(const int line, const char *file, void *pointer, int type);
|
||||
#endif
|
||||
|
||||
extern Set *genSet[MAXNODE];
|
||||
extern Set *killSet[MAXNODE];
|
||||
extern Set *inSet[MAXNODE];
|
||||
extern Set *outSet[MAXNODE];
|
||||
|
||||
//
|
||||
// used in compute loop invariant
|
||||
//
|
||||
|
||||
int stmtEqual(void *e1, void *e2)
|
||||
{
|
||||
SgStatement *ex1, *ex2;
|
||||
if (!e1 && !e2)
|
||||
return 1;
|
||||
if (!e1 || !e2)
|
||||
return 0;
|
||||
|
||||
ex1 = (SgStatement *)e1;
|
||||
ex2 = (SgStatement *)e2;
|
||||
|
||||
if (ex1 != ex2)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
void stmtPrint(void *e1)
|
||||
{
|
||||
SgStatement *ex1;
|
||||
if (!e1)
|
||||
return;
|
||||
|
||||
ex1 = (SgStatement *)e1;
|
||||
printf("statement at line %d:\n", ex1->lineNumber());
|
||||
ex1->unparsestdout();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void exprPrint(void *e1)
|
||||
{
|
||||
SgExpression *ex1;
|
||||
if (!e1)
|
||||
return;
|
||||
ex1 = (SgExpression *)e1;
|
||||
ex1->unparsestdout();
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
//
|
||||
//function to Compute Loop Invariant Computation
|
||||
// assume Reaching definition has been done
|
||||
// and also the used and defined for each statment has also been computed
|
||||
//
|
||||
|
||||
Set *loopInvariantStmt(SgStatement *func, SgStatement *stmt)
|
||||
{
|
||||
SgStatement *last, *first, *defreach, *temp, *cp;
|
||||
SgForStmt *loop;
|
||||
Set *invariant, *reachdef;
|
||||
SgExpression *use, *pt, *usevar, *expr;
|
||||
int change, id, inloop, inv, step;
|
||||
PT_ELSET el;
|
||||
int i;
|
||||
if (!stmt || !func)
|
||||
return NULL;
|
||||
|
||||
if (!(loop = isSgForStmt(stmt)))
|
||||
return NULL;
|
||||
|
||||
last = stmt->lastNodeOfStmt();
|
||||
invariant = new Set(stmtEqual, NULL, stmtPrint);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, invariant, 1);
|
||||
#endif
|
||||
change = 1;
|
||||
step = 0;
|
||||
while (change)
|
||||
{
|
||||
change = 0;
|
||||
step++;
|
||||
for (temp = stmt->lexNext(); temp; temp = temp->lexNext())
|
||||
{
|
||||
// only if assgn_stat...;
|
||||
if (!isSgAssignStmt(temp))
|
||||
{
|
||||
if (temp == last)
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
id = temp->id();
|
||||
use = (SgExpression *)temp->attributeValue(0, USEDLIST_ATTRIBUTE);
|
||||
//Used[id];
|
||||
reachdef = inSet[id];
|
||||
// look at all the use of ;
|
||||
inv = 1;
|
||||
for (pt = use; pt && (inv == 1); pt = pt->rhs())
|
||||
{
|
||||
usevar = pt->lhs();
|
||||
if (usevar)
|
||||
{// look at if the definition is the reaching set;
|
||||
for (i = 0; i < reachdef->size(); i++)
|
||||
{
|
||||
el = (PT_ELSET)reachdef->getElement(i);
|
||||
if (el)
|
||||
{
|
||||
defreach = el->stmt;
|
||||
expr = el->expr;
|
||||
if (expr)
|
||||
{
|
||||
if (expr->symbol() && usevar->symbol() &&
|
||||
(expr->symbol() == usevar->symbol()))
|
||||
{
|
||||
// we have a definition of the variable;
|
||||
if (!invariant->isInSet((void *)defreach))
|
||||
{
|
||||
// look at if in the loop body;
|
||||
inloop = 0;
|
||||
cp = defreach;
|
||||
while (cp)
|
||||
{
|
||||
if (cp == stmt)
|
||||
{
|
||||
inloop = 1;
|
||||
break;
|
||||
}
|
||||
if ((cp->variant() == GLOBAL) || (cp == func))
|
||||
{
|
||||
inloop = 0;
|
||||
break;
|
||||
}
|
||||
cp = cp->controlParent();
|
||||
}
|
||||
if (inloop)
|
||||
{
|
||||
inv = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inv && !invariant->isInSet((void *)temp) && (step < MAXITDATAFLOW))
|
||||
{
|
||||
invariant->addElement((void *)temp);
|
||||
change = 1;
|
||||
}
|
||||
if (step >= MAXITDATAFLOW)
|
||||
Message("invariant computation is Looping", 0);
|
||||
if (temp == last)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return invariant;
|
||||
}
|
||||
|
||||
412
Sapfor/_src/SageAnalysisTool/loopTransform.cpp
Normal file
412
Sapfor/_src/SageAnalysisTool/loopTransform.cpp
Normal file
@@ -0,0 +1,412 @@
|
||||
#include <stdio.h>
|
||||
#include "sage++user.h"
|
||||
#include "definesValues.h"
|
||||
#include "set.h"
|
||||
#include "definitionSet.h"
|
||||
#include "inducVar.h"
|
||||
#include "depGraph.h"
|
||||
|
||||
#ifdef __SPF
|
||||
extern "C" void addToCollection(const int line, const char *file, void *pointer, int type);
|
||||
extern "C" void removeFromCollection(void *pointer);
|
||||
#endif
|
||||
|
||||
extern int countPerfectLoopNest(SgStatement*);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// some global declarations
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Loop Transformation Sets. (the validity checkings for the transformations
|
||||
// are in the depGraph method.
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// b is the outer loopm
|
||||
// permut specify the loop permutations
|
||||
// the n outermost loops must be perfectly nested
|
||||
// permut start at 0; Example
|
||||
// do i = 0
|
||||
// do j = 8
|
||||
// do k = 1
|
||||
// ....
|
||||
// permut = [2,1,0]
|
||||
// gives
|
||||
// do k = 1
|
||||
// do j = 8
|
||||
// do i = 0
|
||||
// ....
|
||||
//
|
||||
|
||||
int loopInterchange(SgStatement *b, int *permut, int n)
|
||||
{
|
||||
SgSymbol *tab_symb[MAXNESTEDLOOP];
|
||||
SgExpression *tab_bf[MAXNESTEDLOOP];
|
||||
SgExpression * tab_bi[MAXNESTEDLOOP];
|
||||
SgExpression * tab_step[MAXNESTEDLOOP];
|
||||
SgForStmt *loop, *tloop;
|
||||
int i;
|
||||
if (!(loop = isSgForStmt(b)))
|
||||
return 0;
|
||||
|
||||
if (n > countPerfectLoopNest(loop))
|
||||
{
|
||||
Message("Interchange loop error, loops are not perfectly nested", loop->lineNumber());
|
||||
return 0;
|
||||
}
|
||||
tloop = loop;
|
||||
for (i = 0; (i < n); i++)
|
||||
{
|
||||
tab_symb[i] = tloop->symbol();
|
||||
tab_bf[i] = tloop->start();
|
||||
tab_bi[i] = tloop->end();
|
||||
tab_step[i] = tloop->step();
|
||||
tloop = isSgForStmt(tloop->getNextLoop());
|
||||
}
|
||||
|
||||
tloop = loop;
|
||||
for (i = 0; (i < n); i++)
|
||||
{
|
||||
if (tab_symb[permut[i]])
|
||||
tloop->setSymbol(*tab_symb[permut[i]]);
|
||||
if (tab_bf[permut[i]])
|
||||
tloop->setStart(*tab_bf[permut[i]]);
|
||||
if (tab_bi[permut[i]])
|
||||
tloop->setEnd(*tab_bi[permut[i]]);
|
||||
if (tab_step[permut[i]])
|
||||
tloop->setStep(*tab_step[permut[i]]);
|
||||
tloop = isSgForStmt(tloop->getNextLoop());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Tile a loop.
|
||||
// assumed to be perfectly nested.
|
||||
// size is NO_STEP we do not want it to be tiled
|
||||
//
|
||||
|
||||
int tileLoops(SgStatement *func, SgStatement *b, int *size, int nb)
|
||||
{
|
||||
int i, j;
|
||||
SgSymbol *tab_symb[MAXNESTEDLOOP];
|
||||
SgStatement *body, *ptstmt;
|
||||
SgForStmt *internal_loop, *temp, *last_loop;
|
||||
SgForStmt *loop, *temloo;
|
||||
SgExpression *borne_inf[MAXNESTEDLOOP];
|
||||
SgExpression *borne_sup[MAXNESTEDLOOP];
|
||||
SgExpression *step[MAXNESTEDLOOP];
|
||||
SgType *typint;
|
||||
SgSymbol *min_fonc;
|
||||
char strfoname[256];
|
||||
|
||||
if (!(loop = isSgForStmt(b)) || !func)
|
||||
return 0;
|
||||
if (nb > countPerfectLoopNest(loop))
|
||||
{
|
||||
Message("loop Tilling error, loops are not perfectly nested", loop->lineNumber());
|
||||
return 0;
|
||||
}
|
||||
if (nb == 0) return 0;
|
||||
|
||||
if (nb >= MAXNESTEDLOOP)
|
||||
{
|
||||
Message("Too many nested level", b->lineNumber());
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < MAXNESTEDLOOP; i++)
|
||||
{
|
||||
tab_symb[i] = NULL;
|
||||
borne_inf[i] = NULL;
|
||||
borne_sup[i] = NULL;
|
||||
step[i] = NULL;
|
||||
}
|
||||
last_loop = loop;
|
||||
for (i = 0; i < nb; i++)
|
||||
{
|
||||
if (size[i] != NO_STEP)
|
||||
{
|
||||
if (last_loop->step())
|
||||
{
|
||||
Message("Cannot tile loop, there is already a step", last_loop->lineNumber());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
last_loop = isSgForStmt(last_loop->getNextLoop());
|
||||
}
|
||||
// Get integer type;
|
||||
typint = SgTypeInt();
|
||||
// get the indexes of the loops;
|
||||
temloo = loop;
|
||||
for (i = 0; i < nb; i++)
|
||||
{
|
||||
tab_symb[i] = temloo->symbol();
|
||||
internal_loop = temloo;
|
||||
temloo = isSgForStmt(temloo->getNextLoop());
|
||||
}
|
||||
if (!internal_loop)
|
||||
{
|
||||
Message("Internal loop not found", loop->lineNumber());
|
||||
return 0;
|
||||
}
|
||||
// generate the new symbol and declare them
|
||||
for (i = 0; i < nb; i++)
|
||||
{
|
||||
sprintf(strfoname, "iT%d_%d", loop->id(), i);
|
||||
tab_symb[i + nb] = new SgVariableSymb(strfoname);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, tab_symb[i + nb], 1);
|
||||
#endif
|
||||
tab_symb[i + nb]->declareTheSymbol(*func);
|
||||
}
|
||||
last_loop = loop;
|
||||
for (i = 0; i < nb; i++)
|
||||
{
|
||||
if (size[i] != NO_STEP)
|
||||
{
|
||||
SgValueExp *tmp = (new SgValueExp(size[i] + 1));
|
||||
last_loop->setStep(*tmp);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, tmp, 1);
|
||||
#endif
|
||||
}
|
||||
last_loop = isSgForStmt(last_loop->getNextLoop());
|
||||
}
|
||||
|
||||
// create a min function;
|
||||
min_fonc = new SgSymbol(FUNCTION_NAME, "min", *typint, *(loop->controlParent()));
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, min_fonc, 1);
|
||||
#endif
|
||||
// creation of the bound expressions;
|
||||
last_loop = loop;
|
||||
for (i = 0; i < nb; i++)
|
||||
{
|
||||
if (size[i] != NO_STEP)
|
||||
{
|
||||
SgFunctionCallExp *cexp;
|
||||
borne_inf[i + nb] = new SgValueExp(0);
|
||||
cexp = new SgFunctionCallExp(*min_fonc);
|
||||
borne_sup[i + nb] = cexp;
|
||||
|
||||
SgValueExp *tmp = (new SgValueExp(size[i]));
|
||||
SgVarRefExp *tmp1 = (new SgVarRefExp(*tab_symb[i]));
|
||||
cexp->addArg(((last_loop->end())->copy()) - *tmp1);
|
||||
cexp->addArg(*tmp);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, borne_inf[i + nb], 1);
|
||||
addToCollection(__LINE__, __FILE__, cexp, 1);
|
||||
addToCollection(__LINE__, __FILE__, tmp, 1);
|
||||
addToCollection(__LINE__, __FILE__, tmp1, 1);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
borne_inf[i + nb] = new SgValueExp(1);
|
||||
borne_sup[i + nb] = &((last_loop->end())->copy());
|
||||
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, borne_inf[i + nb], 1);
|
||||
#endif
|
||||
}
|
||||
step[i + nb] = NULL;
|
||||
last_loop = isSgForStmt(last_loop->getNextLoop());
|
||||
}
|
||||
// remove the loop body;
|
||||
// update the steps;
|
||||
body = internal_loop->extractStmtBody();
|
||||
// upper bound for NO_STEP loops
|
||||
last_loop = loop;
|
||||
for (i = 0; i < nb; i++)
|
||||
{
|
||||
if (size[i] == NO_STEP)
|
||||
{
|
||||
SgValueExp *tmp = (new SgValueExp(1));
|
||||
last_loop->setEnd(*tmp);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, tmp, 1);
|
||||
#endif
|
||||
}
|
||||
last_loop = isSgForStmt(last_loop->getNextLoop());
|
||||
}
|
||||
// create the new loop;
|
||||
last_loop = internal_loop;
|
||||
for (i = 0; i < nb; i++)
|
||||
{
|
||||
loop = new SgForStmt(tab_symb[i + nb], borne_inf[i + nb], borne_sup[i + nb], step[i + nb], NULL);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, loop, 1);
|
||||
#endif
|
||||
last_loop->insertStmtAfter(*loop, *last_loop);
|
||||
last_loop = loop;
|
||||
}
|
||||
|
||||
// update the loop body;
|
||||
if (!body || !last_loop)
|
||||
{
|
||||
Message("The loop may not have a body or internal error", 0);
|
||||
return 0;
|
||||
}
|
||||
last_loop->insertStmtAfter(*body, *last_loop);
|
||||
|
||||
for (j = 0; j < last_loop->numberOfChildrenList1(); j++)
|
||||
{
|
||||
ptstmt = last_loop->childList1(j);
|
||||
if (ptstmt)
|
||||
{
|
||||
for (i = 0; i < nb; i++)
|
||||
{
|
||||
if (size[i] != NO_STEP)
|
||||
{
|
||||
SgVarRefExp *tmp = (new SgVarRefExp(*tab_symb[i]));
|
||||
SgVarRefExp *tmp1 = (new SgVarRefExp(*tab_symb[i + nb]));
|
||||
ptstmt->replaceSymbByExp(*tab_symb[i], *tmp + *tmp1);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, tmp, 1);
|
||||
addToCollection(__LINE__, __FILE__, tmp1, 1);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
SgVarRefExp *tmp = (new SgVarRefExp(*tab_symb[i]));
|
||||
ptstmt->replaceSymbByExp(*tab_symb[i], *tmp);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, tmp, 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
// distribute the loops according to the
|
||||
// table of SCC.
|
||||
// for instance consider the following loop
|
||||
//
|
||||
// do i= 1,100
|
||||
//[1] x = 2
|
||||
//[2] do j= 1,100
|
||||
// D(j+i) = A(i,j)
|
||||
// D(j+i) = A(i,j)
|
||||
// enddo
|
||||
//[3] x = 2
|
||||
// enddo
|
||||
// and the following content of the
|
||||
// [[1,3],2] scc table index
|
||||
//
|
||||
|
||||
int distributeLoopSCC(SgStatement *b, int *sccTable, int leadingdim, int numSCC)
|
||||
{
|
||||
int i, j;
|
||||
SgStatement *last, **sccloop, **sccextracted, *ptstm;
|
||||
SgStatement *previous, *cp, *copl;
|
||||
SgForStmt *loop;
|
||||
int nbstat;
|
||||
|
||||
if (!(loop = isSgForStmt(b)) || !sccTable)
|
||||
return 0;
|
||||
|
||||
nbstat = loop->numberOfChildrenList1() - 1; // does not remove the controlend;
|
||||
sccloop = new SgStatement *[numSCC];
|
||||
sccextracted = new SgStatement *[nbstat];
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, sccloop, 2);
|
||||
addToCollection(__LINE__, __FILE__, sccextracted, 2);
|
||||
#endif
|
||||
for (j = 0; j < nbstat; j++)
|
||||
{
|
||||
ptstm = loop->childList1(j);
|
||||
sccextracted[j] = ptstm;
|
||||
}
|
||||
for (j = 0; j < nbstat; j++)
|
||||
{
|
||||
if (sccextracted[j])
|
||||
sccextracted[j]->extractStmt();
|
||||
}
|
||||
// now creates the loop;
|
||||
previous = loop->nodeBefore();
|
||||
cp = loop->controlParent();
|
||||
loop->extractStmt();
|
||||
copl = &(loop->copy());
|
||||
previous->insertStmtAfter(*loop, *cp);
|
||||
sccloop[0] = loop;
|
||||
last = loop->lastNodeOfStmt();
|
||||
// need to extractloop before doing the copy;
|
||||
|
||||
for (j = 1; j < numSCC; j++)
|
||||
{
|
||||
if (j == numSCC - 1)
|
||||
sccloop[j] = copl;
|
||||
else
|
||||
sccloop[j] = &(copl->copy());
|
||||
last->insertStmtAfter(*(sccloop[j]), *cp);
|
||||
last = sccloop[j]->lastNodeOfStmt();
|
||||
}
|
||||
|
||||
for (j = 0; j < numSCC; j++)
|
||||
{
|
||||
for (i = leadingdim - 1; i >= 0; i--)
|
||||
{
|
||||
// insert in the right body the statement;
|
||||
// go revserse order; simpler;
|
||||
if (sccTable[j*leadingdim + i])
|
||||
if (sccextracted[sccTable[j*leadingdim + i] - 1])
|
||||
sccloop[j]->insertStmtAfter(*sccextracted[sccTable[j*leadingdim + i] - 1], *sccloop[j]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __SPF
|
||||
removeFromCollection(sccloop);
|
||||
removeFromCollection(sccextracted);
|
||||
#endif
|
||||
delete []sccloop;
|
||||
delete []sccextracted;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Takes two loops and fusion the bodies
|
||||
//
|
||||
|
||||
int loopFusion(SgStatement *loop1, SgStatement *loop2)
|
||||
{
|
||||
SgForStmt *doloop1;
|
||||
SgForStmt *doloop2;
|
||||
SgStatement *body, *last;
|
||||
|
||||
if (!(doloop1 = isSgForStmt(loop1)))
|
||||
return 0;
|
||||
if (!(doloop2 = isSgForStmt(loop2)))
|
||||
return 0;
|
||||
|
||||
if (!doloop1->symbol())
|
||||
return 0;
|
||||
|
||||
SgVarRefExp *tmp = (new SgVarRefExp(*doloop1->symbol()));
|
||||
doloop2->replaceSymbByExp(*doloop2->symbol(), *tmp);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, tmp, 1);
|
||||
#endif
|
||||
body = doloop2->extractStmtBody();
|
||||
if (!body)
|
||||
return 0;
|
||||
last = doloop1->lastNodeOfStmt();
|
||||
if (!last)
|
||||
return 0;
|
||||
last = last->nodeBefore();
|
||||
if (!last)
|
||||
return 0;
|
||||
last->insertStmtAfter(*body, *doloop1);
|
||||
doloop2->extractStmt();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
8
Sapfor/_src/SageAnalysisTool/reductionCode.h
Normal file
8
Sapfor/_src/SageAnalysisTool/reductionCode.h
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// code for reduction recogniction
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
// see definesValues.h files
|
||||
|
||||
|
||||
425
Sapfor/_src/SageAnalysisTool/set.cpp
Normal file
425
Sapfor/_src/SageAnalysisTool/set.cpp
Normal file
@@ -0,0 +1,425 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "sage++user.h"
|
||||
#include "definesValues.h"
|
||||
#include "set.h"
|
||||
|
||||
#ifdef __SPF
|
||||
extern "C" void addToCollection(const int line, const char *file, void *pointer, int type);
|
||||
extern "C" void removeFromCollection(void *pointer);
|
||||
#endif
|
||||
|
||||
Set::Set(int(*feq)(void *e1, void *e2),
|
||||
void *(*fcomb)(void *e1, void *e2),
|
||||
void(*fp)(void *e1))
|
||||
{
|
||||
|
||||
data = NULL;
|
||||
nbelement = 0;
|
||||
nballocated = 0;
|
||||
equal = feq;
|
||||
combine = fcomb;
|
||||
printEl = fp;
|
||||
deallocelem = 0;
|
||||
}
|
||||
|
||||
void Set::printSet()
|
||||
{
|
||||
int i;
|
||||
if (!printEl)
|
||||
{
|
||||
Message("Function printEl not given", 0);
|
||||
return;
|
||||
}
|
||||
if (!this->size())
|
||||
printf("Empty set\n");
|
||||
else
|
||||
{
|
||||
for (i = 0; i < this->size(); i++)
|
||||
{
|
||||
(*printEl)(getElement(i));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void Set::interSet(Set *s1, Set *s2)
|
||||
{
|
||||
int i, j;
|
||||
int trouve;
|
||||
void *e1, *e2;
|
||||
if (!equal)
|
||||
return;
|
||||
if (!s1 || !s2)
|
||||
return;
|
||||
if (!equal)
|
||||
{
|
||||
Message("Function Equal not given", 0);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < s1->size(); i++)
|
||||
{
|
||||
e1 = s1->getElement(i);
|
||||
if (e1)
|
||||
{
|
||||
trouve = 0;
|
||||
for (j = 0; j < s2->size(); j++)
|
||||
{
|
||||
e2 = s2->getElement(j);
|
||||
if ((*equal)(e1, e2))
|
||||
{
|
||||
trouve = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (trouve)
|
||||
this->addElement(e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Set::unionSet(Set *s1)
|
||||
{
|
||||
int i, j;
|
||||
int trouve;
|
||||
void *e1, *e2;
|
||||
int initsize;
|
||||
int initsize2;
|
||||
|
||||
if (!s1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!equal)
|
||||
{
|
||||
Message("Function Equal not given", 0);
|
||||
return;
|
||||
}
|
||||
initsize = s1->size();
|
||||
initsize2 = this->size();
|
||||
for (i = 0; i < initsize; i++)
|
||||
{
|
||||
e1 = s1->getElement(i);
|
||||
if (e1)
|
||||
{
|
||||
trouve = 0;
|
||||
for (j = 0; j < initsize2; j++)
|
||||
{
|
||||
e2 = this->getElement(j);
|
||||
if ((*equal)(e1, e2))
|
||||
{
|
||||
trouve = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!trouve)
|
||||
this->addElement(e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
int Set::equalSet(Set *s1)
|
||||
{
|
||||
int i, j;
|
||||
int trouve;
|
||||
void *e1, *e2;
|
||||
if (!s1)
|
||||
return 0;
|
||||
|
||||
if (!equal)
|
||||
{
|
||||
Message("Function Equal not given", 0);
|
||||
return 0;
|
||||
}
|
||||
if (this->size() != s1->size())
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < size(); i++)
|
||||
{
|
||||
e1 = getElement(i);
|
||||
if (e1)
|
||||
{
|
||||
trouve = 0;
|
||||
for (j = 0; j < s1->size(); j++)
|
||||
{
|
||||
e2 = s1->getElement(j);
|
||||
if ((*equal)(e1, e2))
|
||||
{
|
||||
trouve = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!trouve)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Set::isInSet(void *e1)
|
||||
{
|
||||
int i, j;
|
||||
int trouve;
|
||||
void *e2;
|
||||
if (!e1)
|
||||
return 0;
|
||||
if (!equal)
|
||||
{
|
||||
Message("Function Equal not given", 0);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < size(); i++)
|
||||
{
|
||||
e2 = getElement(i);
|
||||
if (e1)
|
||||
{
|
||||
if ((*equal)(e1, e2))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Set::diffSet(Set *s1, Set *s2)
|
||||
{
|
||||
int i, j;
|
||||
int trouve;
|
||||
void *e1, *e2;
|
||||
int initsize;
|
||||
if (!s2)
|
||||
{
|
||||
if (s1)
|
||||
{
|
||||
for (i = 1; i < s1->size(); i++)
|
||||
{
|
||||
e1 = s1->getElement(i);
|
||||
this->addElement(e1);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!equal)
|
||||
{
|
||||
Message("Function Equal not given", 0);
|
||||
return;
|
||||
}
|
||||
initsize = s1->size();
|
||||
for (i = 0; i < initsize; i++)
|
||||
{
|
||||
e1 = s1->getElement(i);
|
||||
if (e1)
|
||||
{
|
||||
trouve = 0;
|
||||
for (j = 1; j < s2->size(); j++)
|
||||
{
|
||||
e2 = s2->getElement(j);
|
||||
if ((*equal)(e1, e2))
|
||||
{
|
||||
trouve = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!trouve)
|
||||
this->addElement(e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Set::Reallocatedata()
|
||||
{
|
||||
int i;
|
||||
void **pt;
|
||||
|
||||
pt = new void *[nballocated + ALLOCATECHUNKSET];
|
||||
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, pt, 2);
|
||||
#endif
|
||||
for (i = 0; i < nballocated + ALLOCATECHUNKSET; i++)
|
||||
pt[i] = NULL;
|
||||
|
||||
for (i = 0; i < nballocated; i++)
|
||||
pt[i] = data[i];
|
||||
|
||||
if (nballocated)
|
||||
{
|
||||
#ifdef __SPF
|
||||
removeFromCollection(data);
|
||||
#endif
|
||||
delete[] data;
|
||||
}
|
||||
data = pt;
|
||||
nballocated = nballocated + ALLOCATECHUNKSET;
|
||||
}
|
||||
|
||||
void Set::addElement(void *el)
|
||||
{
|
||||
if (!el)
|
||||
return;
|
||||
// should check if already here
|
||||
if (nbelement >= MAXELEMENT)
|
||||
{
|
||||
Message("Too many element in set", 0);
|
||||
return;
|
||||
}
|
||||
while (nballocated <= (nbelement + 1))
|
||||
{
|
||||
Reallocatedata();
|
||||
}
|
||||
data[nbelement] = el;
|
||||
nbelement++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Set *Set::compact()
|
||||
{
|
||||
int i, k;
|
||||
int trouve;
|
||||
Set *newset;
|
||||
if (!equal)
|
||||
{
|
||||
Message("Function Equal not given", 0);
|
||||
return NULL;
|
||||
}
|
||||
// look at duplicate elements, and combine (to see later) if necessary
|
||||
newset = new Set(equal, combine, printEl);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, newset, 1);
|
||||
#endif
|
||||
for (i = 0; i < this->size(); i++)
|
||||
{
|
||||
trouve = 0;
|
||||
for (k = 0; k < newset->size(); k++)
|
||||
{
|
||||
if ((*equal)(data[i], newset->data[k]))
|
||||
{
|
||||
trouve = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!trouve && data[i])
|
||||
{
|
||||
newset->addElement(data[i]);
|
||||
}
|
||||
}
|
||||
return newset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Set *Set::combineSet()
|
||||
{
|
||||
int i, j, inisize;
|
||||
int change;
|
||||
Set *newset, *temp;
|
||||
void *pt;
|
||||
int step = 0;
|
||||
if (!combine)
|
||||
{
|
||||
Message("Function Combine not given", 0);
|
||||
return NULL;
|
||||
}
|
||||
temp = this->copy();
|
||||
change = 1;
|
||||
|
||||
while (change)
|
||||
{
|
||||
step++;
|
||||
change = 0;
|
||||
inisize = temp->size();
|
||||
for (i = 0; i < inisize; i++)
|
||||
{
|
||||
for (j = i + 1; j < inisize; j++)
|
||||
{
|
||||
if (temp->getElement(i) && temp->getElement(j))
|
||||
{
|
||||
pt = combine(temp->getElement(i), temp->getElement(j));
|
||||
if (pt)
|
||||
{
|
||||
temp->addElement(pt);
|
||||
change = 1;
|
||||
temp->rmElement(j);
|
||||
temp->rmElement(i);
|
||||
}
|
||||
else
|
||||
temp->addElement(pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (step > MAXITDATAFLOW)
|
||||
{
|
||||
Message("Combine set is Looping", 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
///////////////////////////////
|
||||
// PAS DE DESALLOCATION //
|
||||
///////////////////////////////
|
||||
// newset = temp;
|
||||
// temp = temp->compact();
|
||||
// if (newset)
|
||||
// delete newset;
|
||||
return temp;
|
||||
}
|
||||
|
||||
Set *Set::copy()
|
||||
{
|
||||
int i, k;
|
||||
Set *newset;
|
||||
newset = new Set(equal, combine, printEl);
|
||||
#ifdef __SPF
|
||||
addToCollection(__LINE__, __FILE__, newset, 1);
|
||||
#endif
|
||||
for (i = 0; i < this->size(); i++)
|
||||
{
|
||||
if (data[i])
|
||||
newset->addElement(data[i]);
|
||||
}
|
||||
return newset;
|
||||
}
|
||||
|
||||
void *Set::getElement(int i) const
|
||||
{
|
||||
void *pt;
|
||||
if ((i < 0) || (i >= nbelement))
|
||||
return NULL;
|
||||
pt = data[i];
|
||||
return pt;
|
||||
}
|
||||
|
||||
void *Set::rmElement(int i)
|
||||
{
|
||||
void *pt;
|
||||
if ((i < 0) || (i >= nbelement))
|
||||
return NULL;
|
||||
pt = data[i];
|
||||
data[i] = NULL;
|
||||
return pt;
|
||||
}
|
||||
|
||||
Set::~Set()
|
||||
{
|
||||
int i;
|
||||
if (data)
|
||||
{
|
||||
if (deallocelem)
|
||||
{
|
||||
for (i = 0; i < nbelement; i++)
|
||||
{
|
||||
#ifdef __SPF
|
||||
removeFromCollection(data[i]);
|
||||
#endif
|
||||
delete [](char*)data[i];
|
||||
}
|
||||
}
|
||||
#ifdef __SPF
|
||||
removeFromCollection(data);
|
||||
#endif
|
||||
delete []data;
|
||||
}
|
||||
}
|
||||
47
Sapfor/_src/SageAnalysisTool/set.h
Normal file
47
Sapfor/_src/SageAnalysisTool/set.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sage++user.h>
|
||||
|
||||
//
|
||||
// class Set used for data flow analysis...
|
||||
//
|
||||
|
||||
class Set {
|
||||
void **data;
|
||||
int nbelement;
|
||||
int nballocated;
|
||||
int deallocelem;
|
||||
SgStatement *stmt;
|
||||
|
||||
// used to compare two elements
|
||||
int(*equal)(void *e1, void *e2);
|
||||
void *(*combine)(void *e1, void *e2);
|
||||
void(*printEl)(void *e1);
|
||||
|
||||
public:
|
||||
Set(int(*feq)(void *e1, void *e2),
|
||||
void *(*fcomb)(void *e1, void *e2),
|
||||
void(*fp)(void *e1))
|
||||
/* end of fp */;
|
||||
~Set();
|
||||
void interSet(Set *s1, Set *s2);
|
||||
void unionSet(Set *s1);
|
||||
Set *combineSet();
|
||||
void diffSet(Set *s1, Set *s2);
|
||||
int equalSet(Set *s1);
|
||||
int isInSet(void *e1);
|
||||
void setDealllocateElem() { deallocelem = 1; }
|
||||
void resetDealllocateElem() { deallocelem = 0; }
|
||||
void printSet();
|
||||
int size() const { return nbelement; }
|
||||
void addElement(void *el);
|
||||
void *rmElement(int i);
|
||||
void* getElement(int i) const;
|
||||
Set *compact();
|
||||
Set *copy();
|
||||
void setStmt(SgStatement *s) { stmt = s; }
|
||||
SgStatement* getStmt() const { return stmt; }
|
||||
// add a chunk to the size ;
|
||||
void Reallocatedata();
|
||||
};
|
||||
Reference in New Issue
Block a user