Initial revision
authorceriel <none@none>
Mon, 24 Nov 1986 20:58:35 +0000 (20:58 +0000)
committerceriel <none@none>
Mon, 24 Nov 1986 20:58:35 +0000 (20:58 +0000)
mach/arm/top/Makefile [new file with mode: 0644]
mach/m68020/top/Makefile [new file with mode: 0644]
mach/m68k2/top/Makefile [new file with mode: 0644]
mach/pdp/top/Makefile [new file with mode: 0644]
mach/proto/top/Makefile [new file with mode: 0644]
mach/proto/top/queue.c [new file with mode: 0644]
mach/proto/top/queue.h [new file with mode: 0644]
mach/proto/top/top.c [new file with mode: 0644]
mach/proto/top/top.h [new file with mode: 0644]
mach/vax4/top/Makefile [new file with mode: 0644]
mach/vax4/top/table [new file with mode: 0644]

diff --git a/mach/arm/top/Makefile b/mach/arm/top/Makefile
new file mode 100644 (file)
index 0000000..37628d5
--- /dev/null
@@ -0,0 +1,41 @@
+EM=../../..
+PREFLAGS=-I.
+PFLAGS=
+CFLAGS=$(PREFLAGS) $(PFLAGS) -O
+LDFLAGS=-i $(PFLAGS)
+LINTOPTS=-hbxac
+CDIR=$(EM)/mach/proto/top
+CFILES=$(CDIR)/top.c $(CDIR)/queue.c gen.c
+OFILES=top.o queue.o gen.o
+
+all:   gen.c
+       make top
+
+top:   $(OFILES)
+       $(CC) $(LDFLAGS) $(OFILES)  $(LIBS) -o top
+
+top.o: $(CDIR)/top.c
+       $(CC) -c $(CFLAGS) $(CDIR)/top.c
+
+queue.o: $(CDIR)/queue.c
+       $(CC) -c $(CFLAGS) $(CDIR)/queue.c
+
+install: all
+       $(EM)/mach/install top
+
+cmp:    all
+       -$(EM)/mach/compare top
+
+gen.c: table
+       $(EM)/lib/topgen table
+
+lint: $(CFILES)
+       lint $(LINTOPTS) $(PREFLAGS) $(CFILES)
+
+clean:
+       rm -f *.o gen.c gen.h top
+
+top.o:         gen.h
+top.o:         $(CDIR)/top.h
+top.o:         $(CDIR)/queue.h
+queue.o:       $(CDIR)/queue.h
diff --git a/mach/m68020/top/Makefile b/mach/m68020/top/Makefile
new file mode 100644 (file)
index 0000000..37628d5
--- /dev/null
@@ -0,0 +1,41 @@
+EM=../../..
+PREFLAGS=-I.
+PFLAGS=
+CFLAGS=$(PREFLAGS) $(PFLAGS) -O
+LDFLAGS=-i $(PFLAGS)
+LINTOPTS=-hbxac
+CDIR=$(EM)/mach/proto/top
+CFILES=$(CDIR)/top.c $(CDIR)/queue.c gen.c
+OFILES=top.o queue.o gen.o
+
+all:   gen.c
+       make top
+
+top:   $(OFILES)
+       $(CC) $(LDFLAGS) $(OFILES)  $(LIBS) -o top
+
+top.o: $(CDIR)/top.c
+       $(CC) -c $(CFLAGS) $(CDIR)/top.c
+
+queue.o: $(CDIR)/queue.c
+       $(CC) -c $(CFLAGS) $(CDIR)/queue.c
+
+install: all
+       $(EM)/mach/install top
+
+cmp:    all
+       -$(EM)/mach/compare top
+
+gen.c: table
+       $(EM)/lib/topgen table
+
+lint: $(CFILES)
+       lint $(LINTOPTS) $(PREFLAGS) $(CFILES)
+
+clean:
+       rm -f *.o gen.c gen.h top
+
+top.o:         gen.h
+top.o:         $(CDIR)/top.h
+top.o:         $(CDIR)/queue.h
+queue.o:       $(CDIR)/queue.h
diff --git a/mach/m68k2/top/Makefile b/mach/m68k2/top/Makefile
new file mode 100644 (file)
index 0000000..37628d5
--- /dev/null
@@ -0,0 +1,41 @@
+EM=../../..
+PREFLAGS=-I.
+PFLAGS=
+CFLAGS=$(PREFLAGS) $(PFLAGS) -O
+LDFLAGS=-i $(PFLAGS)
+LINTOPTS=-hbxac
+CDIR=$(EM)/mach/proto/top
+CFILES=$(CDIR)/top.c $(CDIR)/queue.c gen.c
+OFILES=top.o queue.o gen.o
+
+all:   gen.c
+       make top
+
+top:   $(OFILES)
+       $(CC) $(LDFLAGS) $(OFILES)  $(LIBS) -o top
+
+top.o: $(CDIR)/top.c
+       $(CC) -c $(CFLAGS) $(CDIR)/top.c
+
+queue.o: $(CDIR)/queue.c
+       $(CC) -c $(CFLAGS) $(CDIR)/queue.c
+
+install: all
+       $(EM)/mach/install top
+
+cmp:    all
+       -$(EM)/mach/compare top
+
+gen.c: table
+       $(EM)/lib/topgen table
+
+lint: $(CFILES)
+       lint $(LINTOPTS) $(PREFLAGS) $(CFILES)
+
+clean:
+       rm -f *.o gen.c gen.h top
+
+top.o:         gen.h
+top.o:         $(CDIR)/top.h
+top.o:         $(CDIR)/queue.h
+queue.o:       $(CDIR)/queue.h
diff --git a/mach/pdp/top/Makefile b/mach/pdp/top/Makefile
new file mode 100644 (file)
index 0000000..37628d5
--- /dev/null
@@ -0,0 +1,41 @@
+EM=../../..
+PREFLAGS=-I.
+PFLAGS=
+CFLAGS=$(PREFLAGS) $(PFLAGS) -O
+LDFLAGS=-i $(PFLAGS)
+LINTOPTS=-hbxac
+CDIR=$(EM)/mach/proto/top
+CFILES=$(CDIR)/top.c $(CDIR)/queue.c gen.c
+OFILES=top.o queue.o gen.o
+
+all:   gen.c
+       make top
+
+top:   $(OFILES)
+       $(CC) $(LDFLAGS) $(OFILES)  $(LIBS) -o top
+
+top.o: $(CDIR)/top.c
+       $(CC) -c $(CFLAGS) $(CDIR)/top.c
+
+queue.o: $(CDIR)/queue.c
+       $(CC) -c $(CFLAGS) $(CDIR)/queue.c
+
+install: all
+       $(EM)/mach/install top
+
+cmp:    all
+       -$(EM)/mach/compare top
+
+gen.c: table
+       $(EM)/lib/topgen table
+
+lint: $(CFILES)
+       lint $(LINTOPTS) $(PREFLAGS) $(CFILES)
+
+clean:
+       rm -f *.o gen.c gen.h top
+
+top.o:         gen.h
+top.o:         $(CDIR)/top.h
+top.o:         $(CDIR)/queue.h
+queue.o:       $(CDIR)/queue.h
diff --git a/mach/proto/top/Makefile b/mach/proto/top/Makefile
new file mode 100644 (file)
index 0000000..37628d5
--- /dev/null
@@ -0,0 +1,41 @@
+EM=../../..
+PREFLAGS=-I.
+PFLAGS=
+CFLAGS=$(PREFLAGS) $(PFLAGS) -O
+LDFLAGS=-i $(PFLAGS)
+LINTOPTS=-hbxac
+CDIR=$(EM)/mach/proto/top
+CFILES=$(CDIR)/top.c $(CDIR)/queue.c gen.c
+OFILES=top.o queue.o gen.o
+
+all:   gen.c
+       make top
+
+top:   $(OFILES)
+       $(CC) $(LDFLAGS) $(OFILES)  $(LIBS) -o top
+
+top.o: $(CDIR)/top.c
+       $(CC) -c $(CFLAGS) $(CDIR)/top.c
+
+queue.o: $(CDIR)/queue.c
+       $(CC) -c $(CFLAGS) $(CDIR)/queue.c
+
+install: all
+       $(EM)/mach/install top
+
+cmp:    all
+       -$(EM)/mach/compare top
+
+gen.c: table
+       $(EM)/lib/topgen table
+
+lint: $(CFILES)
+       lint $(LINTOPTS) $(PREFLAGS) $(CFILES)
+
+clean:
+       rm -f *.o gen.c gen.h top
+
+top.o:         gen.h
+top.o:         $(CDIR)/top.h
+top.o:         $(CDIR)/queue.h
+queue.o:       $(CDIR)/queue.h
diff --git a/mach/proto/top/queue.c b/mach/proto/top/queue.c
new file mode 100644 (file)
index 0000000..3cf1e59
--- /dev/null
@@ -0,0 +1,72 @@
+#include "top.h"
+#include "queue.h"
+
+empty_queue(q)
+       queue q;
+{
+       q->head = q->tail = (instr_p) 0;
+       q->qlen = 0;
+}
+
+int empty(q)
+       queue q;
+{
+       return q->qlen == 0;
+}
+
+remove_head(q)
+       queue q;
+{
+       if ( (q->head = q->head->fw) == (instr_p) 0) {
+               q->tail = (instr_p) 0;
+       } else {
+               q->head->bw = (instr_p) 0;
+       }
+       q->qlen--;
+}
+
+add(q,instr)
+       register queue q;
+       register instr_p instr;
+{
+       if (q->qlen++ == 0) {
+               q->head = q->tail = instr;
+               instr->bw = (instr_p) 0;
+       } else {
+               q->tail->fw = instr;
+               instr->bw = q->tail;
+               q->tail = instr;
+       }
+       instr->fw = (instr_p) 0;
+}
+
+insert(q,instr)
+       queue q;
+       instr_p instr;
+{
+       if (q->qlen++ == 0) {
+               q->head = q->tail = instr;
+               instr->fw = (instr_p) 0;
+       } else {
+               q->head->bw = instr;
+               instr->fw = q->head;
+               q->head = instr;
+       }
+       instr->bw = (instr_p) 0;
+}
+
+join_queues(q1,q2)
+       queue q1,q2;
+{
+       if (q1->qlen > 0) {
+               q2->qlen += q1->qlen;
+               q1->tail->fw = q2->head;
+               if (q2->qlen > 0) {
+                       q2->head->bw = q1->tail;
+               } else {
+                       q2->tail = q1->tail;
+               }
+               q2->head = q1->head;
+               empty_queue(q1);
+       }
+}
diff --git a/mach/proto/top/queue.h b/mach/proto/top/queue.h
new file mode 100644 (file)
index 0000000..d2adebf
--- /dev/null
@@ -0,0 +1,12 @@
+typedef struct item *item_p;
+typedef struct queue_t *queue;
+
+struct queue_t {
+       instr_p head;
+       instr_p tail;
+       int     qlen;
+};
+
+#define qhead(q)       (q)->head
+#define qlength(q)     (q)->qlen
+#define next(x)                (x)->fw
diff --git a/mach/proto/top/top.c b/mach/proto/top/top.c
new file mode 100644 (file)
index 0000000..11ea824
--- /dev/null
@@ -0,0 +1,651 @@
+#include <stdio.h>
+#include "gen.h"
+#include "top.h"
+#include "queue.h"
+
+/* STANDARD MACHINE-INDEPENT C CODE *************/
+
+extern char *lstrip();
+extern instr_p newinstr();
+extern instr_p read_instr();
+extern instr_p gen_instr();
+extern char *eval_templ();
+extern instr_p malloc();
+
+struct variable var[NRVARS+1];
+struct variable ANY;  /* ANY symbol matching any instruction */
+
+char *REST;  /* Opcode of first instruction not matched by current pattern */
+
+#include "gen.c"
+
+
+/* Macros for efficiency: */
+
+#define is_white(c)    ( (c) == ' ' || (c) == '\t')
+
+/* Skip white space in the unprocessed part of instruction 'ip' */
+#define skip_white(ip) while (is_white(*(ip)->rest_line)) (ip)->rest_line++
+
+main()
+{
+       optimize();
+       exit(0);
+}
+
+
+/* Optimize the standard input.
+ * The optimizer uses a moving window. The instructions in the current
+ * window are matched against a set of patterns generated from the
+ * machine description table. If the match fails, the first instruction of
+ * the window is moved to a back-up queue and a new instruction is
+ * read from the input and appended to the end of the window.
+ * If a matching pattern is found (and its operands etc. are ok),
+ * the instructions at the head of the window are replaced by new
+ * instructions, as indicated in the descriptor table; a new window
+ * is created, consisting of the back-up instructions and the new
+ * instructions and the rest of the old window. So effectively the
+ * window moves a bit to the left after every hit. Hence sequences of
+ * optimizations like:
+ *     movl r0,x ; cmpl $0,x  -> movl r0,x ; tstl x -> movl r0,x
+ * are captured without having a separate pattern for "movl ; cmpl".
+ * 
+ * Whenever the backup queue exceeds some threshold, its first instruction
+ * is written to the output and is removed.
+ */
+
+optimize()
+{
+       struct queue_t windowq, backupq;
+       queue window, backup;
+       instr_p ip;
+       bool change;
+
+       window = &windowq;
+       backup = &backupq;
+       empty_queue(window);
+       empty_queue(backup);
+       fill_window(window,MIN_WINDOW_SIZE);
+       while (!empty(window)) {
+               if (try_hashentry(hashtab[hash(window)],window) ||
+                   try_hashentry(hashany,window)) {
+                       join_queues(backup,window);
+               } else {
+                       ip = qhead(window);
+                       remove_head(window);
+                       add(backup,ip);
+                       if (qlength(backup) > MIN_WINDOW_SIZE)  {
+                               write_first(backup);
+                       }
+               }
+               fill_window(window,MIN_WINDOW_SIZE);
+       }
+       while (!empty(backup)) write_first(backup);
+}
+
+
+
+bool try_hashentry(list,window)
+       int *list;
+       queue window;
+{
+       int *pp;
+       patdescr_p p;
+
+       for (pp = list; *pp != -1; pp++) {
+               p = &patterns[*pp];
+               if (check_pattern(p,window) &&
+                   check_operands(p,window) &&
+                   check_constraint(p-patterns)) {
+                       xform(p,window);
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+
+/* TEMP. */
+
+/* int hash(w)
+       queue w;
+{
+       instr_p ip;
+
+       ip = qhead(w);
+       return ip->opc[0] % 31;
+}
+*/
+
+
+int hash(w)
+       queue w;
+{
+       register char *p;
+       register sum,i;
+       instr_p ip;
+
+       ip = qhead(w);
+/*     for (sum=0,p=ip->opc;*p;p++)
+               sum += *p;
+*/
+
+       for (sum=i=0,p=ip->opc;*p;i += 3)
+               sum += (*p++)<<(i&07);
+       return(sum%127);
+}
+
+/* Fill the working window until it contains at least 'len' items.
+ * When end-of-file is encountered it may contain fewer items.
+ */
+
+fill_window(w,len)
+       queue w;
+{
+       instr_p ip;
+
+       while(qlength(w) < len) {
+               if ((ip = read_instr()) == NIL) break;
+               ip->rest_line = ip->line;
+               set_opcode(ip);
+               add(w,ip);
+       }
+}
+
+write_first(w)
+       queue w;
+{
+       instr_p ip;
+
+       write_instr(ip = qhead(w));
+       remove_head(w);
+       oldinstr(ip);
+}
+
+
+/* Try to recognize the opcode part of an instruction */
+
+set_opcode(ip)
+       instr_p ip;
+{
+       register char *p,*q;
+       char *qlim;
+
+       if (ip->state == JUNK) return;
+       skip_white(ip);
+       p = ip->rest_line;
+       if (*p == LABEL_STARTER) {
+               strcpy(ip->opc,"labdef");
+               ip->state = ONLY_OPC;
+               return;
+       }
+       q = ip->opc;
+       qlim = q + MAX_OPC_LEN;
+       while(*p != OPC_TERMINATOR && *p != '\n') {
+               if (q == qlim) {
+                       ip->state = JUNK;
+                       return;
+               }
+               *q++ = *p++;
+       }
+       *q = '\0';
+       ip->rest_line = p;
+       ip->state = (well_shaped(ip->opc) ? ONLY_OPC : JUNK);
+}
+
+
+
+/* Check if pattern 'p' matches the current input */
+
+bool check_pattern(p,w)
+       patdescr_p p;
+       queue w;
+{
+       register idescr_p id_p;
+       idescr_p idlim;
+       register instr_p ip;
+
+       ip = qhead(w);
+       ANY.vstate = UNINSTANTIATED;
+       idlim = &p->pat[p->patlen];
+       for (id_p = p->pat; id_p < idlim; id_p++) {
+               if (ip == NIL || ip->state == JUNK) return FALSE;
+               if (id_p->opcode == (char *) 0) {
+                       unify(ip->opc,&ANY);
+               } else {
+                       if (strcmp(ip->opc,id_p->opcode) != 0) return FALSE;
+               }
+               ip = next(ip);
+       }
+       REST = ip->opc;
+       return TRUE;
+}
+
+
+
+bool check_operands(p,w)
+       patdescr_p p;
+       queue w;
+{
+       instr_p ip;
+       idescr_p id_p;
+       int n;
+
+       /* fprintf(stderr,"try pattern %d\n",p-patterns); */
+       clear_vars();
+       for (id_p = p->pat, ip = qhead(w); id_p < &p->pat[p->patlen];
+                                         id_p++, ip = next(ip)) {
+               assert(ip != NIL);
+               if (ip->state == JUNK ||
+                   (ip->state == ONLY_OPC && !split_operands(ip))) {
+                       return FALSE;
+               }
+               for (n = 0; n < MAXOP; n++) {
+                       if (!opmatch(&id_p->templates[n],ip->op[n])) {
+                               return FALSE;
+                       }
+               }
+       }
+       /* fprintf(stderr,"yes\n"); */
+       return TRUE;
+}
+
+
+
+/* Reset all variables to uninstantiated */
+
+clear_vars()
+{
+       register v;
+
+       for (v = 1; v <= NRVARS; v++) var[v].vstate = UNINSTANTIATED;
+}
+
+
+/* See if operand 's' matches the operand described by template 't'.
+ * As a side effect, any uninstantiated variables used in the
+ * template may become instantiated. For such a variable we also
+ * check if it satisfies the constraint imposed on it in the
+ * mode-definitions part of the table.
+ */
+
+bool opmatch(t,s)
+       templ_p t;
+       char *s;
+{
+       char *l, buf[MAXOPLEN];
+       bool was_instantiated;
+       int vno;
+
+       vno = t->varno;
+       if (vno == -1 || s[0] == '\0' ) {
+               return (vno == -1 && s[0] == '\0');
+       }
+       was_instantiated = (var[vno].vstate == INSTANTIATED);
+       strcpy(buf,s);
+       if ( (l=lstrip(buf,t->lctxt)) != NULLSTRING && rstrip(l,t->rctxt)) {
+               return vno == 0 || (unify(l,&var[vno]) &&
+                       (was_instantiated || tok_chk(vno)));
+       }
+       return FALSE;
+}
+
+
+
+/* Try to recognize the operands of an instruction */
+
+bool split_operands(ip)
+       instr_p ip;
+{
+       int i;
+       bool res;
+
+       if (strcmp(ip->opc,"labdef") ==0) {
+               labeldef(ip);
+       } else {
+               for (i = 0; operand(ip,i) && op_separator(ip); i++);
+       }
+       res = remainder_empty(ip);
+       ip->state = (res ? DONE : JUNK);
+       return res;
+}
+
+
+
+labeldef(ip)
+       instr_p ip;
+{
+       char *p;
+       int oplen;
+
+       p = ip->rest_line;
+       while( *p != LABEL_TERMINATOR) p++;
+       oplen = p - ip->rest_line;
+       if (oplen == 0 || oplen > MAXOPLEN) return;
+       strncpy(ip->op[0],ip->rest_line,oplen);
+       ip->op[0][oplen] = '\0';
+       ip->rest_line = ++p;
+       return;
+}
+
+
+
+
+/* Try to recognize the next operand of instruction 'ip' */
+
+bool operand(ip,n)
+       register instr_p ip;
+{
+       register char *p;
+       int oplen;
+
+       skip_white(ip);
+       p = ip->rest_line;
+       while( *p != OP_SEPARATOR && *p != '\n') p++;
+       oplen = p - ip->rest_line;
+       if (oplen == 0 || oplen > MAXOPLEN) return FALSE;
+       strncpy(ip->op[n],ip->rest_line,oplen);
+       ip->op[n][oplen] = '\0';
+       ip->rest_line = p;
+       return TRUE;
+}
+
+
+
+/* See if the unprocessed part of instruction 'ip' is empty
+ * (or contains only white space).
+ */
+
+bool remainder_empty(ip)
+       instr_p ip;
+{
+       skip_white(ip);
+       return *ip->rest_line == '\n';
+}
+
+
+/* Try to match 'ctxt' at the beginning of string 'str'. If this
+ * succeeds then return a pointer to the rest (unmatched part) of 'str'.
+ */
+
+char *lstrip(str,ctxt)
+       register char *str, *ctxt;
+{
+       assert(ctxt != NULLSTRING);
+       while (*str != '\0' && *str == *ctxt) {
+               str++;
+               ctxt++;
+       }
+       return (*ctxt == '\0' ? str : NULLSTRING);
+}
+
+
+
+/* Try to match 'ctxt' at the end of 'str'. If this succeeds then
+ * replace truncate 'str'.
+ */
+
+bool rstrip(str,ctxt)
+       char *str,*ctxt;
+{
+       register char *s, *c;
+
+       for (s = str; *s != '\0'; s++);
+       for (c = ctxt; *c != '\0'; c++);
+       while (c >= ctxt) {
+               if (s < str || *s != *c--) return FALSE;
+               *s-- = '\0';
+       }
+       return TRUE;
+}
+
+
+
+/* Try to unify variable 'v' with string 'str'. If the variable
+ * was instantiated the unification only succeeds if the variable
+ * and the string match; else the unification succeeds and the
+ * variable becomes instantiated to the string.
+ */
+
+bool unify(str,v)
+       char *str;
+       struct variable *v;
+{
+       if (v->vstate == UNINSTANTIATED) {
+               v->vstate = INSTANTIATED;
+               strcpy(v->value,str);
+               return TRUE;
+       } else {
+               return strcmp(v->value,str) == 0;
+       }
+}
+
+
+
+/* Transform the working window according to pattern 'p' */
+
+xform(p,w)
+       patdescr_p p;
+       queue w;
+{
+       register instr_p ip;
+       int i;
+
+       for (i = 0; i < p->patlen; i++) {
+               ip = qhead(w);
+               remove_head(w);
+               oldinstr(ip);
+       }
+       replacement(p,w);
+}
+
+
+
+/* Generate the replacement for pattern 'p' and insert it
+ * at the front of the working window.
+ * Note that we generate instructions in reverser order.
+ */
+
+replacement(p,w)
+       patdescr_p p;
+       queue w;
+{
+       idescr_p id_p;
+
+       for (id_p = &p->repl[p->replen-1]; id_p >= p->repl; id_p--) {
+               insert(w,gen_instr(id_p));
+       }
+}
+
+
+
+/* Generate an instruction described by 'id_p'.
+ * We build a 'line' for the new instruction and call set_opcode()
+ * to re-recognize its opcode. Hence generated instructions are treated
+ * in exactly the same way as normal instructions that are just read in.
+ */
+
+instr_p gen_instr(id_p)
+       idescr_p id_p;
+{
+       char *opc;
+       instr_p ip;
+       templ_p t;
+       register char *s;
+       bool islabdef;
+       int n;
+       static char tmp[] = "x";
+
+       ip = newinstr();
+       s = ip->line;
+       opc = id_p->opcode;
+       if (opc == (char *) 0) opc = ANY.value;
+       if (strcmp(opc,"labdef") == 0) {
+               islabdef = TRUE;
+               s[0] = '\0';
+       } else {
+               strcpy(s,opc);
+               tmp[0] = OPC_TERMINATOR;
+               strcat(s,tmp);
+               islabdef = FALSE;
+       }
+       for (n = 0; n < MAXOP;) {
+               t = &id_p->templates[n++];
+               if (t->varno == -1) break;
+               strcat(s,t->lctxt);
+               if (t->varno != 0) strcat(s,var[t->varno].value);
+               strcat(s,t->rctxt);
+               if (n<MAXOP && id_p->templates[n].varno!=-1) {
+                       tmp[0] = OP_SEPARATOR;
+                       strcat(s,tmp);
+               }
+       }
+       if (islabdef) {
+               tmp[0] = LABEL_TERMINATOR;
+               strcat(s,tmp);
+       }
+       strcat(s,"\n");
+       ip->rest_line = ip->line;
+       set_opcode(ip);
+       return ip;
+}
+
+
+
+/* Reading and writing instructions.
+ * An instruction is assumed to be on one line. The line
+ * is copied to the 'line' field of an instruction struct,
+ * terminated by a \n and \0. If the line is too long (>MAXLINELEN),
+ * it is split into pieces of length MAXLINELEN and the state of
+ * each such struct is set to JUNK (so it will not be optimized).
+ */
+
+static bool junk_state = FALSE;  /* TRUE while processing a very long line */
+
+instr_p read_instr()
+{
+       register instr_p ip;
+       register int c;
+       register char *p;
+       char *plim;
+
+       ip = newinstr();
+       plim = &ip->line[MAXLINELEN];
+       if (( c = getchar()) == EOF) return NIL;
+       for (p = ip->line; p < plim;) {
+               *p++ = c;
+               if (c == '\n') {
+                       *p = '\0';
+                       if (junk_state) ip->state = JUNK;
+                       junk_state = FALSE;
+                       return ip;
+               }
+               c = getchar();
+       }
+       ungetc(c,stdin);
+       *p = '\0';
+       junk_state = ip->state = JUNK;
+       return ip;
+}
+
+
+write_instr(ip)
+       instr_p ip;
+{
+       register char *p;
+
+       for (p = ip->line; *p != '\0'; p++) {
+               putchar(*p);
+       }
+}
+
+
+
+/* Core allocation.
+ * As all instruction struct have the same size we can re-use every struct.
+ * We maintain a pool of free instruction structs.
+ */
+
+static instr_p instr_pool;
+int nr_mallocs = 0; /* for statistics */
+
+instr_p newinstr()
+{
+       register instr_p ip;
+       int i;
+
+       if (instr_pool == NIL) {
+               instr_pool = malloc(sizeof(struct instruction));
+               nr_mallocs++;
+       }
+       assert(instr_pool != NIL);
+       ip = instr_pool;
+       instr_pool = instr_pool->fw;
+       ip->fw = ip->bw = NIL;
+       ip->rest_line = NULLSTRING;
+       ip->line[0] = ip->opc[0] = '\0';
+       ip->state = ONLY_OPC;
+       for (i = 0; i < MAXOP; i++) ip->op[i][0] = '\0';
+       return ip;
+}
+
+oldinstr(ip)
+       instr_p ip;
+{
+       ip->fw = instr_pool;
+       instr_pool = ip;
+}
+
+
+
+/* Debugging stuff */
+
+badassertion(file,line)
+       char *file;
+       unsigned line; 
+{
+       fprintf(stderr,"assertion failed file %s, line %u\n",file,line);
+       error("assertion");
+}
+
+/* VARARGS1 */
+error(s,a)
+       char *s,*a; 
+{
+       fprintf(stderr,s,a);
+       fprintf(stderr,"\n");
+       _cleanup();
+       abort();
+       exit(-1);
+}
+
+/* Low level routines */
+
+bool op_separator(ip)
+       instr_p ip;
+{
+       skip_white(ip);
+       if (*(ip->rest_line) == OP_SEPARATOR) {
+               ip->rest_line++;
+               return TRUE;
+       } else {
+               return FALSE;
+       }
+}
+
+
+
+bool well_shaped(opc)
+       char *opc;
+{
+       return is_letter(opc[0]);
+}
+
+
+bool is_letter(c)
+{
+       return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+}
+
+/* is_white(c) : turned into a macro, see beginning of file */
+
diff --git a/mach/proto/top/top.h b/mach/proto/top/top.h
new file mode 100644 (file)
index 0000000..899b7fe
--- /dev/null
@@ -0,0 +1,88 @@
+/* Tunable constants; may be overruled by machine descriptor table */
+
+#ifndef OP_SEPARATOR
+#define OP_SEPARATOR ','
+#endif
+#ifndef LABEL_TERMINATOR
+#define LABEL_TERMINATOR       ':'
+#endif
+#ifndef LABEL_STARTER
+#define LABEL_STARTER  'I'
+#endif
+#ifndef OPC_TERMINATOR
+#define OPC_TERMINATOR ' '
+#endif
+
+#ifndef MAX_OPC_LEN
+#define MAX_OPC_LEN    10
+#endif
+#ifndef MAXOPLEN
+#define MAXOPLEN       25
+#endif
+#ifndef MAXOP
+#define MAXOP          2
+#endif
+#ifndef MAXLINELEN
+#define MAXLINELEN     100
+#endif
+#ifndef MAXVARLEN
+#define MAXVARLEN      25
+#endif
+
+
+typedef struct instruction *instr_p;
+typedef struct pattern_descr *patdescr_p;
+typedef struct instr_descr *idescr_p;
+typedef struct template *templ_p;
+
+struct instruction {
+       instr_p fw;
+       instr_p bw;
+       char    line[MAXLINELEN+1];
+       char    *rest_line;
+       char    opc[MAX_OPC_LEN+1];
+       char    op[MAXOP][MAXOPLEN+1];
+       short   state;
+};
+
+/* state: */
+#define        ONLY_OPC        0
+#define JUNK           1
+#define        DONE            2
+
+struct variable {
+       int     vstate;
+       char    value[MAXVARLEN];
+};
+
+/* vstate: */
+#define UNINSTANTIATED 0
+#define INSTANTIATED   1
+
+struct pattern_descr {
+       int     patlen;
+       idescr_p pat;
+       int     replen;
+       idescr_p repl;
+};
+
+struct template {
+       char    *lctxt;
+       int     varno;
+       char    *rctxt;
+};
+
+struct instr_descr {
+       char            *opcode;
+       struct template templates[MAXOP];
+};
+
+typedef int bool;
+
+#define TRUE   1
+#define FALSE  0
+
+#define NIL (instr_p) 0
+#define NULLSTRING (char *) 0
+
+#define assert(x) if(!(x)) badassertion(__FILE__,__LINE__)
diff --git a/mach/vax4/top/Makefile b/mach/vax4/top/Makefile
new file mode 100644 (file)
index 0000000..37628d5
--- /dev/null
@@ -0,0 +1,41 @@
+EM=../../..
+PREFLAGS=-I.
+PFLAGS=
+CFLAGS=$(PREFLAGS) $(PFLAGS) -O
+LDFLAGS=-i $(PFLAGS)
+LINTOPTS=-hbxac
+CDIR=$(EM)/mach/proto/top
+CFILES=$(CDIR)/top.c $(CDIR)/queue.c gen.c
+OFILES=top.o queue.o gen.o
+
+all:   gen.c
+       make top
+
+top:   $(OFILES)
+       $(CC) $(LDFLAGS) $(OFILES)  $(LIBS) -o top
+
+top.o: $(CDIR)/top.c
+       $(CC) -c $(CFLAGS) $(CDIR)/top.c
+
+queue.o: $(CDIR)/queue.c
+       $(CC) -c $(CFLAGS) $(CDIR)/queue.c
+
+install: all
+       $(EM)/mach/install top
+
+cmp:    all
+       -$(EM)/mach/compare top
+
+gen.c: table
+       $(EM)/lib/topgen table
+
+lint: $(CFILES)
+       lint $(LINTOPTS) $(PREFLAGS) $(CFILES)
+
+clean:
+       rm -f *.o gen.c gen.h top
+
+top.o:         gen.h
+top.o:         $(CDIR)/top.h
+top.o:         $(CDIR)/queue.h
+queue.o:       $(CDIR)/queue.h
diff --git a/mach/vax4/top/table b/mach/vax4/top/table
new file mode 100644 (file)
index 0000000..ea754dd
--- /dev/null
@@ -0,0 +1,287 @@
+/* VAX descriptor table for ACK target optimizer,
+ * Prolog prototype
+ */
+
+/* tunable constants-> */
+
+MAXOP                  4;
+MAXLINELEN             50;
+LABEL_STARTER          'L';
+OPC_TERMINATOR         '       ';
+
+%%;
+
+ZERO           {strcmp(VAL,"$0") == 0};
+ONE            {strcmp(VAL,"$1") == 0};
+M_ONE          {strcmp(VAL,"$-1") == 0};
+CONST          {VAL[0] == '$'};
+NUM,NUM1       {is_number(VAL)};
+REG            {is_register(VAL)};
+SREG           {is_scratchreg(VAL)};
+LAB,LAB2       {VAL[0] == 'L'};
+A,B            {no_side_effects(VAL) };
+X,Y,LOG                {TRUE};
+
+%%;
+
+movab 1(X),X                   ->      incl X;
+movab -1(X),X                  ->      decl X;
+
+movzbw ZERO,X                  ->      clrw X;
+movzbl ZERO,X                  ->      clrl X;
+movb ZERO,X                    ->      clrb X;
+movw ZERO,X                    ->      clrw X;
+movl ZERO,X                    ->      clrl X;
+cvtbw ZERO,X                   ->      clrw X;
+cvtww ZERO,X                   ->      clrw X;
+cvtbl ZERO,X                   ->      clrl X;
+cvtwl ZERO,X                   ->      clrl X;
+
+/* change 3-operand instructions to 2-operand instructions */
+
+addw3 X,Y,Y                    ->      addw2 X,Y;
+addl3 X,Y,Y                    ->      addl2 X,Y;
+addf3 X,Y,Y                    ->      addf2 X,Y;
+addd3 X,Y,Y                    ->      addd2 X,Y;
+
+addw3 X,Y,X                    ->      addw2 Y,X;
+addl3 X,Y,X                    ->      addl2 Y,X;
+addf3 X,Y,X                    ->      addf2 Y,X;
+addd3 X,Y,X                    ->      addd2 Y,X;
+
+subw3 X,Y,Y                    ->      subw2 X,Y;
+subl3 X,Y,Y                    ->      subl2 X,Y;
+subf3 X,Y,Y                    ->      subf2 X,Y;
+subd3 X,Y,Y                    ->      subd2 X,Y;
+
+mulw3 X,Y,Y                    ->      mulw2 X,Y;
+mull3 X,Y,Y                    ->      mull2 X,Y;
+mulf3 X,Y,Y                    ->      mulf2 X,Y;
+muld3 X,Y,Y                    ->      muld2 X,Y;
+
+mulw3 X,Y,X                    ->      mulw2 Y,X;
+mull3 X,Y,X                    ->      mull2 Y,X;
+mulf3 X,Y,X                    ->      mulf2 Y,X;
+muld3 X,Y,X                    ->      muld2 Y,X;
+
+divw3 X,Y,Y                    ->      divw2 X,Y;
+divl3 X,Y,Y                    ->      divl2 X,Y;
+divf3 X,Y,Y                    ->      divf2 X,Y;
+divd3 X,Y,Y                    ->      divd2 X,Y;
+
+xorw3 X,Y,Y                    ->      xorw2 X,Y;
+xorl3 X,Y,Y                    ->      xorl2 X,Y;
+
+bisw3 X,Y,Y                    ->      bisw2 X,Y;
+bisl3 X,Y,Y                    ->      bisl2 X,Y;
+bisw3 X,Y,X                    ->      bisw2 Y,X;
+bisl3 X,Y,X                    ->      bisl2 Y,X;
+
+bicw3 X,Y,Y                    ->      bicw2 X,Y;
+bicl3 X,Y,Y                    ->      bicl2 X,Y;
+
+/* eliminate negative constants */
+
+addw2 $-NUM,X                  ->      subw2 $NUM,X;
+addl2 $-NUM,X                  ->      subl2 $NUM,X;
+addw3 $-NUM,X,Y                        ->      subw3 $NUM,X,Y;
+addl3 $-NUM,X,Y                        ->      subl3 $NUM,X,Y;
+addw3 X,$-NUM,Y                        ->      subw3 $NUM,X,Y;
+addl3 X,$-NUM,Y                        ->      subl3 $NUM,X,Y;
+
+subw2 $-NUM,X                  ->      addw2 $NUM,X;
+subl2 $-NUM,X                  ->      addl2 $NUM,X;
+subw3 $-NUM,X,Y                        ->      addw3 $NUM,X,Y;
+subl3 $-NUM,X,Y                        ->      addl3 $NUM,X,Y;
+subw3 X,$-NUM,Y                        ->      addw3 $NUM,X,Y;
+subl3 X,$-NUM,Y                        ->      addl3 $NUM,X,Y;
+
+/* use special instructions */
+
+addw2 ONE,X                    ->      incw X;
+addl2 ONE,X                    ->      incl X;
+subw2 ONE,X                    ->      decw X;
+subl2 ONE,X                    ->      decl X;
+
+addw2 M_ONE,X                  ->      decw X;
+addl2 M_ONE,X                  ->      decl X;
+subw2 M_ONE,X                  ->      incw X;
+subl2 M_ONE,X                  ->      incl X;
+
+bitw $NUM,A : jneq LAB
+       {is_poweroftwo(NUM,LOG)}->      jbs $LOG,A,LAB;
+bitl $NUM,A : jneq LAB
+       {is_poweroftwo(NUM,LOG)}->      jbs $LOG,A,LAB;
+bitw $NUM,A : jeql LAB
+       {is_poweroftwo(NUM,LOG)}->      jbc $LOG,A,LAB;
+bitl $NUM,A : jeql LAB
+       {is_poweroftwo(NUM,LOG)}->      jbc $LOG,A,LAB;
+bitw ONE,A : jneq LAB          ->      jlbs A,LAB;
+bitl ONE,A : jneq LAB          ->      jlbs A,LAB;
+bitw ONE,A : jneq LAB          ->      jlbc A,LAB;
+bitl ONE,A : jneq LAB          ->      jlbc A,LAB;
+ashl $-NUM,A,REG : bicw2 $~NUM1,REG
+       {is_p2m1(NUM1,LOG)}     ->      extzv $NUM,$LOG,A,REG;
+ashl $-NUM,A,REG : bicl2 $~NUM1,REG
+       {is_p2m1(NUM1,LOG)}     ->      extzv $NUM,$LOG,A,REG;
+
+/* stack optimizations */
+
+movl (sp)+,X : pushl X         ->      movl (sp),X;
+tstw (sp)+ : movw X,-(sp)      ->      movw X,(sp);
+tstl (sp)+ : movl X,-(sp)      ->      movl X,(sp);
+tstw (sp)+ : clrw -(sp)                ->      clrw (sp);
+tstl (sp)+ : clrl -(sp)                ->      clrl (sp);
+tstw (sp)+ : movzbw X,-(sp)    ->      movzbw X,(sp);
+tstl (sp)+ : movzbl X,-(sp)    ->      movzbl X,(sp);
+tstw (sp)+ : cvtbw X,-(sp)     ->      cvtbw X,(sp);
+tstl (sp)+ : cvtbl X,-(sp)     ->      cvtbl X,(sp);
+tstw (sp)+ : tstw X            ->      movw X,(sp)+;
+tstl (sp)+ : tstl X            ->      movl X,(sp)+;
+tstl (sp)+ : pushl X           ->      movl X,(sp);
+tstl (sp)+ : pushab X          ->      movab X,(sp);
+tstl (sp)+ : pushaw X          ->      movaw X,(sp);
+tstl (sp)+ : pushal X          ->      moval X,(sp);
+tstl (sp)+ : pushaq X          ->      movaq X,(sp);
+
+/* push constants */
+
+clrw -(sp) : movw $NUM,-(sp)   ->      pushl $NUM;
+clrw -(sp) : mnegw $NUM, -(sp) ->      movzwl $-NUM,-(sp);
+clrw -(sp) : movw X,-(sp)      ->      movzwl X,-(sp);
+clrw -(sp) : cvtbw $NUM,-(sp)  ->      pushl $NUM;
+clrw -(sp) : cvtbw CONST,-(sp) ->      movzwl CONST,-(sp);
+
+/* compare with zero */
+
+cmpb X,ZERO                    ->      tstb X;
+cmpw X,ZERO                    ->      tstw X;
+cmpl X,ZERO                    ->      tstl X;
+cmpb ZERO,X : jneq LAB         ->      tstb X: jneq LAB;
+cmpw ZERO,X : jneq LAB         ->      tstw X: jneq LAB;
+cmpl ZERO,X : jneq LAB         ->      tstl X: jneq LAB;
+
+cmpb ZERO,X : jeql LAB         ->      tstb X: jeql LAB;
+cmpw ZERO,X : jeql LAB         ->      tstw X: jeql LAB;
+cmpl ZERO,X : jeql LAB         ->      tstl X: jeql LAB;
+
+cmpb ZERO,X : jgtr LAB         ->      tstb X: jlss LAB;
+cmpw ZERO,X : jgtr LAB         ->      tstw X: jlss LAB;
+cmpl ZERO,X : jgtr LAB         ->      tstl X: jlss LAB;
+
+cmpb ZERO,X : jlss LAB         ->      tstb X: jgtr LAB;
+cmpw ZERO,X : jlss LAB         ->      tstw X: jgtr LAB;
+cmpl ZERO,X : jlss LAB         ->      tstl X: jgtr LAB;
+
+cmpb ZERO,X : jgeq LAB         ->      tstb X: jleq LAB;
+cmpw ZERO,X : jgeq LAB         ->      tstw X: jleq LAB;
+cmpl ZERO,X : jgeq LAB         ->      tstl X: jleq LAB;
+
+cmpb ZERO,X : jleq LAB         ->      tstb X: jgeq LAB;
+cmpw ZERO,X : jleq LAB         ->      tstw X: jgeq LAB;
+cmpl ZERO,X : jleq LAB         ->      tstl X: jgeq LAB;
+
+/* compare with -1 */
+
+cmpw M_ONE,SREG : jeql LAB     ->      incw SREG : jeql LAB;
+cmpl M_ONE,SREG : jeql LAB     ->      incl SREG : jeql LAB;
+cmpw M_ONE,SREG : jneq LAB     ->      incw SREG : jneq LAB;
+cmpl M_ONE,SREG : jneq LAB     ->      incl SREG : jneq LAB;
+
+/* eliminate redundant tests */
+
+movw X,A : tstw A              ->      movw X,A;
+movl X,A : tstl A              ->      movl X,A;
+movw A,X : tstw A              ->      movw A,X;
+movl A,X : tstl A              ->      movl A,X;
+
+/* skip over jumps */
+
+jeql LAB : jbr LAB2 : labdef LAB ->    jneq LAB2 : labdef LAB;
+jgeq LAB : jbr LAB2 : labdef LAB ->    jlss LAB2 : labdef LAB;
+jgtr LAB : jbr LAB2 : labdef LAB ->    jleq LAB2 : labdef LAB;
+jlss LAB : jbr LAB2 : labdef LAB ->    jgeq LAB2 : labdef LAB;
+jleq LAB : jbr LAB2 : labdef LAB ->    jgtr LAB2 : labdef LAB;
+jneq LAB : jbr LAB2 : labdef LAB ->    jeql LAB2 : labdef LAB;
+
+/* Register propagation */
+
+movl REG,A : ANY *A            ->      movl REG,A : ANY *REG;
+movl REG,A : ANY *A,X          ->      movl REG,A : ANY *REG,X;
+movl REG,A : ANY X,*A          ->      movl REG,A : ANY X,*REG;
+movl REG,A : ANY *A,X,Y                ->      movl REG,A : ANY *REG,X,Y;
+movl REG,A : ANY X,*A,Y                ->      movl REG,A : ANY X,*REG,Y;
+movl REG,A : ANY X,Y,*A                ->      movl REG,A : ANY X,Y,*REG;
+
+
+%%;
+
+/* Auxiliary routines: */
+
+int is_number(s)
+       register char *s;
+{
+       while (*s >= '0' && *s <= '9') s++;
+       return *s == '\0';
+}
+
+int is_poweroftwo(s,t)
+       char *s,*t;
+{
+       long    arg, pow;
+       register int i;
+
+       arg = atol(s);
+       pow = 1;
+       i = 0;
+       while (pow > 0) {
+               if (pow == arg) {
+                       sprintf(t,"%d",i);
+                       return 1;
+               }
+               pow <<= 1;
+               i++;
+       }
+       return 0;
+}
+
+int is_p2m1(s,t)
+       char *s,*t;
+{
+       long arg;
+       char buf[MAXLINELEN];
+
+       arg = atol(s)+1;
+       sprintf(buf,"%ld",arg);
+       return is_poweroftwo(buf,t);
+}
+
+int no_side_effects(s)
+       register char *s;
+{
+
+       for(;;) {
+               switch(*s++) {
+                       case '\0': return TRUE;
+                       case '-':  if (*s == '(') return FALSE; break;
+                       case ')':  if (*s == '+') return FALSE; break;
+               }
+       }
+       /* NOTREACHED */
+}
+
+int is_register(s)
+       register char *s;
+{
+       if (*s++ == 'r' && *s >= '0' && *s <= '9') {
+               if (*s++ == '1' && (*s == '0' || *s == '1')) s++;
+               return *s == '\0';
+       }
+       return FALSE;
+}
+
+int is_scratchreg(s)
+       register char *s;
+{
+       return *s++ == 'r' && *s >= '0' && *s++ <= '3' && *s == '\0';
+}