Initial revision
authorbal <none@none>
Mon, 26 Nov 1984 15:04:22 +0000 (15:04 +0000)
committerbal <none@none>
Mon, 26 Nov 1984 15:04:22 +0000 (15:04 +0000)
38 files changed:
util/ego/cj/Makefile [new file with mode: 0644]
util/ego/cj/cj.c [new file with mode: 0644]
util/ego/share/alloc.c [new file with mode: 0644]
util/ego/share/alloc.h [new file with mode: 0644]
util/ego/share/aux.c [new file with mode: 0644]
util/ego/share/aux.h [new file with mode: 0644]
util/ego/share/cset.c [new file with mode: 0644]
util/ego/share/cset.h [new file with mode: 0644]
util/ego/share/debug.c [new file with mode: 0644]
util/ego/share/debug.h [new file with mode: 0644]
util/ego/share/def.h [new file with mode: 0644]
util/ego/share/files.c [new file with mode: 0644]
util/ego/share/files.h [new file with mode: 0644]
util/ego/share/get.c [new file with mode: 0644]
util/ego/share/get.h [new file with mode: 0644]
util/ego/share/global.c [new file with mode: 0644]
util/ego/share/global.h [new file with mode: 0644]
util/ego/share/go.c [new file with mode: 0644]
util/ego/share/go.h [new file with mode: 0644]
util/ego/share/init_glob.c [new file with mode: 0644]
util/ego/share/init_glob.h [new file with mode: 0644]
util/ego/share/locals.c [new file with mode: 0644]
util/ego/share/locals.h [new file with mode: 0644]
util/ego/share/lset.c [new file with mode: 0644]
util/ego/share/lset.h [new file with mode: 0644]
util/ego/share/makecldef.c [new file with mode: 0644]
util/ego/share/map.c [new file with mode: 0644]
util/ego/share/map.h [new file with mode: 0644]
util/ego/share/parser.c [new file with mode: 0644]
util/ego/share/parser.h [new file with mode: 0644]
util/ego/share/put.c [new file with mode: 0644]
util/ego/share/put.h [new file with mode: 0644]
util/ego/share/show.c [new file with mode: 0644]
util/ego/share/stack_chg.c [new file with mode: 0644]
util/ego/share/stack_chg.h [new file with mode: 0644]
util/ego/share/types.h [new file with mode: 0644]
util/ego/sp/Makefile [new file with mode: 0644]
util/ego/sp/sp.c [new file with mode: 0644]

