Files
SAPFOR/dvm/fdvm/trunk/Sage/lib/oldsrc/glob_anal.c
2023-09-14 19:43:13 +03:00

495 lines
13 KiB
C

/*********************************************************************/
/* pC++/Sage++ Copyright (C) 1993 */
/* Indiana University University of Oregon University of Rennes */
/*********************************************************************/
/* file: glob_anal.c */
#include <stdio.h>
#include "db.h"
#ifdef SYS5
#include <string.h>
#else
#include <strings.h>
#endif
#define MAX_FUNS 500
#ifdef __SPF
extern void addToCollection(const int line, const char *file, void *pointer, int type);
#endif
void *malloc();
void bind_call_site_info();
static PTR_FILE current_file;
extern PTR_FILE cur_file;
extern int debug;
typedef struct call_list *PTR_CALLS;
typedef struct function_decl *PTR_FUNCS;
struct call_list {
char *name;
int funs_number; /* set to the index in the funs table */
/* -1 if the function is unknown */
PTR_LLND used, modified;
PTR_BFND call_site; /* statement which holds call to this fun */
PTR_CALLS next;
};
struct function_decl {
PTR_FILE file; /* file object where this function was
* defined */
PTR_SYMB name; /* point to the symbol table of this functin */
PTR_BFND fun; /* point to the BIF node of this functio */
int is_done;
PTR_LLND used, modified;
PTR_CALLS calls;
} funs[MAX_FUNS];
int num_of_funs = 0;
static int now;
static int val[MAX_FUNS], /* keep the depth-first numbering */
ival[MAX_FUNS]; /* keep the inverse calling numbering */
/*
* visit does the depth-first numbering for nodes
* for the call graph
*
* the array "val" keep the depth-first visiting numbering
* while the array "ival" is the inverse of "val", i.e. is
* the reverse calling sequence
*/
static void visit(k)
int k;
{
PTR_CALLS p;
ival[now] = k;
val[k] = now++;
for (p = funs[k].calls; p; p = p->next) /* for each adjacent node */
if (val[p->funs_number] < 0)/* haven't visited yet */
visit(p->funs_number);
}
/*
* dfs does the depth-first search of the call graph
*/
static void dfs()
{
int k;
now = 0; /* keep track of the numbering */
for (k = 0; k < num_of_funs; k++) /* initialize to be un-read */
val[k] = -1;
for (k = 0; k < num_of_funs; k++) /* now do the depth-first search */
if (val[k] < 0)
visit(k);
}
void reset_llnd(p)
PTR_LLND p;
{
if (p == NULL)
return;
if (p->variant == VAR_REF) {
p->entry.Template.ll_ptr1 = NULL;
}
reset_llnd(p->entry.Template.ll_ptr1);
reset_llnd(p->entry.Template.ll_ptr2);
}
void reset_scalar_propogation(b)
PTR_BFND b;
{
PTR_BLOB bl;
if (b == NULL)
return;
if ((b->variant != FUNC_HEDR) && (b->variant != PROC_HEDR)) {
reset_llnd(b->entry.Template.ll_ptr1);
reset_llnd(b->entry.Template.ll_ptr2);
reset_llnd(b->entry.Template.ll_ptr3);
}
for (bl = b->entry.Template.bl_ptr1; bl; bl = bl->next)
reset_scalar_propogation(bl->ref);
for (bl = b->entry.Template.bl_ptr2; bl; bl = bl->next)
reset_scalar_propogation(bl->ref);
}
/* make_fun_decl initialized an entry in the funs table for a function at */
/* statement b */
static void make_fun_decl(f, b)
PTR_FILE f;
PTR_BFND b;
{
PTR_FUNCS i;
PTR_LLND make_llnd();
i = funs + num_of_funs++;
if (num_of_funs > MAX_FUNS) {
fprintf(stderr, "Too many functions!\n");
return;
}
/* b's ll_ptr3 points to an expr list whose ll_ptr1 is the pre global */
/* analysis use set and whose ll_ptr2 will be the post analysis use set */
if (b->entry.Template.ll_ptr3 == NULL) { /* summary of use info */
fprintf(stderr, "bad initial analysis. run vcc or cfp again\n");
b->entry.Template.ll_ptr3 = make_llnd(cur_file,EXPR_LIST,NULL, NULL, NULL);
}
if (b->entry.Template.ll_ptr2 == NULL) { /* summary of mod info */
fprintf(stderr, "bad initial analysis. run vcc or cfp again\n");
b->entry.Template.ll_ptr2 = make_llnd(cur_file,EXPR_LIST, NULL, NULL, NULL);
}
i->file = f;
i->name = b->entry.Template.symbol;
i->fun = b;
i->is_done = 0;
i->used = b->entry.Template.ll_ptr3->entry.Template.ll_ptr1;
i->modified = b->entry.Template.ll_ptr2->entry.Template.ll_ptr1;
i->calls = NULL;
}
/* call this function with the project_object */
/* to build the list of functions. */
static void make_fun_list(proj)
PTR_PROJ proj;
{
PTR_FILE f;
PTR_BLOB b1, b;
PTR_BFND p;
PTR_REFL make_name_list();
PTR_SETS alloc_sets();
/* Scan through all files in the project */
for (b1 = proj->file_chain; b1; b1 = b1->next) {
f = (PTR_FILE) b1->ref;
for (b = f->global_bfnd->entry.Template.bl_ptr1; b; b = b->next)
if (b->ref->variant == FUNC_HEDR ||
b->ref->variant == PROC_HEDR ||
b->ref->variant == PROG_HEDR) {
make_fun_decl(f, b->ref);
p = b->ref;
if (p->entry.Template.sets == NULL)
p->entry.Template.sets = alloc_sets();
p->entry.Template.sets->out_use = NULL;
p->entry.Template.sets->in_use = NULL;
p->entry.Template.sets->out_def = NULL;
p->entry.Template.sets->in_def = NULL;
p->entry.Template.sets->gen = NULL;
p->entry.Template.sets->use = NULL;
/* set in_def to be a ref list of all */
/* parameters to this proc. this is */
/* used in the global analysis phase */
p->entry.Template.sets->in_def =
make_name_list(
p->entry.Template.symbol->entry.proc_decl.in_list
);
}
}
}
/* find_by_name searches the funs list for the function whose name is */
/* given by the char string s */
static int find_by_name(PTR_FILE f, char *s)
/*PTR_FILE f;*/
/*char *s;*/
{
int i;
f = f; /* make lint happy, f unused */
for (i = 0; i < num_of_funs; i++)
if ( /* funs[i].file == f && */ (!strcmp(s, funs[i].name->ident)))
return i;
for (i = 0; i < num_of_funs; i++)
if (!strcmp(s, funs[i].name->ident))
return i;
return (-1);
}
PTR_BFND find_fun_by_name(s)
char *s;
{
int i;
i = find_by_name(NULL, s);
if (i < 0)
return NULL;
return funs[i].fun;
}
/* get_fun_number takes a pointer to a symbol table entry and looks */
/* it up in the funs table and returns the index. like the others */
/* it returns -1 if nothing is found that matches s. */
/*static int get_fun_number(f, s)
PTR_FILE f;
PTR_SYMB s;
{
int i;
for (i = 0; i < num_of_funs; i++)
if (funs[i].file == f && funs[i].name == s)
return i;
return (-1);
}*/
/* append_to_call_list takes the symbol table pointer of a function */
/* that calls another function whose name is given by a char string */
/* and appends the name of the called function to the calls list of */
/* the funs entry for the calling function. */
static void append_to_call_list(calling_fun, called_fun_ident, bf)
int calling_fun;
char *called_fun_ident;
PTR_BFND bf;
{
int called_fun;
PTR_CALLS p;
PTR_BFND b;
called_fun = find_by_name(funs[calling_fun].file, called_fun_ident);
if (called_fun == -1) {
fprintf(stderr, "Called \"%s\" function not in the project\n",
called_fun_ident);
return;
}
b = funs[calling_fun].fun;
p = (PTR_CALLS) malloc(sizeof(struct call_list));
#ifdef __SPF
addToCollection(__LINE__, __FILE__,p, 0);
#endif
p->name = b->entry.Template.symbol->ident;
p->funs_number = called_fun;
p->call_site = bf;
p->used = NULL;
p->modified = NULL;
p->next = funs[calling_fun].calls;
funs[calling_fun].calls = p;
}
static void func_call_in_llnd(ll, i, bf)
PTR_LLND ll;
int i;
PTR_BFND bf;
{
if (ll == NULL)
return;
if (ll->variant == FUNC_CALL ||
ll->variant == PROC_CALL ||
ll->variant == FUNCTION_REF)
append_to_call_list(i, ll->entry.Template.symbol->ident, bf);
/* NOTE: the following code is "tag" dependent */
if (ll->variant >= VAR_LIST && ll->variant < CONST_NAME) {
func_call_in_llnd(ll->entry.Template.ll_ptr1, i, bf);
func_call_in_llnd(ll->entry.Template.ll_ptr2, i, bf);
}
}
static void func_call_in_bfnd(bl, i)
PTR_BLOB bl;
int i;
{
PTR_BFND bf;
PTR_BLOB bl1;
for (bl1 = bl; bl1; bl1 = bl1->next) {
bf = bl1->ref;
if (bf->variant == PROC_CALL ||
bf->variant == FUNC_CALL ||
bf->variant == PROC_STAT)
append_to_call_list(i, bf->entry.Template.symbol->ident, bf);
func_call_in_llnd(bf->entry.Template.ll_ptr1, i, bf);
func_call_in_llnd(bf->entry.Template.ll_ptr2, i, bf);
func_call_in_llnd(bf->entry.Template.ll_ptr3, i, bf);
func_call_in_bfnd(bf->entry.Template.bl_ptr1, i);
func_call_in_bfnd(bf->entry.Template.bl_ptr2, i);
}
}
static void rec_list_cgraph(i)
int i;
{
func_call_in_bfnd(funs[i].fun->entry.Template.bl_ptr1, i);
}
void BuildCallGraph()
{
int i;
fprintf(stderr, "\n the call graph is:\n");
for (i = 0; i < num_of_funs; i++) {
rec_list_cgraph(i);
}
}
/*
* ready_for_analysis returns
*
* 0 if not ready
* 1 if it is ready
* 2 if analysis is done.
*/
static int ready_for_analysis(i)
int i;
{
PTR_CALLS calls;
if (funs[i].is_done == 0) {
for (calls = funs[i].calls; calls; calls = calls->next)
if (calls->funs_number > -1 &&
funs[calls->funs_number].is_done == 0)
return (0);
return (1);
}
return (2);
}
static PTR_LLND link_ll_chain(list, elist)
PTR_LLND list, elist;
{
PTR_LLND p;
p = list;
while (p != NULL && p->entry.Template.ll_ptr2 != NULL)
p = p->entry.Template.ll_ptr2;
if (p != NULL)
p->entry.Template.ll_ptr2 = elist;
else
list = elist;
return (list);
}
static PTR_LLND link_ll_set_list(b, s)
PTR_LLND s;
PTR_BFND b;
{
PTR_REFL rl, build_refl(), remove_locals_from_list();
PTR_LLND link_set_list();
rl = build_refl(b, s);
rl = remove_locals_from_list(rl);
return (link_set_list(rl));
}
static void use_mod(c)
PTR_CALLS c;
{
PTR_BFND b;
PTR_LLND used, modified;
b = c->call_site;
bind_call_site_info(b, &used, &modified);
c->used = link_ll_set_list(b, used);
c->modified = link_ll_set_list(b, modified);
}
static void compute_use_mod()
{
int modified = 1;
PTR_CALLS calls;
PTR_LLND use, mod;
int i, j;
while (modified) {
modified = 0;
for (j = num_of_funs - 1; j >= 0; j--) {
i = ival[j];
if (ready_for_analysis(i) == 1) {
if (debug) {
fprintf(stderr, "_______________________________\n");
fprintf(stderr, "doing global analysis for %s\n", funs[i].name->ident);
}
calls = funs[i].calls;
current_file = funs[i].file;
while (calls != NULL) {
if (calls->funs_number > -1 &&
funs[calls->funs_number].is_done == 1)
use_mod(calls);
calls = calls->next;
}
funs[i].is_done = 1;
/* now link results together */
use = funs[i].used;
mod = funs[i].modified;
calls = funs[i].calls;
while (calls != NULL) {
if (calls->funs_number > -1 &&
funs[calls->funs_number].is_done == 1) {
use = link_ll_chain(use, calls->used);
mod = link_ll_chain(mod, calls->modified);
}
calls = calls->next;
}
use = link_ll_set_list(funs[i].fun, use);
mod = link_ll_set_list(funs[i].fun, mod);
funs[i].used = link_ll_set_list(funs[i].fun, use);
funs[i].modified = link_ll_set_list(funs[i].fun, mod);
funs[i].fun->entry.Template.ll_ptr3
->entry.Template.ll_ptr2 = funs[i].used;
funs[i].fun->entry.Template.ll_ptr2
->entry.Template.ll_ptr2 = funs[i].modified;
modified = 1;
}
} /* end for */
} /* end while */
modified = 0;
for (i = 0; i < num_of_funs; i++) {
if (ready_for_analysis(i) == 2) {
funs[i].fun->entry.Template.ll_ptr3
->entry.Template.ll_ptr2 = funs[i].used;
funs[i].fun->entry.Template.ll_ptr2
->entry.Template.ll_ptr2 = funs[i].modified;
}
else
modified = 1;
}
if (modified && debug)
fprintf(stderr, "; cycle in call graph. no global analysis\n");
current_file = NULL;
}
/****************************************************************
* *
* GlobalAnal -- does the inter-procedural analysis for the *
* given project *
* *
* Input: *
* proj - the pointer to the project to be analized *
* *
* Output: *
* none *
* *
****************************************************************/
void GlobalAnal(proj)
PTR_PROJ proj;
{
make_fun_list(proj); /* gather all the functions declared */
BuildCallGraph(); /* build the call graph */
dfs(); /* do the depth-first search */
compute_use_mod(); /* do the inter-procedural analysis now */
}