Initial revision
This commit is contained in:
parent
6a9e49f683
commit
6d481ce4d6
23
util/ego/cj/Makefile
Normal file
23
util/ego/cj/Makefile
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
EMH=../../../h
|
||||
EML=../../../lib
|
||||
SHARE=../share
|
||||
OBJECTS=cj.o
|
||||
SHOBJECTS=$(SHARE)/get.o $(SHARE)/put.o $(SHARE)/alloc.o $(SHARE)/global.o $(SHARE)/debug.o $(SHARE)/files.o $(SHARE)/map.o $(SHARE)/lset.o $(SHARE)/cset.o $(SHARE)/aux.o $(SHARE)/stack_chg.o $(SHARE)/go.o
|
||||
MSHOBJECTS=$(SHARE)/get.m $(SHARE)/put.m $(SHARE)/alloc.m $(SHARE)/global.m $(SHARE)/debug.m $(SHARE)/files.m $(SHARE)/map.m $(SHARE)/lset.m $(SHARE)/cset.m $(SHARE)/aux.m $(SHARE)/stack_chg.m
|
||||
SRC=cj.c
|
||||
.SUFFIXES: .m
|
||||
|
||||
.c.o:
|
||||
cc $(CFLAGS) -c $<
|
||||
.c.m:
|
||||
ack -O -L -c.m $(CFLAGS) $<
|
||||
all: $(OBJECTS)
|
||||
cj: \
|
||||
$(OBJECTS) $(SHOBJECTS)
|
||||
cc -o cj -i $(OBJECTS) $(SHOBJECTS) $(EML)/em_data.a
|
||||
lpr:
|
||||
pr $(SRC) | lpr
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
|
352
util/ego/cj/cj.c
Normal file
352
util/ego/cj/cj.c
Normal file
|
@ -0,0 +1,352 @@
|
|||
/* C R O S S J U M P I N G
|
||||
*
|
||||
* CJ.H
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/files.h"
|
||||
#include "../share/get.h"
|
||||
#include "../share/put.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/map.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/def.h"
|
||||
#include "../share/stack_chg.h"
|
||||
#include "../share/go.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
|
||||
|
||||
/* Cross jumping performs optimzations like:
|
||||
*
|
||||
* if cond then goto L1; if cond then goto L1
|
||||
* S1; -----> S1;
|
||||
* S2; goto L3;
|
||||
* goto L2; L1:
|
||||
* L1: S3;
|
||||
* S3; L3:
|
||||
* S2; S2;
|
||||
* L2:
|
||||
*
|
||||
* CJ looks for two basic blocks b1 and b2 with the following properties:
|
||||
* - there exists a basic block S such that SUCC(b1) = SUCC(b2) = {S}
|
||||
* (so both have only 1 successor)
|
||||
* - the last N (N > 0) instructions of b1 and b2, not counting a possible
|
||||
* BRAnch instruction, are the same.
|
||||
* As a result of the first condition, at least of the two blocks must end
|
||||
* on an (unconditional) BRAnch instruction. If both end on a BRA, one block
|
||||
* is chosen at random. Assume this block is b1. A new label L is put just
|
||||
* before the N common instructions of block b2 (so this block is split
|
||||
* into two). The BRA of b1 is changed into a BRA L. So dynamically the same
|
||||
* instructions are executed in a slightly different order; yet the size of
|
||||
* the code has become smaller.
|
||||
*/
|
||||
|
||||
|
||||
STATIC int Scj; /* number of optimizations found */
|
||||
|
||||
|
||||
|
||||
#define DLINK(l1,l2) l1->l_next=l2; l2->l_prev=l1
|
||||
|
||||
|
||||
STATIC bool same_instr(l1,l2)
|
||||
line_p l1,l2;
|
||||
{
|
||||
/* See if l1 and l2 are the same instruction */
|
||||
|
||||
if (l1 == 0 || l2 == 0 || TYPE(l1) != TYPE(l2)) return FALSE;
|
||||
if (INSTR(l1) != INSTR(l2)) return FALSE;
|
||||
switch(TYPE(l1)) {
|
||||
case OPSHORT: return SHORT(l1) == SHORT(l2);
|
||||
case OPOFFSET: return OFFSET(l1) == OFFSET(l2);
|
||||
case OPPROC: return PROC(l1) == PROC(l2);
|
||||
case OPOBJECT: return OBJ(l1) == OBJ(l2);
|
||||
case OPINSTRLAB: return INSTRLAB(l1) == INSTRLAB(l2);
|
||||
case OPNO: return TRUE;
|
||||
default: return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC line_p last_mnem(b)
|
||||
bblock_p b;
|
||||
{
|
||||
/* Determine the last line of a list */
|
||||
|
||||
register line_p l;
|
||||
|
||||
for (l = b->b_start; l->l_next != (line_p) 0; l = l->l_next);
|
||||
while (INSTR(l) < sp_fmnem || INSTR(l) > sp_lmnem) l = PREV(l);
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
STATIC bool is_desirable(text)
|
||||
line_p text;
|
||||
{
|
||||
/* We avoid to generate a BRAnch in the middle of some expression,
|
||||
* as the code generator will write the contents of the fakestack
|
||||
* to the real stack if it encounters a BRA. We do not avoid to
|
||||
* split the parameter-pushing code of a subroutine call into two,
|
||||
* as the parameters are pushed on the real stack anyway.
|
||||
* So e.g. "LOL a ; LOL b; ADI" will not be split, but
|
||||
* "LOL a; LOL b; CAL f" may be split.
|
||||
*/
|
||||
|
||||
line_p l;
|
||||
bool ok;
|
||||
int stack_diff,pop,push;
|
||||
|
||||
stack_diff = 0;
|
||||
for (l = text; l != (line_p) 0; l = l->l_next) {
|
||||
switch(INSTR(l)) {
|
||||
case op_cal:
|
||||
case op_asp:
|
||||
case op_bra:
|
||||
return TRUE;
|
||||
}
|
||||
line_change(l,&ok,&pop,&push);
|
||||
/* printf("instr %d, pop %d, push %d, ok %d\n",INSTR(l),pop,push,ok); */
|
||||
if (!ok || (stack_diff -= pop) < 0) {
|
||||
return FALSE;
|
||||
} else {
|
||||
stack_diff += push;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
STATIC cp_loops(b1,b2)
|
||||
bblock_p b1,b2;
|
||||
{
|
||||
/* Copy the loopset of b2 to b1 */
|
||||
|
||||
Lindex i;
|
||||
loop_p lp;
|
||||
for (i = Lfirst(b2->b_loops); i != (Lindex) 0;
|
||||
i = Lnext(i,b2->b_loops)) {
|
||||
lp = (loop_p) Lelem(i);
|
||||
Ladd(lp,&b1->b_loops);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC jump_cross(l1,l2,b1,b2)
|
||||
line_p l1,l2;
|
||||
bblock_p b1,b2;
|
||||
{
|
||||
/* A cross-jump from block b2 to block b1 is found; the code in
|
||||
* block b2 from line l2 up to the BRAnch is removed; block b1 is
|
||||
* split into two; the second part consists of a new label
|
||||
* followed by the code from l1 till the end of the block.
|
||||
*/
|
||||
|
||||
line_p l;
|
||||
bblock_p b;
|
||||
bblock_p s;
|
||||
|
||||
/* First adjust the control flow graph */
|
||||
b = freshblock(); /* create a new basic block */
|
||||
b->b_succ = b1->b_succ;
|
||||
/* SUCC(b1) = {b} */
|
||||
b1->b_succ = Lempty_set(); Ladd(b,&b1->b_succ);
|
||||
/* SUCC(b2) = {b} */
|
||||
Ldeleteset(b2->b_succ); b2->b_succ = Lempty_set(); Ladd(b,&b2->b_succ);
|
||||
/* PRED(b) = {b1,b2} */
|
||||
b->b_pred = Lempty_set(); Ladd(b1,&b->b_pred); Ladd(b2,&b->b_pred);
|
||||
/* PRED(SUCC(b)) := PRED(SUCC(b)) - {b1,b2} + {b} */
|
||||
assert(Lnrelems(b->b_succ) == 1);
|
||||
s = (bblock_p) Lelem(Lfirst(b->b_succ));
|
||||
Lremove(b1,&s->b_pred); Lremove(b2,&s->b_pred); Ladd(b,&s->b_pred);
|
||||
cp_loops(b,b1);
|
||||
b->b_idom = common_dom(b1,b2);
|
||||
b->b_flags = b1->b_flags;
|
||||
b->b_next = b1->b_next;
|
||||
b1->b_next = b;
|
||||
|
||||
/* Now adjust the EM text */
|
||||
l = PREV(l1);
|
||||
if (l == (line_p) 0) {
|
||||
b1->b_start = (line_p) 0;
|
||||
} else {
|
||||
l->l_next = (line_p) 0;
|
||||
}
|
||||
l = newline(OPINSTRLAB);
|
||||
l->l_instr = op_lab;
|
||||
INSTRLAB(l) = freshlabel();
|
||||
DLINK(l,l1);
|
||||
b->b_start = l;
|
||||
for (l = l2; INSTR(l) != op_bra; l = l->l_next) {
|
||||
assert (l != (line_p) 0);
|
||||
rm_line(l,b2);
|
||||
}
|
||||
INSTRLAB(l) = INSTRLAB(b->b_start);
|
||||
}
|
||||
|
||||
|
||||
STATIC bool try_tail(b1,b2)
|
||||
bblock_p b1,b2;
|
||||
{
|
||||
/* See if b1 and b2 end on the same sequence of instructions */
|
||||
|
||||
line_p l1,l2;
|
||||
bblock_p b = (bblock_p) 0;
|
||||
int cnt = 0;
|
||||
/* printf("try block %d and %d\n",b1->b_id,b2->b_id); */
|
||||
|
||||
if (b1->b_start == (line_p) 0 || b2->b_start == (line_p) 0) return FALSE;
|
||||
l1 = last_mnem(b1);
|
||||
l2 = last_mnem(b2);
|
||||
/* printf("consider:\n"); showinstr(l1); showinstr(l2); */
|
||||
if (INSTR(l1) == op_bra) {
|
||||
b = b1;
|
||||
l1 = PREV(l1);
|
||||
}
|
||||
if (INSTR(l2) == op_bra) {
|
||||
b = b2;
|
||||
l2 = PREV(l2);
|
||||
}
|
||||
assert(b != (bblock_p) 0);
|
||||
while(same_instr(l1,l2)) {
|
||||
cnt++;
|
||||
l1 = PREV(l1);
|
||||
l2 = PREV(l2);
|
||||
/* printf("consider:\n"); showinstr(l1); showinstr(l2); */
|
||||
}
|
||||
if (cnt >= 1) {
|
||||
l1 = (l1 == 0 ? b1->b_start : l1->l_next);
|
||||
l2 = (l2 == 0 ? b2->b_start : l2->l_next);
|
||||
if (is_desirable(l1)) {
|
||||
if (b == b1) {
|
||||
jump_cross(l2,l1,b2,b1);
|
||||
Scj++;
|
||||
} else {
|
||||
jump_cross(l1,l2,b1,b2);
|
||||
Scj++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool try_pred(b)
|
||||
bblock_p b;
|
||||
{
|
||||
/* See if there is any pair (b1,b2), both in PRED(b) for
|
||||
* which we can perform cross jumping.
|
||||
*/
|
||||
|
||||
register bblock_p b1,b2;
|
||||
register Lindex i,j;
|
||||
lset s = b->b_pred;
|
||||
|
||||
for (i = Lfirst(s); i != (Lindex) 0; i = Lnext(i,s)) {
|
||||
b1 = (bblock_p) Lelem(i);
|
||||
if (Lnrelems(b1->b_succ) != 1) continue;
|
||||
for (j = Lfirst(s); j != (Lindex) 0; j = Lnext(j,s)) {
|
||||
b2 = (bblock_p) Lelem(j);
|
||||
if (b1 != b2 && Lnrelems(b2->b_succ) == 1) {
|
||||
if (try_tail(b1,b2)) return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
cj_optimize(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Perform cross jumping for procedure p.
|
||||
* In case cases a cross-jumping optimization which give
|
||||
* new opportunities for further cross-jumping optimizations.
|
||||
* Hence we repeat the whole process for the entire procedure,
|
||||
* untill we find no further optimizations.
|
||||
*/
|
||||
|
||||
bblock_p b;
|
||||
bool changes = TRUE;
|
||||
|
||||
while(changes) {
|
||||
changes = FALSE;
|
||||
b = p->p_start;
|
||||
while (b != (bblock_p) 0) {
|
||||
if (try_pred(b)) {
|
||||
changes = TRUE;
|
||||
} else {
|
||||
b = b->b_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
go(argc,argv,no_action,cj_optimize,no_action,no_action);
|
||||
report("cross jumps",Scj);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******
|
||||
* Debugging stuff
|
||||
*/
|
||||
|
||||
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 (lnp == 0) return;
|
||||
if (INSTR(lnp) < sp_fmnem || INSTR(lnp) > sp_lmnem) {
|
||||
printf("\t*** ?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\t%s", &em_mnem[4 * (INSTR(lnp)-sp_fmnem)]);
|
||||
switch (TYPE(lnp)) {
|
||||
case OPNO:
|
||||
break;
|
||||
case OPSHORT:
|
||||
printf(" %d", SHORT(lnp)); break;
|
||||
case OPOBJECT:
|
||||
printf(" %d", OBJ(lnp)->o_id); break;
|
||||
case OPOFFSET:
|
||||
printf(" %D", OFFSET(lnp)); break;
|
||||
default:
|
||||
printf(" ?"); break;
|
||||
}
|
||||
printf("\n");
|
||||
} /* showinstr */
|
||||
|
||||
|
||||
STATIC print_list(list,b1,b2,p)
|
||||
line_p list;
|
||||
bblock_p b1,b2;
|
||||
proc_p p;
|
||||
{
|
||||
line_p l;
|
||||
printf("block %d and %d of proc %d:\n",b1->b_id,b2->b_id,p->p_id);
|
||||
for (l = list; l != 0; l = l->l_next) {
|
||||
showinstr(l);
|
||||
}
|
||||
}
|
475
util/ego/share/alloc.c
Normal file
475
util/ego/share/alloc.c
Normal file
|
@ -0,0 +1,475 @@
|
|||
/* S H A R E D F I L E
|
||||
*
|
||||
* A L L O C . C
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "alloc.h"
|
||||
|
||||
|
||||
short * myalloc();
|
||||
short * malloc();
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
STATIC unsigned maxuse, curruse;
|
||||
|
||||
short *newcore(size)
|
||||
int size;
|
||||
{
|
||||
if ((curruse += (unsigned) (size+2)) > maxuse) maxuse = curruse;
|
||||
return myalloc(size);
|
||||
}
|
||||
|
||||
oldcore(p,size)
|
||||
short *p;
|
||||
int size;
|
||||
{
|
||||
curruse -= (size+2);
|
||||
free(p);
|
||||
}
|
||||
|
||||
coreusage()
|
||||
{
|
||||
fprintf(stderr,"Maximal core usage (excl. buffers):%u\n",maxuse);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* The following two sizetables contain the sizes of the various kinds
|
||||
* of line and argument structures.
|
||||
* The assumption when making the tables was that every non-byte object
|
||||
* had to be aligned on an even boundary. On machines where alignment
|
||||
* is worse ( for example a long has to be aligned on a longword bound )
|
||||
* these tables should be revised.
|
||||
* A wasteful but safe approach is to replace every line of them by
|
||||
* sizeof(line_t)
|
||||
* and
|
||||
* sizeof(arg_t)
|
||||
* respectively.
|
||||
*/
|
||||
|
||||
#ifndef NOTCOMPACT
|
||||
int lsizetab[] = {
|
||||
2*sizeof(line_p)+2*sizeof(byte),
|
||||
2*sizeof(line_p)+2*sizeof(byte)+sizeof(short),
|
||||
2*sizeof(line_p)+2*sizeof(byte)+sizeof(offset),
|
||||
2*sizeof(line_p)+2*sizeof(byte)+sizeof(lab_id),
|
||||
2*sizeof(line_p)+2*sizeof(byte)+sizeof(obj_p),
|
||||
2*sizeof(line_p)+2*sizeof(byte)+sizeof(proc_p),
|
||||
2*sizeof(line_p)+2*sizeof(byte)+sizeof(arg_p),
|
||||
};
|
||||
|
||||
int asizetab[] = {
|
||||
sizeof(arg_p)+sizeof(short)+sizeof(offset),
|
||||
sizeof(arg_p)+sizeof(short)+sizeof(lab_id),
|
||||
sizeof(arg_p)+sizeof(short)+sizeof(obj_p),
|
||||
sizeof(arg_p)+sizeof(short)+sizeof(proc_p),
|
||||
sizeof(arg_p)+sizeof(short)+sizeof(argb_t),
|
||||
sizeof(arg_p)+sizeof(short)+sizeof(short)+sizeof(argb_t),
|
||||
sizeof(arg_p)+sizeof(short)+sizeof(short)+sizeof(argb_t),
|
||||
sizeof(arg_p)+sizeof(short)+sizeof(short)+sizeof(argb_t)
|
||||
};
|
||||
#else
|
||||
int lsizetab[] = {
|
||||
sizeof(struct line),
|
||||
sizeof(struct line),
|
||||
sizeof(struct line),
|
||||
sizeof(struct line),
|
||||
sizeof(struct line),
|
||||
sizeof(struct line),
|
||||
sizeof(struct line)
|
||||
};
|
||||
|
||||
int asizetab[] = {
|
||||
sizeof (struct arg),
|
||||
sizeof (struct arg),
|
||||
sizeof (struct arg),
|
||||
sizeof (struct arg),
|
||||
sizeof (struct arg),
|
||||
sizeof (struct arg),
|
||||
sizeof (struct arg),
|
||||
sizeof (struct arg)
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* alloc routines:
|
||||
* Two parts:
|
||||
* 1) typed alloc and free routines
|
||||
* 2) untyped raw core allocation
|
||||
*/
|
||||
|
||||
/*
|
||||
* PART 1
|
||||
*/
|
||||
|
||||
line_p newline(optyp) int optyp; {
|
||||
register line_p lnp;
|
||||
register kind=optyp;
|
||||
|
||||
lnp = (line_p) newcore(lsizetab[kind]);
|
||||
TYPE(lnp) = optyp;
|
||||
return(lnp);
|
||||
}
|
||||
|
||||
oldline(lnp) register line_p lnp; {
|
||||
register kind=TYPE(lnp)&BMASK;
|
||||
|
||||
if (kind == OPLIST)
|
||||
oldargs(ARG(lnp));
|
||||
oldcore((short *) lnp,lsizetab[kind]);
|
||||
}
|
||||
|
||||
arg_p newarg(kind) int kind; {
|
||||
register arg_p ap;
|
||||
|
||||
ap = (arg_p) newcore(asizetab[kind]);
|
||||
ap->a_type = kind;
|
||||
return(ap);
|
||||
}
|
||||
|
||||
oldargs(ap) register arg_p ap; {
|
||||
register arg_p next;
|
||||
|
||||
while (ap != (arg_p) 0) {
|
||||
next = ap->a_next;
|
||||
switch(ap->a_type) {
|
||||
case ARGSTRING:
|
||||
oldargb(ap->a_a.a_string.ab_next);
|
||||
break;
|
||||
case ARGICN:
|
||||
case ARGUCN:
|
||||
case ARGFCN:
|
||||
oldargb(ap->a_a.a_con.ac_con.ab_next);
|
||||
break;
|
||||
}
|
||||
oldcore((short *) ap,asizetab[ap->a_type]);
|
||||
ap = next;
|
||||
}
|
||||
}
|
||||
|
||||
oldargb(abp) register argb_p abp; {
|
||||
register argb_p next;
|
||||
|
||||
while (abp != (argb_p) 0) {
|
||||
next = abp->ab_next;
|
||||
oldcore((short *) abp,sizeof (argb_t));
|
||||
abp = next;
|
||||
}
|
||||
}
|
||||
|
||||
num_p newnum() {
|
||||
|
||||
return((num_p) newcore(sizeof(struct num)));
|
||||
}
|
||||
|
||||
oldnum(lp) num_p lp; {
|
||||
|
||||
oldcore((short *) lp,sizeof(struct num));
|
||||
}
|
||||
|
||||
|
||||
sym_p newsym() {
|
||||
|
||||
return((sym_p) newcore(sizeof(struct sym)));
|
||||
}
|
||||
|
||||
oldsym(sp) sym_p sp; {
|
||||
oldcore((short *) sp,sizeof(struct sym));
|
||||
}
|
||||
|
||||
|
||||
prc_p newprc() {
|
||||
return((prc_p) newcore(sizeof(struct prc)));
|
||||
}
|
||||
|
||||
|
||||
oldprc(pp) prc_p pp; {
|
||||
oldcore((short *) pp,sizeof(struct prc));
|
||||
}
|
||||
|
||||
|
||||
argb_p newargb() {
|
||||
|
||||
return((argb_p) newcore(sizeof(argb_t)));
|
||||
}
|
||||
|
||||
obj_p newobject() {
|
||||
return((obj_p) newcore(sizeof(struct obj)));
|
||||
}
|
||||
|
||||
oldobjects(op) register obj_p op; {
|
||||
register obj_p next;
|
||||
|
||||
while (op != (obj_p) 0) {
|
||||
next = op->o_next;
|
||||
oldcore((short *) op, sizeof(struct obj));
|
||||
op = next;
|
||||
}
|
||||
}
|
||||
|
||||
proc_p newproc() {
|
||||
return((proc_p) newcore(sizeof(struct proc)));
|
||||
}
|
||||
|
||||
oldproc(p) proc_p p; {
|
||||
oldcore((short *) p, sizeof(struct proc));
|
||||
}
|
||||
|
||||
dblock_p newdblock() {
|
||||
return((dblock_p) newcore(sizeof(struct dblock)));
|
||||
}
|
||||
|
||||
olddblock(dbl) dblock_p dbl; {
|
||||
oldobjects(dbl->d_objlist);
|
||||
oldargs(dbl->d_values);
|
||||
oldcore((short *) dbl, sizeof(struct dblock));
|
||||
}
|
||||
|
||||
|
||||
bblock_p newbblock() {
|
||||
return((bblock_p) newcore(sizeof(struct bblock)));
|
||||
}
|
||||
|
||||
oldbblock(b) bblock_p b; {
|
||||
oldcore((short *) b, sizeof(struct bblock));
|
||||
}
|
||||
|
||||
|
||||
short **newmap(length) short length; {
|
||||
return((short **) newcore((length+1) * sizeof(short *)));
|
||||
}
|
||||
|
||||
oldmap(mp,length) short **mp, length; {
|
||||
oldcore((short *) mp, (length+1) * sizeof(short *));
|
||||
}
|
||||
|
||||
|
||||
elem_p newelem() {
|
||||
return((elem_p) newcore(sizeof(struct elemholder)));
|
||||
}
|
||||
|
||||
|
||||
oldelem(ep) elem_p ep; {
|
||||
oldcore((short *) ep, sizeof(struct elemholder));
|
||||
}
|
||||
|
||||
|
||||
cset newbitvect(n) short n; {
|
||||
return((cset) newcore((n-1)*sizeof(int) + sizeof(struct bitvector)));
|
||||
/* sizeof(struct bitvector) equals to the size of a struct with
|
||||
* one short, followed by one ALLIGNED int. So the above statement
|
||||
* also works e.g. on a VAX.
|
||||
*/
|
||||
}
|
||||
|
||||
oldbitvect(s,n) cset s; short n; {
|
||||
oldcore((short *) s, (n-1)*sizeof(int) + sizeof(struct bitvector));
|
||||
}
|
||||
|
||||
|
||||
loop_p newloop() {
|
||||
return((loop_p) newcore(sizeof(struct loop)));
|
||||
}
|
||||
|
||||
|
||||
oldloop(lp) loop_p lp; {
|
||||
oldcore((short *) lp, sizeof(struct loop));
|
||||
}
|
||||
|
||||
use_p newuse() {
|
||||
return((use_p) newcore(sizeof(struct use)));
|
||||
}
|
||||
|
||||
|
||||
olduse(u) use_p u; {
|
||||
oldcore((short *) u, sizeof(struct use));
|
||||
}
|
||||
|
||||
|
||||
change_p newchange() {
|
||||
return((change_p) newcore(sizeof(struct change)));
|
||||
}
|
||||
|
||||
|
||||
oldchange(c) change_p c; {
|
||||
oldcore((short *) c, sizeof(struct change));
|
||||
}
|
||||
|
||||
|
||||
iv_p newiv() {
|
||||
return((iv_p) newcore(sizeof(struct iv)));
|
||||
}
|
||||
|
||||
oldiv(i) iv_p i; {
|
||||
oldcore((short *) i, sizeof(struct iv));
|
||||
}
|
||||
|
||||
|
||||
code_p newcinfo() {
|
||||
return((code_p) newcore(sizeof(struct code_info)));
|
||||
}
|
||||
|
||||
oldcinfo(c) code_p c; {
|
||||
oldcore((short *) c, sizeof(struct code_info));
|
||||
}
|
||||
|
||||
|
||||
call_p newcall() {
|
||||
return((call_p) newcore(sizeof(struct call)));
|
||||
}
|
||||
|
||||
oldcall(c) call_p c; {
|
||||
oldcore((short *) c, sizeof(struct call));
|
||||
}
|
||||
|
||||
|
||||
actual_p newactual() {
|
||||
return((actual_p) newcore(sizeof(struct actual)));
|
||||
}
|
||||
|
||||
oldactual(a) actual_p a; {
|
||||
oldcore((short *) a, sizeof(struct actual));
|
||||
}
|
||||
|
||||
formal_p newformal() {
|
||||
return((formal_p) newcore(sizeof(struct formal)));
|
||||
}
|
||||
|
||||
oldformal(f) formal_p f; {
|
||||
oldcore((short *) f, sizeof(struct formal));
|
||||
}
|
||||
|
||||
calcnt_p newcalcnt() {
|
||||
return ((calcnt_p) newcore(sizeof(struct calcnt)));
|
||||
}
|
||||
|
||||
oldcalcnt(cc) calcnt_p cc; {
|
||||
oldcore((short *) cc, sizeof(struct calcnt));
|
||||
}
|
||||
|
||||
local_p newlocal() {
|
||||
return ((local_p) newcore(sizeof(struct local)));
|
||||
}
|
||||
|
||||
oldlocal(lc) local_p lc; {
|
||||
oldcore((short *) lc, sizeof(struct local));
|
||||
}
|
||||
|
||||
|
||||
short *newtable(length) short length; {
|
||||
return((short *) newcore((length+1) * sizeof(short)));
|
||||
}
|
||||
|
||||
oldtable(mp,length) short **mp, length; {
|
||||
oldcore((short *) mp, (length+1) * sizeof(short));
|
||||
}
|
||||
|
||||
char **newnametab(tablen,namelen)
|
||||
short tablen,namelen;
|
||||
{
|
||||
register char **np, **tab;
|
||||
|
||||
tab = (char **) newmap(tablen);
|
||||
for (np = &tab[1]; np <= &tab[tablen]; np++) {
|
||||
*np = (char *) newcore(namelen);
|
||||
}
|
||||
return tab;
|
||||
}
|
||||
|
||||
bext_p newcfbx() {
|
||||
return ((bext_p) newcore(sizeof(struct bext_cf)));
|
||||
}
|
||||
|
||||
oldcfbx(bxp) bext_p bxp; {
|
||||
oldcore((short *) bxp,sizeof(struct bext_cf));
|
||||
}
|
||||
|
||||
lpext_p newcflpx() {
|
||||
return ((lpext_p) newcore (sizeof(struct lpext_cf)));
|
||||
}
|
||||
|
||||
oldcflpx(lxp) lpext_p lxp; {
|
||||
oldcore((short *) lxp,sizeof(struct lpext_cf));
|
||||
}
|
||||
|
||||
lpext_p newsrlpx() {
|
||||
return ((lpext_p) newcore (sizeof(struct lpext_sr)));
|
||||
}
|
||||
|
||||
oldsrlpx(lxp) lpext_p lxp; {
|
||||
oldcore((short *) lxp,sizeof(struct lpext_sr));
|
||||
}
|
||||
|
||||
pext_p newilpx() {
|
||||
return ((pext_p) newcore(sizeof(struct pext_il)));
|
||||
}
|
||||
|
||||
oldilpx(pxp) pext_p pxp; {
|
||||
oldcore((short *) pxp,sizeof(struct pext_il));
|
||||
}
|
||||
|
||||
|
||||
bext_p newudbx() {
|
||||
return ((bext_p) newcore(sizeof(struct bext_ud)));
|
||||
}
|
||||
|
||||
oldudbx(bxp) bext_p bxp; {
|
||||
oldcore((short *) bxp,sizeof(struct bext_ud));
|
||||
}
|
||||
|
||||
bext_p newlvbx() {
|
||||
return ((bext_p) newcore(sizeof(struct bext_lv)));
|
||||
}
|
||||
|
||||
oldlvbx(bxp) bext_p bxp; {
|
||||
oldcore((short *) bxp,sizeof(struct bext_lv));
|
||||
}
|
||||
|
||||
lpext_p newralpx() {
|
||||
return ((lpext_p) newcore (sizeof(struct lpext_ra)));
|
||||
}
|
||||
|
||||
oldralpx(lxp) lpext_p lxp; {
|
||||
oldcore((short *) lxp,sizeof(struct lpext_ra));
|
||||
}
|
||||
|
||||
bext_p newrabx() {
|
||||
return ((bext_p) newcore(sizeof(struct bext_ra)));
|
||||
}
|
||||
|
||||
oldrabx(bxp) bext_p bxp; {
|
||||
oldcore((short *) bxp,sizeof(struct bext_ra));
|
||||
}
|
||||
|
||||
|
||||
cond_p newcondtab(l) int l;
|
||||
{
|
||||
return (cond_p) newcore(l * (sizeof (struct cond_tab)));
|
||||
}
|
||||
|
||||
oldcondtab(tab) cond_p tab;
|
||||
{
|
||||
int i;
|
||||
for (i = 0; tab[i].mc_cond != DEFAULT; i++);
|
||||
oldcore((short *) tab,((i+1) * sizeof (struct cond_tab)));
|
||||
}
|
||||
|
||||
|
||||
short *myalloc(size) register size; {
|
||||
register short *p,*q;
|
||||
|
||||
p = malloc(size);
|
||||
if (p == 0)
|
||||
error("out of memory");
|
||||
for(q=p;size>0;size -= sizeof(short))
|
||||
*q++ = 0;
|
||||
return(p);
|
||||
}
|
87
util/ego/share/alloc.h
Normal file
87
util/ego/share/alloc.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/* I N T E R M E D I A T E C O D E
|
||||
*
|
||||
* C O R E A L L O C A T I O N A N D D E A L L O C A T I O N
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
extern short *newcore();
|
||||
extern oldcore();
|
||||
#else
|
||||
extern short *myalloc();
|
||||
#define newcore(size) myalloc(size)
|
||||
#define oldcore(p,size) free(p)
|
||||
#endif
|
||||
|
||||
#define newstruct(t) (newcore (sizeof (struct t)))
|
||||
#define oldstruct(t,p) oldcore((short *) p,sizeof (struct t))
|
||||
|
||||
extern line_p newline(); /* (byte optype) */
|
||||
extern dblock_p newdblock();
|
||||
extern obj_p newobject();
|
||||
extern proc_p newproc();
|
||||
extern arg_p newarg(); /* (byte argtype) */
|
||||
extern argb_p newargb();
|
||||
extern bblock_p newbblock();
|
||||
extern short **newmap(); /* (short length) */
|
||||
extern elem_p newelem();
|
||||
extern cset newbitvect(); /* (short nrbytes) */
|
||||
extern loop_p newloop();
|
||||
extern use_p newuse();
|
||||
extern change_p newchange();
|
||||
extern cond_p newcondtab();
|
||||
|
||||
|
||||
extern oldline() ;
|
||||
extern oldargs() ;
|
||||
extern oldargb() ;
|
||||
extern oldobjects() ;
|
||||
extern oldproc() ;
|
||||
extern olddblock() ;
|
||||
extern oldbblock();
|
||||
extern oldmap();
|
||||
extern oldelem();
|
||||
extern oldbitvect(); /* (cset s, short nrbytes) */
|
||||
extern oldloop();
|
||||
extern olduse();
|
||||
extern oldchange();
|
||||
extern oldcondtab();
|
||||
|
||||
extern sym_p newsym();
|
||||
extern prc_p newprc();
|
||||
extern num_p newnum();
|
||||
extern oldnum() ;
|
||||
extern oldsym();
|
||||
extern oldprc();
|
||||
extern iv_p newiv();
|
||||
extern oldiv();
|
||||
extern code_p newcinfo();
|
||||
extern oldcinfo();
|
||||
extern call_p newcall();
|
||||
extern oldcall();
|
||||
extern actual_p newactual();
|
||||
extern oldactual();
|
||||
extern formal_p newformal();
|
||||
extern oldformal();
|
||||
extern calcnt_p newcalcnt();
|
||||
extern oldcalcnt();
|
||||
extern local_p newlocal();
|
||||
extern oldlocal();
|
||||
extern short *newtable();
|
||||
extern oldtable();
|
||||
extern char **newnametab();
|
||||
extern bext_p newcfbx();
|
||||
extern oldcfbx();
|
||||
extern lpext_p newcflpx();
|
||||
extern oldcflpx();
|
||||
extern lpext_p newsrlpx();
|
||||
extern oldsrlpx();
|
||||
extern pext_p newilpx();
|
||||
extern oldilpx();
|
||||
extern bext_p newudbx();
|
||||
extern oldudbx();
|
||||
extern bext_p newlvbx();
|
||||
extern oldlvbx();
|
||||
extern bext_p newrabx();
|
||||
extern oldrabx();
|
||||
extern lpext_p newralpx();
|
||||
extern oldralpx();
|
246
util/ego/share/aux.c
Normal file
246
util/ego/share/aux.c
Normal file
|
@ -0,0 +1,246 @@
|
|||
/* S H A R E D F I L E
|
||||
*
|
||||
* A U X I L I A R Y R O U T I N E S
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/map.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../../../h/em_mes.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
|
||||
offset off_set(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
switch(lnp->l_optype) {
|
||||
case OPSHORT:
|
||||
return (offset) SHORT(lnp);
|
||||
case OPOFFSET:
|
||||
return OFFSET(lnp);
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
offset aoff(ap,n)
|
||||
register arg_p ap;
|
||||
{
|
||||
while (n>0) {
|
||||
if (ap != (arg_p) 0)
|
||||
ap = ap->a_next;
|
||||
n--;
|
||||
}
|
||||
if (ap == (arg_p) 0)
|
||||
error("too few parameters");
|
||||
if (ap->a_type != ARGOFF)
|
||||
error("offset expected");
|
||||
return(ap->a_a.a_offset);
|
||||
}
|
||||
|
||||
|
||||
offset tmplocal(p,size)
|
||||
proc_p p;
|
||||
int size;
|
||||
{
|
||||
/* Allocate a new local variable in the stack frame of p */
|
||||
|
||||
p->p_localbytes += (offset) size;
|
||||
return -(p->p_localbytes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
line_p int_line(off)
|
||||
offset off;
|
||||
{
|
||||
/* Allocate a line struct of type OPSHORT or OPOFFSET,
|
||||
* whichever one fits best.
|
||||
*/
|
||||
|
||||
line_p lnp;
|
||||
|
||||
if ((short) off == off) {
|
||||
/* fits in a short */
|
||||
lnp = newline(OPSHORT);
|
||||
SHORT(lnp) = (short) off;
|
||||
} else {
|
||||
lnp = newline(OPOFFSET);
|
||||
OFFSET(lnp) = off;
|
||||
}
|
||||
return lnp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
line_p reg_mes(tmp,size,typ,score)
|
||||
offset tmp;
|
||||
short size;
|
||||
int typ,score;
|
||||
{
|
||||
/* Generate a register message */
|
||||
|
||||
line_p l;
|
||||
arg_p a;
|
||||
|
||||
#define NEXTARG(a,val) a->a_next = newarg(ARGOFF); a = a->a_next; \
|
||||
a->a_a.a_offset = val
|
||||
l = newline(OPLIST);
|
||||
l->l_instr = ps_mes;
|
||||
a = ARG(l) = newarg(ARGOFF);
|
||||
a->a_a.a_offset = ms_reg;
|
||||
NEXTARG(a,tmp);
|
||||
NEXTARG(a,size);
|
||||
NEXTARG(a,typ);
|
||||
NEXTARG(a,score);
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
bool dom(b1,b2)
|
||||
bblock_p b1,b2;
|
||||
{
|
||||
/* See if b1 dominates b2. Note that a block always
|
||||
* dominates itself.
|
||||
*/
|
||||
|
||||
register bblock_p b;
|
||||
|
||||
for (b = b2; b != (bblock_p) 0; b = b->b_idom) {
|
||||
/* See if b1 is a (not necessarily proper) ancestor
|
||||
* of b2 in the immediate dominator tree.
|
||||
*/
|
||||
if (b == b1) return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bblock_p common_dom(a,b)
|
||||
bblock_p a,b;
|
||||
{
|
||||
/* find a basic block that dominates a as well as b;
|
||||
* note that a basic block also dominates itself.
|
||||
*/
|
||||
|
||||
assert (a != (bblock_p) 0);
|
||||
assert (b != (bblock_p) 0);
|
||||
if (dom(a,b)) {
|
||||
return a;
|
||||
} else {
|
||||
if (dom(b,a)) {
|
||||
return b;
|
||||
} else {
|
||||
return common_dom(a->b_idom,b->b_idom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define R time_space_ratio
|
||||
|
||||
short add_timespace(time,space)
|
||||
short time,space;
|
||||
{
|
||||
/* Add together a time and space, using the time_space_ratio
|
||||
* parameter that may be set by the user, indicating the need
|
||||
* to optimize for time, space or something in between.
|
||||
*/
|
||||
|
||||
return (R * time + (100 - R) * space) / 100;
|
||||
}
|
||||
|
||||
|
||||
|
||||
rm_line(l,b)
|
||||
line_p l;
|
||||
bblock_p b;
|
||||
{
|
||||
if (b->b_start == l) {
|
||||
b->b_start = l->l_next;
|
||||
} else {
|
||||
PREV(l)->l_next = l->l_next;
|
||||
}
|
||||
if (l->l_next != (line_p) 0) {
|
||||
PREV(l->l_next) = PREV(l);
|
||||
}
|
||||
oldline(l);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
appnd_line(l1,l2)
|
||||
line_p l1,l2;
|
||||
{
|
||||
/* Put l1 after l2 */
|
||||
|
||||
PREV(l1) = l2;
|
||||
l1->l_next = l2->l_next;
|
||||
l2->l_next = l1;
|
||||
if (l1->l_next != (line_p) 0) {
|
||||
PREV(l1->l_next) = l1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
line_p last_instr(b)
|
||||
bblock_p b;
|
||||
{
|
||||
/* Determine the last line of a list */
|
||||
|
||||
register line_p l = b->b_start;
|
||||
|
||||
if (l == (line_p) 0) return (line_p) 0;
|
||||
while (l->l_next != (line_p) 0) l = l->l_next;
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
line_p find_mesreg(off)
|
||||
offset off;
|
||||
{
|
||||
/* Find the register message for the local with the given offset */
|
||||
|
||||
Lindex li;
|
||||
line_p l;
|
||||
|
||||
for (li = Lfirst(mesregs); li != (Lindex) 0; li = Lnext(li,mesregs)) {
|
||||
l = (line_p) Lelem(li);
|
||||
if (aoff(ARG(l),1) == off) return l;
|
||||
}
|
||||
return (line_p) 0;
|
||||
}
|
||||
|
||||
|
||||
bool is_regvar(off)
|
||||
offset off;
|
||||
{
|
||||
return find_mesreg(off) != (line_p) 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
offset regv_arg(off,n)
|
||||
offset off;
|
||||
int n;
|
||||
{
|
||||
/* fetch the n'th argument of the register message of the
|
||||
* local variable at offset off;
|
||||
*/
|
||||
|
||||
line_p x = find_mesreg(off);
|
||||
assert (x != (line_p) 0);
|
||||
return aoff(ARG(x),n);
|
||||
}
|
66
util/ego/share/aux.h
Normal file
66
util/ego/share/aux.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* S H A R E D
|
||||
*
|
||||
* A U X I L I A R Y R O U T I N E S
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
extern offset off_set(); /* (line_p lnp)
|
||||
* lnp has a SHORT or OFFSET operand. Return
|
||||
* the value of this operand as an offset.
|
||||
*/
|
||||
extern offset aoff(); /* (arg_p list; int n)
|
||||
* Determine the offset field of the
|
||||
* n'th argument in the list (this argument
|
||||
* must have type ARGOFF). Start counting at 0.
|
||||
*/
|
||||
extern offset tmplocal(); /* (proc_p p, int size)
|
||||
* Allocate a new local variable in the
|
||||
* stack frame of p.
|
||||
*/
|
||||
line_p int_line(); /* (offset off)
|
||||
* Allocate a line struct of type OPSHORT
|
||||
* or OPOFFSET, whichever one fits best.
|
||||
*/
|
||||
extern line_p reg_mes(); /* (offset tmp; short size; int typ,score)
|
||||
* Generate a register message with the
|
||||
* given arguments.
|
||||
*/
|
||||
extern bool dom(); /* (bblock_p b1,b2)
|
||||
/* See if b1 dominates b2. Note that a
|
||||
* block always * dominates itself.
|
||||
*/
|
||||
extern bblock_p common_dom(); /* (bblock_p a,b)
|
||||
* find a basic block that dominates a as
|
||||
* well as b; note that a basic block also
|
||||
* dominates itself.
|
||||
*/
|
||||
extern short add_timespace(); /* (short time,space)
|
||||
* Add together a time and space, using
|
||||
* the time_space_ratio parameter that
|
||||
* may be set by the user.
|
||||
*/
|
||||
extern rm_line(); /* ( line_p l; bblock_p b)
|
||||
* Remove line l from b basic block b.
|
||||
*/
|
||||
|
||||
extern appnd_line(); /* ( line_p l1,l2)
|
||||
* Put line l1 after l2.
|
||||
*/
|
||||
extern line_p last_instr(); /* ( bblock_p b)
|
||||
* Determine the last line of a basic block.
|
||||
*/
|
||||
extern line_p find_mesreg(); /* (offset off)
|
||||
* Find the register message for the local
|
||||
* with the given offset.
|
||||
*/
|
||||
extern bool is_regvar(); /* (offset off)
|
||||
* See if there is a 'register message'
|
||||
* for the local variable with the
|
||||
* given offset.
|
||||
*/
|
||||
extern offset regv_arg(); /* (offset off; int n)
|
||||
* Fetch the n'th argument of the
|
||||
* register message of the local with
|
||||
* the given offset.
|
||||
*/
|
277
util/ego/share/cset.c
Normal file
277
util/ego/share/cset.c
Normal file
|
@ -0,0 +1,277 @@
|
|||
/* S H A R E D F I L E
|
||||
*
|
||||
* C S E T . C
|
||||
*/
|
||||
|
||||
|
||||
#include "types.h"
|
||||
#include "cset.h"
|
||||
#include "alloc.h"
|
||||
#include "debug.h"
|
||||
#include "global.h"
|
||||
|
||||
|
||||
/* A set over a range of integers from 1 to N may be represented
|
||||
* as a 'compact' set. Such a set is represented as a 'bitvector'
|
||||
* record, containing the size of the set (i.e. N) and a row
|
||||
* of words (the bitvector itself). An integer J (1 <= J <= N) is
|
||||
* an element of the set iff the J-th bit of the vector is a '1'.
|
||||
* Any redundant bits in the last word are garanteed to be zero bits.
|
||||
* This package implements the usual operations on sets.
|
||||
* The name of every operation is preceede by a 'C' to
|
||||
* distinguish it from the operation on 'long' (list)
|
||||
* sets whth a similar name.
|
||||
*/
|
||||
|
||||
|
||||
/* The two arithmetic operations 'divide by wordlength' and
|
||||
* 'modulo wordlength' can be performed very efficiently
|
||||
* if the word length (of the source machine) is 16.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
cset Cempty_set(n)
|
||||
short n;
|
||||
{
|
||||
cset s;
|
||||
|
||||
s = newbitvect(DIVWL(n-1) + 1);
|
||||
s->v_size = n;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
bool Cis_elem(x,s)
|
||||
Celem_t x;
|
||||
cset s;
|
||||
{
|
||||
short n;
|
||||
int mask;
|
||||
|
||||
assert(x>0 && x <= s->v_size);
|
||||
n = DIVWL(x-1);
|
||||
mask = (1 << MODWL(x-1));
|
||||
if ((s->v_bits[n] & mask) == 0) {
|
||||
return FALSE;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Cadd(x,s_p)
|
||||
Celem_t x;
|
||||
cset *s_p;
|
||||
{
|
||||
cset s;
|
||||
short n;
|
||||
int mask;
|
||||
|
||||
s = *s_p;
|
||||
assert(x>0 && x <= s->v_size);
|
||||
n = DIVWL(x-1);
|
||||
mask = (1 << MODWL(x-1));
|
||||
s->v_bits[n] |= mask;
|
||||
}
|
||||
|
||||
|
||||
Cremove(x,s_p)
|
||||
Celem_t x;
|
||||
cset *s_p;
|
||||
{
|
||||
cset s;
|
||||
short n;
|
||||
int mask;
|
||||
|
||||
s = *s_p;
|
||||
assert(x>0 && x <= s->v_size);
|
||||
n = DIVWL(x-1);
|
||||
mask = (1 << MODWL(x-1));
|
||||
s->v_bits[n] &= ~mask;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The operations first, next and elem can be used to iterate
|
||||
* over a set. For example:
|
||||
* for (i = Cfirst(s); i != (Cindex) 0; i = Cnext(i,s) {
|
||||
* x = Celem(i);
|
||||
* use x
|
||||
* }
|
||||
* which is like:
|
||||
* 'for all elements x of s do'
|
||||
* use x
|
||||
*
|
||||
* The implementation of first and next is not very fast.
|
||||
* It could be made much more efficient (at the price of a
|
||||
* higher complexity) by not using 'is_elem'.
|
||||
* Iteration over a bitvector, however, is not supposed to
|
||||
* be used very often.
|
||||
*/
|
||||
|
||||
Cindex Cfirst(s)
|
||||
cset s;
|
||||
{
|
||||
return Cnext((Cindex) 0,s);
|
||||
}
|
||||
|
||||
|
||||
Cindex Cnext(i,s)
|
||||
Cindex i;
|
||||
cset s;
|
||||
{
|
||||
register short n;
|
||||
|
||||
for (n = i+1; n <= s->v_size; n++) {
|
||||
if (Cis_elem(n,s)) {
|
||||
return (Cindex) n;
|
||||
}
|
||||
}
|
||||
return (Cindex) 0;
|
||||
}
|
||||
|
||||
|
||||
Celem_t Celem(i)
|
||||
Cindex i;
|
||||
{
|
||||
return (Celem_t) i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Cjoin(s1,s2_p)
|
||||
cset s1, *s2_p;
|
||||
{
|
||||
/* Two sets are joined by or-ing their bitvectors,
|
||||
* word by word.
|
||||
*/
|
||||
|
||||
cset s2;
|
||||
short n;
|
||||
register short i;
|
||||
|
||||
s2 = *s2_p;
|
||||
assert(s1->v_size == s2->v_size);
|
||||
n = DIVWL(s1->v_size -1); /* #words -1 */
|
||||
for (i = 0; i <= n; i++) {
|
||||
s2->v_bits[i] |= s1->v_bits[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Cintersect(s1,s2_p)
|
||||
cset s1, *s2_p;
|
||||
{
|
||||
/* Two sets are intersected by and-ing their bitvectors,
|
||||
* word by word.
|
||||
*/
|
||||
|
||||
cset s2;
|
||||
short n;
|
||||
register short i;
|
||||
|
||||
s2 = *s2_p;
|
||||
assert(s1->v_size == s2->v_size);
|
||||
n = DIVWL(s1->v_size -1); /* #words -1 */
|
||||
for (i = 0; i <= n; i++) {
|
||||
s2->v_bits[i] &= s1->v_bits[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Cdeleteset(s)
|
||||
cset s;
|
||||
{
|
||||
oldbitvect(s,DIVWL(s->v_size - 1) + 1);
|
||||
}
|
||||
|
||||
|
||||
bool Cis_subset(s1,s2)
|
||||
cset s1,s2;
|
||||
{
|
||||
/* See if s1 is a subset of s2 */
|
||||
|
||||
register short i;
|
||||
|
||||
assert(s1->v_size == s2->v_size);
|
||||
if (s1->v_size == 0) return TRUE;
|
||||
for (i = 0; i <= DIVWL(s1->v_size-1); i++) {
|
||||
if ((s1->v_bits[i] & ~(s2->v_bits[i])) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
Cclear_set(s_p)
|
||||
cset *s_p;
|
||||
{
|
||||
cset s;
|
||||
register short i;
|
||||
|
||||
s = *s_p;
|
||||
assert (s != (cset) 0);
|
||||
for (i = 0; i <= DIVWL(s->v_size-1); i++) {
|
||||
s->v_bits[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Ccopy_set(s1,s2_p)
|
||||
cset s1, *s2_p;
|
||||
{
|
||||
cset s2;
|
||||
register short i;
|
||||
|
||||
s2 = *s2_p;
|
||||
assert (s1->v_size == s2->v_size);
|
||||
for (i = 0; i <= DIVWL(s1->v_size-1); i++) {
|
||||
s2->v_bits[i] = s1->v_bits[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Csubtract(s1,s2_p)
|
||||
cset s1, *s2_p;
|
||||
{
|
||||
cset s2;
|
||||
register short i;
|
||||
|
||||
s2 = *s2_p;
|
||||
assert (s1->v_size == s2->v_size);
|
||||
for (i = 0; i <= DIVWL(s1->v_size-1); i++) {
|
||||
s2->v_bits[i] &= ~(s1->v_bits[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Cequal(s1,s2)
|
||||
cset s1, s2;
|
||||
{
|
||||
register short i;
|
||||
|
||||
assert (s1->v_size == s2->v_size);
|
||||
for (i = 0; i <= DIVWL(s1->v_size-1); i++) {
|
||||
if (s1->v_bits[i] != s2->v_bits[i]) return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
short Cnrelems(s)
|
||||
cset s;
|
||||
{
|
||||
register short n, cnt;
|
||||
|
||||
cnt = 0;
|
||||
for (n = 1; n <= s->v_size; n++) {
|
||||
if (Cis_elem(n,s)) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
21
util/ego/share/cset.h
Normal file
21
util/ego/share/cset.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* O P E R A T I O N S F O R
|
||||
* C O M P A C T S E T S
|
||||
*/
|
||||
|
||||
|
||||
extern cset Cempty_set(); /* (short) */
|
||||
extern bool Cis_elem(); /* (Celem, cset) */
|
||||
extern Cadd(); /* (Celem, *cset) */
|
||||
extern Cremove(); /* (Celem, *cset) */
|
||||
extern Cindex Cfirst(); /* (cset) */
|
||||
extern Cindex Cnext(); /* (Cindex, cset) */
|
||||
extern Celem_t Celem(); /* (Cindex) */
|
||||
extern Cjoin(); /* (cset, *cset) */
|
||||
extern Cintersect(); /* (cset, *cset) */
|
||||
extern Cdeleteset(); /* (cset) */
|
||||
extern bool Cis_subset(); /* (cset, cset) */
|
||||
extern Cclearset(); /* (cset, *cset) */
|
||||
extern Ccopy_set(); /* (cset, *cset) */
|
||||
extern Csubtract(); /* (cset, *cset) */
|
||||
extern bool Cequal(); /* (cset, cset) */
|
||||
extern short Cnrelems(); /* (cset) */
|
145
util/ego/share/debug.c
Normal file
145
util/ego/share/debug.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
/* S H A R E D F I L E
|
||||
*
|
||||
* D E B U G . C
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "types.h"
|
||||
#include "def.h"
|
||||
#include "debug.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "global.h"
|
||||
|
||||
|
||||
|
||||
int linecount; /* # lines in this file */
|
||||
bool verbose_flag = FALSE; /* generate verbose output ? */
|
||||
|
||||
/* VARARGS1 */
|
||||
error(s,a) char *s,*a; {
|
||||
|
||||
fprintf(stderr,"error on line %u",linecount);
|
||||
if (filename != (char *) 0) {
|
||||
fprintf(stderr," file %s",filename);
|
||||
}
|
||||
fprintf(stderr,": ");
|
||||
fprintf(stderr,s,a);
|
||||
fprintf(stderr,"\n");
|
||||
_cleanup();
|
||||
abort();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
#ifdef TRACE
|
||||
/* VARARGS1 */
|
||||
OUTTRACE(s,n)
|
||||
char *s;
|
||||
int n;
|
||||
{
|
||||
fprintf(stderr,"> ");
|
||||
fprintf(stderr,s,n);
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VERBOSE
|
||||
/* VARARGS1 */
|
||||
OUTVERBOSE(s,n1,n2)
|
||||
char *s;
|
||||
int n1,n2;
|
||||
{
|
||||
if (verbose_flag) {
|
||||
fprintf(stderr,"optimization: ");
|
||||
fprintf(stderr,s,n1,n2);
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
badassertion(file,line) char *file; unsigned line; {
|
||||
|
||||
fprintf(stderr,"assertion failed file %s, line %u\n",file,line);
|
||||
error("assertion");
|
||||
}
|
||||
#endif
|
||||
/* Valid Address */
|
||||
|
||||
VA(a) short *a; {
|
||||
if (a == (short *) 0) error("VA: 0 argument");
|
||||
if ( ((unsigned) a & 01) == 01) {
|
||||
/* MACHINE DEPENDENT TEST */
|
||||
error("VA: odd argument");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Valid Instruction code */
|
||||
|
||||
VI(i) short i; {
|
||||
if (i > ps_last) error("VI: illegal instr: %d", i);
|
||||
}
|
||||
|
||||
|
||||
/* Valid Line */
|
||||
|
||||
VL(l) line_p l; {
|
||||
byte instr, optype;
|
||||
|
||||
VA((short *) l);
|
||||
instr = l->l_instr;
|
||||
VI(instr);
|
||||
optype = TYPE(l);
|
||||
if (optype < OP_FIRST || optype > OP_LAST) {
|
||||
error("VL: illegal optype: %d", optype);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Valid Data block */
|
||||
|
||||
VD(d) dblock_p d; {
|
||||
byte pseudo;
|
||||
|
||||
VA((short *) d);
|
||||
pseudo = d->d_pseudo;
|
||||
if (pseudo < D_FIRST || pseudo > D_LAST) {
|
||||
error("VD: illegal pseudo: %d",pseudo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Valid Object */
|
||||
|
||||
VO(o) obj_p o; {
|
||||
offset off;
|
||||
|
||||
VA((short *) o);
|
||||
off = o->o_off;
|
||||
if (off < 0 || off > 10000) {
|
||||
error("VO: unlikely offset: %d", off);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Valid Proc */
|
||||
|
||||
VP(p) proc_p p; {
|
||||
proc_id pid;
|
||||
int nrlabs;
|
||||
|
||||
VA((short *) p);
|
||||
pid = p->p_id;
|
||||
if (pid <0 || pid > 1000) {
|
||||
error("VP: unlikely proc_id: %d", (int) pid);
|
||||
}
|
||||
nrlabs = p->p_nrlabels;
|
||||
if (nrlabs < 0 || nrlabs > 500) {
|
||||
error("VP: unlikely p_nrlabels: %d", nrlabs);
|
||||
}
|
||||
}
|
56
util/ego/share/debug.h
Normal file
56
util/ego/share/debug.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* D E B U G G I N G T O O L S */
|
||||
|
||||
/* TEMPORARY: */
|
||||
#define DEBUG
|
||||
|
||||
extern int linecount; /* # lines in this file */
|
||||
extern bool verbose_flag; /* generate verbose output ? */
|
||||
|
||||
/* VARARGS 1 */
|
||||
error();
|
||||
|
||||
|
||||
#ifdef TRACE
|
||||
extern OUTTRACE();
|
||||
#else
|
||||
#define OUTTRACE(s,n)
|
||||
#endif
|
||||
#ifdef VERBOSE
|
||||
extern OUTVERBOSE();
|
||||
#else
|
||||
#define OUTVERBOSE(s,n1,n2)
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
|
||||
/* Some (all?) Unix debuggers don't particularly like
|
||||
* static procedures and variables. Therefor we make everything
|
||||
* global when debugging.
|
||||
*/
|
||||
|
||||
#define STATIC
|
||||
|
||||
#define assert(x) if(!(x)) badassertion(__FILE__,__LINE__)
|
||||
|
||||
extern VI();
|
||||
extern VL();
|
||||
extern VD();
|
||||
extern VA();
|
||||
extern VO();
|
||||
extern VP();
|
||||
|
||||
|
||||
|
||||
#else /*DEBUG*/
|
||||
|
||||
#define assert(b)
|
||||
|
||||
#define VI(i)
|
||||
#define VL(l)
|
||||
#define VD(d)
|
||||
#define VA(a)
|
||||
#define VO(o)
|
||||
#define VP(p)
|
||||
|
||||
|
||||
#define STATIC static
|
||||
#endif
|
14
util/ego/share/def.h
Normal file
14
util/ego/share/def.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* G L O B A L M A C R O D E F I N I T I O N S
|
||||
*
|
||||
* F O R A L L O P T I M I Z E R P A S S E S
|
||||
*/
|
||||
|
||||
#define MARK_DBLOCK 0
|
||||
#define MARK_OBJ 1
|
||||
#define MARK_ARG 2
|
||||
|
||||
|
||||
#define op_lab (sp_lmnem+1)
|
||||
#define op_last op_lab
|
||||
#define ps_sym (sp_lpseu+1)
|
||||
#define ps_last ps_sym
|
17
util/ego/share/files.c
Normal file
17
util/ego/share/files.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* S H A R E D F I L E
|
||||
*
|
||||
* F I L E S . C
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
FILE *openfile(name,mode)
|
||||
char *name,*mode;
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
if ((f = fopen(name,mode)) == NULL) {
|
||||
error("cannot open %s",name);
|
||||
}
|
||||
return f;
|
||||
}
|
33
util/ego/share/files.h
Normal file
33
util/ego/share/files.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* F I L E N A M E S */
|
||||
|
||||
/* The names of the input files of every phase are passed as
|
||||
* arguments to the phase. First come the input file names,
|
||||
* then the output file names. We use a one-letter convention
|
||||
* to denote the type of file:
|
||||
* p: procedure table file
|
||||
* d: data table file
|
||||
* l: EM text file (lines of EM instructions)
|
||||
* b: basic block file (Control Flow Graph file)
|
||||
*/
|
||||
|
||||
/* The input file names */
|
||||
|
||||
#define pname argv[1]
|
||||
#define dname argv[2]
|
||||
#define lname argv[3]
|
||||
#define bname argv[4]
|
||||
|
||||
/* The output file names */
|
||||
|
||||
#define pname2 argv[5]
|
||||
#define dname2 argv[6]
|
||||
#define lname2 argv[7]
|
||||
#define bname2 argv[8]
|
||||
|
||||
#define ARGSTART 9
|
||||
|
||||
extern FILE *openfile(); /* (char *name, *mode)
|
||||
* Open a file with the given name
|
||||
* and mode; aborts if the file
|
||||
* cannot be opened.
|
||||
*/
|
911
util/ego/share/get.c
Normal file
911
util/ego/share/get.c
Normal file
|
@ -0,0 +1,911 @@
|
|||
/* S H A R E D F I L E
|
||||
*
|
||||
* G E T . C
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "types.h"
|
||||
#include "def.h"
|
||||
#include "debug.h"
|
||||
#include "global.h"
|
||||
#include "lset.h"
|
||||
#include "cset.h"
|
||||
#include "get.h"
|
||||
#include "alloc.h"
|
||||
#include "map.h"
|
||||
#include "aux.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_mes.h"
|
||||
#include "../../../h/em_flag.h"
|
||||
|
||||
extern char em_flag[];
|
||||
|
||||
|
||||
/* global variables */
|
||||
|
||||
static FILE *f;
|
||||
STATIC block_id lastbid; /* block identifying number */
|
||||
STATIC lab_id lastlabid; /* last label identifier */
|
||||
|
||||
/* creating new identifying numbers, i.e. numbers that did not
|
||||
* appear in the input.
|
||||
*/
|
||||
|
||||
bblock_p freshblock()
|
||||
{
|
||||
bblock_p b;
|
||||
b = newbblock();
|
||||
b->b_id = ++lastbid;
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
lab_id freshlabel()
|
||||
{
|
||||
curproc->p_nrlabels++;
|
||||
return ++lastlabid;
|
||||
}
|
||||
|
||||
|
||||
/* local routines */
|
||||
|
||||
#define getbyte() getc(f)
|
||||
|
||||
#define getmark() getbyte()
|
||||
|
||||
STATIC short getshort() {
|
||||
register int l_byte, h_byte;
|
||||
|
||||
l_byte = getbyte();
|
||||
h_byte = getbyte();
|
||||
if ( h_byte>=128 ) h_byte -= 256 ;
|
||||
return l_byte | (h_byte*256) ;
|
||||
}
|
||||
|
||||
|
||||
STATIC offset getoff() {
|
||||
register long l;
|
||||
register int h_byte;
|
||||
|
||||
l = getbyte();
|
||||
l |= ((unsigned) getbyte())*256 ;
|
||||
l |= getbyte()*256L*256L ;
|
||||
h_byte = getbyte() ;
|
||||
if ( h_byte>=128 ) h_byte -= 256 ;
|
||||
return l | (h_byte*256L*256*256L) ;
|
||||
}
|
||||
|
||||
STATIC int getint()
|
||||
{
|
||||
/* Read an integer from the input file. This routine is
|
||||
* only used when reading a bitvector-set. We expect an
|
||||
* integer to be either a short or a long.
|
||||
*/
|
||||
|
||||
if (sizeof(int) == sizeof(short)) {
|
||||
return getshort();
|
||||
} else {
|
||||
assert (sizeof(int) == sizeof(offset));
|
||||
return getoff();
|
||||
}
|
||||
}
|
||||
|
||||
/* getptable */
|
||||
|
||||
loop_p getloop(id)
|
||||
loop_id id;
|
||||
{
|
||||
/* Map a loop identifier onto a loop struct.
|
||||
* If no struct was alocated yet for this identifier then
|
||||
* allocate one now and update the loop-map table.
|
||||
*/
|
||||
|
||||
|
||||
assert (id > 0 && id <=lplength);
|
||||
if (lpmap[id] == (loop_p) 0) {
|
||||
lpmap[id] = newloop();
|
||||
lpmap[id]->lp_id = id;
|
||||
}
|
||||
return (lpmap[id]);
|
||||
}
|
||||
|
||||
bblock_p getblock(id)
|
||||
block_id id;
|
||||
{
|
||||
/* Map a basic block identifier onto a block struct
|
||||
* If no struct was alocated yet for this identifier then
|
||||
* allocate one now and update the block-map table.
|
||||
*/
|
||||
|
||||
|
||||
assert (id >= 0 && id <=blength);
|
||||
if (id == 0) return (bblock_p) 0;
|
||||
if (bmap[id] == (bblock_p) 0) {
|
||||
bmap[id] = newbblock();
|
||||
bmap[id]->b_id = id;
|
||||
}
|
||||
return (bmap[id]);
|
||||
}
|
||||
|
||||
|
||||
lset getlset(p)
|
||||
char *((*p) ());
|
||||
{
|
||||
/* Read a 'long' set. Such a set is represented externally
|
||||
* as a sequence of identifying numbers terminated by a 0.
|
||||
* The procedural parameter p maps such a number onto a
|
||||
* pointer to a struct (bblock_p, loop_p etc.).
|
||||
*/
|
||||
|
||||
lset s;
|
||||
int id;
|
||||
|
||||
s = Lempty_set();
|
||||
while (id = getshort()) {
|
||||
Ladd( (*p) (id), &s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
cset getcset()
|
||||
{
|
||||
/* Read a 'compact' set. Such a set is represented externally
|
||||
* a row of bytes (its bitvector) preceded by its length.
|
||||
*/
|
||||
|
||||
cset s;
|
||||
register short i;
|
||||
|
||||
s = Cempty_set(getshort());
|
||||
for (i = 0; i <= DIVWL(s->v_size-1);i++) {
|
||||
s->v_bits[i] = getint();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
proc_p getptable(pname)
|
||||
char *pname;
|
||||
{
|
||||
short i;
|
||||
proc_p head, p, *pp;
|
||||
short all;
|
||||
|
||||
if ((f = fopen(pname,"r")) == NULL) {
|
||||
error("cannot open %s",pname);
|
||||
}
|
||||
|
||||
plength = getshort(); /* table is preceded by its length */
|
||||
assert(plength >= 0);
|
||||
assert(plength < 1000); /* See if its a reasonable number */
|
||||
pmap = (proc_p *) newmap(plength); /* allocate the pmap table */
|
||||
|
||||
all = getshort();
|
||||
head = (proc_p) 0;
|
||||
pp = &head;
|
||||
for (i = 0; i < plength; i++) {
|
||||
if (feof(f)) {
|
||||
error("unexpected eof %s", pname);
|
||||
}
|
||||
p = newproc();
|
||||
p->p_id = getshort();
|
||||
assert(p->p_id > 0 && p->p_id <= plength);
|
||||
pmap[p->p_id] = p;
|
||||
p->p_flags1 = getbyte();
|
||||
if (p->p_flags1 & PF_BODYSEEN) {
|
||||
p->p_nrlabels = getshort();
|
||||
p->p_localbytes = getoff();
|
||||
p->p_nrformals = getoff();
|
||||
if (all) {
|
||||
p->p_change = newchange();
|
||||
p->p_change->c_ext = getcset();
|
||||
p->p_change->c_flags = getshort();
|
||||
p->p_use = newuse();
|
||||
p->p_use->u_flags = getshort();
|
||||
p->p_calling = getcset();
|
||||
}
|
||||
}
|
||||
*pp = p;
|
||||
pp = &(p->p_next);
|
||||
}
|
||||
fclose(f);
|
||||
OUTTRACE("have read proc table of length %d",plength);
|
||||
return head; /* pointer to first structure of list */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* getdtable */
|
||||
|
||||
dblock_p getdtable(dname)
|
||||
char *dname;
|
||||
{
|
||||
/* Read the data block table. Every data block may
|
||||
* have a list of objects and a list of values (arguments),
|
||||
* each of which is also represented by a structure.
|
||||
* So the input file contains a mixture of dblock,
|
||||
* obj and arg records, each one having its own
|
||||
* attributes. A mark indicates which one comes next.
|
||||
* We assume that the syntactic structure of the input
|
||||
* is correct.
|
||||
*/
|
||||
|
||||
dblock_p head, d, *dp;
|
||||
obj_p obj, *op;
|
||||
arg_p arg, *ap;
|
||||
/* dp, op an ap tell how the next dblock/obj/arg
|
||||
* has to be linked.
|
||||
*/
|
||||
int n;
|
||||
|
||||
head = (dblock_p) 0;
|
||||
dp = &head;
|
||||
if ((f = fopen(dname,"r")) == NULL) {
|
||||
error("cannot open %s", dname);
|
||||
}
|
||||
olength = getshort();
|
||||
assert(olength >= 0);
|
||||
assert(olength < 5000); /* See if its a reasonable number */
|
||||
/* total number of objects */
|
||||
omap = (obj_p *) newmap(olength); /* allocate omap table */
|
||||
|
||||
while (TRUE) {
|
||||
n = getmark();
|
||||
if (feof(f)) break;
|
||||
switch(n) {
|
||||
case MARK_DBLOCK:
|
||||
d = *dp = newdblock();
|
||||
op = &d->d_objlist;
|
||||
ap = &d->d_values;
|
||||
dp = &d->d_next;
|
||||
d->d_id = getshort();
|
||||
d->d_pseudo = getbyte();
|
||||
d->d_size = getoff();
|
||||
d->d_fragmnr = getshort();
|
||||
d->d_flags1 = getbyte();
|
||||
break;
|
||||
case MARK_OBJ:
|
||||
obj = *op = newobject();
|
||||
op = &obj->o_next;
|
||||
obj->o_dblock = d;
|
||||
obj->o_id = getshort();
|
||||
assert(obj->o_id >0);
|
||||
assert(obj->o_id <= olength);
|
||||
omap[obj->o_id] = obj;
|
||||
obj->o_size = getoff();
|
||||
obj->o_off = getoff();
|
||||
break;
|
||||
case MARK_ARG:
|
||||
arg = *ap = newarg(ARGOFF);
|
||||
ap = &arg->a_next;
|
||||
arg->a_a.a_offset = getoff();
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
}
|
||||
OUTTRACE("have read data table, %d objects",olength);
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* getbblocks */
|
||||
|
||||
STATIC argstring(length,abp)
|
||||
short length;
|
||||
register argb_p abp;
|
||||
{
|
||||
|
||||
while (length--) {
|
||||
if (abp->ab_index == NARGBYTES)
|
||||
abp = abp->ab_next = newargb();
|
||||
abp->ab_contents[abp->ab_index++] = getbyte();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC arg_p readargs()
|
||||
{
|
||||
/* Read a list of arguments and allocate structures
|
||||
* for them. Return a pointer to the head of the list.
|
||||
*/
|
||||
|
||||
arg_p head, arg, *ap;
|
||||
byte t;
|
||||
short length;
|
||||
|
||||
ap = &head;
|
||||
for (;;) {
|
||||
/* every argument list is terminated by an
|
||||
* ARGCEND byte in Intermediate Code.
|
||||
*/
|
||||
t = getbyte();
|
||||
if (t == (byte) ARGCEND) {
|
||||
return head;
|
||||
}
|
||||
arg = *ap = newarg(t);
|
||||
ap = &arg->a_next;
|
||||
switch((short) t) {
|
||||
case ARGOFF:
|
||||
arg->a_a.a_offset = getoff();
|
||||
break;
|
||||
case ARGINSTRLAB:
|
||||
arg->a_a.a_instrlab = getshort();
|
||||
break;
|
||||
case ARGOBJECT:
|
||||
arg->a_a.a_obj = omap[getshort()];
|
||||
/* Read an object identifier (o_id)
|
||||
* and use the omap table to obtain
|
||||
* a pointer to the rigth obj struct.
|
||||
*/
|
||||
break;
|
||||
case ARGPROC:
|
||||
arg->a_a.a_proc = pmap[getshort()];
|
||||
/* Read a procedure identifier (p_id) */
|
||||
break;
|
||||
case ARGSTRING:
|
||||
length = getshort();
|
||||
argstring(length, &arg->a_a.a_string);
|
||||
break;
|
||||
case ARGICN:
|
||||
case ARGUCN:
|
||||
case ARGFCN:
|
||||
length = getshort();
|
||||
arg->a_a.a_con.ac_length = length;
|
||||
/* size of the constant */
|
||||
argstring(getshort(),
|
||||
&arg->a_a.a_con.ac_con);
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC line_p read_line(p_out)
|
||||
proc_p *p_out;
|
||||
{
|
||||
/* Read a line of EM code (i.e. one instruction)
|
||||
* and its arguments (if any).
|
||||
* In Intermediate Code, the first byte is the
|
||||
* instruction code and the second byte denotes the kind
|
||||
* of operand(s) that follow.
|
||||
*/
|
||||
|
||||
line_p lnp;
|
||||
byte instr;
|
||||
|
||||
instr = getbyte();
|
||||
if (feof(f)) return (line_p) 0;
|
||||
lnp = newline(getbyte());
|
||||
linecount++;
|
||||
lnp->l_instr = instr;
|
||||
switch(TYPE(lnp)) {
|
||||
/* read the operand(s) */
|
||||
case OPSHORT:
|
||||
SHORT(lnp) = getshort();
|
||||
break;
|
||||
case OPOFFSET:
|
||||
OFFSET(lnp) = getoff();
|
||||
break;
|
||||
case OPINSTRLAB:
|
||||
INSTRLAB(lnp) = getshort();
|
||||
if (instr == op_lab) {
|
||||
/* defining occurrence of an
|
||||
* instruction label.
|
||||
*/
|
||||
lmap[INSTRLAB(lnp)] = lnp;
|
||||
}
|
||||
break;
|
||||
case OPOBJECT:
|
||||
OBJ(lnp) = omap[getshort()];
|
||||
break;
|
||||
case OPPROC:
|
||||
PROC(lnp) = pmap[getshort()];
|
||||
if ((instr & BMASK) == ps_pro) {
|
||||
/* enter new procedure: allocate a
|
||||
* label map and a label-block map table.
|
||||
*/
|
||||
*p_out = PROC(lnp);
|
||||
llength = (*p_out)->p_nrlabels;
|
||||
lmap = (line_p *) newmap(llength);
|
||||
/* maps lab_id to line structure */
|
||||
lbmap = (bblock_p *) newmap(llength);
|
||||
/* maps lab_id to bblock structure */
|
||||
lastlabid = llength;
|
||||
}
|
||||
break;
|
||||
case OPLIST:
|
||||
ARG(lnp) = readargs();
|
||||
break;
|
||||
default:
|
||||
assert(TYPE(lnp) == OPNO);
|
||||
}
|
||||
return lnp;
|
||||
}
|
||||
|
||||
|
||||
STATIC message(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* See if lnp is some useful message.
|
||||
* (e.g. a message telling that a certain local variable
|
||||
* will never be referenced indirectly, so it may be put
|
||||
* in a register. If so, add it to the mesregs set.)
|
||||
*/
|
||||
|
||||
assert(ARG(lnp)->a_type == ARGOFF);
|
||||
switch((int) aoff(ARG(lnp),0)) {
|
||||
case ms_reg:
|
||||
if (ARG(lnp)->a_next != (arg_p) 0) {
|
||||
/* take only "mes 3" with further arguments */
|
||||
Ladd(lnp,&mesregs);
|
||||
}
|
||||
break;
|
||||
case ms_err:
|
||||
error("ms_err encountered");
|
||||
case ms_opt:
|
||||
error("ms_opt encountered");
|
||||
case ms_emx:
|
||||
ws = aoff(ARG(lnp),1);
|
||||
ps = aoff(ARG(lnp),2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC line_p getlines(lf,n,p_out,collect_mes)
|
||||
FILE *lf;
|
||||
int n;
|
||||
proc_p *p_out;
|
||||
bool collect_mes;
|
||||
{
|
||||
/* Read n lines of EM text and doubly link them.
|
||||
* Also process messages.
|
||||
*/
|
||||
|
||||
line_p head, *pp, l, lprev;
|
||||
|
||||
f = lf; /* EM input file */
|
||||
pp = &head;
|
||||
lprev = (line_p) 0;
|
||||
while (n--) {
|
||||
l = *pp = read_line(p_out);
|
||||
PREV(l) = lprev;
|
||||
pp = &l->l_next;
|
||||
lprev = l;
|
||||
if (collect_mes && INSTR(l) == ps_mes) {
|
||||
message(l);
|
||||
}
|
||||
}
|
||||
*pp = (line_p) 0;
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool getunit(gf,lf,kind_out,g_out,l_out,p_out,collect_mes)
|
||||
FILE *gf,*lf;
|
||||
short *kind_out;
|
||||
bblock_p *g_out;
|
||||
line_p *l_out;
|
||||
proc_p *p_out;
|
||||
bool collect_mes;
|
||||
{
|
||||
/* Read control flow graph (gf) and EM text (lf) of the next procedure.
|
||||
* A pointer to the proctable entry of the read procedure is
|
||||
* returned via p_out.
|
||||
* This routine also constructs the bmap and lpmap tables.
|
||||
* Note that we allocate structs for basic blocks and loops
|
||||
* at their first reference rather than at when we read them.
|
||||
*/
|
||||
|
||||
int n,i;
|
||||
bblock_p head, *pp, b;
|
||||
loop_p lp;
|
||||
|
||||
f = gf;
|
||||
blength = getshort(); /* # basic blocks in this procedure */
|
||||
if (feof(f)) return FALSE;
|
||||
if (blength == 0) {
|
||||
/* data unit */
|
||||
*kind_out = LDATA;
|
||||
n = getshort();
|
||||
*l_out = getlines(lf,n,p_out,collect_mes);
|
||||
return TRUE;
|
||||
}
|
||||
*kind_out = LTEXT;
|
||||
bmap = (bblock_p *) newmap(blength); /* maps block_id on bblock_p */
|
||||
lplength = getshort(); /* # loops in this procedure */
|
||||
lpmap = (loop_p *) newmap(lplength); /* maps loop_id on loop_p */
|
||||
|
||||
/* Read the basic blocks and the EM text */
|
||||
pp = &head; /* we use a pointer-to-a-pointer to link the structs */
|
||||
for (i = 0; i < blength; i++) {
|
||||
b = getblock(getshort());
|
||||
n = getshort(); /* #instructions in the block */
|
||||
b->b_succ = getlset(getblock);
|
||||
b->b_pred = getlset(getblock);
|
||||
b->b_idom = getblock(getshort());
|
||||
b->b_loops = getlset(getloop);
|
||||
b->b_flags = getshort();
|
||||
b->b_start = getlines(lf,n,p_out,collect_mes); /* read EM text */
|
||||
*pp = b;
|
||||
pp = &b->b_next;
|
||||
f = gf;
|
||||
}
|
||||
lastbid = blength; /* last block_id */
|
||||
|
||||
/* read the information about loops */
|
||||
curproc->p_loops = Lempty_set();
|
||||
for (i = 0; i < lplength; i++) {
|
||||
lp = getloop(getshort());
|
||||
lp->lp_level = getshort(); /* nesting level */
|
||||
lp->lp_entry = getblock(getshort()); /* entry block of the loop */
|
||||
lp->lp_end = getblock(getshort()); /* tail of back edge of loop */
|
||||
Ladd(lp,&curproc->p_loops);
|
||||
}
|
||||
*g_out = head;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* The procedure getbblocks is used only by the Control Flow phase.
|
||||
* It reads the EM textfile and partitions every procedure into
|
||||
* a number of basic blocks.
|
||||
*/
|
||||
|
||||
|
||||
#define LABEL0 0
|
||||
#define LABEL 1
|
||||
#define NORMAL 2
|
||||
#define JUMP 3
|
||||
#define END 4
|
||||
#define AFTERPRO 5
|
||||
#define INIT 6
|
||||
|
||||
|
||||
/* These global variables are used by getbblocks and nextblock. */
|
||||
|
||||
STATIC bblock_p b, *bp; /* b is the current basic block, bp is
|
||||
* the address where the next block has
|
||||
* to be linked.
|
||||
*/
|
||||
STATIC line_p lnp, *lp; /* lnp is the current line, lp is
|
||||
* the address where the next line
|
||||
* has to be linked.
|
||||
*/
|
||||
STATIC short state; /* We use a finite state machine with the
|
||||
* following states:
|
||||
* LABEL0: after the first (successive)
|
||||
* instruction label.
|
||||
* LABEL1: after at least two successive
|
||||
* instruction labels.
|
||||
* NORMAL: after a normal instruction.
|
||||
* JUMP: after a branch (conditional,
|
||||
* unconditional or CSA/CSB).
|
||||
* END: after an END pseudo
|
||||
* AFTERPRO: after we've read a PRO pseudo
|
||||
* INIT: initial state
|
||||
*/
|
||||
|
||||
|
||||
STATIC nextblock()
|
||||
{
|
||||
/* allocate a new basic block structure and
|
||||
* set b, bp and lp.
|
||||
*/
|
||||
|
||||
b = *bp = freshblock();
|
||||
bp = &b->b_next;
|
||||
b->b_start = lnp;
|
||||
b->b_succ = Lempty_set();
|
||||
b->b_pred = Lempty_set();
|
||||
b->b_extend = newcfbx(); /* basic block extension for CF */
|
||||
b->b_extend->bx_cf.bx_bucket = Lempty_set();
|
||||
b->b_extend->bx_cf.bx_semi = 0;
|
||||
lp = &lnp->l_next;
|
||||
#ifdef TRACE
|
||||
fprintf(stderr,"new basic block, id = %d\n",lastbid);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
STATIC short kind(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* determine if lnp is a label, branch, end or otherwise */
|
||||
|
||||
short instr;
|
||||
byte flow;
|
||||
|
||||
if ((instr = INSTR(lnp)) == op_lab) return (short) LABEL;
|
||||
if (instr == ps_end) return (short) END;
|
||||
if (instr > sp_lmnem) return (short) NORMAL; /* pseudo */
|
||||
if ((flow = (em_flag[instr-sp_fmnem] & EM_FLO)) == FLO_C ||
|
||||
flow == FLO_T) return (short) JUMP; /* conditional/uncond. jump */
|
||||
return (short) NORMAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool getbblocks(fp,kind_out,n_out,g_out,l_out)
|
||||
FILE *fp;
|
||||
short *kind_out;
|
||||
short *n_out;
|
||||
bblock_p *g_out;
|
||||
line_p *l_out;
|
||||
{
|
||||
bblock_p head = (bblock_p) 0;
|
||||
line_p headl = (line_p) 0;
|
||||
|
||||
curproc = (proc_p) 0;
|
||||
/* curproc will get a value when we encounter a PRO pseudo.
|
||||
* If there is no such pseudo, we're reading only data
|
||||
* declarations or messages (outside any proc.).
|
||||
*/
|
||||
f = fp;
|
||||
lastbid = (block_id) 0; /* block identier */
|
||||
state = INIT; /* initial state */
|
||||
bp = &head;
|
||||
|
||||
for (;;) {
|
||||
#ifdef TRACE
|
||||
fprintf(stderr,"state = %d\n",state);
|
||||
#endif
|
||||
switch(state) {
|
||||
case LABEL0:
|
||||
nextblock();
|
||||
/* Fall through !! */
|
||||
case LABEL:
|
||||
lbmap[INSTRLAB(lnp)] = b;
|
||||
/* The lbmap table contains for each
|
||||
* label_id the basic block of that label.
|
||||
*/
|
||||
lnp = read_line(&curproc);
|
||||
state = kind(lnp);
|
||||
if (state != END) {
|
||||
*lp = lnp;
|
||||
lp = &lnp->l_next;
|
||||
}
|
||||
break;
|
||||
case NORMAL:
|
||||
lnp = read_line(&curproc);
|
||||
if ( (state = kind(lnp)) == LABEL) {
|
||||
/* If we come accross a label
|
||||
* here, it must be the beginning
|
||||
* of a new basic block.
|
||||
*/
|
||||
state = LABEL0;
|
||||
} else {
|
||||
if (state != END) {
|
||||
*lp = lnp;
|
||||
lp = &lnp->l_next;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JUMP:
|
||||
lnp = read_line(&curproc);
|
||||
/* fall through ... */
|
||||
case AFTERPRO:
|
||||
switch(state = kind(lnp)) {
|
||||
case LABEL:
|
||||
state = LABEL0;
|
||||
break;
|
||||
case JUMP:
|
||||
case NORMAL:
|
||||
nextblock();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case END:
|
||||
*lp = lnp;
|
||||
#ifdef TRACE
|
||||
fprintf(stderr,"at end of proc, %d blocks\n",lastbid);
|
||||
#endif
|
||||
if (head == (bblock_p) 0) {
|
||||
*kind_out = LDATA;
|
||||
*l_out = headl;
|
||||
} else {
|
||||
*kind_out = LTEXT;
|
||||
*g_out = head;
|
||||
*n_out = (short) lastbid;
|
||||
/* number of basic blocks */
|
||||
}
|
||||
return TRUE;
|
||||
case INIT:
|
||||
lnp = read_line(&curproc);
|
||||
if (feof(f)) return FALSE;
|
||||
if (INSTR(lnp) == ps_pro) {
|
||||
state = AFTERPRO;
|
||||
} else {
|
||||
state = NORMAL;
|
||||
headl = lnp;
|
||||
lp = &lnp->l_next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The following routines are only used by the Inline Substitution phase */
|
||||
|
||||
call_p getcall(cf)
|
||||
FILE *cf;
|
||||
{
|
||||
/* read a call from the call-file */
|
||||
|
||||
call_p c;
|
||||
proc_p voided;
|
||||
actual_p act,*app;
|
||||
short n,m;
|
||||
|
||||
f = cf;
|
||||
c = newcall();
|
||||
n = getshort(); /* void nesting level */
|
||||
if (feof(f)) return (call_p) 0;
|
||||
c->cl_caller = pmap[getshort()];
|
||||
c->cl_id = getshort();
|
||||
c->cl_proc = pmap[getshort()];
|
||||
c->cl_looplevel = getbyte();
|
||||
c->cl_flags = getbyte();
|
||||
c->cl_ratio = getshort();
|
||||
app = &c->cl_actuals;
|
||||
n = getshort();
|
||||
while(n--) {
|
||||
act = newactual();
|
||||
m = getshort();
|
||||
act->ac_size = getoff();
|
||||
act->ac_inl = getbyte();
|
||||
act->ac_exp = getlines(cf,m,&voided);
|
||||
*app = act;
|
||||
app = &act->ac_next;
|
||||
}
|
||||
*app = (actual_p) 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
line_p get_text(lf,p_out)
|
||||
FILE *lf;
|
||||
proc_p *p_out;
|
||||
{
|
||||
/* Read the EM text of one unit
|
||||
* If it is a procedure, set p_out to
|
||||
* the proc. just read. Else set p_out
|
||||
* to 0.
|
||||
*/
|
||||
|
||||
line_p dumhead, l, lprev;
|
||||
loop_p *oldlpmap = lpmap;
|
||||
line_p *oldlmap = lmap;
|
||||
short oldllength = llength;
|
||||
short oldlastlabid = lastlabid;
|
||||
|
||||
f = lf;
|
||||
*p_out = (proc_p) 0;
|
||||
dumhead = newline(OPNO);
|
||||
/* The list of instructions is preceeded by a dummy
|
||||
* line, to simplify list manipulation
|
||||
*/
|
||||
dumhead->l_instr = op_nop; /* just for fun */
|
||||
lprev = dumhead;
|
||||
for (;;) {
|
||||
l = read_line(p_out);
|
||||
if (feof(f)) return (line_p) 0;
|
||||
lprev->l_next = l;
|
||||
PREV(l) = lprev;
|
||||
if (INSTR(l) == ps_end) break;
|
||||
if (INSTR(l) == ps_mes) {
|
||||
message(l);
|
||||
}
|
||||
lprev = l;
|
||||
}
|
||||
/* The tables that map labels to instructions
|
||||
* and labels to basic blocks are not used.
|
||||
*/
|
||||
if (*p_out != (proc_p) 0) {
|
||||
oldmap(lmap,llength);
|
||||
oldmap(lbmap,llength);
|
||||
lmap = oldlmap;
|
||||
lpmap = oldlpmap;
|
||||
}
|
||||
llength = oldllength;
|
||||
lastlabid = oldlastlabid;
|
||||
return dumhead;
|
||||
}
|
||||
|
||||
|
||||
|
||||
calcnt_p getcc(ccf,p)
|
||||
FILE *ccf;
|
||||
proc_p p;
|
||||
{
|
||||
/* Get call-count info of procedure p */
|
||||
|
||||
calcnt_p head,cc,*ccp;
|
||||
short i;
|
||||
|
||||
fseek(ccf,p->p_extend->px_il.p_ccaddr,0);
|
||||
f = ccf;
|
||||
head = (calcnt_p) 0;
|
||||
ccp = &head;
|
||||
for (i = getshort(); i != (short) 0; i--) {
|
||||
cc = *ccp = newcalcnt();
|
||||
cc->cc_proc = pmap[getshort()];
|
||||
cc->cc_count = getshort();
|
||||
ccp = &cc->cc_next;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
/* The following routine is only used by the Compact Assembly generation phase,
|
||||
* which does not read basic blocks.
|
||||
*/
|
||||
|
||||
line_p get_ca_lines(lf,p_out)
|
||||
FILE *lf;
|
||||
proc_p *p_out;
|
||||
{
|
||||
/* Read lines of EM text and link them.
|
||||
* Register messages are outputted immediately after the PRO.
|
||||
*/
|
||||
|
||||
line_p head, *pp, l;
|
||||
line_p headm, *mp;
|
||||
arg_p a;
|
||||
|
||||
f = lf; /* EM input file */
|
||||
pp = &head;
|
||||
mp = &headm;
|
||||
headm = (line_p) 0;
|
||||
while (TRUE) {
|
||||
l = read_line(p_out);
|
||||
if (feof(f)) break;
|
||||
assert (l != (line_p) 0);
|
||||
if (INSTR(l) == ps_end && INSTR(head) != ps_pro) {
|
||||
/* Delete end pseudo after data-unit */
|
||||
oldline(l);
|
||||
break;
|
||||
}
|
||||
if (INSTR(l) == ps_mes && l->l_a.la_arg->a_a.a_offset == ms_reg) {
|
||||
/* l is a register message */
|
||||
if (l->l_a.la_arg->a_next == (arg_p) 0) {
|
||||
/* register message without arguments */
|
||||
oldline(l);
|
||||
} else {
|
||||
*mp = l;
|
||||
mp = &l->l_next;
|
||||
}
|
||||
} else {
|
||||
*pp = l;
|
||||
pp = &l->l_next;
|
||||
}
|
||||
if (INSTR(l) == ps_end) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*pp = (line_p) 0;
|
||||
if (INSTR(head) == ps_pro) {
|
||||
/* append register message without arguments to list */
|
||||
l = newline(OPLIST);
|
||||
l->l_instr = ps_mes;
|
||||
a = ARG(l) = newarg(ARGOFF);
|
||||
a->a_a.a_offset = ms_reg;
|
||||
*mp = l;
|
||||
l->l_next = head->l_next;
|
||||
head->l_next = headm;
|
||||
} else {
|
||||
assert(headm == (line_p) 0);
|
||||
}
|
||||
return head;
|
||||
}
|
56
util/ego/share/get.h
Normal file
56
util/ego/share/get.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* I N P U T R O U T I N E S */
|
||||
|
||||
extern bblock_p freshblock(); /* ()
|
||||
* Allocate a bblock struct and assign
|
||||
* it a brand new block_id.
|
||||
*/
|
||||
extern lab_id freshlabel(); /* ()
|
||||
* Get a brand new lab_id.
|
||||
*/
|
||||
extern dblock_p getdtable(); /* (char *dname)
|
||||
* Read the data block table from
|
||||
* the file with the given name.
|
||||
*/
|
||||
extern proc_p getptable(); /* (char *pname)
|
||||
* Read the proc table from
|
||||
* the file with the given name.
|
||||
*/
|
||||
extern bool getunit(); /* (FILE *gf,*lf; short kind_out;
|
||||
* bblock_p g_out; line_p l_out;
|
||||
* proc_p *p_out; bool collect_mes)
|
||||
* Read the control flow graph
|
||||
* (from file gf) and the EM text
|
||||
* (from lf). If collect_mes is TRUE,
|
||||
* all register messages will be
|
||||
* collected and put in the global
|
||||
* variable 'mesregs'. The proc read
|
||||
* is returned in p_out.
|
||||
*/
|
||||
extern bool getbblocks(); /* (FILE *f,short kind_out,
|
||||
* short *n_out, bblock_p *g_out,
|
||||
* line_p *l_out)
|
||||
* Read the EM text of a single
|
||||
* unit from the given file.
|
||||
* This unit can be either a procedure
|
||||
* or a umber of data declarations and
|
||||
* messages. If it is a proc., then
|
||||
* partition the text into
|
||||
* basic blocks. Return the
|
||||
* number of basic blocks in n_out.
|
||||
*/
|
||||
extern call_p getcall(); /* (FILE *cf)
|
||||
* Read a call from the call-file
|
||||
*/
|
||||
extern line_p get_text(); /* (FILE *lf; proc_p *p_out)
|
||||
* Read the EM text of one procedure.
|
||||
* The procedure read is returned via
|
||||
* p_out.
|
||||
*/
|
||||
extern calcnt_p getcc(); /* (FILE *ccf; proc_p p)
|
||||
* Read the call-count information
|
||||
* of procedure p.
|
||||
*/
|
||||
extern line_p get_ca_lines(); /* (FILE *lf; proc_p *p_out)
|
||||
* Read em lines till end pseudo is met.
|
||||
* (Used only by CA phase).
|
||||
*/
|
21
util/ego/share/global.c
Normal file
21
util/ego/share/global.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* S H A R E D F I L E
|
||||
*
|
||||
* G L O B A L . C
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
|
||||
int ps = 0;
|
||||
int ws = 0;
|
||||
|
||||
proc_p curproc; /* current procedure */
|
||||
|
||||
char *filename; /* name of current input file */
|
||||
|
||||
lset mesregs; /* set of MES ms_reg pseudos */
|
||||
|
||||
short time_space_ratio = 50;
|
||||
/* 0 if optimizing for space only,
|
||||
* 100 if optimizing for time only,
|
||||
* else something 'in between'.
|
||||
*/
|
51
util/ego/share/global.h
Normal file
51
util/ego/share/global.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/* G L O B A L V A R I A B L E S */
|
||||
|
||||
/* sizes of TARGET machine */
|
||||
|
||||
extern int ps; /* pointer size */
|
||||
extern int ws; /* word size */
|
||||
|
||||
/* sizes of SOURCE machine (i.e. machine on which
|
||||
* the optimizer runs)
|
||||
*/
|
||||
|
||||
/* number of bits in a byte */
|
||||
#define BYTELENGTH 8
|
||||
|
||||
/* number of bits in a word */
|
||||
#define WORDLENGTH 32
|
||||
|
||||
#if BYTELENGTH==8
|
||||
#define DIVBL(a) ((a) >> 3)
|
||||
#define MODBL(a) ((a) & 07)
|
||||
#else
|
||||
#define DIVBL(a) (a/BYTELENGTH)
|
||||
#define MODBL(a) (a%BYTELENGTH)
|
||||
#endif
|
||||
|
||||
#if WORDLENGTH==16
|
||||
#define DIVWL(a) ((a) >> 4)
|
||||
#define MODWL(a) ((a) & 017)
|
||||
#else
|
||||
#if WORDLENGTH==32
|
||||
#define DIVWL(a) ((a) >> 5)
|
||||
#define MODWL(a) ((a) & 037)
|
||||
#else
|
||||
#define DIVWL(a) (a/WORDLENGTH)
|
||||
#define MODWL(a) (a%WORDLENGTH)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#define UNKNOWN_SIZE (-1)
|
||||
|
||||
extern proc_p curproc; /* current procedure */
|
||||
|
||||
extern char *filename; /* name of current input file */
|
||||
|
||||
extern lset mesregs; /* set of MES ms_reg pseudos */
|
||||
|
||||
extern short time_space_ratio; /* 0 if optimizing for space only,
|
||||
* 100 if optimizing for time only,
|
||||
* else something 'in between'.
|
||||
*/
|
152
util/ego/share/go.c
Normal file
152
util/ego/share/go.c
Normal file
|
@ -0,0 +1,152 @@
|
|||
/* S H A R E D F I L E
|
||||
*
|
||||
* G O . C
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "global.h"
|
||||
#include "files.h"
|
||||
#include "get.h"
|
||||
#include "put.h"
|
||||
#include "lset.h"
|
||||
#include "map.h"
|
||||
#include "alloc.h"
|
||||
#include "go.h"
|
||||
|
||||
|
||||
STATIC bool report_flag = FALSE; /* report #optimizations found? */
|
||||
STATIC bool core_flag = FALSE; /* report core usage? */
|
||||
|
||||
|
||||
STATIC mach_init(machfile,phase_machinit)
|
||||
char *machfile;
|
||||
int (*phase_machinit)();
|
||||
{
|
||||
/* Read target machine dependent information */
|
||||
|
||||
FILE *f;
|
||||
|
||||
f = openfile(machfile,"r");
|
||||
fscanf(f,"%d",&ws);
|
||||
fscanf(f,"%d",&ps);
|
||||
if (ws != ps && ps != 2*ws) error("illegal pointer size");
|
||||
phase_machinit(f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
go(argc,argv,initialize,optimize,phase_machinit,proc_flag)
|
||||
int argc;
|
||||
char *argv[];
|
||||
int (*initialize)();
|
||||
int (*optimize)();
|
||||
int (*phase_machinit)();
|
||||
int (*proc_flag)();
|
||||
{
|
||||
FILE *f, *gf, *f2, *gf2; /* The EM input and output and
|
||||
* the basic block graphs input and output
|
||||
*/
|
||||
bblock_p g;
|
||||
line_p l;
|
||||
short kind;
|
||||
int i;
|
||||
char *p;
|
||||
bool time_opt = FALSE;
|
||||
|
||||
linecount = 0;
|
||||
for (i = ARGSTART; i < argc; i++) {
|
||||
p = argv[i];
|
||||
if (*p++ != '-') error("illegal argument");
|
||||
switch(*p) {
|
||||
case 'S':
|
||||
time_opt = FALSE;
|
||||
break;
|
||||
case 'T':
|
||||
time_opt = TRUE;
|
||||
break;
|
||||
case 'M':
|
||||
p++;
|
||||
mach_init(p,phase_machinit);
|
||||
break;
|
||||
case 'C':
|
||||
core_flag = TRUE;
|
||||
break;
|
||||
case 'Q':
|
||||
report_flag = TRUE;
|
||||
break;
|
||||
case 'V':
|
||||
verbose_flag = TRUE;
|
||||
break;
|
||||
default:
|
||||
proc_flag(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
time_space_ratio = (time_opt ? 100 : 0);
|
||||
fproc = getptable(pname); /* proc table */
|
||||
fdblock = getdtable(dname); /* data block table */
|
||||
initialize();
|
||||
if (optimize == no_action) return;
|
||||
f = openfile(lname,"r");
|
||||
gf = openfile(bname,"r");
|
||||
f2 = openfile(lname2,"w");
|
||||
gf2 = openfile(bname2,"w");
|
||||
mesregs = Lempty_set();
|
||||
while (getunit(gf,f,&kind,&g,&l,&curproc,TRUE)) {
|
||||
/* Read the control flow graph and EM text of
|
||||
* one procedure and optimize it.
|
||||
*/
|
||||
if (kind == LDATA) {
|
||||
putunit(LDATA, (proc_p) 0, l, gf2, f2);
|
||||
continue;
|
||||
}
|
||||
OUTTRACE("flow graph of proc %d read",curproc->p_id);
|
||||
curproc->p_start = g;
|
||||
/* The global variable curproc points to the
|
||||
* current procedure. It is set by getgraph
|
||||
*/
|
||||
optimize(curproc);
|
||||
putunit(LTEXT,curproc,(line_p) 0,gf2,f2);
|
||||
/* output control flow graph + text */
|
||||
OUTTRACE("graph of proc %d outputted",curproc->p_id);
|
||||
Ldeleteset(mesregs);
|
||||
mesregs = Lempty_set();
|
||||
}
|
||||
fclose(f);
|
||||
fclose(f2);
|
||||
fclose(gf);
|
||||
fclose(gf2);
|
||||
f = openfile(dname2,"w");
|
||||
putdtable(fdblock,f);
|
||||
fclose(f);
|
||||
f = openfile(pname2,"w");
|
||||
putptable(fproc,f,TRUE);
|
||||
fclose(f);
|
||||
core_usage();
|
||||
}
|
||||
|
||||
|
||||
no_action() { }
|
||||
|
||||
core_usage()
|
||||
{
|
||||
if (core_flag) {
|
||||
coreusage();
|
||||
}
|
||||
}
|
||||
|
||||
report(s,n)
|
||||
char *s;
|
||||
int n;
|
||||
{
|
||||
/* Report number of optimizations found, if report_flag is set */
|
||||
|
||||
if (report_flag) {
|
||||
fprintf(stderr,"%s: %d\n",s,n);
|
||||
}
|
||||
}
|
34
util/ego/share/go.h
Normal file
34
util/ego/share/go.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* S H A R E D F I L E
|
||||
*
|
||||
* G O . H
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
extern go(); /* ( int argc; char *argv[];
|
||||
* int (*initialize)(); int (*optimize)();
|
||||
* int (*phase_machinit)(); int (*proc_flag)() )
|
||||
* This is the main driving routine of the optimizer.
|
||||
* It first processes the flags given as argument;
|
||||
* for every flag it does not recognize itself, it
|
||||
* calls 'proc_flag'; as soon as the -M flag is seen,
|
||||
* it opens the machine descriptor file and
|
||||
* reads phase-independend information (notably the
|
||||
* wordsize and pointersize of the target machine);
|
||||
* next it calls 'phase_machinit' with this file as
|
||||
* parameter. Subsequently it calls 'initialize'.
|
||||
* Finally, all procedures are read, one at a time,
|
||||
* and 'optimize' is called with the current procedure
|
||||
* as parameter.
|
||||
*/
|
||||
extern no_action(); /* ()
|
||||
* Parameter to be supplied for e.g. 'initialize' if
|
||||
* no action is required.
|
||||
*/
|
||||
extern core_usage(); /* ()
|
||||
* Report core usage, if core_flag is set.
|
||||
*/
|
||||
extern report(); /* ( char *s; int n)
|
||||
* Report number of optimizations found, if
|
||||
* report_flag is set
|
||||
*/
|
57
util/ego/share/init_glob.c
Normal file
57
util/ego/share/init_glob.c
Normal file
|
@ -0,0 +1,57 @@
|
|||
|
||||
/* S H A R E D F I L E
|
||||
*
|
||||
* I N I T _ G L O B L S
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/map.h"
|
||||
|
||||
|
||||
extern short nrglobals;
|
||||
|
||||
init_globals()
|
||||
{
|
||||
/* Assign a 'global variable number (o_globnr) to
|
||||
* every global variable for which we want to
|
||||
* maintain ud-info. We do not maintain ud-info
|
||||
* for a global variable if:
|
||||
* - it is part of a ROM data block (so it will never be changed)
|
||||
* - it's size is not known
|
||||
* - it overlaps another variable (e.g. LOE X+2 ; LDE X)
|
||||
*/
|
||||
|
||||
dblock_p d;
|
||||
obj_p obj, prev;
|
||||
short nr = 1;
|
||||
offset ill_zone, x;
|
||||
|
||||
for (d = fdblock; d != (dblock_p) 0; d = d->d_next) {
|
||||
ill_zone = (offset) 0;
|
||||
for (obj = d->d_objlist; obj != (obj_p) 0; obj = obj->o_next) {
|
||||
if (d->d_pseudo == DROM ||
|
||||
obj->o_size == UNKNOWN_SIZE) {
|
||||
obj->o_globnr = 0; /* var. not considered */
|
||||
continue;
|
||||
}
|
||||
if (obj->o_off < ill_zone) {
|
||||
obj->o_globnr = 0; /* var. not considered */
|
||||
if (prev != (obj_p) 0 && prev->o_globnr != 0) {
|
||||
prev->o_globnr = 0;
|
||||
nr--;
|
||||
}
|
||||
} else {
|
||||
obj->o_globnr = nr++;
|
||||
}
|
||||
if ((x = obj->o_off + obj->o_size) > ill_zone) {
|
||||
ill_zone = x;
|
||||
}
|
||||
prev = obj;
|
||||
}
|
||||
}
|
||||
nrglobals = nr -1;
|
||||
}
|
10
util/ego/share/init_glob.h
Normal file
10
util/ego/share/init_glob.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
/* S H A R E D
|
||||
*
|
||||
* I N I T _ G L O B L S
|
||||
*
|
||||
*/
|
||||
|
||||
extern init_globals(); /* Assign a 'global variable number (o_globnr)
|
||||
* to every global variable.
|
||||
*/
|
240
util/ego/share/locals.c
Normal file
240
util/ego/share/locals.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* L O C A L S . C
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "global.h"
|
||||
#include "lset.h"
|
||||
#include "cset.h"
|
||||
#include "def.h"
|
||||
#include "get.h"
|
||||
#include "aux.h"
|
||||
#include "alloc.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_mes.h"
|
||||
#include "locals.h"
|
||||
|
||||
extern short nrglobals;
|
||||
|
||||
short nrlocals;
|
||||
local_p *locals; /* dynamic array */
|
||||
|
||||
STATIC localvar(off,size,locs,reg,score)
|
||||
offset off;
|
||||
short size;
|
||||
local_p *locs;
|
||||
bool reg;
|
||||
offset score;
|
||||
{
|
||||
/* process a reference to a local variable.
|
||||
* A local is characterized by a (offset,size) pair.
|
||||
* We first collect all locals in a list, sorted
|
||||
* by offset. Later we will construct a table
|
||||
* out of this list.
|
||||
*/
|
||||
|
||||
local_p lc, x, *prevp;
|
||||
|
||||
prevp = locs;
|
||||
for (lc = *locs; lc != (local_p) 0; lc = lc->lc_next) {
|
||||
if (lc->lc_off == off && lc->lc_size == size) {
|
||||
if (reg) {
|
||||
REGVAR(lc); /* register variable */
|
||||
lc->lc_score = score;
|
||||
}
|
||||
return; /* local already present */
|
||||
}
|
||||
if (lc->lc_off > off) break;
|
||||
prevp = &lc->lc_next;
|
||||
}
|
||||
/* the local was not seen before; create an entry
|
||||
* for it in the list.
|
||||
*/
|
||||
x = *prevp = newlocal();
|
||||
x->lc_off = off;
|
||||
x->lc_size = size;
|
||||
x->lc_next = lc;
|
||||
if (reg) {
|
||||
REGVAR(x);
|
||||
x->lc_score = score;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC check_message(l,locs)
|
||||
line_p l;
|
||||
local_p *locs;
|
||||
{
|
||||
/* See if l is a register message */
|
||||
|
||||
arg_p arg;
|
||||
|
||||
arg = ARG(l);
|
||||
if (aoff(arg,0) == ms_reg && arg->a_next != (arg_p) 0) {
|
||||
localvar(aoff(arg,1), (short) aoff(arg,2), locs, TRUE,
|
||||
aoff(arg,4));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
STATIC check_local_use(l,locs)
|
||||
line_p l;
|
||||
local_p *locs;
|
||||
{
|
||||
short sz;
|
||||
|
||||
switch(INSTR(l)) {
|
||||
case op_lol:
|
||||
case op_stl:
|
||||
case op_inl:
|
||||
case op_del:
|
||||
case op_zrl:
|
||||
sz = ws;
|
||||
break;
|
||||
case op_ldl:
|
||||
case op_sdl:
|
||||
sz = 2 * ws;
|
||||
break;
|
||||
case op_lil:
|
||||
case op_sil:
|
||||
sz = ps;
|
||||
break;
|
||||
case ps_mes:
|
||||
check_message(l,locs);
|
||||
/* fall through .. */
|
||||
default:
|
||||
return;
|
||||
}
|
||||
localvar(off_set(l),sz,locs,FALSE,(offset) 0);
|
||||
}
|
||||
|
||||
|
||||
make_localtab(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Make a table of local variables.
|
||||
* This table is used to associate a
|
||||
* unique number with a local. If two
|
||||
* locals overlap (e.g. LDL 4 and LDL 2)
|
||||
* none of them is considered any further,
|
||||
* i.e. we don't compute ud-info for them.
|
||||
*/
|
||||
|
||||
local_p prev, next, lc;
|
||||
local_p locallist = (local_p) 0;
|
||||
short cnt = 0;
|
||||
offset x, ill_zone = 0;
|
||||
register bblock_p b;
|
||||
register line_p l;
|
||||
|
||||
/* first make a list of all locals used */
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
for (l = b->b_start; l != (line_p) 0; l = l->l_next) {
|
||||
check_local_use(l,&locallist);
|
||||
}
|
||||
}
|
||||
/* Now remove overlapping locals, count useful ones on the fly */
|
||||
for (lc = locallist; lc != (local_p) 0; lc = lc->lc_next) {
|
||||
if (ill_zone != 0 && lc->lc_off < ill_zone) {
|
||||
/* this local overlaps with a previous one */
|
||||
BADLC(lc);
|
||||
if (!IS_BADLC(prev)) {
|
||||
BADLC(prev);
|
||||
cnt--;
|
||||
}
|
||||
} else {
|
||||
cnt++;
|
||||
}
|
||||
x = lc->lc_off + lc->lc_size;
|
||||
if (ill_zone == 0 || x > ill_zone) {
|
||||
ill_zone = x;
|
||||
}
|
||||
prev = lc;
|
||||
}
|
||||
/* Now we know how many local variables there are */
|
||||
nrlocals = cnt;
|
||||
locals = (local_p *) newmap(cnt);
|
||||
cnt = 1;
|
||||
for (lc = locallist; lc != (local_p) 0; lc = next) {
|
||||
next = lc->lc_next;
|
||||
if (IS_BADLC(lc)) {
|
||||
oldlocal(lc);
|
||||
} else {
|
||||
locals[cnt++] = lc;
|
||||
lc->lc_next = (local_p) 0;
|
||||
}
|
||||
}
|
||||
assert (cnt == nrlocals+1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC find_local(off,nr_out,found_out)
|
||||
offset off;
|
||||
short *nr_out;
|
||||
bool *found_out;
|
||||
{
|
||||
/* Try to find the local variable at the given
|
||||
* offset. Return its local-number.
|
||||
*/
|
||||
|
||||
short v;
|
||||
|
||||
for (v = 1; v <= nrlocals; v++) {
|
||||
if (locals[v]->lc_off > off) break;
|
||||
if (locals[v]->lc_off == off) {
|
||||
*found_out = TRUE;
|
||||
*nr_out = v;
|
||||
return;
|
||||
}
|
||||
}
|
||||
*found_out = FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var_nr(l,nr_out,found_out)
|
||||
line_p l;
|
||||
short *nr_out;
|
||||
bool *found_out;
|
||||
{
|
||||
/* Determine the number of the variable referenced
|
||||
* by EM instruction l.
|
||||
*/
|
||||
|
||||
offset off;
|
||||
short nr;
|
||||
|
||||
switch(TYPE(l)) {
|
||||
case OPOBJECT:
|
||||
/* global variable */
|
||||
if (OBJ(l)->o_globnr == 0) {
|
||||
/* We don't maintain ud-info for this var */
|
||||
*found_out = FALSE;
|
||||
} else {
|
||||
*nr_out = GLOB_TO_VARNR(OBJ(l)->o_globnr);
|
||||
*found_out = TRUE;
|
||||
}
|
||||
return;
|
||||
case OPSHORT:
|
||||
off = (offset) SHORT(l);
|
||||
break;
|
||||
case OPOFFSET:
|
||||
off = OFFSET(l);
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
/* Its's a local variable */
|
||||
find_local(off,&nr,found_out);
|
||||
if (*found_out) {
|
||||
*nr_out = LOC_TO_VARNR(nr);
|
||||
}
|
||||
}
|
39
util/ego/share/locals.h
Normal file
39
util/ego/share/locals.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
/*
|
||||
* L O C A L S . H
|
||||
*/
|
||||
|
||||
extern local_p *locals; /* table of locals, index is local-number */
|
||||
extern short nrlocals; /* number of locals for which we keep ud-info */
|
||||
|
||||
extern make_localtab(); /* (proc_p p)
|
||||
* Analyse the text of procedure p to determine
|
||||
* which local variable p has. Make a table of
|
||||
* these variables ('locals') and count them
|
||||
* ('nrlocals'). Also collect register messages.
|
||||
*/
|
||||
extern var_nr(); /* (line_p l; short *nr_out;bool *found_out)
|
||||
* Compute the 'variable number' of the
|
||||
* variable referenced by EM instruction l.
|
||||
*/
|
||||
|
||||
/* Every global variable for which ud-info is maintained has
|
||||
* a 'global variable number' (o_globnr). Every useful local
|
||||
* has a 'local variable number', which is its index in the
|
||||
* 'locals' table. All these variables also have a
|
||||
* 'variable number'. Conversions exist between these numbers.
|
||||
*/
|
||||
|
||||
#define TO_GLOBAL(v) (v)
|
||||
#define TO_LOCAL(v) (v - nrglobals)
|
||||
#define GLOB_TO_VARNR(v) (v)
|
||||
#define LOC_TO_VARNR(v) (v + nrglobals)
|
||||
#define IS_GLOBAL(v) (v <= nrglobals)
|
||||
#define IS_LOCAL(v) (v > nrglobals)
|
||||
|
||||
#define REGVAR(lc) lc->lc_flags |= LCF_REG
|
||||
#define IS_REGVAR(lc) (lc->lc_flags & LCF_REG)
|
||||
#define BADLC(lc) lc->lc_flags |= LCF_BAD
|
||||
#define IS_BADLC(lc) (lc->lc_flags & LCF_BAD)
|
||||
|
||||
|
208
util/ego/share/lset.c
Normal file
208
util/ego/share/lset.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
/* L O N G S E T S
|
||||
*
|
||||
* L S E T . C
|
||||
*/
|
||||
|
||||
|
||||
#include "types.h"
|
||||
#include "lset.h"
|
||||
#include "alloc.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
/* A 'long' set is represented as a linear list of 'elemholder'
|
||||
* records. Every such record contains a pointer to an element
|
||||
* of the set and to the next elemholder. An empty set is
|
||||
* represented as a null pointer.
|
||||
* An element of a long set must be of some pointer type or,
|
||||
* in any case, must have the size of a pointer. Note that
|
||||
* the strict typing rules are not obeyed here.
|
||||
* This package implements the usual operations on sets.
|
||||
* The name of every operation is preceeded by a 'L' to
|
||||
* distinguish it from the operation on 'compact' (bitvector)
|
||||
* sets with a similar name.
|
||||
*/
|
||||
|
||||
|
||||
lset Lempty_set()
|
||||
{
|
||||
return ((lset) 0);
|
||||
}
|
||||
|
||||
|
||||
bool Lis_elem(x,s)
|
||||
register Lelem_t x;
|
||||
register lset s;
|
||||
{
|
||||
|
||||
/* Search the list to see if x is an element of s */
|
||||
while (s != (elem_p) 0) {
|
||||
if (s->e_elem == x) {
|
||||
return TRUE;
|
||||
}
|
||||
s = s->e_next;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
Ladd(x,s_p)
|
||||
Lelem_t x;
|
||||
lset *s_p;
|
||||
{
|
||||
/* add x to a set. Note that the set is given as in-out
|
||||
* parameter, because it may be changed.
|
||||
*/
|
||||
|
||||
elem_p t;
|
||||
|
||||
if (!Lis_elem(x,*s_p)) {
|
||||
t = newelem(); /* allocate a new elemholder */
|
||||
t->e_elem = x;
|
||||
t->e_next = *s_p; /* insert it at the head of the list */
|
||||
*s_p = t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Lremove(x,s_p)
|
||||
Lelem_t x;
|
||||
lset *s_p;
|
||||
{
|
||||
/* Remove x from a set. If x was not an element of
|
||||
* the set, nothing happens.
|
||||
*/
|
||||
|
||||
register elem_p *epp, ep;
|
||||
lset s;
|
||||
|
||||
s = *s_p;
|
||||
epp = &s;
|
||||
while ((ep = *epp) != (elem_p) 0) {
|
||||
if (ep->e_elem == x) {
|
||||
*epp = ep->e_next;
|
||||
oldelem(ep);
|
||||
break;
|
||||
} else {
|
||||
epp = &ep->e_next;
|
||||
}
|
||||
}
|
||||
*s_p = s;
|
||||
}
|
||||
|
||||
|
||||
/* The operations first, next and elem can be used to iterate
|
||||
* over a set. For example:
|
||||
* for (i = Lfirst(s); i != (Lindex) 0; i = Lnext(i,s) {
|
||||
* x = Lelem(i);
|
||||
* use x
|
||||
* }
|
||||
* which is like:
|
||||
* 'for all elements x of s do'
|
||||
* use x
|
||||
*/
|
||||
|
||||
|
||||
Lindex Lfirst(s)
|
||||
lset s;
|
||||
{
|
||||
return ((Lindex) s);
|
||||
/* Note that an index for long sets is just
|
||||
* a pointer to an elemholder.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
Lindex Lnext(i,s)
|
||||
Lindex i;
|
||||
lset s;
|
||||
{
|
||||
assert(i != (Lindex) 0);
|
||||
return (i->e_next);
|
||||
}
|
||||
|
||||
|
||||
Lelem_t Lelem(i)
|
||||
Lindex i;
|
||||
{
|
||||
return (i->e_elem);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Ljoin(s1,s2_p)
|
||||
lset s1,*s2_p;
|
||||
{
|
||||
/* Join two sets, assign the result to the second set
|
||||
* and delete the first set (i.e. the value of the
|
||||
* first set becomes undefined).
|
||||
*/
|
||||
|
||||
register elem_p *epp, ep;
|
||||
lset s2;
|
||||
|
||||
/* First all elements of s1 that are also an element of s2
|
||||
* are removed from the s1 list. The two resulting lists
|
||||
* (for s1 and s2) are linked (s1 first).
|
||||
* Note the usage of epp, which points to a pointer that
|
||||
* points to the next elemholder record of the list.
|
||||
*/
|
||||
|
||||
s2 = *s2_p;
|
||||
epp = &s1;
|
||||
while ((ep = *epp) != (elem_p) 0) {
|
||||
if (Lis_elem(ep->e_elem,s2)) {
|
||||
/* remove an element */
|
||||
*epp = ep->e_next;
|
||||
oldelem(ep);
|
||||
} else {
|
||||
epp = &ep->e_next;
|
||||
}
|
||||
}
|
||||
*epp = s2; /* last record of s1 (or s1 itself) now points
|
||||
* to first record of s2.
|
||||
*/
|
||||
*s2_p = s1;
|
||||
}
|
||||
|
||||
|
||||
Ldeleteset(s)
|
||||
lset s;
|
||||
{
|
||||
register elem_p ep, next;
|
||||
|
||||
for (ep = s; ep != (elem_p) 0; ep = next) {
|
||||
next = ep->e_next;
|
||||
oldelem(ep);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Lis_subset(s1,s2)
|
||||
lset s1,s2;
|
||||
{
|
||||
/* See if s1 is a subset of s2 */
|
||||
|
||||
register Lindex i;
|
||||
|
||||
for (i = Lfirst(s1); i != (Lindex) 0; i = Lnext(i,s1)) {
|
||||
if (!Lis_elem(Lelem(i),s2)) return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
short Lnrelems(s)
|
||||
lset s;
|
||||
{
|
||||
/* Compute the number of elements of a set */
|
||||
|
||||
register elem_p ep;
|
||||
register short cnt;
|
||||
|
||||
cnt = 0;
|
||||
for (ep = s; ep != (elem_p) 0; ep = ep->e_next) {
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
16
util/ego/share/lset.h
Normal file
16
util/ego/share/lset.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* O P E R A T I O N S F O R
|
||||
* L O N G S E T S
|
||||
*/
|
||||
|
||||
|
||||
extern lset Lempty_set(); /* () */
|
||||
extern bool Lis_elem(); /* (Lelem_t, lset) */
|
||||
extern Ladd(); /* (Lelem_t, *lset) */
|
||||
extern Lremove(); /* (Lelem_t, *lset) */
|
||||
extern Lindex Lfirst(); /* (lset) */
|
||||
extern Lindex Lnext(); /* (Lindex, lset) */
|
||||
extern Lelem_t Lelem(); /* (Lindex) */
|
||||
extern Ljoin(); /* (lset, *lset) */
|
||||
extern Ldeleteset(); /* (lset) */
|
||||
extern bool Lis_subset(); /* (lset, lset) */
|
||||
extern short Lnrelems(); /* (lset) */
|
83
util/ego/share/makecldef.c
Normal file
83
util/ego/share/makecldef.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* MAKECLASSDEF
|
||||
*
|
||||
* This program is used by several phases of the optimizer
|
||||
* to make the file classdefs.h. It reads two files:
|
||||
* - the em_mnem,h file, containing the definitions of the
|
||||
* EM mnemonics
|
||||
* - the class-file, containing tuples:
|
||||
* (mnemonic, src_class, res_class)
|
||||
* where src_class and res_class are integers telling how
|
||||
* to compute the number of bytes popped and pushed
|
||||
* by the instruction.
|
||||
* The output (standard output) is a C array.
|
||||
*/
|
||||
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
convert(mnemfile,classfile)
|
||||
FILE *mnemfile, *classfile;
|
||||
{
|
||||
char mnem1[10], mnem2[10],def[10];
|
||||
int src,res,newcl,opc;
|
||||
|
||||
newcl = TRUE;
|
||||
printf("struct class classtab[] = {\n");
|
||||
printf("\tNOCLASS,\tNOCLASS,\n");
|
||||
/* EM mnemonics start at 1, arrays in C at 0 */
|
||||
for (;;) {
|
||||
fscanf(mnemfile,"%s%s%d",def,mnem1,&opc);
|
||||
/* read a line like "#define op_aar 1" */
|
||||
if (feof(mnemfile)) break;
|
||||
if (strcmp(def,"#define") != 0) {
|
||||
error("bad mnemonic file, #define expected");
|
||||
}
|
||||
if (newcl) {
|
||||
fscanf(classfile,"%s%d%d",mnem2,&src,&res);
|
||||
/* read a line like "op_loc 8 1" */
|
||||
}
|
||||
if (feof(classfile) || strcmp(mnem1,mnem2) != 0) {
|
||||
/* there is no line for this mnemonic, so
|
||||
* it has no class.
|
||||
*/
|
||||
printf("\tNOCLASS,\tNOCLASS,\n");
|
||||
newcl = FALSE;
|
||||
} else {
|
||||
printf("\tCLASS%d,\t\tCLASS%d,\n",src,res);
|
||||
/* print a line like "CLASS8, CLASS1," */
|
||||
newcl = TRUE;
|
||||
}
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
error(s)
|
||||
char *s;
|
||||
{
|
||||
fprintf(stderr,"%s\n",s);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
FILE *f1,*f2;
|
||||
|
||||
if (argc != 3) {
|
||||
error("usage: makeclassdef mnemfile classfile");
|
||||
}
|
||||
if ((f1 = fopen(argv[1],"r")) == NULL) {
|
||||
error("cannot open mnemonic file");
|
||||
}
|
||||
if ((f2 = fopen(argv[2],"r")) == NULL) {
|
||||
error("cannot open class file");
|
||||
}
|
||||
convert(f1,f2);
|
||||
}
|
21
util/ego/share/map.c
Normal file
21
util/ego/share/map.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* M A P . C */
|
||||
|
||||
#include "types.h"
|
||||
#include "map.h"
|
||||
|
||||
short plength;
|
||||
short olength;
|
||||
short llength;
|
||||
short blength;
|
||||
short lplength;
|
||||
line_p *lmap;
|
||||
bblock_p *lbmap;
|
||||
proc_p *pmap ; /* dynamically allocated array that maps
|
||||
* every proc_id to a proc_p.
|
||||
*/
|
||||
obj_p *omap; /* maps obj_id to obj_p */
|
||||
loop_p *lpmap; /* maps loop_id to loop_p */
|
||||
bblock_p *bmap; /* maps block_id to bblock_p */
|
||||
|
||||
dblock_p fdblock; /* first dblock */
|
||||
proc_p fproc; /* first proc */
|
38
util/ego/share/map.h
Normal file
38
util/ego/share/map.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* M A P . H */
|
||||
|
||||
extern short plength; /* length of pmap, i.e. number of procs */
|
||||
extern short olength; /* length of omap, i.e. number of objects */
|
||||
extern short llength; /* length of lmap and lbmap, i.e.
|
||||
* # instruction labels in current proc.
|
||||
*/
|
||||
extern short lplength; /* length of lpmap, i.e. number of loops
|
||||
* in current procedure.
|
||||
*/
|
||||
extern short blength; /* length of bmap, i.e. number of basic blocks
|
||||
* in current procedure.
|
||||
*/
|
||||
|
||||
|
||||
extern line_p *lmap; /* contains for every label_id its
|
||||
* defining occurrence (line structure)
|
||||
* label_id --> line_p
|
||||
*/
|
||||
extern bblock_p *lbmap; /* contains for every label_id its
|
||||
* basic block.
|
||||
* label_id --> bblock_p
|
||||
*/
|
||||
extern proc_p *pmap; /* contains for every proc_id its proc structure
|
||||
* proc_id --> proc_p
|
||||
*/
|
||||
extern obj_p *omap; /* contains for every obj_id its object struct
|
||||
* obj_id --> obj_p
|
||||
*/
|
||||
extern loop_p *lpmap; /* contains for every loop_id its loop struct
|
||||
* loop_id --> loop_p
|
||||
*/
|
||||
extern bblock_p *bmap; /* contains for every block_id its bblock struct
|
||||
* block_id --> bblock_p
|
||||
*/
|
||||
|
||||
extern dblock_p fdblock;/* first dblock, heads dblock list */
|
||||
extern proc_p fproc; /* first proc, heads proc table */
|
277
util/ego/share/parser.c
Normal file
277
util/ego/share/parser.c
Normal file
|
@ -0,0 +1,277 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "alloc.h"
|
||||
#include "global.h"
|
||||
#include "lset.h"
|
||||
#include "aux.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
|
||||
struct class {
|
||||
byte src_class;
|
||||
byte res_class;
|
||||
};
|
||||
|
||||
typedef struct class *class_p;
|
||||
|
||||
|
||||
#define NOCLASS 0
|
||||
#define CLASS1 1
|
||||
#define CLASS2 2
|
||||
#define CLASS3 3
|
||||
#define CLASS4 4
|
||||
#define CLASS5 5
|
||||
#define CLASS6 6
|
||||
#define CLASS7 7
|
||||
#define CLASS8 8
|
||||
#define CLASS9 9
|
||||
#define CLASS10 10
|
||||
#define CLASS11 11
|
||||
|
||||
#include "classdefs.h"
|
||||
/* The file classdefs.h contains the table classtab. It is
|
||||
* generated automatically from the file classdefs.src.
|
||||
*/
|
||||
|
||||
STATIC bool classes(instr,src_out,res_out)
|
||||
int instr;
|
||||
int *src_out, *res_out;
|
||||
{
|
||||
/* Determine the classes of the given instruction */
|
||||
|
||||
class_p c;
|
||||
|
||||
if (instr < sp_fmnem || instr > sp_lmnem) return FALSE;
|
||||
c = &classtab[instr];
|
||||
if (c->src_class == NOCLASS) return FALSE;
|
||||
*src_out = c->src_class;
|
||||
*res_out = c->res_class;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool uses_arg(class)
|
||||
int class;
|
||||
{
|
||||
/* See if a member of the given class uses
|
||||
* an argument.
|
||||
*/
|
||||
|
||||
switch(class) {
|
||||
case CLASS1:
|
||||
case CLASS2:
|
||||
case CLASS3:
|
||||
case CLASS4:
|
||||
case CLASS11:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool uses_2args(class)
|
||||
int class;
|
||||
{
|
||||
/* See if a member of the given class uses
|
||||
* 2 arguments.
|
||||
*/
|
||||
|
||||
return class == CLASS10;
|
||||
}
|
||||
|
||||
|
||||
STATIC bool parse_locs(l,c1_out,c2_out)
|
||||
line_p l;
|
||||
offset *c1_out, *c2_out;
|
||||
{
|
||||
if (INSTR(l) == op_loc && INSTR(PREV(l)) == op_loc) {
|
||||
*c1_out = off_set(l);
|
||||
*c2_out = off_set(PREV(l));
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool check_args(l,src_class,res_class,arg1_out,arg2_out)
|
||||
line_p l;
|
||||
int src_class,res_class;
|
||||
offset *arg1_out, *arg2_out;
|
||||
{
|
||||
/* Several EM instructions have an argument
|
||||
* giving the size of the operand(s) of
|
||||
* the instruction. E.g. a 'adi 4' is a 4-byte
|
||||
* addition. The size may also be put on the
|
||||
* stack. In this case we give up our
|
||||
* efforts to recognize the parameter expression.
|
||||
* Some instructions (e.g. CIU) use 2 arguments
|
||||
* that are both on the stack. In this case we
|
||||
* check if both arguments are LOCs (the usual case),
|
||||
* else we give up.
|
||||
*/
|
||||
|
||||
if (uses_2args(src_class) || uses_2args(res_class)) {
|
||||
return parse_locs(PREV(l),arg1_out,arg2_out);
|
||||
}
|
||||
if (uses_arg(src_class) || uses_arg(res_class)) {
|
||||
if (TYPE(l) == OPSHORT) {
|
||||
*arg1_out = (offset) SHORT(l);
|
||||
return TRUE;
|
||||
} else {
|
||||
if (TYPE(l) == OPOFFSET) {
|
||||
*arg1_out = OFFSET(l);
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE; /* no argument needed */
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC offset nrbytes(class,arg1,arg2)
|
||||
int class;
|
||||
offset arg1,arg2;
|
||||
{
|
||||
/* Determine the number of bytes of the given
|
||||
* arguments and class.
|
||||
*/
|
||||
|
||||
offset n;
|
||||
|
||||
switch(class) {
|
||||
case CLASS1:
|
||||
n = arg1;
|
||||
break;
|
||||
case CLASS2:
|
||||
n = 2 * arg1;
|
||||
break;
|
||||
case CLASS3:
|
||||
n = arg1 + ws;
|
||||
break;
|
||||
case CLASS4:
|
||||
n = arg1 + ps;
|
||||
break;
|
||||
case CLASS5:
|
||||
n = ws;
|
||||
break;
|
||||
case CLASS6:
|
||||
n = 2 * ws;
|
||||
break;
|
||||
case CLASS7:
|
||||
n = ps;
|
||||
break;
|
||||
case CLASS8:
|
||||
n = 2 * ps;
|
||||
break;
|
||||
case CLASS9:
|
||||
n = 0;
|
||||
break;
|
||||
case CLASS10:
|
||||
n = arg2 + 2*ws;
|
||||
break;
|
||||
case CLASS11:
|
||||
n = arg1 + 2*ps;
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC attrib(l,expect_out,srcb_out,resb_out)
|
||||
line_p l;
|
||||
offset *expect_out, *srcb_out, *resb_out;
|
||||
{
|
||||
/* Determine a number of attributes of an EM
|
||||
* instruction appearing in an expression.
|
||||
* If it is something we don't
|
||||
* expect in such expression (e.g. a store)
|
||||
* expect_out is set to FALSE. Else we
|
||||
* determine the number of bytes popped from
|
||||
* the stack by the instruction and the
|
||||
* number of bytes pushed on the stack as
|
||||
* result.
|
||||
*/
|
||||
|
||||
int src_class,res_class;
|
||||
offset arg1, arg2;
|
||||
|
||||
if (l == (line_p) 0 || !classes(INSTR(l),&src_class,&res_class) ||
|
||||
!check_args(l,src_class,res_class,&arg1,&arg2)) {
|
||||
*expect_out = FALSE;
|
||||
} else {
|
||||
*expect_out = TRUE;
|
||||
*srcb_out = nrbytes(src_class,arg1,arg2);
|
||||
*resb_out = nrbytes(res_class,arg1,arg2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool parse(l,nbytes,l_out,level,action0)
|
||||
line_p l, *l_out;
|
||||
offset nbytes;
|
||||
int level;
|
||||
int (*action0) ();
|
||||
{
|
||||
/* This is a recursive descent parser for
|
||||
* EM expressions.
|
||||
* It tries to recognize EM code that loads exactly
|
||||
* 'nbytes' bytes on the stack.
|
||||
* 'l' is the last instruction of this code.
|
||||
* As EM is essentially postfix, this instruction
|
||||
* can be regarded as the root node of an expression
|
||||
* tree. The EM code is traversed from right to left,
|
||||
* i.e. top down. On success, TRUE is returned and
|
||||
* 'l_out' will point to the first instruction
|
||||
* of the recognized code. On toplevel, when an
|
||||
* expression has been recognized, the procedure-parameter
|
||||
* 'action0' is called, with parameters: the first and
|
||||
* last instruction of the expression and the number of
|
||||
* bytes recognized.
|
||||
*/
|
||||
|
||||
offset more, expected, sourcebytes,resultbytes;
|
||||
line_p lnp;
|
||||
|
||||
more = nbytes; /* #bytes to be recognized */
|
||||
while (more > 0) {
|
||||
attrib(l,&expected,&sourcebytes,&resultbytes);
|
||||
/* Get the attributes of EM instruction 'l'.
|
||||
* 'expected' denotes if it is something we can use;
|
||||
* 'sourcebytes' and 'resultbytes' are the number of
|
||||
* bytes popped resp. pushed by the instruction
|
||||
* (e.g. 'adi 2' pops 4 bytes and pushes 2 bytes).
|
||||
*/
|
||||
if (!expected || (more -= resultbytes) < 0) return FALSE;
|
||||
if (sourcebytes == 0) {
|
||||
/* a leaf of the expression tree */
|
||||
lnp = l;
|
||||
} else {
|
||||
if (!parse(PREV(l),sourcebytes,&lnp,level+1,action0)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (level == 0) {
|
||||
/* at toplevel */
|
||||
(*action0) (lnp,l,resultbytes);
|
||||
}
|
||||
l = PREV(lnp);
|
||||
}
|
||||
/* Now we've recognized a number of expressions that
|
||||
* together push nbytes on the stack.
|
||||
*/
|
||||
*l_out = lnp;
|
||||
return TRUE;
|
||||
}
|
13
util/ego/share/parser.h
Normal file
13
util/ego/share/parser.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
bool parse(); /* (line_p l, *l_out; offset nbytes;
|
||||
* int level; int (*action0) ())
|
||||
* This is a recursive descent parser for
|
||||
* EM expressions.
|
||||
* It tries to recognize EM code that loads exactly
|
||||
* 'nbytes' bytes on the stack.
|
||||
* 'l' is the last instruction of this code.
|
||||
* On toplevel, when an expression has been
|
||||
* recognized, the procedure-parameter
|
||||
* 'action0' is called, with parameters: the first and
|
||||
* last instruction of the expression and the number of
|
||||
* bytes recognized.
|
||||
*/
|
528
util/ego/share/put.c
Normal file
528
util/ego/share/put.c
Normal file
|
@ -0,0 +1,528 @@
|
|||
/* P U T . C */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "types.h"
|
||||
#include "global.h"
|
||||
#include "debug.h"
|
||||
#include "def.h"
|
||||
#include "map.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "lset.h"
|
||||
#include "alloc.h"
|
||||
#include "put.h"
|
||||
|
||||
|
||||
/* the output file */
|
||||
|
||||
static FILE *f; /* current output file, can be EM text file,
|
||||
* basic block file, data block file or proc table file.
|
||||
*/
|
||||
|
||||
|
||||
#define outbyte(b) putc(b,f)
|
||||
|
||||
|
||||
/* The output can be either 'typed' or 'untyped'. Typed data
|
||||
* consists of a value preceded by a byte specifying what kind
|
||||
* of value it is (e.g. 2 bytes constant, 4 bytes constant,
|
||||
* proc-id, lab-id, string etc.). Untyped data consists
|
||||
* of the value only. We use typed data for the EM text and
|
||||
* untyped data for all other files.
|
||||
*/
|
||||
|
||||
/* putlines */
|
||||
|
||||
STATIC putargs(ap)
|
||||
register arg_p ap;
|
||||
{
|
||||
while (ap != (arg_p) 0) {
|
||||
outbyte((byte) ap->a_type & BMASK);
|
||||
switch(ap->a_type) {
|
||||
case ARGOFF:
|
||||
outoff(ap->a_a.a_offset);
|
||||
break;
|
||||
case ARGINSTRLAB:
|
||||
outlab(ap->a_a.a_instrlab);
|
||||
break;
|
||||
case ARGOBJECT:
|
||||
outobject(ap->a_a.a_obj);
|
||||
break;
|
||||
case ARGPROC:
|
||||
outproc(ap->a_a.a_proc);
|
||||
break;
|
||||
case ARGSTRING:
|
||||
putstr(&ap->a_a.a_string);
|
||||
break;
|
||||
case ARGICN:
|
||||
case ARGUCN:
|
||||
case ARGFCN:
|
||||
outshort(ap->a_a.a_con.ac_length);
|
||||
putstr(&ap->a_a.a_con.ac_con);
|
||||
break;
|
||||
}
|
||||
ap = ap->a_next;
|
||||
}
|
||||
outbyte((byte) ARGCEND);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC putstr(abp) register argb_p abp; {
|
||||
register argb_p tbp;
|
||||
register length;
|
||||
|
||||
length = 0;
|
||||
tbp = abp;
|
||||
while (tbp!= (argb_p) 0) {
|
||||
length += tbp->ab_index;
|
||||
tbp = tbp->ab_next;
|
||||
}
|
||||
outshort(length);
|
||||
while (abp != (argb_p) 0) {
|
||||
for (length=0;length<abp->ab_index;length++)
|
||||
outbyte( (byte) abp->ab_contents[length] );
|
||||
abp = abp->ab_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outoff(off) offset off; {
|
||||
|
||||
outshort( (short) (off&0177777L) );
|
||||
outshort( (short) (off>>16) );
|
||||
}
|
||||
|
||||
|
||||
STATIC outshort(i) short i; {
|
||||
|
||||
outbyte( (byte) (i&BMASK) );
|
||||
outbyte( (byte) (i>>8) );
|
||||
}
|
||||
|
||||
|
||||
STATIC outint(i)
|
||||
int i;
|
||||
{
|
||||
/* Write an integer to the output file. This routine is
|
||||
* only used when outputting a bitvector-set. We expect an
|
||||
* integer to be either a short or a long.
|
||||
*/
|
||||
|
||||
if (sizeof(int) == sizeof(short)) {
|
||||
outshort(i);
|
||||
} else {
|
||||
assert (sizeof(int) == sizeof(offset));
|
||||
outoff(i);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC outlab(lid) lab_id lid; {
|
||||
outshort((short) lid);
|
||||
}
|
||||
|
||||
|
||||
STATIC outobject(obj) obj_p obj; {
|
||||
outshort((short) obj->o_id);
|
||||
}
|
||||
|
||||
|
||||
STATIC outproc(p) proc_p p; {
|
||||
outshort((short) p->p_id);
|
||||
}
|
||||
|
||||
|
||||
short putlines(l,lf)
|
||||
line_p l;
|
||||
FILE *lf;
|
||||
{
|
||||
/* Output the list of em instructions headed by l.
|
||||
* Return the number of instruction written.
|
||||
*/
|
||||
|
||||
register line_p lnp;
|
||||
line_p next;
|
||||
short instr;
|
||||
short count= 0;
|
||||
|
||||
f = lf; /* Set f to the EM-text output file */
|
||||
for (lnp = l; lnp != (line_p) 0; lnp = next) {
|
||||
VL(lnp);
|
||||
count++;
|
||||
next = lnp->l_next;
|
||||
instr = INSTR(lnp);
|
||||
outbyte((byte) instr);
|
||||
outbyte((byte) TYPE(lnp));
|
||||
switch(TYPE(lnp)) {
|
||||
case OPSHORT:
|
||||
outshort(SHORT(lnp));
|
||||
break;
|
||||
case OPOFFSET:
|
||||
outoff(OFFSET(lnp));
|
||||
break;
|
||||
case OPINSTRLAB:
|
||||
outlab(INSTRLAB(lnp));
|
||||
break;
|
||||
case OPOBJECT:
|
||||
outobject(OBJ(lnp));
|
||||
break;
|
||||
case OPPROC:
|
||||
outproc(PROC(lnp));
|
||||
break;
|
||||
case OPLIST:
|
||||
putargs(ARG(lnp));
|
||||
break;
|
||||
}
|
||||
oldline(lnp);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* putdtable */
|
||||
|
||||
#define outmark(m) outbyte((byte) m)
|
||||
|
||||
|
||||
STATIC putobjects(obj)
|
||||
register obj_p obj;
|
||||
{
|
||||
while (obj != (obj_p) 0) {
|
||||
outmark(MARK_OBJ);
|
||||
outshort(obj->o_id);
|
||||
outoff(obj->o_size);
|
||||
outoff(obj->o_off);
|
||||
obj = obj->o_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC putvalues(arg)
|
||||
register arg_p arg;
|
||||
{
|
||||
while (arg != (arg_p) 0) {
|
||||
assert(arg->a_type == ARGOFF);
|
||||
outmark(MARK_ARG);
|
||||
outoff(arg->a_a.a_offset);
|
||||
arg = arg->a_next;
|
||||
}
|
||||
}
|
||||
putdtable(head,df)
|
||||
dblock_p head;
|
||||
FILE *df;
|
||||
{
|
||||
/* Write the datablock table to the data block file df. */
|
||||
|
||||
register dblock_p dbl;
|
||||
register obj_p obj;
|
||||
dblock_p next;
|
||||
register short n = 0;
|
||||
|
||||
f = df; /* set f to the data block output file */
|
||||
/* Count the number of objects */
|
||||
for (dbl = head; dbl != (dblock_p) 0; dbl = dbl->d_next) {
|
||||
for (obj = dbl->d_objlist; obj != (obj_p) 0;
|
||||
obj = obj->o_next) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
outshort(n); /* The table is preceded by #objects . */
|
||||
for (dbl = head; dbl != (dblock_p) 0; dbl = next) {
|
||||
next = dbl->d_next;
|
||||
outmark(MARK_DBLOCK);
|
||||
outshort(dbl->d_id);
|
||||
outbyte(dbl->d_pseudo);
|
||||
outoff(dbl->d_size);
|
||||
outshort(dbl->d_fragmnr);
|
||||
outbyte(dbl->d_flags1);
|
||||
putobjects(dbl->d_objlist);
|
||||
putvalues(dbl->d_values);
|
||||
olddblock(dbl);
|
||||
}
|
||||
fclose(f);
|
||||
if (omap != (obj_p *) 0) {
|
||||
oldmap(omap,olength); /* release memory for omap */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* putptable */
|
||||
|
||||
|
||||
|
||||
STATIC outcset(s)
|
||||
cset s;
|
||||
{
|
||||
/* A 'compact' set is represented externally as a row of words
|
||||
* (its bitvector) preceded by its length.
|
||||
*/
|
||||
|
||||
register short i;
|
||||
|
||||
outshort(s->v_size);
|
||||
for (i = 0; i <= DIVWL(s->v_size - 1); i++) {
|
||||
outint(s->v_bits[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
putptable(head,pf,all)
|
||||
proc_p head;
|
||||
FILE *pf;
|
||||
bool all;
|
||||
{
|
||||
register proc_p p;
|
||||
proc_p next;
|
||||
register short n = 0;
|
||||
/* Write the proc table */
|
||||
|
||||
f = pf;
|
||||
/* Determine the number of procs */
|
||||
for (p = head; p != (proc_p) 0; p = p->p_next) {
|
||||
n++;
|
||||
}
|
||||
outshort(n); /* The table is preceded by its length. */
|
||||
outshort ((all?1:0)); /* if all=false, only some of the attributes
|
||||
are written. */
|
||||
for (p = head; p != (proc_p) 0; p = next) {
|
||||
next = p->p_next;
|
||||
outshort(p->p_id);
|
||||
outbyte(p->p_flags1);
|
||||
if (p->p_flags1 & PF_BODYSEEN) {
|
||||
/* If we have no access to the EM text of the
|
||||
* body of a procedure, we have no information
|
||||
* about it whatsoever, so there is nothing
|
||||
* to output in that case.
|
||||
*/
|
||||
outshort(p->p_nrlabels);
|
||||
outoff(p->p_localbytes);
|
||||
outoff(p->p_nrformals);
|
||||
if (all) {
|
||||
outcset(p->p_change->c_ext);
|
||||
outshort(p->p_change->c_flags);
|
||||
outshort(p->p_use->u_flags);
|
||||
outcset(p->p_calling);
|
||||
Cdeleteset(p->p_change->c_ext);
|
||||
oldchange(p->p_change);
|
||||
olduse(p->p_use);
|
||||
Cdeleteset(p->p_calling);
|
||||
}
|
||||
}
|
||||
oldproc(p);
|
||||
}
|
||||
fclose(f);
|
||||
if (pmap != (proc_p *) 0) {
|
||||
oldmap(pmap,plength); /* release memory for pmap */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* putunit */
|
||||
|
||||
STATIC outloop(l)
|
||||
loop_p l;
|
||||
{
|
||||
outshort((short) l->lp_id);
|
||||
}
|
||||
|
||||
|
||||
STATIC outblock(b)
|
||||
bblock_p b;
|
||||
{
|
||||
if (b == (bblock_p) 0) {
|
||||
outshort((short) 0);
|
||||
} else {
|
||||
outshort((short) b->b_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outid(e,p)
|
||||
Lelem_t e;
|
||||
int (*p) ();
|
||||
{
|
||||
/* Auxiliary routine used by outlset. */
|
||||
|
||||
/* NOSTRICT */
|
||||
(*p) (e);
|
||||
}
|
||||
|
||||
|
||||
STATIC outlset(s,p)
|
||||
lset s;
|
||||
int (*p) ();
|
||||
{
|
||||
/* A 'long' set is represented externally as a
|
||||
* a sequence of elements terminated by a 0 word.
|
||||
* The procedural parameter p is a routine that
|
||||
* prints an id (proc_id, obj_id etc.).
|
||||
*/
|
||||
|
||||
register Lindex i;
|
||||
|
||||
for (i = Lfirst(s); i != (Lindex) 0; i = Lnext(i,s)) {
|
||||
outid(Lelem(i),p);
|
||||
}
|
||||
outshort((short) 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
putunit(kind,p,l,gf,lf)
|
||||
short kind;
|
||||
proc_p p;
|
||||
line_p l;
|
||||
FILE *gf, *lf;
|
||||
{
|
||||
register bblock_p b;
|
||||
register short n = 0;
|
||||
Lindex pi;
|
||||
loop_p lp;
|
||||
|
||||
f = gf;
|
||||
if (kind == LDATA) {
|
||||
outshort(0); /* No basic blocks */
|
||||
n = putlines(l,lf);
|
||||
f = gf;
|
||||
outshort(n);
|
||||
return;
|
||||
}
|
||||
/* Determine the number of basic blocks */
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
n++;
|
||||
}
|
||||
outshort(n); /* # basic blocks */
|
||||
outshort(Lnrelems(p->p_loops)); /* # loops */
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
n = putlines(b->b_start,lf);
|
||||
f = gf;
|
||||
outblock(b); /* put its block_id */
|
||||
outshort(n); /* #instructions of the block */
|
||||
outlset(b->b_succ, outblock); /* put succ set */
|
||||
outlset(b->b_pred, outblock); /* put pred set */
|
||||
outblock(b->b_idom); /* put id of immediate dominator */
|
||||
outlset(b->b_loops, outloop); /* put loop set */
|
||||
outshort(b->b_flags);
|
||||
}
|
||||
/* The Control Flow Graph of every procedure is followed
|
||||
* by a description of the loops of the procedure.
|
||||
* Every loop contains an id, an entry block and a level.
|
||||
*/
|
||||
for (pi = Lfirst(p->p_loops); pi != (Lindex) 0;
|
||||
pi = Lnext(pi,p->p_loops)) {
|
||||
lp = (loop_p) Lelem(pi);
|
||||
outloop(lp); /* id */
|
||||
outshort(lp->lp_level); /* nesting level */
|
||||
outblock(lp->lp_entry); /* loop entry block */
|
||||
outblock(lp->lp_end);
|
||||
oldloop(lp);
|
||||
}
|
||||
Ldeleteset(p->p_loops);
|
||||
/* We will now release the memory of the basic blocks.
|
||||
* Note that it would be incorrect to release a basic block
|
||||
* after it has been written, because there may be references
|
||||
* to it from other (later) blocks.
|
||||
*/
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
Ldeleteset(b->b_loops);
|
||||
Ldeleteset(b->b_succ);
|
||||
Ldeleteset(b->b_pred);
|
||||
oldbblock(b);
|
||||
}
|
||||
/* Release the memory for the lmap, lbmap, bmap, lpmap tables */
|
||||
if (lmap != (line_p *) 0) oldmap(lmap,llength);
|
||||
if (lbmap != (bblock_p *) 0) oldmap(lbmap,llength);
|
||||
if (bmap != (bblock_p *) 0) oldmap(bmap,blength);
|
||||
if (lpmap != (loop_p *) 0) oldmap(lpmap,lplength);
|
||||
f = lf;
|
||||
}
|
||||
|
||||
|
||||
/* The following routines are only used by the Inline Substitution phase */
|
||||
|
||||
|
||||
STATIC putactuals(alist,cfile)
|
||||
actual_p alist;
|
||||
FILE *cfile;
|
||||
{
|
||||
/* output a list of actual parameters */
|
||||
|
||||
actual_p a,next;
|
||||
line_p l;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
for (a = alist; a != (actual_p) 0; a = a->ac_next) count++;
|
||||
outshort(count); /* number of actuals */
|
||||
for (a = alist; a != (actual_p) 0; a = next) {
|
||||
next = a->ac_next;
|
||||
count = 0;
|
||||
for (l = a->ac_exp; l != (line_p) 0; l= l->l_next) count++;
|
||||
outshort(count); /* length of actual */
|
||||
outoff(a->ac_size);
|
||||
outbyte(a->ac_inl);
|
||||
count = putlines(a->ac_exp,cfile);
|
||||
oldactual(a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
putcall(c,cfile,level)
|
||||
call_p c;
|
||||
FILE *cfile;
|
||||
short level;
|
||||
{
|
||||
/* output a call */
|
||||
|
||||
call_p nc,nextc;
|
||||
|
||||
|
||||
f = cfile;
|
||||
outshort(level); /* nesting level */
|
||||
outshort(c->cl_caller->p_id); /* calling proc */
|
||||
outshort(c->cl_id);
|
||||
outshort(c->cl_proc->p_id); /* called proc */
|
||||
outbyte(c->cl_looplevel);
|
||||
outbyte(c->cl_flags);
|
||||
outshort(c->cl_ratio);
|
||||
putactuals(c->cl_actuals,cfile);
|
||||
nc = c->cl_car;
|
||||
oldcall(c);
|
||||
for (; nc != (call_p) 0; nc = nextc) {
|
||||
/* take care of nested calls */
|
||||
nextc = nc->cl_cdr;
|
||||
putcall(nc,cfile,level+1);
|
||||
}
|
||||
}
|
||||
|
||||
long putcc(head,ccf)
|
||||
calcnt_p head;
|
||||
FILE *ccf;
|
||||
{
|
||||
/* Write call-count information to file ccf.
|
||||
* Return the disk address of the info written.
|
||||
*/
|
||||
|
||||
calcnt_p cc;
|
||||
long addr;
|
||||
short cnt;
|
||||
|
||||
addr = ftell(ccf);
|
||||
f = ccf;
|
||||
cnt = 0;
|
||||
for (cc = head; cc != (calcnt_p) 0;cc = cc->cc_next) cnt++;
|
||||
outshort(cnt);
|
||||
for (cc = head; cc != (calcnt_p) 0; cc = cc->cc_next) {
|
||||
outproc(cc->cc_proc);
|
||||
outshort(cc->cc_count);
|
||||
}
|
||||
return addr;
|
||||
}
|
42
util/ego/share/put.h
Normal file
42
util/ego/share/put.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* O U T P U T R O U T I N E S */
|
||||
|
||||
|
||||
|
||||
extern putdtable(); /* (dblock_p head, FILE *df)
|
||||
* Write the data block table to file df,
|
||||
* preceded by its length.
|
||||
*/
|
||||
extern putptable(); /* (proc_p head, FILE *pf, bool all)
|
||||
* Write the proc table to file pf,
|
||||
* preceded by its length. If all=false,
|
||||
* the fields computed by CF will not be
|
||||
* written (used by the IC phase).
|
||||
*/
|
||||
extern putunit(); /* (short kind; proc_p p; line_p l;
|
||||
* FILE *gf, *lf)
|
||||
* If kind = LTEXT, then write
|
||||
* the control flow graph to file gf,
|
||||
* preceded by its length (#basic blocks);
|
||||
* write the EM code of every basic block
|
||||
* in the graph to file lf, preceded by
|
||||
* the number of instructions in the block.
|
||||
* Else, (kind = LDATA) just write the
|
||||
* list of instructions (data declarations)
|
||||
* to lf.
|
||||
*/
|
||||
extern short putlines(); /* (line_p l; FILE *lf)
|
||||
* Output the list of em instructions
|
||||
* headed by l. Return the number of
|
||||
* instructions written.
|
||||
*/
|
||||
extern putcall(); /* (call_p call; FILE *cfile; short level)
|
||||
* Write the call
|
||||
* with the given id to the given file.
|
||||
* The level is the nesting level, used by
|
||||
* putcall when it calls itself recurively.
|
||||
* It should be 0 on outer levels.
|
||||
*/
|
||||
extern long putcc(); /* (calcnt_p head; FILE *ccf)
|
||||
* Write call-count information to
|
||||
* file ccf.
|
||||
*/
|
415
util/ego/share/show.c
Normal file
415
util/ego/share/show.c
Normal file
|
@ -0,0 +1,415 @@
|
|||
/* S H O W . C */
|
||||
|
||||
/* This program can be used to make the output of the 'cf' pass
|
||||
* human readable. It will display either the procedure table,
|
||||
* the datablock table, the basic block table or the EM text,
|
||||
* depending on the flag that is passed as first argument.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_flag.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../share/types.h"
|
||||
#include "../share/def.h"
|
||||
#include "../share/global.h"
|
||||
|
||||
|
||||
#define BMASK 0377
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
extern byte em_flag[];
|
||||
|
||||
#define space1() printf(" ")
|
||||
char format[] = " %-11s%d\n";
|
||||
char lformat[] = " %-11s%D\n";
|
||||
char sformat[] = " %-10s%s\n";
|
||||
char dformat[] = " %-11s%d\n";
|
||||
char oformat[] = " %-11s%D\n";
|
||||
|
||||
|
||||
|
||||
FILE *f; /* input file */
|
||||
|
||||
|
||||
#define getbyte() getc(f)
|
||||
|
||||
short getshort()
|
||||
{
|
||||
register n;
|
||||
|
||||
n = getbyte();
|
||||
n |= getbyte() << 8;
|
||||
return n;
|
||||
}
|
||||
|
||||
int getint()
|
||||
{
|
||||
/* Read an integer from the input file. This routine is
|
||||
* only used when reading a bitvector-set. We expect an
|
||||
* integer to be either a short or a long.
|
||||
*/
|
||||
|
||||
if (sizeof(int) == sizeof(short)) {
|
||||
return getshort();
|
||||
} else {
|
||||
return getoff();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
offset getoff()
|
||||
{
|
||||
register offset n;
|
||||
|
||||
n = (unsigned) getshort();
|
||||
n |= ((offset) getshort() ) << 16;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/* VARARGS 1 */
|
||||
error(s,a) char *s,*a; {
|
||||
|
||||
fprintf(stderr,"error");
|
||||
fprintf(stderr,": ");
|
||||
fprintf(stderr,s,a);
|
||||
fprintf(stderr,"\n");
|
||||
abort();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
if (argc != 3 || argv[1][0] != '-') {
|
||||
error("usage: %s -[ldpbc] filename",argv[0]);
|
||||
}
|
||||
if ((f = fopen(argv[2], "r")) == NULL) {
|
||||
error("cannot open %s", argv[2]);
|
||||
}
|
||||
switch(argv[1][1]) {
|
||||
case 'l':
|
||||
showl();
|
||||
break;
|
||||
case 'd':
|
||||
showd();
|
||||
break;
|
||||
case 'p':
|
||||
showp();
|
||||
break;
|
||||
case 'b':
|
||||
showb();
|
||||
break;
|
||||
case 'c':
|
||||
showc();
|
||||
break;
|
||||
default:
|
||||
error("bad flag");
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
showcset()
|
||||
{
|
||||
/* print a compact (bitvector) set */
|
||||
|
||||
short size;
|
||||
register short i,j;
|
||||
int w, mask;
|
||||
|
||||
size = getshort();
|
||||
/* # significant bits in bitvector */
|
||||
i = 1;
|
||||
printf(" { ");
|
||||
if (size == 0) {
|
||||
printf("}\n");
|
||||
return;
|
||||
}
|
||||
for (;;) {
|
||||
w = getint();
|
||||
mask = 1 ;
|
||||
for (j = 1; j <= WORDLENGTH; j++) {
|
||||
if (w & mask) {
|
||||
printf("%d ",i);
|
||||
}
|
||||
if (i++ == size) {
|
||||
printf ("}\n");
|
||||
return;
|
||||
}
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
showp()
|
||||
{
|
||||
byte b;
|
||||
short n;
|
||||
short all;
|
||||
printf("total number of procs: %d\n\n",getshort());
|
||||
all = getshort();
|
||||
while (TRUE) {
|
||||
n = getshort();
|
||||
if (feof(f)) break;
|
||||
printf("PROC\n");
|
||||
printf(format,"id =",n);
|
||||
printf(format,"flags1 =",b = getbyte());
|
||||
if (b & PF_BODYSEEN) {
|
||||
printf(format,"# labels =",getshort());
|
||||
printf(lformat,"# locals =",getoff());
|
||||
printf(lformat,"# formals =",getoff());
|
||||
if (all == 1) {
|
||||
printf(" changed ="); showcset();
|
||||
printf(format,"c_flags =",getshort());
|
||||
printf(" used ="); showcset();
|
||||
printf(format,"u_flags =",getshort());
|
||||
printf(" calling ="); showcset();
|
||||
}
|
||||
} else {
|
||||
printf(" body not available\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *pseudo[] = {"hol", "bss", "rom", "con", "unknown" };
|
||||
|
||||
showd()
|
||||
{
|
||||
short n;
|
||||
printf("total number of objects: %d\n\n",getshort());
|
||||
while (TRUE) {
|
||||
n = getbyte();
|
||||
if (feof(f)) break;
|
||||
switch(n) {
|
||||
case MARK_DBLOCK:
|
||||
printf("DBLOCK\n");
|
||||
printf(format,"id =",getshort());
|
||||
printf(sformat,"pseudo =",
|
||||
pseudo[(short) getbyte()]);
|
||||
printf(lformat,"size =",getoff());
|
||||
printf(format,"fragment =",getshort());
|
||||
printf(format,"flags1 =",
|
||||
(short) getbyte());
|
||||
break;
|
||||
case MARK_OBJ:
|
||||
printf(" OBJ\n");
|
||||
space1();
|
||||
printf(format,"id =",getshort());
|
||||
space1();
|
||||
printf(lformat,"size =",getoff());
|
||||
space1();
|
||||
printf(lformat,"offset =",getoff());
|
||||
break;
|
||||
case MARK_ARG:
|
||||
printf(" VALUE\n");
|
||||
space1();
|
||||
printf(lformat,"offset =",getoff());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* The mnemonics of the EM instructions and pseudos */
|
||||
|
||||
|
||||
extern char em_mnem[];
|
||||
extern char em_pseu[];
|
||||
char lab_mnem[] = "instrlab";
|
||||
char sym_mnem[] = "datalab";
|
||||
|
||||
showinstr()
|
||||
{
|
||||
short instr;
|
||||
char *s;
|
||||
|
||||
instr = (short) getbyte();
|
||||
if (feof(f)) return FALSE;
|
||||
if (instr >= sp_fmnem && instr <= sp_lmnem) {
|
||||
s = &(em_mnem[(instr-sp_fmnem) *4]);
|
||||
} else {
|
||||
if (instr == op_lab) {
|
||||
s = lab_mnem;
|
||||
} else {
|
||||
if (instr == ps_sym) {
|
||||
s = sym_mnem;
|
||||
} else {
|
||||
s = &(em_pseu[(instr-sp_fpseu)*4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("%s",s);
|
||||
switch((short) getbyte()) {
|
||||
case OPSHORT:
|
||||
case OPOBJECT:
|
||||
printf(" %d", getshort());
|
||||
break;
|
||||
case OPPROC:
|
||||
printf(" $%d",getshort());
|
||||
break;
|
||||
case OPINSTRLAB:
|
||||
printf(" *%d",getshort());
|
||||
break;
|
||||
case OPOFFSET:
|
||||
printf(" %D", getoff());
|
||||
break;
|
||||
case OPLIST:
|
||||
arglist();
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
showl()
|
||||
{
|
||||
while (showinstr());
|
||||
}
|
||||
|
||||
|
||||
|
||||
arglist()
|
||||
{
|
||||
short length;
|
||||
for (;;) {
|
||||
switch((short) getbyte()) {
|
||||
case ARGOBJECT:
|
||||
printf(" %d", getshort());
|
||||
break;
|
||||
case ARGPROC:
|
||||
printf(" $%d",getshort());
|
||||
break;
|
||||
case ARGINSTRLAB:
|
||||
printf(" *%d",getshort());
|
||||
break;
|
||||
case ARGOFF:
|
||||
printf(" %D", getoff());
|
||||
break;
|
||||
case ARGICN:
|
||||
case ARGUCN:
|
||||
case ARGFCN:
|
||||
printf(" %d",getshort());
|
||||
/* Fall through !! */
|
||||
case ARGSTRING:
|
||||
length = getshort();
|
||||
putchar(' ');
|
||||
putchar('"');
|
||||
while (length--) {
|
||||
putchar(getbyte());
|
||||
}
|
||||
putchar('"');
|
||||
break;
|
||||
case ARGCEND:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
showlset()
|
||||
{
|
||||
register short x;
|
||||
|
||||
printf("{ ");
|
||||
while (x = getshort()) {
|
||||
printf("%d ",x);
|
||||
}
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
showb()
|
||||
{
|
||||
/* basic block file */
|
||||
|
||||
short n,m;
|
||||
|
||||
while (TRUE) {
|
||||
n = getshort();
|
||||
if (feof(f)) break;
|
||||
if (n == 0) {
|
||||
printf("Declaration Unit:\n");
|
||||
printf(dformat,"#instrs =",getshort());
|
||||
printf("\n");
|
||||
continue;
|
||||
}
|
||||
printf("Control Flow Graph:\n");
|
||||
printf("number of basic blocks: %d\n",n);
|
||||
m = getshort(); /* #loops */
|
||||
while (n--) {
|
||||
printf(" BASIC BLOCK\n");
|
||||
printf(dformat,"id =",getshort());
|
||||
printf(dformat,"# instrs =",getshort());
|
||||
printf(" succ =");
|
||||
showlset();
|
||||
printf(" pred =");
|
||||
showlset();
|
||||
printf(dformat,"idom =",getshort());
|
||||
printf(" loops =");
|
||||
showlset();
|
||||
printf(dformat,"flags =",getshort());
|
||||
}
|
||||
printf("number of loops: %d\n",m);
|
||||
while (m--) {
|
||||
printf(" LOOP\n");
|
||||
printf(dformat,"id =",getshort());
|
||||
printf(dformat,"level =",getshort());
|
||||
printf(dformat,"entry =",getshort());
|
||||
printf(dformat,"end =",getshort());
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
showc()
|
||||
{
|
||||
int n,m,cnt,t;
|
||||
|
||||
cnt = 1;
|
||||
while(TRUE) {
|
||||
t = getshort();
|
||||
if (feof(f)) break;
|
||||
printf("CALL %d\n",cnt++);
|
||||
printf(format,"nestlevel =",t);
|
||||
printf(format,"calling p. =",getshort());
|
||||
printf(format,"call_id =",getshort());
|
||||
printf(format,"called p. =",getshort());
|
||||
printf(format,"looplevel =",getbyte());
|
||||
printf(format,"flags =",getbyte());
|
||||
printf(format,"ratio =",getshort());
|
||||
printf(" actuals:");
|
||||
n = getshort();
|
||||
if (n == 0) {
|
||||
printf(" ---\n");
|
||||
} else {
|
||||
while (n--) {
|
||||
printf("\n");
|
||||
m = getshort();
|
||||
printf(oformat,"size =",getoff());
|
||||
printf(dformat,"inl =",getbyte());
|
||||
while (m--) {
|
||||
printf(" ");
|
||||
showinstr();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
104
util/ego/share/stack_chg.c
Normal file
104
util/ego/share/stack_chg.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
/* S T A C K _ C H A N G E . C */
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
|
||||
#include "pop_push.h"
|
||||
|
||||
#define IS_LOC(l) (l!=(line_p) 0 && INSTR(l)==op_loc && TYPE(l)==OPSHORT)
|
||||
|
||||
int stack_change(l,sign)
|
||||
line_p l;
|
||||
char sign;
|
||||
{
|
||||
/* Interpret the string in the third column of the em_table file */
|
||||
|
||||
char *s;
|
||||
bool argdef;
|
||||
short arg;
|
||||
int sum = 0;
|
||||
line_p p = PREV(l);
|
||||
line_p pp = (p == (line_p) 0 ? (line_p) 0 : PREV(p));
|
||||
short i = INSTR(l);
|
||||
|
||||
if (i < sp_fmnem || i > sp_lmnem) {
|
||||
return 0;
|
||||
} else {
|
||||
if (TYPE(l) == OPSHORT) {
|
||||
arg = SHORT(l);
|
||||
if (arg < ws) {
|
||||
/* E.g. a LOI 1 loads word-size bytes,
|
||||
* not 1 byte!
|
||||
*/
|
||||
arg = ws;
|
||||
}
|
||||
argdef = TRUE;
|
||||
} else {
|
||||
argdef = FALSE;
|
||||
}
|
||||
}
|
||||
s = pop_push[i];
|
||||
if (*s == '0') return 0;
|
||||
while (*s != '\0') {
|
||||
if (*s++ == sign) {
|
||||
switch(*s) {
|
||||
case 'w':
|
||||
sum += ws;
|
||||
break;
|
||||
case 'd':
|
||||
sum += 2 * ws;
|
||||
break;
|
||||
case 'p':
|
||||
sum += ps;
|
||||
break;
|
||||
case 'a':
|
||||
if (!argdef) return -1;
|
||||
sum += arg;
|
||||
break;
|
||||
case 'x':
|
||||
if (IS_LOC(p)) {
|
||||
sum += SHORT(p);
|
||||
break;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
case 'y':
|
||||
if (IS_LOC(pp)) {
|
||||
sum += SHORT(pp);
|
||||
break;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
case '?':
|
||||
return -1;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
}
|
||||
s++;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
|
||||
line_change(l,ok_out,pop_out,push_out)
|
||||
line_p l;
|
||||
bool *ok_out;
|
||||
int *pop_out,*push_out;
|
||||
{
|
||||
short pop,push;
|
||||
|
||||
pop = stack_change(l,'-');
|
||||
push = stack_change(l,'+');
|
||||
*ok_out = (pop != -1 && push != -1);
|
||||
*pop_out = pop;
|
||||
*push_out = push;
|
||||
}
|
||||
|
||||
|
10
util/ego/share/stack_chg.h
Normal file
10
util/ego/share/stack_chg.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
/* S T A C K _ C H A N G E . H */
|
||||
|
||||
extern line_change(); /* ( line_p l; bool *ok_out; int *pop_out,*push_out)
|
||||
* Try to determine how the stack-height will be
|
||||
* affected by the EM instruction l. 'ok_out' is set
|
||||
* to false if we fail to do so. pop_out and
|
||||
* push_out are set to the number of bytes popped
|
||||
* and pushed. E.g. for an "ADI 2" 4 and 2 are returned.
|
||||
*/
|
562
util/ego/share/types.h
Normal file
562
util/ego/share/types.h
Normal file
|
@ -0,0 +1,562 @@
|
|||
/* I N T E R N A L D A T A S T R U C T U R E S O F E G O */
|
||||
|
||||
|
||||
/* This file contains the definitions of the global data types.
|
||||
*/
|
||||
|
||||
|
||||
/* TEMPORARY: */
|
||||
#define LONGOFF
|
||||
|
||||
|
||||
#define IDL 8 /* identifier length */
|
||||
#define DYNAMIC 1
|
||||
#define NARGBYTES 14
|
||||
#define BMASK 0377
|
||||
|
||||
typedef struct argbytes argb_t;
|
||||
typedef char byte;
|
||||
typedef byte bool;
|
||||
typedef long offset;
|
||||
typedef short obj_id;
|
||||
typedef short proc_id;
|
||||
typedef short dblock_id;
|
||||
typedef short block_id;
|
||||
typedef short loop_id;
|
||||
typedef short lab_id;
|
||||
|
||||
|
||||
typedef struct dblock *dblock_p;
|
||||
typedef struct obj *obj_p;
|
||||
typedef struct proc *proc_p;
|
||||
typedef struct loop *loop_p;
|
||||
typedef struct change *change_p;
|
||||
typedef struct use *use_p;
|
||||
typedef struct bblock *bblock_p;
|
||||
typedef struct line *line_p;
|
||||
typedef struct arg *arg_p;
|
||||
typedef struct argbytes *argb_p;
|
||||
typedef struct elemholder *elem_p;
|
||||
typedef struct elemholder *lset;
|
||||
typedef struct bitvector *cset;
|
||||
typedef elem_p Lindex;
|
||||
typedef short Cindex;
|
||||
typedef char *Lelem_t;
|
||||
typedef short Celem_t;
|
||||
|
||||
typedef union pext_t *pext_p;
|
||||
typedef union bext_t *bext_p;
|
||||
typedef union lpext_t *lpext_p;
|
||||
|
||||
/* Intermediate Code generation */
|
||||
|
||||
typedef struct sym *sym_p;
|
||||
typedef struct prc *prc_p;
|
||||
typedef struct num *num_p;
|
||||
|
||||
/* Inline Substitution */
|
||||
typedef struct call *call_p;
|
||||
typedef struct actual *actual_p;
|
||||
typedef struct formal *formal_p;
|
||||
typedef struct calcnt *calcnt_p;
|
||||
typedef short call_id;
|
||||
|
||||
/* Strength Reduction */
|
||||
typedef struct iv *iv_p;
|
||||
typedef struct code_info *code_p;
|
||||
|
||||
/* Used-Definition Analysis */
|
||||
typedef struct local *local_p;
|
||||
|
||||
typedef struct cond_tab *cond_p;
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
/* DATABLOCKS */
|
||||
|
||||
/* A datablock is a block of global data, declared by means of
|
||||
* a hol, bss, con or rom pseudo. The declaration may be in a file
|
||||
* that is inaccessible to EGO, in which case the pseudo is unknown.
|
||||
* Successive rom or con pseudos that are garanteed to be in the
|
||||
* same fragment (according to the EM definition) share the
|
||||
* same fragment number.
|
||||
*/
|
||||
|
||||
#define DHOL 0
|
||||
#define DBSS 1
|
||||
#define DROM 2
|
||||
#define DCON 3
|
||||
#define DUNKNOWN 4
|
||||
|
||||
|
||||
/* The following constants are used by the debugging tools: */
|
||||
#define D_FIRST DHOL
|
||||
#define D_LAST DUNKNOWN
|
||||
|
||||
|
||||
struct dblock {
|
||||
dblock_id d_id; /* unique integer */
|
||||
byte d_pseudo; /* one of DHOL,DBSS,DROM,DCON,DUNKNOWN */
|
||||
offset d_size; /* # bytes, -1 if unknown */
|
||||
obj_p d_objlist; /* list of objects of the data block */
|
||||
byte d_flags1; /* see below */
|
||||
byte d_flags2; /* free to be used by phases */
|
||||
arg_p d_values; /* values, in case of ROM */
|
||||
short d_fragmnr; /* fragment number */
|
||||
dblock_p d_next; /* link to next block */
|
||||
};
|
||||
|
||||
|
||||
#define DF_EXTERNAL 01 /* Is name visible outside its module? */
|
||||
|
||||
/* OBJECTS */
|
||||
|
||||
/* An object is a row of successive bytes in one datablock
|
||||
* that are considered to be a whole. E.g. scalar variables,
|
||||
* arrays, I/O buffers etc. are objects.
|
||||
*/
|
||||
|
||||
struct obj {
|
||||
offset o_off; /* offset within the block */
|
||||
offset o_size; /* size of the object, 0 if not known */
|
||||
obj_id o_id; /* unique integer */
|
||||
dblock_p o_dblock; /* backlink to data block */
|
||||
short o_globnr; /* global variable number */
|
||||
obj_p o_next; /* link */
|
||||
};
|
||||
|
||||
|
||||
/* PROCEDURES */
|
||||
|
||||
struct proc {
|
||||
proc_id p_id; /* unique integer */
|
||||
short p_nrlabels; /* #instruction labels in the proc */
|
||||
offset p_localbytes; /* #bytes for locals */
|
||||
offset p_nrformals; /* #bytes for formals */
|
||||
byte p_flags1; /* see below */
|
||||
byte p_flags2; /* free to be used by phases */
|
||||
bblock_p p_start; /* pointer to first basic block */
|
||||
cset p_calling; /* set of all procs called by this one */
|
||||
lset p_loops; /* information about loops */
|
||||
change_p p_change; /* variables changed by this proc */
|
||||
use_p p_use; /* variables used by this proc */
|
||||
pext_p p_extend; /* pointer to any further information */
|
||||
proc_p p_next; /* link */
|
||||
};
|
||||
|
||||
|
||||
union pext_t {
|
||||
struct pext_il {
|
||||
call_p p_cals; /* candidate calls for in line expansion */
|
||||
short p_size; /* length of proc (EM-instrs or bytes) */
|
||||
formal_p p_formals; /* description of formals */
|
||||
short p_nrcalled; /* # times proc is called (varying) */
|
||||
long p_ccaddr; /* address of calcnt info on disk */
|
||||
long p_laddr; /* address in EM-text file on disk */
|
||||
short p_orglabels; /* original #labels before substitution */
|
||||
offset p_orglocals; /* original #bytes for locals */
|
||||
} px_il;
|
||||
} ;
|
||||
|
||||
#define PF_EXTERNAL 01 /* proc is externally visible */
|
||||
#define PF_BODYSEEN 02 /* body of proc is available as EM text */
|
||||
#define PF_CALUNKNOWN 04 /* proc calls an unavailable procedure */
|
||||
#define PF_ENVIRON 010 /* proc does a lxa or lxl */
|
||||
#define PF_LPI 020 /* proc may be called indirect */
|
||||
#define PF_CALINLOOP 040 /* proc ever called in a loop? (transitively) */
|
||||
|
||||
#define CALLED_IN_LOOP(p) p->p_flags1 |= PF_CALINLOOP
|
||||
#define IS_CALLED_IN_LOOP(p) (p->p_flags1 & PF_CALINLOOP)
|
||||
|
||||
|
||||
/* LOOPS */
|
||||
|
||||
struct loop {
|
||||
loop_id lp_id; /* unique integer */
|
||||
short lp_level; /* nesting level, 0=outermost loop,
|
||||
* 1=loop within loop etc. */
|
||||
bblock_p lp_entry; /* unique entry block of loop */
|
||||
bblock_p lp_end; /* tail of back edge of natural loop */
|
||||
lpext_p lp_extend; /* pointer to any further information */
|
||||
};
|
||||
|
||||
|
||||
|
||||
union lpext_t {
|
||||
struct lpext_cf {
|
||||
lset lpx_blocks;
|
||||
short lpx_count;
|
||||
bool lpx_messy;
|
||||
} lpx_cf;
|
||||
struct lpext_sr {
|
||||
lset lpx_blocks; /* basic blocks constituting the loop */
|
||||
bblock_p lpx_header; /* header block, 0 if no one allocated yet */
|
||||
bool lpx_done; /* TRUE if we've processed this loop */
|
||||
line_p lpx_instr; /* current last instruction in header block*/
|
||||
} lpx_sr;
|
||||
struct lpext_ra {
|
||||
lset lpx_blocks; /* basic blocks constituting the loop */
|
||||
bblock_p lpx_header; /* header block, 0 if no one allocated yet */
|
||||
} lpx_ra;
|
||||
} ;
|
||||
|
||||
/* CHANGED/USED VARIABLES INFORMATION */
|
||||
|
||||
|
||||
struct change {
|
||||
cset c_ext; /* external variables changed */
|
||||
short c_flags; /* see below */
|
||||
};
|
||||
|
||||
struct use {
|
||||
short u_flags; /* see below */
|
||||
};
|
||||
|
||||
|
||||
#define CF_INDIR 01
|
||||
#define UF_INDIR 01
|
||||
|
||||
|
||||
/* SETS */
|
||||
|
||||
|
||||
/* There are 2 set representations:
|
||||
* - long (lset), which is essentially a list
|
||||
* - compact (cset), which is essentially a bitvector
|
||||
*/
|
||||
|
||||
|
||||
struct elemholder {
|
||||
char *e_elem; /* pointer to the element */
|
||||
elem_p e_next; /* link */
|
||||
};
|
||||
|
||||
struct bitvector {
|
||||
short v_size; /* # significant bits */
|
||||
int v_bits[DYNAMIC];/* a row of bits */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* BASIC BLOCKS */
|
||||
|
||||
|
||||
/* Note that the b_succ and b_pred fields constitute the
|
||||
* Control Flow Graph
|
||||
*/
|
||||
|
||||
|
||||
struct bblock {
|
||||
block_id b_id; /* unique integer */
|
||||
line_p b_start; /* pointer to first instruction */
|
||||
lset b_succ; /* set of successor blocks */
|
||||
lset b_pred; /* set of predecessor blocks */
|
||||
bblock_p b_idom; /* immediate dominator */
|
||||
lset b_loops; /* set of loops it is in */
|
||||
short b_flags; /* see below */
|
||||
bext_p b_extend; /* pointer to any further information */
|
||||
bblock_p b_next; /* link to textually next block */
|
||||
};
|
||||
|
||||
|
||||
union bext_t {
|
||||
struct bext_cf {
|
||||
short bx_semi; /* dfs number of semi-dominator */
|
||||
bblock_p bx_parent; /* parent in dfs spanning tree */
|
||||
lset bx_bucket; /* set of vertices whose sdom is b */
|
||||
bblock_p bx_ancestor; /* ancestor of b in forest, */
|
||||
bblock_p bx_label; /* used by link/eval */
|
||||
} bx_cf;
|
||||
struct bext_ud {
|
||||
cset bx_gen; /* definition generated in b */
|
||||
cset bx_kill; /* defs. outside b killed by b */
|
||||
cset bx_in; /* defs. reaching beginning of b */
|
||||
cset bx_out; /* defs. reaching end of b */
|
||||
cset bx_cgen; /* generated copies */
|
||||
cset bx_ckill; /* killed copies */
|
||||
cset bx_cin; /* copies reaching begin of b */
|
||||
cset bx_cout; /* copies reaching end of b */
|
||||
cset bx_chgvars; /* variables changed by b */
|
||||
} bx_ud;
|
||||
struct bext_lv {
|
||||
cset bx_use; /* variables used before being defined */
|
||||
cset bx_def; /* variables defined before being used */
|
||||
cset bx_lin; /* variables live at entry of b */
|
||||
cset bx_lout; /* variables live at exit of b */
|
||||
} bx_lv;
|
||||
struct bext_ra {
|
||||
short bx_begin; /* number of first instruction of block */
|
||||
short bx_end; /* number of last instruction of block */
|
||||
short bx_usecnt; /* used by minimal_score() */
|
||||
short bx_dist; /* ,, */
|
||||
bool bx_mark; /* ,, */
|
||||
} bx_ra;
|
||||
} ;
|
||||
|
||||
|
||||
#define BF_STRONG 01
|
||||
#define BF_FIRM 02
|
||||
|
||||
#define IS_STRONG(b) (b->b_flags&BF_STRONG)
|
||||
#define IS_FIRM(b) (b->b_flags&BF_FIRM)
|
||||
|
||||
|
||||
/* EM INSTRUCTIONS */
|
||||
|
||||
/* Kinds of operand types (l_optype field) */
|
||||
|
||||
#define OPNO 0
|
||||
#define OPSHORT 1
|
||||
#define OPOFFSET 2
|
||||
#define OPINSTRLAB 3
|
||||
#define OPOBJECT 4
|
||||
#define OPPROC 5
|
||||
#define OPLIST 6
|
||||
|
||||
|
||||
/* The following constants are used by the debugging tools: */
|
||||
#define OP_FIRST OPNO
|
||||
#define OP_LAST OPLIST
|
||||
|
||||
#define LDATA 0
|
||||
#define LTEXT 01
|
||||
|
||||
struct line {
|
||||
line_p l_next; /* link */
|
||||
byte l_instr; /* instruction */
|
||||
byte l_optype; /* kind of operand, used as tag */
|
||||
line_p l_prev; /* backlink to previous instruction */
|
||||
union {
|
||||
short la_short; /* short: LOC 5 */
|
||||
offset la_offset; /* offset: LDC 20 */
|
||||
lab_id la_instrlab; /* label: BRA *10 */
|
||||
obj_p la_obj; /* object: LOE X+2 */
|
||||
proc_p la_proc; /* proc: CAL F3 */
|
||||
arg_p la_arg; /* arguments: HOL 10,0,0 */
|
||||
} l_a;
|
||||
};
|
||||
|
||||
|
||||
/* ARGUMENTS */
|
||||
|
||||
|
||||
/* String representation of a constant, partitioned into
|
||||
* pieces of NARGBYTES bytes.
|
||||
*/
|
||||
|
||||
#define ARGOFF 0
|
||||
#define ARGINSTRLAB 1
|
||||
#define ARGOBJECT 2
|
||||
#define ARGPROC 3
|
||||
#define ARGSTRING 4
|
||||
#define ARGICN 5
|
||||
#define ARGUCN 6
|
||||
#define ARGFCN 7
|
||||
#define ARGCEND 8
|
||||
|
||||
|
||||
struct argbytes {
|
||||
argb_p ab_next;
|
||||
short ab_index;
|
||||
char ab_contents[NARGBYTES];
|
||||
};
|
||||
|
||||
|
||||
struct arg {
|
||||
arg_p a_next; /* link */
|
||||
short a_type; /* kind of argument */
|
||||
union {
|
||||
offset a_offset; /* offset */
|
||||
lab_id a_instrlab; /* instruction label */
|
||||
proc_p a_proc; /* procedure */
|
||||
obj_p a_obj; /* object */
|
||||
argb_t a_string; /* string */
|
||||
struct { /* int/unsigned/float constant */
|
||||
short ac_length; /* size in bytes */
|
||||
argb_t ac_con; /* its string repres. */
|
||||
} a_con;
|
||||
} a_a;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Macros to increase readability: */
|
||||
|
||||
#define INSTR(lnp) (lnp->l_instr & BMASK)
|
||||
#define TYPE(lnp) lnp->l_optype
|
||||
#define PREV(lnp) lnp->l_prev
|
||||
#define SHORT(lnp) lnp->l_a.la_short
|
||||
#define OFFSET(lnp) lnp->l_a.la_offset
|
||||
#define INSTRLAB(lnp) lnp->l_a.la_instrlab
|
||||
#define OBJ(lnp) lnp->l_a.la_obj
|
||||
#define PROC(lnp) lnp->l_a.la_proc
|
||||
#define ARG(lnp) lnp->l_a.la_arg
|
||||
|
||||
|
||||
/* Data structures for Intermediate Code generation */
|
||||
|
||||
|
||||
struct sym {
|
||||
sym_p sy_next; /* link */
|
||||
char sy_name[IDL]; /* name of the symbol */
|
||||
dblock_p sy_dblock; /* pointer to dblock struct */
|
||||
};
|
||||
struct prc {
|
||||
prc_p pr_next; /* link */
|
||||
char pr_name[IDL]; /* name of the procedure */
|
||||
proc_p pr_proc; /* pointer tto proc struct */
|
||||
};
|
||||
|
||||
|
||||
struct num {
|
||||
num_p n_next; /* link */
|
||||
unsigned n_number; /* EM repr. e.g. 120 in 'BRA *120' */
|
||||
lab_id n_labid; /* sequential integer repr. of IC */
|
||||
};
|
||||
|
||||
|
||||
/* Data structures for Inline Substitution */
|
||||
|
||||
struct call {
|
||||
proc_p cl_caller; /* calling procedure */
|
||||
call_id cl_id; /* uniquely denotes a CAL instruction */
|
||||
proc_p cl_proc; /* the called procedure */
|
||||
byte cl_looplevel; /* loop nesting level of the CAL */
|
||||
bool cl_flags; /* flag bits */
|
||||
short cl_ratio; /* indicates 'speed gain / size lost' */
|
||||
call_p cl_cdr; /* link to next call */
|
||||
call_p cl_car; /* link to nested calls */
|
||||
actual_p cl_actuals; /* actual parameter expr. trees */
|
||||
};
|
||||
|
||||
#define CLF_INLPARS 017 /* min(15,nr. of inline parameters) */
|
||||
#define CLF_SELECTED 020 /* is call selected for expansion? */
|
||||
#define CLF_EVER_EXPANDED 040 /* ever expanded? e.g. in a nested call. */
|
||||
#define CLF_FIRM 0100 /* indicates if the call takes place in a
|
||||
* firm block of a loop (i.e. one that
|
||||
* is always executed, except
|
||||
* -perhaps- at the last iteration).
|
||||
* Used for heuristics only.
|
||||
*/
|
||||
|
||||
struct actual {
|
||||
line_p ac_exp; /* copy of EM text */
|
||||
/* 0 for actuals that are not inline */
|
||||
offset ac_size; /* number of bytes of parameter */
|
||||
bool ac_inl; /* TRUE if it may be expanded in line */
|
||||
actual_p ac_next; /* link */
|
||||
};
|
||||
|
||||
|
||||
struct formal {
|
||||
offset f_offset; /* offsetin bytes */
|
||||
byte f_flags; /* flags FF_BAD etc. */
|
||||
byte f_type; /* SINGLE, DOUBLE,POINTER,UNKNOWN */
|
||||
formal_p f_next; /* link */
|
||||
};
|
||||
|
||||
|
||||
/* flags of formal: */
|
||||
|
||||
#define FF_BAD 01
|
||||
#define FF_REG 02
|
||||
#define FF_ONCEUSED 04
|
||||
#define FF_OFTENUSED 06
|
||||
#define USEMASK 014
|
||||
|
||||
/* types of formals: */
|
||||
|
||||
#define SINGLE 1
|
||||
#define DOUBLE 2
|
||||
#define POINTER 3
|
||||
#define UNKNOWN 4
|
||||
|
||||
/* 'call-count' information keeps track of the number
|
||||
* of times one procedure calls another. Conceptually,
|
||||
* it may be regarded as a two dimensional array, where
|
||||
* calcnt[p,q] is the number of times p calls q. As this
|
||||
* matrix would be very dense, we use a more efficient
|
||||
* list representation. Every procedure has a list
|
||||
* of calcnt structs.
|
||||
*/
|
||||
|
||||
struct calcnt {
|
||||
proc_p cc_proc; /* the called procedure */
|
||||
short cc_count; /* # times proc. is called in the
|
||||
* original text of the caller.
|
||||
*/
|
||||
calcnt_p cc_next; /* link */
|
||||
};
|
||||
|
||||
|
||||
/* Data structures for Strength Reduction */
|
||||
|
||||
/* An induction variable */
|
||||
|
||||
struct iv {
|
||||
offset iv_off; /* offset of the induction variable */
|
||||
line_p iv_incr; /* pointer to last instr. of EM-code that
|
||||
* increments the induction variable */
|
||||
offset iv_step; /* step value */
|
||||
};
|
||||
|
||||
|
||||
/* All information about a reducible piece of code is collected in
|
||||
* a single structure.
|
||||
*/
|
||||
|
||||
struct code_info {
|
||||
loop_p co_loop; /* the loop the code is in */
|
||||
bblock_p co_block; /* the basic block the code is in */
|
||||
line_p co_lfirst; /* first instruction of the code */
|
||||
line_p co_llast; /* last instruction of the code */
|
||||
line_p co_ivexpr; /* start of linear expr. using iv */
|
||||
line_p co_endexpr; /* end of the expression */
|
||||
int co_sign; /* sign of iv in above expr */
|
||||
iv_p co_iv; /* the induction variable */
|
||||
offset co_temp; /* temporary variable */
|
||||
int co_tmpsize; /* size of the temp. variable (ws or ps)*/
|
||||
int co_instr; /* the expensive instruction (mli,lar..)*/
|
||||
union {
|
||||
line_p co_loadlc; /* LOC lc instruction (for mult.)*/
|
||||
line_p co_desc; /* load address of descriptor
|
||||
* (for lar etc.) */
|
||||
} c_o;
|
||||
};
|
||||
|
||||
|
||||
/* Data structures for Use-Definition and Live-Dead Analysis */
|
||||
|
||||
struct local {
|
||||
offset lc_off; /* offset of local in stackframe */
|
||||
short lc_size; /* size of local in bytes */
|
||||
short lc_flags; /* see below */
|
||||
offset lc_score; /* score in register message, if regvar */
|
||||
local_p lc_next; /* link, only used when building the list */
|
||||
};
|
||||
|
||||
/* values of lc_flags */
|
||||
|
||||
#define LCF_BAD 01
|
||||
/* Set when no ud-info for this local is maintained, e.g. when it is
|
||||
* overlapped by another local.
|
||||
*/
|
||||
#define LCF_REG 02 /* register variable */
|
||||
#define LCF_LIVE 04 /* use by live-dead message generation */
|
||||
|
||||
|
||||
struct cond_tab {
|
||||
short mc_cond; /* Denotes a condition e.g. FITBYTE */
|
||||
short mc_tval; /* value for time optimization */
|
||||
short mc_sval; /* value for space optimization */
|
||||
short mc_dummy; /* allignment */
|
||||
};
|
||||
|
||||
/* conditions: */
|
||||
|
||||
#define DEFAULT 0
|
||||
#define FITBYTE 1
|
||||
#define IN_0_63 2
|
||||
#define IN_0_8 3
|
||||
|
46
util/ego/sp/Makefile
Normal file
46
util/ego/sp/Makefile
Normal file
|
@ -0,0 +1,46 @@
|
|||
|
||||
EMH=../../../h
|
||||
EML=../../../lib
|
||||
SHARE=../share
|
||||
OBJECTS=sp.o
|
||||
MOBJECTS=sp.m
|
||||
SHOBJECTS=$(SHARE)/get.o $(SHARE)/put.o $(SHARE)/alloc.o $(SHARE)/global.o $(SHARE)/debug.o $(SHARE)/files.o $(SHARE)/map.o $(SHARE)/lset.o $(SHARE)/cset.o $(SHARE)/aux.o $(SHARE)/stack_chg.o $(SHARE)/go.o
|
||||
MSHOBJECTS=$(SHARE)/get.m $(SHARE)/put.m $(SHARE)/alloc.m $(SHARE)/global.m $(SHARE)/debug.m $(SHARE)/files.m $(SHARE)/map.m $(SHARE)/lset.m $(SHARE)/cset.m $(SHARE)/aux.m $(SHARE)/stack_chg.m
|
||||
SRC=sp.c
|
||||
.SUFFIXES: .m
|
||||
|
||||
.c.o:
|
||||
cc $(CFLAGS) -c $<
|
||||
.c.m:
|
||||
ack -O -L -c.m $(CFLAGS) $<
|
||||
all: $(OBJECTS)
|
||||
sp: \
|
||||
$(OBJECTS) $(SHOBJECTS)
|
||||
cc -o sp -i $(OBJECTS) $(SHOBJECTS) $(EML)/em_data.a
|
||||
optim: $(MOBJECTS) $(MSHOBJECTS)
|
||||
ego IC CF $(F) CA $(MOBJECTS) $(MSHOBJECTS)
|
||||
ack -O -o sp.ego -.c lfile.m $(EML)/em_data.a
|
||||
lpr:
|
||||
pr $(SRC) | lpr
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
sp.o: ../share/alloc.h
|
||||
sp.o: ../share/aux.h
|
||||
sp.o: ../share/debug.h
|
||||
sp.o: ../share/files.h
|
||||
sp.o: ../share/get.h
|
||||
sp.o: ../share/global.h
|
||||
sp.o: ../share/go.h
|
||||
sp.o: ../share/lset.h
|
||||
sp.o: ../share/map.h
|
||||
sp.o: ../share/put.h
|
||||
sp.o: ../share/stack_chg.h
|
||||
sp.o: ../share/types.h
|
||||
sp.o: ../../../h/em_mnem.h
|
||||
sp.o: ../../../h/em_spec.h
|
||||
stack_chg.o: ../share/debug.h
|
||||
stack_chg.o: ../share/global.h
|
||||
stack_chg.o: ../share/types.h
|
||||
stack_chg.o: ../../../h/em_mnem.h
|
||||
stack_chg.o: ../../../h/em_spec.h
|
||||
stack_chg.o: pop_push.h
|
240
util/ego/sp/sp.c
Normal file
240
util/ego/sp/sp.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
/* S T A C K P O L L U T I O N
|
||||
*
|
||||
* S P . C
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/files.h"
|
||||
#include "../share/get.h"
|
||||
#include "../share/put.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/map.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/go.h"
|
||||
#include "../share/stack_chg.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
|
||||
|
||||
/* Stack pollution throws away the ASP instructions after a procedure call.
|
||||
* This saves a lot of code, at the cost of some extra stack space.
|
||||
* ASPs that are part of a loop are not removed.
|
||||
*/
|
||||
|
||||
#define BF_MARK 04
|
||||
#define MARK(b) b->b_flags |= BF_MARK
|
||||
#define NOT_MARKED(b) (!(b->b_flags&BF_MARK))
|
||||
#define IN_LOOP(b) (Lnrelems(b->b_loops) > 0)
|
||||
|
||||
STATIC int Ssp; /* number of optimizations */
|
||||
|
||||
/* According to the EM definition, the stack must be cleaned up
|
||||
* before any return. However, for some backends it causes no harm
|
||||
* if the stack is not cleaned up. If so, we can do Stack Pollution
|
||||
* more globally.
|
||||
*/
|
||||
|
||||
STATIC int globl_sp_allowed;
|
||||
|
||||
|
||||
#define IS_ASP(l) (INSTR(l) == op_asp && TYPE(l) == OPSHORT && SHORT(l) > 0)
|
||||
|
||||
|
||||
STATIC sp_machinit(f)
|
||||
FILE *f;
|
||||
{
|
||||
/* Read target machine dependent information for this phase */
|
||||
char s[100];
|
||||
|
||||
for (;;) {
|
||||
while(getc(f) != '\n');
|
||||
fscanf(f,"%s",s);
|
||||
if (strcmp(s,"%%SP") == 0)break;
|
||||
}
|
||||
fscanf(f,"%d",&globl_sp_allowed);
|
||||
}
|
||||
comb_asps(l1,l2,b)
|
||||
line_p l1,l2;
|
||||
bblock_p b;
|
||||
{
|
||||
assert(INSTR(l1) == op_asp);
|
||||
assert(INSTR(l2) == op_asp);
|
||||
assert(TYPE(l1) == OPSHORT);
|
||||
assert(TYPE(l2) == OPSHORT);
|
||||
|
||||
SHORT(l2) += SHORT(l1);
|
||||
rm_line(l1,b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
stack_pollution(b)
|
||||
bblock_p b;
|
||||
{
|
||||
/* For every pair of successive ASP instructions in basic
|
||||
* block b, try to combine the two into one ASP.
|
||||
*/
|
||||
|
||||
register line_p l;
|
||||
line_p asp,next = b->b_start;
|
||||
bool asp_seen = FALSE;
|
||||
int stack_diff,pop,push;
|
||||
bool ok;
|
||||
|
||||
do {
|
||||
stack_diff = 0;
|
||||
for (l = next; l != (line_p) 0; l = next) {
|
||||
next = l->l_next;
|
||||
if (IS_ASP(l)) break;
|
||||
if (asp_seen) {
|
||||
if (INSTR(l) == op_ret) {
|
||||
stack_diff -= SHORT(l);
|
||||
} else {
|
||||
line_change(l,&ok,&pop,&push);
|
||||
if (!ok || (stack_diff -= pop) < 0) {
|
||||
/* can't eliminate last ASP */
|
||||
asp_seen = FALSE;
|
||||
} else {
|
||||
stack_diff += push;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (asp_seen) {
|
||||
if (l == (line_p) 0) {
|
||||
/* last asp of basic block */
|
||||
if (globl_sp_allowed &&
|
||||
NOT_MARKED(b) && !IN_LOOP(b)) {
|
||||
Ssp++;
|
||||
rm_line(asp,b);
|
||||
}
|
||||
} else {
|
||||
/* try to combine with previous asp */
|
||||
if (SHORT(l) == stack_diff) {
|
||||
Ssp++;
|
||||
comb_asps(asp,l,b);
|
||||
}
|
||||
}
|
||||
}
|
||||
asp = l;
|
||||
asp_seen = TRUE; /* use new ASP for next try! */
|
||||
} while (asp != (line_p) 0);
|
||||
}
|
||||
|
||||
STATIC bool block_save(b)
|
||||
bblock_p b;
|
||||
{
|
||||
|
||||
register line_p l;
|
||||
int stack_diff,pop,push;
|
||||
bool ok;
|
||||
|
||||
stack_diff = 0;
|
||||
for (l = b->b_start; l != (line_p) 0; l = l->l_next) {
|
||||
if (INSTR(l) == op_ret) {
|
||||
stack_diff -= SHORT(l);
|
||||
break;
|
||||
}
|
||||
line_change(l,&ok,&pop,&push);
|
||||
/* printf("instr %d, pop %d,push %d,ok %d\n",INSTR(l),pop,push,ok); */
|
||||
if (!ok || (stack_diff -= pop) < 0) {
|
||||
return FALSE;
|
||||
} else {
|
||||
stack_diff += push;
|
||||
}
|
||||
}
|
||||
return stack_diff >= 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC mark_pred(b)
|
||||
bblock_p b;
|
||||
{
|
||||
Lindex i;
|
||||
bblock_p x;
|
||||
|
||||
for (i = Lfirst(b->b_pred); i != (Lindex) 0; i = Lnext(i,b->b_pred)) {
|
||||
x = (bblock_p) Lelem(i);
|
||||
if (NOT_MARKED(x)) {
|
||||
MARK(x);
|
||||
mark_pred(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
STATIC mark_unsave_blocks(p)
|
||||
proc_p p;
|
||||
{
|
||||
register bblock_p b;
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
if (NOT_MARKED(b) && !block_save(b)) {
|
||||
MARK(b);
|
||||
mark_pred(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sp_optimize(p)
|
||||
proc_p p;
|
||||
{
|
||||
register bblock_p b;
|
||||
|
||||
mark_unsave_blocks(p);
|
||||
for (b = p->p_start; b != 0; b = b->b_next) {
|
||||
stack_pollution(b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
go(argc,argv,no_action,sp_optimize,sp_machinit,no_action);
|
||||
report("stack adjustments deleted",Ssp);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***** DEBUGGING:
|
||||
|
||||
debug_stack_pollution(p)
|
||||
proc_p p;
|
||||
{
|
||||
register bblock_p b;
|
||||
register line_p l;
|
||||
int lcnt,aspcnt,instr;
|
||||
|
||||
for (b = p->p_start; b != 0; b = b->b_next) {
|
||||
lcnt = 0; aspcnt = 0;
|
||||
for (l = b->b_start; l != 0; l= l->l_next) {
|
||||
instr = INSTR(l);
|
||||
if (instr >= sp_fmnem && instr <= sp_lmnem) {
|
||||
lcnt++;
|
||||
if (instr == op_asp && off_set(l) > 0) {
|
||||
aspcnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("%d\t%d\n",aspcnt,lcnt);
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
Loading…
Reference in a new issue