Initial revision
This commit is contained in:
123
util/ego/cs/cs.h
Normal file
123
util/ego/cs/cs.h
Normal 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
44
util/ego/cs/cs_alloc.c
Normal 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
24
util/ego/cs/cs_alloc.h
Normal 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
64
util/ego/cs/cs_aux.c
Normal 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
25
util/ego/cs/cs_aux.h
Normal 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
18
util/ego/cs/cs_avail.h
Normal 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
156
util/ego/cs/cs_debug.c
Normal 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
33
util/ego/cs/cs_debug.h
Normal 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
142
util/ego/cs/cs_entity.c
Normal 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
15
util/ego/cs/cs_entity.h
Normal 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
372
util/ego/cs/cs_kill.c
Normal 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
24
util/ego/cs/cs_kill.h
Normal 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
10
util/ego/cs/cs_profit.h
Normal 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
132
util/ego/cs/cs_stack.c
Normal 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
18
util/ego/cs/cs_stack.h
Normal 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
4
util/ego/cs/cs_vnm.h
Normal file
@@ -0,0 +1,4 @@
|
||||
extern vnm(); /* (bblock_p bp)
|
||||
* Performs the valuenumbering algorithm on the basic
|
||||
* block in bp.
|
||||
*/
|
||||
Reference in New Issue
Block a user