Initial revision

This commit is contained in:
bal
1984-11-26 13:43:22 +00:00
parent 5481dd47a9
commit 7b798175ad
36 changed files with 4585 additions and 0 deletions

123
util/ego/cs/cs.h Normal file
View File

@@ -0,0 +1,123 @@
typedef short valnum;
typedef struct entity *entity_p;
typedef struct avail *avail_p;
typedef struct token *token_p;
typedef struct occur *occur_p;
struct token {
valnum tk_vn;
offset tk_size;
line_p tk_lfirst; /* Textually first instruction, involved
* in pushing this token.
*/
};
/* We distinguish these entities. */
#define ENCONST 0
#define ENLOCAL 1
#define ENEXTERNAL 2
#define ENINDIR 3
#define ENOFFSETTED 4
#define ENALOCAL 5
#define ENAEXTERNAL 6
#define ENAOFFSETTED 7
#define ENALOCBASE 8
#define ENAARGBASE 9
#define ENPROC 10
#define ENFZER 11
#define ENARRELEM 12
#define ENLOCBASE 13
#define ENHEAPPTR 14
#define ENIGNMASK 15
struct entity {
valnum en_vn;
bool en_static;
byte en_kind; /* ENLOCAL, ENEXTERNAL, etc. */
offset en_size;
union {
offset en__val; /* ENCONST. */
offset en__loc; /* ENLOCAL, ENALOCAL. */
obj_p en__ext; /* ENEXTERNAL, ENAEXTERNAL. */
valnum en__ind; /* ENINDIR. */
struct {
valnum en__base;
offset en__off;
} en_offs; /* ENOFFSETTED, ENAOFFSETTED. */
offset en__levels; /* ENALOCBASE, ENAARGBASE. */
proc_p en__pro; /* ENPROC. */
struct {
valnum en__arbase;
valnum en__index;
valnum en__adesc;
} en_arr; /* ENARRELEM. */
} en_inf;
};
/* Macros to increase ease of use. */
#define en_val en_inf.en__val
#define en_loc en_inf.en__loc
#define en_ext en_inf.en__ext
#define en_ind en_inf.en__ind
#define en_base en_inf.en_offs.en__base
#define en_off en_inf.en_offs.en__off
#define en_levels en_inf.en__levels
#define en_pro en_inf.en__pro
#define en_arbase en_inf.en_arr.en__arbase
#define en_index en_inf.en_arr.en__index
#define en_adesc en_inf.en_arr.en__adesc
struct occur {
line_p oc_lfirst; /* First instruction of expression. */
line_p oc_llast; /* Last one. */
bblock_p oc_belongs; /* Basic block it belongs to. */
};
/* We distinguish these groups of instructions. */
#define SIMPLE_LOAD 0
#define EXPENSIVE_LOAD 1
#define LOAD_ARRAY 2
#define STORE_DIRECT 3
#define STORE_INDIR 4
#define STORE_ARRAY 5
#define UNAIR_OP 6
#define BINAIR_OP 7
#define TERNAIR_OP 8
#define KILL_ENTITY 9
#define SIDE_EFFECTS 10
#define FIDDLE_STACK 11
#define IGNORE 12
#define HOPELESS 13
#define BBLOCK_END 14
struct avail {
avail_p av_before; /* Ptr to earlier discovered expressions. */
byte av_instr; /* Operator instruction. */
offset av_size;
line_p av_found; /* Line where expression is first found. */
lset av_occurs; /* Set of recurrences of expression. */
entity_p av_saveloc; /* Local where result is put in. */
valnum av_result;
union {
valnum av__operand; /* EXPENSIVE_LOAD, UNAIR_OP. */
struct {
valnum av__oleft;
valnum av__oright;
} av_2; /* BINAIR_OP. */
struct {
valnum av__ofirst;
valnum av__osecond;
valnum av__othird;
} av_3; /* TERNAIR_OP. */
} av_o;
};
/* Macros to increase ease of use. */
#define av_operand av_o.av__operand
#define av_oleft av_o.av_2.av__oleft
#define av_oright av_o.av_2.av__oright
#define av_ofirst av_o.av_3.av__ofirst
#define av_osecond av_o.av_3.av__osecond
#define av_othird av_o.av_3.av__othird
extern int Scs; /* Number of optimizations found. */

