home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.cs.arizona.edu
/
ftp.cs.arizona.edu.tar
/
ftp.cs.arizona.edu
/
icon
/
historic
/
v92.tgz
/
v92.tar
/
v92
/
src
/
iconc
/
lifetime.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-22
|
14KB
|
497 lines
/*
* lifetime.c - perform liveness analysis to determine lifetime of intermediate
* results.
*/
#include "::h:gsupport.h"
#include "::h:lexdef.h"
#include "ctrans.h"
#include "cglobals.h"
#include "ctree.h"
#include "ctoken.h"
#include "csym.h"
#include "ccode.h"
#include "cproto.h"
/*
* Prototypes for static functions.
*/
hidden novalue arg_life Params((nodeptr n, long min_result, long max_result,
int resume, int frst_arg, int nargs, nodeptr resumer,
nodeptr *failer, int *gen));
static int postn = -1; /* relative position in execution order (all neg) */
/*
* liveness - compute lifetimes of intermediate results.
*/
novalue liveness(n, resumer, failer, gen)
nodeptr n;
nodeptr resumer;
nodeptr *failer;
int *gen;
{
struct loop {
nodeptr resumer;
int gen;
nodeptr lifetime;
int every_cntrl;
struct loop *prev;
} loop_info;
struct loop *loop_sav;
static struct loop *cur_loop = NULL;
nodeptr failer1;
nodeptr failer2;
int gen1 = 0;
int gen2 = 0;
struct node *cases;
struct node *clause;
long min_result; /* minimum result sequence length */
long max_result; /* maximum result sequence length */
int resume; /* flag - resumption possible after last result */
n->postn = postn--;
switch (n->n_type) {
case N_Activat:
/*
* Activation can fail or succeed.
*/
arg_life(n, 0L, 1L, 0, 1, 2, resumer, failer, gen);
break;
case N_Alt:
Tree1(n)->lifetime = n->lifetime;
Tree0(n)->lifetime = n->lifetime;
liveness(Tree1(n), resumer, &failer2, &gen2);
liveness(Tree0(n), resumer, &failer1, &gen1);
*failer = failer2;
*gen = 1;
break;
case N_Apply:
/*
* Assume operation can suspend or fail.
*/
arg_life(n, 0L, UnbndSeq, 1, 0, 2, resumer, failer, gen);
break;
case N_Augop:
/*
* Impl0(n) is assignment. Impl1(n) is the augmented operation.
*/
min_result = Impl0(n)->min_result * Impl1(n)->min_result;
max_result = Impl0(n)->max_result * Impl1(n)->max_result;
resume = Impl0(n)->resume | Impl1(n)->resume;
arg_life(n, min_result, max_result, resume, 2, 2, resumer, failer,
gen);
break;
case N_Bar:
if (resumer == NULL)
n->intrnl_lftm = n;
else
n->intrnl_lftm = resumer;
Tree0(n)->lifetime = n->lifetime;
liveness(Tree0(n), resumer, failer, &gen1);
*gen = 1;
break;
case N_Break:
if (cur_loop == NULL) {
nfatal(n, "invalid context for break", NULL);
return;
}
Tree0(n)->lifetime = cur_loop->lifetime;
loop_sav = cur_loop;
cur_loop = cur_loop->prev;
liveness(Tree0(n), loop_sav->resumer, &failer1, &gen1);
cur_loop = loop_sav;
cur_loop->gen |= gen1;
*failer = NULL;
*gen = 0;
break;
case N_Case:
*failer = resumer;
*gen = 0;
cases = Tree1(n);
while (cases != NULL) {
if (cases->n_type == N_Ccls) {
clause = cases;
cases = NULL;
}
else {
clause = Tree1(cases);
cases = Tree0(cases);
}
/*
* Body.
*/
Tree1(clause)->lifetime = n->lifetime;
liveness(Tree1(clause), resumer, &failer2, &gen2);
if (resumer == NULL && failer2 != NULL)
*failer = n;
*gen |= gen2;
/*
* The expression being compared can be resumed.
*/
Tree0(clause)->lifetime = clause;
liveness(Tree0(clause), clause, &failer1, &gen1);
}
if (Tree2(n) == NULL) {
if (resumer == NULL)
*failer = n;
}
else {
Tree2(n)->lifetime = n->lifetime;
liveness(Tree2(n), resumer, &failer2, &gen2); /* default */
if (resumer == NULL && failer2 != NULL)
*failer = n;
*gen |= gen2;
}
/*
* control clause is bounded
*/
Tree0(n)->lifetime = n;
liveness(Tree0(n), NULL, &failer1, &gen1);
if (failer1 != NULL && *failer == NULL)
*failer = failer1;
break;
case N_Create:
Tree0(n)->lifetime = n;
loop_sav = cur_loop;
cur_loop = NULL; /* check for invalid break and next */
liveness(Tree0(n), n, &failer1, &gen1);
cur_loop = loop_sav;
*failer = NULL;
*gen = 0;
break;
case N_Cset:
case N_Empty:
case N_Id:
case N_Int:
case N_Real:
case N_Str:
*failer = resumer;
*gen = 0;
break;
case N_Field:
Tree0(n)->lifetime = n;
liveness(Tree0(n), resumer, failer, gen);
break;
case N_If:
Tree1(n)->lifetime = n->lifetime;
liveness(Tree1(n), resumer, failer, gen);
if (Tree2(n)->n_type != N_Empty) {
Tree2(n)->lifetime = n->lifetime;
liveness(Tree2(n), resumer, &failer2, &gen2);
if (failer2 != NULL) {
if (*failer == NULL)
*failer = failer2;
else {
if ((*failer)->postn < failer2->postn)
*failer = failer2;
if ((*failer)->postn < n->postn)
*failer = n;
}
}
*gen |= gen2;
}
/*
* control clause is bounded
*/
Tree0(n)->lifetime = NULL;
liveness(Tree0(n), NULL, &failer1, &gen1);
if (Tree2(n)->n_type == N_Empty && failer1 != NULL && *failer == NULL)
*failer = failer1;
break;
case N_Invok:
/*
* Assume operation can suspend and fail.
*/
arg_life(n, 0L, UnbndSeq, 1, 1, Val0(n) + 1, resumer, failer, gen);
break;
case N_InvOp:
arg_life(n, Impl1(n)->min_result, Impl1(n)->max_result,
Impl1(n)->resume, 2, Val0(n), resumer, failer, gen);
break;
case N_InvProc:
if (Proc1(n)->ret_flag & DoesFail)
min_result = 0L;
else
min_result = 1L;
if (Proc1(n)->ret_flag & DoesSusp) {
max_result = UnbndSeq;
resume = 1;
}
else {
max_result = 1L;
resume = 0;
}
arg_life(n, min_result, max_result, resume, 2, Val0(n), resumer,
failer, gen);
break;
case N_InvRec:
arg_life(n, err_conv ? 0L : 1L, 1L, 1, 2, Val0(n), resumer, failer,
gen);
break;
case N_Limit:
if (resumer == NULL)
n->intrnl_lftm = n;
else
n->intrnl_lftm = resumer;
Tree0(n)->lifetime = n->lifetime;
liveness(Tree0(n), resumer, &failer1, &gen1);
Tree1(n)->lifetime = n;
liveness(Tree1(n), failer1 == NULL ? n : failer1, &failer2, &gen2);
*failer = failer2;
*gen = gen1 | gen2;
break;
case N_Loop: {
loop_info.prev = cur_loop;
loop_info.resumer = resumer;
loop_info.gen = 0;
loop_info.every_cntrl = 0;
loop_info.lifetime = n->lifetime;
cur_loop = &loop_info;
switch ((int)Val0(Tree0(n))) {
case EVERY:
/*
* The body is bounded. The control clause is resumed
* by the control structure.
*/
Tree2(n)->lifetime = NULL;
liveness(Tree2(n), NULL, &failer2, &gen2);
loop_info.every_cntrl = 1;
Tree1(n)->lifetime = NULL;
liveness(Tree1(n), n, &failer1, &gen1);
break;
case REPEAT:
/*
* The body is bounded.
*/
Tree1(n)->lifetime = NULL;
liveness(Tree1(n), NULL, &failer1, &gen1);
break;
case SUSPEND:
/*
* The body is bounded. The control clause is resumed
* by the control structure.
*/
Tree2(n)->lifetime = NULL;
liveness(Tree2(n), NULL, &failer2, &gen2);
loop_info.every_cntrl = 1;
Tree1(n)->lifetime = n;
liveness(Tree1(n), n, &failer1, &gen1);
break;
case WHILE:
case UNTIL:
/*
* The body and the control clause are each bounded.
*/
Tree2(n)->lifetime = NULL;
liveness(Tree2(n), NULL, &failer1, &gen1);
Tree1(n)->lifetime = NULL;
liveness(Tree1(n), NULL, &failer1, &gen1);
break;
}
*failer = (resumer == NULL ? n : resumer); /* assume a loop can fail */
*gen = cur_loop->gen;
cur_loop = cur_loop->prev;
}
break;
case N_Next:
if (cur_loop == NULL) {
nfatal(n, "invalid context for next", NULL);
return;
}
if (cur_loop->every_cntrl)
*failer = n;
else
*failer = NULL;
*gen = 0;
break;
case N_Not:
/*
* The expression is bounded.
*/
Tree0(n)->lifetime = NULL;
liveness(Tree0(n), NULL, &failer1, &gen1);
*failer = (resumer == NULL ? n : resumer);
*gen = 0;
break;
case N_Ret:
if (Val0(Tree0(n)) == RETURN) {
/*
* The expression is bounded.
*/
Tree1(n)->lifetime = n;
liveness(Tree1(n), NULL, &failer1, &gen1);
}
*failer = NULL;
*gen = 0;
break;
case N_Scan: {
struct implement *asgn_impl;
if (resumer == NULL)
n->intrnl_lftm = n;
else
n->intrnl_lftm = resumer;
if (optab[Val0(Tree0(n))].tok.t_type == AUGQMARK) {
asgn_impl = optab[asgn_loc].binary;
arg_life(n, asgn_impl->min_result, asgn_impl->max_result,
asgn_impl->resume, 1, 2, resumer, failer, gen);
}
else {
Tree2(n)->lifetime = n->lifetime;
liveness(Tree2(n), resumer, &failer2, &gen2); /* body */
Tree1(n)->lifetime = n;
liveness(Tree1(n), failer2, &failer1, &gen1); /* subject */
*failer = failer1;
*gen = gen1 | gen2;
}
}
break;
case N_Sect:
/*
* Impl0(n) is sectioning.
*/
min_result = Impl0(n)->min_result;
max_result = Impl0(n)->max_result;
resume = Impl0(n)->resume;
if (Impl1(n) != NULL) {
/*
* Impl1(n) is plus or minus.
*/
min_result *= Impl1(n)->min_result;
max_result *= Impl1(n)->max_result;
resume |= Impl1(n)->resume;
}
arg_life(n, min_result, max_result, resume, 2, 3, resumer, failer,
gen);
break;
case N_Slist:
/*
* expr1 is not bounded, expr0 is bounded.
*/
Tree1(n)->lifetime = n->lifetime;
liveness(Tree1(n), resumer, failer, gen);
Tree0(n)->lifetime = NULL;
liveness(Tree0(n), NULL, &failer1, &gen1);
break;
case N_SmplAsgn:
Tree3(n)->lifetime = n;
liveness(Tree3(n), resumer, failer, gen); /* 2nd operand */
Tree2(n)->lifetime = n->lifetime; /* may be result of := */
liveness(Tree2(n), *failer, &failer1, &gen1); /* 1st operand */
break;
case N_SmplAug:
/*
* Impl1(n) is the augmented operation.
*/
arg_life(n, Impl1(n)->min_result, Impl1(n)->max_result,
Impl1(n)->resume, 2, 2, resumer, failer, gen);
break;
default:
fprintf(stderr, "compiler error: node type %d unknown\n", n->n_type);
exit(ErrorExit);
}
}
/*
* arg_life - compute the lifetimes of an argument list.
*/
static novalue arg_life(n, min_result, max_result, resume, frst_arg, nargs,
resumer, failer, gen)
nodeptr n;
long min_result; /* minimum result sequence length */
long max_result; /* maximum result sequence length */
int resume; /* flag - resumption possible after last result */
int frst_arg;
int nargs;
nodeptr resumer;
nodeptr *failer;
int *gen;
{
nodeptr failer1;
nodeptr failer2;
nodeptr lifetime;
int inv_fail; /* failure after operation in invoked */
int reuse;
int gen2;
int i;
/*
* Determine what, if anything, can resume the rightmost argument.
*/
if (resumer == NULL && min_result == 0)
failer1 = n;
else
failer1 = resumer;
if (failer1 == NULL)
inv_fail = 0;
else
inv_fail = 1;
/*
* If the operation can be resumed, variables internal to the operation
* have and extended lifetime.
*/
if (resumer != NULL && (max_result > 1 || max_result == UnbndSeq || resume))
n->intrnl_lftm = resumer;
else
n->intrnl_lftm = n;
/*
* Go through the parameter list right to left, propagating resumption
* information, computing lifetimes, and determining whether anything
* can generate.
*/
lifetime = n;
reuse = 0;
*gen = 0;
for (i = frst_arg + nargs - 1; i >= frst_arg; --i) {
n->n_field[i].n_ptr->lifetime = lifetime;
n->n_field[i].n_ptr->reuse = reuse;
liveness(n->n_field[i].n_ptr, failer1, &failer2, &gen2);
if (resumer != NULL && gen2)
lifetime = resumer;
if (inv_fail && gen2)
reuse = 1;
failer1 = failer2;
*gen |= gen2;
}
*failer = failer1;
if (max_result > 1 || max_result == UnbndSeq)
*gen = 1;
}