diff --git a/util/ego/cj/Makefile b/util/ego/cj/Makefile
new file mode 100644 (file)
index 0000000..4a2f23d
--- /dev/null
@@ -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
+
diff --git a/util/ego/cj/cj.c b/util/ego/cj/cj.c
new file mode 100644 (file)
index 0000000..3c27ebc
--- /dev/null
@@ -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);
+       }
+}
diff --git a/util/ego/share/alloc.c b/util/ego/share/alloc.c
new file mode 100644 (file)
index 0000000..c7cbc2d
--- /dev/null
@@ -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);
+}
diff --git a/util/ego/share/alloc.h b/util/ego/share/alloc.h
new file mode 100644 (file)
index 0000000..8fa5cd4
--- /dev/null
@@ -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();
diff --git a/util/ego/share/aux.c b/util/ego/share/aux.c
new file mode 100644 (file)
index 0000000..d753ef5
--- /dev/null
@@ -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);
+}
diff --git a/util/ego/share/aux.h b/util/ego/share/aux.h
new file mode 100644 (file)
index 0000000..451aa39
--- /dev/null
@@ -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.
+                                */
diff --git a/util/ego/share/cset.c b/util/ego/share/cset.c
new file mode 100644 (file)
index 0000000..646fefe
--- /dev/null
@@ -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;
+}
diff --git a/util/ego/share/cset.h b/util/ego/share/cset.h
new file mode 100644 (file)
index 0000000..1c7199c
--- /dev/null
@@ -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)                       */
diff --git a/util/ego/share/debug.c b/util/ego/share/debug.c
new file mode 100644 (file)
index 0000000..104a307
--- /dev/null
@@ -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);
+       }
+}
diff --git a/util/ego/share/debug.h b/util/ego/share/debug.h
new file mode 100644 (file)
index 0000000..72da2c6
--- /dev/null
@@ -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
diff --git a/util/ego/share/def.h b/util/ego/share/def.h
new file mode 100644 (file)
index 0000000..07db907
--- /dev/null
@@ -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
diff --git a/util/ego/share/files.c b/util/ego/share/files.c
new file mode 100644 (file)
index 0000000..062306e
--- /dev/null
@@ -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;
+}
diff --git a/util/ego/share/files.h b/util/ego/share/files.h
new file mode 100644 (file)
index 0000000..494893b
--- /dev/null
@@ -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.
+                                */
diff --git a/util/ego/share/get.c b/util/ego/share/get.c
new file mode 100644 (file)
index 0000000..e09c4ee
--- /dev/null
@@ -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;
+}
diff --git a/util/ego/share/get.h b/util/ego/share/get.h
new file mode 100644 (file)
index 0000000..c3185fb
--- /dev/null
@@ -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).
+                                        */
diff --git a/util/ego/share/global.c b/util/ego/share/global.c
new file mode 100644 (file)
index 0000000..37d8a00
--- /dev/null
@@ -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'.
+                                */
diff --git a/util/ego/share/global.h b/util/ego/share/global.h
new file mode 100644 (file)
index 0000000..198e30f
--- /dev/null
@@ -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'.
+                                */
diff --git a/util/ego/share/go.c b/util/ego/share/go.c
new file mode 100644 (file)
index 0000000..5a59735
--- /dev/null
@@ -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);
+       }
+}
diff --git a/util/ego/share/go.h b/util/ego/share/go.h
new file mode 100644 (file)
index 0000000..3c3bff1
--- /dev/null
@@ -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
+                        */
diff --git a/util/ego/share/init_glob.c b/util/ego/share/init_glob.c
new file mode 100644 (file)
index 0000000..088d679
--- /dev/null
@@ -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;
+}
diff --git a/util/ego/share/init_glob.h b/util/ego/share/init_glob.h
new file mode 100644 (file)
index 0000000..984b847
--- /dev/null
@@ -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.
+                                 */
diff --git a/util/ego/share/locals.c b/util/ego/share/locals.c
new file mode 100644 (file)
index 0000000..e71c0a9
--- /dev/null
@@ -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);
+       }
+}
diff --git a/util/ego/share/locals.h b/util/ego/share/locals.h
new file mode 100644 (file)
index 0000000..3b101fd
--- /dev/null
@@ -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)
+
+
diff --git a/util/ego/share/lset.c b/util/ego/share/lset.c
new file mode 100644 (file)
index 0000000..85348dc
--- /dev/null
@@ -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;
+}
diff --git a/util/ego/share/lset.h b/util/ego/share/lset.h
new file mode 100644 (file)
index 0000000..826b894
--- /dev/null
@@ -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)                       */
diff --git a/util/ego/share/makecldef.c b/util/ego/share/makecldef.c
new file mode 100644 (file)
index 0000000..f656b09
--- /dev/null
@@ -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);
+}
diff --git a/util/ego/share/map.c b/util/ego/share/map.c
new file mode 100644 (file)
index 0000000..6545882
--- /dev/null
@@ -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   */
diff --git a/util/ego/share/map.h b/util/ego/share/map.h
new file mode 100644 (file)
index 0000000..9c3a465
--- /dev/null
@@ -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 */
diff --git a/util/ego/share/parser.c b/util/ego/share/parser.c
new file mode 100644 (file)
index 0000000..94ddb51
--- /dev/null
@@ -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;
+}
diff --git a/util/ego/share/parser.h b/util/ego/share/parser.h
new file mode 100644 (file)
index 0000000..b09c5f5
--- /dev/null
@@ -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.
+                        */
diff --git a/util/ego/share/put.c b/util/ego/share/put.c
new file mode 100644 (file)
index 0000000..ba26b07
--- /dev/null
@@ -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;
+}
diff --git a/util/ego/share/put.h b/util/ego/share/put.h
new file mode 100644 (file)
index 0000000..73c0a47
--- /dev/null
@@ -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.
+                                */
diff --git a/util/ego/share/show.c b/util/ego/share/show.c
new file mode 100644 (file)
index 0000000..b7e3d1a
--- /dev/null
@@ -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();
+                               }
+                       }
+               }
+       }
+}
diff --git a/util/ego/share/stack_chg.c b/util/ego/share/stack_chg.c
new file mode 100644 (file)
index 0000000..89a8056
--- /dev/null
@@ -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;
+}
+
+
diff --git a/util/ego/share/stack_chg.h b/util/ego/share/stack_chg.h
new file mode 100644 (file)
index 0000000..5257626
--- /dev/null
@@ -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.
+                        */
diff --git a/util/ego/share/types.h b/util/ego/share/types.h
new file mode 100644 (file)
index 0000000..d002ca2
--- /dev/null
@@ -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
+
diff --git a/util/ego/sp/Makefile b/util/ego/sp/Makefile
new file mode 100644 (file)
index 0000000..e33dc9f
--- /dev/null
@@ -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
diff --git a/util/ego/sp/sp.c b/util/ego/sp/sp.c
new file mode 100644 (file)
index 0000000..001c202
--- /dev/null
@@ -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);
+       }
+}
+
+*/