44
util/ego/cs/cs_alloc.c Normal file
View File

@@ -0,0 +1,44 @@
#include "../share/types.h"
#include "../share/alloc.h"
#include "cs.h"
occur_p newoccur(l1, l2, b)
line_p l1, l2;
bblock_p b;
{
/* Allocate a new struct occur and initialize it. */
register occur_p rop;
rop = (occur_p) newcore(sizeof(struct occur));
rop->oc_lfirst = l1; rop->oc_llast = l2; rop->oc_belongs = b;
return rop;
}
oldoccur(ocp)
occur_p ocp;
{
oldcore((short *) ocp, sizeof(struct occur));
}
avail_p newavail()
{
return (avail_p) newcore(sizeof(struct avail));
}
oldavail(avp)
avail_p avp;
{
oldcore((short *) avp, sizeof(struct avail));
}
entity_p newentity()
{
return (entity_p) newcore(sizeof(struct entity));
}
oldentity(enp)
entity_p enp;
{
oldcore((short *) enp, sizeof(struct entity));
}

24
util/ego/cs/cs_alloc.h Normal file
View File

@@ -0,0 +1,24 @@
extern occur_p newoccur(); /* (line_p l1, l2; bblock_p b)
* Returns a pointer to a new struct occur
* and initializes it.
*/
extern oldoccur(); /* (occur_p ocp)
* Release the struct occur ocp points to.
*/
extern avail_p newavail(); /* ()
* Return a pointer to a new struct avail.
*/
extern oldavail(); /* (avail_p avp)
* Release the struct avail avp points to.
*/
extern entity_p newentity(); /* ()
* Return a pointer to a new struct entity.
*/
extern oldentity(); /* (entity_p enp)
* Release the struct entity enp points to.
*/

64
util/ego/cs/cs_aux.c Normal file
View File

@@ -0,0 +1,64 @@
#include "../share/types.h"
#include "../share/debug.h"
#include "../share/aux.h"
#include "../share/global.h"
#include "../share/lset.h"
#include "cs.h"
#include "cs_entity.h"
offset array_elemsize(vn)
valnum vn;
{
/* Vn is the valuenumber of an entity that points to
* an array-descriptor. The third element of this descriptor holds
* the size of the array-elements.
* IF we can find this entity, AND IF we can find the descriptor AND IF
* this descriptor is located in ROM, then we return the size.
*/
entity_p enp;
enp = find_entity(vn);
if (enp == (entity_p) 0)
return UNKNOWN_SIZE;
if (enp->en_kind != ENAEXTERNAL)
return UNKNOWN_SIZE;
if (enp->en_ext->o_dblock->d_pseudo != DROM)
return UNKNOWN_SIZE;
return aoff(enp->en_ext->o_dblock->d_values, 2);
}
occur_p occ_elem(i)
Lindex i;
{
return (occur_p) Lelem(i);
}
entity_p en_elem(i)
Lindex i;
{
return (entity_p) Lelem(i);
}
/* The value numbers associated with each distinct value
* start at 1.
*/
STATIC valnum val_no;
valnum newvalnum()
{
/* Return a completely new value number. */
return ++val_no;
}
start_valnum()
{
/* Restart value numbering. */
val_no = 0;
}

25
util/ego/cs/cs_aux.h Normal file
View File

@@ -0,0 +1,25 @@
extern offset array_elemsize(); /* (valnum vm)
* Returns the size of array-elements,
* if vn is the valuenumber of the
* address of an array-descriptor.
*/
extern occur_p occ_elem(); /* (Lindex i)
* Returns a pointer to the occurrence
* of which i is an index in a set.
*/
extern entity_p en_elem(); /* (Lindex i)
* Returns a pointer to the entity
* of which i is an index in a set.
*/
extern valnum newvalnum(); /* ()
* Returns a completely new
* value number.
*/
extern start_valnum(); /* ()
* Restart value numbering.
*/

18
util/ego/cs/cs_avail.h Normal file
View File

