Initial revision
This commit is contained in:
parent
3b2d51a96b
commit
5ced6d6aef
11 changed files with 1356 additions and 0 deletions
41
mach/arm/top/Makefile
Normal file
41
mach/arm/top/Makefile
Normal file
|
@ -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
|
41
mach/m68020/top/Makefile
Normal file
41
mach/m68020/top/Makefile
Normal file
|
@ -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
|
41
mach/m68k2/top/Makefile
Normal file
41
mach/m68k2/top/Makefile
Normal file
|
@ -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
|
41
mach/pdp/top/Makefile
Normal file
41
mach/pdp/top/Makefile
Normal file
|
@ -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
|
41
mach/proto/top/Makefile
Normal file
41
mach/proto/top/Makefile
Normal file
|
@ -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
|
72
mach/proto/top/queue.c
Normal file
72
mach/proto/top/queue.c
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
12
mach/proto/top/queue.h
Normal file
12
mach/proto/top/queue.h
Normal file
|
@ -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
|
651
mach/proto/top/top.c
Normal file
651
mach/proto/top/top.c
Normal file
|
@ -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 */
|
||||
|
88
mach/proto/top/top.h
Normal file
88
mach/proto/top/top.h
Normal file
|
@ -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__)
|
41
mach/vax4/top/Makefile
Normal file
41
mach/vax4/top/Makefile
Normal file
|
@ -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
|
287
mach/vax4/top/table
Normal file
287
mach/vax4/top/table
Normal file
|
@ -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';
|
||||
}
|
Loading…
Reference in a new issue