--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+#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);
+ }
+}
--- /dev/null
+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
--- /dev/null
+#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 */
+
--- /dev/null
+/* 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__)
--- /dev/null
+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
--- /dev/null
+/* 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';
+}