@@ -0,0 +1,18 @@
extern avail_p avails; /* The set of available expressions. */
extern avail_p av_enter(); /* (avail_p avp, occur_p ocp, byte kind)
* Puts the available expression in avp
* in the list of available expressions,
* if it is not already there. Add ocp to set of
* occurrences of this expression.
* If we have a new expression, we test whether
* the result is saved. When this expression
* recurs,we test if we can still use the
* variable into which it was saved.
* (Kind is the kind of the expression.)
* Returns a pointer into the list.
*/
extern clr_avails(); /* Release all space occupied by the old list
* of available expressions.
*/

156
util/ego/cs/cs_debug.c Normal file
View File

@@ -0,0 +1,156 @@
#include <stdio.h>
#include "../../../h/em_spec.h"
#include "../share/types.h"
#include "../share/debug.h"
#include "../share/lset.h"
#include "cs.h"
#include "cs_aux.h"
#include "cs_avail.h"
#include "cs_entity.h"
#ifdef VERBOSE
extern char em_mnem[]; /* The mnemonics of the EM instructions. */
STATIC showinstr(lnp)
line_p lnp;
{
/* Makes the instruction in `lnp' human readable. Only lines that
* can occur in expressions that are going to be eliminated are
* properly handled.
*/
if (INSTR(lnp) < sp_fmnem && INSTR(lnp) > sp_lmnem) {
fprintf(stderr,"*** ?\n");
return;
}
fprintf(stderr,"%s", &em_mnem[4 * (INSTR(lnp)-sp_fmnem)]);
switch (TYPE(lnp)) {
case OPNO:
break;
case OPSHORT:
fprintf(stderr," %d", SHORT(lnp));
break;
case OPOBJECT:
fprintf(stderr," %d", OBJ(lnp)->o_id);
break;
case OPOFFSET:
fprintf(stderr," %D", OFFSET(lnp));
break;
default:
fprintf(stderr," ?");
break;
}
fprintf(stderr,"\n");
}
SHOWOCCUR(ocp)
occur_p ocp;
{
/* Shows all instructions in an occurrence. */
register line_p lnp, next;
if (verbose_flag) {
for (lnp = ocp->oc_lfirst; lnp != (line_p) 0; lnp = next) {
next = lnp == ocp->oc_llast ? (line_p) 0 : lnp->l_next;
showinstr(lnp);
}
}
}
#endif
#ifdef TRACE
SHOWAVAIL(avp)
avail_p avp;
{
/* Shows an available expression. */
showinstr(avp->av_found);
fprintf(stderr,"result %d,", avp->av_result);
fprintf(stderr,"occurred %d times\n", Lnrelems(avp->av_occurs) + 1);
}
OUTAVAILS()
{
register avail_p ravp;
fprintf(stderr,"AVAILABLE EXPRESSIONS\n");
for (ravp = avails; ravp != (avail_p) 0; ravp = ravp->av_before) {
SHOWAVAIL(ravp);
fprintf(stderr,"\n");
}
}
STATIC char *enkinds[] = {
"constant",
"local",
"external",
"indirect",
"offsetted",
"address of local",
"address of external",
"address of offsetted",
"address of local base",
"address of argument base",
"procedure",
"floating zero",
"array element",
"local base",
"heap pointer",
"ignore mask"
};
OUTENTITIES()
{
register Lindex i;
fprintf(stderr,"ENTITIES\n");
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
register entity_p rep = en_elem(i);
fprintf(stderr,"%s,", enkinds[rep->en_kind]);
fprintf(stderr,"size %D,", rep->en_size);
fprintf(stderr,"valno %d,", rep->en_vn);
switch (rep->en_kind) {
case ENCONST:
fprintf(stderr,"$%D\n", rep->en_val);
break;
case ENLOCAL:
case ENALOCAL:
fprintf(stderr,"%D(LB)\n", rep->en_loc);
break;
case ENINDIR:
fprintf(stderr,"*%d\n", rep->en_ind);
break;
case ENOFFSETTED:
case ENAOFFSETTED:
fprintf(stderr,"%D(%d)\n", rep->en_off, rep->en_base);
break;
case ENALOCBASE:
case ENAARGBASE:
fprintf(stderr,"%D levels\n", rep->en_levels);
break;
case ENARRELEM:
fprintf(stderr,"%d[%d], ",rep->en_arbase,rep->en_index);
fprintf(stderr,"rom at %d\n", rep->en_adesc);
break;
}
fprintf(stderr,"\n");
}
}
/* XXX */
OUTTRACE(s, n)
char *s;
{
fprintf(stderr,"trace: ");
fprintf(stderr,s, n);
fprintf(stderr,"\n");
}
#endif TRACE

33
util/ego/cs/cs_debug.h Normal file
View File

@@ -0,0 +1,33 @@
#ifdef VERBOSE
extern SHOWOCCUR(); /* (occur_p ocp)
* Shows all lines in an occurrence.
*/
#else
#define SHOWOCCUR(x)
#endif
#ifdef TRACE
extern OUTAVAILS(); /* ()
* Prints all available expressions.
*/
extern OUTENTITIES(); /* ()
* Prints all entities.
*/
extern SHOWAVAIL(); /* (avail_p avp)
* Shows an available expression.
*/
#else TRACE
#define OUTAVAILS()
#define OUTENTITIES()
#define SHOWAVAIL(x)
#endif TRACE

142
util/ego/cs/cs_entity.c Normal file
View File

@@ -0,0 +1,142 @@
/* F U N C T I O N S F O R A C C E S S I N G T H E S E T
*
* O F E N T I T I E S
*/
#include "../share/types.h"
#include "../share/global.h"
#include "../share/lset.h"
#include "../share/debug.h"
#include "cs.h"
#include "cs_alloc.h"
#include "cs_aux.h"
lset entities; /* Our pseudo symbol-table. */
entity_p find_entity(vn)
valnum vn;
{
/* Try to find the entity with valuenumber vn. */
register Lindex i;
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
if (en_elem(i)->en_vn == vn)
return en_elem(i);
}
return (entity_p) 0;
}
STATIC bool same_entity(enp1, enp2)
entity_p enp1, enp2;
{
if (enp1->en_kind != enp2->en_kind) return FALSE;
if (enp1->en_size != enp2->en_size) return FALSE;
if (enp1->en_size == UNKNOWN_SIZE) return FALSE;
switch (enp1->en_kind) {
case ENCONST:
return enp1->en_val == enp2->en_val;
case ENLOCAL:
case ENALOCAL:
return enp1->en_loc == enp2->en_loc;
case ENEXTERNAL:
case ENAEXTERNAL:
return enp1->en_ext == enp2->en_ext;
case ENINDIR:
return enp1->en_ind == enp2->en_ind;
case ENOFFSETTED:
case ENAOFFSETTED:
return enp1->en_base == enp2->en_base &&
enp1->en_off == enp2->en_off;
case ENALOCBASE:
case ENAARGBASE:
return enp1->en_levels == enp2->en_levels;
case ENPROC:
return enp1->en_pro == enp2->en_pro;
case ENARRELEM:
return enp1->en_arbase == enp2->en_arbase &&
enp1->en_index == enp2->en_index &&
enp1->en_adesc == enp2->en_adesc;
default:
return TRUE;
}
}
STATIC copy_entity(src, dst)
entity_p src, dst;
{
dst->en_static = src->en_static;
dst->en_kind = src->en_kind;
dst->en_size = src->en_size;
switch (src->en_kind) {
case ENCONST:
dst->en_val = src->en_val;
break;
case ENLOCAL:
case ENALOCAL:
dst->en_loc = src->en_loc;
break;
case ENEXTERNAL:
case ENAEXTERNAL:
dst->en_ext = src->en_ext;
break;
case ENINDIR:
dst->en_ind = src->en_ind;
break;
case ENOFFSETTED:
case ENAOFFSETTED:
dst->en_base = src->en_base;
dst->en_off = src->en_off;
break;
case ENALOCBASE:
case ENAARGBASE:
dst->en_levels = src->en_levels;
break;
case ENPROC:
dst->en_pro = src->en_pro;
break;
case ENARRELEM:
dst->en_arbase = src->en_arbase;
dst->en_index = src->en_index;
dst->en_adesc = src->en_adesc;
break;
}
}
entity_p en_enter(enp)
register entity_p enp;
{
/* Put the entity in enp in the entity set, if it is not already there.
* Return pointer to stored entity.
*/
register Lindex i;
register entity_p new;
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
if (same_entity(en_elem(i), enp))
return en_elem(i);
}
/* A new entity. */
new = newentity();
new->en_vn = newvalnum();
copy_entity(enp, new);
Ladd(new, &entities);
return new;
}
clr_entities()
{
/* Throw away all pseudo-symboltable information. */
register Lindex i;
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
oldentity(en_elem(i));
}
Ldeleteset(entities);
entities = Lempty_set();
}

15
util/ego/cs/cs_entity.h Normal file
View File

@@ -0,0 +1,15 @@
extern lset entities; /* The pseudo-symboltable. */
extern entity_p find_entity(); /* (valnum vn)
* Tries to find an entity with value number vn.
*/
extern entity_p en_enter(); /* (entity_p enp)
* Enter the entity in enp in the set of
* entities if it was not already there.
*/
extern clr_entities(); /* ()
* Release all space occupied by our
* pseudo-symboltable.
*/

372
util/ego/cs/cs_kill.c Normal file
View File

@@ -0,0 +1,372 @@
#include "../../../h/em_mnem.h"
#include "../share/types.h"
#include "../share/debug.h"
#include "../share/global.h"
#include "../share/lset.h"
#include "../share/cset.h"
#include "../share/aux.h"
#include "../share/map.h"
#include "cs.h"
#include "cs_aux.h"
#include "cs_debug.h"
#include "cs_avail.h"
#include "cs_entity.h"
STATIC base_valno(enp)
entity_p enp;
{
/* Return the value number of the (base) address of an indirectly
* accessed entity.
*/
switch (enp->en_kind) {
default:
assert(FALSE);
break;
case ENINDIR:
return enp->en_ind;
case ENOFFSETTED:
return enp->en_base;
case ENARRELEM:
return enp->en_arbase;
}
/* NOTREACHED */
}
STATIC entity_p find_base(vn)
valnum vn;
{
/* Vn is the valuenumber of the (base) address of an indirectly
* accessed entity. Return the entity that holds this address
* recursively.
*/
register Lindex i;
register avail_p ravp;
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
register entity_p renp = en_elem(i);
if (renp->en_vn == vn) {
switch (renp->en_kind) {
case ENAEXTERNAL:
case ENALOCAL:
case ENALOCBASE:
case ENAARGBASE:
return renp;
case ENAOFFSETTED:
return find_base(renp->en_base);
}
}
}
/* We couldn't find it among the entities.
* Let's try the available expressions.
*/
for (ravp = avails; ravp != (avail_p) 0; ravp = ravp->av_before) {
if (ravp->av_result == vn) {
if (ravp->av_instr == (byte) op_aar)
return find_base(ravp->av_ofirst);
if (ravp->av_instr == (byte) op_ads)
return find_base(ravp->av_oleft);
}
}
/* Bad luck. */
return (entity_p) 0;
}
STATIC bool obj_overlap(op1, op2)
obj_p op1, op2;
{
/* Op1 and op2 point to two objects in the same datablock.
* Obj_overlap returns whether these objects might overlap.
*/
obj_p tmp;
if (op1->o_off > op2->o_off) {
/* Exchange them. */
tmp = op1; op1 = op2; op2 = tmp;
}
return op1->o_size == UNKNOWN_SIZE ||
op1->o_off + op1->o_size > op2->o_off;
}
#define same_datablock(o1, o2) ((o1)->o_dblock == (o2)->o_dblock)
STATIC bool addr_local(enp)
entity_p enp;
{
/* Is enp the address of a stack item. */
if (enp == (entity_p) 0) return FALSE;
return enp->en_kind == ENALOCAL || enp->en_kind == ENALOCBASE ||
enp->en_kind == ENAARGBASE;
}
STATIC bool addr_external(enp)
entity_p enp;
{
/* Is enp the address of an external. */
return enp != (entity_p) 0 && enp->en_kind == ENAEXTERNAL;
}
STATIC kill_external(obp, indir)
obj_p obp;
int indir;
{
/* A store is done via the object in obp. If this store is direct
* we kill directly accessed entities in the same data block only
* if they overlap with obp, otherwise we kill everything in the
* data block. Indirectly accessed entities of which it can not be
* proven taht they are not in the same data block, are killed in
* both cases.
*/
register Lindex i;
OUTTRACE("kill external", 0);
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
entity_p enp = en_elem(i);
entity_p base;
switch (enp->en_kind) {
case ENEXTERNAL:
if (!same_datablock(enp->en_ext, obp))
break;
if (!indir && !obj_overlap(enp->en_ext, obp))
break;
OUTTRACE("kill %d", enp->en_vn);
enp->en_vn = newvalnum();
break;
case ENINDIR:
case ENOFFSETTED:
case ENARRELEM:
/* We spare its value number if we are sure
* that its (base) address points into the
* stack or into another data block.
*/
base = find_base(base_valno(enp));
if (addr_local(base))
break;
if (addr_external(base) &&
!same_datablock(base->en_ext, obp)
)
break;
OUTTRACE("kill %d", enp->en_vn);
enp->en_vn = newvalnum();
break;
}
}
}
STATIC bool loc_overlap(enp1, enp2)
entity_p enp1, enp2;
{
/* Enp1 and enp2 point to two locals. Loc_overlap returns whether
* they overlap.
*/
entity_p tmp;
assert(enp1->en_kind == ENLOCAL && enp2->en_kind == ENLOCAL);
if (enp1->en_loc > enp2->en_loc) {
/* Exchange them. */
tmp = enp1; enp1 = enp2; enp2 = tmp;
}
if (enp1->en_loc < 0 && enp2->en_loc >= 0)
return FALSE; /* Locals and parameters do not overlap. */
else return enp1->en_size == UNKNOWN_SIZE ||
enp1->en_loc + enp1->en_size > enp2->en_loc;
}
STATIC kill_local(enp, indir)
entity_p enp;
bool indir;
{
/* This time a store is done into an ENLOCAL. */
register Lindex i;
OUTTRACE("kill local", 0);
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
entity_p rep = en_elem(i);
entity_p base;
switch (rep->en_kind) {
case ENLOCAL:
if (indir) {
/* Kill locals that might be stored into
* via a pointer. Note: enp not used.
*/
if (!is_regvar(rep->en_loc)) {
OUTTRACE("kill %d", rep->en_vn);
rep->en_vn = newvalnum();
}
} else if (loc_overlap(rep, enp)) {
/* Only kill overlapping locals. */
OUTTRACE("kill %d", rep->en_vn);
rep->en_vn = newvalnum();
}
break;
case ENINDIR:
case ENOFFSETTED:
case ENARRELEM:
if (!is_regvar(enp->en_loc)) {
base = find_base(base_valno(rep));
if (!addr_external(base)) {
OUTTRACE("kill %d", rep->en_vn);
rep->en_vn = newvalnum();
}
}
break;
}
}
}
STATIC kill_sim()
{
/* A store is done into the ENIGNMASK. */
register Lindex i;
OUTTRACE("kill sim", 0);
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
register entity_p rep = en_elem(i);
if (rep->en_kind == ENIGNMASK) {
OUTTRACE("kill %d", rep->en_vn);
rep->en_vn = newvalnum();
return; /* There is only one ignoremask. */
}
}
}
kill_direct(enp)
entity_p enp;
{
/* A store will be done into enp. We must forget the values of all the
* entities this one may overlap with.
*/
switch (enp->en_kind) {
default:
assert(FALSE);
break;
case ENEXTERNAL:
kill_external(enp->en_ext, FALSE);
break;
case ENLOCAL:
kill_local(enp, FALSE);
break;
case ENIGNMASK:
kill_sim();
break;
}
}
kill_indir(enp)
entity_p enp;
{
/* An indirect store is done, in an ENINDIR,
* an ENOFFSETTED or an ENARRELEM.
*/
entity_p p;
/* If we can find the (base) address of this entity, then we can spare
* the entities that are provably not pointed to by the address.
* We will also make use of the MES 3 pseudo's, generated by
* the front-end. When a MES 3 is generated for a local, this local
* will not be referenced indirectly.
*/
if ((p = find_base(base_valno(enp))) == (entity_p) 0) {
kill_much(); /* Kill all entities without registermessage. */
} else {
switch (p->en_kind) {
case ENAEXTERNAL:
/* An indirect store into global data. */
kill_external(p->en_ext, TRUE);
break;
case ENALOCAL:
case ENALOCBASE:
case ENAARGBASE:
/* An indirect store into stack data. */
kill_local(p, TRUE);
break;
}
}
}
kill_much()
{
/* Kills all killable entities,
* except the locals for which a registermessage was generated.
*/
register Lindex i;
OUTTRACE("kill much", 0);
for (i = Lfirst(entities); i != (Lindex) i; i = Lnext(i, entities)) {
register entity_p rep = en_elem(i);
if (rep->en_static) continue;
if (rep->en_kind == ENLOCAL && is_regvar(rep->en_loc)) continue;
OUTTRACE("kill %d", rep->en_vn);
rep->en_vn = newvalnum();
}
}
STATIC bool bad_procflags(pp)
proc_p pp;
{
/* Return whether the flags about the procedure in pp indicate
* that we have little information about it. It might be that
* we haven't seen the text of pp, or that we have seen that pp
* calls a procedure which we haven't seen the text of.
*/
return !(pp->p_flags1 & PF_BODYSEEN) || (pp->p_flags1 & PF_CALUNKNOWN);
}
STATIC kill_globset(s)
cset s;
{
/* S is a set of global variables that might be changed.
* We act as if a direct store is done into each of them.
*/
register Cindex i;
OUTTRACE("kill globset", 0);
for (i = Cfirst(s); i != (Cindex) 0; i = Cnext(i,s)) {
kill_external(omap[Celem(i)], FALSE);
}
}
kill_call(pp)
proc_p pp;
{
/* Kill everything that might be destroyed by calling
* the procedure in pp.
*/
if (bad_procflags(pp)) {
/* We don't know enough about this procedure. */
kill_much();
} else if (pp->p_change->c_flags & CF_INDIR) {
/* The procedure does an indirect store. */
kill_much();
} else {
/* Procedure might affect global data. */
kill_globset(pp->p_change->c_ext);
}
}
kill_all()
{
/* Kills all entities. */
register Lindex i;
OUTTRACE("kill all entities", 0);
for (i = Lfirst(entities); i != (Lindex) i; i = Lnext(i, entities)) {
entity_p enp = en_elem(i);
OUTTRACE("kill %d", enp->en_vn);
enp->en_vn = newvalnum();
}
}

24
util/ego/cs/cs_kill.h Normal file
View File

@@ -0,0 +1,24 @@
extern kill_call(); /* (proc_p pp)
* Kill all entities that might have an other value
* after execution of the procedure in pp.
*/
extern kill_much(); /* ()
* Kill all killable entities except those for which
* a register message was generated.
* Constants, addresses, etc are not killable.
*/
extern kill_indir(); /* (entity_p enp)
* Kill all entities that might have an other value
* after indirect assignment to the entity in enp.
*/
extern kill_direct(); /* (entity_p enp)
* Kill all entities that might have an other value
* after direct assignment to the entity in enp.
*/
extern kill_all(); /* ()
* Kill all entities.
*/

10
util/ego/cs/cs_profit.h Normal file
View File

@@ -0,0 +1,10 @@
extern cs_machinit(); /* (FILE *f)
* Read phase-specific information from f.
*/
extern bool desirable(); /* (avail_p avp)
* Return whether it is desirable to eliminate
* the recurrences of the expression in avp.
* At the same time delete the recurrences
* for which it is not allowed.
*/

132
util/ego/cs/cs_stack.c Normal file
View File

@@ -0,0 +1,132 @@
/*
* S T A C K M O D U L E
*/
#include "../share/types.h"
#include "../share/global.h"
#include "../share/debug.h"
#include "../share/aux.h"
#include "cs.h"
#include "cs_aux.h"
#define STACK_DEPTH 50
STATIC struct token Stack[STACK_DEPTH];
STATIC token_p free_token;
#define Delete_top() {--free_token; }
#define Empty_stack() {free_token = &Stack[0]; }
#define Stack_empty() (free_token == &Stack[0])
#define Top (free_token - 1)
Push(tkp)
token_p tkp;
{
if (tkp->tk_size == UNKNOWN_SIZE) {
Empty_stack(); /* The contents of the Stack is useless. */
} else {
assert(free_token < &Stack[STACK_DEPTH]);
free_token->tk_vn = tkp->tk_vn;
free_token->tk_size = tkp->tk_size;
free_token++->tk_lfirst = tkp->tk_lfirst;
}
}
#define WORD_MULTIPLE(n) ((n / ws) * ws + ( n % ws ? ws : 0 ))
Pop(tkp, size)
token_p tkp;
offset size;
{
/* Pop a token with given size from the valuenumber stack into tkp. */
/* First simple case. */
if (size != UNKNOWN_SIZE && !Stack_empty() && size == Top->tk_size) {
tkp->tk_vn = Top->tk_vn;
tkp->tk_size = size;
tkp->tk_lfirst = Top->tk_lfirst;
Delete_top();
return;
}
/* Now we're in trouble: we must pop something that is not there!
* We just put a dummy into tkp and pop tokens until we've
* popped size bytes.
*/
/* Create dummy. */
tkp->tk_vn = newvalnum();
tkp->tk_lfirst = (line_p) 0;
/* Now fiddle with the Stack. */
if (Stack_empty()) return;
if (size == UNKNOWN_SIZE) {
Empty_stack();
return;
}
if (size > Top->tk_size) {
while (!Stack_empty() && size >= Top->tk_size) {
size -= Top->tk_size;
Delete_top();
}
}
/* Now Stack_empty OR size < Top->tk_size. */
if (!Stack_empty()) {
if (Top->tk_size - size < ws) {
Delete_top();
} else {
Top->tk_vn = newvalnum();
Top->tk_size -= WORD_MULTIPLE(size);
}
}
}
Dup(lnp)
line_p lnp;
{
/* Duplicate top bytes on the Stack. */
register token_p bottom = Top;
register token_p oldtop = Top;
register offset nbytes = off_set(lnp);
struct token dummy;
/* Find the bottom of the bytes to be duplicated.
* It is possible that we cannot find it.
*/
while (bottom > &Stack[0] && bottom->tk_size < nbytes) {
nbytes -= bottom->tk_size;
bottom--;
}
if (bottom < &Stack[0]) {
/* There was nothing. */
dummy.tk_vn = newvalnum();
dummy.tk_size = nbytes;
dummy.tk_lfirst = lnp;
Push(&dummy);
} else {
if (bottom->tk_size < nbytes) {
/* Not enough, bottom == &Stack[0]. */
dummy.tk_vn = newvalnum();
dummy.tk_size = nbytes - bottom->tk_size;
dummy.tk_lfirst = lnp;
Push(&dummy);
} else if (bottom->tk_size > nbytes) {
/* Not integral # tokens. */
dummy.tk_vn = newvalnum();
dummy.tk_size = nbytes;
dummy.tk_lfirst = lnp;
Push(&dummy);
bottom++;
}
/* Bottom points to lowest token to be dupped. */
while (bottom <= oldtop) {
Push(bottom++);
Top->tk_lfirst = lnp;
}
}
}
clr_stack()
{
free_token = &Stack[0];
}

18
util/ego/cs/cs_stack.h Normal file
View File

@@ -0,0 +1,18 @@
extern Push(); /* (token_p tkp)
* Push the token in tkp on the fake-stack.
*/
extern Pop(); /* (token_p tkp; offset size)
* Pop a token of size bytes from the fake-stack
* into tkp. If such a token is not there
* we put a dummy in tkp and adjust the fake-stack.
*/
extern Dup(); /* (line_p lnp)
* Reflect the changes made by the dup-instruction
* in lnp to the EM-stack into the fake-stack.
*/
extern clr_stack(); /* ()
* Clear the fake-stack.
*/

4
util/ego/cs/cs_vnm.h Normal file
View File

@@ -0,0 +1,4 @@
extern vnm(); /* (bblock_p bp)
* Performs the valuenumbering algorithm on the basic
* block in bp.
*/