fixup commit for tag 'distr2'
This commit is contained in:
@@ -1,23 +0,0 @@
|
||||
Makefile
|
||||
ack.h
|
||||
data.c
|
||||
data.h
|
||||
dmach.c
|
||||
dmach.h
|
||||
files.c
|
||||
grows.c
|
||||
grows.h
|
||||
intable.c
|
||||
list.c
|
||||
list.h
|
||||
main.c
|
||||
malloc.c
|
||||
mktables.c
|
||||
pc
|
||||
rmach.c
|
||||
run.c
|
||||
scan.c
|
||||
svars.c
|
||||
trans.c
|
||||
trans.h
|
||||
util.c
|
||||
@@ -1,2 +0,0 @@
|
||||
Makefile
|
||||
em_pc.c
|
||||
@@ -1,19 +0,0 @@
|
||||
# @(#)Makefile 1.1
|
||||
EM = ../..
|
||||
h = $(EM)/h
|
||||
CFLAGS = -n -O -I$h
|
||||
ALL = anm asize astrip
|
||||
OFILES = anm.o asize.o astrip.o
|
||||
CFILES = anm.c asize.c astrip.c
|
||||
|
||||
all: $(ALL)
|
||||
|
||||
cp cmp: all
|
||||
for i in $(ALL); do $@ $$i $$ROOT/usr/bin/$$i; done
|
||||
|
||||
clean: ; rm -f $(ALL) $(OFILES)
|
||||
get: ; getall
|
||||
unget: ; ungetall
|
||||
|
||||
print: $(CFILES)
|
||||
pr -n Makefile $(CFILES) | lpr
|
||||
310
util/amisc/anm.c
310
util/amisc/anm.c
@@ -1,310 +0,0 @@
|
||||
#define DUK /* Modifications by Duk Bekema. */
|
||||
|
||||
/* @(#)anm.c 1.4 */
|
||||
/* $Header$ */
|
||||
/*
|
||||
** print symbol tables for
|
||||
** ACK object files
|
||||
**
|
||||
** anm [-gopruns] [name ...]
|
||||
*/
|
||||
#define ushort unsigned short
|
||||
|
||||
#include "out.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int numsort_flg;
|
||||
int sectsort_flg;
|
||||
int undef_flg;
|
||||
int revsort_flg = 1;
|
||||
int globl_flg;
|
||||
int nosort_flg;
|
||||
int arch_flg;
|
||||
int prep_flg;
|
||||
struct outhead hbuf;
|
||||
struct outsect sbuf;
|
||||
FILE *fi;
|
||||
long off;
|
||||
char *malloc();
|
||||
char *realloc();
|
||||
long s_base[S_MAX]; /* for specially encoded bases */
|
||||
|
||||
main(argc, argv)
|
||||
char **argv;
|
||||
{
|
||||
int narg;
|
||||
int compare();
|
||||
|
||||
if (--argc>0 && argv[1][0]=='-' && argv[1][1]!=0) {
|
||||
argv++;
|
||||
while (*++*argv) switch (**argv) {
|
||||
case 'n': /* sort numerically */
|
||||
numsort_flg++;
|
||||
continue;
|
||||
|
||||
case 's': /* sort in section order */
|
||||
sectsort_flg++;
|
||||
continue;
|
||||
|
||||
case 'g': /* globl symbols only */
|
||||
globl_flg++;
|
||||
continue;
|
||||
|
||||
case 'u': /* undefined symbols only */
|
||||
undef_flg++;
|
||||
continue;
|
||||
|
||||
case 'r': /* sort in reverse order */
|
||||
revsort_flg = -1;
|
||||
continue;
|
||||
|
||||
case 'p': /* don't sort -- symbol table order */
|
||||
nosort_flg++;
|
||||
continue;
|
||||
|
||||
case 'o': /* prepend a name to each line */
|
||||
prep_flg++;
|
||||
continue;
|
||||
|
||||
default: /* oops */
|
||||
fprintf(stderr, "anm: invalid argument -%c\n", *argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
argc--;
|
||||
}
|
||||
if (argc == 0) {
|
||||
argc = 1;
|
||||
argv[1] = "a.out";
|
||||
}
|
||||
narg = argc;
|
||||
|
||||
while(argc--) {
|
||||
struct outname *nbufp = NULL;
|
||||
struct outname nbuf;
|
||||
char *cbufp;
|
||||
long fi_to_co;
|
||||
long n;
|
||||
unsigned readcount;
|
||||
int i,j;
|
||||
|
||||
fi = fopen(*++argv,"r");
|
||||
if (fi == NULL) {
|
||||
fprintf(stderr, "anm: cannot open %s\n", *argv);
|
||||
continue;
|
||||
}
|
||||
|
||||
getofmt((char *)&hbuf, SF_HEAD, fi);
|
||||
if (BADMAGIC(hbuf)) {
|
||||
fprintf(stderr, "anm: %s-- bad format\n", *argv);
|
||||
fclose(fi);
|
||||
continue;
|
||||
}
|
||||
if (narg > 1)
|
||||
printf("\n%s:\n", *argv);
|
||||
|
||||
n = hbuf.oh_nname;
|
||||
if (n == 0) {
|
||||
fprintf(stderr, "anm: %s-- no name list\n", *argv);
|
||||
fclose(fi);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hbuf.oh_nchar == 0) {
|
||||
fprintf(stderr, "anm: %s-- no names\n", *argv);
|
||||
fclose(fi);
|
||||
continue;
|
||||
}
|
||||
if ((readcount = hbuf.oh_nchar) != hbuf.oh_nchar) {
|
||||
fprintf(stderr, "anm: string area too big in %s\n", *argv);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* store special section bases */
|
||||
if (hbuf.oh_flags & HF_8086) {
|
||||
for (i=0; i<hbuf.oh_nsect; i++) {
|
||||
getofmt((char *)&sbuf, SF_SECT, fi);
|
||||
s_base[i+S_MIN] =
|
||||
(sbuf.os_base>>12) & 03777760;
|
||||
}
|
||||
}
|
||||
|
||||
if ((cbufp = (char *)malloc(readcount)) == NULL) {
|
||||
fprintf(stderr, "anm: out of memory on %s\n", *argv);
|
||||
exit(2);
|
||||
}
|
||||
fseek(fi, OFF_CHAR(hbuf), 0);
|
||||
if (fread(cbufp, 1, readcount, fi) == 0) {
|
||||
fprintf(stderr, "anm: read error on %s\n", *argv);
|
||||
exit(2);
|
||||
}
|
||||
fi_to_co = cbufp - OFF_CHAR(hbuf);
|
||||
|
||||
fseek(fi, OFF_NAME(hbuf), 0);
|
||||
i = 0;
|
||||
while (--n >= 0) {
|
||||
getofmt((char *)&nbuf, SF_NAME, fi);
|
||||
|
||||
if (nbuf.on_foff == 0)
|
||||
continue; /* skip entries without names */
|
||||
|
||||
if (globl_flg && (nbuf.on_type&S_EXT)==0)
|
||||
continue;
|
||||
|
||||
if (undef_flg
|
||||
&&
|
||||
((nbuf.on_type&S_TYP)!=S_UND || (nbuf.on_type&S_ETC)!=0))
|
||||
continue;
|
||||
|
||||
nbuf.on_mptr = nbuf.on_foff + fi_to_co;
|
||||
|
||||
/* adjust value for specially encoded bases */
|
||||
if (hbuf.oh_flags & HF_8086) {
|
||||
if (((nbuf.on_type&S_ETC) == 0) ||
|
||||
((nbuf.on_type&S_ETC) == S_SCT)) {
|
||||
j = nbuf.on_type&S_TYP;
|
||||
if ((j>=S_MIN) && (j<=S_MAX))
|
||||
nbuf.on_valu += s_base[j];
|
||||
}
|
||||
}
|
||||
|
||||
if (nbufp == NULL)
|
||||
nbufp = (struct outname *)malloc(sizeof(struct outname));
|
||||
else
|
||||
nbufp = (struct outname *)realloc(nbufp, (i+1)*sizeof(struct outname));
|
||||
if (nbufp == NULL) {
|
||||
fprintf(stderr, "anm: out of memory on %s\n", *argv);
|
||||
exit(2);
|
||||
}
|
||||
nbufp[i++] = nbuf;
|
||||
}
|
||||
|
||||
if (nosort_flg==0)
|
||||
qsort(nbufp, i, sizeof(struct outname), compare);
|
||||
|
||||
for (n=0; n<i; n++) {
|
||||
char cs1[4];
|
||||
char cs2[4];
|
||||
|
||||
if (prep_flg)
|
||||
printf("%s:", *argv);
|
||||
|
||||
switch(nbufp[n].on_type&S_ETC) {
|
||||
case S_SCT:
|
||||
sprintf(cs1, "%2d", (nbufp[n].on_type&S_TYP) - S_MIN);
|
||||
sprintf(cs2, " S");
|
||||
break;
|
||||
case S_FIL:
|
||||
sprintf(cs1, " -");
|
||||
sprintf(cs2, " F");
|
||||
break;
|
||||
case S_MOD:
|
||||
sprintf(cs1, " -");
|
||||
sprintf(cs2, " M");
|
||||
break;
|
||||
case 0:
|
||||
if (nbufp[n].on_type&S_EXT)
|
||||
sprintf(cs2, " E");
|
||||
else
|
||||
sprintf(cs2, " -");
|
||||
|
||||
switch(nbufp[n].on_type&S_TYP) {
|
||||
case S_UND:
|
||||
sprintf(cs1, " U");
|
||||
break;
|
||||
case S_ABS:
|
||||
sprintf(cs1, " A");
|
||||
break;
|
||||
default:
|
||||
sprintf(cs1, "%2d", (nbufp[n].on_type&S_TYP) - S_MIN);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("%8lx %s %s %s\n",nbufp[n].on_valu,cs1,cs2,nbufp[n].on_mptr);
|
||||
}
|
||||
|
||||
if (nbufp)
|
||||
free((char *)nbufp);
|
||||
if (cbufp)
|
||||
free((char *)cbufp);
|
||||
fclose(fi);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
compare(p1, p2)
|
||||
struct outname *p1, *p2;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (sectsort_flg) {
|
||||
if ((p1->on_type&S_TYP) > (p2->on_type&S_TYP))
|
||||
return(revsort_flg);
|
||||
if ((p1->on_type&S_TYP) < (p2->on_type&S_TYP))
|
||||
return(-revsort_flg);
|
||||
}
|
||||
|
||||
if (numsort_flg) {
|
||||
if (p1->on_valu > p2->on_valu)
|
||||
return(revsort_flg);
|
||||
if (p1->on_valu < p2->on_valu)
|
||||
return(-revsort_flg);
|
||||
}
|
||||
|
||||
i = strcmp(p1->on_mptr, p2->on_mptr);
|
||||
|
||||
if (i > 0)
|
||||
return(revsort_flg);
|
||||
if (i < 0)
|
||||
return(-revsort_flg);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
getofmt(p, s, f)
|
||||
register char *p;
|
||||
register char *s;
|
||||
register FILE *f;
|
||||
{
|
||||
register i;
|
||||
register long l;
|
||||
|
||||
for (;;) {
|
||||
switch (*s++) {
|
||||
/* case '0': p++; continue; */
|
||||
case '1':
|
||||
*p++ = getc(f);
|
||||
continue;
|
||||
case '2':
|
||||
i = getc(f);
|
||||
i |= (getc(f) << 8);
|
||||
#ifndef DUK
|
||||
*((short *)p)++ = i;
|
||||
#else DUK
|
||||
*((short *)p) = i;
|
||||
p += sizeof(short);
|
||||
#endif DUK
|
||||
continue;
|
||||
case '4':
|
||||
l = (long)getc(f);
|
||||
l |= ((long)getc(f) << 8);
|
||||
l |= ((long)getc(f) << 16);
|
||||
l |= ((long)getc(f) << 24);
|
||||
#ifndef DUK
|
||||
*((long *)p)++ = l;
|
||||
#else DUK
|
||||
*((long *)p) = l;
|
||||
p += sizeof(long);
|
||||
#endif DUK
|
||||
continue;
|
||||
default:
|
||||
case '\0':
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
#define DUK /* Modifications by Duk Bekema. */
|
||||
|
||||
/* @(#)asize.c 1.2 */
|
||||
/* $Header$ */
|
||||
#define ushort unsigned short
|
||||
|
||||
#include <stdio.h>
|
||||
#include "out.h"
|
||||
|
||||
/*
|
||||
asize -- determine object size
|
||||
|
||||
*/
|
||||
|
||||
main(argc, argv)
|
||||
char **argv;
|
||||
{
|
||||
struct outhead buf;
|
||||
struct outsect sbuf;
|
||||
ushort nrsect;
|
||||
long sum;
|
||||
int gorp;
|
||||
FILE *f;
|
||||
|
||||
if (--argc == 0) {
|
||||
argc = 1;
|
||||
argv[1] = "a.out";
|
||||
}
|
||||
gorp = argc;
|
||||
|
||||
while(argc--) {
|
||||
if ((f = fopen(*++argv, "r"))==NULL) {
|
||||
fprintf(stderr, "asize: cannot open %s\n", *argv);
|
||||
continue;
|
||||
}
|
||||
getofmt ((char *)&buf, SF_HEAD , f);
|
||||
if(BADMAGIC(buf)) {
|
||||
fprintf(stderr, "asize: %s-- bad format\n", *argv);
|
||||
fclose(f);
|
||||
continue;
|
||||
}
|
||||
nrsect = buf.oh_nsect;
|
||||
if (nrsect == 0) {
|
||||
fprintf(stderr, "asize: %s-- no sections\n", *argv);
|
||||
fclose(f);
|
||||
continue;
|
||||
}
|
||||
if (gorp > 1)
|
||||
printf("%s: ", *argv);
|
||||
|
||||
sum = 0;
|
||||
while (nrsect-- > 0) {
|
||||
getofmt ((char *)&sbuf, SF_SECT , f);
|
||||
printf("%ld", sbuf.os_size);
|
||||
sum += sbuf.os_size;
|
||||
if (nrsect > 0)
|
||||
putchar('+');
|
||||
}
|
||||
printf(" = %ld = 0x%lx\n", sum, sum);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
getofmt(p, s, f)
|
||||
register char *p;
|
||||
register char *s;
|
||||
register FILE *f;
|
||||
{
|
||||
register i;
|
||||
register long l;
|
||||
|
||||
for (;;) {
|
||||
switch (*s++) {
|
||||
/* case '0': p++; continue; */
|
||||
case '1':
|
||||
*p++ = getc(f);
|
||||
continue;
|
||||
case '2':
|
||||
i = getc(f);
|
||||
i |= (getc(f) << 8);
|
||||
#ifndef DUK
|
||||
*((short *)p)++ = i;
|
||||
#else DUK
|
||||
*((short *)p) = i;
|
||||
p += sizeof(short);
|
||||
#endif DUK
|
||||
continue;
|
||||
case '4':
|
||||
l = (long)getc(f);
|
||||
l |= (long)(getc(f) << 8);
|
||||
l |= ((long)getc(f) << 16);
|
||||
l |= ((long)getc(f) << 24);
|
||||
#ifndef DUK
|
||||
*((long *)p)++ = l;
|
||||
#else DUK
|
||||
*((long *)p) = l;
|
||||
p += sizeof(long);
|
||||
#endif DUK
|
||||
continue;
|
||||
default:
|
||||
case '\0':
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
#define DUK /* Modifications by Duk Bekema. */
|
||||
|
||||
/* @(#)astrip.c 1.1 */
|
||||
/* $Header$ */
|
||||
#define ushort unsigned short
|
||||
|
||||
#include "out.h"
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
|
||||
astrip -- remove symbols and relocation bits
|
||||
|
||||
*/
|
||||
|
||||
char *tname;
|
||||
char *mktemp();
|
||||
FILE *fopen();
|
||||
FILE *tf;
|
||||
struct outhead buf;
|
||||
|
||||
main(argc, argv)
|
||||
char **argv;
|
||||
{
|
||||
int status;
|
||||
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGQUIT, SIG_IGN);
|
||||
tname = mktemp("/tmp/sXXXXX");
|
||||
while(--argc) {
|
||||
if ((status = strip(argv[argc])) > 1)
|
||||
break;
|
||||
}
|
||||
unlink(tname);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
strip(name)
|
||||
char *name;
|
||||
{
|
||||
long size;
|
||||
FILE *f;
|
||||
|
||||
if ((f = fopen(name,"r")) == NULL) {
|
||||
fprintf(stderr, "astrip: cannot open %s\n", name);
|
||||
return(1);
|
||||
}
|
||||
getofmt ((char *)&buf, SF_HEAD , f);
|
||||
if(BADMAGIC(buf)) {
|
||||
fprintf(stderr, "astrip: %s-- bad format\n", name);
|
||||
fclose(f);
|
||||
return(1);
|
||||
}
|
||||
size = OFF_RELO(buf) - SZ_HEAD;
|
||||
buf.oh_flags &= ~HF_LINK;
|
||||
buf.oh_nrelo = 0;
|
||||
buf.oh_nname = 0;
|
||||
buf.oh_nchar = 0;
|
||||
|
||||
|
||||
if ((tf = fopen(tname,"w")) == NULL) {
|
||||
fprintf(stderr, "astrip: cannot create temp file %s\n", tname);
|
||||
fclose(f);
|
||||
return(2);
|
||||
}
|
||||
fseek(tf, (long)0, 0);
|
||||
putofmt((char *)&buf,SF_HEAD,tf,tname);
|
||||
if(copy(name, tname, f, tf, size)) {
|
||||
fclose(f);
|
||||
fclose(tf);
|
||||
return(1);
|
||||
}
|
||||
fclose(f);
|
||||
fclose(tf);
|
||||
size += SZ_HEAD;
|
||||
if ((f = fopen(name,"w")) == NULL) {
|
||||
fprintf(stderr, "astrip: cannot write %s\n", name);
|
||||
return(1);
|
||||
}
|
||||
if ((tf = fopen(tname,"r")) == NULL) {
|
||||
fprintf(stderr, "astrip: cannot read temp file %s\n", tname);
|
||||
fclose(f);
|
||||
return(2);
|
||||
}
|
||||
fseek(tf, (long)0, 0);
|
||||
if(copy(tname, name, tf, f, size)) {
|
||||
fclose(f);
|
||||
fclose(tf);
|
||||
return(2);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
fclose(tf);
|
||||
return(0);
|
||||
}
|
||||
|
||||
copy(fnam, tnam, fr, to, size)
|
||||
char *fnam;
|
||||
char *tnam;
|
||||
long size;
|
||||
FILE *fr,*to;
|
||||
{
|
||||
register s, n;
|
||||
char lbuf[512];
|
||||
|
||||
while(size != (long)0) {
|
||||
s = 512;
|
||||
if(size < 512)
|
||||
s = (int) size;
|
||||
n = fread(lbuf,1,s,fr);
|
||||
if(n != s) {
|
||||
fprintf(stderr, "astrip: unexpected eof on %s\n", fnam);
|
||||
return(1);
|
||||
}
|
||||
n = fwrite(lbuf,1,s,to);
|
||||
if(n != s) {
|
||||
fprintf(stderr, "astrip: write error on %s\n", tnam);
|
||||
return(1);
|
||||
}
|
||||
size -= (long)s;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
getofmt(p, s, f)
|
||||
register char *p;
|
||||
register char *s;
|
||||
register FILE *f;
|
||||
{
|
||||
register i;
|
||||
register long l;
|
||||
|
||||
for (;;) {
|
||||
switch (*s++) {
|
||||
/* case '0': p++; continue; */
|
||||
case '1':
|
||||
*p++ = getc(f);
|
||||
continue;
|
||||
case '2':
|
||||
i = getc(f);
|
||||
i |= (getc(f) << 8);
|
||||
#ifndef DUK
|
||||
*((short *)p)++ = i;
|
||||
#else DUK
|
||||
*((short *)p) = i;
|
||||
p += sizeof(short);
|
||||
#endif DUK
|
||||
continue;
|
||||
case '4':
|
||||
l = (long)getc(f);
|
||||
l |= (long)(getc(f) << 8);
|
||||
l |= ((long)getc(f) << 16);
|
||||
l |= ((long)getc(f) << 24);
|
||||
#ifndef DUK
|
||||
*((long *)p)++ = l;
|
||||
#else DUK
|
||||
*((long *)p) = l;
|
||||
p += sizeof(long);
|
||||
#endif DUK
|
||||
continue;
|
||||
default:
|
||||
case '\0':
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
putofmt(p, s, f, fnam)
|
||||
register char *p;
|
||||
register char *s;
|
||||
register FILE *f;
|
||||
char *fnam;
|
||||
{
|
||||
register i,j;
|
||||
register long l;
|
||||
|
||||
while (j = *s++) {
|
||||
switch (j -= '0') {
|
||||
/* case 0: p++; break; */
|
||||
case 1:
|
||||
i = *p++; putc(i,f);
|
||||
break;
|
||||
case 2:
|
||||
#ifndef DUK
|
||||
i = *((short *)p)++;
|
||||
#else DUK
|
||||
i = *((short *)p);
|
||||
p += sizeof(short);
|
||||
#endif DUK
|
||||
putc(i,f);
|
||||
i>>=8; putc(i,f);
|
||||
break;
|
||||
case 4:
|
||||
#ifndef DUK
|
||||
l = *((long *)p)++;
|
||||
#else DUK
|
||||
l = *((long *)p);
|
||||
p += sizeof(long);
|
||||
#endif DUK
|
||||
putc(l,f);
|
||||
l >>=8; putc(l,f);
|
||||
l >>=8; putc(l,f);
|
||||
l >>=8; putc(l,f);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (ferror(f)) fprintf(stderr, "astrip: write error on %s\n", fnam);
|
||||
}
|
||||
}
|
||||
@@ -1835,7 +1835,7 @@ finishio() {
|
||||
if (bsize>=0)
|
||||
fprintf(hfile,"#define TEM_BSIZE %d\n",bsize);
|
||||
else
|
||||
yyerror("EM_BSIZE undefined");
|
||||
fprintf(hfile,"extern int TEM_BSIZE;\n");
|
||||
if (fmt!=0)
|
||||
fprintf(hfile,"#define WRD_FMT \"%s\"\n",fmt);
|
||||
fprintf(hfile,"#define MAXALLREG %d\n",maxallreg);
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
EMH=../../../h
|
||||
EMLIB=../../../lib
|
||||
SHR=../share
|
||||
|
||||
CFILES=\
|
||||
bo.c
|
||||
|
||||
OFILES=\
|
||||
bo.o
|
||||
|
||||
HFILES=
|
||||
|
||||
PRFILES=\
|
||||
$(CFILES) $(HFILES) Makefile
|
||||
|
||||
SHARE_OFILES=\
|
||||
$(SHR)/get.o $(SHR)/put.o $(SHR)/alloc.o $(SHR)/global.o $(SHR)/debug.o \
|
||||
$(SHR)/files.o $(SHR)/map.o $(SHR)/lset.o $(SHR)/cset.o $(SHR)/aux.o \
|
||||
$(SHR)/stack_chg.o $(SHR)/go.o
|
||||
|
||||
SHARE_MFILES=\
|
||||
$(SHR)/get.m $(SHR)/put.m $(SHR)/alloc.m $(SHR)/global.m $(SHR)/debug.m \
|
||||
$(SHR)/files.m $(SHR)/map.m $(SHR)/lset.m $(SHR)/cset.m $(SHR)/aux.m \
|
||||
$(SHR)/stack_chg.m $(SHR)/go.m
|
||||
|
||||
bo: $(OFILES)
|
||||
$(CC) -o bo $(LDFLAGS) $(OFILES) $(SHARE_OFILES) $(EMLIB)/em_data.a
|
||||
|
||||
bo_ack: $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -c.o $(CFLAGS) $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -o bo -.c $(LDFLAGS) bo.o $(EMLIB)/em_data.a
|
||||
|
||||
lint:
|
||||
lint $(LINTFLAGS) $(CPPFLAGS) $(CFILES)
|
||||
|
||||
pr: $(PRFILES)
|
||||
@pr $?
|
||||
@touch pr
|
||||
|
||||
depend:
|
||||
$(SHR)/makedepend
|
||||
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
|
||||
bo.o: ../share/alloc.h
|
||||
bo.o: ../share/aux.h
|
||||
bo.o: ../share/debug.h
|
||||
bo.o: ../share/def.h
|
||||
bo.o: ../share/files.h
|
||||
bo.o: ../share/get.h
|
||||
bo.o: ../share/global.h
|
||||
bo.o: ../share/go.h
|
||||
bo.o: ../share/lset.h
|
||||
bo.o: ../share/map.h
|
||||
bo.o: ../share/put.h
|
||||
bo.o: ../share/types.h
|
||||
bo.o: ../../../h/em_mnem.h
|
||||
bo.o: ../../../h/em_pseu.h
|
||||
bo.o: ../../../h/em_spec.h
|
||||
318
util/ego/bo/bo.c
318
util/ego/bo/bo.c
@@ -1,318 +0,0 @@
|
||||
/* B R A N C H O P T I M I Z A T I O N
|
||||
*
|
||||
* B O . C
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/files.h"
|
||||
#include "../share/get.h"
|
||||
#include "../share/put.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/map.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/def.h"
|
||||
#include "../share/go.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
|
||||
#define LP_BLOCKS lp_extend->lpx_ra.lpx_blocks
|
||||
|
||||
#define newbolpx() (lpext_p) newstruct(lpext_ra)
|
||||
#define oldbolpx(x) oldstruct(lpext_ra,x)
|
||||
|
||||
STATIC int Sbo; /* #optimizations found */
|
||||
|
||||
#define DLINK(l1,l2) l1->l_next=l2; l2->l_prev=l1
|
||||
|
||||
/* This module performs some very simple branch optimizations.
|
||||
*
|
||||
* I) Look for pairs of basic blocks (B1,B2), such that
|
||||
* SUCC(b1) = {B2} and
|
||||
* PRED(B2) = {B1}.
|
||||
* In this case B1 and B2 can be combined into one block.
|
||||
* This optimization is mainly succesful:
|
||||
* 1) for switch statements in C, as the C compiler generates a branch
|
||||
* over the entire switch.
|
||||
* 2) for return statements, if the only way to return from a procedure
|
||||
* is via a return statement somewhere in the middle of the procedure.
|
||||
* II) Optimize while statements. Transformations like:
|
||||
* 1: jmp 2
|
||||
* tst cond 1:
|
||||
* beq 2f S
|
||||
* S 2:
|
||||
* jmp 1 tst cond
|
||||
* 2: bneq 1
|
||||
* are done by this optimization.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
STATIC line_p last_code(lines,skip_pseu)
|
||||
line_p lines;
|
||||
bool skip_pseu;
|
||||
{
|
||||
/* Determine the last line of a list */
|
||||
|
||||
register line_p l;
|
||||
|
||||
for (l = lines; l->l_next != (line_p) 0; l = l->l_next);
|
||||
if (skip_pseu) {
|
||||
while (INSTR(l) < sp_fmnem || INSTR(l) > sp_lmnem) l = PREV(l);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
STATIC short cc_tab[12] =
|
||||
{op_blt,op_zlt,op_ble,op_zle,op_beq,op_zeq,
|
||||
op_zne,op_bne,op_zgt,op_bgt,op_zge,op_bge};
|
||||
|
||||
|
||||
STATIC short rev_cond(cond)
|
||||
short cond;
|
||||
{
|
||||
register i;
|
||||
|
||||
for (i = 0; i < 12; i++) {
|
||||
if (cond == cc_tab[i]) return cc_tab[11-i];
|
||||
}
|
||||
return op_nop;
|
||||
}
|
||||
|
||||
STATIC bool is_bcc(l)
|
||||
line_p l;
|
||||
{
|
||||
return rev_cond(INSTR(l)) != op_nop;
|
||||
}
|
||||
|
||||
|
||||
STATIC bo_optloop(p,b,x,bra,bcc)
|
||||
proc_p p;
|
||||
bblock_p b,x;
|
||||
line_p bra,bcc;
|
||||
{
|
||||
bblock_p prevb,n;
|
||||
line_p l;
|
||||
|
||||
if (b->b_start == bra) {
|
||||
b->b_start = (line_p) 0;
|
||||
} else {
|
||||
PREV(bra)->l_next = (line_p) 0;
|
||||
}
|
||||
PREV(bra) = (line_p) 0;
|
||||
bcc->l_instr = rev_cond(INSTR(bcc));
|
||||
n = x->b_next;
|
||||
l = n->b_start;
|
||||
if (l == (line_p) 0 || INSTR(l) != op_lab) {
|
||||
l = newline(OPINSTRLAB);
|
||||
l->l_instr = op_lab;
|
||||
INSTRLAB(l) = freshlabel();
|
||||
if (n->b_start != (line_p) 0) {
|
||||
DLINK(l,n->b_start);
|
||||
}
|
||||
n->b_start = l;
|
||||
}
|
||||
INSTRLAB(bcc) = INSTRLAB(l);
|
||||
for (prevb = p->p_start; prevb != (bblock_p) 0 && prevb->b_next != x;
|
||||
prevb = prevb->b_next);
|
||||
if (prevb == (bblock_p) 0) {
|
||||
p->p_start = x->b_next;
|
||||
} else {
|
||||
prevb->b_next = x->b_next;
|
||||
l = last_instr(prevb);
|
||||
if (l == (line_p) 0) {
|
||||
prevb->b_start = bra;
|
||||
} else {
|
||||
if (INSTR(l) == op_bra &&
|
||||
INSTRLAB(l) == INSTRLAB(bra)) {
|
||||
oldline(bra);
|
||||
} else {
|
||||
appnd_line(bra,l);
|
||||
}
|
||||
}
|
||||
}
|
||||
x->b_next = b->b_next;
|
||||
b->b_next = x;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bo_tryloop(p,loop)
|
||||
proc_p p;
|
||||
lset loop;
|
||||
{
|
||||
Lindex i,j;
|
||||
bblock_p b,x;
|
||||
line_p bra,bcc;
|
||||
|
||||
for (i = Lfirst(loop); i != (Lindex) 0; i = Lnext(i,loop)) {
|
||||
b = (bblock_p) Lelem(i);
|
||||
if (b->b_next != (bblock_p) 0 && !Lis_elem(b->b_next,loop)) {
|
||||
j = Lfirst(b->b_succ);
|
||||
if (j != (Lindex) 0 &&
|
||||
(bra = last_instr(b)) != (line_p) 0 &&
|
||||
INSTR(bra) == op_bra) {
|
||||
x = (bblock_p) Lelem(j); /* single successor */
|
||||
if (Lis_elem(b->b_next,x->b_succ) &&
|
||||
is_bcc((bcc = last_instr(x)))) {
|
||||
OUTVERBOSE("branch optimization proc %d block %d\n", curproc->p_id,x->b_id);
|
||||
Sbo++;
|
||||
bo_optloop(p,b,x,bra,bcc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bo_loops(p)
|
||||
proc_p p;
|
||||
{
|
||||
Lindex i;
|
||||
loop_p lp;
|
||||
|
||||
for (i = Lfirst(p->p_loops); i != (Lindex) 0; i = Lnext(i,p->p_loops)) {
|
||||
lp = (loop_p) (Lelem(i));
|
||||
bo_tryloop(p,lp->LP_BLOCKS);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mv_code(b1,b2)
|
||||
bblock_p b1,b2;
|
||||
{
|
||||
line_p l,x;
|
||||
|
||||
l = last_code(b2->b_start,TRUE);
|
||||
DLINK(l,b1->b_start);
|
||||
x = l->l_next;
|
||||
if (INSTR(l) == op_bra) {
|
||||
rm_line(l,b2);
|
||||
}
|
||||
if (INSTR(x) == op_lab) {
|
||||
rm_line(x,b2);
|
||||
}
|
||||
}
|
||||
|
||||
bo_switch(b)
|
||||
bblock_p b;
|
||||
{
|
||||
bblock_p s,x;
|
||||
Lindex i;
|
||||
line_p l;
|
||||
|
||||
if (Lnrelems(b->b_succ) == 1) {
|
||||
s = (bblock_p) Lelem(Lfirst(b->b_succ));
|
||||
if (b->b_start != (line_p) 0 &&
|
||||
s->b_start != (line_p) 0 &&
|
||||
Lnrelems(s->b_pred) == 1 &&
|
||||
(s->b_next == (bblock_p) 0 ||
|
||||
!Lis_elem(s->b_next,s->b_succ))) {
|
||||
l = last_code(s->b_start,FALSE);
|
||||
if (INSTR(l) == ps_end) {
|
||||
if (PREV(l) == (line_p) 0) return;
|
||||
PREV(l)->l_next = (line_p) 0;
|
||||
PREV(l) = (line_p) 0;
|
||||
} else {
|
||||
l = (line_p) 0;
|
||||
}
|
||||
OUTVERBOSE("branch optimization in proc %d, block %d",curproc->p_id,b->b_id);
|
||||
Sbo++;
|
||||
Ldeleteset(b->b_succ);
|
||||
b->b_succ = s->b_succ;
|
||||
Ldeleteset(s->b_pred);
|
||||
s->b_succ = Lempty_set();
|
||||
s->b_pred = Lempty_set();
|
||||
for (i = Lfirst(b->b_succ); i != (Lindex) 0;
|
||||
i = Lnext(i,b->b_succ)) {
|
||||
x = (bblock_p) Lelem(i);
|
||||
Lremove(s,&x->b_pred);
|
||||
Ladd(b,&x->b_pred);
|
||||
if (x->b_idom == s) {
|
||||
x->b_idom = b;
|
||||
}
|
||||
}
|
||||
mv_code(s,b);
|
||||
s->b_start = l;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC bo_extproc(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Allocate the extended data structures for procedure p */
|
||||
|
||||
register loop_p lp;
|
||||
register Lindex pi;
|
||||
|
||||
for (pi = Lfirst(p->p_loops); pi != (Lindex) 0;
|
||||
pi = Lnext(pi,p->p_loops)) {
|
||||
lp = (loop_p) Lelem(pi);
|
||||
lp->lp_extend = newbolpx();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC loop_blocks(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Compute the LP_BLOCKS sets for all loops of p */
|
||||
|
||||
register bblock_p b;
|
||||
register Lindex i;
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
for (i = Lfirst(b->b_loops); i != (Lindex) 0;
|
||||
i = Lnext(i,b->b_loops)) {
|
||||
Ladd(b,&(((loop_p) Lelem(i))->LP_BLOCKS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC bo_cleanproc(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Allocate the extended data structures for procedure p */
|
||||
|
||||
register loop_p lp;
|
||||
register Lindex pi;
|
||||
register bblock_p b;
|
||||
|
||||
for (pi = Lfirst(p->p_loops); pi != (Lindex) 0;
|
||||
pi = Lnext(pi,p->p_loops)) {
|
||||
lp = (loop_p) Lelem(pi);
|
||||
oldbolpx(lp->lp_extend);
|
||||
}
|
||||
}
|
||||
|
||||
bo_optimize(p)
|
||||
proc_p p;
|
||||
{
|
||||
bblock_p b;
|
||||
|
||||
bo_extproc(p);
|
||||
loop_blocks(p);
|
||||
bo_loops(p);
|
||||
for (b = p->p_start; b != 0; b = b->b_next) {
|
||||
bo_switch(b);
|
||||
}
|
||||
bo_cleanproc(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
go(argc,argv,no_action,bo_optimize,no_action,no_action);
|
||||
report("branch optimizations", Sbo);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
EMH=../../../h
|
||||
EMLIB=../../../lib
|
||||
SHR=../share
|
||||
|
||||
CFILES=\
|
||||
ca.c ca_put.c
|
||||
|
||||
OFILES=\
|
||||
ca.o ca_put.o
|
||||
|
||||
HFILES=\
|
||||
ca.h ca_put.h
|
||||
|
||||
PRFILES=\
|
||||
$(CFILES) $(HFILES) Makefile
|
||||
|
||||
SHARE_OFILES=\
|
||||
$(SHR)/get.o $(SHR)/alloc.o $(SHR)/global.o $(SHR)/aux.o $(SHR)/debug.o \
|
||||
$(SHR)/lset.o $(SHR)/cset.o $(SHR)/files.o $(SHR)/map.o
|
||||
|
||||
SHARE_MFILES=\
|
||||
$(SHR)/get.m $(SHR)/alloc.m $(SHR)/global.m $(SHR)/aux.m $(SHR)/debug.m \
|
||||
$(SHR)/lset.m $(SHR)/cset.m $(SHR)/files.m $(SHR)/map.m
|
||||
|
||||
ca: $(OFILES)
|
||||
$(CC) -o ca $(LDFLAGS) $(OFILES) $(SHARE_OFILES) $(EMLIB)/em_data.a
|
||||
|
||||
ca_ack: $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -c.o $(CFLAGS) $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -o ca -.c $(LDFLAGS) ca.o $(EMLIB)/em_data.a
|
||||
|
||||
lint:
|
||||
lint $(LINTFLAGS) $(CPPFLAGS) $(CFILES)
|
||||
|
||||
pr: $(PRFILES)
|
||||
@pr $?
|
||||
@touch pr
|
||||
|
||||
depend:
|
||||
$(SHR)/makedepend
|
||||
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
|
||||
ca.o: ../share/alloc.h
|
||||
ca.o: ../share/debug.h
|
||||
ca.o: ../share/files.h
|
||||
ca.o: ../share/get.h
|
||||
ca.o: ../share/global.h
|
||||
ca.o: ../share/lset.h
|
||||
ca.o: ../share/map.h
|
||||
ca.o: ../share/types.h
|
||||
ca.o: ca.h
|
||||
ca.o: ca_put.h
|
||||
ca_put.o: ../../../h/em_flag.h
|
||||
ca_put.o: ../../../h/em_mes.h
|
||||
ca_put.o: ../../../h/em_mnem.h
|
||||
ca_put.o: ../../../h/em_pseu.h
|
||||
ca_put.o: ../../../h/em_spec.h
|
||||
ca_put.o: ../share/alloc.h
|
||||
ca_put.o: ../share/debug.h
|
||||
ca_put.o: ../share/def.h
|
||||
ca_put.o: ../share/map.h
|
||||
ca_put.o: ../share/types.h
|
||||
ca_put.o: ca.h
|
||||
271
util/ego/ca/ca.c
271
util/ego/ca/ca.c
@@ -1,271 +0,0 @@
|
||||
/*
|
||||
* C O M P A C T A S S E M B L Y L A N G U A G E G E N E R A T I O N
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "ca.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/files.h"
|
||||
#include "../share/map.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/get.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_mes.h"
|
||||
#include "ca_put.h"
|
||||
|
||||
|
||||
/* This phase transforms the Intermediate Code of the global optimizer
|
||||
* to 'standard' compact assembly language, which will be processed
|
||||
* by the code generator.
|
||||
*/
|
||||
|
||||
|
||||
short dlength;
|
||||
dblock_p *dmap;
|
||||
|
||||
char **dnames, **pnames; /* Dynamically allocated arrays of strings.
|
||||
* pnames[i] contains a pointer to the name
|
||||
* of the procedure with proc_id i.
|
||||
*/
|
||||
|
||||
|
||||
STATIC char **newnametab(tablen,namelen)
|
||||
short tablen,namelen;
|
||||
{
|
||||
register char **np, **tab;
|
||||
|
||||
tab = (char **) newmap(tablen);
|
||||
for (np = &tab[1]; np <= &tab[tablen]; np++) {
|
||||
*np = (char *) newcore(namelen);
|
||||
}
|
||||
return tab;
|
||||
}
|
||||
|
||||
|
||||
STATIC line_p get_ca_lines(lf,p_out)
|
||||
FILE *lf;
|
||||
proc_p *p_out;
|
||||
{
|
||||
/* Read lines of EM text and link them.
|
||||
* Register messages are outputted immediately after the PRO.
|
||||
*/
|
||||
|
||||
line_p head, *pp, l;
|
||||
line_p headm, *mp;
|
||||
arg_p a;
|
||||
|
||||
curinp = lf; /* EM input file */
|
||||
pp = &head;
|
||||
mp = &headm;
|
||||
headm = (line_p) 0;
|
||||
while (TRUE) {
|
||||
l = read_line(p_out);
|
||||
if (feof(curinp)) break;
|
||||
assert (l != (line_p) 0);
|
||||
if (INSTR(l) == ps_end && INSTR(head) != ps_pro) {
|
||||
/* Delete end pseudo after data-unit */
|
||||
oldline(l);
|
||||
break;
|
||||
}
|
||||
if (INSTR(l) == ps_mes && l->l_a.la_arg->a_a.a_offset == ms_reg) {
|
||||
/* l is a register message */
|
||||
if (l->l_a.la_arg->a_next == (arg_p) 0) {
|
||||
/* register message without arguments */
|
||||
oldline(l);
|
||||
} else {
|
||||
*mp = l;
|
||||
mp = &l->l_next;
|
||||
}
|
||||
} else {
|
||||
*pp = l;
|
||||
pp = &l->l_next;
|
||||
}
|
||||
if (INSTR(l) == ps_end) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*pp = (line_p) 0;
|
||||
if (head != (line_p) 0 && INSTR(head) == ps_pro) {
|
||||
/* append register message without arguments to list */
|
||||
l = newline(OPLIST);
|
||||
l->l_instr = ps_mes;
|
||||
a = ARG(l) = newarg(ARGOFF);
|
||||
a->a_a.a_offset = ms_reg;
|
||||
*mp = l;
|
||||
l->l_next = head->l_next;
|
||||
head->l_next = headm;
|
||||
} else {
|
||||
assert(headm == (line_p) 0);
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
STATIC int makedmap(dbl)
|
||||
dblock_p dbl;
|
||||
{
|
||||
/* construct the dmap table */
|
||||
|
||||
dblock_p d;
|
||||
int cnt;
|
||||
|
||||
/* determine the length of the table */
|
||||
|
||||
cnt = 0;
|
||||
for (d = dbl; d != (dblock_p) 0; d = d->d_next) cnt++;
|
||||
dmap = (dblock_p *) newmap(cnt);
|
||||
for (d = dbl; d != (dblock_p) 0; d = d->d_next) {
|
||||
assert(d->d_id) <= cnt;
|
||||
dmap[d->d_id] = d;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC getdnames(dumpd)
|
||||
FILE *dumpd;
|
||||
{
|
||||
/* Read the names of the datalabels from
|
||||
* the dump file.
|
||||
*/
|
||||
|
||||
char str[IDL+1];
|
||||
char *s;
|
||||
int id;
|
||||
register int i;
|
||||
|
||||
dnames = (char **) newnametab(dlength,IDL);
|
||||
for (;;) {
|
||||
if (fscanf(dumpd,"%d %s",&id,str) == EOF) return;
|
||||
assert(id <= dlength);
|
||||
s = dnames[id];
|
||||
for (i = 0; i < IDL; i++) {
|
||||
*s++ = str[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC getpnames(dumpp)
|
||||
FILE *dumpp;
|
||||
{
|
||||
/* Read the names of the procedures from
|
||||
* the dump file.
|
||||
*/
|
||||
|
||||
char str[IDL+1];
|
||||
char *s;
|
||||
int id;
|
||||
register int i;
|
||||
|
||||
pnames = (char **) newnametab(plength,IDL);
|
||||
for (;;) {
|
||||
if (fscanf(dumpp,"%d %s",&id,str) == EOF) return;
|
||||
assert(id <= plength);
|
||||
s = pnames[id];
|
||||
for (i = 0; i < IDL; i++) {
|
||||
*s++ = str[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC bool name_exists(name,endp,endd)
|
||||
char *name;
|
||||
proc_p endp;
|
||||
dblock_p endd;
|
||||
{
|
||||
/* Search the proctable (from fproc to endp)
|
||||
* and the data block table (from fdblock to endd)
|
||||
* to see if the name is already in use.
|
||||
*/
|
||||
|
||||
proc_p p;
|
||||
dblock_p d;
|
||||
|
||||
for (p = fproc; p != endp; p = p->p_next) {
|
||||
if (strncmp(name,pnames[p->p_id],IDL) == 0) return TRUE;
|
||||
}
|
||||
for (d = fdblock; d != endd; d = d->d_next) {
|
||||
if (strncmp(name,dnames[d->d_id],IDL) == 0) return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int nn = 0;
|
||||
|
||||
STATIC new_name(s)
|
||||
char *s;
|
||||
{
|
||||
s[0] = '_';
|
||||
s[1] = 'I';
|
||||
s[2] = 'I';
|
||||
sprintf(&s[3],"%d",nn);
|
||||
nn++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC uniq_names()
|
||||
{
|
||||
/* The names of all internal procedures and data blocks
|
||||
* are made different. As the optimizer combines several
|
||||
* modules into one, there may be name conflicts between
|
||||
* procedures or data blocks that were internal in
|
||||
* different source modules.
|
||||
*/
|
||||
|
||||
proc_p p;
|
||||
dblock_p d;
|
||||
|
||||
for (p = fproc; p != (proc_p) 0; p = p->p_next) {
|
||||
if (!(p->p_flags1 & PF_EXTERNAL) &&
|
||||
name_exists(pnames[p->p_id],p,fdblock)) {
|
||||
new_name(pnames[p->p_id]);
|
||||
}
|
||||
}
|
||||
for (d = fdblock; d != (dblock_p) 0; d = d->d_next) {
|
||||
if (!(d->d_flags1 & DF_EXTERNAL) &&
|
||||
name_exists(dnames[d->d_id],(proc_p) 0,d) ) {
|
||||
new_name(dnames[d->d_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
/* CA does not output proctable etc. files. Instead, its
|
||||
* pname2 and dname2 arguments contain the names of the
|
||||
* dump files created by IC.
|
||||
*/
|
||||
FILE *f, *f2; /* The EM input and output. */
|
||||
FILE *df, *pf; /* The dump files */
|
||||
line_p lnp;
|
||||
|
||||
fproc = getptable(pname); /* proc table */
|
||||
fdblock = getdtable(dname); /* data block table */
|
||||
dlength = makedmap(fdblock); /* allocate dmap table */
|
||||
df = openfile(dname2,"r");
|
||||
getdnames(df);
|
||||
fclose(df);
|
||||
pf = openfile(pname2,"r");
|
||||
getpnames(pf);
|
||||
fclose(pf);
|
||||
uniq_names();
|
||||
f = openfile(lname,"r");
|
||||
f2 = stdout;
|
||||
cputmagic(f2); /* write magic number */
|
||||
while ((lnp = get_ca_lines(f,&curproc)) != (line_p) 0) {
|
||||
cputlines(lnp,f2);
|
||||
}
|
||||
fclose(f);
|
||||
fclose(f2);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* C O M P A C T A S S E M B L Y L A N G U A G E G E N E R A T I O N
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#define PF_SYMOUT 01
|
||||
#define DF_SYMOUT 01
|
||||
|
||||
extern dblock_p *dmap;
|
||||
|
||||
extern char **dnames;
|
||||
extern char **pnames;
|
||||
|
||||
extern byte em_flag[];
|
||||
@@ -1,413 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "ca.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/def.h"
|
||||
#include "../share/map.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_flag.h"
|
||||
#include "../../../h/em_mes.h"
|
||||
#include "../share/alloc.h"
|
||||
|
||||
#define outbyte(b) putc(b,outfile)
|
||||
|
||||
FILE *outfile;
|
||||
|
||||
STATIC proc_p thispro;
|
||||
|
||||
STATIC outinst(m) {
|
||||
|
||||
outbyte( (byte) m );
|
||||
}
|
||||
|
||||
STATIC coutshort(i) short i; {
|
||||
|
||||
outbyte( (byte) (i&BMASK) );
|
||||
outbyte( (byte) (i>>8) );
|
||||
}
|
||||
|
||||
STATIC coutint(i) short i; {
|
||||
|
||||
if (i>= -sp_zcst0 && i< sp_ncst0-sp_zcst0)
|
||||
outbyte( (byte) (i+sp_zcst0+sp_fcst0) );
|
||||
else {
|
||||
outbyte( (byte) sp_cst2) ;
|
||||
coutshort(i);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC coutoff(off) offset off; {
|
||||
|
||||
if ((short) off == off)
|
||||
coutint((short) off);
|
||||
else {
|
||||
outbyte( (byte) sp_cst4) ;
|
||||
coutshort( (short) (off&0177777L) );
|
||||
coutshort( (short) (off>>16) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outsym(s,t)
|
||||
char *s;
|
||||
int t;
|
||||
{
|
||||
register byte *p;
|
||||
register unsigned num;
|
||||
|
||||
if (s[0] == '.') {
|
||||
num = atoi(&s[1]);
|
||||
if (num < 256) {
|
||||
outbyte( (byte) sp_dlb1) ;
|
||||
outbyte( (byte) (num) );
|
||||
} else {
|
||||
outbyte( (byte) sp_dlb2) ;
|
||||
coutshort((short) num);
|
||||
}
|
||||
} else {
|
||||
p= s;
|
||||
while (*p && p < &s[IDL])
|
||||
p++;
|
||||
num = p - s;
|
||||
outbyte( (byte) t);
|
||||
coutint((short) num);
|
||||
p = s;
|
||||
while (num--)
|
||||
outbyte( (byte) *p++ );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outdsym(dbl)
|
||||
dblock_p dbl;
|
||||
{
|
||||
outsym(dnames[dbl->d_id],sp_dnam);
|
||||
}
|
||||
|
||||
|
||||
STATIC outpsym(p)
|
||||
proc_p p;
|
||||
{
|
||||
outsym(pnames[p->p_id],sp_pnam);
|
||||
}
|
||||
|
||||
|
||||
STATIC outddef(id) short id; {
|
||||
|
||||
dblock_p dbl;
|
||||
|
||||
dbl = dmap[id];
|
||||
dbl->d_flags2 |= DF_SYMOUT;
|
||||
if (dbl->d_flags1 & DF_EXTERNAL) {
|
||||
outinst(ps_exa);
|
||||
outdsym(dbl);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC outpdef(p) proc_p p; {
|
||||
p->p_flags2 |= PF_SYMOUT;
|
||||
if (p->p_flags1 & PF_EXTERNAL) {
|
||||
outinst(ps_exp);
|
||||
outpsym(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outdocc(obj) obj_p obj; {
|
||||
dblock_p dbl;
|
||||
|
||||
dbl = obj->o_dblock;
|
||||
if ((dbl->d_flags2 & DF_SYMOUT) == 0) {
|
||||
dbl->d_flags2 |= DF_SYMOUT;
|
||||
if ((dbl->d_flags1 & DF_EXTERNAL) == 0) {
|
||||
outinst(ps_ina);
|
||||
outdsym(dbl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outpocc(p) proc_p p; {
|
||||
if ((p->p_flags2 & PF_SYMOUT) == 0) {
|
||||
p->p_flags2 |= PF_SYMOUT;
|
||||
if ((p->p_flags1 & PF_EXTERNAL) == 0) {
|
||||
outinst(ps_inp);
|
||||
outpsym(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC coutobject(obj)
|
||||
obj_p obj;
|
||||
{
|
||||
/* In general, an object is defined by a global data
|
||||
* label and an offset. There are two special cases:
|
||||
* the label is omitted if the object is part of the current
|
||||
* hol block; the offset is omitted if it is 0 and the label
|
||||
* was not omitted.
|
||||
*/
|
||||
if (dnames[obj->o_dblock->d_id][0] == '\0') {
|
||||
coutoff(obj->o_off);
|
||||
} else {
|
||||
if (obj->o_off == 0) {
|
||||
outdsym(obj->o_dblock);
|
||||
} else {
|
||||
outbyte((byte) sp_doff);
|
||||
outdsym(obj->o_dblock);
|
||||
coutoff(obj->o_off);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC cputstr(abp) register argb_p abp; {
|
||||
register argb_p tbp;
|
||||
register length;
|
||||
|
||||
length = 0;
|
||||
tbp = abp;
|
||||
while (tbp!= (argb_p) 0) {
|
||||
length += tbp->ab_index;
|
||||
tbp = tbp->ab_next;
|
||||
}
|
||||
coutint(length);
|
||||
while (abp != (argb_p) 0) {
|
||||
for (length=0;length<abp->ab_index;length++)
|
||||
outbyte( (byte) abp->ab_contents[length] );
|
||||
abp = abp->ab_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outnum(n)
|
||||
int n;
|
||||
{
|
||||
if (n < 256) {
|
||||
outbyte((byte) sp_ilb1);
|
||||
outbyte((byte) n);
|
||||
} else {
|
||||
outbyte((byte) sp_ilb2);
|
||||
coutshort((short) n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC numlab(n)
|
||||
int n;
|
||||
{
|
||||
if (n < sp_nilb0) {
|
||||
outbyte((byte) (n + sp_filb0));
|
||||
} else {
|
||||
outnum(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC cputargs(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
register arg_p ap;
|
||||
int cnt = 0;
|
||||
ap = ARG(lnp);
|
||||
while (ap != (arg_p) 0) {
|
||||
switch(ap->a_type) {
|
||||
case ARGOFF:
|
||||
coutoff(ap->a_a.a_offset);
|
||||
break;
|
||||
case ARGOBJECT:
|
||||
coutobject(ap->a_a.a_obj);
|
||||
break;
|
||||
case ARGPROC:
|
||||
outpsym(ap->a_a.a_proc);
|
||||
break;
|
||||
case ARGINSTRLAB:
|
||||
outnum(ap->a_a.a_instrlab);
|
||||
break;
|
||||
case ARGSTRING:
|
||||
outbyte((byte) sp_scon);
|
||||
cputstr(&ap->a_a.a_string);
|
||||
break;
|
||||
case ARGICN:
|
||||
outbyte((byte) sp_icon);
|
||||
goto casecon;
|
||||
case ARGUCN:
|
||||
outbyte((byte) sp_ucon);
|
||||
goto casecon;
|
||||
case ARGFCN:
|
||||
outbyte((byte) sp_fcon);
|
||||
casecon:
|
||||
coutint(ap->a_a.a_con.ac_length);
|
||||
cputstr(&ap->a_a.a_con.ac_con);
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
ap = ap->a_next;
|
||||
/* Avoid generating extremely long CON or ROM statements */
|
||||
if (cnt++ > 10 && ap != (arg_p) 0 &&
|
||||
(INSTR(lnp) == ps_con || INSTR(lnp) == ps_rom)) {
|
||||
cnt = 0;
|
||||
outbyte((byte) sp_cend);
|
||||
outinst(INSTR(lnp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC outoperand(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* Output the operand of instruction lnp */
|
||||
|
||||
switch(TYPE(lnp)) {
|
||||
case OPNO:
|
||||
if ((em_flag[INSTR(lnp)-sp_fmnem]&EM_PAR) != PAR_NO) {
|
||||
outbyte((byte) sp_cend);
|
||||
}
|
||||
break;
|
||||
case OPSHORT:
|
||||
if (INSTR(lnp) == ps_sym) {
|
||||
outsym(dnames[SHORT(lnp)],sp_dnam);
|
||||
} else {
|
||||
coutint(SHORT(lnp));
|
||||
}
|
||||
break;
|
||||
case OPOFFSET:
|
||||
coutoff(OFFSET(lnp));
|
||||
break;
|
||||
case OPINSTRLAB:
|
||||
if (INSTR(lnp) == op_lab) {
|
||||
numlab(INSTRLAB(lnp));
|
||||
} else {
|
||||
if (INSTR(lnp) < sp_fpseu) {
|
||||
coutint(INSTRLAB(lnp));
|
||||
} else {
|
||||
numlab(INSTRLAB(lnp));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OPOBJECT:
|
||||
coutobject(OBJ(lnp));
|
||||
break;
|
||||
case OPPROC:
|
||||
outpsym(PROC(lnp));
|
||||
break;
|
||||
case OPLIST:
|
||||
cputargs(lnp);
|
||||
switch(INSTR(lnp)) {
|
||||
case ps_con:
|
||||
case ps_rom:
|
||||
case ps_mes:
|
||||
outbyte((byte) sp_cend);
|
||||
/* list terminator */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outvisibility(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* In EM names of datalabels and procedures can be made
|
||||
* externally visible, so they can be used in other files.
|
||||
* There are special EM pseudo-instructions to state
|
||||
* explicitly that a certain identifier is externally
|
||||
* visible (ps_exa,ps_exp) or invisible (ps_ina,ps_inp).
|
||||
* If there is no such pseudo for a certain identifier,
|
||||
* the identifier is external only if its first use
|
||||
* in the current file is an applied occurrence.
|
||||
* Unfortunately the global optimizer may change the
|
||||
* order of defining and applied occurrences.
|
||||
* In the first optimizer pass (ic) we record for each identifier
|
||||
* whether it is external or not. If necessary we generate
|
||||
* pseudo instructions here.
|
||||
*/
|
||||
|
||||
arg_p ap;
|
||||
short instr;
|
||||
|
||||
instr = INSTR(lnp);
|
||||
switch(TYPE(lnp)) {
|
||||
case OPOBJECT:
|
||||
outdocc(OBJ(lnp));
|
||||
/* applied occurrence of a data label */
|
||||
break;
|
||||
case OPSHORT:
|
||||
if (instr == ps_sym) {
|
||||
outddef(SHORT(lnp));
|
||||
/* defining occ. data label */
|
||||
}
|
||||
break;
|
||||
case OPPROC:
|
||||
if (instr == ps_pro) {
|
||||
outpdef(PROC(lnp));
|
||||
/* defining occ. procedure */
|
||||
} else {
|
||||
outpocc(PROC(lnp));
|
||||
}
|
||||
break;
|
||||
case OPLIST:
|
||||
for (ap = ARG(lnp); ap != (arg_p) 0; ap = ap->a_next) {
|
||||
switch(ap->a_type) {
|
||||
case ARGOBJECT:
|
||||
outdocc(ap->a_a.a_obj);
|
||||
break;
|
||||
case ARGPROC:
|
||||
outpocc(ap->a_a.a_proc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cputlines(l,lf)
|
||||
line_p l;
|
||||
FILE *lf;
|
||||
{
|
||||
/* Output the lines in Campact assembly language
|
||||
* format.
|
||||
*/
|
||||
|
||||
line_p next,lnp;
|
||||
|
||||
outfile = lf;
|
||||
for (lnp = l; lnp != (line_p) 0; lnp = next) {
|
||||
next = lnp->l_next;
|
||||
outvisibility(lnp); /* take care of visibiltity rules */
|
||||
if (INSTR(lnp) != ps_sym && INSTR(lnp) != op_lab) {
|
||||
outinst(INSTR(lnp));
|
||||
}
|
||||
outoperand(lnp);
|
||||
switch(INSTR(lnp)) {
|
||||
case ps_pro:
|
||||
thispro = PROC(lnp);
|
||||
/* fall through ... */
|
||||
case ps_end:
|
||||
coutoff(thispro->p_localbytes);
|
||||
}
|
||||
oldline(lnp);
|
||||
}
|
||||
if (lmap != (line_p *) 0) {
|
||||
oldmap(lmap,llength);
|
||||
lmap = (line_p *) 0;
|
||||
}
|
||||
}
|
||||
|
||||
cputmagic(lf)
|
||||
FILE *lf;
|
||||
{
|
||||
/* write the magic number */
|
||||
|
||||
outfile = lf;
|
||||
coutshort(sp_magic);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
/* C O M P A C T A S S E M B L Y G E N E R A T I O N
|
||||
*
|
||||
* C A _ P U T . C
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
extern cputlines();
|
||||
extern cputmagic();
|
||||
@@ -1,82 +0,0 @@
|
||||
EMH=../../../h
|
||||
EMLIB=../../../lib
|
||||
SHR=../share
|
||||
|
||||
CFILES=\
|
||||
cf.c cf_succ.c cf_idom.c cf_loop.c
|
||||
|
||||
OFILES=\
|
||||
cf.o cf_idom.o cf_loop.o cf_succ.o
|
||||
|
||||
HFILES=\
|
||||
cf.h cf_succ.h cf_idom.h cf_loop.h
|
||||
|
||||
PRFILES=\
|
||||
$(CFILES) $(HFILES) Makefile
|
||||
|
||||
SHARE_OFILES=\
|
||||
$(SHR)/get.o $(SHR)/put.o $(SHR)/alloc.o $(SHR)/global.o \
|
||||
$(SHR)/debug.o $(SHR)/files.o $(SHR)/map.o $(SHR)/lset.o \
|
||||
$(SHR)/cset.o $(SHR)/aux.o
|
||||
|
||||
SHARE_MFILES=\
|
||||
$(SHR)/get.m $(SHR)/put.m $(SHR)/alloc.m $(SHR)/global.m \
|
||||
$(SHR)/debug.m $(SHR)/files.m $(SHR)/map.m $(SHR)/lset.m \
|
||||
$(SHR)/cset.m $(SHR)/aux.m
|
||||
|
||||
cf: $(OFILES)
|
||||
$(CC) -o cf $(LDFLAGS) $(OFILES) $(SHARE_OFILES) $(EMLIB)/em_data.a
|
||||
|
||||
cf_ack: $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -c.o $(CFLAGS) $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -o cf -.c $(LDFLAGS) cf.o $(EMLIB)/em_data.a
|
||||
|
||||
lint:
|
||||
lint $(LINTFLAGS) $(CPPFLAGS) $(CFILES)
|
||||
|
||||
pr: $(PRFILES)
|
||||
@pr $?
|
||||
@touch pr
|
||||
|
||||
depend:
|
||||
$(SHR)/makedepend
|
||||
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
cf.o: ../../../h/em_mnem.h
|
||||
cf.o: ../share/alloc.h
|
||||
cf.o: ../share/cset.h
|
||||
cf.o: ../share/debug.h
|
||||
cf.o: ../share/files.h
|
||||
cf.o: ../share/get.h
|
||||
cf.o: ../share/global.h
|
||||
cf.o: ../share/lset.h
|
||||
cf.o: ../share/map.h
|
||||
cf.o: ../share/put.h
|
||||
cf.o: ../share/types.h
|
||||
cf.o: cf.h
|
||||
cf.o: cf_idom.h
|
||||
cf.o: cf_loop.h
|
||||
cf.o: cf_succ.h
|
||||
cf_idom.o: ../share/alloc.h
|
||||
cf_idom.o: ../share/debug.h
|
||||
cf_idom.o: ../share/lset.h
|
||||
cf_idom.o: ../share/types.h
|
||||
cf_idom.o: cf.h
|
||||
cf_loop.o: ../share/alloc.h
|
||||
cf_loop.o: ../share/debug.h
|
||||
cf_loop.o: ../share/lset.h
|
||||
cf_loop.o: ../share/types.h
|
||||
cf_loop.o: cf.h
|
||||
cf_succ.o: ../../../h/em_flag.h
|
||||
cf_succ.o: ../../../h/em_mnem.h
|
||||
cf_succ.o: ../../../h/em_pseu.h
|
||||
cf_succ.o: ../../../h/em_spec.h
|
||||
cf_succ.o: ../share/cset.h
|
||||
cf_succ.o: ../share/debug.h
|
||||
cf_succ.o: ../share/def.h
|
||||
cf_succ.o: ../share/global.h
|
||||
cf_succ.o: ../share/lset.h
|
||||
cf_succ.o: ../share/map.h
|
||||
cf_succ.o: ../share/types.h
|
||||
cf_succ.o: cf.h
|
||||
520
util/ego/cf/cf.c
520
util/ego/cf/cf.c
@@ -1,520 +0,0 @@
|
||||
/* C O N T R O L F L O W
|
||||
*
|
||||
* M A I N R O U T I N E
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/map.h"
|
||||
#include "../share/files.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/cset.h"
|
||||
#include "../share/get.h"
|
||||
#include "../share/put.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_flag.h"
|
||||
#include "../share/def.h"
|
||||
#include "cf.h"
|
||||
#include "cf_succ.h"
|
||||
#include "cf_idom.h"
|
||||
#include "cf_loop.h"
|
||||
|
||||
#define newcfbx() (bext_p) newstruct(bext_cf)
|
||||
#define oldcfbx(x) oldstruct(bext_cf,x)
|
||||
|
||||
extern char em_flag[];
|
||||
|
||||
STATIC cset lpi_set; /* set of procedures used in LPI instruction */
|
||||
STATIC cset cai_set; /* set of all procedures doing a CAI */
|
||||
|
||||
|
||||
/* The procedure getbblocks reads the EM textfile and
|
||||
* partitions every procedure into a number of basic blocks.
|
||||
*/
|
||||
|
||||
#define LABEL0 0
|
||||
#define LABEL 1
|
||||
#define NORMAL 2
|
||||
#define JUMP 3
|
||||
#define END 4
|
||||
#define AFTERPRO 5
|
||||
#define INIT 6
|
||||
|
||||
|
||||
/* These global variables are used by getbblocks and nextblock. */
|
||||
|
||||
STATIC bblock_p b, *bp; /* b is the current basic block, bp is
|
||||
* the address where the next block has
|
||||
* to be linked.
|
||||
*/
|
||||
STATIC line_p lnp, *lp; /* lnp is the current line, lp is
|
||||
* the address where the next line
|
||||
* has to be linked.
|
||||
*/
|
||||
STATIC short state; /* We use a finite state machine with the
|
||||
* following states:
|
||||
* LABEL0: after the first (successive)
|
||||
* instruction label.
|
||||
* LABEL1: after at least two successive
|
||||
* instruction labels.
|
||||
* NORMAL: after a normal instruction.
|
||||
* JUMP: after a branch (conditional,
|
||||
* unconditional or CSA/CSB).
|
||||
* END: after an END pseudo
|
||||
* AFTERPRO: after we've read a PRO pseudo
|
||||
* INIT: initial state
|
||||
*/
|
||||
|
||||
|
||||
STATIC nextblock()
|
||||
{
|
||||
/* allocate a new basic block structure and
|
||||
* set b, bp and lp.
|
||||
*/
|
||||
|
||||
b = *bp = freshblock();
|
||||
bp = &b->b_next;
|
||||
b->b_start = lnp;
|
||||
b->b_succ = Lempty_set();
|
||||
b->b_pred = Lempty_set();
|
||||
b->b_extend = newcfbx(); /* basic block extension for CF */
|
||||
b->b_extend->bx_cf.bx_bucket = Lempty_set();
|
||||
b->b_extend->bx_cf.bx_semi = 0;
|
||||
lp = &lnp->l_next;
|
||||
#ifdef TRACE
|
||||
fprintf(stderr,"new basic block, id = %d\n",lastbid);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
STATIC short kind(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* determine if lnp is a label, branch, end or otherwise */
|
||||
|
||||
short instr;
|
||||
byte flow;
|
||||
|
||||
if ((instr = INSTR(lnp)) == op_lab) return (short) LABEL;
|
||||
if (instr == ps_end) return (short) END;
|
||||
if (instr > sp_lmnem) return (short) NORMAL; /* pseudo */
|
||||
if ((flow = (em_flag[instr-sp_fmnem] & EM_FLO)) == FLO_C ||
|
||||
flow == FLO_T) return (short) JUMP; /* conditional/uncond. jump */
|
||||
return (short) NORMAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool getbblocks(fp,kind_out,n_out,g_out,l_out)
|
||||
FILE *fp;
|
||||
short *kind_out;
|
||||
short *n_out;
|
||||
bblock_p *g_out;
|
||||
line_p *l_out;
|
||||
{
|
||||
bblock_p head = (bblock_p) 0;
|
||||
line_p headl = (line_p) 0;
|
||||
|
||||
curproc = (proc_p) 0;
|
||||
/* curproc will get a value when we encounter a PRO pseudo.
|
||||
* If there is no such pseudo, we're reading only data
|
||||
* declarations or messages (outside any proc.).
|
||||
*/
|
||||
curinp = fp;
|
||||
lastbid = (block_id) 0; /* block identier */
|
||||
state = INIT; /* initial state */
|
||||
bp = &head;
|
||||
|
||||
for (;;) {
|
||||
#ifdef TRACE
|
||||
fprintf(stderr,"state = %d\n",state);
|
||||
#endif
|
||||
switch(state) {
|
||||
case LABEL0:
|
||||
nextblock();
|
||||
/* Fall through !! */
|
||||
case LABEL:
|
||||
lbmap[INSTRLAB(lnp)] = b;
|
||||
/* The lbmap table contains for each
|
||||
* label_id the basic block of that label.
|
||||
*/
|
||||
lnp = read_line(&curproc);
|
||||
state = kind(lnp);
|
||||
if (state != END) {
|
||||
*lp = lnp;
|
||||
lp = &lnp->l_next;
|
||||
}
|
||||
break;
|
||||
case NORMAL:
|
||||
lnp = read_line(&curproc);
|
||||
if ( (state = kind(lnp)) == LABEL) {
|
||||
/* If we come accross a label
|
||||
* here, it must be the beginning
|
||||
* of a new basic block.
|
||||
*/
|
||||
state = LABEL0;
|
||||
} else {
|
||||
if (state != END) {
|
||||
*lp = lnp;
|
||||
lp = &lnp->l_next;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JUMP:
|
||||
lnp = read_line(&curproc);
|
||||
/* fall through ... */
|
||||
case AFTERPRO:
|
||||
switch(state = kind(lnp)) {
|
||||
case LABEL:
|
||||
state = LABEL0;
|
||||
break;
|
||||
case JUMP:
|
||||
case NORMAL:
|
||||
nextblock();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case END:
|
||||
*lp = lnp;
|
||||
#ifdef TRACE
|
||||
fprintf(stderr,"at end of proc, %d blocks\n",lastbid);
|
||||
#endif
|
||||
if (head == (bblock_p) 0) {
|
||||
*kind_out = LDATA;
|
||||
*l_out = headl;
|
||||
} else {
|
||||
*kind_out = LTEXT;
|
||||
*g_out = head;
|
||||
*n_out = (short) lastbid;
|
||||
/* number of basic blocks */
|
||||
}
|
||||
return TRUE;
|
||||
case INIT:
|
||||
lnp = read_line(&curproc);
|
||||
if (feof(curinp)) return FALSE;
|
||||
if (INSTR(lnp) == ps_pro) {
|
||||
state = AFTERPRO;
|
||||
} else {
|
||||
state = NORMAL;
|
||||
headl = lnp;
|
||||
lp = &lnp->l_next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC interproc_analysis(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Interprocedural analysis of a procedure p determines:
|
||||
* - all procedures called by p (the 'call graph')
|
||||
* - the set of objects changed by p (directly)
|
||||
* - whether p does a load-indirect (loi,lof etc.)
|
||||
* - whether p does a store-indirect (sti, stf etc.)
|
||||
* The changed/used variables information will be
|
||||
* transitively closed, i.e. if P calls Q and Q changes
|
||||
* a variable X, the P changes X too.
|
||||
* (The same applies for used variables and for use/store
|
||||
* indirect).
|
||||
* The transitive closure will be computed by main
|
||||
* after all procedures have been processed.
|
||||
*/
|
||||
|
||||
bblock_p b;
|
||||
line_p lnp;
|
||||
bool inloop;
|
||||
|
||||
/* Allocate memory for structs and sets */
|
||||
|
||||
p->p_use = newuse();
|
||||
p->p_change = newchange();
|
||||
p->p_change->c_ext = Cempty_set(olength);
|
||||
p->p_calling = Cempty_set(plength);
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
inloop = (Lnrelems(b->b_loops) > 0);
|
||||
for (lnp = b->b_start; lnp != (line_p) 0; lnp = lnp->l_next) {
|
||||
/* for all instructions of p do */
|
||||
switch(INSTR(lnp)) {
|
||||
case op_cal:
|
||||
Cadd(PROC(lnp)->p_id, &p->p_calling);
|
||||
/* add called proc to p_calling */
|
||||
if (inloop) {
|
||||
CALLED_IN_LOOP(PROC(lnp));
|
||||
}
|
||||
break;
|
||||
case op_cai:
|
||||
Cadd(p->p_id,&cai_set);
|
||||
break;
|
||||
case op_lpi:
|
||||
Cadd(PROC(lnp)->p_id, &lpi_set);
|
||||
/* All procedures that have their names used
|
||||
* in an lpi instruction, may be called via
|
||||
* a cai instruction.
|
||||
*/
|
||||
PROC(lnp)->p_flags1 |= PF_LPI;
|
||||
break;
|
||||
case op_ste:
|
||||
case op_sde:
|
||||
case op_ine:
|
||||
case op_dee:
|
||||
case op_zre:
|
||||
Cadd(OBJ(lnp)->o_id, &p->p_change->c_ext);
|
||||
/* Add changed object to c_ext */
|
||||
break;
|
||||
case op_lil:
|
||||
case op_lof:
|
||||
case op_loi:
|
||||
case op_los:
|
||||
case op_lar:
|
||||
p->p_use->u_flags |= UF_INDIR;
|
||||
/* p does a load-indirect */
|
||||
break;
|
||||
case op_sil:
|
||||
case op_stf:
|
||||
case op_sti:
|
||||
case op_sts:
|
||||
case op_sar:
|
||||
p->p_change->c_flags |= CF_INDIR;
|
||||
/* p does a store-indirect */
|
||||
break;
|
||||
case op_blm:
|
||||
case op_bls:
|
||||
p->p_use->u_flags |= UF_INDIR;
|
||||
p->p_change->c_flags |= CF_INDIR;
|
||||
/* p does both */
|
||||
break;
|
||||
case op_mon:
|
||||
printf("mon not yet implemented\n");
|
||||
break;
|
||||
case op_lxl:
|
||||
case op_lxa:
|
||||
curproc->p_flags1 |= PF_ENVIRON;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC cf_cleanproc(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Remove the extended data structures of p */
|
||||
|
||||
register bblock_p b;
|
||||
register Lindex pi;
|
||||
loop_p lp;
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
oldcfbx(b->b_extend);
|
||||
}
|
||||
for (pi = Lfirst(p->p_loops); pi != (Lindex) 0; pi = Lnext(pi,
|
||||
p->p_loops)) {
|
||||
lp = (loop_p) Lelem(pi);
|
||||
oldcflpx(lp->lp_extend);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define CHANGE_INDIR(ch) ((ch->c_flags & CF_INDIR) != 0)
|
||||
#define USE_INDIR(us) ((us->u_flags & UF_INDIR) != 0)
|
||||
#define CALLS_UNKNOWN(p) (p->p_flags1 & (byte) PF_CALUNKNOWN)
|
||||
#define BODY_KNOWN(p) (p->p_flags1 & (byte) PF_BODYSEEN)
|
||||
#define ENVIRON(p) (p->p_flags1 & (byte) PF_ENVIRON)
|
||||
|
||||
|
||||
STATIC bool add_info(q,p)
|
||||
proc_p q,p;
|
||||
{
|
||||
/* Determine the consequences for used/changed variables info
|
||||
* of the fact that p calls q. If e.g. q changes a variable X
|
||||
* then p changes this variable too. This routine is an
|
||||
* auxiliary routine of the transitive closure process.
|
||||
* The returned value indicates if there was any change in
|
||||
* the information of p.
|
||||
*/
|
||||
|
||||
change_p chp, chq;
|
||||
use_p usp, usq;
|
||||
bool diff = FALSE;
|
||||
|
||||
chp = p->p_change;
|
||||
chq = q->p_change;
|
||||
usp = p->p_use;
|
||||
usq = q->p_use;
|
||||
|
||||
if (!BODY_KNOWN(q)) {
|
||||
/* q is a procedure of which the body is not available
|
||||
* as EM text.
|
||||
*/
|
||||
if (CALLS_UNKNOWN(p)) {
|
||||
return FALSE;
|
||||
/* p already called an unknown procedure */
|
||||
} else {
|
||||
p->p_flags1 |= PF_CALUNKNOWN;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
if (CALLS_UNKNOWN(q)) {
|
||||
/* q calls a procedure of which the body is not available
|
||||
* as EM text.
|
||||
*/
|
||||
if (!CALLS_UNKNOWN(p)) {
|
||||
p->p_flags1 |= PF_CALUNKNOWN;
|
||||
diff = TRUE;
|
||||
}
|
||||
}
|
||||
if (IS_CALLED_IN_LOOP(p) && !IS_CALLED_IN_LOOP(q)) {
|
||||
CALLED_IN_LOOP(q);
|
||||
diff = TRUE;
|
||||
}
|
||||
if (!Cis_subset(chq->c_ext, chp->c_ext)) {
|
||||
/* q changes global variables (objects) that
|
||||
* p did not (yet) change. Add all variables
|
||||
* changed by q to the c_ext set of p.
|
||||
*/
|
||||
Cjoin(chq->c_ext, &chp->c_ext);
|
||||
diff = TRUE;
|
||||
}
|
||||
if (CHANGE_INDIR(chq) && !CHANGE_INDIR(chp)) {
|
||||
/* q does a change-indirect (sil etc.)
|
||||
* and p did not (yet).
|
||||
*/
|
||||
chp->c_flags |= CF_INDIR;
|
||||
diff = TRUE;
|
||||
}
|
||||
if (USE_INDIR(usq) && !USE_INDIR(usp)) {
|
||||
/* q does a use-indirect (lil etc.)
|
||||
* and p dis not (yet).
|
||||
*/
|
||||
usp->u_flags |= UF_INDIR;
|
||||
diff = TRUE;
|
||||
}
|
||||
if (ENVIRON(q) && !ENVIRON(p)) {
|
||||
/* q uses or changes local variables in its
|
||||
* environment while p does not (yet).
|
||||
*/
|
||||
p->p_flags1 |= PF_ENVIRON;
|
||||
diff = TRUE;
|
||||
}
|
||||
return diff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC trans_clos(head)
|
||||
proc_p head;
|
||||
{
|
||||
/* Compute the transitive closure of the used/changed
|
||||
* variable information.
|
||||
*/
|
||||
|
||||
register proc_p p,q;
|
||||
Cindex i;
|
||||
bool changes = TRUE;
|
||||
|
||||
while(changes) {
|
||||
changes = FALSE;
|
||||
for (p = head; p != (proc_p) 0; p = p->p_next) {
|
||||
if (!BODY_KNOWN(p)) continue;
|
||||
for (i = Cfirst(p->p_calling); i != (Cindex) 0;
|
||||
i = Cnext(i,p->p_calling)) {
|
||||
q = pmap[Celem(i)];
|
||||
if (add_info(q,p)) {
|
||||
changes = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
indir_calls()
|
||||
{
|
||||
Cindex i;
|
||||
proc_p p;
|
||||
|
||||
for (i = Cfirst(cai_set); i != (Cindex) 0; i = Cnext(i,cai_set)) {
|
||||
p = pmap[Celem(i)]; /* p does a CAI */
|
||||
Cjoin(lpi_set, &p->p_calling);
|
||||
}
|
||||
Cdeleteset(lpi_set);
|
||||
Cdeleteset(cai_set);
|
||||
}
|
||||
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
FILE *f, *f2, *gf2; /* The EM input, EM output, basic block output */
|
||||
bblock_p g;
|
||||
short n, kind;
|
||||
line_p l;
|
||||
|
||||
linecount = 0;
|
||||
fproc = getptable(pname); /* proc table */
|
||||
fdblock = getdtable(dname); /* data block table */
|
||||
lpi_set = Cempty_set(plength);
|
||||
cai_set = Cempty_set(plength);
|
||||
if ((f = fopen(lname,"r")) == NULL) {
|
||||
error("cannot open %s", lname);
|
||||
}
|
||||
if ((f2 = fopen(lname2,"w")) == NULL) {
|
||||
error("cannot open %s", lname2);
|
||||
}
|
||||
if ((gf2 = fopen(bname2,"w")) == NULL) {
|
||||
error("cannot open %s",bname2);
|
||||
}
|
||||
while (getbblocks(f,&kind,&n,&g,&l)) {
|
||||
/* read EM text of one unit and
|
||||
* (if it is a procedure)
|
||||
* partition it into n basic blocks.
|
||||
*/
|
||||
if (kind == LDATA) {
|
||||
putunit(LDATA,(proc_p) 0,l,gf2,f2);
|
||||
} else {
|
||||
curproc->p_start = g;
|
||||
/* The global variable curproc points to the
|
||||
* current procedure. It is set by getbblocks
|
||||
*/
|
||||
control_flow(g); /* compute pred and succ */
|
||||
dominators(g,n); /* compute immediate dominators */
|
||||
loop_detection(curproc); /* compute loops */
|
||||
interproc_analysis(curproc);
|
||||
/* Interprocedural analysis */
|
||||
cf_cleanproc(curproc);
|
||||
putunit(LTEXT,curproc,(line_p) 0,gf2,f2);
|
||||
/* output control flow graph + text */
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
fclose(f2);
|
||||
fclose(gf2);
|
||||
indir_calls();
|
||||
trans_clos(fproc);
|
||||
/* Compute transitive closure of used/changed
|
||||
* variables information for every procedure.
|
||||
*/
|
||||
if ((f = fopen(dname2,"w")) == NULL) {
|
||||
error("cannot open %s",dname2);
|
||||
}
|
||||
putdtable(fdblock,f);
|
||||
if ((f = fopen(pname2,"w")) == NULL) {
|
||||
error("cannot open %s",pname2);
|
||||
}
|
||||
putptable(fproc,f,TRUE);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/* C O N T R O L F L O W */
|
||||
|
||||
/* Macro's for extended data structures: */
|
||||
|
||||
#define B_SEMI b_extend->bx_cf.bx_semi
|
||||
#define B_PARENT b_extend->bx_cf.bx_parent
|
||||
#define B_BUCKET b_extend->bx_cf.bx_bucket
|
||||
#define B_ANCESTOR b_extend->bx_cf.bx_ancestor
|
||||
#define B_LABEL b_extend->bx_cf.bx_label
|
||||
|
||||
#define LP_BLOCKS lp_extend->lpx_cf.lpx_blocks
|
||||
#define LP_COUNT lp_extend->lpx_cf.lpx_count
|
||||
#define LP_MESSY lp_extend->lpx_cf.lpx_messy
|
||||
|
||||
#define newcflpx() (lpext_p) newstruct(lpext_cf)
|
||||
#define oldcflpx(x) oldstruct(lpext_cf,x)
|
||||
@@ -1,138 +0,0 @@
|
||||
/* C O N T R O L F L O W
|
||||
*
|
||||
* C F _ I D O M . C
|
||||
*/
|
||||
|
||||
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "cf.h"
|
||||
|
||||
|
||||
/* The algorithm for finding dominators in a flowgraph
|
||||
* that is used here, was developed by Thomas Lengauer
|
||||
* and Robert E. Tarjan of Stanford University.
|
||||
* The algorithm is described in their article:
|
||||
* A Fast Algorithm for Finding Dominators
|
||||
* in a Flowgraph
|
||||
* which was published in:
|
||||
* ACM Transactions on Programming Languages and Systems,
|
||||
* Vol. 1, No. 1, July 1979, Pages 121-141.
|
||||
*/
|
||||
|
||||
|
||||
#define UNREACHABLE(b) (b->B_SEMI == (short) 0)
|
||||
|
||||
short dfs_nr;
|
||||
bblock_p *vertex; /* dynamically allocated array */
|
||||
|
||||
|
||||
STATIC dfs(v)
|
||||
bblock_p v;
|
||||
{
|
||||
/* Depth First Search */
|
||||
|
||||
Lindex i;
|
||||
bblock_p w;
|
||||
|
||||
v->B_SEMI = ++dfs_nr;
|
||||
vertex[dfs_nr] = v->B_LABEL = v;
|
||||
v->B_ANCESTOR = (bblock_p) 0;
|
||||
for (i = Lfirst(v->b_succ); i != (Lindex) 0; i = Lnext(i,v->b_succ)) {
|
||||
w = (bblock_p) Lelem(i);
|
||||
if (w->B_SEMI == 0) {
|
||||
w->B_PARENT = v;
|
||||
dfs(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC compress(v)
|
||||
bblock_p v;
|
||||
{
|
||||
if (v->B_ANCESTOR->B_ANCESTOR != (bblock_p) 0) {
|
||||
compress(v->B_ANCESTOR);
|
||||
if (v->B_ANCESTOR->B_LABEL->B_SEMI < v->B_LABEL->B_SEMI) {
|
||||
v->B_LABEL = v->B_ANCESTOR->B_LABEL;
|
||||
}
|
||||
v->B_ANCESTOR = v->B_ANCESTOR->B_ANCESTOR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bblock_p eval(v)
|
||||
bblock_p v;
|
||||
{
|
||||
if (v->B_ANCESTOR == (bblock_p) 0) {
|
||||
return v;
|
||||
} else {
|
||||
compress(v);
|
||||
return v->B_LABEL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC linkblocks(v,w)
|
||||
bblock_p v,w;
|
||||
{
|
||||
w->B_ANCESTOR = v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
dominators(r,n)
|
||||
bblock_p r;
|
||||
short n;
|
||||
{
|
||||
/* Compute the immediate dominator of every basic
|
||||
* block in the control flow graph rooted by r.
|
||||
*/
|
||||
|
||||
register short i;
|
||||
Lindex ind, next;
|
||||
bblock_p v,w,u;
|
||||
|
||||
dfs_nr = 0;
|
||||
vertex = (bblock_p *) newmap(n);
|
||||
/* allocate vertex (dynamic array). All remaining
|
||||
* initializations were done by the routine
|
||||
* nextblock of get.c.
|
||||
*/
|
||||
dfs(r);
|
||||
for (i = dfs_nr; i > 1; i--) {
|
||||
w = vertex[i];
|
||||
for (ind = Lfirst(w->b_pred); ind != (Lindex) 0;
|
||||
ind = Lnext(ind,w->b_pred)) {
|
||||
v = (bblock_p) Lelem(ind);
|
||||
if (UNREACHABLE(v)) continue;
|
||||
u = eval(v);
|
||||
if (u->B_SEMI < w->B_SEMI) {
|
||||
w->B_SEMI = u->B_SEMI;
|
||||
}
|
||||
}
|
||||
Ladd(w,&(vertex[w->B_SEMI]->B_BUCKET));
|
||||
linkblocks(w->B_PARENT,w);
|
||||
for (ind = Lfirst(w->B_PARENT->B_BUCKET); ind != (Lindex) 0;
|
||||
ind = next) {
|
||||
next = Lnext(ind,w->B_PARENT->B_BUCKET);
|
||||
v = (bblock_p) Lelem(ind);
|
||||
Lremove(v,&w->B_PARENT->B_BUCKET);
|
||||
u = eval(v);
|
||||
v->b_idom = (u->B_SEMI < v->B_SEMI ? u : w->B_PARENT);
|
||||
}
|
||||
}
|
||||
for (i = 2; i <= dfs_nr; i++) {
|
||||
w = vertex[i];
|
||||
if (w->b_idom != vertex[w->B_SEMI]) {
|
||||
w->b_idom = w->b_idom->b_idom;
|
||||
}
|
||||
}
|
||||
r->b_idom = (bblock_p) 0;
|
||||
oldmap(vertex,n); /* release memory for dynamic array vertex */
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/* C O N T R O L F L O W
|
||||
*
|
||||
* I M M E D I A T E D O M I N A T O R S
|
||||
*/
|
||||
|
||||
|
||||
extern dominator(); /* (bblock_p head, short n)
|
||||
* Compute for every basic block its immediate
|
||||
* dominator. The dominator relation is hence
|
||||
* recorded as a tree in which every node contains
|
||||
* a pointer to its parent, which is its
|
||||
* immediate dominator.
|
||||
* 'n' is the number of nodes (basic blocks) in
|
||||
* the control flow graph.
|
||||
*/
|
||||
@@ -1,400 +0,0 @@
|
||||
/* C O N T R O L F L O W
|
||||
*
|
||||
* C F _ L O O P . C
|
||||
*/
|
||||
|
||||
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/aux.h"
|
||||
#include "cf.h"
|
||||
|
||||
#define MARK_STRONG(b) b->b_flags |= BF_STRONG
|
||||
#define MARK_FIRM(b) b->b_flags |= BF_FIRM
|
||||
#define BF_MARK 04
|
||||
#define MARK(b) b->b_flags |= BF_MARK
|
||||
#define MARKED(b) (b->b_flags&BF_MARK)
|
||||
#define INSIDE_LOOP(b,lp) Lis_elem(b,lp->LP_BLOCKS)
|
||||
|
||||
|
||||
|
||||
/* The algorithm to detect loops that is used here is taken
|
||||
* from: Aho & Ullman, Principles of Compiler Design, section 13.1.
|
||||
* The algorithm uses the dominator relation between nodes
|
||||
* of the control flow graph:
|
||||
* d DOM n => every path from the initial node to n goes through d.
|
||||
* The dominator relation is recorded via the immediate dominator tree
|
||||
* (b_idom field of bblock struct) from which the dominator relation
|
||||
* can be easily computed (see procedure 'dom' below).
|
||||
* The algorithm first finds 'back edges'. A back edge is an edge
|
||||
* a->b in the flow graph whose head (b) dominates its tail (a).
|
||||
* The 'natural loop' of back edge n->d consists of those nodes
|
||||
* that can reach n without going through d. These nodes, plus d
|
||||
* form the loop.
|
||||
* The whole process is rather complex, because different back edges
|
||||
* may result in the same loop and because loops may partly overlap
|
||||
* each other (without one being nested inside the other).
|
||||
*/
|
||||
|
||||
|
||||
|
||||
STATIC bool same_loop(l1,l2)
|
||||
loop_p l1,l2;
|
||||
{
|
||||
/* Two loops are the same if:
|
||||
* (1) they have the same number of basic blocks, and
|
||||
* (2) the head of the back edge of the first loop
|
||||
* also is part of the second loop, and
|
||||
* (3) the tail of the back edge of the first loop
|
||||
* also is part of the second loop.
|
||||
*/
|
||||
|
||||
return (l1->LP_COUNT == l2->LP_COUNT &&
|
||||
Lis_elem(l1->lp_entry, l2->LP_BLOCKS) &&
|
||||
Lis_elem(l1->lp_end, l2->LP_BLOCKS));
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool inner_loop(l1,l2)
|
||||
loop_p l1,l2;
|
||||
{
|
||||
/* Loop l1 is an inner loop of l2 if:
|
||||
* (1) the first loop has fewer basic blocks than
|
||||
* the second one, and
|
||||
* (2) the head of the back edge of the first loop
|
||||
* also is part of the second loop, and
|
||||
* (3) the tail of the back edge of the first loop
|
||||
* also is part of the second loop.
|
||||
*/
|
||||
|
||||
return (l1->LP_COUNT < l2->LP_COUNT &&
|
||||
Lis_elem(l1->lp_entry, l2->LP_BLOCKS) &&
|
||||
Lis_elem(l1->lp_end, l2->LP_BLOCKS));
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC insrt(b,lpb,s_p)
|
||||
bblock_p b;
|
||||
lset *lpb;
|
||||
lset *s_p;
|
||||
{
|
||||
/* Auxiliary routine used by 'natural_loop'.
|
||||
* Note that we use a set rather than a stack,
|
||||
* as Aho & Ullman do.
|
||||
*/
|
||||
|
||||
if (!Lis_elem(b,*lpb)) {
|
||||
Ladd(b,lpb);
|
||||
Ladd(b,s_p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC loop_p natural_loop(d,n)
|
||||
bblock_p d,n;
|
||||
{
|
||||
/* Find the basic blocks of the natural loop of the
|
||||
* back edge 'n->d' (i.e. n->d is an edge in the control
|
||||
* flow graph and d dominates n). The natural loop consists
|
||||
* of those blocks which can reach n without going through d.
|
||||
* We find these blocks by finding all predecessors of n,
|
||||
* up to d.
|
||||
*/
|
||||
|
||||
loop_p lp;
|
||||
bblock_p m;
|
||||
lset loopblocks;
|
||||
Lindex pi;
|
||||
lset s;
|
||||
|
||||
lp = newloop();
|
||||
lp->lp_extend = newcflpx();
|
||||
lp->lp_entry = d; /* loop entry block */
|
||||
lp->lp_end = n; /* tail of back edge */
|
||||
s = Lempty_set();
|
||||
loopblocks = Lempty_set();
|
||||
Ladd(d,&loopblocks);
|
||||
insrt(n,&loopblocks,&s);
|
||||
while ((pi = Lfirst(s)) != (Lindex) 0) {
|
||||
m = (bblock_p) Lelem(pi);
|
||||
Lremove(m,&s);
|
||||
for (pi = Lfirst(m->b_pred); pi != (Lindex) 0;
|
||||
pi = Lnext(pi,m->b_pred)) {
|
||||
insrt((bblock_p) Lelem(pi),&loopblocks,&s);
|
||||
}
|
||||
}
|
||||
lp->LP_BLOCKS = loopblocks;
|
||||
lp->LP_COUNT = Lnrelems(loopblocks);
|
||||
return lp;
|
||||
}
|
||||
|
||||
|
||||
STATIC loop_p org_loop(lp,loops)
|
||||
loop_p lp;
|
||||
lset loops;
|
||||
{
|
||||
/* See if the loop lp was already found via another
|
||||
* back edge; if so return this loop; else return 0.
|
||||
*/
|
||||
|
||||
register Lindex li;
|
||||
|
||||
for (li = Lfirst(loops); li != (Lindex) 0; li = Lnext(li,loops)) {
|
||||
if (same_loop((loop_p) Lelem(li), lp)) {
|
||||
#ifdef DEBUG
|
||||
/* printf("messy loop found\n"); */
|
||||
#endif
|
||||
return (loop_p) Lelem(li);
|
||||
}
|
||||
}
|
||||
return (loop_p) 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC collapse_loops(loops_p)
|
||||
lset *loops_p;
|
||||
{
|
||||
register Lindex li1, li2;
|
||||
register loop_p lp1,lp2;
|
||||
|
||||
for (li1 = Lfirst(*loops_p); li1 != (Lindex) 0; li1 = Lnext(li1,*loops_p)) {
|
||||
lp1 = (loop_p) Lelem(li1);
|
||||
lp1->lp_level = (short) 0;
|
||||
for (li2 = Lfirst(*loops_p); li2 != (Lindex) 0;
|
||||
li2 = Lnext(li2,*loops_p)) {
|
||||
lp2 = (loop_p) Lelem(li2);
|
||||
if (lp1 != lp2 && lp1->lp_entry == lp2->lp_entry) {
|
||||
Ljoin(lp2->LP_BLOCKS,&lp1->LP_BLOCKS);
|
||||
oldcflpx(lp2->lp_extend);
|
||||
Lremove(lp2,loops_p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC loop_per_block(lp)
|
||||
loop_p lp;
|
||||
{
|
||||
bblock_p b;
|
||||
|
||||
/* Update the b_loops sets */
|
||||
|
||||
register Lindex bi;
|
||||
|
||||
for (bi = Lfirst(lp->LP_BLOCKS); bi != (Lindex) 0;
|
||||
bi = Lnext(bi,lp->LP_BLOCKS)) {
|
||||
b = (bblock_p) Lelem(bi);
|
||||
Ladd(lp,&(b->b_loops));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC loop_attrib(loops)
|
||||
lset loops;
|
||||
{
|
||||
/* Compute several attributes */
|
||||
|
||||
register Lindex li;
|
||||
register loop_p lp;
|
||||
loop_id lastlpid = 0;
|
||||
|
||||
for (li = Lfirst(loops); li != (Lindex) 0; li = Lnext(li,loops)) {
|
||||
lp = (loop_p) Lelem(li);
|
||||
lp->lp_id = ++lastlpid;
|
||||
loop_per_block(lp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC nest_levels(loops)
|
||||
lset loops;
|
||||
{
|
||||
/* Compute the nesting levels of all loops of
|
||||
* the current procedure. For every loop we just count
|
||||
* all loops of which the former is an inner loop.
|
||||
* The running time is quadratic in the number of loops
|
||||
* of the current procedure. As this number tends to be
|
||||
* very small, there is no cause for alarm.
|
||||
*/
|
||||
|
||||
register Lindex li1, li2;
|
||||
register loop_p lp;
|
||||
|
||||
for (li1 = Lfirst(loops); li1 != (Lindex) 0; li1 = Lnext(li1,loops)) {
|
||||
lp = (loop_p) Lelem(li1);
|
||||
lp->lp_level = (short) 0;
|
||||
for (li2 = Lfirst(loops); li2 != (Lindex) 0;
|
||||
li2 = Lnext(li2,loops)) {
|
||||
if (inner_loop(lp,(loop_p) Lelem(li2))) {
|
||||
lp->lp_level++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC cleanup(loops)
|
||||
lset loops;
|
||||
{
|
||||
/* Throw away the LP_BLOCKS sets */
|
||||
|
||||
register Lindex i;
|
||||
|
||||
for (i = Lfirst(loops); i != (Lindex) 0; i = Lnext(i,loops)) {
|
||||
Ldeleteset(((loop_p) Lelem(i))->LP_BLOCKS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC bool does_exit(b,lp)
|
||||
bblock_p b;
|
||||
loop_p lp;
|
||||
{
|
||||
/* See if b may exit the loop, i.e. if it
|
||||
* has a successor outside the loop
|
||||
*/
|
||||
|
||||
Lindex i;
|
||||
|
||||
for (i = Lfirst(b->b_succ); i != (Lindex) 0; i = Lnext(i,b->b_succ)) {
|
||||
if (!INSIDE_LOOP(Lelem(i),lp)) return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
STATIC mark_succ(b,lp)
|
||||
bblock_p b;
|
||||
loop_p lp;
|
||||
{
|
||||
Lindex i;
|
||||
bblock_p succ;
|
||||
|
||||
for (i = Lfirst(b->b_succ); i != (Lindex) 0; i = Lnext(i,b->b_succ)) {
|
||||
succ = (bblock_p) Lelem(i);
|
||||
if (succ != b && succ != lp->lp_entry && INSIDE_LOOP(succ,lp) &&
|
||||
!MARKED(succ)) {
|
||||
MARK(succ);
|
||||
mark_succ(succ,lp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC mark_blocks(lp)
|
||||
loop_p lp;
|
||||
{
|
||||
/* Mark the strong and firm blocks of a loop.
|
||||
* The last set of blocks consists of the end-block
|
||||
* of the loop (i.e. the head of the back edge
|
||||
* of the natural loop) and its dominators
|
||||
* (including the loop entry block, i.e. the
|
||||
* tail of the back edge).
|
||||
*/
|
||||
|
||||
register bblock_p b;
|
||||
|
||||
/* First mark all blocks that are the successor of a
|
||||
* block that may exit the loop (i.e. contains a
|
||||
* -possibly conditional- jump to somewhere outside
|
||||
* the loop.
|
||||
*/
|
||||
|
||||
if (lp->LP_MESSY) return; /* messy loops are hopeless cases */
|
||||
for (b = lp->lp_entry; b != (bblock_p) 0; b = b->b_next) {
|
||||
if (!MARKED(b) && does_exit(b,lp)) {
|
||||
mark_succ(b,lp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now find all firm blocks. A block is strong
|
||||
* if it is firm and not marked.
|
||||
*/
|
||||
|
||||
for (b = lp->lp_end; ; b = b->b_idom) {
|
||||
MARK_FIRM(b);
|
||||
if (!MARKED(b)) {
|
||||
MARK_STRONG(b);
|
||||
}
|
||||
if (b == lp->lp_entry) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC mark_loopblocks(loops)
|
||||
lset loops;
|
||||
{
|
||||
/* Determine for all loops which basic blocks
|
||||
* of the loop are strong (i.e. are executed
|
||||
* during every iteration) and which blocks are
|
||||
* firm (i.e. executed during every iteration with
|
||||
* the only possible exception of the last one).
|
||||
*/
|
||||
|
||||
Lindex i;
|
||||
loop_p lp;
|
||||
|
||||
for (i = Lfirst(loops); i != (Lindex) 0; i = Lnext(i,loops)) {
|
||||
lp = (loop_p) Lelem(i);
|
||||
mark_blocks(lp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
loop_detection(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Find all natural loops of procedure p. Every loop is
|
||||
* assigned a unique identifying number, a set of basic
|
||||
* blocks, a loop entry block and a nesting level number.
|
||||
* Every basic block is assigned a nesting level number
|
||||
* and a set of loops it is part of.
|
||||
*/
|
||||
|
||||
lset loops; /* the set of all loops */
|
||||
loop_p lp,org;
|
||||
register bblock_p b;
|
||||
bblock_p s;
|
||||
Lindex si;
|
||||
|
||||
loops = Lempty_set();
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
for (si = Lfirst(b->b_succ); si != (Lindex) 0;
|
||||
si = Lnext(si,b->b_succ)) {
|
||||
s = (bblock_p) Lelem(si);
|
||||
if (dom(s,b)) {
|
||||
/* 'b->s' is a back edge */
|
||||
lp = natural_loop(s,b);
|
||||
if ((org = org_loop(lp,loops)) == (loop_p) 0) {
|
||||
/* new loop */
|
||||
Ladd(lp,&loops);
|
||||
} else {
|
||||
/* Same loop, generated by several back
|
||||
* edges; such a loop is called a messy
|
||||
* loop.
|
||||
*/
|
||||
org->LP_MESSY = TRUE;
|
||||
Ldeleteset(lp->LP_BLOCKS);
|
||||
oldcflpx(lp->lp_extend);
|
||||
oldloop(lp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
collapse_loops(&loops);
|
||||
loop_attrib(loops);
|
||||
nest_levels(loops);
|
||||
mark_loopblocks(loops); /* determine firm and strong blocks */
|
||||
cleanup(loops);
|
||||
p->p_loops = loops;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
/* C O N T R O L F L O W
|
||||
*
|
||||
* L O O P D E T E C T I O N
|
||||
*/
|
||||
|
||||
extern loop_detection(); /* (proc_p p)
|
||||
* Detect all loops of procedure p.
|
||||
* Every basic block of p is assigned
|
||||
* a set of all loops it is part of.
|
||||
* For every loop we record the number
|
||||
* of blocks it contains, the loop entry
|
||||
* block and its nesting level (0 = outer
|
||||
* loop, 1 = loop within loop etc.).
|
||||
*/
|
||||
@@ -1,250 +0,0 @@
|
||||
/* C O N T R O L F L O W
|
||||
*
|
||||
* C F _ S U C C . C
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "../share/def.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/cset.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_flag.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "cf.h"
|
||||
#include "../share/map.h"
|
||||
|
||||
extern char em_flag[];
|
||||
|
||||
|
||||
STATIC succeeds(succ,pred)
|
||||
bblock_p succ, pred;
|
||||
{
|
||||
assert(pred != (bblock_p) 0);
|
||||
if (succ != (bblock_p) 0) {
|
||||
Ladd(succ, &pred->b_succ);
|
||||
Ladd(pred, &succ->b_pred);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define IS_RETURN(i) (i == op_ret || i == op_rtt)
|
||||
#define IS_CASE_JUMP(i) (i == op_csa || i == op_csb)
|
||||
#define IS_UNCOND_JUMP(i) (i <= sp_lmnem && (em_flag[i-sp_fmnem] & EM_FLO) == FLO_T)
|
||||
#define IS_COND_JUMP(i) (i <= sp_lmnem && (em_flag[i-sp_fmnem] & EM_FLO) == FLO_C)
|
||||
#define TARGET(lnp) (lbmap[INSTRLAB(lnp)])
|
||||
#define ATARGET(arg) (lbmap[arg->a_a.a_instrlab])
|
||||
|
||||
|
||||
|
||||
STATIC arg_p skip_const(arg)
|
||||
arg_p arg;
|
||||
{
|
||||
assert(arg != (arg_p) 0);
|
||||
switch(arg->a_type) {
|
||||
case ARGOFF:
|
||||
case ARGICN:
|
||||
case ARGUCN:
|
||||
break;
|
||||
default:
|
||||
error("bad case descriptor");
|
||||
}
|
||||
return arg->a_next;
|
||||
}
|
||||
|
||||
|
||||
STATIC arg_p use_label(arg,b)
|
||||
arg_p arg;
|
||||
bblock_p b;
|
||||
{
|
||||
if (arg->a_type == ARGINSTRLAB) {
|
||||
/* arg is a non-null label */
|
||||
succeeds(ATARGET(arg),b);
|
||||
}
|
||||
return arg->a_next;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC case_flow(instr,desc,b)
|
||||
short instr;
|
||||
line_p desc;
|
||||
bblock_p b;
|
||||
{
|
||||
/* Analyse the case descriptor (given as a ROM pseudo instruction).
|
||||
* Every instruction label appearing in the descriptor
|
||||
* heads a basic block that is a successor of the block
|
||||
* in which the case instruction appears (b).
|
||||
*/
|
||||
|
||||
register arg_p arg;
|
||||
|
||||
assert(instr == op_csa || instr == op_csb);
|
||||
assert(TYPE(desc) == OPLIST);
|
||||
arg = ARG(desc);
|
||||
arg = use_label(arg,b);
|
||||
/* See if there is a default label. If so, then
|
||||
* its block is a successor of b. Set arg to
|
||||
* next argument.
|
||||
*/
|
||||
if (instr == op_csa) {
|
||||
arg = skip_const(arg); /* skip lower bound */
|
||||
arg = skip_const(arg); /* skip lower-upper bound */
|
||||
while (arg != (arg_p) 0) {
|
||||
/* All following arguments are case labels
|
||||
* or zeroes.
|
||||
*/
|
||||
arg = use_label(arg,b);
|
||||
}
|
||||
} else {
|
||||
/* csb instruction */
|
||||
arg = skip_const(arg); /* skip #entries */
|
||||
while (arg != (arg_p) 0) {
|
||||
/* All following arguments are alternatively
|
||||
* an index and an instruction label (possibly 0).
|
||||
*/
|
||||
arg = skip_const(arg); /* skip index */
|
||||
arg = use_label(arg,b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC line_p case_descr(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* lnp is the instruction just before a csa or csb,
|
||||
* so it is the instruction that pushes the address
|
||||
* of a case descriptor on the stack. Find that
|
||||
* descriptor, i.e. a rom pseudo instruction.
|
||||
* Note that this instruction will always be part
|
||||
* of the procedure in which the csa/csb occurs.
|
||||
*/
|
||||
|
||||
register line_p l;
|
||||
dblock_p d;
|
||||
obj_p obj;
|
||||
dblock_id id;
|
||||
|
||||
if (lnp == (line_p) 0 || (INSTR(lnp)) != op_lae) {
|
||||
error("cannot find 'lae descr' before csa/csb");
|
||||
}
|
||||
/* We'll first find the ROM and its dblock_id */
|
||||
obj = OBJ(lnp);
|
||||
if (obj->o_off != (offset) 0) {
|
||||
error("bad 'lae descr' before csa/csb");
|
||||
/* We require a descriptor to be an entire rom,
|
||||
* not part of a rom.
|
||||
*/
|
||||
}
|
||||
d = obj->o_dblock;
|
||||
assert(d != (dblock_p) 0);
|
||||
if (d->d_pseudo != DROM) {
|
||||
error("case descriptor must be in rom");
|
||||
}
|
||||
id = d->d_id;
|
||||
/* We'll use the dblock_id to find the defining occurrence
|
||||
* of the rom in the EM text (i.e. a rom pseudo). As all
|
||||
* pseudos appear at the beginning of a procedure, we only
|
||||
* have to look in its first basic block.
|
||||
*/
|
||||
assert(curproc != (proc_p) 0);
|
||||
assert(curproc->p_start != (bblock_p) 0);
|
||||
l = curproc->p_start->b_start; /* first instruction of curproc */
|
||||
while (l != (line_p) 0) {
|
||||
if ((INSTR(l)) == ps_sym &&
|
||||
SHORT(l) == id) {
|
||||
/* found! */
|
||||
assert((INSTR(l->l_next)) == ps_rom);
|
||||
return l->l_next;
|
||||
}
|
||||
l = l->l_next;
|
||||
}
|
||||
error("cannot find rom pseudo for case descriptor");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC last2_instrs(b,last_out,prev_out)
|
||||
bblock_p b;
|
||||
line_p *last_out,*prev_out;
|
||||
{
|
||||
/* Determine the last and one-but-last instruction
|
||||
* of basic block b. An end-pseudo is not regarded
|
||||
* as an instruction. If the block contains only 1
|
||||
* instruction, prev_out is 0.
|
||||
*/
|
||||
|
||||
register line_p l1,l2;
|
||||
|
||||
l2 = b->b_start; /* first instruction of b */
|
||||
assert(l2 != (line_p) 0); /* block can not be empty */
|
||||
if ((l1 = l2->l_next) == (line_p) 0 || INSTR(l1) == ps_end) {
|
||||
*last_out = l2; /* single instruction */
|
||||
*prev_out = (line_p) 0;
|
||||
} else {
|
||||
while(l1->l_next != (line_p) 0 && INSTR(l1->l_next) != ps_end) {
|
||||
l2 = l1;
|
||||
l1 = l1->l_next;
|
||||
}
|
||||
*last_out = l1;
|
||||
*prev_out = l2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
control_flow(head)
|
||||
bblock_p head;
|
||||
{
|
||||
/* compute the successor and predecessor relation
|
||||
* for every basic block.
|
||||
*/
|
||||
|
||||
register bblock_p b;
|
||||
line_p lnp, prev;
|
||||
short instr;
|
||||
|
||||
for (b = head; b != (bblock_p) 0; b = b->b_next) {
|
||||
/* for every basic block, in textual order, do */
|
||||
last2_instrs(b, &lnp, &prev);
|
||||
/* find last and one-but-last instruction */
|
||||
instr = INSTR(lnp);
|
||||
/* The last instruction of the basic block
|
||||
* determines the set of successors of the block.
|
||||
*/
|
||||
if (IS_CASE_JUMP(instr)) {
|
||||
case_flow(instr,case_descr(prev),b);
|
||||
/* If lnp is a csa or csb, then the instruction
|
||||
* just before it (i.e. prev) must be the
|
||||
* instruction that pushes the address of the
|
||||
* case descriptor. This descriptor is found
|
||||
* and analysed in order to build the successor
|
||||
* and predecessor sets of b.
|
||||
*/
|
||||
} else {
|
||||
if (!IS_RETURN(instr)) {
|
||||
if (IS_UNCOND_JUMP(instr)) {
|
||||
succeeds(TARGET(lnp),b);
|
||||
} else {
|
||||
if (IS_COND_JUMP(instr)) {
|
||||
succeeds(TARGET(lnp),b);
|
||||
succeeds(b->b_next, b);
|
||||
/* Textually next block is
|
||||
* a successor of b.
|
||||
*/
|
||||
} else {
|
||||
/* normal instruction */
|
||||
succeeds(b->b_next, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
/* C O N T R O L F L O W
|
||||
*
|
||||
* S U C C E S S O R / P R E D E C E S S O R R E L A T I O N S
|
||||
*/
|
||||
|
||||
extern control_flow(); /* (bblock_p head)
|
||||
* Compute for every basic block
|
||||
* its successors and predecessors
|
||||
* in the control flow graph.
|
||||
*/
|
||||
@@ -1,60 +0,0 @@
|
||||
EMH=../../../h
|
||||
EMLIB=../../../lib
|
||||
SHR=../share
|
||||
|
||||
CFILES=\
|
||||
cj.c
|
||||
|
||||
OFILES=\
|
||||
cj.o
|
||||
|
||||
HFILES=
|
||||
|
||||
PRFILES=\
|
||||
$(CFILES) $(HFILES) Makefile
|
||||
|
||||
SHARE_OFILES=\
|
||||
$(SHR)/get.o $(SHR)/put.o $(SHR)/alloc.o $(SHR)/global.o $(SHR)/debug.o \
|
||||
$(SHR)/files.o $(SHR)/map.o $(SHR)/lset.o $(SHR)/cset.o $(SHR)/aux.o \
|
||||
$(SHR)/stack_chg.o $(SHR)/go.o
|
||||
|
||||
SHARE_MFILES=\
|
||||
$(SHR)/get.m $(SHR)/put.m $(SHR)/alloc.m $(SHR)/global.m $(SHR)/debug.m \
|
||||
$(SHR)/files.m $(SHR)/map.m $(SHR)/lset.m $(SHR)/cset.m $(SHR)/aux.m $(SHR)/stack_chg.m $(SHR)/go.m
|
||||
|
||||
cj: $(OFILES)
|
||||
$(CC) -o \
|
||||
cj $(LDFLAGS) $(OFILES) $(SHARE_OFILES) $(EMLIB)/em_data.a
|
||||
|
||||
cj_ack: $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -c.o $(CFLAGS) $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -o cj -.c $(LDFLAGS) cj.o $(EMLIB)/em_data.a
|
||||
|
||||
lint:
|
||||
lint $(LINTFLAGS) $(CPPFLAGS) $(CFILES)
|
||||
|
||||
pr: $(PRFILES)
|
||||
@pr $?
|
||||
@touch pr
|
||||
|
||||
depend:
|
||||
$(SHR)/makedepend
|
||||
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
|
||||
cj.o: ../../../h/em_mnem.h
|
||||
cj.o: ../../../h/em_spec.h
|
||||
cj.o: ../share/alloc.h
|
||||
cj.o: ../share/aux.h
|
||||
cj.o: ../share/debug.h
|
||||
cj.o: ../share/def.h
|
||||
cj.o: ../share/files.h
|
||||
cj.o: ../share/get.h
|
||||
cj.o: ../share/global.h
|
||||
cj.o: ../share/go.h
|
||||
cj.o: ../share/lset.h
|
||||
cj.o: ../share/map.h
|
||||
cj.o: ../share/put.h
|
||||
cj.o: ../share/stack_chg.h
|
||||
cj.o: ../share/types.h
|
||||
355
util/ego/cj/cj.c
355
util/ego/cj/cj.c
@@ -1,355 +0,0 @@
|
||||
/* C R O S S J U M P I N G
|
||||
*
|
||||
* CJ.H
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/files.h"
|
||||
#include "../share/get.h"
|
||||
#include "../share/put.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/map.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/def.h"
|
||||
#include "../share/stack_chg.h"
|
||||
#include "../share/go.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
|
||||
|
||||
/* Cross jumping performs optimzations like:
|
||||
*
|
||||
* if cond then goto L1; if cond then goto L1
|
||||
* S1; -----> S1;
|
||||
* S2; goto L3;
|
||||
* goto L2; L1:
|
||||
* L1: S3;
|
||||
* S3; L3:
|
||||
* S2; S2;
|
||||
* L2:
|
||||
*
|
||||
* CJ looks for two basic blocks b1 and b2 with the following properties:
|
||||
* - there exists a basic block S such that SUCC(b1) = SUCC(b2) = {S}
|
||||
* (so both have only 1 successor)
|
||||
* - the last N (N > 0) instructions of b1 and b2, not counting a possible
|
||||
* BRAnch instruction, are the same.
|
||||
* As a result of the first condition, at least of the two blocks must end
|
||||
* on an (unconditional) BRAnch instruction. If both end on a BRA, one block
|
||||
* is chosen at random. Assume this block is b1. A new label L is put just
|
||||
* before the N common instructions of block b2 (so this block is split
|
||||
* into two). The BRA of b1 is changed into a BRA L. So dynamically the same
|
||||
* instructions are executed in a slightly different order; yet the size of
|
||||
* the code has become smaller.
|
||||
*/
|
||||
|
||||
|
||||
STATIC int Scj; /* number of optimizations found */
|
||||
|
||||
|
||||
|
||||
#define DLINK(l1,l2) l1->l_next=l2; l2->l_prev=l1
|
||||
|
||||
|
||||
STATIC bool same_instr(l1,l2)
|
||||
line_p l1,l2;
|
||||
{
|
||||
/* See if l1 and l2 are the same instruction */
|
||||
|
||||
if (l1 == 0 || l2 == 0 || TYPE(l1) != TYPE(l2)) return FALSE;
|
||||
if (INSTR(l1) != INSTR(l2)) return FALSE;
|
||||
switch(TYPE(l1)) {
|
||||
case OPSHORT: return SHORT(l1) == SHORT(l2);
|
||||
case OPOFFSET: return OFFSET(l1) == OFFSET(l2);
|
||||
case OPPROC: return PROC(l1) == PROC(l2);
|
||||
case OPOBJECT: return OBJ(l1) == OBJ(l2);
|
||||
case OPINSTRLAB: return INSTRLAB(l1) == INSTRLAB(l2);
|
||||
case OPNO: return TRUE;
|
||||
default: return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC line_p last_mnem(b)
|
||||
bblock_p b;
|
||||
{
|
||||
/* Determine the last line of a list */
|
||||
|
||||
register line_p l;
|
||||
|
||||
for (l = b->b_start; l->l_next != (line_p) 0; l = l->l_next);
|
||||
while (l != (line_p) 0 && (INSTR(l) < sp_fmnem || INSTR(l) > sp_lmnem)) {
|
||||
l = PREV(l);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
STATIC bool is_desirable(text)
|
||||
line_p text;
|
||||
{
|
||||
/* We avoid to generate a BRAnch in the middle of some expression,
|
||||
* as the code generator will write the contents of the fakestack
|
||||
* to the real stack if it encounters a BRA. We do not avoid to
|
||||
* split the parameter-pushing code of a subroutine call into two,
|
||||
* as the parameters are pushed on the real stack anyway.
|
||||
* So e.g. "LOL a ; LOL b; ADI" will not be split, but
|
||||
* "LOL a; LOL b; CAL f" may be split.
|
||||
*/
|
||||
|
||||
line_p l;
|
||||
bool ok;
|
||||
int stack_diff,pop,push;
|
||||
|
||||
stack_diff = 0;
|
||||
for (l = text; l != (line_p) 0; l = l->l_next) {
|
||||
switch(INSTR(l)) {
|
||||
case op_cal:
|
||||
case op_asp:
|
||||
case op_bra:
|
||||
return TRUE;
|
||||
}
|
||||
line_change(l,&ok,&pop,&push);
|
||||
/* printf("instr %d, pop %d, push %d, ok %d\n",INSTR(l),pop,push,ok); */
|
||||
if (!ok || (stack_diff -= pop) < 0) {
|
||||
return FALSE;
|
||||
} else {
|
||||
stack_diff += push;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
STATIC cp_loops(b1,b2)
|
||||
bblock_p b1,b2;
|
||||
{
|
||||
/* Copy the loopset of b2 to b1 */
|
||||
|
||||
Lindex i;
|
||||
loop_p lp;
|
||||
for (i = Lfirst(b2->b_loops); i != (Lindex) 0;
|
||||
i = Lnext(i,b2->b_loops)) {
|
||||
lp = (loop_p) Lelem(i);
|
||||
Ladd(lp,&b1->b_loops);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC jump_cross(l1,l2,b1,b2)
|
||||
line_p l1,l2;
|
||||
bblock_p b1,b2;
|
||||
{
|
||||
/* A cross-jump from block b2 to block b1 is found; the code in
|
||||
* block b2 from line l2 up to the BRAnch is removed; block b1 is
|
||||
* split into two; the second part consists of a new label
|
||||
* followed by the code from l1 till the end of the block.
|
||||
*/
|
||||
|
||||
line_p l;
|
||||
bblock_p b;
|
||||
bblock_p s;
|
||||
|
||||
/* First adjust the control flow graph */
|
||||
b = freshblock(); /* create a new basic block */
|
||||
b->b_succ = b1->b_succ;
|
||||
/* SUCC(b1) = {b} */
|
||||
b1->b_succ = Lempty_set(); Ladd(b,&b1->b_succ);
|
||||
/* SUCC(b2) = {b} */
|
||||
Ldeleteset(b2->b_succ); b2->b_succ = Lempty_set(); Ladd(b,&b2->b_succ);
|
||||
/* PRED(b) = {b1,b2} */
|
||||
b->b_pred = Lempty_set(); Ladd(b1,&b->b_pred); Ladd(b2,&b->b_pred);
|
||||
/* PRED(SUCC(b)) := PRED(SUCC(b)) - {b1,b2} + {b} */
|
||||
assert(Lnrelems(b->b_succ) == 1);
|
||||
s = (bblock_p) Lelem(Lfirst(b->b_succ));
|
||||
Lremove(b1,&s->b_pred); Lremove(b2,&s->b_pred); Ladd(b,&s->b_pred);
|
||||
cp_loops(b,b1);
|
||||
b->b_idom = common_dom(b1,b2);
|
||||
b->b_flags = b1->b_flags;
|
||||
b->b_next = b1->b_next;
|
||||
b1->b_next = b;
|
||||
|
||||
/* Now adjust the EM text */
|
||||
l = PREV(l1);
|
||||
if (l == (line_p) 0) {
|
||||
b1->b_start = (line_p) 0;
|
||||
} else {
|
||||
l->l_next = (line_p) 0;
|
||||
}
|
||||
l = newline(OPINSTRLAB);
|
||||
l->l_instr = op_lab;
|
||||
INSTRLAB(l) = freshlabel();
|
||||
DLINK(l,l1);
|
||||
b->b_start = l;
|
||||
for (l = l2; INSTR(l) != op_bra; l = l->l_next) {
|
||||
assert (l != (line_p) 0);
|
||||
rm_line(l,b2);
|
||||
}
|
||||
INSTRLAB(l) = INSTRLAB(b->b_start);
|
||||
}
|
||||
|
||||
|
||||
STATIC bool try_tail(b1,b2)
|
||||
bblock_p b1,b2;
|
||||
{
|
||||
/* See if b1 and b2 end on the same sequence of instructions */
|
||||
|
||||
line_p l1,l2;
|
||||
bblock_p b = (bblock_p) 0;
|
||||
int cnt = 0;
|
||||
/* printf("try block %d and %d\n",b1->b_id,b2->b_id); */
|
||||
|
||||
if (b1->b_start == (line_p) 0 || b2->b_start == (line_p) 0) return FALSE;
|
||||
l1 = last_mnem(b1);
|
||||
l2 = last_mnem(b2);
|
||||
if (l1 == (line_p) 0 || l2 == (line_p) 0) return FALSE;
|
||||
/* printf("consider:\n"); showinstr(l1); showinstr(l2); */
|
||||
if (INSTR(l1) == op_bra) {
|
||||
b = b1;
|
||||
l1 = PREV(l1);
|
||||
}
|
||||
if (INSTR(l2) == op_bra) {
|
||||
b = b2;
|
||||
l2 = PREV(l2);
|
||||
}
|
||||
assert(b != (bblock_p) 0);
|
||||
while(same_instr(l1,l2)) {
|
||||
cnt++;
|
||||
l1 = PREV(l1);
|
||||
l2 = PREV(l2);
|
||||
/* printf("consider:\n"); showinstr(l1); showinstr(l2); */
|
||||
}
|
||||
if (cnt >= 1) {
|
||||
l1 = (l1 == 0 ? b1->b_start : l1->l_next);
|
||||
l2 = (l2 == 0 ? b2->b_start : l2->l_next);
|
||||
if (is_desirable(l1)) {
|
||||
if (b == b1) {
|
||||
jump_cross(l2,l1,b2,b1);
|
||||
Scj++;
|
||||
} else {
|
||||
jump_cross(l1,l2,b1,b2);
|
||||
Scj++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool try_pred(b)
|
||||
bblock_p b;
|
||||
{
|
||||
/* See if there is any pair (b1,b2), both in PRED(b) for
|
||||
* which we can perform cross jumping.
|
||||
*/
|
||||
|
||||
register bblock_p b1,b2;
|
||||
register Lindex i,j;
|
||||
lset s = b->b_pred;
|
||||
|
||||
for (i = Lfirst(s); i != (Lindex) 0; i = Lnext(i,s)) {
|
||||
b1 = (bblock_p) Lelem(i);
|
||||
if (Lnrelems(b1->b_succ) != 1) continue;
|
||||
for (j = Lfirst(s); j != (Lindex) 0; j = Lnext(j,s)) {
|
||||
b2 = (bblock_p) Lelem(j);
|
||||
if (b1 != b2 && Lnrelems(b2->b_succ) == 1) {
|
||||
if (try_tail(b1,b2)) return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
cj_optimize(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Perform cross jumping for procedure p.
|
||||
* In case cases a cross-jumping optimization which give
|
||||
* new opportunities for further cross-jumping optimizations.
|
||||
* Hence we repeat the whole process for the entire procedure,
|
||||
* untill we find no further optimizations.
|
||||
*/
|
||||
|
||||
bblock_p b;
|
||||
bool changes = TRUE;
|
||||
|
||||
while(changes) {
|
||||
changes = FALSE;
|
||||
b = p->p_start;
|
||||
while (b != (bblock_p) 0) {
|
||||
if (try_pred(b)) {
|
||||
changes = TRUE;
|
||||
} else {
|
||||
b = b->b_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
go(argc,argv,no_action,cj_optimize,no_action,no_action);
|
||||
report("cross jumps",Scj);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******
|
||||
* Debugging stuff
|
||||
*/
|
||||
|
||||
extern char em_mnem[]; /* The mnemonics of the EM instructions. */
|
||||
|
||||
STATIC showinstr(lnp) line_p lnp; {
|
||||
|
||||
/* Makes the instruction in `lnp' human readable. Only lines that
|
||||
* can occur in expressions that are going to be eliminated are
|
||||
* properly handled.
|
||||
*/
|
||||
if (lnp == 0) return;
|
||||
if (INSTR(lnp) < sp_fmnem || INSTR(lnp) > sp_lmnem) {
|
||||
printf("\t*** ?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\t%s", &em_mnem[4 * (INSTR(lnp)-sp_fmnem)]);
|
||||
switch (TYPE(lnp)) {
|
||||
case OPNO:
|
||||
break;
|
||||
case OPSHORT:
|
||||
printf(" %d", SHORT(lnp)); break;
|
||||
case OPOBJECT:
|
||||
printf(" %d", OBJ(lnp)->o_id); break;
|
||||
case OPOFFSET:
|
||||
printf(" %D", OFFSET(lnp)); break;
|
||||
default:
|
||||
printf(" ?"); break;
|
||||
}
|
||||
printf("\n");
|
||||
} /* showinstr */
|
||||
|
||||
|
||||
STATIC print_list(list,b1,b2,p)
|
||||
line_p list;
|
||||
bblock_p b1,b2;
|
||||
proc_p p;
|
||||
{
|
||||
line_p l;
|
||||
printf("block %d and %d of proc %d:\n",b1->b_id,b2->b_id,p->p_id);
|
||||
for (l = list; l != 0; l = l->l_next) {
|
||||
showinstr(l);
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
EMH=../../../h
|
||||
EMLIB=../../../lib
|
||||
SHR=../share
|
||||
|
||||
CFILES=\
|
||||
cs.c cs_alloc.c cs_aux.c cs_avail.c cs_debug.c cs_elim.c \
|
||||
cs_entity.c cs_kill.c cs_partit.c cs_profit.c cs_getent.c \
|
||||
cs_stack.c cs_vnm.c
|
||||
|
||||
OFILES=\
|
||||
cs.o cs_alloc.o cs_aux.o cs_avail.o cs_debug.o cs_elim.o \
|
||||
cs_entity.o cs_kill.o cs_partit.o cs_profit.o cs_getent.o \
|
||||
cs_stack.o cs_vnm.o
|
||||
|
||||
HFILES=\
|
||||
cs.h cs_alloc.h cs_aux.h cs_avail.h cs_debug.h cs_elim.h \
|
||||
cs_entity.h cs_kill.h cs_partit.h cs_profit.h cs_getent.h \
|
||||
cs_stack.h cs_vnm.h
|
||||
|
||||
PRFILES=\
|
||||
$(CFILES) $(HFILES) Makefile
|
||||
|
||||
SHARE_OFILES=\
|
||||
$(SHR)/get.o $(SHR)/put.o $(SHR)/alloc.o $(SHR)/global.o $(SHR)/debug.o\
|
||||
$(SHR)/files.o $(SHR)/map.o $(SHR)/lset.o $(SHR)/cset.o $(SHR)/aux.o\
|
||||
$(SHR)/go.o
|
||||
|
||||
SHARE_MFILES=\
|
||||
$(SHR)/get.m $(SHR)/put.m $(SHR)/alloc.m $(SHR)/global.m $(SHR)/debug.m\
|
||||
$(SHR)/files.m $(SHR)/map.m $(SHR)/lset.m $(SHR)/cset.m $(SHR)/aux.m\
|
||||
$(SHR)/go.m
|
||||
|
||||
cs: $(OFILES)
|
||||
$(CC) -o cs $(LDFLAGS) $(OFILES) $(SHARE_OFILES) $(EMLIB)/em_data.a
|
||||
|
||||
cs_ack: $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -c.o $(CFLAGS) $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -o cs -.c $(LDFLAGS) cs.o $(EMLIB)/em_data.a
|
||||
|
||||
lint:
|
||||
lint $(LINTFLAGS) $(CPPFLAGS) $(CFILES)
|
||||
|
||||
pr: $(PRFILES)
|
||||
@pr $?
|
||||
@touch pr
|
||||
|
||||
depend:
|
||||
$(SHR)/makedepend
|
||||
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
cs.o: ../share/debug.h
|
||||
cs.o: ../share/go.h
|
||||
cs.o: ../share/types.h
|
||||
cs.o: cs.h
|
||||
cs.o: cs_aux.h
|
||||
cs.o: cs_avail.h
|
||||
cs.o: cs_debug.h
|
||||
cs.o: cs_elim.h
|
||||
cs.o: cs_entity.h
|
||||
cs.o: cs_profit.h
|
||||
cs.o: cs_stack.h
|
||||
cs.o: cs_vnm.h
|
||||
cs_alloc.o: ../share/alloc.h
|
||||
cs_alloc.o: ../share/types.h
|
||||
cs_alloc.o: cs.h
|
||||
cs_aux.o: ../share/aux.h
|
||||
cs_aux.o: ../share/debug.h
|
||||
cs_aux.o: ../share/global.h
|
||||
cs_aux.o: ../share/lset.h
|
||||
cs_aux.o: ../share/types.h
|
||||
cs_aux.o: cs.h
|
||||
cs_aux.o: cs_entity.h
|
||||
cs_avail.o: ../../../h/em_mnem.h
|
||||
cs_avail.o: ../share/aux.h
|
||||
cs_avail.o: ../share/debug.h
|
||||
cs_avail.o: ../share/global.h
|
||||
cs_avail.o: ../share/lset.h
|
||||
cs_avail.o: ../share/types.h
|
||||
cs_avail.o: cs.h
|
||||
cs_avail.o: cs_alloc.h
|
||||
cs_avail.o: cs_aux.h
|
||||
cs_avail.o: cs_getent.h
|
||||
cs_debug.o: ../../../h/em_spec.h
|
||||
cs_debug.o: ../share/debug.h
|
||||
cs_debug.o: ../share/lset.h
|
||||
cs_debug.o: ../share/types.h
|
||||
cs_debug.o: cs.h
|
||||
cs_debug.o: cs_aux.h
|
||||
cs_debug.o: cs_avail.h
|
||||
cs_debug.o: cs_entity.h
|
||||
cs_elim.o: ../../../h/em_mnem.h
|
||||
cs_elim.o: ../../../h/em_reg.h
|
||||
cs_elim.o: ../share/alloc.h
|
||||
cs_elim.o: ../share/aux.h
|
||||
cs_elim.o: ../share/debug.h
|
||||
cs_elim.o: ../share/global.h
|
||||
cs_elim.o: ../share/lset.h
|
||||
cs_elim.o: ../share/types.h
|
||||
cs_elim.o: cs.h
|
||||
cs_elim.o: cs_alloc.h
|
||||
cs_elim.o: cs_aux.h
|
||||
cs_elim.o: cs_avail.h
|
||||
cs_elim.o: cs_debug.h
|
||||
cs_elim.o: cs_partit.h
|
||||
cs_elim.o: cs_profit.h
|
||||
cs_entity.o: ../share/debug.h
|
||||
cs_entity.o: ../share/global.h
|
||||
cs_entity.o: ../share/lset.h
|
||||
cs_entity.o: ../share/types.h
|
||||
cs_entity.o: cs.h
|
||||
cs_entity.o: cs_aux.h
|
||||
cs_getent.o: ../../../h/em_mnem.h
|
||||
cs_getent.o: ../share/aux.h
|
||||
cs_getent.o: ../share/debug.h
|
||||
cs_getent.o: ../share/global.h
|
||||
cs_getent.o: ../share/types.h
|
||||
cs_getent.o: cs.h
|
||||
cs_getent.o: cs_aux.h
|
||||
cs_getent.o: cs_entity.h
|
||||
cs_getent.o: cs_stack.h
|
||||
cs_kill.o: ../../../h/em_mnem.h
|
||||
cs_kill.o: ../share/aux.h
|
||||
cs_kill.o: ../share/cset.h
|
||||
cs_kill.o: ../share/debug.h
|
||||
cs_kill.o: ../share/global.h
|
||||
cs_kill.o: ../share/lset.h
|
||||
cs_kill.o: ../share/types.h
|
||||
cs_kill.o: cs.h
|
||||
cs_kill.o: cs_aux.h
|
||||
cs_kill.o: cs_avail.h
|
||||
cs_kill.o: cs_debug.h
|
||||
cs_kill.o: cs_entity.h
|
||||
cs_partit.o: ../../../h/em_mnem.h
|
||||
cs_partit.o: ../../../h/em_pseu.h
|
||||
cs_partit.o: ../../../h/em_reg.h
|
||||
cs_partit.o: ../../../h/em_spec.h
|
||||
cs_partit.o: ../share/aux.h
|
||||
cs_partit.o: ../share/debug.h
|
||||
cs_partit.o: ../share/global.h
|
||||
cs_partit.o: ../share/types.h
|
||||
cs_partit.o: cs.h
|
||||
cs_partit.o: cs_stack.h
|
||||
cs_profit.o: ../../../h/em_mnem.h
|
||||
cs_profit.o: ../../../h/em_spec.h
|
||||
cs_profit.o: ../share/aux.h
|
||||
cs_profit.o: ../share/cset.h
|
||||
cs_profit.o: ../share/debug.h
|
||||
cs_profit.o: ../share/global.h
|
||||
cs_profit.o: ../share/lset.h
|
||||
cs_profit.o: ../share/types.h
|
||||
cs_profit.o: cs.h
|
||||
cs_profit.o: cs_aux.h
|
||||
cs_profit.o: cs_avail.h
|
||||
cs_profit.o: cs_partit.h
|
||||
cs_stack.o: ../share/aux.h
|
||||
cs_stack.o: ../share/debug.h
|
||||
cs_stack.o: ../share/global.h
|
||||
cs_stack.o: ../share/types.h
|
||||
cs_stack.o: cs.h
|
||||
cs_stack.o: cs_aux.h
|
||||
cs_valno.o: ../share/debug.h
|
||||
cs_valno.o: ../share/types.h
|
||||
cs_valno.o: cs.h
|
||||
cs_vnm.o: ../../../h/em_mnem.h
|
||||
cs_vnm.o: ../share/aux.h
|
||||
cs_vnm.o: ../share/debug.h
|
||||
cs_vnm.o: ../share/global.h
|
||||
cs_vnm.o: ../share/types.h
|
||||
cs_vnm.o: cs.h
|
||||
cs_vnm.o: cs_alloc.h
|
||||
cs_vnm.o: cs_aux.h
|
||||
cs_vnm.o: cs_avail.h
|
||||
cs_vnm.o: cs_entity.h
|
||||
cs_vnm.o: cs_getent.h
|
||||
cs_vnm.o: cs_kill.h
|
||||
cs_vnm.o: cs_partit.h
|
||||
cs_vnm.o: cs_stack.h
|
||||
@@ -1,78 +0,0 @@
|
||||
|
||||
/* C O M M O N S U B E X P R E S S I O N E L I M I N A T I O N */
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/go.h"
|
||||
#include "cs.h"
|
||||
#include "cs_aux.h"
|
||||
#include "cs_avail.h"
|
||||
#include "cs_debug.h"
|
||||
#include "cs_elim.h"
|
||||
#include "cs_entity.h"
|
||||
#include "cs_profit.h"
|
||||
#include "cs_stack.h"
|
||||
#include "cs_vnm.h"
|
||||
|
||||
int Scs; /* Number of optimizations found. */
|
||||
|
||||
STATIC cs_clear()
|
||||
{
|
||||
clr_avails();
|
||||
clr_entities();
|
||||
clr_stack();
|
||||
|
||||
start_valnum();
|
||||
}
|
||||
|
||||
STATIC cs_optimize(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Optimize all basic blocks of one procedure. */
|
||||
|
||||
register bblock_p rbp, bdone;
|
||||
|
||||
avails = (avail_p) 0;
|
||||
entities = Lempty_set();
|
||||
cs_clear();
|
||||
|
||||
rbp = p->p_start;
|
||||
|
||||
while (rbp != (bblock_p) 0) {
|
||||
/* First we build a list of common expressions with the
|
||||
* value numbering algorithm. We take blocks in textual order
|
||||
* as long as the next block can only be reached through the
|
||||
* block we have just done. Note that if a block is preceded
|
||||
* by itself, the number of predecessors is greater than 1,
|
||||
* but the previous block can still be its immediate dominator.
|
||||
*/
|
||||
do { vnm(rbp); bdone = rbp;
|
||||
OUTTRACE("basic block %d processed", bdone->b_id);
|
||||
rbp = rbp->b_next;
|
||||
} while (rbp != (bblock_p) 0 && rbp->b_idom == bdone &&
|
||||
Lnrelems(rbp->b_pred) == 1
|
||||
);
|
||||
OUTTRACE("value numbering completed", 0);
|
||||
OUTAVAILS(); OUTENTITIES();
|
||||
|
||||
/* Now we put out the instructions without common
|
||||
* subexpressions but with the use of temporaries,
|
||||
* which will be local variables of procedure p.
|
||||
*/
|
||||
eliminate(p);
|
||||
cs_clear();
|
||||
}
|
||||
}
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
Scs = 0;
|
||||
go(argc, argv, no_action, cs_optimize, cs_machinit, no_action);
|
||||
report("Duplicate expressions eliminated", Scs);
|
||||
exit(0);
|
||||
}
|
||||
123
util/ego/cs/cs.h
123
util/ego/cs/cs.h
@@ -1,123 +0,0 @@
|
||||
typedef short valnum;
|
||||
typedef struct entity *entity_p;
|
||||
typedef struct avail *avail_p;
|
||||
typedef struct token *token_p;
|
||||
typedef struct occur *occur_p;
|
||||
|
||||
struct token {
|
||||
valnum tk_vn;
|
||||
offset tk_size;
|
||||
line_p tk_lfirst; /* Textually first instruction, involved
|
||||
* in pushing this token.
|
||||
*/
|
||||
};
|
||||
|
||||
/* We distinguish these entities. */
|
||||
#define ENCONST 0
|
||||
#define ENLOCAL 1
|
||||
#define ENEXTERNAL 2
|
||||
#define ENINDIR 3
|
||||
#define ENOFFSETTED 4
|
||||
#define ENALOCAL 5
|
||||
#define ENAEXTERNAL 6
|
||||
#define ENAOFFSETTED 7
|
||||
#define ENALOCBASE 8
|
||||
#define ENAARGBASE 9
|
||||
#define ENPROC 10
|
||||
#define ENFZER 11
|
||||
#define ENARRELEM 12
|
||||
#define ENLOCBASE 13
|
||||
#define ENHEAPPTR 14
|
||||
#define ENIGNMASK 15
|
||||
|
||||
struct entity {
|
||||
valnum en_vn;
|
||||
bool en_static;
|
||||
byte en_kind; /* ENLOCAL, ENEXTERNAL, etc. */
|
||||
offset en_size;
|
||||
union {
|
||||
offset en__val; /* ENCONST. */
|
||||
offset en__loc; /* ENLOCAL, ENALOCAL. */
|
||||
obj_p en__ext; /* ENEXTERNAL, ENAEXTERNAL. */
|
||||
valnum en__ind; /* ENINDIR. */
|
||||
struct {
|
||||
valnum en__base;
|
||||
offset en__off;
|
||||
} en_offs; /* ENOFFSETTED, ENAOFFSETTED. */
|
||||
offset en__levels; /* ENALOCBASE, ENAARGBASE. */
|
||||
proc_p en__pro; /* ENPROC. */
|
||||
struct {
|
||||
valnum en__arbase;
|
||||
valnum en__index;
|
||||
valnum en__adesc;
|
||||
} en_arr; /* ENARRELEM. */
|
||||
} en_inf;
|
||||
};
|
||||
|
||||
/* Macros to increase ease of use. */
|
||||
#define en_val en_inf.en__val
|
||||
#define en_loc en_inf.en__loc
|
||||
#define en_ext en_inf.en__ext
|
||||
#define en_ind en_inf.en__ind
|
||||
#define en_base en_inf.en_offs.en__base
|
||||
#define en_off en_inf.en_offs.en__off
|
||||
#define en_levels en_inf.en__levels
|
||||
#define en_pro en_inf.en__pro
|
||||
#define en_arbase en_inf.en_arr.en__arbase
|
||||
#define en_index en_inf.en_arr.en__index
|
||||
#define en_adesc en_inf.en_arr.en__adesc
|
||||
|
||||
struct occur {
|
||||
line_p oc_lfirst; /* First instruction of expression. */
|
||||
line_p oc_llast; /* Last one. */
|
||||
bblock_p oc_belongs; /* Basic block it belongs to. */
|
||||
};
|
||||
|
||||
/* We distinguish these groups of instructions. */
|
||||
#define SIMPLE_LOAD 0
|
||||
#define EXPENSIVE_LOAD 1
|
||||
#define LOAD_ARRAY 2
|
||||
#define STORE_DIRECT 3
|
||||
#define STORE_INDIR 4
|
||||
#define STORE_ARRAY 5
|
||||
#define UNAIR_OP 6
|
||||
#define BINAIR_OP 7
|
||||
#define TERNAIR_OP 8
|
||||
#define KILL_ENTITY 9
|
||||
#define SIDE_EFFECTS 10
|
||||
#define FIDDLE_STACK 11
|
||||
#define IGNORE 12
|
||||
#define HOPELESS 13
|
||||
#define BBLOCK_END 14
|
||||
|
||||
struct avail {
|
||||
avail_p av_before; /* Ptr to earlier discovered expressions. */
|
||||
byte av_instr; /* Operator instruction. */
|
||||
offset av_size;
|
||||
line_p av_found; /* Line where expression is first found. */
|
||||
lset av_occurs; /* Set of recurrences of expression. */
|
||||
entity_p av_saveloc; /* Local where result is put in. */
|
||||
valnum av_result;
|
||||
union {
|
||||
valnum av__operand; /* EXPENSIVE_LOAD, UNAIR_OP. */
|
||||
struct {
|
||||
valnum av__oleft;
|
||||
valnum av__oright;
|
||||
} av_2; /* BINAIR_OP. */
|
||||
struct {
|
||||
valnum av__ofirst;
|
||||
valnum av__osecond;
|
||||
valnum av__othird;
|
||||
} av_3; /* TERNAIR_OP. */
|
||||
} av_o;
|
||||
};
|
||||
|
||||
/* Macros to increase ease of use. */
|
||||
#define av_operand av_o.av__operand
|
||||
#define av_oleft av_o.av_2.av__oleft
|
||||
#define av_oright av_o.av_2.av__oright
|
||||
#define av_ofirst av_o.av_3.av__ofirst
|
||||
#define av_osecond av_o.av_3.av__osecond
|
||||
#define av_othird av_o.av_3.av__othird
|
||||
|
||||
extern int Scs; /* Number of optimizations found. */
|
||||
@@ -1,44 +0,0 @@
|
||||
#include "../share/types.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "cs.h"
|
||||
|
||||
occur_p newoccur(l1, l2, b)
|
||||
line_p l1, l2;
|
||||
bblock_p b;
|
||||
{
|
||||
/* Allocate a new struct occur and initialize it. */
|
||||
|
||||
register occur_p rop;
|
||||
|
||||
rop = (occur_p) newcore(sizeof(struct occur));
|
||||
rop->oc_lfirst = l1; rop->oc_llast = l2; rop->oc_belongs = b;
|
||||
return rop;
|
||||
}
|
||||
|
||||
oldoccur(ocp)
|
||||
occur_p ocp;
|
||||
{
|
||||
oldcore((short *) ocp, sizeof(struct occur));
|
||||
}
|
||||
|
||||
avail_p newavail()
|
||||
{
|
||||
return (avail_p) newcore(sizeof(struct avail));
|
||||
}
|
||||
|
||||
oldavail(avp)
|
||||
avail_p avp;
|
||||
{
|
||||
oldcore((short *) avp, sizeof(struct avail));
|
||||
}
|
||||
|
||||
entity_p newentity()
|
||||
{
|
||||
return (entity_p) newcore(sizeof(struct entity));
|
||||
}
|
||||
|
||||
oldentity(enp)
|
||||
entity_p enp;
|
||||
{
|
||||
oldcore((short *) enp, sizeof(struct entity));
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
extern occur_p newoccur(); /* (line_p l1, l2; bblock_p b)
|
||||
* Returns a pointer to a new struct occur
|
||||
* and initializes it.
|
||||
*/
|
||||
|
||||
extern oldoccur(); /* (occur_p ocp)
|
||||
* Release the struct occur ocp points to.
|
||||
*/
|
||||
|
||||
extern avail_p newavail(); /* ()
|
||||
* Return a pointer to a new struct avail.
|
||||
*/
|
||||
|
||||
extern oldavail(); /* (avail_p avp)
|
||||
* Release the struct avail avp points to.
|
||||
*/
|
||||
|
||||
extern entity_p newentity(); /* ()
|
||||
* Return a pointer to a new struct entity.
|
||||
*/
|
||||
|
||||
extern oldentity(); /* (entity_p enp)
|
||||
* Release the struct entity enp points to.
|
||||
*/
|
||||
@@ -1,64 +0,0 @@
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "cs.h"
|
||||
#include "cs_entity.h"
|
||||
|
||||
offset array_elemsize(vn)
|
||||
valnum vn;
|
||||
{
|
||||
/* Vn is the valuenumber of an entity that points to
|
||||
* an array-descriptor. The third element of this descriptor holds
|
||||
* the size of the array-elements.
|
||||
* IF we can find this entity, AND IF we can find the descriptor AND IF
|
||||
* this descriptor is located in ROM, then we return the size.
|
||||
*/
|
||||
entity_p enp;
|
||||
|
||||
enp = find_entity(vn);
|
||||
|
||||
if (enp == (entity_p) 0)
|
||||
return UNKNOWN_SIZE;
|
||||
|
||||
if (enp->en_kind != ENAEXTERNAL)
|
||||
return UNKNOWN_SIZE;
|
||||
|
||||
if (enp->en_ext->o_dblock->d_pseudo != DROM)
|
||||
return UNKNOWN_SIZE;
|
||||
|
||||
return aoff(enp->en_ext->o_dblock->d_values, 2);
|
||||
}
|
||||
|
||||
occur_p occ_elem(i)
|
||||
Lindex i;
|
||||
{
|
||||
return (occur_p) Lelem(i);
|
||||
}
|
||||
|
||||
entity_p en_elem(i)
|
||||
Lindex i;
|
||||
{
|
||||
return (entity_p) Lelem(i);
|
||||
}
|
||||
|
||||
/* The value numbers associated with each distinct value
|
||||
* start at 1.
|
||||
*/
|
||||
|
||||
STATIC valnum val_no;
|
||||
|
||||
valnum newvalnum()
|
||||
{
|
||||
/* Return a completely new value number. */
|
||||
|
||||
return ++val_no;
|
||||
}
|
||||
|
||||
start_valnum()
|
||||
{
|
||||
/* Restart value numbering. */
|
||||
|
||||
val_no = 0;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
extern offset array_elemsize(); /* (valnum vm)
|
||||
* Returns the size of array-elements,
|
||||
* if vn is the valuenumber of the
|
||||
* address of an array-descriptor.
|
||||
*/
|
||||
|
||||
extern occur_p occ_elem(); /* (Lindex i)
|
||||
* Returns a pointer to the occurrence
|
||||
* of which i is an index in a set.
|
||||
*/
|
||||
|
||||
extern entity_p en_elem(); /* (Lindex i)
|
||||
* Returns a pointer to the entity
|
||||
* of which i is an index in a set.
|
||||
*/
|
||||
|
||||
extern valnum newvalnum(); /* ()
|
||||
* Returns a completely new
|
||||
* value number.
|
||||
*/
|
||||
|
||||
extern start_valnum(); /* ()
|
||||
* Restart value numbering.
|
||||
*/
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
/* M O D U L E F O R A C C E S S S I N G T H E L I S T
|
||||
*
|
||||
* O F A V A I L A B L E E X P R E S S I O N S
|
||||
*/
|
||||
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/global.h"
|
||||
#include "cs.h"
|
||||
#include "cs_aux.h"
|
||||
#include "cs_debug.h"
|
||||
#include "cs_alloc.h"
|
||||
#include "cs_getent.h"
|
||||
|
||||
avail_p avails; /* The list of available expressions. */
|
||||
|
||||
STATIC bool commutative(instr)
|
||||
int instr;
|
||||
{
|
||||
/* Is instr a commutative operator? */
|
||||
|
||||
switch (instr) {
|
||||
case op_adf: case op_adi: case op_adu: case op_and:
|
||||
case op_cms: case op_ior: case op_mlf: case op_mli:
|
||||
case op_mlu:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC bool same_avail(kind, avp1, avp2)
|
||||
byte kind;
|
||||
avail_p avp1, avp2;
|
||||
{
|
||||
/* Two expressions are the same if they have the same operator,
|
||||
* the same size, and their operand(s) have the same value.
|
||||
* Only if the operator is commutative, the order of the operands
|
||||
* does not matter.
|
||||
*/
|
||||
if (avp1->av_instr != avp2->av_instr) return FALSE;
|
||||
if (avp1->av_size != avp2->av_size) return FALSE;
|
||||
|
||||
switch (kind) {
|
||||
default:
|
||||
assert(FALSE);
|
||||
break;
|
||||
case EXPENSIVE_LOAD:
|
||||
case UNAIR_OP:
|
||||
return avp1->av_operand == avp2->av_operand;
|
||||
case BINAIR_OP:
|
||||
if (commutative(avp1->av_instr & BMASK))
|
||||
return avp1->av_oleft == avp2->av_oleft &&
|
||||
avp1->av_oright == avp2->av_oright
|
||||
||
|
||||
avp1->av_oleft == avp2->av_oright &&
|
||||
avp1->av_oright == avp2->av_oleft
|
||||
;
|
||||
else
|
||||
return avp1->av_oleft == avp2->av_oleft &&
|
||||
avp1->av_oright == avp2->av_oright;
|
||||
case TERNAIR_OP:
|
||||
return avp1->av_ofirst == avp2->av_ofirst &&
|
||||
avp1->av_osecond == avp2->av_osecond &&
|
||||
avp1->av_othird == avp2->av_othird;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
STATIC check_local(avp)
|
||||
avail_p avp;
|
||||
{
|
||||
/* Check if the local in which the result of avp was stored,
|
||||
* still holds this result. Update if not.
|
||||
*/
|
||||
if (avp->av_saveloc == (entity_p) 0) return; /* Nothing to check. */
|
||||
|
||||
if (avp->av_saveloc->en_vn != avp->av_result) {
|
||||
OUTTRACE("save local changed value", 0);
|
||||
avp->av_saveloc = (entity_p) 0;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC entity_p result_local(size, l)
|
||||
offset size;
|
||||
line_p l;
|
||||
{
|
||||
/* If the result of an expression of size bytes is stored into a
|
||||
* local for which a registermessage was generated, return a pointer
|
||||
* to this local.
|
||||
*/
|
||||
line_p dummy;
|
||||
entity_p enp;
|
||||
|
||||
if (l == (line_p) 0)
|
||||
return (entity_p) 0;
|
||||
|
||||
if (INSTR(l)==op_stl && size==ws || INSTR(l)==op_sdl && size==2*ws) {
|
||||
enp = getentity(l, &dummy);
|
||||
if (is_regvar(enp->en_loc)) {
|
||||
OUTTRACE("save local found, %D(LB)", enp->en_loc);
|
||||
return enp;
|
||||
}
|
||||
}
|
||||
|
||||
return (entity_p) 0;
|
||||
}
|
||||
|
||||
STATIC copy_avail(kind, src, dst)
|
||||
int kind;
|
||||
avail_p src, dst;
|
||||
{
|
||||
/* Copy some attributes from src to dst. */
|
||||
|
||||
dst->av_instr = src->av_instr;
|
||||
dst->av_size = src->av_size;
|
||||
|
||||
switch (kind) {
|
||||
default:
|
||||
assert(FALSE);
|
||||
break;
|
||||
case EXPENSIVE_LOAD:
|
||||
case UNAIR_OP:
|
||||
dst->av_operand = src->av_operand;
|
||||
break;
|
||||
case BINAIR_OP:
|
||||
dst->av_oleft = src->av_oleft;
|
||||
dst->av_oright = src->av_oright;
|
||||
break;
|
||||
case TERNAIR_OP:
|
||||
dst->av_ofirst = src->av_ofirst;
|
||||
dst->av_osecond = src->av_osecond;
|
||||
dst->av_othird = src->av_othird;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
avail_p av_enter(avp, ocp, kind)
|
||||
avail_p avp;
|
||||
occur_p ocp;
|
||||
int kind;
|
||||
{
|
||||
/* Put the available expression avp in the list,
|
||||
* if it is not already there.
|
||||
* Add ocp to the set of occurrences of this expression.
|
||||
*/
|
||||
register avail_p ravp;
|
||||
line_p last = ocp->oc_llast;
|
||||
|
||||
for (ravp = avails; ravp != (avail_p) 0; ravp = ravp->av_before) {
|
||||
if (same_avail(kind, ravp, avp)) { /* It was there. */
|
||||
Ladd(ocp, &ravp->av_occurs);
|
||||
/* Can we still use the local in which
|
||||
* the result was stored?
|
||||
*/
|
||||
check_local(ravp);
|
||||
return ravp;
|
||||
}
|
||||
}
|
||||
/* A new available axpression. */
|
||||
ravp = newavail();
|
||||
|
||||
/* Remember local, if any, that holds result. */
|
||||
if (avp->av_instr != (byte) INSTR(last)) {
|
||||
/* Only possible when instr is the implicit AAR in
|
||||
* a LAR or SAR.
|
||||
*/
|
||||
ravp->av_saveloc = (entity_p) 0;
|
||||
} else {
|
||||
ravp->av_saveloc = result_local(avp->av_size, last->l_next);
|
||||
}
|
||||
ravp->av_found = last;
|
||||
ravp->av_result = kind == EXPENSIVE_LOAD? avp->av_operand: newvalnum();
|
||||
copy_avail(kind, avp, ravp);
|
||||
oldoccur(ocp);
|
||||
ravp->av_before = avails;
|
||||
avails = ravp;
|
||||
return ravp;
|
||||
}
|
||||
|
||||
clr_avails()
|
||||
{
|
||||
/* Throw away the information about the available expressions. */
|
||||
|
||||
register avail_p ravp, next;
|
||||
register Lindex i;
|
||||
register lset s;
|
||||
|
||||
for (ravp = avails; ravp != (avail_p) 0; ravp = next) {
|
||||
next = ravp->av_before;
|
||||
|
||||
s = ravp->av_occurs;
|
||||
for (i = Lfirst(s); i != (Lindex) 0; i = Lnext(i, s)) {
|
||||
oldoccur(occ_elem(i));
|
||||
}
|
||||
Ldeleteset(s);
|
||||
oldavail(ravp);
|
||||
}
|
||||
avails = (avail_p) 0;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
extern avail_p avails; /* The set of available expressions. */
|
||||
|
||||
extern avail_p av_enter(); /* (avail_p avp, occur_p ocp, byte kind)
|
||||
* Puts the available expression in avp
|
||||
* in the list of available expressions,
|
||||
* if it is not already there. Add ocp to set of
|
||||
* occurrences of this expression.
|
||||
* If we have a new expression, we test whether
|
||||
* the result is saved. When this expression
|
||||
* recurs,we test if we can still use the
|
||||
* variable into which it was saved.
|
||||
* (Kind is the kind of the expression.)
|
||||
* Returns a pointer into the list.
|
||||
*/
|
||||
|
||||
extern clr_avails(); /* Release all space occupied by the old list
|
||||
* of available expressions.
|
||||
*/
|
||||
@@ -1,156 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/lset.h"
|
||||
#include "cs.h"
|
||||
#include "cs_aux.h"
|
||||
#include "cs_avail.h"
|
||||
#include "cs_entity.h"
|
||||
|
||||
#ifdef VERBOSE
|
||||
|
||||
extern char em_mnem[]; /* The mnemonics of the EM instructions. */
|
||||
|
||||
STATIC showinstr(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* Makes the instruction in `lnp' human readable. Only lines that
|
||||
* can occur in expressions that are going to be eliminated are
|
||||
* properly handled.
|
||||
*/
|
||||
if (INSTR(lnp) < sp_fmnem && INSTR(lnp) > sp_lmnem) {
|
||||
fprintf(stderr,"*** ?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr,"%s", &em_mnem[4 * (INSTR(lnp)-sp_fmnem)]);
|
||||
switch (TYPE(lnp)) {
|
||||
case OPNO:
|
||||
break;
|
||||
case OPSHORT:
|
||||
fprintf(stderr," %d", SHORT(lnp));
|
||||
break;
|
||||
case OPOBJECT:
|
||||
fprintf(stderr," %d", OBJ(lnp)->o_id);
|
||||
break;
|
||||
case OPOFFSET:
|
||||
fprintf(stderr," %D", OFFSET(lnp));
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr," ?");
|
||||
break;
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
|
||||
SHOWOCCUR(ocp)
|
||||
occur_p ocp;
|
||||
{
|
||||
/* Shows all instructions in an occurrence. */
|
||||
|
||||
register line_p lnp, next;
|
||||
|
||||
if (verbose_flag) {
|
||||
for (lnp = ocp->oc_lfirst; lnp != (line_p) 0; lnp = next) {
|
||||
next = lnp == ocp->oc_llast ? (line_p) 0 : lnp->l_next;
|
||||
|
||||
showinstr(lnp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TRACE
|
||||
|
||||
SHOWAVAIL(avp)
|
||||
avail_p avp;
|
||||
{
|
||||
/* Shows an available expression. */
|
||||
showinstr(avp->av_found);
|
||||
fprintf(stderr,"result %d,", avp->av_result);
|
||||
fprintf(stderr,"occurred %d times\n", Lnrelems(avp->av_occurs) + 1);
|
||||
|
||||
}
|
||||
|
||||
OUTAVAILS()
|
||||
{
|
||||
register avail_p ravp;
|
||||
|
||||
fprintf(stderr,"AVAILABLE EXPRESSIONS\n");
|
||||
|
||||
for (ravp = avails; ravp != (avail_p) 0; ravp = ravp->av_before) {
|
||||
SHOWAVAIL(ravp);
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC char *enkinds[] = {
|
||||
"constant",
|
||||
"local",
|
||||
"external",
|
||||
"indirect",
|
||||
"offsetted",
|
||||
"address of local",
|
||||
"address of external",
|
||||
"address of offsetted",
|
||||
"address of local base",
|
||||
"address of argument base",
|
||||
"procedure",
|
||||
"floating zero",
|
||||
"array element",
|
||||
"local base",
|
||||
"heap pointer",
|
||||
"ignore mask"
|
||||
};
|
||||
|
||||
OUTENTITIES()
|
||||
{
|
||||
register Lindex i;
|
||||
|
||||
fprintf(stderr,"ENTITIES\n");
|
||||
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
|
||||
register entity_p rep = en_elem(i);
|
||||
|
||||
fprintf(stderr,"%s,", enkinds[rep->en_kind]);
|
||||
fprintf(stderr,"size %D,", rep->en_size);
|
||||
fprintf(stderr,"valno %d,", rep->en_vn);
|
||||
switch (rep->en_kind) {
|
||||
case ENCONST:
|
||||
fprintf(stderr,"$%D\n", rep->en_val);
|
||||
break;
|
||||
case ENLOCAL:
|
||||
case ENALOCAL:
|
||||
fprintf(stderr,"%D(LB)\n", rep->en_loc);
|
||||
break;
|
||||
case ENINDIR:
|
||||
fprintf(stderr,"*%d\n", rep->en_ind);
|
||||
break;
|
||||
case ENOFFSETTED:
|
||||
case ENAOFFSETTED:
|
||||
fprintf(stderr,"%D(%d)\n", rep->en_off, rep->en_base);
|
||||
break;
|
||||
case ENALOCBASE:
|
||||
case ENAARGBASE:
|
||||
fprintf(stderr,"%D levels\n", rep->en_levels);
|
||||
break;
|
||||
case ENARRELEM:
|
||||
fprintf(stderr,"%d[%d], ",rep->en_arbase,rep->en_index);
|
||||
fprintf(stderr,"rom at %d\n", rep->en_adesc);
|
||||
break;
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX */
|
||||
OUTTRACE(s, n)
|
||||
char *s;
|
||||
{
|
||||
fprintf(stderr,"trace: ");
|
||||
fprintf(stderr,s, n);
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
|
||||
#endif TRACE
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifdef VERBOSE
|
||||
|
||||
extern SHOWOCCUR(); /* (occur_p ocp)
|
||||
* Shows all lines in an occurrence.
|
||||
*/
|
||||
|
||||
#else
|
||||
|
||||
#define SHOWOCCUR(x)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TRACE
|
||||
|
||||
extern OUTAVAILS(); /* ()
|
||||
* Prints all available expressions.
|
||||
*/
|
||||
|
||||
extern OUTENTITIES(); /* ()
|
||||
* Prints all entities.
|
||||
*/
|
||||
|
||||
extern SHOWAVAIL(); /* (avail_p avp)
|
||||
* Shows an available expression.
|
||||
*/
|
||||
|
||||
#else TRACE
|
||||
|
||||
#define OUTAVAILS()
|
||||
#define OUTENTITIES()
|
||||
#define SHOWAVAIL(x)
|
||||
|
||||
#endif TRACE
|
||||
@@ -1,283 +0,0 @@
|
||||
#include "../../../h/em_reg.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../share/types.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/debug.h"
|
||||
#include "cs.h"
|
||||
#include "cs_avail.h"
|
||||
#include "cs_alloc.h"
|
||||
#include "cs_aux.h"
|
||||
#include "cs_debug.h"
|
||||
#include "cs_profit.h"
|
||||
#include "cs_partit.h"
|
||||
#include "cs_debug.h"
|
||||
|
||||
STATIC dlink(l1, l2)
|
||||
line_p l1, l2;
|
||||
{
|
||||
/* Doubly link the lines in l1 and l2. */
|
||||
|
||||
if (l1 != (line_p) 0)
|
||||
l1->l_next = l2;
|
||||
if (l2 != (line_p) 0)
|
||||
l2->l_prev = l1;
|
||||
}
|
||||
|
||||
STATIC remove_lines(first, last)
|
||||
line_p first, last;
|
||||
{
|
||||
/* Throw away the lines between and including first and last.
|
||||
* Don't worry about any pointers; the (must) have been taken care of.
|
||||
*/
|
||||
register line_p lnp, next;
|
||||
|
||||
last->l_next = (line_p) 0; /* Delimit the list. */
|
||||
for (lnp = first; lnp != (line_p) 0; lnp = next) {
|
||||
next = lnp->l_next;
|
||||
oldline(lnp);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC bool contained(ocp1, ocp2)
|
||||
occur_p ocp1, ocp2;
|
||||
{
|
||||
/* Determine whether ocp1 is contained within ocp2. */
|
||||
|
||||
register line_p lnp, next;
|
||||
|
||||
for (lnp = ocp2->oc_lfirst; lnp != (line_p) 0; lnp = next) {
|
||||
next = lnp != ocp2->oc_llast ? lnp->l_next : (line_p) 0;
|
||||
|
||||
if (lnp == ocp1->oc_llast) return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
STATIC delete(ocp, start)
|
||||
occur_p ocp;
|
||||
avail_p start;
|
||||
{
|
||||
/* Delete all occurrences that are contained within ocp.
|
||||
* They must have been entered in the list before start:
|
||||
* if an expression is contained with an other, its operator line
|
||||
* appears before the operator line of the other because EM-expressions
|
||||
* are postfix.
|
||||
*/
|
||||
register avail_p ravp;
|
||||
register Lindex i, next;
|
||||
|
||||
for (ravp = start; ravp != (avail_p) 0; ravp = ravp->av_before) {
|
||||
for (i = Lfirst(ravp->av_occurs); i != (Lindex) 0; i = next) {
|
||||
next = Lnext(i, ravp->av_occurs);
|
||||
|
||||
if (contained(occ_elem(i), ocp)) {
|
||||
OUTTRACE("delete contained occurrence", 0);
|
||||
# ifdef TRACE
|
||||
SHOWOCCUR(occ_elem(i));
|
||||
# endif
|
||||
oldoccur(occ_elem(i));
|
||||
Lremove(Lelem(i), &ravp->av_occurs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC complete_aar(lnp, instr, descr_vn)
|
||||
line_p lnp;
|
||||
int instr;
|
||||
valnum descr_vn;
|
||||
{
|
||||
/* Lnp is an instruction that loads the address of an array-element.
|
||||
* Instr tells us what effect we should achieve; load (instr is op_lar)
|
||||
* or store (instr is op_sar) this array-element. Descr_vn is the
|
||||
* valuenumber of the address of the descriptor of this array.
|
||||
* We append a loi or sti of the correct number of bytes.
|
||||
*/
|
||||
register line_p lindir;
|
||||
|
||||
lindir = int_line(array_elemsize(descr_vn));
|
||||
lindir->l_instr = instr == op_lar ? op_loi : op_sti;
|
||||
dlink(lindir, lnp->l_next);
|
||||
dlink(lnp, lindir);
|
||||
}
|
||||
|
||||
STATIC replace(ocp, tmp, avp)
|
||||
occur_p ocp;
|
||||
offset tmp;
|
||||
avail_p avp;
|
||||
{
|
||||
/* Replace the lines in the occurrence in ocp by a load of the
|
||||
* temporary with offset tmp.
|
||||
*/
|
||||
register line_p lol, first, last;
|
||||
|
||||
assert(avp->av_size == ws || avp->av_size == 2*ws);
|
||||
|
||||
first = ocp->oc_lfirst; last = ocp->oc_llast;
|
||||
|
||||
lol = int_line(tmp);
|
||||
lol->l_instr = avp->av_size == ws ? op_lol : op_ldl;
|
||||
dlink(lol, last->l_next);
|
||||
|
||||
if (first->l_prev == (line_p) 0) ocp->oc_belongs->b_start = lol;
|
||||
dlink(first->l_prev, lol);
|
||||
|
||||
if (avp->av_instr == (byte) op_aar) {
|
||||
/* There may actually be a LAR or a SAR instruction; in that
|
||||
* case we have to complete the array-instruction.
|
||||
*/
|
||||
register int instr = INSTR(last);
|
||||
|
||||
if (instr != op_aar) complete_aar(lol, instr, avp->av_othird);
|
||||
}
|
||||
|
||||
/* Throw away the by now useless lines. */
|
||||
remove_lines(first, last);
|
||||
}
|
||||
|
||||
STATIC append(avp, tmp)
|
||||
avail_p avp;
|
||||
offset tmp;
|
||||
{
|
||||
/* Avp->av_found points to a line with an operator in it. This
|
||||
* routine emits a sequence of instructions that saves the result
|
||||
* in a local with offset tmp. In most cases we just append
|
||||
* avp->av_found with stl/sdl tmp and lol/ldl tmp depending on
|
||||
* avp->av_size. If however the operator is an aar contained
|
||||
* within a lar or sar, we must first generate the aar.
|
||||
*/
|
||||
register line_p stl, lol;
|
||||
|
||||
assert(avp->av_size == ws || avp->av_size == 2*ws);
|
||||
|
||||
stl = int_line(tmp);
|
||||
stl->l_instr = avp->av_size == ws ? op_stl : op_sdl;
|
||||
lol = int_line(tmp);
|
||||
lol->l_instr = avp->av_size == ws ? op_lol : op_ldl;
|
||||
|
||||
dlink(lol, avp->av_found->l_next);
|
||||
dlink(stl, lol);
|
||||
dlink(avp->av_found, stl);
|
||||
|
||||
if (avp->av_instr == (byte) op_aar) {
|
||||
register int instr = INSTR(avp->av_found);
|
||||
|
||||
if (instr != op_aar) {
|
||||
complete_aar(lol, instr, avp->av_othird);
|
||||
avp->av_found->l_instr = op_aar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC set_replace(avp, tmp)
|
||||
avail_p avp;
|
||||
offset tmp;
|
||||
{
|
||||
/* Avp->av_occurs is now a set of occurrences, each of which will be
|
||||
* replaced by a reference to a local.
|
||||
* Each time we eliminate an expression, we delete from our
|
||||
* list those expressions that are physically contained in them,
|
||||
* because we cannot eliminate them again.
|
||||
*/
|
||||
register Lindex i;
|
||||
register lset s = avp->av_occurs;
|
||||
|
||||
for (i = Lfirst(s); i != (Lindex) 0; i = Lnext(i, s)) {
|
||||
OUTVERBOSE("eliminate duplicate", 0);
|
||||
SHOWOCCUR(occ_elem(i));
|
||||
Scs++;
|
||||
delete(occ_elem(i), avp->av_before);
|
||||
replace(occ_elem(i), tmp, avp);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int reg_score(enp)
|
||||
entity_p enp;
|
||||
{
|
||||
/* Enp is a local that will go into a register.
|
||||
* We return its score upto now.
|
||||
*/
|
||||
assert(is_regvar(enp->en_loc));
|
||||
return regv_arg(enp->en_loc, 4);
|
||||
}
|
||||
|
||||
STATIC line_p gen_mesreg(off, avp, pp)
|
||||
offset off;
|
||||
avail_p avp;
|
||||
proc_p pp;
|
||||
{
|
||||
/* Generate a register message for the local that will hold the
|
||||
* result of the expression in avp, at the appropriate place in
|
||||
* the procedure in pp.
|
||||
*/
|
||||
register line_p reg;
|
||||
|
||||
reg = reg_mes(off, (short) avp->av_size, regtype(avp->av_instr), 0);
|
||||
appnd_line(reg, pp->p_start->b_start);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
STATIC change_score(mes, score)
|
||||
line_p mes;
|
||||
int score;
|
||||
{
|
||||
/* Change the score in the register message in mes to score. */
|
||||
|
||||
register arg_p ap = ARG(mes);
|
||||
|
||||
ap = ap->a_next; /* Offset. */
|
||||
ap = ap->a_next; /* Size. */
|
||||
ap = ap->a_next; /* Type. */
|
||||
ap = ap->a_next; /* Score. */
|
||||
|
||||
ap->a_a.a_offset = score;
|
||||
}
|
||||
|
||||
eliminate(pp)
|
||||
proc_p pp;
|
||||
{
|
||||
/* Eliminate costly common subexpressions within procedure pp.
|
||||
* We scan the available expressions in - with respect to time found -
|
||||
* reverse order, to find largest first, e.g. `A + B + C' before
|
||||
* `A + B'.
|
||||
* We do not eliminate an expression when the size
|
||||
* is not one of ws or 2*ws, because then we cannot use lol or ldl.
|
||||
* Code is appended to the first occurrence of the expression
|
||||
* to store the result into a local.
|
||||
*/
|
||||
register avail_p ravp;
|
||||
register int score;
|
||||
register offset tmp;
|
||||
register line_p mes;
|
||||
|
||||
for (ravp = avails; ravp != (avail_p) 0; ravp = ravp->av_before) {
|
||||
|
||||
if (ravp->av_size != ws && ravp->av_size != 2*ws) continue;
|
||||
|
||||
if (ravp->av_saveloc == (entity_p) 0) {
|
||||
/* We save it ourselves. */
|
||||
score = 2; /* Stl and lol. */
|
||||
} else {
|
||||
score = reg_score(ravp->av_saveloc);
|
||||
}
|
||||
if (desirable(ravp)) {
|
||||
score += Lnrelems(ravp->av_occurs);
|
||||
OUTTRACE("temporary local score %d", score);
|
||||
if (ravp->av_saveloc != (entity_p) 0) {
|
||||
tmp = ravp->av_saveloc->en_loc;
|
||||
mes = find_mesreg(tmp);
|
||||
OUTVERBOSE("re-using %D(LB)", tmp);
|
||||
} else {
|
||||
tmp = tmplocal(pp, ravp->av_size);
|
||||
mes = gen_mesreg(tmp, ravp, pp);
|
||||
append(ravp, tmp);
|
||||
}
|
||||
change_score(mes, score);
|
||||
set_replace(ravp, tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
extern eliminate(); /* (proc_p pp)
|
||||
* Eliminate some of the recurrences of expressions
|
||||
* that were found by the valuenumbering
|
||||
* algorithm.
|
||||
*/
|
||||
@@ -1,142 +0,0 @@
|
||||
/* F U N C T I O N S F O R A C C E S S I N G T H E S E T
|
||||
*
|
||||
* O F E N T I T I E S
|
||||
*/
|
||||
|
||||
#include "../share/types.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/debug.h"
|
||||
#include "cs.h"
|
||||
#include "cs_alloc.h"
|
||||
#include "cs_aux.h"
|
||||
|
||||
lset entities; /* Our pseudo symbol-table. */
|
||||
|
||||
entity_p find_entity(vn)
|
||||
valnum vn;
|
||||
{
|
||||
/* Try to find the entity with valuenumber vn. */
|
||||
|
||||
register Lindex i;
|
||||
|
||||
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
|
||||
if (en_elem(i)->en_vn == vn)
|
||||
return en_elem(i);
|
||||
}
|
||||
|
||||
return (entity_p) 0;
|
||||
}
|
||||
|
||||
STATIC bool same_entity(enp1, enp2)
|
||||
entity_p enp1, enp2;
|
||||
{
|
||||
if (enp1->en_kind != enp2->en_kind) return FALSE;
|
||||
if (enp1->en_size != enp2->en_size) return FALSE;
|
||||
if (enp1->en_size == UNKNOWN_SIZE) return FALSE;
|
||||
|
||||
switch (enp1->en_kind) {
|
||||
case ENCONST:
|
||||
return enp1->en_val == enp2->en_val;
|
||||
case ENLOCAL:
|
||||
case ENALOCAL:
|
||||
return enp1->en_loc == enp2->en_loc;
|
||||
case ENEXTERNAL:
|
||||
case ENAEXTERNAL:
|
||||
return enp1->en_ext == enp2->en_ext;
|
||||
case ENINDIR:
|
||||
return enp1->en_ind == enp2->en_ind;
|
||||
case ENOFFSETTED:
|
||||
case ENAOFFSETTED:
|
||||
return enp1->en_base == enp2->en_base &&
|
||||
enp1->en_off == enp2->en_off;
|
||||
case ENALOCBASE:
|
||||
case ENAARGBASE:
|
||||
return enp1->en_levels == enp2->en_levels;
|
||||
case ENPROC:
|
||||
return enp1->en_pro == enp2->en_pro;
|
||||
case ENARRELEM:
|
||||
return enp1->en_arbase == enp2->en_arbase &&
|
||||
enp1->en_index == enp2->en_index &&
|
||||
enp1->en_adesc == enp2->en_adesc;
|
||||
default:
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC copy_entity(src, dst)
|
||||
entity_p src, dst;
|
||||
{
|
||||
dst->en_static = src->en_static;
|
||||
dst->en_kind = src->en_kind;
|
||||
dst->en_size = src->en_size;
|
||||
|
||||
switch (src->en_kind) {
|
||||
case ENCONST:
|
||||
dst->en_val = src->en_val;
|
||||
break;
|
||||
case ENLOCAL:
|
||||
case ENALOCAL:
|
||||
dst->en_loc = src->en_loc;
|
||||
break;
|
||||
case ENEXTERNAL:
|
||||
case ENAEXTERNAL:
|
||||
dst->en_ext = src->en_ext;
|
||||
break;
|
||||
case ENINDIR:
|
||||
dst->en_ind = src->en_ind;
|
||||
break;
|
||||
case ENOFFSETTED:
|
||||
case ENAOFFSETTED:
|
||||
dst->en_base = src->en_base;
|
||||
dst->en_off = src->en_off;
|
||||
break;
|
||||
case ENALOCBASE:
|
||||
case ENAARGBASE:
|
||||
dst->en_levels = src->en_levels;
|
||||
break;
|
||||
case ENPROC:
|
||||
dst->en_pro = src->en_pro;
|
||||
break;
|
||||
case ENARRELEM:
|
||||
dst->en_arbase = src->en_arbase;
|
||||
dst->en_index = src->en_index;
|
||||
dst->en_adesc = src->en_adesc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
entity_p en_enter(enp)
|
||||
register entity_p enp;
|
||||
{
|
||||
/* Put the entity in enp in the entity set, if it is not already there.
|
||||
* Return pointer to stored entity.
|
||||
*/
|
||||
register Lindex i;
|
||||
register entity_p new;
|
||||
|
||||
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
|
||||
if (same_entity(en_elem(i), enp))
|
||||
return en_elem(i);
|
||||
}
|
||||
/* A new entity. */
|
||||
new = newentity();
|
||||
new->en_vn = newvalnum();
|
||||
copy_entity(enp, new);
|
||||
Ladd(new, &entities);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
clr_entities()
|
||||
{
|
||||
/* Throw away all pseudo-symboltable information. */
|
||||
|
||||
register Lindex i;
|
||||
|
||||
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
|
||||
oldentity(en_elem(i));
|
||||
}
|
||||
Ldeleteset(entities);
|
||||
entities = Lempty_set();
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
extern lset entities; /* The pseudo-symboltable. */
|
||||
|
||||
extern entity_p find_entity(); /* (valnum vn)
|
||||
* Tries to find an entity with value number vn.
|
||||
*/
|
||||
|
||||
extern entity_p en_enter(); /* (entity_p enp)
|
||||
* Enter the entity in enp in the set of
|
||||
* entities if it was not already there.
|
||||
*/
|
||||
|
||||
extern clr_entities(); /* ()
|
||||
* Release all space occupied by our
|
||||
* pseudo-symboltable.
|
||||
*/
|
||||
@@ -1,219 +0,0 @@
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../share/types.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "cs.h"
|
||||
#include "cs_aux.h"
|
||||
#include "cs_entity.h"
|
||||
#include "cs_stack.h"
|
||||
|
||||
#define WS1 0
|
||||
#define WS2 1
|
||||
#define PS 2
|
||||
#define ARGW 3
|
||||
#define ARDESC3 4
|
||||
|
||||
STATIC struct inf_entity {
|
||||
byte inf_instr; /* Key. */
|
||||
byte inf_used; /* Kind of entity used by key. */
|
||||
byte inf_size; /* Indication of the size. */
|
||||
} inf_table[] = {
|
||||
op_adp, ENAOFFSETTED, PS,
|
||||
op_dee, ENEXTERNAL, WS1,
|
||||
op_del, ENLOCAL, WS1,
|
||||
op_ine, ENEXTERNAL, WS1,
|
||||
op_inl, ENLOCAL, WS1,
|
||||
op_lae, ENAEXTERNAL, PS,
|
||||
op_lal, ENALOCAL, PS,
|
||||
op_lar, ENARRELEM, ARDESC3,
|
||||
op_ldc, ENCONST, WS2,
|
||||
op_lde, ENEXTERNAL, WS2,
|
||||
op_ldf, ENOFFSETTED, WS2,
|
||||
op_ldl, ENLOCAL, WS2,
|
||||
op_lil, ENINDIR, WS1,
|
||||
op_lim, ENIGNMASK, WS1,
|
||||
op_loc, ENCONST, WS1,
|
||||
op_loe, ENEXTERNAL, WS1,
|
||||
op_lof, ENOFFSETTED, WS1,
|
||||
op_loi, ENINDIR, ARGW,
|
||||
op_lol, ENLOCAL, WS1,
|
||||
op_lpi, ENPROC, PS,
|
||||
op_lxa, ENAARGBASE, PS,
|
||||
op_lxl, ENALOCBASE, PS,
|
||||
op_sar, ENARRELEM, ARDESC3,
|
||||
op_sde, ENEXTERNAL, WS2,
|
||||
op_sdf, ENOFFSETTED, WS2,
|
||||
op_sdl, ENLOCAL, WS2,
|
||||
op_sil, ENINDIR, WS1,
|
||||
op_ste, ENEXTERNAL, WS1,
|
||||
op_stf, ENOFFSETTED, WS1,
|
||||
op_sti, ENINDIR, ARGW,
|
||||
op_stl, ENLOCAL, WS1,
|
||||
op_zer, ENCONST, ARGW,
|
||||
op_zre, ENEXTERNAL, WS1,
|
||||
op_zrf, ENFZER, ARGW,
|
||||
op_zrl, ENLOCAL, WS1,
|
||||
op_nop /* Delimitor. */
|
||||
};
|
||||
|
||||
#define INFKEY(ip) (ip->inf_instr & BMASK)
|
||||
#define ENKIND(ip) ip->inf_used
|
||||
#define SIZEINF(ip) ip->inf_size
|
||||
|
||||
STATIC struct inf_entity *getinf(n)
|
||||
int n;
|
||||
{
|
||||
struct inf_entity *ip;
|
||||
|
||||
for (ip = &inf_table[0]; INFKEY(ip) != op_nop; ip++) {
|
||||
if (INFKEY(ip) == n) return ip;
|
||||
}
|
||||
return (struct inf_entity *) 0;
|
||||
}
|
||||
|
||||
entity_p getentity(lnp, l_out)
|
||||
line_p lnp, *l_out;
|
||||
{
|
||||
/* Build the entities where lnp refers to, and enter them.
|
||||
* If a token needs to be popped, the first line that pushed
|
||||
* it is stored in *l_out.
|
||||
* The main entity lnp refers to, is returned.
|
||||
*/
|
||||
struct entity en;
|
||||
struct token tk;
|
||||
struct inf_entity *ip;
|
||||
valnum vn;
|
||||
offset indexsize;
|
||||
struct token adesc, index, arbase;
|
||||
|
||||
*l_out = lnp;
|
||||
|
||||
/* Lor is a special case. */
|
||||
if (INSTR(lnp) == op_lor) {
|
||||
en.en_static = FALSE;
|
||||
en.en_size = ps;
|
||||
switch (off_set(lnp)) {
|
||||
default:
|
||||
assert(FALSE);
|
||||
break;
|
||||
case 0:
|
||||
en.en_kind = ENLOCBASE;
|
||||
break;
|
||||
case 1:
|
||||
return (entity_p) 0;
|
||||
case 2:
|
||||
en.en_kind = ENHEAPPTR;
|
||||
break;
|
||||
}
|
||||
return en_enter(&en);
|
||||
}
|
||||
|
||||
if ( (ip = getinf(INSTR(lnp))) == (struct inf_entity *) 0)
|
||||
return (entity_p) 0; /* It does not refer to any entity. */
|
||||
|
||||
/* Lil and sil refer to two entities. */
|
||||
if (INSTR(lnp) == op_lil || INSTR(lnp) == op_sil) {
|
||||
en.en_static = FALSE;
|
||||
en.en_kind = ENLOCAL;
|
||||
en.en_size = ps; /* Local must be a pointer. */
|
||||
en.en_loc = off_set(lnp);
|
||||
vn = en_enter(&en)->en_vn;
|
||||
}
|
||||
|
||||
en.en_static = FALSE;
|
||||
en.en_kind = ENKIND(ip);
|
||||
|
||||
/* Fill in the size of the entity. */
|
||||
switch (SIZEINF(ip)) {
|
||||
default:
|
||||
assert(FALSE);
|
||||
break;
|
||||
case WS1:
|
||||
en.en_size = ws;
|
||||
break;
|
||||
case WS2:
|
||||
en.en_size = 2*ws;
|
||||
break;
|
||||
case PS:
|
||||
en.en_size = ps;
|
||||
break;
|
||||
case ARGW:
|
||||
if (TYPE(lnp) != OPNO) {
|
||||
en.en_size = off_set(lnp);
|
||||
} else {
|
||||
Pop(&tk, (offset) ws);
|
||||
*l_out = tk.tk_lfirst;
|
||||
en.en_size = UNKNOWN_SIZE;
|
||||
}
|
||||
break;
|
||||
case ARDESC3:
|
||||
assert(en.en_kind == ENARRELEM);
|
||||
if (TYPE(lnp) != OPNO) {
|
||||
indexsize = off_set(lnp);
|
||||
} else {
|
||||
Pop(&tk, (offset) ws);
|
||||
indexsize = UNKNOWN_SIZE;
|
||||
}
|
||||
Pop(&adesc, (offset) ps);
|
||||
en.en_adesc = adesc.tk_vn;
|
||||
Pop(&index, indexsize);
|
||||
en.en_index = index.tk_vn;
|
||||
Pop(&arbase, (offset) ps);
|
||||
en.en_arbase = arbase.tk_vn;
|
||||
*l_out = arbase.tk_lfirst;
|
||||
en.en_size = array_elemsize(adesc.tk_vn);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fill in additional information. */
|
||||
switch (en.en_kind) {
|
||||
case ENFZER:
|
||||
en.en_static = TRUE;
|
||||
break;
|
||||
case ENCONST:
|
||||
en.en_static = TRUE;
|
||||
en.en_val = off_set(lnp);
|
||||
break;
|
||||
case ENALOCAL:
|
||||
en.en_static = TRUE;
|
||||
case ENLOCAL:
|
||||
en.en_loc = off_set(lnp);
|
||||
break;
|
||||
case ENAEXTERNAL:
|
||||
en.en_static = TRUE;
|
||||
case ENEXTERNAL:
|
||||
en.en_ext = OBJ(lnp);
|
||||
break;
|
||||
case ENINDIR:
|
||||
if (INSTR(lnp) == op_loi || INSTR(lnp) == op_sti) {
|
||||
Pop(&tk, (offset) ps);
|
||||
*l_out = tk.tk_lfirst;
|
||||
vn = tk.tk_vn;
|
||||
}
|
||||
en.en_ind = vn;
|
||||
break;
|
||||
case ENAOFFSETTED:
|
||||
en.en_static = TRUE;
|
||||
case ENOFFSETTED:
|
||||
Pop(&tk, (offset) ps);
|
||||
*l_out = tk.tk_lfirst;
|
||||
en.en_base = tk.tk_vn;
|
||||
en.en_off = off_set(lnp);
|
||||
break;
|
||||
case ENALOCBASE:
|
||||
case ENAARGBASE:
|
||||
en.en_static = TRUE;
|
||||
en.en_levels = off_set(lnp);
|
||||
break;
|
||||
case ENPROC:
|
||||
en.en_pro = PROC(lnp);
|
||||
break;
|
||||
case ENARRELEM:
|
||||
/* We gathered the information in the previous switch.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
return en_enter(&en);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
extern entity_p getentity(); /* (line_p lnp, *l_out)
|
||||
* Extract the entity lnp refers and enter it
|
||||
* in the table of entities. The main entity
|
||||
* lnp refers to is returned; sometimes there
|
||||
* is more than one entity. The first line that
|
||||
* was involved in pushing it is returned
|
||||
* through l_out.
|
||||
*/
|
||||
@@ -1,372 +0,0 @@
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/cset.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/map.h"
|
||||
#include "cs.h"
|
||||
#include "cs_aux.h"
|
||||
#include "cs_debug.h"
|
||||
#include "cs_avail.h"
|
||||
#include "cs_entity.h"
|
||||
|
||||
STATIC base_valno(enp)
|
||||
entity_p enp;
|
||||
{
|
||||
/* Return the value number of the (base) address of an indirectly
|
||||
* accessed entity.
|
||||
*/
|
||||
switch (enp->en_kind) {
|
||||
default:
|
||||
assert(FALSE);
|
||||
break;
|
||||
case ENINDIR:
|
||||
return enp->en_ind;
|
||||
case ENOFFSETTED:
|
||||
return enp->en_base;
|
||||
case ENARRELEM:
|
||||
return enp->en_arbase;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
STATIC entity_p find_base(vn)
|
||||
valnum vn;
|
||||
{
|
||||
/* Vn is the valuenumber of the (base) address of an indirectly
|
||||
* accessed entity. Return the entity that holds this address
|
||||
* recursively.
|
||||
*/
|
||||
register Lindex i;
|
||||
register avail_p ravp;
|
||||
|
||||
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
|
||||
register entity_p renp = en_elem(i);
|
||||
|
||||
if (renp->en_vn == vn) {
|
||||
switch (renp->en_kind) {
|
||||
case ENAEXTERNAL:
|
||||
case ENALOCAL:
|
||||
case ENALOCBASE:
|
||||
case ENAARGBASE:
|
||||
return renp;
|
||||
case ENAOFFSETTED:
|
||||
return find_base(renp->en_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We couldn't find it among the entities.
|
||||
* Let's try the available expressions.
|
||||
*/
|
||||
for (ravp = avails; ravp != (avail_p) 0; ravp = ravp->av_before) {
|
||||
if (ravp->av_result == vn) {
|
||||
if (ravp->av_instr == (byte) op_aar)
|
||||
return find_base(ravp->av_ofirst);
|
||||
if (ravp->av_instr == (byte) op_ads)
|
||||
return find_base(ravp->av_oleft);
|
||||
}
|
||||
}
|
||||
|
||||
/* Bad luck. */
|
||||
return (entity_p) 0;
|
||||
}
|
||||
|
||||
STATIC bool obj_overlap(op1, op2)
|
||||
obj_p op1, op2;
|
||||
{
|
||||
/* Op1 and op2 point to two objects in the same datablock.
|
||||
* Obj_overlap returns whether these objects might overlap.
|
||||
*/
|
||||
obj_p tmp;
|
||||
|
||||
if (op1->o_off > op2->o_off) {
|
||||
/* Exchange them. */
|
||||
tmp = op1; op1 = op2; op2 = tmp;
|
||||
}
|
||||
return op1->o_size == UNKNOWN_SIZE ||
|
||||
op1->o_off + op1->o_size > op2->o_off;
|
||||
}
|
||||
|
||||
#define same_datablock(o1, o2) ((o1)->o_dblock == (o2)->o_dblock)
|
||||
|
||||
STATIC bool addr_local(enp)
|
||||
entity_p enp;
|
||||
{
|
||||
/* Is enp the address of a stack item. */
|
||||
|
||||
if (enp == (entity_p) 0) return FALSE;
|
||||
|
||||
return enp->en_kind == ENALOCAL || enp->en_kind == ENALOCBASE ||
|
||||
enp->en_kind == ENAARGBASE;
|
||||
}
|
||||
|
||||
STATIC bool addr_external(enp)
|
||||
entity_p enp;
|
||||
{
|
||||
/* Is enp the address of an external. */
|
||||
|
||||
return enp != (entity_p) 0 && enp->en_kind == ENAEXTERNAL;
|
||||
}
|
||||
|
||||
STATIC kill_external(obp, indir)
|
||||
obj_p obp;
|
||||
int indir;
|
||||
{
|
||||
/* A store is done via the object in obp. If this store is direct
|
||||
* we kill directly accessed entities in the same data block only
|
||||
* if they overlap with obp, otherwise we kill everything in the
|
||||
* data block. Indirectly accessed entities of which it can not be
|
||||
* proven taht they are not in the same data block, are killed in
|
||||
* both cases.
|
||||
*/
|
||||
register Lindex i;
|
||||
|
||||
OUTTRACE("kill external", 0);
|
||||
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
|
||||
entity_p enp = en_elem(i);
|
||||
entity_p base;
|
||||
|
||||
switch (enp->en_kind) {
|
||||
case ENEXTERNAL:
|
||||
if (!same_datablock(enp->en_ext, obp))
|
||||
break;
|
||||
if (!indir && !obj_overlap(enp->en_ext, obp))
|
||||
break;
|
||||
OUTTRACE("kill %d", enp->en_vn);
|
||||
enp->en_vn = newvalnum();
|
||||
break;
|
||||
case ENINDIR:
|
||||
case ENOFFSETTED:
|
||||
case ENARRELEM:
|
||||
/* We spare its value number if we are sure
|
||||
* that its (base) address points into the
|
||||
* stack or into another data block.
|
||||
*/
|
||||
base = find_base(base_valno(enp));
|
||||
if (addr_local(base))
|
||||
break;
|
||||
if (addr_external(base) &&
|
||||
!same_datablock(base->en_ext, obp)
|
||||
)
|
||||
break;
|
||||
OUTTRACE("kill %d", enp->en_vn);
|
||||
enp->en_vn = newvalnum();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC bool loc_overlap(enp1, enp2)
|
||||
entity_p enp1, enp2;
|
||||
{
|
||||
/* Enp1 and enp2 point to two locals. Loc_overlap returns whether
|
||||
* they overlap.
|
||||
*/
|
||||
entity_p tmp;
|
||||
|
||||
assert(enp1->en_kind == ENLOCAL && enp2->en_kind == ENLOCAL);
|
||||
|
||||
if (enp1->en_loc > enp2->en_loc) {
|
||||
/* Exchange them. */
|
||||
tmp = enp1; enp1 = enp2; enp2 = tmp;
|
||||
}
|
||||
if (enp1->en_loc < 0 && enp2->en_loc >= 0)
|
||||
return FALSE; /* Locals and parameters do not overlap. */
|
||||
else return enp1->en_size == UNKNOWN_SIZE ||
|
||||
enp1->en_loc + enp1->en_size > enp2->en_loc;
|
||||
}
|
||||
|
||||
STATIC kill_local(enp, indir)
|
||||
entity_p enp;
|
||||
bool indir;
|
||||
{
|
||||
/* This time a store is done into an ENLOCAL. */
|
||||
|
||||
register Lindex i;
|
||||
|
||||
OUTTRACE("kill local", 0);
|
||||
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
|
||||
entity_p rep = en_elem(i);
|
||||
entity_p base;
|
||||
|
||||
switch (rep->en_kind) {
|
||||
case ENLOCAL:
|
||||
if (indir) {
|
||||
/* Kill locals that might be stored into
|
||||
* via a pointer. Note: enp not used.
|
||||
*/
|
||||
if (!is_regvar(rep->en_loc)) {
|
||||
OUTTRACE("kill %d", rep->en_vn);
|
||||
rep->en_vn = newvalnum();
|
||||
}
|
||||
} else if (loc_overlap(rep, enp)) {
|
||||
/* Only kill overlapping locals. */
|
||||
OUTTRACE("kill %d", rep->en_vn);
|
||||
rep->en_vn = newvalnum();
|
||||
}
|
||||
break;
|
||||
case ENINDIR:
|
||||
case ENOFFSETTED:
|
||||
case ENARRELEM:
|
||||
if (!is_regvar(enp->en_loc)) {
|
||||
base = find_base(base_valno(rep));
|
||||
if (!addr_external(base)) {
|
||||
OUTTRACE("kill %d", rep->en_vn);
|
||||
rep->en_vn = newvalnum();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC kill_sim()
|
||||
{
|
||||
/* A store is done into the ENIGNMASK. */
|
||||
|
||||
register Lindex i;
|
||||
|
||||
OUTTRACE("kill sim", 0);
|
||||
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
|
||||
register entity_p rep = en_elem(i);
|
||||
|
||||
if (rep->en_kind == ENIGNMASK) {
|
||||
OUTTRACE("kill %d", rep->en_vn);
|
||||
rep->en_vn = newvalnum();
|
||||
return; /* There is only one ignoremask. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kill_direct(enp)
|
||||
entity_p enp;
|
||||
{
|
||||
/* A store will be done into enp. We must forget the values of all the
|
||||
* entities this one may overlap with.
|
||||
*/
|
||||
switch (enp->en_kind) {
|
||||
default:
|
||||
assert(FALSE);
|
||||
break;
|
||||
case ENEXTERNAL:
|
||||
kill_external(enp->en_ext, FALSE);
|
||||
break;
|
||||
case ENLOCAL:
|
||||
kill_local(enp, FALSE);
|
||||
break;
|
||||
case ENIGNMASK:
|
||||
kill_sim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kill_indir(enp)
|
||||
entity_p enp;
|
||||
{
|
||||
/* An indirect store is done, in an ENINDIR,
|
||||
* an ENOFFSETTED or an ENARRELEM.
|
||||
*/
|
||||
entity_p p;
|
||||
|
||||
/* If we can find the (base) address of this entity, then we can spare
|
||||
* the entities that are provably not pointed to by the address.
|
||||
* We will also make use of the MES 3 pseudo's, generated by
|
||||
* the front-end. When a MES 3 is generated for a local, this local
|
||||
* will not be referenced indirectly.
|
||||
*/
|
||||
if ((p = find_base(base_valno(enp))) == (entity_p) 0) {
|
||||
kill_much(); /* Kill all entities without registermessage. */
|
||||
} else {
|
||||
switch (p->en_kind) {
|
||||
case ENAEXTERNAL:
|
||||
/* An indirect store into global data. */
|
||||
kill_external(p->en_ext, TRUE);
|
||||
break;
|
||||
case ENALOCAL:
|
||||
case ENALOCBASE:
|
||||
case ENAARGBASE:
|
||||
/* An indirect store into stack data. */
|
||||
kill_local(p, TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kill_much()
|
||||
{
|
||||
/* Kills all killable entities,
|
||||
* except the locals for which a registermessage was generated.
|
||||
*/
|
||||
register Lindex i;
|
||||
|
||||
OUTTRACE("kill much", 0);
|
||||
for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) {
|
||||
register entity_p rep = en_elem(i);
|
||||
|
||||
if (rep->en_static) continue;
|
||||
if (rep->en_kind == ENLOCAL && is_regvar(rep->en_loc)) continue;
|
||||
OUTTRACE("kill %d", rep->en_vn);
|
||||
rep->en_vn = newvalnum();
|
||||
}
|
||||
}
|
||||
|
||||
STATIC bool bad_procflags(pp)
|
||||
proc_p pp;
|
||||
{
|
||||
/* Return whether the flags about the procedure in pp indicate
|
||||
* that we have little information about it. It might be that
|
||||
* we haven't seen the text of pp, or that we have seen that pp
|
||||
* calls a procedure which we haven't seen the text of.
|
||||
*/
|
||||
return !(pp->p_flags1 & PF_BODYSEEN) || (pp->p_flags1 & PF_CALUNKNOWN);
|
||||
}
|
||||
|
||||
STATIC kill_globset(s)
|
||||
cset s;
|
||||
{
|
||||
/* S is a set of global variables that might be changed.
|
||||
* We act as if a direct store is done into each of them.
|
||||
*/
|
||||
register Cindex i;
|
||||
|
||||
OUTTRACE("kill globset", 0);
|
||||
for (i = Cfirst(s); i != (Cindex) 0; i = Cnext(i,s)) {
|
||||
kill_external(omap[Celem(i)], FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
kill_call(pp)
|
||||
proc_p pp;
|
||||
{
|
||||
/* Kill everything that might be destroyed by calling
|
||||
* the procedure in pp.
|
||||
*/
|
||||
if (bad_procflags(pp)) {
|
||||
/* We don't know enough about this procedure. */
|
||||
kill_much();
|
||||
} else if (pp->p_change->c_flags & CF_INDIR) {
|
||||
/* The procedure does an indirect store. */
|
||||
kill_much();
|
||||
} else {
|
||||
/* Procedure might affect global data. */
|
||||
kill_globset(pp->p_change->c_ext);
|
||||
}
|
||||
}
|
||||
|
||||
kill_all()
|
||||
{
|
||||
/* Kills all entities. */
|
||||
|
||||
register Lindex i;
|
||||
|
||||
OUTTRACE("kill all entities", 0);
|
||||
for (i = Lfirst(entities); i != (Lindex) i; i = Lnext(i, entities)) {
|
||||
entity_p enp = en_elem(i);
|
||||
|
||||
OUTTRACE("kill %d", enp->en_vn);
|
||||
enp->en_vn = newvalnum();
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
extern kill_call(); /* (proc_p pp)
|
||||
* Kill all entities that might have an other value
|
||||
* after execution of the procedure in pp.
|
||||
*/
|
||||
|
||||
extern kill_much(); /* ()
|
||||
* Kill all killable entities except those for which
|
||||
* a register message was generated.
|
||||
* Constants, addresses, etc are not killable.
|
||||
*/
|
||||
|
||||
extern kill_indir(); /* (entity_p enp)
|
||||
* Kill all entities that might have an other value
|
||||
* after indirect assignment to the entity in enp.
|
||||
*/
|
||||
|
||||
extern kill_direct(); /* (entity_p enp)
|
||||
* Kill all entities that might have an other value
|
||||
* after direct assignment to the entity in enp.
|
||||
*/
|
||||
|
||||
extern kill_all(); /* ()
|
||||
* Kill all entities.
|
||||
*/
|
||||
@@ -1,371 +0,0 @@
|
||||
/* Functions to partition the huge set of EM-instructions. */
|
||||
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_reg.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../share/types.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "cs.h"
|
||||
#include "cs_stack.h"
|
||||
|
||||
#define XXX (-1)
|
||||
#define ARGW 0
|
||||
#define WS 1
|
||||
#define PS 2
|
||||
#define FEF 3
|
||||
#define FIF 4
|
||||
#define CVT 5
|
||||
|
||||
#define ANY 0
|
||||
#define PTR 1
|
||||
#define FLT 2
|
||||
|
||||
STATIC struct {
|
||||
byte i_group; /* Group of instruction. */
|
||||
byte i_op1; /* Indication of size of operand of unary operator. */
|
||||
/* Idem for 1st operand of binary operator. */
|
||||
byte i_op2; /* Idem for 2nd operand of binary operator. */
|
||||
byte i_av; /* Idem for result of operators. */
|
||||
byte i_regtype; /* ANY, PTR, FLT. */
|
||||
} info[] = {
|
||||
XXX, XXX, XXX, XXX, XXX,
|
||||
/* aar */ TERNAIR_OP, XXX, XXX, PS, PTR,
|
||||
/* adf */ BINAIR_OP, ARGW, ARGW, ARGW, FLT,
|
||||
/* adi */ BINAIR_OP, ARGW, ARGW, ARGW, ANY,
|
||||
/* adp */ EXPENSIVE_LOAD, XXX, XXX, XXX, PTR,
|
||||
/* ads */ BINAIR_OP, PS, ARGW, PS, PTR,
|
||||
/* adu */ BINAIR_OP, ARGW, ARGW, ARGW, ANY,
|
||||
/* and */ BINAIR_OP, ARGW, ARGW, ARGW, ANY,
|
||||
/* asp */ FIDDLE_STACK, XXX, XXX, XXX, XXX,
|
||||
/* ass */ FIDDLE_STACK, XXX, XXX, XXX, XXX,
|
||||
/* beq */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* bge */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* bgt */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* ble */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* blm */ HOPELESS, XXX, XXX, XXX, XXX,
|
||||
/* bls */ HOPELESS, XXX, XXX, XXX, XXX,
|
||||
/* blt */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* bne */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* bra */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* cai */ SIDE_EFFECTS, XXX, XXX, XXX, XXX,
|
||||
/* cal */ SIDE_EFFECTS, XXX, XXX, XXX, XXX,
|
||||
/* cff */ TERNAIR_OP, XXX, XXX, CVT, FLT,
|
||||
/* cfi */ TERNAIR_OP, XXX, XXX, CVT, ANY,
|
||||
/* cfu */ TERNAIR_OP, XXX, XXX, CVT, ANY,
|
||||
/* cif */ TERNAIR_OP, XXX, XXX, CVT, FLT,
|
||||
/* cii */ TERNAIR_OP, XXX, XXX, CVT, ANY,
|
||||
/* ciu */ TERNAIR_OP, XXX, XXX, CVT, ANY,
|
||||
/* cmf */ BINAIR_OP, ARGW, ARGW, WS, ANY,
|
||||
/* cmi */ BINAIR_OP, ARGW, ARGW, WS, ANY,
|
||||
/* cmp */ BINAIR_OP, PS, PS, WS, ANY,
|
||||
/* cms */ BINAIR_OP, ARGW, ARGW, WS, ANY,
|
||||
/* cmu */ BINAIR_OP, ARGW, ARGW, WS, ANY,
|
||||
/* com */ UNAIR_OP, ARGW, XXX, ARGW, ANY,
|
||||
/* csa */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* csb */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* cuf */ TERNAIR_OP, XXX, XXX, CVT, FLT,
|
||||
/* cui */ TERNAIR_OP, XXX, XXX, CVT, ANY,
|
||||
/* cuu */ TERNAIR_OP, XXX, XXX, CVT, ANY,
|
||||
/* dch */ UNAIR_OP, PS, XXX, PS, PTR,
|
||||
/* dec */ UNAIR_OP, WS, XXX, WS, ANY,
|
||||
/* dee */ KILL_ENTITY, XXX, XXX, XXX, XXX,
|
||||
/* del */ KILL_ENTITY, XXX, XXX, XXX, XXX,
|
||||
/* dup */ FIDDLE_STACK, XXX, XXX, XXX, XXX,
|
||||
/* dus */ FIDDLE_STACK, XXX, XXX, XXX, XXX,
|
||||
/* dvf */ BINAIR_OP, ARGW, ARGW, ARGW, FLT,
|
||||
/* dvi */ BINAIR_OP, ARGW, ARGW, ARGW, ANY,
|
||||
/* dvu */ BINAIR_OP, ARGW, ARGW, ARGW, ANY,
|
||||
/* exg */ FIDDLE_STACK, XXX, XXX, XXX, XXX,
|
||||
/* fef */ UNAIR_OP, ARGW, XXX, FEF, XXX,
|
||||
/* fif */ BINAIR_OP, ARGW, ARGW, FIF, XXX,
|
||||
/* fil */ IGNORE, XXX, XXX, XXX, XXX,
|
||||
/* gto */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* inc */ UNAIR_OP, WS, XXX, WS, ANY,
|
||||
/* ine */ KILL_ENTITY, XXX, XXX, XXX, XXX,
|
||||
/* inl */ KILL_ENTITY, XXX, XXX, XXX, XXX,
|
||||
/* inn */ BINAIR_OP, ARGW, WS, WS, ANY,
|
||||
/* ior */ BINAIR_OP, ARGW, ARGW, ARGW, ANY,
|
||||
/* lae */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* lal */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* lar */ LOAD_ARRAY, XXX, XXX, XXX, ANY,
|
||||
/* ldc */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* lde */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* ldf */ EXPENSIVE_LOAD, XXX, XXX, XXX, ANY,
|
||||
/* ldl */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* lfr */ FIDDLE_STACK, XXX, XXX, XXX, XXX,
|
||||
/* lil */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* lim */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* lin */ IGNORE, XXX, XXX, XXX, XXX,
|
||||
/* lni */ IGNORE, XXX, XXX, XXX, XXX,
|
||||
/* loc */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* loe */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* lof */ EXPENSIVE_LOAD, XXX, XXX, XXX, ANY,
|
||||
/* loi */ EXPENSIVE_LOAD, XXX, XXX, XXX, ANY,
|
||||
/* lol */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* lor */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* los */ FIDDLE_STACK, XXX, XXX, XXX, XXX,
|
||||
/* lpb */ UNAIR_OP, PS, XXX, PS, PTR,
|
||||
/* lpi */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* lxa */ EXPENSIVE_LOAD, XXX, XXX, XXX, PTR,
|
||||
/* lxl */ EXPENSIVE_LOAD, XXX, XXX, XXX, PTR,
|
||||
/* mlf */ BINAIR_OP, ARGW, ARGW, ARGW, FLT,
|
||||
/* mli */ BINAIR_OP, ARGW, ARGW, ARGW, ANY,
|
||||
/* mlu */ BINAIR_OP, ARGW, ARGW, ARGW, ANY,
|
||||
/* mon */ HOPELESS, XXX, XXX, XXX, XXX,
|
||||
/* ngf */ UNAIR_OP, ARGW, XXX, ARGW, FLT,
|
||||
/* ngi */ UNAIR_OP, ARGW, XXX, ARGW, ANY,
|
||||
/* nop */ IGNORE, XXX, XXX, XXX, XXX,
|
||||
/* rck */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* ret */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* rmi */ BINAIR_OP, ARGW, ARGW, ARGW, ANY,
|
||||
/* rmu */ BINAIR_OP, ARGW, ARGW, ARGW, ANY,
|
||||
/* rol */ BINAIR_OP, ARGW, WS, ARGW, ANY,
|
||||
/* ror */ BINAIR_OP, ARGW, WS, ARGW, ANY,
|
||||
/* rtt */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* sar */ STORE_ARRAY, XXX, XXX, XXX, XXX,
|
||||
/* sbf */ BINAIR_OP, ARGW, ARGW, ARGW, FLT,
|
||||
/* sbi */ BINAIR_OP, ARGW, ARGW, ARGW, ANY,
|
||||
/* sbs */ BINAIR_OP, PS, PS, ARGW, ANY,
|
||||
/* sbu */ BINAIR_OP, ARGW, ARGW, ARGW, ANY,
|
||||
/* sde */ STORE_DIRECT, XXX, XXX, XXX, XXX,
|
||||
/* sdf */ STORE_INDIR, XXX, XXX, XXX, XXX,
|
||||
/* sdl */ STORE_DIRECT, XXX, XXX, XXX, XXX,
|
||||
/* set */ UNAIR_OP, WS, XXX, ARGW, ANY,
|
||||
/* sig */ FIDDLE_STACK, XXX, XXX, XXX, XXX,
|
||||
/* sil */ STORE_INDIR, XXX, XXX, XXX, XXX,
|
||||
/* sim */ STORE_DIRECT, XXX, XXX, XXX, XXX,
|
||||
/* sli */ BINAIR_OP, ARGW, WS, ARGW, ANY,
|
||||
/* slu */ BINAIR_OP, ARGW, WS, ARGW, ANY,
|
||||
/* sri */ BINAIR_OP, ARGW, WS, ARGW, ANY,
|
||||
/* sru */ BINAIR_OP, ARGW, WS, ARGW, ANY,
|
||||
/* ste */ STORE_DIRECT, XXX, XXX, XXX, XXX,
|
||||
/* stf */ STORE_INDIR, XXX, XXX, XXX, XXX,
|
||||
/* sti */ STORE_INDIR, XXX, XXX, XXX, XXX,
|
||||
/* stl */ STORE_DIRECT, XXX, XXX, XXX, XXX,
|
||||
/* str */ HOPELESS, XXX, XXX, XXX, XXX,
|
||||
/* sts */ HOPELESS, XXX, XXX, XXX, XXX,
|
||||
/* teq */ UNAIR_OP, WS, XXX, WS, ANY,
|
||||
/* tge */ UNAIR_OP, WS, XXX, WS, ANY,
|
||||
/* tgt */ UNAIR_OP, WS, XXX, WS, ANY,
|
||||
/* tle */ UNAIR_OP, WS, XXX, WS, ANY,
|
||||
/* tlt */ UNAIR_OP, WS, XXX, WS, ANY,
|
||||
/* tne */ UNAIR_OP, WS, XXX, WS, ANY,
|
||||
/* trp */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* xor */ BINAIR_OP, ARGW, ARGW, ARGW, ANY,
|
||||
/* zeq */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* zer */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* zge */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* zgt */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* zle */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* zlt */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* zne */ BBLOCK_END, XXX, XXX, XXX, XXX,
|
||||
/* zre */ KILL_ENTITY, XXX, XXX, XXX, XXX,
|
||||
/* zrf */ SIMPLE_LOAD, XXX, XXX, XXX, XXX,
|
||||
/* zrl */ KILL_ENTITY, XXX, XXX, XXX, XXX
|
||||
};
|
||||
|
||||
#define GROUP(n) (info[n].i_group)
|
||||
#define OP1SIZE(l) (info[INSTR(l)].i_op1)
|
||||
#define OP2SIZE(l) (info[INSTR(l)].i_op2)
|
||||
#define AVSIZE(l) (info[INSTR(l)].i_av)
|
||||
#define REGTYPE(n) (info[n].i_regtype)
|
||||
|
||||
int instrgroup(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
if (INSTR(lnp) == op_lor && SHORT(lnp) == 1) {
|
||||
/* We can't do anything with the stackpointer. */
|
||||
return FIDDLE_STACK;
|
||||
}
|
||||
if (INSTR(lnp) < sp_fmnem || INSTR(lnp) > sp_lmnem) {
|
||||
VI((short) INSTR(lnp));
|
||||
return IGNORE;
|
||||
}
|
||||
return GROUP(INSTR(lnp));
|
||||
}
|
||||
|
||||
bool stack_group(instr)
|
||||
int instr;
|
||||
{
|
||||
/* Is this an instruction that only does something to the top of
|
||||
* the stack?
|
||||
*/
|
||||
switch (GROUP(instr)) {
|
||||
case SIMPLE_LOAD:
|
||||
case EXPENSIVE_LOAD:
|
||||
case LOAD_ARRAY:
|
||||
case UNAIR_OP:
|
||||
case BINAIR_OP:
|
||||
case TERNAIR_OP:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC offset argw(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* Some EM-instructions have their argument either on the same line,
|
||||
* or on top of the stack. We give up when the argument is on top of
|
||||
* the stack.
|
||||
*/
|
||||
struct token dummy;
|
||||
|
||||
if (TYPE(lnp) != OPNO) {
|
||||
return off_set(lnp);
|
||||
} else {
|
||||
Pop(&dummy, (offset) ws);
|
||||
return UNKNOWN_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
offset op11size(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* Returns the size of the first argument of
|
||||
* the unary operator in lnp.
|
||||
*/
|
||||
|
||||
switch (OP1SIZE(lnp)) {
|
||||
case ARGW:
|
||||
return argw(lnp);
|
||||
case WS:
|
||||
return ws;
|
||||
case PS:
|
||||
return ps;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
offset op12size(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* Same for first of binary. */
|
||||
|
||||
switch (OP1SIZE(lnp)) {
|
||||
case ARGW:
|
||||
return argw(lnp);
|
||||
case PS:
|
||||
return ps;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
offset op22size(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
switch (OP2SIZE(lnp)) {
|
||||
case ARGW:
|
||||
return argw(lnp);
|
||||
case WS:
|
||||
return ws;
|
||||
case PS:
|
||||
return ps;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* Ternary operators are op_aar and conversions between types and/or sizes. */
|
||||
|
||||
offset op13size(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* When the instruction is a conversion, the size of the first
|
||||
* operand is the value of the second operand.
|
||||
* We only handle the most likely case, namely that the second operand
|
||||
* was pushed by a loc-instruction.
|
||||
*/
|
||||
if (INSTR(lnp) == op_aar) return ps;
|
||||
|
||||
if (lnp->l_prev != (line_p) 0 &&
|
||||
lnp->l_prev->l_prev != (line_p) 0 &&
|
||||
INSTR(lnp->l_prev->l_prev) == op_loc
|
||||
)
|
||||
return off_set(lnp->l_prev->l_prev);
|
||||
else
|
||||
return UNKNOWN_SIZE;
|
||||
}
|
||||
|
||||
offset op23size(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
if (INSTR(lnp) == op_aar)
|
||||
return argw(lnp);
|
||||
else
|
||||
return ws;
|
||||
}
|
||||
|
||||
offset op33size(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
if (INSTR(lnp) == op_aar)
|
||||
return ps;
|
||||
else
|
||||
return ws;
|
||||
}
|
||||
|
||||
offset avsize(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* Returns the size of the result of the instruction in lnp.
|
||||
* If the instruction is a conversion this size is given on the stack.
|
||||
* We only handle the case that this value was pushed by a loc.
|
||||
*/
|
||||
offset size;
|
||||
|
||||
switch (AVSIZE(lnp)) {
|
||||
case ARGW:
|
||||
return argw(lnp);
|
||||
case WS:
|
||||
return ws;
|
||||
case PS:
|
||||
return ps;
|
||||
case FEF:
|
||||
if ((size = argw(lnp)) != UNKNOWN_SIZE)
|
||||
return size + ws;
|
||||
else
|
||||
return UNKNOWN_SIZE;
|
||||
case FIF:
|
||||
if ((size = argw(lnp)) != UNKNOWN_SIZE)
|
||||
return size + size;
|
||||
else
|
||||
return UNKNOWN_SIZE;
|
||||
case CVT:
|
||||
if (lnp->l_prev != (line_p) 0 &&
|
||||
INSTR(lnp->l_prev) == op_loc
|
||||
)
|
||||
return off_set(lnp->l_prev);
|
||||
else
|
||||
return UNKNOWN_SIZE;
|
||||
default:
|
||||
assert(FALSE);
|
||||
break;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
int regtype(instr)
|
||||
byte instr;
|
||||
{
|
||||
switch (REGTYPE(instr & BMASK)) {
|
||||
case ANY:
|
||||
return reg_any;
|
||||
case PTR:
|
||||
return reg_pointer;
|
||||
case FLT:
|
||||
return reg_float;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/* These routines partition the huge set of EM-instructions in
|
||||
* "manageable chunks.
|
||||
*/
|
||||
|
||||
extern int instrgroup(); /* (line_p lnp)
|
||||
* Return the group into which the instruction
|
||||
* in lnp belongs to.
|
||||
*/
|
||||
|
||||
extern bool stack_group(); /* (int instr)
|
||||
* Return whether instr is an instruction that
|
||||
* only changes the state of the stack, i.e.
|
||||
* is a "true" operator.
|
||||
*/
|
||||
|
||||
extern offset op11size(); /* (line_p lnp)
|
||||
* Return the size of the operand of the unary
|
||||
* operator in lnp.
|
||||
*/
|
||||
|
||||
extern offset op12size(); /* (line_p lnp)
|
||||
* Return the size of the first operand of the
|
||||
* binary operator in lnp.
|
||||
*/
|
||||
|
||||
extern offset op22size(); /* (line_p lnp)
|
||||
* Return the size of the second operand of the
|
||||
* binary operator in lnp.
|
||||
*/
|
||||
|
||||
extern offset op13size(); /* (line_p lnp)
|
||||
* Return the size of the first operand of the
|
||||
* ternary operator in lnp.
|
||||
*/
|
||||
|
||||
extern offset op23size(); /* (line_p lnp)
|
||||
* Return the size of the second operand of the
|
||||
* ternary operator in lnp.
|
||||
*/
|
||||
|
||||
extern offset op33size(); /* (line_p lnp)
|
||||
* Return the size of the third operand of the
|
||||
* ternary operator in lnp.
|
||||
*/
|
||||
|
||||
extern offset avsize(); /* (line_p lnp)
|
||||
* Return the size of the result of the
|
||||
* operator in lnp.
|
||||
*/
|
||||
|
||||
extern int regtype(); /* (byte instr)
|
||||
* Return in what kind of machine-register
|
||||
* the result of instr should be stored:
|
||||
* pointer, float, or any.
|
||||
*/
|
||||
@@ -1,207 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/cset.h"
|
||||
#include "../share/lset.h"
|
||||
#include "cs.h"
|
||||
#include "cs_aux.h"
|
||||
#include "cs_debug.h"
|
||||
#include "cs_avail.h"
|
||||
#include "cs_partit.h"
|
||||
|
||||
STATIC cset addr_modes;
|
||||
STATIC cset cheaps;
|
||||
STATIC cset forbidden;
|
||||
STATIC short LX_threshold;
|
||||
STATIC short AR_limit;
|
||||
STATIC bool DO_sli;
|
||||
|
||||
STATIC get_instrs(f, s_p)
|
||||
FILE *f;
|
||||
cset *s_p;
|
||||
{
|
||||
/* Read a set of instructions from inputfile f into *s_p.
|
||||
* Such a set must be delimited by a number lower than
|
||||
* the number of the first EM mnemonic.
|
||||
*/
|
||||
int instr;
|
||||
|
||||
fscanf(f, "%d", &instr);
|
||||
while (instr >= sp_fmnem) {
|
||||
Cadd((Celem_t) instr, s_p);
|
||||
fscanf(f, "%d", &instr);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC choose_cset(f, s_p)
|
||||
FILE *f;
|
||||
cset *s_p;
|
||||
{
|
||||
/* Read two compact sets of EM instructions from inputfile f.
|
||||
* Choose the first if we optimize with respect to time,
|
||||
* the second if we optimize with respect to space, as
|
||||
* indicated by time_space_ratio.
|
||||
*/
|
||||
cset cs1, cs2; /* Two dummy sets. */
|
||||
|
||||
*s_p = Cempty_set((short) sp_lmnem);
|
||||
|
||||
cs1 = Cempty_set((short) sp_lmnem);
|
||||
get_instrs(f, &cs1);
|
||||
cs2 = Cempty_set((short) sp_lmnem);
|
||||
get_instrs(f, &cs2);
|
||||
|
||||
Ccopy_set(time_space_ratio >= 50 ? cs1 : cs2, s_p);
|
||||
|
||||
Cdeleteset(cs1); Cdeleteset(cs2);
|
||||
}
|
||||
|
||||
cs_machinit(f)
|
||||
FILE *f;
|
||||
{
|
||||
char s[100];
|
||||
int time, space;
|
||||
|
||||
/* Find piece that is relevant for this phase. */
|
||||
do {
|
||||
while (getc(f) != '\n');
|
||||
fscanf(f, "%s", s);
|
||||
} while (strcmp(s, "%%CS"));
|
||||
|
||||
/* Choose a set of instructions which must only be eliminated
|
||||
* if they are at the root of another expression.
|
||||
*/
|
||||
choose_cset(f, &addr_modes);
|
||||
|
||||
/* Choose a set of cheap instructions; i.e. instructions that
|
||||
* are cheaper than a move to save the result of such an
|
||||
* instruction.
|
||||
*/
|
||||
choose_cset(f, &cheaps);
|
||||
|
||||
/* Read how many lexical levels back an LXL/LXA instruction
|
||||
* must at least look before it will be eliminated.
|
||||
*/
|
||||
fscanf(f, "%d %d", &time, &space);
|
||||
LX_threshold = time_space_ratio >= 50 ? time : space;
|
||||
|
||||
/* Read what the size of an array-element may be,
|
||||
* before we think that it is to big to replace
|
||||
* a LAR/SAR of it by AAR LOI/STI <size>.
|
||||
*/
|
||||
fscanf(f, "%d", &space);
|
||||
AR_limit = space;
|
||||
|
||||
/* Read whether we must eliminate an SLI instruction
|
||||
* when it is part of an array-index computation.
|
||||
*/
|
||||
fscanf(f, "%d %d", &time, &space);
|
||||
DO_sli = time_space_ratio >= 50 ? time : space;
|
||||
|
||||
/* Read a set of instructions which we do not want to eliminate.
|
||||
* Note: only instructions need be given that may in principle
|
||||
* be eliminated, but for which better code can be generated
|
||||
* when they stay, and with which is not dealt in the common
|
||||
* decision routines.
|
||||
*/
|
||||
choose_cset(f, &forbidden);
|
||||
}
|
||||
|
||||
STATIC bool is_index(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* Return whether the SLI-instruction in lnp is part of
|
||||
* an array-index computation.
|
||||
*/
|
||||
return lnp->l_prev != (line_p) 0 && INSTR(lnp->l_prev) == op_loc &&
|
||||
lnp->l_next != (line_p) 0 && INSTR(lnp->l_next) == op_ads;
|
||||
}
|
||||
|
||||
STATIC bool gains(avp)
|
||||
avail_p avp;
|
||||
{
|
||||
/* Return whether we can gain something, when we eliminate
|
||||
* an expression such as in avp. We just glue together some
|
||||
* heuristics with some user-supplied stuff.
|
||||
*/
|
||||
if (Cis_elem(avp->av_instr & BMASK, forbidden))
|
||||
return FALSE;
|
||||
|
||||
if (avp->av_instr == (byte) op_lxa || avp->av_instr == (byte) op_lxl)
|
||||
return off_set(avp->av_found) >= LX_threshold;
|
||||
|
||||
if (avp->av_instr == (byte) op_sli)
|
||||
return !is_index(avp->av_found) || DO_sli;
|
||||
|
||||
if (Cis_elem(avp->av_instr & BMASK, addr_modes))
|
||||
return instrgroup(avp->av_found->l_prev) != SIMPLE_LOAD;
|
||||
|
||||
if (Cis_elem(avp->av_instr & BMASK, cheaps))
|
||||
return avp->av_saveloc != (entity_p) 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
STATIC bool okay_lines(avp, ocp)
|
||||
avail_p avp;
|
||||
occur_p ocp;
|
||||
{
|
||||
register line_p lnp, next;
|
||||
|
||||
for (lnp = ocp->oc_lfirst; lnp != (line_p) 0; lnp = next) {
|
||||
next = lnp != ocp->oc_llast ? lnp->l_next : (line_p) 0;
|
||||
|
||||
if (INSTR(lnp) < sp_fmnem || INSTR(lnp) > sp_lmnem)
|
||||
return FALSE;
|
||||
if (!stack_group(INSTR(lnp))) {
|
||||
/* Check for SAR-instruction. */
|
||||
if (INSTR(lnp) != op_sar || next != (line_p) 0)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
/* All lines in this occurrence can in principle be eliminated;
|
||||
* no stores, messages, calls etc.
|
||||
* We now check whether it is desirable to treat a LAR or a SAR
|
||||
* as an AAR LOI/STI. This depends on the size of the array-elements.
|
||||
*/
|
||||
if (INSTR(ocp->oc_llast) == op_lar || INSTR(ocp->oc_llast) == op_sar) {
|
||||
if (avp->av_instr == (byte) op_aar && time_space_ratio < 50) {
|
||||
return array_elemsize(avp->av_othird) <= AR_limit;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool desirable(avp)
|
||||
avail_p avp;
|
||||
{
|
||||
register Lindex i, next;
|
||||
|
||||
if (!gains(avp)) {
|
||||
OUTTRACE("no gain", 0);
|
||||
SHOWAVAIL(avp);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Walk through the occurrences to see whether it is okay to
|
||||
* eliminate them. If not, remove them from the set.
|
||||
*/
|
||||
for (i = Lfirst(avp->av_occurs); i != (Lindex) 0; i = next) {
|
||||
next = Lnext(i, avp->av_occurs);
|
||||
|
||||
if (!okay_lines(avp, occ_elem(i))) {
|
||||
OUTTRACE("may not eliminate", 0);
|
||||
# ifdef TRACE
|
||||
SHOWOCCUR(occ_elem(i));
|
||||
# endif
|
||||
oldoccur(occ_elem(i));
|
||||
Lremove(Lelem(i), &avp->av_occurs);
|
||||
}
|
||||
}
|
||||
|
||||
return Lnrelems(avp->av_occurs) > 0;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
extern cs_machinit(); /* (FILE *f)
|
||||
* Read phase-specific information from f.
|
||||
*/
|
||||
|
||||
extern bool desirable(); /* (avail_p avp)
|
||||
* Return whether it is desirable to eliminate
|
||||
* the recurrences of the expression in avp.
|
||||
* At the same time delete the recurrences
|
||||
* for which it is not allowed.
|
||||
*/
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* S T A C K M O D U L E
|
||||
*/
|
||||
#include "../share/types.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/aux.h"
|
||||
#include "cs.h"
|
||||
#include "cs_aux.h"
|
||||
|
||||
#define STACK_DEPTH 50
|
||||
|
||||
STATIC struct token Stack[STACK_DEPTH];
|
||||
STATIC token_p free_token;
|
||||
|
||||
#define Delete_top() {--free_token; }
|
||||
#define Empty_stack() {free_token = &Stack[0]; }
|
||||
#define Stack_empty() (free_token == &Stack[0])
|
||||
#define Top (free_token - 1)
|
||||
|
||||
Push(tkp)
|
||||
token_p tkp;
|
||||
{
|
||||
if (tkp->tk_size == UNKNOWN_SIZE) {
|
||||
Empty_stack(); /* The contents of the Stack is useless. */
|
||||
} else {
|
||||
assert(free_token < &Stack[STACK_DEPTH]);
|
||||
|
||||
free_token->tk_vn = tkp->tk_vn;
|
||||
free_token->tk_size = tkp->tk_size;
|
||||
free_token++->tk_lfirst = tkp->tk_lfirst;
|
||||
}
|
||||
}
|
||||
|
||||
#define WORD_MULTIPLE(n) ((n / ws) * ws + ( n % ws ? ws : 0 ))
|
||||
|
||||
Pop(tkp, size)
|
||||
token_p tkp;
|
||||
offset size;
|
||||
{
|
||||
/* Pop a token with given size from the valuenumber stack into tkp. */
|
||||
|
||||
/* First simple case. */
|
||||
if (size != UNKNOWN_SIZE && !Stack_empty() && size == Top->tk_size) {
|
||||
tkp->tk_vn = Top->tk_vn;
|
||||
tkp->tk_size = size;
|
||||
tkp->tk_lfirst = Top->tk_lfirst;
|
||||
Delete_top();
|
||||
return;
|
||||
}
|
||||
/* Now we're in trouble: we must pop something that is not there!
|
||||
* We just put a dummy into tkp and pop tokens until we've
|
||||
* popped size bytes.
|
||||
*/
|
||||
/* Create dummy. */
|
||||
tkp->tk_vn = newvalnum();
|
||||
tkp->tk_lfirst = (line_p) 0;
|
||||
|
||||
/* Now fiddle with the Stack. */
|
||||
if (Stack_empty()) return;
|
||||
if (size == UNKNOWN_SIZE) {
|
||||
Empty_stack();
|
||||
return;
|
||||
}
|
||||
if (size > Top->tk_size) {
|
||||
while (!Stack_empty() && size >= Top->tk_size) {
|
||||
size -= Top->tk_size;
|
||||
Delete_top();
|
||||
}
|
||||
}
|
||||
/* Now Stack_empty OR size < Top->tk_size. */
|
||||
if (!Stack_empty()) {
|
||||
if (Top->tk_size - size < ws) {
|
||||
Delete_top();
|
||||
} else {
|
||||
Top->tk_vn = newvalnum();
|
||||
Top->tk_size -= WORD_MULTIPLE(size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dup(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* Duplicate top bytes on the Stack. */
|
||||
|
||||
register token_p bottom = Top;
|
||||
register token_p oldtop = Top;
|
||||
register offset nbytes = off_set(lnp);
|
||||
struct token dummy;
|
||||
|
||||
/* Find the bottom of the bytes to be duplicated.
|
||||
* It is possible that we cannot find it.
|
||||
*/
|
||||
while (bottom > &Stack[0] && bottom->tk_size < nbytes) {
|
||||
nbytes -= bottom->tk_size;
|
||||
bottom--;
|
||||
}
|
||||
|
||||
if (bottom < &Stack[0]) {
|
||||
/* There was nothing. */
|
||||
dummy.tk_vn = newvalnum();
|
||||
dummy.tk_size = nbytes;
|
||||
dummy.tk_lfirst = lnp;
|
||||
Push(&dummy);
|
||||
} else {
|
||||
if (bottom->tk_size < nbytes) {
|
||||
/* Not enough, bottom == &Stack[0]. */
|
||||
dummy.tk_vn = newvalnum();
|
||||
dummy.tk_size = nbytes - bottom->tk_size;
|
||||
dummy.tk_lfirst = lnp;
|
||||
Push(&dummy);
|
||||
} else if (bottom->tk_size > nbytes) {
|
||||
/* Not integral # tokens. */
|
||||
dummy.tk_vn = newvalnum();
|
||||
dummy.tk_size = nbytes;
|
||||
dummy.tk_lfirst = lnp;
|
||||
Push(&dummy);
|
||||
bottom++;
|
||||
}
|
||||
/* Bottom points to lowest token to be dupped. */
|
||||
while (bottom <= oldtop) {
|
||||
Push(bottom++);
|
||||
Top->tk_lfirst = lnp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clr_stack()
|
||||
{
|
||||
free_token = &Stack[0];
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
extern Push(); /* (token_p tkp)
|
||||
* Push the token in tkp on the fake-stack.
|
||||
*/
|
||||
|
||||
extern Pop(); /* (token_p tkp; offset size)
|
||||
* Pop a token of size bytes from the fake-stack
|
||||
* into tkp. If such a token is not there
|
||||
* we put a dummy in tkp and adjust the fake-stack.
|
||||
*/
|
||||
|
||||
extern Dup(); /* (line_p lnp)
|
||||
* Reflect the changes made by the dup-instruction
|
||||
* in lnp to the EM-stack into the fake-stack.
|
||||
*/
|
||||
|
||||
extern clr_stack(); /* ()
|
||||
* Clear the fake-stack.
|
||||
*/
|
||||
@@ -1,321 +0,0 @@
|
||||
|
||||
/* V A L U E N U M B E R I N G M E T H O D */
|
||||
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../share/types.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/aux.h"
|
||||
#include "cs.h"
|
||||
#include "cs_alloc.h"
|
||||
#include "cs_aux.h"
|
||||
#include "cs_entity.h"
|
||||
#include "cs_avail.h"
|
||||
#include "cs_stack.h"
|
||||
#include "cs_kill.h"
|
||||
#include "cs_partit.h"
|
||||
#include "cs_getent.h"
|
||||
|
||||
STATIC push_entity(enp, lfirst)
|
||||
entity_p enp;
|
||||
line_p lfirst;
|
||||
{
|
||||
/* Build token and Push it. */
|
||||
|
||||
struct token tk;
|
||||
|
||||
tk.tk_vn = enp->en_vn;
|
||||
tk.tk_size = enp->en_size;
|
||||
tk.tk_lfirst = lfirst;
|
||||
Push(&tk);
|
||||
}
|
||||
|
||||
STATIC put_expensive_load(bp, lnp, lfirst, enp)
|
||||
bblock_p bp;
|
||||
line_p lnp, lfirst;
|
||||
entity_p enp;
|
||||
{
|
||||
struct avail av;
|
||||
occur_p ocp;
|
||||
|
||||
av.av_instr = INSTR(lnp);
|
||||
av.av_size = enp->en_size;
|
||||
av.av_operand = enp->en_vn;
|
||||
|
||||
ocp = newoccur(lfirst, lnp, bp);
|
||||
|
||||
av_enter(&av, ocp, EXPENSIVE_LOAD);
|
||||
}
|
||||
|
||||
STATIC put_aar(bp, lnp, lfirst, enp)
|
||||
bblock_p bp;
|
||||
line_p lnp, lfirst;
|
||||
entity_p enp;
|
||||
{
|
||||
/* Enp points to an ENARRELEM. We do as if its address was computed. */
|
||||
|
||||
struct avail av;
|
||||
occur_p ocp;
|
||||
|
||||
assert(enp->en_kind == ENARRELEM);
|
||||
av.av_instr = op_aar;
|
||||
av.av_size = ps;
|
||||
av.av_ofirst = enp->en_arbase;
|
||||
av.av_osecond = enp->en_index;
|
||||
av.av_othird = enp->en_adesc;
|
||||
|
||||
ocp = newoccur(lfirst, lnp, bp);
|
||||
|
||||
av_enter(&av, ocp, TERNAIR_OP);
|
||||
}
|
||||
|
||||
STATIC push_avail(avp, lfirst)
|
||||
avail_p avp;
|
||||
line_p lfirst;
|
||||
{
|
||||
struct token tk;
|
||||
|
||||
tk.tk_vn = avp->av_result;
|
||||
tk.tk_size = avp->av_size;
|
||||
tk.tk_lfirst = lfirst;
|
||||
Push(&tk);
|
||||
}
|
||||
|
||||
STATIC push_unair_op(bp, lnp, tkp1)
|
||||
bblock_p bp;
|
||||
line_p lnp;
|
||||
token_p tkp1;
|
||||
{
|
||||
struct avail av;
|
||||
occur_p ocp;
|
||||
|
||||
av.av_instr = INSTR(lnp);
|
||||
av.av_size = avsize(lnp);
|
||||
av.av_operand = tkp1->tk_vn;
|
||||
|
||||
ocp = newoccur(tkp1->tk_lfirst, lnp, bp);
|
||||
|
||||
push_avail(av_enter(&av, ocp, UNAIR_OP), tkp1->tk_lfirst);
|
||||
}
|
||||
|
||||
STATIC push_binair_op(bp, lnp, tkp1, tkp2)
|
||||
bblock_p bp;
|
||||
line_p lnp;
|
||||
token_p tkp1, tkp2;
|
||||
{
|
||||
struct avail av;
|
||||
occur_p ocp;
|
||||
|
||||
av.av_instr = INSTR(lnp);
|
||||
av.av_size = avsize(lnp);
|
||||
av.av_oleft = tkp1->tk_vn;
|
||||
av.av_oright = tkp2->tk_vn;
|
||||
|
||||
ocp = newoccur(tkp1->tk_lfirst, lnp, bp);
|
||||
|
||||
push_avail(av_enter(&av, ocp, BINAIR_OP), tkp1->tk_lfirst);
|
||||
}
|
||||
|
||||
STATIC push_ternair_op(bp, lnp, tkp1, tkp2, tkp3)
|
||||
bblock_p bp;
|
||||
line_p lnp;
|
||||
token_p tkp1, tkp2, tkp3;
|
||||
{
|
||||
struct avail av;
|
||||
occur_p ocp;
|
||||
|
||||
av.av_instr = INSTR(lnp);
|
||||
av.av_size = avsize(lnp);
|
||||
av.av_ofirst = tkp1->tk_vn;
|
||||
av.av_osecond = tkp2->tk_vn;
|
||||
av.av_othird = tkp3->tk_vn;
|
||||
|
||||
ocp = newoccur(tkp1->tk_lfirst, lnp, bp);
|
||||
|
||||
push_avail(av_enter(&av, ocp, TERNAIR_OP), tkp1->tk_lfirst);
|
||||
}
|
||||
|
||||
STATIC fiddle_stack(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* The instruction in lnp does something to the valuenumber-stack. */
|
||||
|
||||
struct token dummy;
|
||||
offset size;
|
||||
|
||||
/* Partly initialize dummy. */
|
||||
dummy.tk_lfirst = lnp;
|
||||
|
||||
switch (INSTR(lnp)) {
|
||||
default:
|
||||
assert(FALSE);
|
||||
break;
|
||||
case op_lor:
|
||||
dummy.tk_vn = newvalnum(); dummy.tk_size = ps;
|
||||
Push(&dummy);
|
||||
break;
|
||||
case op_asp:
|
||||
if ((size = off_set(lnp)) > 0) {
|
||||
Pop(&dummy, size);
|
||||
} else {
|
||||
dummy.tk_vn = newvalnum();
|
||||
dummy.tk_size = size;
|
||||
Push(&dummy);
|
||||
}
|
||||
break;
|
||||
case op_dup:
|
||||
Dup(lnp);
|
||||
break;
|
||||
case op_ass:
|
||||
case op_dus:
|
||||
case op_exg:
|
||||
case op_los:
|
||||
/* Don't waste effort. */
|
||||
clr_stack();
|
||||
break;
|
||||
case op_sig:
|
||||
Pop(&dummy, (offset) ps);
|
||||
break;
|
||||
case op_lfr:
|
||||
dummy.tk_vn = newvalnum();
|
||||
dummy.tk_size = off_set(lnp);
|
||||
Push(&dummy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC proc_p find_proc(vn)
|
||||
valnum vn;
|
||||
{
|
||||
/* Find the procedure-identifier with valuenumber vn. */
|
||||
|
||||
entity_p enp;
|
||||
|
||||
enp = find_entity(vn);
|
||||
|
||||
if (enp != (entity_p) 0 && enp->en_kind == ENPROC)
|
||||
return enp->en_pro;
|
||||
|
||||
return (proc_p) 0;
|
||||
}
|
||||
|
||||
STATIC side_effects(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* Lnp contains a cai or cal instruction. We try to find the callee
|
||||
* and see what side-effects it has.
|
||||
*/
|
||||
struct token tk;
|
||||
proc_p pp;
|
||||
|
||||
if (INSTR(lnp) == op_cai) {
|
||||
Pop(&tk, (offset) ps);
|
||||
pp = find_proc(tk.tk_vn);
|
||||
} else {
|
||||
assert(INSTR(lnp) == op_cal);
|
||||
pp = PROC(lnp);
|
||||
}
|
||||
if (pp != (proc_p) 0) {
|
||||
kill_call(pp);
|
||||
} else {
|
||||
kill_much();
|
||||
}
|
||||
}
|
||||
|
||||
hopeless(instr)
|
||||
int instr;
|
||||
{
|
||||
/* The effect of `instr' is too difficult to
|
||||
* compute. We assume worst case behaviour.
|
||||
*/
|
||||
switch (instr) {
|
||||
default:
|
||||
assert(FALSE);
|
||||
break;
|
||||
case op_mon:
|
||||
case op_str:
|
||||
/* We can't even trust "static" entities. */
|
||||
kill_all();
|
||||
clr_stack();
|
||||
break;
|
||||
case op_blm:
|
||||
case op_bls:
|
||||
case op_sts:
|
||||
kill_much();
|
||||
clr_stack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vnm(bp)
|
||||
bblock_p bp;
|
||||
{
|
||||
register line_p lnp;
|
||||
register entity_p rep;
|
||||
line_p lfirst;
|
||||
struct token tk, tk1, tk2, tk3;
|
||||
|
||||
for (lnp = bp->b_start; lnp != (line_p) 0; lnp = lnp->l_next) {
|
||||
|
||||
rep = getentity(lnp, &lfirst);
|
||||
switch (instrgroup(lnp)) {
|
||||
case SIMPLE_LOAD:
|
||||
push_entity(rep, lfirst);
|
||||
break;
|
||||
case LOAD_ARRAY:
|
||||
put_aar(bp, lnp, lfirst, rep);
|
||||
/* Fall through ... */
|
||||
case EXPENSIVE_LOAD:
|
||||
push_entity(rep, lfirst);
|
||||
put_expensive_load(bp, lnp, lfirst, rep);
|
||||
break;
|
||||
case STORE_DIRECT:
|
||||
kill_direct(rep);
|
||||
Pop(&tk, rep->en_size);
|
||||
rep->en_vn = tk.tk_vn;
|
||||
break;
|
||||
case STORE_ARRAY:
|
||||
put_aar(bp, lnp, lfirst, rep);
|
||||
/* Fall through ... */
|
||||
case STORE_INDIR:
|
||||
kill_indir(rep);
|
||||
Pop(&tk, rep->en_size);
|
||||
rep->en_vn = tk.tk_vn;
|
||||
break;
|
||||
case UNAIR_OP:
|
||||
Pop(&tk1, op11size(lnp));
|
||||
push_unair_op(bp, lnp, &tk1);
|
||||
break;
|
||||
case BINAIR_OP:
|
||||
Pop(&tk2, op22size(lnp));
|
||||
Pop(&tk1, op12size(lnp));
|
||||
push_binair_op(bp, lnp, &tk1, &tk2);
|
||||
break;
|
||||
case TERNAIR_OP:
|
||||
Pop(&tk3, op33size(lnp));
|
||||
Pop(&tk2, op23size(lnp));
|
||||
Pop(&tk1, op13size(lnp));
|
||||
push_ternair_op(bp, lnp, &tk1, &tk2, &tk3);
|
||||
break;
|
||||
case KILL_ENTITY:
|
||||
kill_direct(rep);
|
||||
break;
|
||||
case SIDE_EFFECTS:
|
||||
side_effects(lnp);
|
||||
break;
|
||||
case FIDDLE_STACK:
|
||||
fiddle_stack(lnp);
|
||||
break;
|
||||
case IGNORE:
|
||||
break;
|
||||
case HOPELESS:
|
||||
hopeless(INSTR(lnp));
|
||||
break;
|
||||
case BBLOCK_END:
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
extern vnm(); /* (bblock_p bp)
|
||||
* Performs the valuenumbering algorithm on the basic
|
||||
* block in bp.
|
||||
*/
|
||||
@@ -1,22 +0,0 @@
|
||||
s/.*://
|
||||
s/(//
|
||||
s/)//
|
||||
s/,/ /
|
||||
s/cases//
|
||||
s/case//
|
||||
s/sizes//
|
||||
s/size//
|
||||
s/\-\>//
|
||||
s/pointer/2/g
|
||||
s/general/0/g
|
||||
s/fitbyte/1/
|
||||
s/default/0/
|
||||
s/in_0_63/2/
|
||||
s/in_0_8/3/
|
||||
s/no/0/g
|
||||
s/yes/1/g
|
||||
s/ //g
|
||||
s/ +/ /g
|
||||
s/^ //
|
||||
s/ $//
|
||||
/^$/d
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
wordsize: 2
|
||||
pointersize: 2
|
||||
%%UD
|
||||
access costs of global variables:
|
||||
(1 size)
|
||||
default -> (4,2)
|
||||
access costs of local variables:
|
||||
(1 size)
|
||||
default -> (4,2)
|
||||
%%SR
|
||||
overflow harmful?: no
|
||||
array bound harmful?: no
|
||||
%%SP
|
||||
global stack pollution allowed?: yes
|
||||
@@ -1,103 +0,0 @@
|
||||
wordsize: 2
|
||||
pointersize: 4
|
||||
%%RA
|
||||
general registers: 5
|
||||
address registers: 4
|
||||
floating point registers: 0
|
||||
|
||||
register score parameters:
|
||||
local variable:
|
||||
(2 cases)
|
||||
pointer,pointer
|
||||
(1 size)
|
||||
default -> (6,3)
|
||||
general,general
|
||||
(1 size)
|
||||
default -> (4,2)
|
||||
address of local variable:
|
||||
(2 cases)
|
||||
pointer,pointer
|
||||
(1 size)
|
||||
default -> (0,0)
|
||||
general,pointer
|
||||
(1 size)
|
||||
default -> (2,2)
|
||||
constant:
|
||||
(2 sizes)
|
||||
in_0_8 -> (0,0)
|
||||
default -> (2,2)
|
||||
double constant:
|
||||
(1 size)
|
||||
default -> (-1,-1)
|
||||
address of global variable:
|
||||
(1 size)
|
||||
default -> (4,4)
|
||||
address of procedure:
|
||||
(1 size)
|
||||
default -> (2,4)
|
||||
|
||||
opening cost parameters:
|
||||
local variable:
|
||||
(2 cases)
|
||||
pointer
|
||||
(1 size)
|
||||
default -> (6,4)
|
||||
general
|
||||
(1 size)
|
||||
default -> (8,4)
|
||||
address of local variable:
|
||||
(2 cases)
|
||||
pointer
|
||||
(1 size)
|
||||
default -> (4,2)
|
||||
general
|
||||
(1 size)
|
||||
general -> (4,2)
|
||||
constant:
|
||||
(1 size)
|
||||
default -> (4,4)
|
||||
double constant:
|
||||
(1 size)
|
||||
default -> (1000,1000)
|
||||
address of global variable:
|
||||
(1 size)
|
||||
default -> (6,6)
|
||||
address of procedure:
|
||||
(1 size)
|
||||
default -> (6,6)
|
||||
|
||||
register save costs:
|
||||
(11 cases)
|
||||
0 -> (0,0)
|
||||
1 -> (12,4)
|
||||
2 -> (24,8)
|
||||
3 -> (34,8)
|
||||
4 -> (42,8)
|
||||
5 -> (50,8)
|
||||
6 -> (58,8)
|
||||
7 -> (66,8)
|
||||
8 -> (84,8)
|
||||
9 -> (92,8)
|
||||
0 -> (0,0)
|
||||
%%UD
|
||||
access costs of global variables:
|
||||
(1 size)
|
||||
default -> (7,4)
|
||||
access costs of local variables:
|
||||
(1 size)
|
||||
default -> (4,2)
|
||||
%%SR
|
||||
overflow harmful?: no
|
||||
array bound harmful?: no
|
||||
%%CS
|
||||
#include "../../../h/em_mnem.h"
|
||||
first time then space:
|
||||
addressing modes: op_adp op_lof op_ldf op_loi op_dch op_lpb -1
|
||||
op_adp op_lof op_ldf op_loi op_dch op_lpb -1
|
||||
cheap operations: -1 -1
|
||||
lexical tresholds: 1 1
|
||||
indirection limit: 8
|
||||
do sli if index?: yes yes
|
||||
forbidden operators: -1 -1
|
||||
%%SP
|
||||
global stack pollution allowed?: no
|
||||
@@ -1,5 +0,0 @@
|
||||
for i in *.descr
|
||||
do
|
||||
m=`basename $i .descr`
|
||||
../../../lib/cpp -P -I../../../h $i | sed -f descr.sed > ../../../lib/ego/${m}descr
|
||||
done
|
||||
@@ -1,96 +0,0 @@
|
||||
wordsize: 2
|
||||
pointersize: 2
|
||||
%%RA
|
||||
general registers: 2
|
||||
address registers: 0
|
||||
floating point registers: 0
|
||||
|
||||
register score parameters:
|
||||
local variable:
|
||||
(2 cases)
|
||||
pointer,general
|
||||
(1 size)
|
||||
default -> (6,3)
|
||||
general,general
|
||||
(1 size)
|
||||
default -> (4,2)
|
||||
address of local variable:
|
||||
(2 cases)
|
||||
pointer,general
|
||||
(1 size)
|
||||
default -> (0,0)
|
||||
general,general
|
||||
(1 size)
|
||||
default -> (2,2)
|
||||
constant:
|
||||
(1 sizes)
|
||||
default -> (2,2)
|
||||
double constant:
|
||||
(1 size)
|
||||
default -> (-1,-1)
|
||||
address of global variable:
|
||||
(1 size)
|
||||
default -> (4,2)
|
||||
address of procedure:
|
||||
(1 size)
|
||||
default -> (2,2)
|
||||
|
||||
opening cost parameters:
|
||||
local variable:
|
||||
(2 cases)
|
||||
pointer
|
||||
(1 size)
|
||||
default -> (6,4)
|
||||
general
|
||||
(1 size)
|
||||
default -> (6,4)
|
||||
address of local variable:
|
||||
(2 cases)
|
||||
pointer
|
||||
(1 size)
|
||||
default -> (10,6)
|
||||
general
|
||||
(1 size)
|
||||
general -> (10,6)
|
||||
constant:
|
||||
(1 size)
|
||||
default -> (4,4)
|
||||
double constant:
|
||||
(1 size)
|
||||
default -> (1000,1000)
|
||||
address of global variable:
|
||||
(1 size)
|
||||
default -> (6,4)
|
||||
address of procedure:
|
||||
(1 size)
|
||||
default -> (6,4)
|
||||
|
||||
register save costs:
|
||||
(4 cases)
|
||||
0 -> (0,0)
|
||||
1 -> (12,0)
|
||||
2 -> (24,0)
|
||||
0 -> (0,0)
|
||||
%%UD
|
||||
access costs of global variables:
|
||||
(1 size)
|
||||
default -> (4,2)
|
||||
access costs of local variables:
|
||||
(1 size)
|
||||
default -> (4,2)
|
||||
%%SR
|
||||
overflow harmful?: no
|
||||
array bound harmful?: no
|
||||
%%CS
|
||||
#include "../../../h/em_mnem.h"
|
||||
first time then space:
|
||||
addressing modes: op_adp op_lof op_ldf op_loi op_dch op_lpb -1
|
||||
op_adp op_lof op_ldf op_loi op_dch op_lpb -1
|
||||
cheap operations: op_cii op_cui op_cfi op_ciu op_cff op_cuu op_cif -1
|
||||
op_cii op_cui op_cfi op_ciu op_cff op_cuu op_cif -1
|
||||
lexical tresholds: 1 1
|
||||
indirection limit: 8
|
||||
do sli if index?: yes yes
|
||||
forbidden operators: -1 -1
|
||||
%%SP
|
||||
global stack pollution allowed?: no
|
||||
@@ -1,117 +0,0 @@
|
||||
wordsize: 2
|
||||
pointersize: 4
|
||||
%%RA
|
||||
general registers: 3
|
||||
address registers: 4
|
||||
floating point registers: 0
|
||||
|
||||
register score parameters:
|
||||
local variable:
|
||||
(2 cases)
|
||||
pointer,pointer
|
||||
(2 sizes)
|
||||
fitbyte -> (5,2)
|
||||
default -> (4,3)
|
||||
general,general
|
||||
(2 sizes)
|
||||
fitbyte -> (3,1)
|
||||
default -> (2,2)
|
||||
address of local variable:
|
||||
(2 cases)
|
||||
pointer,pointer
|
||||
(2 sizes)
|
||||
fitbyte -> (0,1)
|
||||
default -> (0,2)
|
||||
general,pointer
|
||||
(2 sizes)
|
||||
fitbyte -> (0,1)
|
||||
default -> (0,2)
|
||||
constant:
|
||||
(3 sizes)
|
||||
in_0_63 -> (0,0)
|
||||
fitbyte -> (0,1)
|
||||
default -> (1,2)
|
||||
double constant:
|
||||
(1 size)
|
||||
default -> (-1,-1)
|
||||
address of global variable:
|
||||
(1 size)
|
||||
default -> (2,4)
|
||||
address of procedure:
|
||||
(1 size)
|
||||
default -> (2,4)
|
||||
|
||||
opening cost parameters:
|
||||
local variable:
|
||||
(2 cases)
|
||||
pointer
|
||||
(2 sizes)
|
||||
fitbyte -> (10,4)
|
||||
default -> (9,5)
|
||||
general
|
||||
(2 sizes)
|
||||
fitbyte -> (8,4)
|
||||
default -> (7,5)
|
||||
address of local variable:
|
||||
(2 cases)
|
||||
pointer
|
||||
(2 sizes)
|
||||
fitbyte -> (0,4)
|
||||
default -> (0,5)
|
||||
general
|
||||
(2 sizes)
|
||||
fitbyte -> (0,4)
|
||||
general -> (0,5)
|
||||
constant:
|
||||
(3 sizes)
|
||||
in_0_63 -> (4,2)
|
||||
fitbyte -> (5,3)
|
||||
default -> (6,4)
|
||||
double constant:
|
||||
(1 size)
|
||||
default -> (1000,1000)
|
||||
address of global variable:
|
||||
(1 size)
|
||||
default -> (6,7)
|
||||
address of procedure:
|
||||
(1 size)
|
||||
default -> (6,7)
|
||||
|
||||
register save costs:
|
||||
(9 cases)
|
||||
0 -> (0,0)
|
||||
1 -> (1,0)
|
||||
2 -> (2,0)
|
||||
3 -> (3,0)
|
||||
4 -> (4,0)
|
||||
5 -> (5,0)
|
||||
6 -> (6,0)
|
||||
7 -> (7,0)
|
||||
0 -> (0,0)
|
||||
%%UD
|
||||
access costs of global variables:
|
||||
(1 size)
|
||||
default -> (7,4)
|
||||
access costs of local variables:
|
||||
(2 sizes)
|
||||
fitbyte -> (3,1)
|
||||
default -> (2,2)
|
||||
%%SR
|
||||
overflow harmful?: no
|
||||
array bound harmful?: no
|
||||
|
||||
%%CS
|
||||
#include "../../../h/em_mnem.h"
|
||||
first time then space:
|
||||
addressing modes: op_adp op_lof op_ldf op_loi op_dch op_lpb -1
|
||||
op_adp op_lof op_ldf op_loi op_dch op_lpb -1
|
||||
cheap operations: op_cii op_cui op_cfi op_ciu op_cff op_cuu op_cif
|
||||
op_cmi op_cmf op_cmu op_cms op_cmp -1
|
||||
op_cii op_cui op_cfi op_ciu op_cff op_cuu op_cif
|
||||
op_cmi op_cmf op_cmu op_cms op_cmp -1
|
||||
lexical tresholds: 1 1
|
||||
indirection limit: 8
|
||||
do sli if index?: no no
|
||||
forbidden operators: -1 -1
|
||||
%%SP
|
||||
global stack pollution allowed?: yes
|
||||
@@ -1,114 +0,0 @@
|
||||
wordsize: 4
|
||||
pointersize: 4
|
||||
%%RA
|
||||
general registers: 8
|
||||
address registers: 0
|
||||
floating point registers: 0
|
||||
|
||||
register score parameters:
|
||||
local variable:
|
||||
(2 cases)
|
||||
pointer,general
|
||||
(2 sizes)
|
||||
fitbyte -> (5,2)
|
||||
default -> (4,3)
|
||||
general,general
|
||||
(2 sizes)
|
||||
fitbyte -> (3,1)
|
||||
default -> (2,2)
|
||||
address of local variable:
|
||||
(2 cases)
|
||||
pointer,general
|
||||
(2 sizes)
|
||||
fitbyte -> (0,1)
|
||||
default -> (0,2)
|
||||
general,general
|
||||
(2 sizes)
|
||||
fitbyte -> (0,1)
|
||||
default -> (0,2)
|
||||
constant:
|
||||
(3 sizes)
|
||||
in_0_63 -> (0,0)
|
||||
fitbyte -> (0,1)
|
||||
default -> (1,2)
|
||||
double constant:
|
||||
(1 size)
|
||||
default -> (-1,-1)
|
||||
address of global variable:
|
||||
(1 size)
|
||||
default -> (2,4)
|
||||
address of procedure:
|
||||
(1 size)
|
||||
default -> (2,4)
|
||||
|
||||
opening cost parameters:
|
||||
local variable:
|
||||
(2 cases)
|
||||
pointer
|
||||
(2 sizes)
|
||||
fitbyte -> (10,4)
|
||||
default -> (9,5)
|
||||
general
|
||||
(2 sizes)
|
||||
fitbyte -> (8,4)
|
||||
default -> (7,5)
|
||||
address of local variable:
|
||||
(2 cases)
|
||||
pointer
|
||||
(2 sizes)
|
||||
fitbyte -> (0,4)
|
||||
default -> (0,5)
|
||||
general
|
||||
(2 sizes)
|
||||
fitbyte -> (0,4)
|
||||
general -> (0,5)
|
||||
constant:
|
||||
(3 sizes)
|
||||
in_0_63 -> (4,2)
|
||||
fitbyte -> (5,3)
|
||||
default -> (6,4)
|
||||
double constant:
|
||||
(1 size)
|
||||
default -> (1000,1000)
|
||||
address of global variable:
|
||||
(1 size)
|
||||
default -> (6,7)
|
||||
address of procedure:
|
||||
(1 size)
|
||||
default -> (6,7)
|
||||
|
||||
register save costs:
|
||||
(8 cases)
|
||||
0 -> (0,0)
|
||||
1 -> (3,1)
|
||||
2 -> (7,3)
|
||||
3 -> (20,4)
|
||||
4 -> (20,4)
|
||||
5 -> (20,4)
|
||||
6 -> (20,4)
|
||||
0 -> (0,0)
|
||||
%%UD
|
||||
access costs of global variables:
|
||||
(1 size)
|
||||
default -> (7,4)
|
||||
access costs of local variables:
|
||||
(2 sizes)
|
||||
fitbyte -> (3,1)
|
||||
default -> (2,2)
|
||||
%%SR
|
||||
overflow harmful?: no
|
||||
array bound harmful?: no
|
||||
|
||||
%%CS
|
||||
#include "../../../h/em_mnem.h"
|
||||
first time then space:
|
||||
addressing modes: op_adp op_lof op_ldf op_loi op_dch op_lpb -1
|
||||
op_adp op_lof op_ldf op_loi op_dch op_lpb -1
|
||||
cheap operations: op_cii op_cui op_cfi op_ciu op_cff op_cuu op_cif -1
|
||||
op_cii op_cui op_cfi op_ciu op_cff op_cuu op_cif -1
|
||||
lexical tresholds: 1 1
|
||||
indirection limit: 8
|
||||
do sli if index?: no no
|
||||
forbidden operators: -1 -1
|
||||
%%SP
|
||||
global stack pollution allowed?: no
|
||||
@@ -1,68 +0,0 @@
|
||||
TMP=/usr/tmp/ego
|
||||
DDUMP=$TMP.dd.$$
|
||||
PDUMP=$TMP.pd.$$
|
||||
PHASES=''
|
||||
FLAGS=''
|
||||
|
||||
|
||||
while :
|
||||
do
|
||||
case $# in
|
||||
0) break ;;
|
||||
esac
|
||||
A="$1"
|
||||
shift
|
||||
case $A in
|
||||
*.m|*.ma) ICARG="$ICARG $A"; continue;;
|
||||
-P) OPT="$1"; shift; continue;;
|
||||
-IL) PHASES="$PHASES il cf " ; continue;;
|
||||
-CS) PHASES="$PHASES cs " ; continue;;
|
||||
-SR) PHASES="$PHASES sr " ; continue;;
|
||||
-UD) PHASES="$PHASES ud " ; continue;;
|
||||
-LV) PHASES="$PHASES lv " ; continue;;
|
||||
-RA) PHASES="$PHASES ra " ; continue;;
|
||||
-SP) PHASES="$PHASES sp " ; continue;;
|
||||
-BO) PHASES="$PHASES bo " ; continue;;
|
||||
-CJ) PHASES="$PHASES cj " ; continue;;
|
||||
-*) FLAGS="$FLAGS $A"; continue;;
|
||||
esac
|
||||
done
|
||||
if test "$PHASES"
|
||||
then :
|
||||
else PHASES='cj bo sp '
|
||||
fi
|
||||
PASSES="ic cf $PHASES ca"
|
||||
OUTFILES="$PDUMP $DDUMP"
|
||||
c=1
|
||||
if test "$ICARG"
|
||||
then :
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
for i in $PASSES
|
||||
do INFILES=$OUTFILES
|
||||
OUTFILES="$TMP.p.$c.$$ $TMP.d.$c.$$ $TMP.l.$c.$$ $TMP.b.$c.$$"
|
||||
trap "rm -f $INFILES $OUTFILES $PDUMP $DDUMP; exit 1" 1 2 15
|
||||
case $i in
|
||||
ic) if $OPT/ic $INFILES - - $OUTFILES $ICARG
|
||||
then :
|
||||
else exit 1
|
||||
fi ;;
|
||||
ca) if $OPT/ca $INFILES $PDUMP $DDUMP - -
|
||||
then
|
||||
rm -f $INFILES $PDUMP $DDUMP
|
||||
else
|
||||
rm -f $INFILES $PDUMP $DDUMP
|
||||
exit 1
|
||||
fi;;
|
||||
*) if $OPT/$i $INFILES $OUTFILES $FLAGS
|
||||
then
|
||||
rm -f $INFILES
|
||||
else
|
||||
rm -f $INFILES
|
||||
exit 1
|
||||
fi ;;
|
||||
esac
|
||||
c=`expr $c + 1`
|
||||
done
|
||||
exit 0
|
||||
@@ -1,100 +0,0 @@
|
||||
EMH=../../../h
|
||||
EMLIB=../../../lib
|
||||
SHR=../share
|
||||
|
||||
CFILES=\
|
||||
ic.c ic_aux.c ic_lib.c ic_lookup.c ic_io.c
|
||||
|
||||
OFILES=\
|
||||
ic.o ic_aux.o ic_lookup.o ic_io.o ic_lib.o
|
||||
|
||||
HFILES=\
|
||||
ic.h ic_aux.h ic_lib.h ic_lookup.h ic_io.h
|
||||
|
||||
PRFILES=\
|
||||
$(CFILES) $(HFILES) Makefile
|
||||
|
||||
SHARE_OFILES=\
|
||||
$(SHR)/put.o $(SHR)/alloc.o $(SHR)/global.o $(SHR)/debug.o \
|
||||
$(SHR)/files.o $(SHR)/map.o $(SHR)/lset.o $(SHR)/cset.o $(SHR)/aux.o
|
||||
|
||||
SHARE_MFILES=\
|
||||
$(SHR)/put.m $(SHR)/alloc.m $(SHR)/global.m $(SHR)/debug.m \
|
||||
$(SHR)/files.m $(SHR)/map.m $(SHR)/lset.m $(SHR)/cset.m $(SHR)/aux.m
|
||||
|
||||
ic: $(OFILES)
|
||||
$(CC) -o ic $(LDFLAGS) $(OFILES) $(SHARE_OFILES) $(EMLIB)/em_data.a
|
||||
|
||||
ic_ack: $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -c.o $(CFLAGS) $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -o ic -.c $(LDFLAGS) ic.o $(EMLIB)/em_data.a
|
||||
|
||||
lint:
|
||||
lint $(LINTFLAGS) $(CPPFLAGS) $(CFILES)
|
||||
|
||||
pr: $(PRFILES)
|
||||
@pr $?
|
||||
@touch pr
|
||||
|
||||
depend:
|
||||
$(SHR)/makedepend
|
||||
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
ic.o: ../../../h/em_flag.h
|
||||
ic.o: ../../../h/em_mes.h
|
||||
ic.o: ../../../h/em_pseu.h
|
||||
ic.o: ../../../h/em_spec.h
|
||||
ic.o: ../share/alloc.h
|
||||
ic.o: ../share/aux.h
|
||||
ic.o: ../share/debug.h
|
||||
ic.o: ../share/def.h
|
||||
ic.o: ../share/files.h
|
||||
ic.o: ../share/global.h
|
||||
ic.o: ../share/map.h
|
||||
ic.o: ../share/put.h
|
||||
ic.o: ../share/types.h
|
||||
ic.o: ic.h
|
||||
ic.o: ic_aux.h
|
||||
ic.o: ic_io.h
|
||||
ic.o: ic_lib.h
|
||||
ic.o: ic_lookup.h
|
||||
ic_aux.o: ../../../h/em_mnem.h
|
||||
ic_aux.o: ../../../h/em_pseu.h
|
||||
ic_aux.o: ../../../h/em_spec.h
|
||||
ic_aux.o: ../share/alloc.h
|
||||
ic_aux.o: ../share/aux.h
|
||||
ic_aux.o: ../share/debug.h
|
||||
ic_aux.o: ../share/def.h
|
||||
ic_aux.o: ../share/global.h
|
||||
ic_aux.o: ../share/types.h
|
||||
ic_aux.o: ic.h
|
||||
ic_aux.o: ic_aux.h
|
||||
ic_aux.o: ic_io.h
|
||||
ic_aux.o: ic_lookup.h
|
||||
ic_io.o: ../../../h/em_pseu.h
|
||||
ic_io.o: ../../../h/em_spec.h
|
||||
ic_io.o: ../share/alloc.h
|
||||
ic_io.o: ../share/debug.h
|
||||
ic_io.o: ../share/types.h
|
||||
ic_io.o: ic.h
|
||||
ic_io.o: ic_io.h
|
||||
ic_io.o: ic_lookup.h
|
||||
ic_lib.o: ../../../h/em_mes.h
|
||||
ic_lib.o: ../../../h/em_pseu.h
|
||||
ic_lib.o: ../../../h/em_spec.h
|
||||
ic_lib.o: ../share/debug.h
|
||||
ic_lib.o: ../share/files.h
|
||||
ic_lib.o: ../share/global.h
|
||||
ic_lib.o: ../share/types.h
|
||||
ic_lib.o: ic.h
|
||||
ic_lib.o: ic_io.h
|
||||
ic_lib.o: ic_lib.h
|
||||
ic_lib.o: ic_lookup.h
|
||||
ic_lookup.o: ../../../h/em_spec.h
|
||||
ic_lookup.o: ../share/alloc.h
|
||||
ic_lookup.o: ../share/debug.h
|
||||
ic_lookup.o: ../share/map.h
|
||||
ic_lookup.o: ../share/types.h
|
||||
ic_lookup.o: ic.h
|
||||
ic_lookup.o: ic_lookup.h
|
||||
520
util/ego/ic/ic.c
520
util/ego/ic/ic.c
@@ -1,520 +0,0 @@
|
||||
/* I N T E R M E D I A T E C O D E
|
||||
*
|
||||
* I C . C
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/def.h"
|
||||
#include "../share/map.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_flag.h"
|
||||
#include "../../../h/em_mes.h"
|
||||
#include "ic.h"
|
||||
#include "ic_lookup.h"
|
||||
#include "ic_aux.h"
|
||||
#include "ic_io.h"
|
||||
#include "ic_lib.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/files.h"
|
||||
#include "../share/put.h"
|
||||
#include "../share/aux.h"
|
||||
|
||||
|
||||
/* Global variables */
|
||||
|
||||
|
||||
dblock_p db;
|
||||
dblock_p curhol = (dblock_p) 0; /* hol block in current scope */
|
||||
dblock_p ldblock; /* last dblock */
|
||||
proc_p lproc; /* last proc */
|
||||
short tabval; /* used by table1, table2 and table3 */
|
||||
offset tabval2;
|
||||
char string[IDL+1];
|
||||
line_p firstline; /* first line of current procedure */
|
||||
line_p lastline; /* last line read */
|
||||
int labelcount; /* # labels in current procedure */
|
||||
short fragm_type = DUNKNOWN; /* fragm. type: DCON, DROM or DUNKNOWN */
|
||||
short fragm_nr = 0; /* fragment number */
|
||||
obj_id lastoid = 0;
|
||||
proc_id lastpid = 0;
|
||||
dblock_id lastdid = 0;
|
||||
lab_id lastlid = 0;
|
||||
|
||||
offset mespar = UNKNOWN_SIZE;
|
||||
/* argumument of ps_par message of current procedure */
|
||||
|
||||
|
||||
extern process_lines();
|
||||
extern int readline();
|
||||
extern line_p readoperand();
|
||||
extern line_p inpseudo();
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
/* The input files must be legal EM Compact
|
||||
* Assembly Language files, as produced by the EM Peephole
|
||||
* Optimizer.
|
||||
* Their file names are passed as arguments.
|
||||
* The output consists of the files:
|
||||
* - lfile: the EM code in Intermediate Code format
|
||||
* - dfile: the data block table file
|
||||
* - pfile: the proc table file
|
||||
* - pdump: the names of all procedures
|
||||
* - ddump: the names of all data blocks
|
||||
*/
|
||||
|
||||
FILE *lfile, *dfile, *pfile, *pdump, *ddump;
|
||||
|
||||
lfile = openfile(lname2,"w");
|
||||
pdump = openfile(argv[1],"w");
|
||||
ddump = openfile(argv[2],"w");
|
||||
while (next_file(argc,argv) != NULL) {
|
||||
/* Read all EM input files, process the code
|
||||
* and concatenate all output.
|
||||
*/
|
||||
process_lines(lfile);
|
||||
dump_procnames(prochash,NPROCHASH,pdump);
|
||||
dump_dblocknames(symhash,NSYMHASH,ddump);
|
||||
/* Save the names of all procedures that were
|
||||
* first come accross in this file.
|
||||
*/
|
||||
cleanprocs(prochash,NPROCHASH,PF_EXTERNAL);
|
||||
cleandblocks(symhash,NSYMHASH,DF_EXTERNAL);
|
||||
/* Make all procedure names that were internal
|
||||
* in this input file invisible.
|
||||
*/
|
||||
}
|
||||
fclose(lfile);
|
||||
fclose(pdump);
|
||||
fclose(ddump);
|
||||
|
||||
|
||||
/* remove the remainder of the hashing tables */
|
||||
cleanprocs(prochash,NPROCHASH,0);
|
||||
cleandblocks(symhash,NSYMHASH,0);
|
||||
/* Now write the datablock table and the proctable */
|
||||
dfile = openfile(dname2,"w");
|
||||
putdtable(fdblock, dfile);
|
||||
pfile = openfile(pname2,"w");
|
||||
putptable(fproc, pfile,FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Value returned by readline */
|
||||
|
||||
#define NORMAL 0
|
||||
#define WITH_OPERAND 1
|
||||
#define EOFILE 2
|
||||
#define PRO_INSTR 3
|
||||
#define END_INSTR 4
|
||||
#define DELETED_INSTR 5
|
||||
|
||||
|
||||
STATIC add_end()
|
||||
{
|
||||
/* Add an end-pseudo to the current instruction list */
|
||||
|
||||
lastline->l_next = newline(OPNO);
|
||||
lastline = lastline->l_next;
|
||||
lastline->l_instr = ps_end;
|
||||
}
|
||||
|
||||
|
||||
process_lines(fout)
|
||||
FILE *fout;
|
||||
{
|
||||
line_p lnp;
|
||||
short instr;
|
||||
bool eof;
|
||||
|
||||
/* Read and process the code contained in the current file,
|
||||
* on a per procedure basis.
|
||||
* On the fly, fragments are formed. Recall that two
|
||||
* successive CON pseudos are allocated consecutively
|
||||
* in a single fragment, unless these CON pseudos are
|
||||
* separated in the assembly language program by one
|
||||
* of: ROM, BSS, HOL and END (and of course EndOfFile).
|
||||
* The same is true for ROM pseudos.
|
||||
* We keep track of a fragment type (DROM after a ROM
|
||||
* pseudo, DCON after a CON and DUNKNOWN after a HOL,
|
||||
* BSS, END or EndOfFile) and a fragment number (which
|
||||
* is incremented every time we enter a new fragment).
|
||||
* Every data block is assigned such a number
|
||||
* when we come accross its defining occurrence.
|
||||
*/
|
||||
|
||||
eof = FALSE;
|
||||
firstline = (line_p) 0;
|
||||
lastline = (line_p) 0;
|
||||
while (!eof) {
|
||||
linecount++; /* for error messages */
|
||||
switch(readline(&instr, &lnp)) {
|
||||
/* read one line, see what kind it is */
|
||||
case WITH_OPERAND:
|
||||
/* instruction with operand, e.g. LOL 10 */
|
||||
lnp = readoperand(instr);
|
||||
lnp->l_instr = instr;
|
||||
/* Fall through! */
|
||||
case NORMAL:
|
||||
VL(lnp);
|
||||
if (lastline != (line_p) 0) {
|
||||
lastline->l_next = lnp;
|
||||
}
|
||||
lastline = lnp;
|
||||
break;
|
||||
case EOFILE:
|
||||
eof = TRUE;
|
||||
fragm_type = DUNKNOWN;
|
||||
if (firstline != (line_p) 0) {
|
||||
add_end();
|
||||
putlines(firstline,fout);
|
||||
firstline = (line_p) 0;
|
||||
}
|
||||
break;
|
||||
case PRO_INSTR:
|
||||
VL(lnp);
|
||||
labelcount = 0;
|
||||
if (firstline != lnp) {
|
||||
/* If PRO is not the first
|
||||
* instruction:
|
||||
*/
|
||||
add_end();
|
||||
putlines(firstline,fout);
|
||||
firstline = lnp;
|
||||
}
|
||||
lastline = lnp;
|
||||
break;
|
||||
case END_INSTR:
|
||||
curproc->p_nrformals = mespar;
|
||||
mespar = UNKNOWN_SIZE;
|
||||
assert(lastline != (line_p) 0);
|
||||
lastline->l_next = lnp;
|
||||
putlines(firstline,fout);
|
||||
/* write and delete code */
|
||||
firstline = (line_p) 0;
|
||||
lastline = (line_p) 0;
|
||||
cleaninstrlabs();
|
||||
/* scope of instruction labels ends here,
|
||||
* so forget about them.
|
||||
*/
|
||||
fragm_type = DUNKNOWN;
|
||||
break;
|
||||
case DELETED_INSTR:
|
||||
/* EXP, INA etc. are deleted */
|
||||
break;
|
||||
default:
|
||||
error("illegal readline");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int readline(instr_out, lnp_out)
|
||||
short *instr_out;
|
||||
line_p *lnp_out;
|
||||
{
|
||||
register line_p lnp;
|
||||
short n;
|
||||
|
||||
/* Read one line. If it is a normal EM instruction without
|
||||
* operand, we can allocate a line struct for it here.
|
||||
* If so, return a pointer to it via lnp_out, else just
|
||||
* return the instruction code via instr_out.
|
||||
*/
|
||||
|
||||
VA((short *) instr_out);
|
||||
VA((short *) lnp_out);
|
||||
switch(table1()) {
|
||||
/* table1 sets string, tabval or tabval2 and
|
||||
* returns an indication of what was read.
|
||||
*/
|
||||
case ATEOF:
|
||||
return EOFILE;
|
||||
case INST:
|
||||
*instr_out = tabval; /* instruction code */
|
||||
return WITH_OPERAND;
|
||||
case DLBX:
|
||||
/* data label defining occurrence, precedes
|
||||
* a data block.
|
||||
*/
|
||||
db = block_of_lab(string);
|
||||
/* global variable, used by inpseudo */
|
||||
lnp = newline(OPSHORT);
|
||||
SHORT(lnp) = (short) db->d_id;
|
||||
lnp->l_instr = ps_sym;
|
||||
*lnp_out = lnp;
|
||||
if (firstline == (line_p) 0) {
|
||||
firstline = lnp;
|
||||
/* only a pseudo (e.g. PRO) or data label
|
||||
* can be the first instruction.
|
||||
*/
|
||||
}
|
||||
return NORMAL;
|
||||
case ILBX:
|
||||
/* instruction label defining occurrence */
|
||||
labelcount++;
|
||||
lnp = newline(OPINSTRLAB);
|
||||
lnp->l_instr = op_lab;
|
||||
INSTRLAB(lnp) = instr_lab(tabval);
|
||||
*lnp_out = lnp;
|
||||
return NORMAL;
|
||||
case PSEU:
|
||||
n = tabval;
|
||||
lnp = inpseudo(n); /* read a pseudo */
|
||||
if (lnp == (line_p) 0) return DELETED_INSTR;
|
||||
*lnp_out = lnp;
|
||||
lnp->l_instr = n;
|
||||
if (firstline == (line_p) 0) {
|
||||
firstline = lnp;
|
||||
/* only a pseudo (e.g. PRO) or data label
|
||||
* can be the first instruction.
|
||||
*/
|
||||
}
|
||||
if (n == ps_end) return END_INSTR;
|
||||
if (n == ps_pro) return PRO_INSTR;
|
||||
return NORMAL;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
line_p readoperand(instr)
|
||||
short instr;
|
||||
{
|
||||
/* Read the operand of the given instruction.
|
||||
* Create a line struct and return a pointer to it.
|
||||
*/
|
||||
|
||||
|
||||
register line_p lnp;
|
||||
short flag;
|
||||
|
||||
VI(instr);
|
||||
flag = em_flag[ instr - sp_fmnem] & EM_PAR;
|
||||
if (flag == PAR_NO) {
|
||||
return (newline(OPNO));
|
||||
}
|
||||
switch(table2()) {
|
||||
case sp_cend:
|
||||
return(newline(OPNO));
|
||||
case CSTX1:
|
||||
/* constant */
|
||||
/* If the instruction has the address
|
||||
* of an external variable as argument,
|
||||
* the constant must be regarded as an
|
||||
* offset in the current hol block,
|
||||
* so an object must be created.
|
||||
* Similarly, the instruction may have
|
||||
* an instruction label as argument.
|
||||
*/
|
||||
switch(flag) {
|
||||
case PAR_G:
|
||||
lnp = newline(OPOBJECT);
|
||||
OBJ(lnp) =
|
||||
object((char *) 0,(offset) tabval,
|
||||
opr_size(instr));
|
||||
break;
|
||||
case PAR_B:
|
||||
lnp = newline(OPINSTRLAB);
|
||||
INSTRLAB(lnp) = instr_lab(tabval);
|
||||
break;
|
||||
default:
|
||||
lnp = newline(OPSHORT);
|
||||
SHORT(lnp) = tabval;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#ifdef LONGOFF
|
||||
case CSTX2:
|
||||
/* double constant */
|
||||
lnp = newline(OPOFFSET);
|
||||
OFFSET(lnp) = tabval2;
|
||||
break;
|
||||
#endif
|
||||
case ILBX:
|
||||
/* applied occurrence instruction label */
|
||||
lnp = newline(OPINSTRLAB);
|
||||
INSTRLAB(lnp) = instr_lab(tabval);
|
||||
break;
|
||||
case DLBX:
|
||||
/* applied occurrence data label */
|
||||
lnp = newline(OPOBJECT);
|
||||
OBJ(lnp) = object(string, (offset) 0,
|
||||
opr_size(instr) );
|
||||
break;
|
||||
case VALX1:
|
||||
lnp = newline(OPOBJECT);
|
||||
OBJ(lnp) = object(string, (offset) tabval,
|
||||
opr_size(instr) );
|
||||
break;
|
||||
#ifdef LONGOFF
|
||||
case VALX2:
|
||||
lnp = newline(OPOBJECT);
|
||||
OBJ(lnp) = object(string,tabval2,
|
||||
opr_size(instr) );
|
||||
break;
|
||||
#endif
|
||||
case sp_pnam:
|
||||
lnp = newline(OPPROC);
|
||||
PROC(lnp) = proclookup(string,OCCURRING);
|
||||
VP(PROC(lnp));
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
return lnp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
line_p inpseudo(n)
|
||||
short n;
|
||||
{
|
||||
int m;
|
||||
line_p lnp;
|
||||
byte pseu;
|
||||
short nlast;
|
||||
|
||||
/* Read the (remainder of) a pseudo instruction, the instruction
|
||||
* code of which is n. The END pseudo may be deleted (return 0).
|
||||
* The pseudos INA, EXA, INP and EXP (visibility pseudos) must
|
||||
* also be deleted, although the effects they have on the
|
||||
* visibility of global names and procedure names must first
|
||||
* be recorded in the datablock or procedure table.
|
||||
*/
|
||||
|
||||
|
||||
switch(n) {
|
||||
case ps_hol:
|
||||
case ps_bss:
|
||||
case ps_rom:
|
||||
case ps_con:
|
||||
if (lastline == (line_p) 0 || !is_datalabel(lastline)) {
|
||||
if (n == ps_hol) {
|
||||
/* A HOL need not be preceded
|
||||
* by a label.
|
||||
*/
|
||||
curhol = db = block_of_lab((char *) 0);
|
||||
} else {
|
||||
assert(lastline != (line_p) 0);
|
||||
nlast = INSTR(lastline);
|
||||
if (n == nlast &&
|
||||
(n == ps_rom || n == ps_con)) {
|
||||
/* Two successive roms/cons are
|
||||
* combined into one data block
|
||||
* if the second is not preceded by
|
||||
* a data label.
|
||||
*/
|
||||
lnp = arglist(0);
|
||||
pseu = (byte) (n == ps_rom?DROM:DCON);
|
||||
combine(db,lastline,lnp,pseu);
|
||||
oldline(lnp);
|
||||
return (line_p) 0;
|
||||
} else {
|
||||
error("datablock without label");
|
||||
}
|
||||
}
|
||||
}
|
||||
VD(db);
|
||||
m = (n == ps_hol || n == ps_bss ? 3 : 0);
|
||||
lnp = arglist(m);
|
||||
/* Read the arguments, 3 for hol or bss and a list
|
||||
* of undetermined length for rom and con.
|
||||
*/
|
||||
dblockdef(db,n,lnp);
|
||||
/* Fill in d_pseudo, d_size and d_values fields of db */
|
||||
if (fragm_type != db->d_pseudo & BMASK) {
|
||||
/* Keep track of fragment numbers,
|
||||
* enter a new fragment.
|
||||
*/
|
||||
fragm_nr++;
|
||||
switch(db->d_pseudo) {
|
||||
case DCON:
|
||||
case DROM:
|
||||
fragm_type = db->d_pseudo;
|
||||
break;
|
||||
default:
|
||||
fragm_type = DUNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
db->d_fragmnr = fragm_nr;
|
||||
return lnp;
|
||||
case ps_ina:
|
||||
getsym(DEFINING);
|
||||
/* Read and lookup a symbol. As this must be
|
||||
* the first occurrence of the symbol and we
|
||||
* say it's a defining occurrence, getsym will
|
||||
* automatically make it internal (according to
|
||||
* the EM visibility rules).
|
||||
* The result (a dblock pointer) is voided.
|
||||
*/
|
||||
return (line_p) 0;
|
||||
case ps_inp:
|
||||
getproc(DEFINING); /* same idea */
|
||||
return (line_p) 0;
|
||||
case ps_exa:
|
||||
getsym(OCCURRING);
|
||||
return (line_p) 0;
|
||||
case ps_exp:
|
||||
getproc(OCCURRING);
|
||||
return (line_p) 0;
|
||||
case ps_pro:
|
||||
curproc = getproc(DEFINING);
|
||||
/* This is a real defining occurrence of a proc */
|
||||
curproc->p_localbytes = get_off();
|
||||
curproc->p_flags1 |= PF_BODYSEEN;
|
||||
/* Record the fact that we came accross
|
||||
* the body of this procedure.
|
||||
*/
|
||||
lnp = newline(OPPROC);
|
||||
PROC(lnp) = curproc;
|
||||
lnp->l_instr = (byte) ps_pro;
|
||||
return lnp;
|
||||
case ps_end:
|
||||
curproc->p_nrlabels = labelcount;
|
||||
lnp = newline(OPNO);
|
||||
get_off();
|
||||
/* Void # localbytes, which we already know
|
||||
* from the PRO instruction.
|
||||
*/
|
||||
return lnp;
|
||||
case ps_mes:
|
||||
lnp = arglist(0);
|
||||
switch((int) aoff(ARG(lnp),0)) {
|
||||
case ms_err:
|
||||
error("ms_err encountered");
|
||||
case ms_opt:
|
||||
error("ms_opt encountered");
|
||||
case ms_emx:
|
||||
ws = aoff(ARG(lnp),1);
|
||||
ps = aoff(ARG(lnp),2);
|
||||
break;
|
||||
case ms_ext:
|
||||
/* this message was already processed
|
||||
* by the lib package
|
||||
*/
|
||||
case ms_src:
|
||||
/* Don't bother about linecounts */
|
||||
oldline(lnp);
|
||||
return (line_p) 0;
|
||||
case ms_par:
|
||||
mespar = aoff(ARG(lnp),1);
|
||||
/* #bytes of parameters of current proc */
|
||||
break;
|
||||
}
|
||||
return lnp;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/* I N T E R M E D I A T E C O D E
|
||||
*
|
||||
* G L O B A L C O N S T A N T S & V A R I A B L E S
|
||||
*/
|
||||
|
||||
|
||||
/* Data structures for Intermediate Code generation */
|
||||
|
||||
typedef struct sym *sym_p;
|
||||
typedef struct prc *prc_p;
|
||||
typedef struct num *num_p;
|
||||
|
||||
|
||||
struct sym {
|
||||
sym_p sy_next; /* link */
|
||||
char sy_name[IDL]; /* name of the symbol */
|
||||
dblock_p sy_dblock; /* pointer to dblock struct */
|
||||
};
|
||||
struct prc {
|
||||
prc_p pr_next; /* link */
|
||||
char pr_name[IDL]; /* name of the procedure */
|
||||
proc_p pr_proc; /* pointer tto proc struct */
|
||||
};
|
||||
|
||||
|
||||
struct num {
|
||||
num_p n_next; /* link */
|
||||
unsigned n_number; /* EM repr. e.g. 120 in 'BRA *120' */
|
||||
lab_id n_labid; /* sequential integer repr. of IC */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* macros used by ic_lib.c and ic_io.c: */
|
||||
|
||||
#define ARCHIVE 0
|
||||
#define NO_ARCHIVE 1
|
||||
|
||||
|
||||
/*
|
||||
* The next constants are close to sp_cend for fast switches
|
||||
*/
|
||||
#define INST 256 /* instruction: number in tabval */
|
||||
#define PSEU 257 /* pseudo: number in tabval */
|
||||
#define ILBX 258 /* label: number in tabval */
|
||||
#define DLBX 259 /* symbol: name in string[] */
|
||||
#define CSTX1 260 /* short constant: stored in tabval */
|
||||
#define CSTX2 261 /* offset: value in tabval2 */
|
||||
#define VALX1 262 /* symbol+short: in string[] and tabval */
|
||||
#define VALX2 263 /* symbol+offset: in string[] and tabval2 */
|
||||
#define ATEOF 264 /* bumped into end of file */
|
||||
|
||||
/* Global variables */
|
||||
|
||||
extern dblock_p db;
|
||||
extern dblock_p curhol; /* hol block in current scope */
|
||||
extern dblock_p ldblock; /* last dblock processed so far */
|
||||
extern proc_p lproc; /* last proc processed so far */
|
||||
extern short tabval; /* used by table1, table2 and table3 */
|
||||
extern offset tabval2;
|
||||
extern char string[];
|
||||
extern line_p lastline; /* last line read */
|
||||
extern int labelcount; /* # labels in current procedure */
|
||||
extern obj_id lastoid; /* last object identifier used */
|
||||
extern proc_id lastpid; /* last proc identifier used */
|
||||
extern lab_id lastlid; /* last label identifier used */
|
||||
extern dblock_id lastdid; /* last dblock identifier used */
|
||||
|
||||
extern byte em_flag[];
|
||||
|
||||
@@ -1,459 +0,0 @@
|
||||
/* I N T E R M E D I A T E C O D E
|
||||
*
|
||||
* I C _ A U X . C
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "../share/types.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/def.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "ic.h"
|
||||
#include "ic_io.h"
|
||||
#include "ic_lookup.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "ic_aux.h"
|
||||
|
||||
|
||||
|
||||
/* opr_size */
|
||||
|
||||
offset opr_size(instr)
|
||||
short instr;
|
||||
{
|
||||
switch(instr) {
|
||||
case op_loe:
|
||||
case op_ste:
|
||||
case op_ine:
|
||||
case op_dee:
|
||||
case op_zre:
|
||||
return (offset) ws;
|
||||
case op_lde:
|
||||
case op_sde:
|
||||
return (offset) 2*ws;
|
||||
case op_lae:
|
||||
case op_fil:
|
||||
return (offset) UNKNOWN_SIZE;
|
||||
default:
|
||||
error("illegal operand of opr_size: %d", instr);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* dblockdef */
|
||||
|
||||
STATIC offset argsize(arg)
|
||||
arg_p arg;
|
||||
{
|
||||
/* Compute the size (in bytes) that the given initializer
|
||||
* will occupy.
|
||||
*/
|
||||
|
||||
offset s;
|
||||
argb_p argb;
|
||||
|
||||
switch(arg->a_type) {
|
||||
case ARGOFF:
|
||||
/* See if value fits in a short */
|
||||
if ((short) arg->a_a.a_offset == arg->a_a.a_offset) {
|
||||
return ws;
|
||||
} else {
|
||||
return 2*ws;
|
||||
}
|
||||
case ARGINSTRLAB:
|
||||
case ARGOBJECT:
|
||||
case ARGPROC:
|
||||
return ps; /* pointer size */
|
||||
case ARGSTRING:
|
||||
/* strings are partitioned into pieces */
|
||||
s = 0;
|
||||
for (argb = &arg->a_a.a_string; argb != (argb_p) 0;
|
||||
argb = argb->ab_next) {
|
||||
s += argb->ab_index;
|
||||
}
|
||||
return s;
|
||||
case ARGICN:
|
||||
case ARGUCN:
|
||||
case ARGFCN:
|
||||
return arg->a_a.a_con.ac_length;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
STATIC offset blocksize(pseudo,args)
|
||||
byte pseudo;
|
||||
arg_p args;
|
||||
{
|
||||
/* Determine the number of bytes of a datablock */
|
||||
|
||||
arg_p arg;
|
||||
offset sum;
|
||||
|
||||
switch(pseudo) {
|
||||
case DHOL:
|
||||
case DBSS:
|
||||
if (args->a_type != ARGOFF) {
|
||||
error("offset expected");
|
||||
}
|
||||
return args->a_a.a_offset;
|
||||
case DCON:
|
||||
case DROM:
|
||||
sum = 0;
|
||||
for (arg = args; arg != (arg_p) 0; arg = arg->a_next) {
|
||||
/* Add the sizes of all initializers */
|
||||
sum += argsize(arg);
|
||||
}
|
||||
return sum;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
STATIC arg_p copy_arg(arg)
|
||||
arg_p arg;
|
||||
{
|
||||
/* Copy one argument */
|
||||
|
||||
arg_p new;
|
||||
|
||||
assert(arg->a_type == ARGOFF);
|
||||
new = newarg(ARGOFF);
|
||||
new->a_a.a_offset = arg->a_a.a_offset;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC arg_p copy_rom(args)
|
||||
arg_p args;
|
||||
{
|
||||
/* Make a copy of the values of a rom,
|
||||
* provided that the rom contains only integer values,
|
||||
*/
|
||||
|
||||
arg_p arg, arg2, argh;
|
||||
|
||||
for (arg = args; arg != (arg_p) 0; arg = arg->a_next) {
|
||||
if (arg->a_type != ARGOFF) {
|
||||
return (arg_p) 0;
|
||||
}
|
||||
}
|
||||
/* Now make the copy */
|
||||
arg2 = argh = copy_arg(args);
|
||||
for (arg = args->a_next; arg != (arg_p) 0; arg = arg->a_next) {
|
||||
arg2->a_next = copy_arg(arg);
|
||||
arg2 = arg2->a_next;
|
||||
}
|
||||
return argh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
dblockdef(db,n,lnp)
|
||||
dblock_p db;
|
||||
int n;
|
||||
line_p lnp;
|
||||
{
|
||||
/* Process a data block defining occurrence */
|
||||
|
||||
byte m;
|
||||
|
||||
switch(n) {
|
||||
case ps_hol:
|
||||
m = DHOL;
|
||||
break;
|
||||
case ps_bss:
|
||||
m = DBSS;
|
||||
break;
|
||||
case ps_con:
|
||||
m = DCON;
|
||||
break;
|
||||
case ps_rom:
|
||||
m = DROM;
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
db->d_pseudo = m;
|
||||
db->d_size = blocksize(m, ARG(lnp));
|
||||
if (m == DROM) {
|
||||
/* We keep the values of a rom block in the data block
|
||||
* table if the values consist of integers only.
|
||||
*/
|
||||
db->d_values = copy_rom(ARG(lnp));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* combine */
|
||||
|
||||
combine(db,l1,l2,pseu)
|
||||
dblock_p db;
|
||||
line_p l1,l2;
|
||||
byte pseu;
|
||||
{
|
||||
/* Combine two successive ROMs/CONs (without a data label
|
||||
* in between into a single ROM. E.g.:
|
||||
* xyz
|
||||
* rom 3,6,9,12
|
||||
* rom 7,0,2
|
||||
* is changed into:
|
||||
* xyz
|
||||
* rom 3,6,9,12,7,0,2
|
||||
*/
|
||||
|
||||
arg_p v;
|
||||
|
||||
db->d_size += blocksize(pseu,ARG(l2));
|
||||
/* db is the data block that was already assigned to the
|
||||
* first rom/con. The second one is not assigned a new
|
||||
* data block of course, as the two are combined into
|
||||
* one instruction.
|
||||
*/
|
||||
if (pseu == DROM && db->d_values != (arg_p) 0) {
|
||||
/* The values contained in a ROM are only copied
|
||||
* to the data block if they may be useful to us
|
||||
* (e.g. they certainly may not be strings). In our
|
||||
* case it means that both ROMs must have useful
|
||||
* arguments.
|
||||
*/
|
||||
for (v = db->d_values; v->a_next != (arg_p) 0; v = v->a_next);
|
||||
/* The first rom contained useful arguments. v now points to
|
||||
* its last argument. Append the arguments of the second
|
||||
* rom to this list. If the second rom has arguments that are
|
||||
* not useful, throw away the entire list (we want to copy
|
||||
* everything or nothing).
|
||||
*/
|
||||
if ((v->a_next = copy_rom(ARG(l2))) == (arg_p) 0) {
|
||||
oldargs(db->d_values);
|
||||
db->d_values = (arg_p) 0;
|
||||
}
|
||||
}
|
||||
for (v = ARG(l1); v->a_next != (arg_p) 0; v = v->a_next);
|
||||
/* combine the arguments of both instructions. */
|
||||
v->a_next = ARG(l2);
|
||||
ARG(l2) = (arg_p) 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* arglist */
|
||||
|
||||
STATIC arg_string(length,abp)
|
||||
offset length;
|
||||
register argb_p abp;
|
||||
{
|
||||
|
||||
while (length--) {
|
||||
if (abp->ab_index == NARGBYTES)
|
||||
abp = abp->ab_next = newargb();
|
||||
abp->ab_contents[abp->ab_index++] = readchar();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
line_p arglist(n)
|
||||
int n;
|
||||
{
|
||||
line_p lnp;
|
||||
register arg_p ap,*app;
|
||||
bool moretocome;
|
||||
offset length;
|
||||
|
||||
|
||||
/*
|
||||
* creates an arglist with n elements
|
||||
* if n == 0 the arglist is variable and terminated by sp_cend
|
||||
*/
|
||||
|
||||
lnp = newline(OPLIST);
|
||||
app = &ARG(lnp);
|
||||
moretocome = TRUE;
|
||||
do {
|
||||
switch(table2()) {
|
||||
default:
|
||||
error("unknown byte in arglist");
|
||||
case CSTX1:
|
||||
tabval2 = (offset) tabval;
|
||||
case CSTX2:
|
||||
*app = ap = newarg(ARGOFF);
|
||||
ap->a_a.a_offset = tabval2;
|
||||
app = &ap->a_next;
|
||||
break;
|
||||
case ILBX:
|
||||
*app = ap = newarg(ARGINSTRLAB);
|
||||
ap->a_a.a_instrlab = instr_lab((short) tabval);
|
||||
app = &ap->a_next;
|
||||
break;
|
||||
case DLBX:
|
||||
*app = ap = newarg(ARGOBJECT);
|
||||
ap->a_a.a_obj = object(string,(offset) 0, (offset) 0);
|
||||
/* The size of the object is unknown */
|
||||
app = &ap->a_next;
|
||||
break;
|
||||
case sp_pnam:
|
||||
*app = ap = newarg(ARGPROC);
|
||||
ap->a_a.a_proc = proclookup(string,OCCURRING);
|
||||
app = &ap->a_next;
|
||||
break;
|
||||
case VALX1:
|
||||
tabval2 = (offset) tabval;
|
||||
case VALX2:
|
||||
*app = ap = newarg(ARGOBJECT);
|
||||
ap->a_a.a_obj = object(string, tabval2, (offset) 0);
|
||||
app = &ap->a_next;
|
||||
break;
|
||||
case sp_scon:
|
||||
*app = ap = newarg(ARGSTRING);
|
||||
length = get_off();
|
||||
arg_string(length,&ap->a_a.a_string);
|
||||
app = &ap->a_next;
|
||||
break;
|
||||
case sp_icon:
|
||||
*app = ap = newarg(ARGICN);
|
||||
goto casecon;
|
||||
case sp_ucon:
|
||||
*app = ap = newarg(ARGUCN);
|
||||
goto casecon;
|
||||
case sp_fcon:
|
||||
*app = ap = newarg(ARGFCN);
|
||||
casecon:
|
||||
length = get_int();
|
||||
ap->a_a.a_con.ac_length = (short) length;
|
||||
arg_string(get_off(),&ap->a_a.a_con.ac_con);
|
||||
app = &ap->a_next;
|
||||
break;
|
||||
case sp_cend:
|
||||
moretocome = FALSE;
|
||||
}
|
||||
if (n && (--n) == 0)
|
||||
moretocome = FALSE;
|
||||
} while (moretocome);
|
||||
return(lnp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* is_datalabel */
|
||||
|
||||
bool is_datalabel(l)
|
||||
line_p l;
|
||||
{
|
||||
VL(l);
|
||||
return (l->l_instr == (byte) ps_sym);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* block_of_lab */
|
||||
|
||||
dblock_p block_of_lab(ident)
|
||||
char *ident;
|
||||
{
|
||||
dblock_p dbl;
|
||||
|
||||
/* Find the datablock with the given name.
|
||||
* Used for defining occurrences.
|
||||
*/
|
||||
|
||||
dbl = symlookup(ident,DEFINING);
|
||||
VD(dbl);
|
||||
if (dbl->d_pseudo != DUNKNOWN) {
|
||||
error("identifier redeclared");
|
||||
}
|
||||
return dbl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* object */
|
||||
|
||||
STATIC obj_p make_object(dbl,off,size)
|
||||
dblock_p dbl;
|
||||
offset off;
|
||||
offset size;
|
||||
{
|
||||
/* Allocate an obj struct with the given attributes
|
||||
* (if it did not exist already).
|
||||
* Return a pointer to the found or newly created object struct.
|
||||
*/
|
||||
|
||||
obj_p obj, prev, new;
|
||||
|
||||
/* See if the object was already present in the object list
|
||||
* of the given datablock. If it is not yet present, find
|
||||
* the right place to insert the new object. Note that
|
||||
* the objects are sorted by offset.
|
||||
*/
|
||||
prev = (obj_p) 0;
|
||||
for (obj = dbl->d_objlist; obj != (obj_p) 0; obj = obj->o_next) {
|
||||
if (obj->o_off >= off) {
|
||||
break;
|
||||
}
|
||||
prev = obj;
|
||||
}
|
||||
/* Note that the data block may contain several objects
|
||||
* with the required offset; we also want the size to
|
||||
* be the right one.
|
||||
*/
|
||||
while (obj != (obj_p) 0 && obj->o_off == off) {
|
||||
if (obj->o_size == UNKNOWN_SIZE) {
|
||||
obj->o_size = size;
|
||||
return obj;
|
||||
} else {
|
||||
if (size == UNKNOWN_SIZE || obj->o_size == size) {
|
||||
return obj;
|
||||
/* This is the right one */
|
||||
} else {
|
||||
prev = obj;
|
||||
obj = obj->o_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Allocate a new object */
|
||||
new = newobject();
|
||||
new->o_id = ++lastoid; /* create a unique object id */
|
||||
new->o_off = off;
|
||||
new->o_size = size;
|
||||
new->o_dblock = dbl;
|
||||
/* Insert the new object */
|
||||
if (prev == (obj_p) 0) {
|
||||
dbl->d_objlist = new;
|
||||
} else {
|
||||
prev->o_next = new;
|
||||
}
|
||||
new->o_next = obj;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
|
||||
obj_p object(ident,off,size)
|
||||
char *ident;
|
||||
offset off;
|
||||
offset size;
|
||||
{
|
||||
dblock_p dbl;
|
||||
|
||||
/* Create an object struct (if it did not yet exist)
|
||||
* for the object with the given size and offset
|
||||
* within the datablock of the given name.
|
||||
*/
|
||||
|
||||
dbl = (ident == (char *) 0 ? curhol : symlookup(ident, OCCURRING));
|
||||
VD(dbl);
|
||||
return(make_object(dbl,off,size));
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/* I N T E R M E D I A T E C O D E
|
||||
*
|
||||
* A U X I L I A R Y R O U T I N E S
|
||||
*/
|
||||
|
||||
|
||||
|
||||
extern offset opr_size(); /* ( short instr )
|
||||
* size of operand of given instruction.
|
||||
* The operand is an object , so the
|
||||
* instruction can be loe, zre etc..
|
||||
*/
|
||||
extern dblockdef(); /* (dblock_p db, int n, line_p lnp)
|
||||
* Fill in d_pseudo, d_size and
|
||||
* d_values fields of db.
|
||||
*/
|
||||
extern combine(); /* (dblock_p db;line_p l1,l2;byte pseu)
|
||||
* Combine two successive ROMs or CONs
|
||||
* (with no data label in between)
|
||||
* into one ROM or CON.
|
||||
*/
|
||||
extern line_p arglist(); /* ( int m)
|
||||
* Read a list of m arguments. If m
|
||||
* is 0, then the list is of
|
||||
* undetermined length; it is
|
||||
* then terminated by a cend symbol.
|
||||
*/
|
||||
extern bool is_datalabel(); /* ( line_p l)
|
||||
* TRUE if l is a data label defining
|
||||
* occurrence (i.e. its l_instr
|
||||
* field is ps_sym).
|
||||
*/
|
||||
extern dblock_p block_of_lab(); /* (char *ident)
|
||||
* Find the datablock with
|
||||
* the given name.
|
||||
*/
|
||||
extern obj_p object(); /* (char *ident,offset off,short size)
|
||||
* Create an object struct.
|
||||
*/
|
||||
@@ -1,204 +0,0 @@
|
||||
/* I N T E R M E D I A T E C O D E
|
||||
*
|
||||
* I C _ I O . C
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/arch.h"
|
||||
#include "ic.h"
|
||||
#include "ic_lookup.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "ic_io.h"
|
||||
|
||||
|
||||
STATIC short libstate;
|
||||
STATIC long bytecnt;
|
||||
|
||||
STATIC FILE *infile; /* The current EM input file */
|
||||
|
||||
STATIC int readbyte()
|
||||
{
|
||||
if (libstate == ARCHIVE && bytecnt-- == 0L) {
|
||||
/* If we're reading from an archive file, we'll
|
||||
* have to count the number of characters read,
|
||||
* to know where the current module ends.
|
||||
*/
|
||||
return EOF;
|
||||
}
|
||||
return getc(infile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
short readshort() {
|
||||
register int l_byte, h_byte;
|
||||
|
||||
l_byte = readbyte();
|
||||
h_byte = readbyte();
|
||||
if ( h_byte>=128 ) h_byte -= 256 ;
|
||||
return l_byte | (h_byte*256) ;
|
||||
}
|
||||
|
||||
#ifdef LONGOFF
|
||||
offset readoffset() {
|
||||
register long l;
|
||||
register int h_byte;
|
||||
|
||||
l = readbyte();
|
||||
l |= ((unsigned) readbyte())*256 ;
|
||||
l |= readbyte()*256L*256L ;
|
||||
h_byte = readbyte() ;
|
||||
if ( h_byte>=128 ) h_byte -= 256 ;
|
||||
return l | (h_byte*256L*256*256L) ;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
short get_int() {
|
||||
|
||||
switch(table2()) {
|
||||
default: error("int expected");
|
||||
case CSTX1:
|
||||
return(tabval);
|
||||
}
|
||||
}
|
||||
|
||||
char readchar()
|
||||
{
|
||||
return(readbyte());
|
||||
}
|
||||
|
||||
|
||||
|
||||
offset get_off() {
|
||||
|
||||
switch (table2()) {
|
||||
default: error("offset expected");
|
||||
case CSTX1:
|
||||
return((offset) tabval);
|
||||
#ifdef LONGOFF
|
||||
case CSTX2:
|
||||
return(tabval2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
STATIC make_string(n) int n; {
|
||||
register char *s;
|
||||
extern char *sprintf();
|
||||
|
||||
s=sprintf(string,".%u",n);
|
||||
assert(s == string);
|
||||
}
|
||||
|
||||
STATIC inident() {
|
||||
register n;
|
||||
register char *p = string;
|
||||
register c;
|
||||
|
||||
n = get_int();
|
||||
while (n--) {
|
||||
c = readbyte();
|
||||
if (p<&string[IDL])
|
||||
*p++ = c;
|
||||
}
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
int table3(n) int n; {
|
||||
|
||||
switch (n) {
|
||||
case sp_ilb1: tabval = readbyte(); return(ILBX);
|
||||
case sp_ilb2: tabval = readshort(); return(ILBX);
|
||||
case sp_dlb1: make_string(readbyte()); return(DLBX);
|
||||
case sp_dlb2: make_string(readshort()); return(DLBX);
|
||||
case sp_dnam: inident(); return(DLBX);
|
||||
case sp_pnam: inident(); return(n);
|
||||
case sp_cst2: tabval = readshort(); return(CSTX1);
|
||||
#ifdef LONGOFF
|
||||
case sp_cst4: tabval2 = readoffset(); return(CSTX2);
|
||||
#endif
|
||||
case sp_doff: if (table2()!=DLBX) error("symbol expected");
|
||||
switch(table2()) {
|
||||
default: error("offset expected");
|
||||
case CSTX1: return(VALX1);
|
||||
#ifdef LONGOFF
|
||||
case CSTX2: return(VALX2);
|
||||
#endif
|
||||
}
|
||||
default: return(n);
|
||||
}
|
||||
}
|
||||
|
||||
int table1() {
|
||||
register n;
|
||||
|
||||
n = readbyte();
|
||||
if (n == EOF)
|
||||
return(ATEOF);
|
||||
if ((n <= sp_lmnem) && (n >= sp_fmnem)) {
|
||||
tabval = n;
|
||||
return(INST);
|
||||
}
|
||||
if ((n <= sp_lpseu) && (n >= sp_fpseu)) {
|
||||
tabval = n;
|
||||
return(PSEU);
|
||||
}
|
||||
if ((n < sp_filb0 + sp_nilb0) && (n >= sp_filb0)) {
|
||||
tabval = n - sp_filb0;
|
||||
return(ILBX);
|
||||
}
|
||||
return(table3(n));
|
||||
}
|
||||
|
||||
int table2() {
|
||||
register n;
|
||||
|
||||
n = readbyte();
|
||||
if ((n < sp_fcst0 + sp_ncst0) && (n >= sp_fcst0)) {
|
||||
tabval = n - sp_zcst0;
|
||||
return(CSTX1);
|
||||
}
|
||||
return(table3(n));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
file_init(f,state,length)
|
||||
FILE *f;
|
||||
short state;
|
||||
long length;
|
||||
{
|
||||
short n;
|
||||
|
||||
infile = f;
|
||||
libstate = state;
|
||||
bytecnt = length;
|
||||
linecount = 0;
|
||||
n = readshort();
|
||||
if (n != (short) sp_magic) {
|
||||
error("wrong magic number: %d", n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
arch_init(arch)
|
||||
FILE *arch;
|
||||
{
|
||||
short n;
|
||||
|
||||
infile = arch;
|
||||
n = readshort();
|
||||
if (n != ARMAG) {
|
||||
error("wrong archive magic number: %d",n);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* I N T E R M E D I A T E C O D E
|
||||
*
|
||||
* L O W L E V E L I / O R O U T I N E S
|
||||
*/
|
||||
|
||||
|
||||
extern int table1(); /* ( )
|
||||
* Read an instruction from the
|
||||
* Compact Assembly Language input
|
||||
* file (in 'neutral state').
|
||||
*/
|
||||
extern int table2(); /* ( )
|
||||
* Read an instruction argument.
|
||||
*/
|
||||
extern int table3(); /* ( int )
|
||||
* Read 'Common Table' item.
|
||||
*/
|
||||
extern short get_int(); /* ( ) */
|
||||
extern offset get_off(); /* ( ) */
|
||||
extern char readchar(); /* ( ) */
|
||||
extern file_init(); /* (FILE *f, short state, long length)
|
||||
* Input file initialization. All
|
||||
* following read operations will read
|
||||
* from the given file f. Also checks
|
||||
* the magic number and sets global
|
||||
* variable 'linecount' to 0.
|
||||
* If the state is ARCHIVE, length
|
||||
* specifies the length of the module.
|
||||
*/
|
||||
extern arch_init(); /* (FILE *arch)
|
||||
* Same as file_init,but opens an
|
||||
* archive file. So it checks the
|
||||
* magic number for archives.
|
||||
*/
|
||||
@@ -1,274 +0,0 @@
|
||||
/* I N T E R M E D I A T E C O D E
|
||||
*
|
||||
* I C _ L I B . C
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_mes.h"
|
||||
#include "../../../h/arch.h"
|
||||
#include "ic.h"
|
||||
#include "ic_lookup.h"
|
||||
#include "ic_io.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/files.h"
|
||||
#include "ic_lib.h"
|
||||
|
||||
|
||||
STATIC skip_string(n)
|
||||
offset n;
|
||||
{
|
||||
/* Read a string of length n and void it */
|
||||
|
||||
while (n--) {
|
||||
readchar();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC skip_arguments()
|
||||
{
|
||||
/* Skip the arguments of a MES pseudo. The argument
|
||||
* list is terminated by a sp_cend byte.
|
||||
*/
|
||||
|
||||
for (;;) {
|
||||
switch(table2()) {
|
||||
case sp_scon:
|
||||
get_off(); /* void */
|
||||
/* fall through !!! */
|
||||
case sp_icon:
|
||||
case sp_ucon:
|
||||
case sp_fcon:
|
||||
get_int(); /* void */
|
||||
skip_string(get_off());
|
||||
break;
|
||||
case sp_cend:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool proc_wanted(name)
|
||||
char *name;
|
||||
{
|
||||
/* See if 'name' is the name of an external procedure
|
||||
* that has been used before, but for which no body
|
||||
* has been given so far.
|
||||
*/
|
||||
|
||||
proc_p p;
|
||||
|
||||
if (( p = proclookup(name,IMPORTING)) != (proc_p) 0 &&
|
||||
!(p->p_flags1 & PF_BODYSEEN)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool data_wanted(name)
|
||||
char *name;
|
||||
{
|
||||
/* See if 'name' is the name of an externally visible
|
||||
* data block that has been used before, but for which
|
||||
* no defining occurrence has been given yet.
|
||||
*/
|
||||
|
||||
dblock_p db;
|
||||
|
||||
if ((db = symlookup(name,IMPORTING)) != (dblock_p) 0 &&
|
||||
db->d_pseudo == DUNKNOWN) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool wanted_names()
|
||||
{
|
||||
/* Read the names of procedures and data labels,
|
||||
* appearing in a 'MES ms_ext' pseudo. Those are
|
||||
* the names of entities that are imported by
|
||||
* a library module.
|
||||
* If any of them is wanted, return TRUE.
|
||||
* A name is wanted if it is the name of a procedure
|
||||
* or data block for which applied occurrences but
|
||||
* no defining occurrence has been met.
|
||||
*/
|
||||
|
||||
for (;;) {
|
||||
switch(table2()) {
|
||||
case DLBX:
|
||||
if (data_wanted(string)) {
|
||||
return TRUE;
|
||||
}
|
||||
/* A data entity with the name
|
||||
* string is available.
|
||||
*/
|
||||
break;
|
||||
case sp_pnam:
|
||||
if (proc_wanted(string)) {
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
case sp_cend:
|
||||
return FALSE;
|
||||
default:
|
||||
error("wrong argument of MES %d", ms_ext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC FILE *curfile = NULL;
|
||||
STATIC bool useful()
|
||||
{
|
||||
/* Determine if any entity imported by the current
|
||||
* compact EM assembly file (which will usually be
|
||||
* part of an archive file) is useful to us.
|
||||
* The file must contain (before any other non-MES line)
|
||||
* a 'MES ms_ext' pseudo that has as arguments the names
|
||||
* of the entities imported.
|
||||
*/
|
||||
|
||||
for (;;) {
|
||||
if (table1() != PSEU || tabval != ps_mes) {
|
||||
error("cannot find MES %d in library file",ms_ext);
|
||||
}
|
||||
if (table2() != CSTX1) {
|
||||
error("message number expected");
|
||||
}
|
||||
if (tabval == ms_ext) {
|
||||
/* This is the one we searched */
|
||||
return wanted_names();
|
||||
/* Read the names of the imported entities
|
||||
* and check if any of them is wanted.
|
||||
*/
|
||||
} else {
|
||||
skip_arguments(); /* skip remainder of this MES */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool is_archive(name)
|
||||
char *name;
|
||||
{
|
||||
/* See if 'name' is the name of an archive file, i.e. it
|
||||
* should end on ".a" and should at least be three characters
|
||||
* long (i.e. the name ".a" is not accepted as an archive name!).
|
||||
*/
|
||||
|
||||
register char *p;
|
||||
|
||||
for (p = name; *p; p++);
|
||||
return (p > name+2) && (*--p == 'a') && (*--p == '.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC struct ar_hdr hdr;
|
||||
|
||||
STATIC bool read_hdr()
|
||||
{
|
||||
/* Read the header of an archive module */
|
||||
|
||||
|
||||
fread(&hdr, sizeof(hdr), 1, curfile);
|
||||
return !feof(curfile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC int argcnt = ARGSTART - 1;
|
||||
STATIC short arstate = NO_ARCHIVE;
|
||||
|
||||
|
||||
FILE *next_file(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
/* See if there are more EM input files. The file names
|
||||
* are given via argv. If a file is an archive file
|
||||
* it is supposed to be a library of EM compact assembly
|
||||
* files. A module (file) contained in this archive file
|
||||
* is only used if it imports at least one procedure or
|
||||
* datalabel for which we have not yet seen a defining
|
||||
* occurrence, although we have seen a used occurrence.
|
||||
*/
|
||||
|
||||
long ptr;
|
||||
|
||||
for (;;) {
|
||||
/* This loop is only exited via a return */
|
||||
if (arstate == ARCHIVE) {
|
||||
/* We were reading an archive file */
|
||||
if (ftell(curfile) & 1) {
|
||||
/* modules in an archive file always
|
||||
* begin on a word boundary, i.e. at
|
||||
* an even address.
|
||||
*/
|
||||
fseek(curfile,1L,1);
|
||||
}
|
||||
if (read_hdr()) { /* read header of next module */
|
||||
ptr = ftell(curfile); /* file position */
|
||||
file_init(curfile,ARCHIVE,hdr.ar_size);
|
||||
/* tell i/o package that we're reading
|
||||
* an archive module of given length.
|
||||
*/
|
||||
if (useful()) {
|
||||
/* re-initialize file, because 'useful'
|
||||
* has read some bytes too.
|
||||
*/
|
||||
fseek(curfile,ptr,0); /* start module */
|
||||
file_init(curfile,ARCHIVE,hdr.ar_size);
|
||||
return curfile;
|
||||
} else {
|
||||
/* skip this module */
|
||||
fseek(curfile,
|
||||
ptr+hdr.ar_size,0);
|
||||
}
|
||||
} else {
|
||||
/* done with this archive */
|
||||
arstate = NO_ARCHIVE;
|
||||
}
|
||||
} else {
|
||||
/* open next file, close old */
|
||||
if (curfile != NULL) {
|
||||
fclose(curfile);
|
||||
}
|
||||
argcnt++;
|
||||
if (argcnt >= argc) {
|
||||
/* done with all arguments */
|
||||
return NULL;
|
||||
}
|
||||
filename = argv[argcnt];
|
||||
if ((curfile = fopen(filename,"r")) == NULL) {
|
||||
error("cannot open %s",filename);
|
||||
}
|
||||
if (is_archive(filename)) {
|
||||
/* ends on '.a' */
|
||||
arstate = ARCHIVE;
|
||||
arch_init(curfile); /* read magic ar number */
|
||||
} else {
|
||||
file_init(curfile,NO_ARCHIVE,0L);
|
||||
return curfile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
/* I N T E R M E D I A T E C O D E
|
||||
*
|
||||
* L I B R A R Y M A N A G E R
|
||||
*/
|
||||
|
||||
|
||||
extern FILE *next_file(); /* (int argc, char *argv[])
|
||||
* See if there are any more EM input files.
|
||||
* 'argv' contains the names of the files
|
||||
* that are passed as arguments to ic.
|
||||
* If an argument is a library (archive
|
||||
* file) only those modules that are useful
|
||||
* are used.
|
||||
*/
|
||||
@@ -1,414 +0,0 @@
|
||||
/* I N T E R M E D I A T E C O D E
|
||||
*
|
||||
* I C _ L O O K U P . C
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/map.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "ic.h"
|
||||
#include "ic_lookup.h"
|
||||
#include "../share/alloc.h"
|
||||
|
||||
|
||||
sym_p symhash[NSYMHASH];
|
||||
prc_p prochash[NPROCHASH];
|
||||
num_p numhash[NNUMHASH];
|
||||
|
||||
|
||||
|
||||
#define newsym() (sym_p) newstruct(sym)
|
||||
#define newprc() (prc_p) newstruct(prc)
|
||||
#define newnum() (num_p) newstruct(num)
|
||||
|
||||
#define oldsym(x) oldstruct(sym,x)
|
||||
#define oldprc(x) oldstruct(prc,x)
|
||||
#define oldnum(x) oldstruct(num,x)
|
||||
|
||||
|
||||
/* instr_lab */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
lab_id instr_lab(number)
|
||||
short number;
|
||||
{
|
||||
register num_p *npp, np;
|
||||
|
||||
/* In EM assembly language, a label is an unsigned number,
|
||||
* e.g. 120 in 'BRA *120'. In IC the labels of a procedure
|
||||
* are represented by consecutive integer numbers, called
|
||||
* lab_id. The mapping takes place here.
|
||||
*/
|
||||
|
||||
|
||||
npp = &numhash[number%NNUMHASH];
|
||||
while (*npp != (num_p) 0) {
|
||||
if ((*npp)->n_number == number) {
|
||||
return(*npp)->n_labid;
|
||||
} else {
|
||||
npp = &(*npp)->n_next;
|
||||
}
|
||||
}
|
||||
|
||||
/* The label was not found in the hashtable, so
|
||||
* create a new entry for it.
|
||||
*/
|
||||
|
||||
*npp = np = newnum();
|
||||
np->n_number = number;
|
||||
np->n_labid = ++lastlid;
|
||||
/* Assign a new label identifier to the num struct.
|
||||
* lastlid is reset to 0 at the beginning of
|
||||
* every new EM procedure (by cleaninstrlabs).
|
||||
*/
|
||||
return (np->n_labid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* symlookup */
|
||||
|
||||
STATIC unsigned hash(string) char *string; {
|
||||
register char *p;
|
||||
register unsigned i,sum;
|
||||
|
||||
for (sum=i=0,p=string;*p;i += 3)
|
||||
sum ^= (*p++)<<(i&07);
|
||||
return(sum);
|
||||
}
|
||||
|
||||
dblock_p symlookup(name, status)
|
||||
char *name;
|
||||
int status;
|
||||
{
|
||||
/* Look up the name of a data block. The name can appear
|
||||
* in either a defining or applied occurrence (status is
|
||||
* DEFINING, OCCURRING resp.), or in a MES ms_ext instruction
|
||||
* as the name of a data block imported by a library module
|
||||
* (status is IMPORTING). Things get complicated,
|
||||
* because a HOL pseudo need not be preceded by a
|
||||
* data label, i.e. a hol block need not have a name.
|
||||
*/
|
||||
|
||||
|
||||
register sym_p *spp, sp;
|
||||
register dblock_p dp;
|
||||
|
||||
if (name == (char *) 0) {
|
||||
assert(status == DEFINING);
|
||||
dp = newdblock();
|
||||
} else {
|
||||
spp = &symhash[hash(name)%NSYMHASH];
|
||||
while (*spp != (sym_p) 0) {
|
||||
/* Every hashtable entry points to a list
|
||||
* of synonyms (i.e. names with the same
|
||||
* hash values). Try to find 'name' in its
|
||||
* list.
|
||||
*/
|
||||
if (strncmp((*spp)->sy_name, name, IDL) == 0) {
|
||||
/* found */
|
||||
return ((*spp)->sy_dblock);
|
||||
} else {
|
||||
spp = &(*spp)->sy_next;
|
||||
}
|
||||
}
|
||||
/* The name is not found, so create a new entry for it.
|
||||
* However, if the status is IMPORTING, we just return 0,
|
||||
* indicating that we don't need this name.
|
||||
*/
|
||||
if (status == IMPORTING) return (dblock_p) 0;
|
||||
*spp = sp = newsym();
|
||||
strncpy(sp->sy_name, name, IDL);
|
||||
dp = sp->sy_dblock = newdblock();
|
||||
}
|
||||
if (fdblock == (dblock_p) 0) {
|
||||
fdblock = dp;
|
||||
/* first data block */
|
||||
} else {
|
||||
ldblock->d_next = dp; /* link to last dblock */
|
||||
}
|
||||
ldblock = dp;
|
||||
dp->d_pseudo = DUNKNOWN; /* clear all fields */
|
||||
dp->d_id = ++lastdid;
|
||||
dp->d_size = 0;
|
||||
dp->d_objlist = (obj_p) 0;
|
||||
dp->d_values = (arg_p) 0;
|
||||
dp->d_next = (dblock_p) 0;
|
||||
dp->d_flags1 = 0;
|
||||
dp->d_flags2 = 0;
|
||||
if (status == OCCURRING) {
|
||||
/* This is the first occurrence of the identifier,
|
||||
* so if it is a used occurrence make the
|
||||
* identifier externally visible, else make it
|
||||
* internal.
|
||||
*/
|
||||
dp->d_flags1 |= DF_EXTERNAL;
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* getsym */
|
||||
|
||||
dblock_p getsym(status)
|
||||
int status;
|
||||
{
|
||||
if (table2() != DLBX) {
|
||||
error("symbol expected");
|
||||
}
|
||||
return(symlookup(string,status));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* getproc */
|
||||
|
||||
proc_p getproc(status)
|
||||
int status;
|
||||
{
|
||||
if (table2() != sp_pnam) {
|
||||
error("proc name expected");
|
||||
}
|
||||
return(proclookup(string,status));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* proclookup */
|
||||
|
||||
proc_p proclookup(name, status)
|
||||
char *name;
|
||||
int status;
|
||||
{
|
||||
register prc_p *ppp, pp;
|
||||
register proc_p dp;
|
||||
|
||||
ppp = &prochash[hash(name)%NPROCHASH];
|
||||
while (*ppp != (prc_p) 0) {
|
||||
/* Every hashtable entry points to a list
|
||||
* of synonyms (i.e. names with the same
|
||||
* hash values). Try to find 'name' in its
|
||||
* list.
|
||||
*/
|
||||
if (strncmp((*ppp)->pr_name, name, IDL) == 0) {
|
||||
/* found */
|
||||
return ((*ppp)->pr_proc);
|
||||
} else {
|
||||
ppp = &(*ppp)->pr_next;
|
||||
}
|
||||
}
|
||||
/* The name is not found, so create a new entry for it,
|
||||
* unless the status is IMPORTING, in which case we
|
||||
* return 0, indicating we don't want this proc.
|
||||
*/
|
||||
if (status == IMPORTING) return (proc_p) 0;
|
||||
*ppp = pp = newprc();
|
||||
strncpy(pp->pr_name, name, IDL);
|
||||
dp = pp->pr_proc = newproc();
|
||||
if (fproc == (proc_p) 0) {
|
||||
fproc = dp; /* first proc */
|
||||
} else {
|
||||
lproc->p_next = dp;
|
||||
}
|
||||
lproc = dp;
|
||||
dp->p_id = ++lastpid; /* create a unique proc_id */
|
||||
dp->p_next = (proc_p) 0;
|
||||
dp->p_flags1 = 0;
|
||||
dp->p_flags2 = 0;
|
||||
if (status == OCCURRING) {
|
||||
/* This is the first occurrence of the identifier,
|
||||
* so if it is a used occurrence the make the
|
||||
* identifier externally visible, else make it
|
||||
* internal.
|
||||
*/
|
||||
dp->p_flags1 |= PF_EXTERNAL;
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* cleaninstrlabs */
|
||||
|
||||
cleaninstrlabs()
|
||||
{
|
||||
register num_p *npp, np, next;
|
||||
|
||||
for (npp = numhash; npp < &numhash[NNUMHASH]; npp++) {
|
||||
for (np = *npp; np != (num_p) 0; np = next) {
|
||||
next = np->n_next;
|
||||
oldnum(np);
|
||||
}
|
||||
*npp = (num_p) 0;
|
||||
}
|
||||
/* Reset last label id (used by instr_lab). */
|
||||
lastlid = (lab_id) 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* dump_procnames */
|
||||
|
||||
dump_procnames(hash,n,f)
|
||||
prc_p hash[];
|
||||
int n;
|
||||
FILE *f;
|
||||
{
|
||||
/* Save the names of the EM procedures in file f.
|
||||
* Note that the Optimizer Intermediate Code does not
|
||||
* use identifiers but proc_ids, object_ids etc.
|
||||
* The names, however, can be used after optimization
|
||||
* is completed, to reconstruct Compact Assembly Language.
|
||||
* The output consists of tuples (proc_id, name).
|
||||
* This routine is called once for every input file.
|
||||
* To prevent names of external procedures being written
|
||||
* more than once, the PF_WRITTEN flag is used.
|
||||
*/
|
||||
|
||||
register prc_p *pp, ph;
|
||||
proc_p p;
|
||||
char str[IDL+1];
|
||||
register int i;
|
||||
|
||||
#define PF_WRITTEN 01
|
||||
|
||||
|
||||
for (pp = &hash[0]; pp < &hash[n]; pp++) {
|
||||
/* Traverse the entire hash table */
|
||||
for (ph = *pp; ph != (prc_p) 0; ph = ph->pr_next) {
|
||||
/* Traverse the list of synonyms */
|
||||
p = ph->pr_proc;
|
||||
if ((p->p_flags2 & PF_WRITTEN) == 0) {
|
||||
/* not been written yet */
|
||||
for(i = 0; i < IDL; i++) {
|
||||
str[i] = ph->pr_name[i];
|
||||
}
|
||||
str[IDL] = '\0';
|
||||
fprintf(f,"%d %s\n",p->p_id, str);
|
||||
p->p_flags2 |= PF_WRITTEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* cleanprocs */
|
||||
|
||||
cleanprocs(hash,n,mask)
|
||||
prc_p hash[];
|
||||
int n,mask;
|
||||
{
|
||||
/* After an EM input file has been processed, the names
|
||||
* of those procedures that are internal (i.e. not visible
|
||||
* outside the file they are defined in) must be removed
|
||||
* from the procedure hash table. This is accomplished
|
||||
* by removing the 'prc struct' from its synonym list.
|
||||
* After the final input file has been processed, all
|
||||
* remaining prc structs are also removed.
|
||||
*/
|
||||
|
||||
register prc_p *pp, ph, x, next;
|
||||
|
||||
for (pp = &hash[0]; pp < &hash[n]; pp++) {
|
||||
/* Traverse the hash table */
|
||||
x = (prc_p) 0;
|
||||
for (ph = *pp; ph != (prc_p) 0; ph = next) {
|
||||
/* Traverse the synonym list.
|
||||
* x points to the prc struct just before ph,
|
||||
* or is 0 if ph is the first struct of
|
||||
* the list.
|
||||
*/
|
||||
next = ph->pr_next;
|
||||
if ((ph->pr_proc->p_flags1 & mask) == 0) {
|
||||
if (x == (prc_p) 0) {
|
||||
*pp = next;
|
||||
} else {
|
||||
x->pr_next = next;
|
||||
}
|
||||
oldprc(ph); /* delete the struct */
|
||||
} else {
|
||||
x = ph;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* dump_dblocknames */
|
||||
|
||||
dump_dblocknames(hash,n,f)
|
||||
sym_p hash[];
|
||||
int n;
|
||||
FILE *f;
|
||||
{
|
||||
/* Save the names of the EM data blocks in file f.
|
||||
* The output consists of tuples (dblock_id, name).
|
||||
* This routine is called once for every input file.
|
||||
*/
|
||||
|
||||
register sym_p *sp, sh;
|
||||
dblock_p d;
|
||||
char str[IDL+1];
|
||||
register int i;
|
||||
|
||||
#define DF_WRITTEN 01
|
||||
|
||||
|
||||
for (sp = &hash[0]; sp < &hash[n]; sp++) {
|
||||
/* Traverse the entire hash table */
|
||||
for (sh = *sp; sh != (sym_p) 0; sh = sh->sy_next) {
|
||||
/* Traverse the list of synonyms */
|
||||
d = sh->sy_dblock;
|
||||
if ((d->d_flags2 & DF_WRITTEN) == 0) {
|
||||
/* not been written yet */
|
||||
for (i = 0; i < IDL; i++) {
|
||||
str[i] = sh->sy_name[i];
|
||||
str[IDL] = '\0';
|
||||
}
|
||||
fprintf(f,"%d %s\n",d->d_id, str);
|
||||
d->d_flags2 |= DF_WRITTEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* cleandblocks */
|
||||
|
||||
cleandblocks(hash,n,mask)
|
||||
sym_p hash[];
|
||||
int n,mask;
|
||||
{
|
||||
/* After an EM input file has been processed, the names
|
||||
* of those data blocks that are internal must be removed.
|
||||
*/
|
||||
|
||||
register sym_p *sp, sh, x, next;
|
||||
|
||||
for (sp = &hash[0]; sp < &hash[n]; sp++) {
|
||||
x = (sym_p) 0;
|
||||
for (sh = *sp; sh != (sym_p) 0; sh = next) {
|
||||
next = sh->sy_next;
|
||||
if ((sh->sy_dblock->d_flags1 & mask) == 0) {
|
||||
if (x == (sym_p) 0) {
|
||||
*sp = next;
|
||||
} else {
|
||||
x->sy_next = next;
|
||||
}
|
||||
oldsym(sh); /* delete the struct */
|
||||
} else {
|
||||
x = sh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/* I N T E R M E D I A T E C O D E
|
||||
*
|
||||
* L O O K - U P R O U T I N E S
|
||||
*/
|
||||
|
||||
/* During Intermediate Code generation data label names ('symbols'),
|
||||
* procedure names and instruction labels (numbers) are translated
|
||||
* to resp. a data block pointer, a proc pointer and a label identifier.
|
||||
* We use three hash tables for this purpose (symhash, prochash, numhash).
|
||||
* Every name/number is hashed to an index in a specific table. A table
|
||||
* entry contains a list of structs (sym, prc, num), each one representing
|
||||
* a 'synonym'. (Synonyms are names/numbers having the same hash value).
|
||||
*/
|
||||
|
||||
|
||||
/* status passed as argument to look_up routines:
|
||||
* resp. used occurrence, defining occurrence, occurrence in
|
||||
* a MES ms_ext pseudo.
|
||||
*/
|
||||
|
||||
#define OCCURRING 0
|
||||
#define DEFINING 1
|
||||
#define IMPORTING 2
|
||||
|
||||
#define NSYMHASH 127
|
||||
#define NPROCHASH 127
|
||||
#define NNUMHASH 37
|
||||
|
||||
extern sym_p symhash[];
|
||||
extern prc_p prochash[];
|
||||
extern num_p numhash[];
|
||||
|
||||
extern lab_id instr_lab(); /* ( short number)
|
||||
* Maps EM labels to sequential
|
||||
* integers.
|
||||
*/
|
||||
extern dblock_p symlookup(); /* (char *ident, int status)
|
||||
* Look up the data block with
|
||||
* the given name.
|
||||
*/
|
||||
extern dblock_p getsym(); /* ( int status)
|
||||
* Read and look up a symbol.
|
||||
* If this is the first occurrence
|
||||
* of it, then make it external
|
||||
* (if status=OCCURRING) or
|
||||
* internal (if DEFINING).
|
||||
*/
|
||||
extern proc_p getproc(); /* (int status)
|
||||
* Same as getsym, but for procedure
|
||||
* names.
|
||||
*/
|
||||
extern proc_p proclookup(); /* ( char *ident, int status)
|
||||
* Find (in the hashtable) the
|
||||
* procedure with the given name.
|
||||
*/
|
||||
extern cleaninstrlabs(); /* ( )
|
||||
* Forget about all instruction labels.
|
||||
*/
|
||||
extern dump_procnames(); /* (prc_p hash[], int n, FILE *f)
|
||||
* Save the names of the procedures
|
||||
* in file f; hash is the hashtable
|
||||
* used and n is its length.
|
||||
*/
|
||||
extern cleanprocs(); /* (prc_p hash[], int n,mask)
|
||||
* Make the names of all procedures
|
||||
* for which p_flags1&mask = 0 invisible
|
||||
*/
|
||||
extern cleandblocks(); /* (sym_p hash[], int n)
|
||||
* Make the names of all data blocks
|
||||
* for which d_flags1&mask = 0 invisible
|
||||
*/
|
||||
@@ -1,160 +0,0 @@
|
||||
EMH=../../../h
|
||||
EMLIB=../../../lib
|
||||
SHR=../share
|
||||
|
||||
CFILES=\
|
||||
il.c il1_anal.c il1_cal.c il1_formal.c il1_aux.c il2_aux.c \
|
||||
il3_subst.c il3_change.c il3_aux.c il_aux.c
|
||||
|
||||
OFILES=\
|
||||
il.o il1_anal.o il1_cal.o il1_formal.o il1_aux.o il2_aux.o \
|
||||
il3_change.o il3_subst.o il3_aux.o il_aux.o
|
||||
|
||||
HFILES=\
|
||||
il.h il1_anal.h il1_cal.h il1_formal.h il1_aux.h il2_aux.h \
|
||||
il3_subst.h il3_change.h il3_aux.h il_aux.h
|
||||
|
||||
PRFILES=\
|
||||
$(CFILES) $(HFILES) Makefile
|
||||
|
||||
SHARE_OFILES=\
|
||||
$(SHR)/get.o $(SHR)/put.o $(SHR)/alloc.o $(SHR)/global.o $(SHR)/debug.o \
|
||||
$(SHR)/files.o $(SHR)/map.o $(SHR)/lset.o $(SHR)/cset.o $(SHR)/parser.o \
|
||||
$(SHR)/aux.o $(SHR)/go.o
|
||||
|
||||
SHARE_MFILES=\
|
||||
$(SHR)/get.m $(SHR)/put.m $(SHR)/alloc.m $(SHR)/global.m $(SHR)/debug.m \
|
||||
$(SHR)/files.m $(SHR)/map.m $(SHR)/lset.m $(SHR)/cset.m $(SHR)/parser.m \
|
||||
$(SHR)/aux.m $(SHR)/go.m
|
||||
|
||||
il: $(OFILES)
|
||||
$(CC) -o il $(LDFLAGS) $(OFILES) $(SHARE_OFILES) $(EMLIB)/em_data.a
|
||||
|
||||
il_ack: $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -c.o $(CFLAGS) $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -o il -.c $(LDFLAGS) il.o $(EMLIB)/em_data.a
|
||||
|
||||
lint:
|
||||
lint $(LINTFLAGS) $(CPPFLAGS) $(CFILES)
|
||||
|
||||
pr: $(PRFILES)
|
||||
@pr $?
|
||||
@touch pr
|
||||
|
||||
depend:
|
||||
$(SHR)/makedepend
|
||||
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
|
||||
il.o: ../../../h/em_mnem.h
|
||||
il.o: ../../../h/em_pseu.h
|
||||
il.o: ../share/alloc.h
|
||||
il.o: ../share/debug.h
|
||||
il.o: ../share/files.h
|
||||
il.o: ../share/get.h
|
||||
il.o: ../share/global.h
|
||||
il.o: ../share/lset.h
|
||||
il.o: ../share/map.h
|
||||
il.o: ../share/put.h
|
||||
il.o: ../share/types.h
|
||||
il.o: il.h
|
||||
il.o: il1_anal.h
|
||||
il.o: il2_aux.h
|
||||
il.o: il3_subst.h
|
||||
il1_anal.o: ../../../h/em_mnem.h
|
||||
il1_anal.o: ../../../h/em_pseu.h
|
||||
il1_anal.o: ../share/alloc.h
|
||||
il1_anal.o: ../share/debug.h
|
||||
il1_anal.o: ../share/global.h
|
||||
il1_anal.o: ../share/lset.h
|
||||
il1_anal.o: ../share/put.h
|
||||
il1_anal.o: ../share/types.h
|
||||
il1_anal.o: il.h
|
||||
il1_anal.o: il1_anal.h
|
||||
il1_anal.o: il1_aux.h
|
||||
il1_anal.o: il1_cal.h
|
||||
il1_anal.o: il1_formal.h
|
||||
il1_anal.o: il_aux.h
|
||||
il1_aux.o: ../../../h/em_spec.h
|
||||
il1_aux.o: ../share/alloc.h
|
||||
il1_aux.o: ../share/debug.h
|
||||
il1_aux.o: ../share/global.h
|
||||
il1_aux.o: ../share/lset.h
|
||||
il1_aux.o: ../share/types.h
|
||||
il1_aux.o: il.h
|
||||
il1_aux.o: il1_aux.h
|
||||
il1_aux.o: il_aux.h
|
||||
il1_cal.o: ../../../h/em_mnem.h
|
||||
il1_cal.o: ../../../h/em_spec.h
|
||||
il1_cal.o: ../share/alloc.h
|
||||
il1_cal.o: ../share/debug.h
|
||||
il1_cal.o: ../share/global.h
|
||||
il1_cal.o: ../share/lset.h
|
||||
il1_cal.o: ../share/parser.h
|
||||
il1_cal.o: ../share/types.h
|
||||
il1_cal.o: il.h
|
||||
il1_cal.o: il1_aux.h
|
||||
il1_cal.o: il1_cal.h
|
||||
il1_formal.o: ../share/alloc.h
|
||||
il1_formal.o: ../share/debug.h
|
||||
il1_formal.o: ../share/global.h
|
||||
il1_formal.o: ../share/lset.h
|
||||
il1_formal.o: ../share/types.h
|
||||
il1_formal.o: il.h
|
||||
il1_formal.o: il1_aux.h
|
||||
il1_formal.o: il1_formal.h
|
||||
il2_aux.o: ../../../h/em_mnem.h
|
||||
il2_aux.o: ../../../h/em_spec.h
|
||||
il2_aux.o: ../share/alloc.h
|
||||
il2_aux.o: ../share/debug.h
|
||||
il2_aux.o: ../share/get.h
|
||||
il2_aux.o: ../share/global.h
|
||||
il2_aux.o: ../share/lset.h
|
||||
il2_aux.o: ../share/types.h
|
||||
il2_aux.o: il.h
|
||||
il2_aux.o: il2_aux.h
|
||||
il2_aux.o: il_aux.h
|
||||
il3_aux.o: ../share/alloc.h
|
||||
il3_aux.o: ../share/debug.h
|
||||
il3_aux.o: ../share/global.h
|
||||
il3_aux.o: ../share/types.h
|
||||
il3_aux.o: il.h
|
||||
il3_aux.o: il3_aux.h
|
||||
il3_aux.o: il_aux.h
|
||||
il3_change.o: ../../../h/em_mes.h
|
||||
il3_change.o: ../../../h/em_mnem.h
|
||||
il3_change.o: ../../../h/em_pseu.h
|
||||
il3_change.o: ../../../h/em_spec.h
|
||||
il3_change.o: ../share/alloc.h
|
||||
il3_change.o: ../share/debug.h
|
||||
il3_change.o: ../share/def.h
|
||||
il3_change.o: ../share/get.h
|
||||
il3_change.o: ../share/global.h
|
||||
il3_change.o: ../share/lset.h
|
||||
il3_change.o: ../share/put.h
|
||||
il3_change.o: ../share/types.h
|
||||
il3_change.o: il.h
|
||||
il3_change.o: il3_aux.h
|
||||
il3_change.o: il3_change.h
|
||||
il3_change.o: il_aux.h
|
||||
il3_subst.o: ../../../h/em_mnem.h
|
||||
il3_subst.o: ../share/alloc.h
|
||||
il3_subst.o: ../share/debug.h
|
||||
il3_subst.o: ../share/get.h
|
||||
il3_subst.o: ../share/global.h
|
||||
il3_subst.o: ../share/lset.h
|
||||
il3_subst.o: ../share/types.h
|
||||
il3_subst.o: il.h
|
||||
il3_subst.o: il3_aux.h
|
||||
il3_subst.o: il3_change.h
|
||||
il3_subst.o: il3_subst.h
|
||||
il_aux.o: ../../../h/em_spec.h
|
||||
il_aux.o: ../share/alloc.h
|
||||
il_aux.o: ../share/debug.h
|
||||
il_aux.o: ../share/global.h
|
||||
il_aux.o: ../share/lset.h
|
||||
il_aux.o: ../share/map.h
|
||||
il_aux.o: ../share/types.h
|
||||
il_aux.o: il.h
|
||||
il_aux.o: il_aux.h
|
||||
312
util/ego/il/il.c
312
util/ego/il/il.c
@@ -1,312 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N */
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "il.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/files.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../share/map.h"
|
||||
#include "il_aux.h"
|
||||
#include "il1_anal.h"
|
||||
#include "il2_aux.h"
|
||||
#include "il3_subst.h"
|
||||
#include "../share/get.h"
|
||||
#include "../share/put.h"
|
||||
#include "../share/go.h"
|
||||
|
||||
int calnr;
|
||||
calcnt_p cchead; /* call-count info of current proc */
|
||||
STATIC short space = 0;
|
||||
|
||||
STATIC char cname[] = "/usr/tmp/ego.i1.XXXXXX";
|
||||
STATIC char ccname[] = "/usr/tmp/ego.i2.XXXXXX";
|
||||
|
||||
/* For debugging only */
|
||||
STATIC char sname[] = "/usr/tmp/ego.i3.XXXXXX";
|
||||
|
||||
int Ssubst;
|
||||
#ifdef VERBOSE
|
||||
int Senv,Srecursive,Slocals,Sinstrlab,Sparsefails,Spremoved,Scals;
|
||||
int Sbig_caller,Sdispensable,Schangedcallee,Sbigcallee,Sspace,Szeroratio;
|
||||
#endif
|
||||
|
||||
/* P A S S 1
|
||||
*
|
||||
* Pass 1 reads and analyses the EM text and the CFG.
|
||||
* It determines for every procedure if it may be expanded
|
||||
* in line and how it uses its formal parameters.
|
||||
* It also collects all calls appearing in the program and
|
||||
* recognizes the actual parameters of every call.
|
||||
* The call descriptors are put in a file (calfile).
|
||||
*/
|
||||
|
||||
pass1(lnam,bnam,cnam)
|
||||
char *lnam, *bnam, *cnam;
|
||||
{
|
||||
FILE *f, *gf, *cf, *ccf; /* The EM input, the basic block graph,
|
||||
* the call-list file and the calcnt file.
|
||||
*/
|
||||
long laddr;
|
||||
bblock_p g;
|
||||
short kind;
|
||||
line_p l;
|
||||
|
||||
f = openfile(lnam,"r");
|
||||
gf = openfile(bnam,"r");
|
||||
cf = openfile(cnam,"w");
|
||||
ccf = openfile(ccname,"w");
|
||||
mesregs = Lempty_set();
|
||||
apriori(fproc);
|
||||
/* use information from the procedure table to
|
||||
* see which calls certainly cannot be expanded.
|
||||
*/
|
||||
while(TRUE) {
|
||||
laddr = ftell(f);
|
||||
if (!getunit(gf,f,&kind,&g,&l,&curproc,TRUE)) break;
|
||||
/* Read the control flow graph and EM text of
|
||||
* one procedure and analyze it.
|
||||
*/
|
||||
if (kind == LDATA) {
|
||||
remunit(LDATA,(proc_p) 0,l);
|
||||
continue;
|
||||
}
|
||||
/* OUTTRACE("flow graph of proc %d read",curproc->p_id); */
|
||||
assert(INSTR(g->b_start) == ps_pro);
|
||||
curproc->p_start = g;
|
||||
curproc->P_LADDR = laddr;
|
||||
/* address of em text in em-file */
|
||||
/* address of graph in basic block file */
|
||||
curproc->P_SIZE = proclength(curproc); /* #instructions */
|
||||
if (BIG_PROC(curproc)) {
|
||||
/* curproc is too large to be expanded in line */
|
||||
UNSUITABLE(curproc);
|
||||
}
|
||||
calnr = 0;
|
||||
anal_proc(curproc,cf,ccf);
|
||||
/* OUTTRACE("proc %d processed",curproc->p_id); */
|
||||
remunit(LTEXT,curproc,(line_p) 0);
|
||||
/* remove control flow graph + text */
|
||||
/* OUTTRACE("graph of proc %d removed",curproc->p_id); */
|
||||
Ldeleteset(mesregs);
|
||||
mesregs = Lempty_set();
|
||||
}
|
||||
fclose(f);
|
||||
fclose(gf);
|
||||
fclose(cf);
|
||||
fclose(ccf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* P A S S 2
|
||||
*
|
||||
* Pass 2 reads the calfile and determines which calls should
|
||||
* be expanded in line. It does not use the EM text.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
STATIC char cname2[] = "/usr/tmp/ego.i4.XXXXXX";
|
||||
|
||||
pass2(cnam,space)
|
||||
char *cnam;
|
||||
short space;
|
||||
{
|
||||
FILE *cf, *cf2, *ccf;
|
||||
call_p c,a;
|
||||
|
||||
cf = openfile(cnam,"r");
|
||||
cf2 = openfile(cname2,"w");
|
||||
ccf = openfile(ccname,"r");
|
||||
while ((c = getcall(cf)) != (call_p) 0) {
|
||||
/* process all calls */
|
||||
if (SUITABLE(c->cl_proc) && anal_params(c)) {
|
||||
/* called proc. may be put in line */
|
||||
/* see which parameters may be put in line */
|
||||
assign_ratio(c); /* assign a rank */
|
||||
a = abstract(c); /* abstract essential info */
|
||||
append_abstract(a,a->cl_caller);
|
||||
/* put it in call-list of calling proc. */
|
||||
putcall(c,cf2,(short) 0);
|
||||
} else {
|
||||
rem_call(c);
|
||||
}
|
||||
}
|
||||
select_calls(fproc,ccf,space);
|
||||
fclose(cf); unlink(cnam);
|
||||
fclose(cf2);
|
||||
fclose(ccf); unlink(ccname);
|
||||
cf2 = openfile(cname2,"r");
|
||||
add_actuals(fproc,cf2);
|
||||
cleancals(fproc); /* remove calls that were not selected */
|
||||
/* add actual parameters to each selected call */
|
||||
fclose(cf2); unlink(cname2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* P A S S 3
|
||||
*
|
||||
* pass 3 reads the substitution file and performs all
|
||||
* substitutions described in that file. It reads the
|
||||
* original EM text and produced a new (optimized)
|
||||
* EM textfile.
|
||||
*/
|
||||
|
||||
|
||||
pass3(lnam,lnam2)
|
||||
char *lnam,*lnam2;
|
||||
{
|
||||
bool verbose = TRUE;
|
||||
FILE *lfile, *lfilerand, *lfile2, *sfile;
|
||||
call_p c,next;
|
||||
line_p l,startscan,cal;
|
||||
short lastcid; /* last call-id seen */
|
||||
|
||||
lfile = openfile(lnam, "r");
|
||||
lfilerand = openfile(lnam, "r");
|
||||
lfile2 = openfile(lnam2,"w");
|
||||
if (verbose) {
|
||||
sfile = openfile(sname,"w");
|
||||
}
|
||||
mesregs = Lempty_set();
|
||||
while ((l = get_text(lfile,&curproc)) != (line_p) 0) {
|
||||
if (curproc == (proc_p) 0) {
|
||||
/* Just a data-unit; no real instructions */
|
||||
putlines(l->l_next,lfile2);
|
||||
oldline(l);
|
||||
continue;
|
||||
}
|
||||
if (IS_DISPENSABLE(curproc)) {
|
||||
liquidate(curproc,l->l_next);
|
||||
} else {
|
||||
startscan = l->l_next;
|
||||
lastcid = 0;
|
||||
for (c = curproc->P_CALS; c != (call_p) 0; c = next) {
|
||||
next = c->cl_cdr;
|
||||
cal = scan_to_cal(startscan,c->cl_id - lastcid);
|
||||
assert (cal != (line_p) 0);
|
||||
startscan = scan_to_cal(cal->l_next,1);
|
||||
/* next CAL */
|
||||
lastcid = c->cl_id;
|
||||
/* next CAL after current one */
|
||||
substitute(lfilerand,c,cal,l->l_next);
|
||||
if (verbose) {
|
||||
putcall(c,sfile,0);
|
||||
} else {
|
||||
rem_call(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
putlines(l->l_next,lfile2);
|
||||
Ldeleteset(mesregs);
|
||||
mesregs = Lempty_set();
|
||||
oldline(l);
|
||||
}
|
||||
fclose(lfile);
|
||||
fclose(lfile2);
|
||||
if (verbose) {
|
||||
fclose(sfile);
|
||||
unlink(sname);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC il_extptab(ptab)
|
||||
proc_p ptab;
|
||||
{
|
||||
/* Allocate space for extension of proctable entries.
|
||||
* Also, initialise some of the fields just allocated.
|
||||
*/
|
||||
|
||||
register proc_p p;
|
||||
|
||||
for (p = ptab; p != (proc_p) 0; p = p->p_next) {
|
||||
p->p_extend = newilpx();
|
||||
p->P_ORGLABELS = p->p_nrlabels;
|
||||
p->P_ORGLOCALS = p->p_localbytes;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC il_cleanptab(ptab)
|
||||
proc_p ptab;
|
||||
{
|
||||
/* De-allocate space for extensions */
|
||||
|
||||
register proc_p p;
|
||||
|
||||
for (p = ptab; p != (proc_p) 0; p = p->p_next) {
|
||||
oldilpx(p->p_extend);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VERBOSE
|
||||
Sdiagnostics()
|
||||
{
|
||||
/* print statictical information */
|
||||
|
||||
fprintf(stderr,"STATISTICS:\n");
|
||||
fprintf(stderr,"Info about procedures:\n");
|
||||
fprintf(stderr,"environment accessed: %d\n",Senv);
|
||||
fprintf(stderr,"recursive: %d\n",Srecursive);
|
||||
fprintf(stderr,"too many locals: %d\n",Slocals);
|
||||
fprintf(stderr,"instr. lab in data block: %d\n",Sinstrlab);
|
||||
fprintf(stderr,"procedures removed: %d\n",Spremoved);
|
||||
fprintf(stderr,"\nInfo about calls:\n");
|
||||
fprintf(stderr,"total number of calls: %d\n",Scals);
|
||||
fprintf(stderr,"total number of calls substituted: %d\n",Ssubst);
|
||||
fprintf(stderr,"parser failed: %d\n",Sparsefails);
|
||||
fprintf(stderr,"caller too big: %d\n",Sbig_caller);
|
||||
fprintf(stderr,"caller dispensable: %d\n",Sdispensable);
|
||||
fprintf(stderr,"callee is changed: %d\n",Schangedcallee);
|
||||
fprintf(stderr,"callee too big: %d\n",Sbigcallee);
|
||||
fprintf(stderr,"no space available: %d\n",Sspace);
|
||||
fprintf(stderr,"zero ratio: %d\n",Szeroratio);
|
||||
}
|
||||
#endif
|
||||
|
||||
il_flags(p)
|
||||
char *p;
|
||||
{
|
||||
if (*p++ == 's') {
|
||||
while (*p != '\0') {
|
||||
space = 10*space +*p++ -'0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
go(argc,argv,no_action,no_action,no_action,il_flags);
|
||||
il_extptab(fproc); /* add extended data structures */
|
||||
mktemp(cname);
|
||||
mktemp(ccname);
|
||||
mktemp(sname);
|
||||
mktemp(cname2);
|
||||
pass1(lname,bname,cname); /* grep calls, analyse procedures */
|
||||
pass2(cname,space); /* select calls to be expanded */
|
||||
pass3(lname,lname2); /* do substitutions */
|
||||
f = openfile(dname2,"w");
|
||||
il_cleanptab(fproc); /* remove extended data structures */
|
||||
putdtable(fdblock,f);
|
||||
f = openfile(pname2,"w");
|
||||
putptable(fproc,f,FALSE);
|
||||
report("inline substitutions",Ssubst);
|
||||
#ifdef VERBOSE
|
||||
if (verbose_flag) {
|
||||
Sdiagnostics();
|
||||
}
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
core_usage();
|
||||
#endif
|
||||
exit(0);
|
||||
}
|
||||
161
util/ego/il/il.h
161
util/ego/il/il.h
@@ -1,161 +0,0 @@
|
||||
/* I N T E R N A L D A T A S T R U C T U R E S O F
|
||||
*
|
||||
* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
typedef struct actual *actual_p;
|
||||
typedef struct calcnt *calcnt_p;
|
||||
typedef short call_id;
|
||||
|
||||
struct call {
|
||||
proc_p cl_caller; /* calling procedure */
|
||||
call_id cl_id; /* uniquely denotes a CAL instruction */
|
||||
proc_p cl_proc; /* the called procedure */
|
||||
byte cl_looplevel; /* loop nesting level of the CAL */
|
||||
bool cl_flags; /* flag bits */
|
||||
short cl_ratio; /* indicates 'speed gain / size lost' */
|
||||
call_p cl_cdr; /* link to next call */
|
||||
call_p cl_car; /* link to nested calls */
|
||||
actual_p cl_actuals; /* actual parameter expr. trees */
|
||||
};
|
||||
|
||||
#define CLF_INLPARS 017 /* min(15,nr. of inline parameters) */
|
||||
#define CLF_SELECTED 020 /* is call selected for expansion? */
|
||||
#define CLF_EVER_EXPANDED 040 /* ever expanded? e.g. in a nested call. */
|
||||
#define CLF_FIRM 0100 /* indicates if the call takes place in a
|
||||
* firm block of a loop (i.e. one that
|
||||
* is always executed, except
|
||||
* -perhaps- at the last iteration).
|
||||
* Used for heuristics only.
|
||||
*/
|
||||
|
||||
struct actual {
|
||||
line_p ac_exp; /* copy of EM text */
|
||||
/* 0 for actuals that are not inline */
|
||||
offset ac_size; /* number of bytes of parameter */
|
||||
bool ac_inl; /* TRUE if it may be expanded in line */
|
||||
actual_p ac_next; /* link */
|
||||
};
|
||||
|
||||
|
||||
struct formal {
|
||||
offset f_offset; /* offsetin bytes */
|
||||
byte f_flags; /* flags FF_BAD etc. */
|
||||
byte f_type; /* SINGLE, DOUBLE,POINTER,UNKNOWN */
|
||||
formal_p f_next; /* link */
|
||||
};
|
||||
|
||||
|
||||
/* flags of formal: */
|
||||
|
||||
#define FF_BAD 01
|
||||
#define FF_REG 02
|
||||
#define FF_ONCEUSED 04
|
||||
#define FF_OFTENUSED 06
|
||||
#define USEMASK 014
|
||||
|
||||
/* types of formals: */
|
||||
|
||||
#define SINGLE 1
|
||||
#define DOUBLE 2
|
||||
#define POINTER 3
|
||||
#define UNKNOWN 4
|
||||
|
||||
/* 'call-count' information keeps track of the number
|
||||
* of times one procedure calls another. Conceptually,
|
||||
* it may be regarded as a two dimensional array, where
|
||||
* calcnt[p,q] is the number of times p calls q. As this
|
||||
* matrix would be very dense, we use a more efficient
|
||||
* list representation. Every procedure has a list
|
||||
* of calcnt structs.
|
||||
*/
|
||||
|
||||
struct calcnt {
|
||||
proc_p cc_proc; /* the called procedure */
|
||||
short cc_count; /* # times proc. is called in the
|
||||
* original text of the caller.
|
||||
*/
|
||||
calcnt_p cc_next; /* link */
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
extern int calnr;
|
||||
extern calcnt_p cchead; /* calcnt info of current proc */
|
||||
|
||||
/* Macro's for extended data structures */
|
||||
|
||||
#define P_CALS p_extend->px_il.p_cals
|
||||
#define P_SIZE p_extend->px_il.p_size
|
||||
#define P_FORMALS p_extend->px_il.p_formals
|
||||
#define P_NRCALLED p_extend->px_il.p_nrcalled
|
||||
#define P_CCADDR p_extend->px_il.p_ccaddr
|
||||
#define P_LADDR p_extend->px_il.p_laddr
|
||||
#define P_ORGLABELS p_extend->px_il.p_orglabels
|
||||
#define P_ORGLOCALS p_extend->px_il.p_orglocals
|
||||
|
||||
/* flags2: */
|
||||
|
||||
#define PF_UNSUITABLE 01
|
||||
#define PF_NO_INLPARS 02
|
||||
#define PF_FALLTHROUGH 04
|
||||
#define PF_DISPENSABLE 010
|
||||
#define PF_CHANGED 020
|
||||
|
||||
|
||||
/* kinds of usages: */
|
||||
|
||||
#define USE 0
|
||||
#define CHANGE 1
|
||||
#define ADDRESS 2
|
||||
|
||||
|
||||
|
||||
|
||||
/* We do not expand calls if:
|
||||
* - the called procedure has to many local variables
|
||||
* - the calling procedure is already very large
|
||||
* - the called procedure is to large.
|
||||
*/
|
||||
|
||||
#define MANY_LOCALS(p) (p->p_localbytes > LOCAL_THRESHOLD)
|
||||
#define LOCAL_THRESHOLD 200
|
||||
#define BIG_CALLER(p) (p->P_SIZE > CALLER_THRESHOLD)
|
||||
#define CALLER_THRESHOLD 500
|
||||
#define BIG_PROC(p) (p->P_SIZE > CALLEE_THRESHOLD)
|
||||
#define CALLEE_THRESHOLD 100
|
||||
|
||||
#define FALLTHROUGH(p) (p->p_flags2 & PF_FALLTHROUGH)
|
||||
#define DISPENSABLE(p) p->p_flags2 |= PF_DISPENSABLE
|
||||
#define IS_DISPENSABLE(p) (p->p_flags2 & PF_DISPENSABLE)
|
||||
#define SELECTED(c) c->cl_flags |= CLF_SELECTED
|
||||
#define IS_SELECTED(c) (c->cl_flags & CLF_SELECTED)
|
||||
#define EVER_EXPANDED(c) c->cl_flags |= CLF_EVER_EXPANDED
|
||||
#define IS_EVER_EXPANDED(c) (c->cl_flags & CLF_EVER_EXPANDED)
|
||||
#define UNSUITABLE(p) p->p_flags2 |= PF_UNSUITABLE
|
||||
#define SUITABLE(p) (!(p->p_flags2&PF_UNSUITABLE))
|
||||
#define INLINE_PARS(p) (!(p->p_flags2&PF_NO_INLPARS))
|
||||
#define PARAMS_UNKNOWN(p) (p->p_nrformals == UNKNOWN_SIZE)
|
||||
|
||||
extern int Ssubst;
|
||||
#ifdef VERBOSE
|
||||
extern int Senv,Srecursive,Slocals,Sinstrlab,Sparsefails,Spremoved,Scals;
|
||||
extern int Sbig_caller,Sdispensable,Schangedcallee,Sbigcallee,Sspace,Szeroratio;
|
||||
#endif
|
||||
|
||||
/* extra core-allocation macros */
|
||||
|
||||
#define newcall() (call_p) newstruct(call)
|
||||
#define newactual() (actual_p) newstruct(actual)
|
||||
#define newformal() (formal_p) newstruct(formal)
|
||||
#define newcalcnt() (calcnt_p) newstruct(calcnt)
|
||||
#define newilpx() (pext_p) newstruct(pext_il)
|
||||
|
||||
#define oldcall(x) oldstruct(call,x)
|
||||
#define oldactual(x) oldstruct(actual,x)
|
||||
#define oldformal(x) oldstruct(formal,x)
|
||||
#define oldcalcnt(x) oldstruct(calcnt,x)
|
||||
#define oldilpx(x) oldstruct(pext_il,x)
|
||||
@@ -1,177 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 1 _ A N A L . C
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "il.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "il1_aux.h"
|
||||
#include "il1_formal.h"
|
||||
#include "il1_cal.h"
|
||||
#include "il1_anal.h"
|
||||
#include "il_aux.h"
|
||||
#include "../share/put.h"
|
||||
|
||||
#define BODY_KNOWN(p) (p->p_flags1 & (byte) PF_BODYSEEN)
|
||||
#define ENVIRON(p) (p->p_flags1 & (byte) PF_ENVIRON)
|
||||
#define RETURN_BLOCK(b) (Lnrelems(b->b_succ) == 0)
|
||||
#define LAST_BLOCK(b) (b->b_next == (bblock_p) 0)
|
||||
|
||||
/* Daisy chain recursion not yet accounted for: */
|
||||
#define RECURSIVE(p) (Cis_elem(p->p_id,p->p_calling))
|
||||
/*
|
||||
#define CALLS_UNKNOWN(p) (p->p_flags1 & (byte) PF_CALUNKNOWN)
|
||||
*/
|
||||
#define CALLS_UNKNOWN(p) (FALSE)
|
||||
|
||||
|
||||
|
||||
apriori(proctab)
|
||||
proc_p proctab;
|
||||
{
|
||||
/* For every procedure, see if we can determine
|
||||
* from the information provided by the previous
|
||||
* phases of the optimizer that it cannot or should not
|
||||
* be expanded in line. This will reduce the length
|
||||
* of the call list.
|
||||
*/
|
||||
|
||||
register proc_p p;
|
||||
|
||||
for (p = proctab; p != (proc_p) 0; p = p->p_next) {
|
||||
if (!BODY_KNOWN(p) ||
|
||||
ENVIRON(p) || RECURSIVE(p) ||
|
||||
PARAMS_UNKNOWN(p) || MANY_LOCALS(p)) {
|
||||
UNSUITABLE(p);
|
||||
#ifdef VERBOSE
|
||||
if (BODY_KNOWN(p)) {
|
||||
if (ENVIRON(p)) Senv++;
|
||||
if (RECURSIVE(p)) Srecursive++;
|
||||
if (MANY_LOCALS(p)) Slocals++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC check_labels(p,arglist)
|
||||
proc_p p;
|
||||
arg_p arglist;
|
||||
{
|
||||
/* Check if any of the arguments contains an instruction
|
||||
* label; if so, make p unsuitable.
|
||||
*/
|
||||
|
||||
arg_p arg;
|
||||
|
||||
for (arg = arglist; arg != (arg_p) 0; arg = arg->a_next) {
|
||||
if (arg->a_type == ARGINSTRLAB) {
|
||||
UNSUITABLE(p);
|
||||
#ifdef VERBOSE
|
||||
Sinstrlab++;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC anal_instr(p,b,cf)
|
||||
proc_p p;
|
||||
bblock_p b;
|
||||
FILE *cf;
|
||||
{
|
||||
/* Analyze the instructions of block b
|
||||
* within procedure p.
|
||||
* See which parameters are used, changed
|
||||
* or have their address taken. Recognize
|
||||
* the actual parameter expressions of
|
||||
* the CAL instructions.
|
||||
*/
|
||||
|
||||
register line_p l;
|
||||
|
||||
for (l = b->b_start; l != (line_p) 0; l = l->l_next) {
|
||||
switch(INSTR(l)) {
|
||||
case op_cal:
|
||||
anal_cal(p,l,b,cf);
|
||||
break;
|
||||
case op_stl:
|
||||
case op_inl:
|
||||
case op_del:
|
||||
case op_zrl:
|
||||
formal(p,b,off_set(l),SINGLE,CHANGE);
|
||||
/* see if the local is a parameter.
|
||||
* If so, it is a one-word parameter
|
||||
* that is stored into.
|
||||
*/
|
||||
break;
|
||||
case op_sdl:
|
||||
formal(p,b,off_set(l),DOUBLE,CHANGE);
|
||||
break;
|
||||
case op_lol:
|
||||
formal(p,b,off_set(l),SINGLE,USE);
|
||||
break;
|
||||
case op_ldl:
|
||||
formal(p,b,off_set(l),DOUBLE,USE);
|
||||
break;
|
||||
case op_sil:
|
||||
case op_lil:
|
||||
formal(p,b,off_set(l),POINTER,USE);
|
||||
break;
|
||||
case op_lal:
|
||||
formal(p,b,off_set(l),UNKNOWN,ADDRESS);
|
||||
break;
|
||||
case ps_rom:
|
||||
case ps_con:
|
||||
case ps_bss:
|
||||
case ps_hol:
|
||||
check_labels(p,ARG(l));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
anal_proc(p,cf,ccf)
|
||||
proc_p p;
|
||||
FILE *cf,*ccf;
|
||||
{
|
||||
/* Analyze a procedure; use information
|
||||
* stored in its basic blocks or in
|
||||
* its instructions.
|
||||
*/
|
||||
|
||||
register bblock_p b;
|
||||
bool fallthrough = TRUE;
|
||||
|
||||
cchead = (calcnt_p) 0;
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
if (RETURN_BLOCK(b) && !LAST_BLOCK(b)) {
|
||||
fallthrough = FALSE;
|
||||
/* p contains a RET instruction somewhere
|
||||
* in the middle of its code.
|
||||
*/
|
||||
}
|
||||
anal_instr(p,b,cf); /* analyze instructions */
|
||||
}
|
||||
if (fallthrough) {
|
||||
p->p_flags2 |= PF_FALLTHROUGH;
|
||||
}
|
||||
rem_indir_acc(p);
|
||||
/* don't expand formal that may be accessed indirectly */
|
||||
p->P_CCADDR = putcc(cchead,ccf);
|
||||
/* write calcnt info and remember disk address */
|
||||
remcc(cchead);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 1 _ A N A L . H
|
||||
*/
|
||||
|
||||
extern apriori(); /* (proc_p proctab)
|
||||
* For every procedure, see if we can determine
|
||||
* from the information provided by the previous
|
||||
* phases of the optimizer that it cannot or should not
|
||||
* be expanded in line. This will reduce the length
|
||||
* of the call list.
|
||||
*/
|
||||
extern anal_proc(); /* (proc_p p, FILE *cf, *cff)
|
||||
* Analyse a procedure. See which formal parameters
|
||||
* it uses and which procedures it calls.
|
||||
* cf and ccf are the call-file and the call-count file.
|
||||
*/
|
||||
@@ -1,208 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 1 _ A U X . C
|
||||
*/
|
||||
|
||||
#include "../share/types.h"
|
||||
#include "il.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "il_aux.h"
|
||||
#include "il1_aux.h"
|
||||
|
||||
#define CHANGE_INDIR(p) (p->p_change->c_flags & CF_INDIR)
|
||||
#define USE_INDIR(p) (p->p_use->u_flags & UF_INDIR)
|
||||
|
||||
#define IS_INSTR(c) (c >= sp_fmnem && c <= sp_lmnem)
|
||||
|
||||
|
||||
bool same_size(t1,t2)
|
||||
int t1, t2;
|
||||
{
|
||||
/* See if the two types have the same size */
|
||||
|
||||
return tsize(t1) == tsize(t2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool is_reg(off,s)
|
||||
offset off;
|
||||
int s;
|
||||
{
|
||||
/* See if there is a register message
|
||||
* for the local or parameter at offset off
|
||||
* and size s.
|
||||
*/
|
||||
|
||||
Lindex i;
|
||||
arg_p arg;
|
||||
|
||||
for (i = Lfirst(mesregs); i != (Lindex) 0; i = Lnext(i,mesregs)) {
|
||||
arg = ((line_p) Lelem(i))->l_a.la_arg->a_next;
|
||||
if (arg->a_a.a_offset == off &&
|
||||
arg->a_next->a_a.a_offset == s) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
rem_actuals(acts)
|
||||
actual_p acts;
|
||||
{
|
||||
/* remove the actual-list */
|
||||
|
||||
actual_p a,next;
|
||||
|
||||
for (a = acts; a != (actual_p) 0; a = next) {
|
||||
next = a->ac_next;
|
||||
/* REMOVE CODE OF a->ac_exp HERE */
|
||||
oldactual(a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
remov_formals(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Remove the list of formals of p */
|
||||
|
||||
formal_p f, next;
|
||||
|
||||
for (f = p->P_FORMALS; f != (formal_p) 0; f = next) {
|
||||
next = f->f_next;
|
||||
oldformal(f);
|
||||
}
|
||||
p->P_FORMALS = (formal_p) 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
rem_indir_acc(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Formals that may be accessed indirectly
|
||||
* cannot be expanded in line, so they are
|
||||
* removed from the formals list.
|
||||
*/
|
||||
|
||||
formal_p prev, f, next;
|
||||
|
||||
if (!USE_INDIR(p) && !CHANGE_INDIR(p)) return;
|
||||
/* Any formal for which we don't have
|
||||
* a register message is now doomed.
|
||||
*/
|
||||
prev = (formal_p) 0;
|
||||
for (f = p->P_FORMALS; f != (formal_p) 0; f = next) {
|
||||
next = f->f_next;
|
||||
if (!is_reg(f->f_offset,tsize(f->f_type))) {
|
||||
if (prev == (formal_p) 0) {
|
||||
p->P_FORMALS = next;
|
||||
} else {
|
||||
prev->f_next = next;
|
||||
}
|
||||
oldformal(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool par_overlap(off1,t1,off2,t2)
|
||||
offset off1,off2;
|
||||
int t1,t2;
|
||||
{
|
||||
/* See if the parameter at offset off1 and type t1
|
||||
* overlaps the paramete at offset off2 and type t2.
|
||||
*/
|
||||
|
||||
if (off1 > off2) {
|
||||
return off2 + tsize(t2) > off1;
|
||||
} else {
|
||||
if (off2 > off1) {
|
||||
return off1 + tsize(t1) > off2;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
short looplevel(b)
|
||||
bblock_p b;
|
||||
{
|
||||
/* determine the loop nesting level of basic block b;
|
||||
* this is the highest nesting level of all blocks
|
||||
* that b is part of.
|
||||
* Note that the level of a loop is 0 for outer loops,
|
||||
* so a block inside a loop with nesting level N has
|
||||
* looplevel N+1.
|
||||
*/
|
||||
|
||||
Lindex i;
|
||||
short max = 0;
|
||||
|
||||
for (i = Lfirst(b->b_loops); i != (Lindex)0; i = Lnext(i,b->b_loops)) {
|
||||
if (((loop_p) Lelem(i))->lp_level >= max) {
|
||||
max = ((loop_p) Lelem(i))->lp_level + 1;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
|
||||
short proclength(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* count the number of EM instructions of p */
|
||||
|
||||
register short cnt;
|
||||
register bblock_p b;
|
||||
register line_p l;
|
||||
|
||||
cnt = 0;
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
for (l = b->b_start; l != (line_p) 0; l = l->l_next) {
|
||||
if (IS_INSTR(INSTR(l))) {
|
||||
/* skip pseudo instructions */
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
line_p copy_code(l1,l2)
|
||||
line_p l1,l2;
|
||||
{
|
||||
/* copy the code between l1 and l2 */
|
||||
|
||||
line_p head, tail, l, lnp;
|
||||
|
||||
head = (line_p) 0;
|
||||
for (lnp = l1; ; lnp = lnp->l_next) {
|
||||
l = duplicate(lnp);
|
||||
if (head == (line_p) 0) {
|
||||
head = tail = l;
|
||||
PREV(l) = (line_p) 0;
|
||||
} else {
|
||||
tail->l_next = l;
|
||||
PREV(l) = tail;
|
||||
tail = l;
|
||||
}
|
||||
if (lnp == l2) break;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 1 _ A U X . H
|
||||
*/
|
||||
|
||||
extern bool same_size(); /* (int t1,t2)
|
||||
* See if the two types t1 and t2 have
|
||||
* the same size.
|
||||
*/
|
||||
extern rem_actuals(); /* (actual_p atcs)
|
||||
* remove an actual-list from core.
|
||||
*/
|
||||
extern remov_formals(); /* (proc_p p)
|
||||
* Remove the formals-list of p from core.
|
||||
*/
|
||||
extern rem_indir_acc(); /* (proc_p p)
|
||||
* Remove formal that may be accessed
|
||||
* indirectly from formal lists of p
|
||||
*/
|
||||
extern bool par_overlap(); /* (offset off1, int t1, offset off2, int t2)
|
||||
* See if the formal at offset off1 and type t1
|
||||
* overlaps the formal at offset off2
|
||||
* and type t2.
|
||||
*/
|
||||
extern short looplevel(); /* (bblock_p b)
|
||||
* Determine the loop nesting level of b.
|
||||
*/
|
||||
extern short proclength(); /* (proc_p p)
|
||||
* Determine the number of EM instructions
|
||||
* in p. Do not count pseudos.
|
||||
*/
|
||||
|
||||
extern line_p copy_code(); /* (line_p l1,l2)
|
||||
* copy the code between l1 and l2.
|
||||
* Pseudos may not be contained in
|
||||
* the list of instructions. If l1==l2
|
||||
* the result is only one instruction.
|
||||
*/
|
||||
@@ -1,138 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 1 _ C A L . C
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "il.h"
|
||||
#include "il1_cal.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "il1_aux.h"
|
||||
#include "../share/parser.h"
|
||||
|
||||
STATIC actual_p acts, *app;
|
||||
|
||||
#define INIT_ACTS() {acts = (actual_p) 0; app = &acts;}
|
||||
#define APPEND_ACTUAL(a) {*app = a; app = &a->ac_next;}
|
||||
|
||||
STATIC make_actual(l1,l2,size)
|
||||
line_p l1,l2;
|
||||
offset size;
|
||||
{
|
||||
/* Allocate a struct for a new actual parameter
|
||||
* expression, the code of which extends from
|
||||
* l1 to l2.
|
||||
*/
|
||||
|
||||
actual_p a;
|
||||
|
||||
a = newactual();
|
||||
a->ac_exp = copy_code(l1,l2);
|
||||
a->ac_size = size;
|
||||
APPEND_ACTUAL(a); /* append it to actual-list */
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool chck_asp(p,l)
|
||||
proc_p p;
|
||||
line_p l;
|
||||
{
|
||||
/* We require a call to a procedure p that has n formal
|
||||
* parameters to be followed by an 'asp n' instruction
|
||||
* (i.e. the caller should remove the actual parameters).
|
||||
*/
|
||||
|
||||
return (p->p_nrformals == 0 || (l != (line_p) 0 &&INSTR(l) == op_asp &&
|
||||
TYPE(l) == OPSHORT && SHORT(l) == p->p_nrformals));
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC inc_count(caller,callee)
|
||||
proc_p caller, callee;
|
||||
{
|
||||
/* Update the call-count information.
|
||||
* Record the fact that there is one more call
|
||||
* to 'callee', appearing in 'caller'.
|
||||
*/
|
||||
|
||||
calcnt_p cc;
|
||||
|
||||
if (!SUITABLE(caller)) return;
|
||||
/* if the calling routine is never expanded in line
|
||||
* we do not need call-count information.
|
||||
*/
|
||||
for (cc = cchead; cc != (calcnt_p) 0; cc = cc->cc_next) {
|
||||
if (cc->cc_proc == callee) {
|
||||
cc->cc_count++;
|
||||
/* #calls to callee from caller */
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* This is the first call from caller to callee.
|
||||
* Allocate a new calcnt struct.
|
||||
*/
|
||||
cc = newcalcnt();
|
||||
cc->cc_proc = callee;
|
||||
cc->cc_count = 1;
|
||||
cc->cc_next = cchead; /* insert it at front of list */
|
||||
cchead = cc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
anal_cal(p,call,b,cf)
|
||||
proc_p p;
|
||||
line_p call;
|
||||
bblock_p b;
|
||||
FILE *cf;
|
||||
{
|
||||
/* Analyze a call instruction. If the called
|
||||
* routine may be expanded in line, try to
|
||||
* recognize the actual parameter expressions of
|
||||
* the call and extend the call list.
|
||||
*/
|
||||
|
||||
call_p c;
|
||||
line_p lnp;
|
||||
proc_p callee;
|
||||
|
||||
#ifdef VERBOSE
|
||||
Scals++;
|
||||
#endif
|
||||
calnr++;
|
||||
callee = PROC(call);
|
||||
if (SUITABLE(callee)) {
|
||||
/* The called procedure may be expanded */
|
||||
callee->P_NRCALLED++; /* #calls to callee from anywhere */
|
||||
INIT_ACTS();
|
||||
if (parse(PREV(call),callee->p_nrformals,&lnp,0,make_actual) &&
|
||||
chck_asp(callee,call->l_next)) {
|
||||
/* succeeded in recognizing the actuals */
|
||||
c = newcall();
|
||||
c->cl_caller = p;
|
||||
c->cl_id = calnr;
|
||||
c->cl_proc = callee;
|
||||
c->cl_looplevel = (byte) looplevel(b);
|
||||
if (c->cl_looplevel > 0 && IS_FIRM(b)) {
|
||||
c->cl_flags |= CLF_FIRM;
|
||||
}
|
||||
c->cl_actuals = acts;
|
||||
inc_count(p,callee);
|
||||
/* update call-count info */
|
||||
putcall(c,cf,(short) 0); /* write the call to the calfile */
|
||||
} else {
|
||||
#ifdef VERBOSE
|
||||
Sparsefails++;
|
||||
#endif
|
||||
rem_actuals(acts);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 1 _ C A L . C
|
||||
*/
|
||||
|
||||
struct class {
|
||||
byte src_class;
|
||||
byte res_class;
|
||||
};
|
||||
|
||||
typedef struct class *class_p;
|
||||
|
||||
extern struct class classtab[];
|
||||
|
||||
#define NOCLASS 0
|
||||
#define CLASS1 1
|
||||
#define CLASS2 2
|
||||
#define CLASS3 3
|
||||
#define CLASS4 4
|
||||
#define CLASS5 5
|
||||
#define CLASS6 6
|
||||
#define CLASS7 7
|
||||
#define CLASS8 8
|
||||
#define CLASS9 9
|
||||
|
||||
|
||||
extern anal_cal(); /* (line_p call, bblock_p b)
|
||||
* analyze a call instruction;
|
||||
* try to recognize the actual parameter
|
||||
* expressions.
|
||||
*/
|
||||
@@ -1,141 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 1 _ F O R M A L . C
|
||||
*/
|
||||
|
||||
#include "../share/types.h"
|
||||
#include "il.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "il1_aux.h"
|
||||
#include "il1_formal.h"
|
||||
|
||||
#define NOT_USED(f) (!(f->f_flags & USEMASK))
|
||||
#define USED_ONCE(f) f->f_flags |= FF_ONCEUSED
|
||||
#define USED_OFTEN(f) f->f_flags |= FF_OFTENUSED
|
||||
#define BADFORMAL(f) f->f_flags |= FF_BAD
|
||||
|
||||
#define OUTSIDE_LOOP(b) (Lnrelems(b->b_loops) == 0)
|
||||
#define IS_FORMAL(x) (x >= 0)
|
||||
|
||||
|
||||
|
||||
formal_p find_formal(p,type,off)
|
||||
proc_p p;
|
||||
int type;
|
||||
offset off;
|
||||
{
|
||||
/* Find a formal parameter of p
|
||||
* If the formal overlaps with an existing formal
|
||||
* or has an unknown type (i.e. its address is used)
|
||||
* 0 is returned.
|
||||
*/
|
||||
|
||||
formal_p f,prev,nf;
|
||||
|
||||
if (type == UNKNOWN) return (formal_p) 0;
|
||||
prev = (formal_p) 0;
|
||||
for (f = p->P_FORMALS; f != (formal_p) 0; f = f->f_next) {
|
||||
if (f->f_offset >= off) break;
|
||||
prev = f;
|
||||
}
|
||||
if (f != (formal_p) 0 && f->f_offset == off) {
|
||||
return (same_size(f->f_type,type) ? f : (formal_p) 0);
|
||||
}
|
||||
if (f != (formal_p) 0 && par_overlap(off,type,f->f_offset,f->f_type)) {
|
||||
return (formal_p) 0;
|
||||
}
|
||||
if (prev != (formal_p) 0 && par_overlap(prev->f_offset,prev->f_type,
|
||||
off,type)) {
|
||||
return (formal_p) 0;
|
||||
}
|
||||
nf = newformal();
|
||||
nf->f_type = type;
|
||||
nf->f_offset = off;
|
||||
if (prev == (formal_p) 0) {
|
||||
p->P_FORMALS = nf;
|
||||
} else {
|
||||
prev->f_next = nf;
|
||||
}
|
||||
nf->f_next = f;
|
||||
return nf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC no_inl_pars(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* p may not have any in line parameters */
|
||||
|
||||
p->p_flags2 |= PF_NO_INLPARS;
|
||||
remov_formals(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC inc_use(f,b)
|
||||
formal_p f;
|
||||
bblock_p b;
|
||||
{
|
||||
/* Increment the use count of formal f.
|
||||
* The counter has only three states: not used,
|
||||
* used once, used more than once.
|
||||
* We count the number of times the formal
|
||||
* is used dynamically (rather than statically),
|
||||
* so if it is used in a loop, the counter
|
||||
* is always set to more than once.
|
||||
*/
|
||||
|
||||
if (NOT_USED(f) && OUTSIDE_LOOP(b)) {
|
||||
USED_ONCE(f);
|
||||
} else {
|
||||
USED_OFTEN(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
formal(p,b,off,type,usage)
|
||||
proc_p p;
|
||||
bblock_p b;
|
||||
offset off;
|
||||
int type,
|
||||
usage;
|
||||
{
|
||||
/* Analyze a reference to a parameter of p
|
||||
* (occurring within basic block b).
|
||||
* The parameter has offset off. If this
|
||||
* offset is less than 0, it is not a
|
||||
* parameter, but a local.
|
||||
* The type can be SINGLE (1 word), DOUBLE
|
||||
* (2 words), POINTER or UNKNOWN.
|
||||
*/
|
||||
|
||||
formal_p f;
|
||||
|
||||
if (!IS_FORMAL(off) || !SUITABLE(p) || !INLINE_PARS(p)) return;
|
||||
/* We are not interested in formal parameters of
|
||||
* proccedures that will never be expanded in line,
|
||||
* or whose parameters will not be expanded in line.
|
||||
*/
|
||||
f = find_formal(p,type,off);
|
||||
/* Find the formal; if not found, create one;
|
||||
* if inconsistent with previous formals (e.g.
|
||||
* overlapping formals) then return 0;
|
||||
* also fills in its type.
|
||||
*/
|
||||
if (f == (formal_p) 0) {
|
||||
no_inl_pars(p);
|
||||
/* parameters of p may not be expanded in line */
|
||||
} else {
|
||||
if (usage == CHANGE) {
|
||||
/* don't expand f in line */
|
||||
BADFORMAL(f);
|
||||
} else {
|
||||
inc_use(f,b); /* increment use count */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 1 _ F O R M A L . C
|
||||
*/
|
||||
|
||||
extern formal(); /* (proc_p p; bblock_p b; offset off;
|
||||
* int type, usage)
|
||||
* Analyze a reference to a parameter of p.
|
||||
* The type denotes its size (single,double,
|
||||
* pointer).
|
||||
*/
|
||||
@@ -1,720 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 2 _ A U X . C
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "il.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "il_aux.h"
|
||||
#include "il2_aux.h"
|
||||
#include "../share/get.h"
|
||||
#include "../share/aux.h"
|
||||
|
||||
#define CHANGE_INDIR(p) (p->p_change->c_flags & CF_INDIR)
|
||||
#define USE_INDIR(p) (p->p_use->u_flags & UF_INDIR)
|
||||
|
||||
#define OFTEN_USED(f) ((f->f_flags&FF_OFTENUSED) == FF_OFTENUSED)
|
||||
#define CHANGE_EXT(p) (Cnrelems(p->p_change->c_ext) > 0)
|
||||
#define NOT_INLINE(a) (a->ac_inl = FALSE)
|
||||
#define INLINE(a) (a->ac_inl = TRUE)
|
||||
|
||||
|
||||
#define CHANGED(p) p->p_flags2 |= PF_CHANGED
|
||||
#define IS_CHANGED(p) (p->p_flags2 & PF_CHANGED)
|
||||
|
||||
|
||||
|
||||
STATIC bool match_pars(fm,act)
|
||||
formal_p fm;
|
||||
actual_p act;
|
||||
{
|
||||
/* Check if every actual parameter has the same
|
||||
* size as its corresponding formal. If not, the
|
||||
* actual parameters should not be expanded in line.
|
||||
*/
|
||||
|
||||
while (act != (actual_p) 0) {
|
||||
if (fm == (formal_p) 0 || tsize(fm->f_type) != act->ac_size) {
|
||||
return FALSE;
|
||||
}
|
||||
act = act->ac_next;
|
||||
fm = fm->f_next;
|
||||
}
|
||||
return (fm == (formal_p) 0 ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
|
||||
STATIC bool change_act(p,act)
|
||||
proc_p p;
|
||||
actual_p act;
|
||||
{
|
||||
/* See if a call to p migth change any of the
|
||||
* operands of the actual parameter expression.
|
||||
* If the parameter is to be expanded in line,
|
||||
* we must be sure its value does not depend
|
||||
* on the point in the program where it is
|
||||
* evaluated.
|
||||
*/
|
||||
|
||||
line_p l;
|
||||
|
||||
for (l = act->ac_exp; l != (line_p) 0; l = l->l_next) {
|
||||
switch(INSTR(l)) {
|
||||
case op_lil:
|
||||
case op_lof:
|
||||
case op_loi:
|
||||
case op_los:
|
||||
case op_ldf:
|
||||
return TRUE;
|
||||
/* assume worst case */
|
||||
case op_lol:
|
||||
case op_ldl:
|
||||
if (CHANGE_INDIR(p)) {
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
case op_loe:
|
||||
case op_lde:
|
||||
if (CHANGE_INDIR(p) || CHANGE_EXT(p)) {
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool is_simple(expr)
|
||||
line_p expr;
|
||||
{
|
||||
/* See if expr is something simple, i.e. a constant or
|
||||
* a variable. So the expression must consist of
|
||||
* only one instruction.
|
||||
*/
|
||||
|
||||
|
||||
if (expr->l_next == (line_p) 0) {
|
||||
switch(INSTR(expr)) {
|
||||
case op_loc:
|
||||
case op_ldc:
|
||||
case op_lol:
|
||||
case op_ldl:
|
||||
case op_loe:
|
||||
case op_lde:
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool too_expensive(fm,act)
|
||||
formal_p fm;
|
||||
actual_p act;
|
||||
{
|
||||
/* If the formal parameter is used often and the
|
||||
* actual parameter is not something simple
|
||||
* (i.e. an expression, not a constant or variable)
|
||||
* it may be too expensive too expand the parameter
|
||||
* in line.
|
||||
*/
|
||||
|
||||
return (OFTEN_USED(fm) && !is_simple(act->ac_exp));
|
||||
}
|
||||
bool anal_params(c)
|
||||
call_p c;
|
||||
{
|
||||
/* Determine which of the actual parameters of a
|
||||
* call may be expanded in line.
|
||||
*/
|
||||
|
||||
proc_p p;
|
||||
actual_p act;
|
||||
formal_p form;
|
||||
int inlpars = 0;
|
||||
|
||||
p = c->cl_proc; /* the called procedure */
|
||||
if (!match_pars(p->P_FORMALS, c->cl_actuals)) return FALSE;
|
||||
if (!INLINE_PARS(p)) {
|
||||
for (act = c->cl_actuals; act != (actual_p) 0;
|
||||
act = act->ac_next) {
|
||||
NOT_INLINE(act);
|
||||
}
|
||||
return TRUE; /* "# of inline pars." field in cl_flags remains 0 */
|
||||
}
|
||||
for (act = c->cl_actuals, form = p->P_FORMALS; act != (actual_p) 0;
|
||||
act = act->ac_next, form = form->f_next) {
|
||||
if (form->f_flags & FF_BAD ||
|
||||
change_act(p,act) || too_expensive(form,act)) {
|
||||
NOT_INLINE(act);
|
||||
} else {
|
||||
INLINE(act);
|
||||
inlpars++;
|
||||
}
|
||||
}
|
||||
if (inlpars > 15) inlpars = 15; /* We've only got 4 bits! */
|
||||
c->cl_flags |= inlpars; /* number of inline parameters */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
STATIC short space_saved(c)
|
||||
call_p c;
|
||||
{
|
||||
/* When a call gets expanded in line, the total size of the
|
||||
* code usually gets incremented, because we have to
|
||||
* duplicate the text of the called routine. However, we save
|
||||
* ourselves a CAL instruction and possibly anASP instruction
|
||||
* (if the called procedure has parameters). Moreover, if we
|
||||
* can put some parameters in line, we don't have to push
|
||||
* their results on the stack before doing the call, so we
|
||||
* save some code here too. The routine estimates the amount of
|
||||
* code saved, expressed in number of EM instructions.
|
||||
*/
|
||||
|
||||
return (1 + (c->cl_flags & CLF_INLPARS) + (c->cl_proc->p_nrformals>0));
|
||||
}
|
||||
|
||||
STATIC short param_score(c)
|
||||
call_p c;
|
||||
{
|
||||
/* If a call has an inline parameter that is a constant,
|
||||
* chances are high that other optimization techniques
|
||||
* can do further optimizations, especially if the constant
|
||||
* happens to be "0". So the call gets extra points for this.
|
||||
*/
|
||||
|
||||
register actual_p act;
|
||||
line_p l;
|
||||
short score = 0;
|
||||
|
||||
for (act = c->cl_actuals; act != (actual_p) 0; act = act->ac_next) {
|
||||
if (act->ac_inl) {
|
||||
l = act->ac_exp;
|
||||
if (l->l_next == (line_p) 0 &&
|
||||
(INSTR(l) == op_loc || INSTR(l) == op_ldc)) {
|
||||
score += (off_set(l) == (offset) 0 ? 2 : 1);
|
||||
/* 0's count for two! */
|
||||
}
|
||||
}
|
||||
}
|
||||
return score;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
assign_ratio(c)
|
||||
call_p c;
|
||||
{
|
||||
/* This routine is one of the most important ones
|
||||
* of the inline substitution phase. It assigns a number
|
||||
* (a 'ratio') to a call, indicating how desirable
|
||||
* it is to expand the call in line.
|
||||
* Currently, a very simplified straightforward heuristic
|
||||
* is used.
|
||||
*/
|
||||
|
||||
short ll, loopfact, ratio;
|
||||
|
||||
ll = c->cl_proc->P_SIZE - space_saved(c);
|
||||
if (ll <= 0) ll = 1;
|
||||
ratio = 1000 / ll;
|
||||
if (ratio == 0) ratio = 1;
|
||||
/* Add points if the called procedure falls through
|
||||
* it's end (no BRA needed) or has formal parameters
|
||||
* (ASP can be deleted).
|
||||
*/
|
||||
if (c->cl_proc->p_flags2 & PF_FALLTHROUGH) {
|
||||
ratio += 10;
|
||||
}
|
||||
if (c->cl_proc->p_nrformals > 0) {
|
||||
ratio += 10;
|
||||
}
|
||||
if (c->cl_caller->p_localbytes == 0) {
|
||||
ratio -= 10;
|
||||
}
|
||||
ratio += (10 *param_score(c));
|
||||
/* Extra points for constants as parameters */
|
||||
if (ratio <= 0) ratio = 1;
|
||||
ll = c->cl_looplevel+1;
|
||||
if (ll == 1 && !IS_CALLED_IN_LOOP(c->cl_caller)) ll = 0;
|
||||
/* If the call is not in a loop and the called proc. is never called
|
||||
* in a loop, ll is set to 0.
|
||||
*/
|
||||
loopfact = (ll > 3 ? 10 : ll*ll);
|
||||
ratio *= loopfact;
|
||||
if (c->cl_flags & CLF_FIRM) {
|
||||
ratio = 2*ratio;
|
||||
}
|
||||
c->cl_ratio = ratio;
|
||||
}
|
||||
|
||||
|
||||
call_p abstract(c)
|
||||
call_p c;
|
||||
{
|
||||
/* Abstract information from the call that is essential
|
||||
* for choosing the calls that will be expanded.
|
||||
* Put the information is an 'abstracted call'.
|
||||
*/
|
||||
|
||||
call_p a;
|
||||
|
||||
a = newcall();
|
||||
a->cl_caller = c->cl_caller;
|
||||
a->cl_id = c->cl_id;
|
||||
a->cl_proc = c->cl_proc;
|
||||
a->cl_looplevel = c->cl_looplevel;
|
||||
a->cl_ratio = c->cl_ratio;
|
||||
a->cl_flags = c->cl_flags;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC adjust_counts(callee,ccf)
|
||||
proc_p callee;
|
||||
FILE *ccf;
|
||||
{
|
||||
/* A call to callee is expanded in line;
|
||||
* the text of callee is not removed, so
|
||||
* every proc called by callee gets its
|
||||
* P_NRCALLED field incremented.
|
||||
*/
|
||||
|
||||
calcnt_p cc, head;
|
||||
|
||||
head = getcc(ccf,callee); /* get calcnt info of called proc */
|
||||
for (cc = head; cc != (calcnt_p) 0; cc = cc->cc_next) {
|
||||
cc->cc_proc->P_NRCALLED += cc->cc_count;
|
||||
}
|
||||
remcc(head); /* remove calcnt info */
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool is_dispensable(callee,ccf)
|
||||
proc_p callee;
|
||||
FILE *ccf;
|
||||
{
|
||||
/* A call to callee is expanded in line.
|
||||
* Decrement its P_NRCALLED field and see if
|
||||
* it can now be removed because it is no
|
||||
* longer called. Procedures that ever have
|
||||
* their address taken (via LPI) will never
|
||||
* be removed, as they might be called indirectly.
|
||||
*/
|
||||
|
||||
if ((--callee->P_NRCALLED) == 0 &&
|
||||
(callee->p_flags1 & PF_LPI) == 0) {
|
||||
DISPENSABLE(callee);
|
||||
OUTTRACE("procedure %d can be removed",callee->p_id);
|
||||
#ifdef VERBOSE
|
||||
Spremoved++;
|
||||
#endif
|
||||
return TRUE;
|
||||
} else {
|
||||
adjust_counts(callee,ccf);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
STATIC call_p nested_calls(a)
|
||||
call_p a;
|
||||
{
|
||||
/* Get a list of all calls that will appear in the
|
||||
* EM text if the call 'a' is expanded in line.
|
||||
* These are the calls in the P_CALS list of the
|
||||
* called procedure.
|
||||
*/
|
||||
|
||||
call_p c, cp, head, *cpp;
|
||||
|
||||
head = (call_p) 0;
|
||||
cpp = &head;
|
||||
for (c = a->cl_proc->P_CALS; c != (call_p) 0; c = c->cl_cdr) {
|
||||
cp = abstract(c);
|
||||
cp->cl_looplevel += a->cl_looplevel;
|
||||
cp->cl_flags = (byte) 0;
|
||||
if (a->cl_flags & CLF_FIRM) {
|
||||
cp->cl_flags |= CLF_FIRM;
|
||||
}
|
||||
assign_ratio(cp);
|
||||
*cpp = cp;
|
||||
cpp = &cp->cl_cdr;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
STATIC call_p find_origin(c)
|
||||
call_p c;
|
||||
{
|
||||
/* c is a nested call. Find the original call.
|
||||
* This origional must be in the P_CALS list
|
||||
* of the calling procedure.
|
||||
*/
|
||||
|
||||
register call_p x;
|
||||
|
||||
for (x = c->cl_caller->P_CALS; x != (call_p) 0; x = x->cl_cdr) {
|
||||
if (x->cl_id == c->cl_id) return x;
|
||||
}
|
||||
assert(FALSE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC selected(a)
|
||||
call_p a;
|
||||
{
|
||||
/* The call a is selected for in line expansion.
|
||||
* Mark the call as being selected and get the
|
||||
* calls nested in it; these will be candidates
|
||||
* too now.
|
||||
*/
|
||||
|
||||
SELECTED(a);
|
||||
EVER_EXPANDED(find_origin(a));
|
||||
a->cl_car = nested_calls(a);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
STATIC compare(x,best,space)
|
||||
call_p x, *best;
|
||||
short space;
|
||||
{
|
||||
/* See if x is better than the current best choice */
|
||||
|
||||
if (x != (call_p) 0 && !IS_CHANGED(x->cl_proc) &&
|
||||
x->cl_proc->P_SIZE - space_saved(x) <= space) {
|
||||
if ((*best == (call_p) 0 && x->cl_ratio != 0) ||
|
||||
(*best != (call_p) 0 && x->cl_ratio > (*best)->cl_ratio )) {
|
||||
*best = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
STATIC call_p best_one(list,space)
|
||||
call_p list;
|
||||
short space;
|
||||
{
|
||||
/* Find the best candidate of the list
|
||||
* that has not already been selected. The
|
||||
* candidate must fit in the given space.
|
||||
* We look in the cdr as well as in the car
|
||||
* direction.
|
||||
*/
|
||||
|
||||
call_p best = (call_p) 0;
|
||||
call_p x,c;
|
||||
|
||||
for (c = list; c != (call_p) 0; c = c->cl_cdr) {
|
||||
if (IS_SELECTED(c)) {
|
||||
compare(best_one(c->cl_car,space),&best,space);
|
||||
} else {
|
||||
compare(c,&best,space);
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC singles(cals)
|
||||
call_p cals;
|
||||
{
|
||||
/* If a procedure is only called once, this call
|
||||
* will be expanded in line, because it costs
|
||||
* no extra space.
|
||||
*/
|
||||
|
||||
call_p c;
|
||||
|
||||
for (c = cals; c != (call_p) 0; c = c->cl_cdr) {
|
||||
if (IS_SELECTED(c)) {
|
||||
singles(c->cl_car);
|
||||
} else {
|
||||
if (c->cl_proc->P_NRCALLED == 1 &&
|
||||
!IS_CHANGED(c->cl_proc) &&
|
||||
(c->cl_proc->p_flags1 & PF_LPI) == 0) {
|
||||
c->cl_proc->P_NRCALLED = 0;
|
||||
SELECTED(c);
|
||||
EVER_EXPANDED(find_origin(c));
|
||||
DISPENSABLE(c->cl_proc);
|
||||
CHANGED(c->cl_caller);
|
||||
OUTTRACE("procedure %d can be removed",
|
||||
c->cl_proc->p_id);
|
||||
#ifdef VERBOSE
|
||||
Spremoved++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC single_calls(proclist)
|
||||
proc_p proclist;
|
||||
{
|
||||
proc_p p;
|
||||
|
||||
for (p = proclist; p != (proc_p) 0; p = p->p_next) {
|
||||
if (!BIG_CALLER(p) && !IS_DISPENSABLE(p)) {
|
||||
/* Calls appearing in a large procedure or in
|
||||
* a procedure that was already eliminated
|
||||
* are not considered.
|
||||
*/
|
||||
singles(p->P_CALS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
select_calls(proclist,ccf,space)
|
||||
proc_p proclist;
|
||||
FILE *ccf;
|
||||
short space ;
|
||||
{
|
||||
/* Select all calls that are to be expanded in line. */
|
||||
|
||||
proc_p p,chp;
|
||||
call_p best, x;
|
||||
|
||||
for (;;) {
|
||||
best = (call_p) 0;
|
||||
chp = (proc_p) 0; /* the changed procedure */
|
||||
for (p = proclist; p != (proc_p) 0; p = p->p_next) {
|
||||
if (!BIG_CALLER(p) && !IS_DISPENSABLE(p)) {
|
||||
/* Calls appearing in a large procedure or in
|
||||
* a procedure that was already eliminated
|
||||
* are not considered.
|
||||
*/
|
||||
x = best_one(p->P_CALS,space);
|
||||
compare(x,&best,space);
|
||||
if (x == best) chp = p;
|
||||
}
|
||||
}
|
||||
if (best == (call_p) 0) break;
|
||||
if (!is_dispensable(best->cl_proc,ccf)) {
|
||||
space -= (best->cl_proc->P_SIZE - space_saved(best));
|
||||
}
|
||||
selected(best);
|
||||
CHANGED(chp);
|
||||
}
|
||||
single_calls(proclist);
|
||||
#ifdef VERBOSE
|
||||
Sstat(proclist,space);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
STATIC nonnested_calls(cfile)
|
||||
FILE *cfile;
|
||||
{
|
||||
register call_p c,a;
|
||||
|
||||
while((c = getcall(cfile)) != (call_p) 0) {
|
||||
/* find the call in the call list of the caller */
|
||||
for (a = c->cl_caller->P_CALS;
|
||||
a != (call_p) 0 && c->cl_id != a->cl_id; a = a->cl_cdr);
|
||||
assert(a != (call_p) 0 && a->cl_proc == c->cl_proc);
|
||||
if (IS_EVER_EXPANDED(a)) {
|
||||
a->cl_actuals = c->cl_actuals;
|
||||
c->cl_actuals = (actual_p) 0;
|
||||
}
|
||||
rem_call(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC copy_pars(src,dest)
|
||||
call_p src, dest;
|
||||
{
|
||||
/* Copy the actual parameters of src to dest. */
|
||||
|
||||
actual_p as,ad, *app;
|
||||
|
||||
app = &dest->cl_actuals;
|
||||
for (as = src->cl_actuals; as != (actual_p) 0; as = as->ac_next) {
|
||||
ad = newactual();
|
||||
ad->ac_exp = copy_expr(as->ac_exp);
|
||||
ad->ac_size = as->ac_size;
|
||||
ad->ac_inl = as->ac_inl;
|
||||
*app = ad;
|
||||
app = &ad->ac_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC nest_pars(cals)
|
||||
call_p cals;
|
||||
{
|
||||
/* Recursive auxiliary procedure of add_actuals. */
|
||||
|
||||
call_p c,org;
|
||||
|
||||
for (c = cals; c != (call_p) 0; c = c->cl_cdr) {
|
||||
if (IS_SELECTED(c)) {
|
||||
org = find_origin(c);
|
||||
copy_pars(org,c);
|
||||
nest_pars(c->cl_car);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
add_actuals(proclist,cfile)
|
||||
proc_p proclist;
|
||||
FILE *cfile;
|
||||
{
|
||||
/* Fetch the actual parameters of all selected calls.
|
||||
* For all non-nested calls (i.e. those calls that
|
||||
* appeared originally in the EM text), we get the
|
||||
* parameters from the cal-file.
|
||||
* For nested calls (i.e. calls
|
||||
* that are a result of in line substitution) we
|
||||
* get the parameters from the original call.
|
||||
*/
|
||||
|
||||
proc_p p;
|
||||
call_p a;
|
||||
|
||||
nonnested_calls(cfile);
|
||||
for (p = proclist; p != (proc_p) 0; p = p->p_next) {
|
||||
for (a = p->P_CALS; a != (call_p) 0; a = a->cl_cdr) {
|
||||
nest_pars(a->cl_car);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC clean(cals)
|
||||
call_p *cals;
|
||||
{
|
||||
call_p c,next,*cpp;
|
||||
|
||||
/* Recursive auxiliary routine of cleancals */
|
||||
|
||||
cpp = cals;
|
||||
for (c = *cpp; c != (call_p) 0; c = next) {
|
||||
next = c->cl_cdr;
|
||||
if (IS_SELECTED(c)) {
|
||||
clean(&c->cl_car);
|
||||
cpp = &c->cl_cdr;
|
||||
} else {
|
||||
assert(c->cl_car == (call_p) 0);
|
||||
oldcall(c);
|
||||
*cpp = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cleancals(proclist)
|
||||
proc_p proclist;
|
||||
{
|
||||
/* Remove all calls in the P_CALS list of p
|
||||
* that were not selected for in line expansion.
|
||||
*/
|
||||
|
||||
register proc_p p;
|
||||
|
||||
for (p = proclist; p != (proc_p) 0; p = p->p_next) {
|
||||
clean(&p->P_CALS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
append_abstract(a,p)
|
||||
call_p a;
|
||||
proc_p p;
|
||||
{
|
||||
/* Append an abstract of a call-descriptor to
|
||||
* the call-list of procedure p.
|
||||
*/
|
||||
|
||||
call_p c;
|
||||
|
||||
if (p->P_CALS == (call_p) 0) {
|
||||
p->P_CALS = a;
|
||||
} else {
|
||||
for (c = p->P_CALS; c->cl_cdr != (call_p) 0; c = c->cl_cdr);
|
||||
c->cl_cdr = a;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef VERBOSE
|
||||
|
||||
/* At the end, we traverse the entire call-list, to see why the
|
||||
* remaining calls were not expanded inline.
|
||||
*/
|
||||
|
||||
|
||||
Sstatist(list,space)
|
||||
call_p list;
|
||||
short space;
|
||||
{
|
||||
call_p c;
|
||||
|
||||
for (c = list; c != (call_p) 0; c = c->cl_cdr) {
|
||||
if (IS_SELECTED(c)) {
|
||||
Sstatist(c->cl_car,space);
|
||||
} else {
|
||||
if (IS_CHANGED(c->cl_proc)) Schangedcallee++;
|
||||
else if (BIG_PROC(c->cl_proc)) Sbigcallee++;
|
||||
else if (c->cl_proc->P_SIZE > space) Sspace++;
|
||||
else if (c->cl_ratio == 0) Szeroratio++;
|
||||
else assert(FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Sstat(proclist,space)
|
||||
proc_p proclist;
|
||||
short space;
|
||||
{
|
||||
proc_p p;
|
||||
|
||||
for (p = proclist; p != (proc_p) 0; p = p->p_next) {
|
||||
if (BIG_CALLER(p)) Sbig_caller++;
|
||||
else if (IS_DISPENSABLE(p)) Sdispensable++;
|
||||
else Sstatist(p->P_CALS,space);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,38 +0,0 @@
|
||||
extern bool anal_params(); /* (call_p c)
|
||||
* See which parameters of the call
|
||||
* may be expanded in line.
|
||||
* If the formals and actuals do not
|
||||
* match, return FALSE
|
||||
*/
|
||||
extern assign_ratio(); /* (call_p c)
|
||||
* Assigna ratio number to the call,
|
||||
* indicating how desirable it is to
|
||||
* expand the call in line.
|
||||
*/
|
||||
extern call_p abstract(); /* (call_p c)
|
||||
* Abstract essential information from
|
||||
* the call.
|
||||
*/
|
||||
extern select_calls(); /* (call_p alist; FILE *ccf;short space)
|
||||
* Select the best calls to be expanded.
|
||||
* Every procedure gets a list of
|
||||
* selected calls appearing in it.
|
||||
* space is the amount of space that the
|
||||
* program is allowed to grow
|
||||
* (expressed in number of EM instructions).
|
||||
*/
|
||||
extern cleancals(); /* (proc_p plist)
|
||||
* Remove all calls that were not selected.
|
||||
*/
|
||||
extern add_actuals(); /* (proc_p plist; FILE *cfile)
|
||||
* Add the actual parameters to the descriptor abstracts
|
||||
* of the selected calls.
|
||||
* the calfile contains the full descriptors of all
|
||||
* calls.
|
||||
* These two are combined to yield a file of full
|
||||
* descriptors of the selected calls.
|
||||
*/
|
||||
extern append_abstract(); /* (call_p a; proc_p p)
|
||||
* Put the call-descriptor abstract in the p_cals
|
||||
* list of p.
|
||||
*/
|
||||
@@ -1,63 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 3 _ A U X . C
|
||||
*/
|
||||
|
||||
|
||||
#include "../share/types.h"
|
||||
#include "il.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/global.h"
|
||||
#include "il_aux.h"
|
||||
#include "il3_aux.h"
|
||||
|
||||
|
||||
|
||||
line_p last_line(lines)
|
||||
line_p lines;
|
||||
{
|
||||
/* Determine the last line of a list */
|
||||
|
||||
register line_p l;
|
||||
|
||||
assert (lines != (line_p) 0);
|
||||
for (l = lines; l->l_next != (line_p) 0; l = l->l_next);
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
app_list(list,l)
|
||||
line_p list,l;
|
||||
{
|
||||
/* Append the list after line l */
|
||||
|
||||
line_p llast;
|
||||
|
||||
assert(l != (line_p) 0);
|
||||
assert (list != (line_p) 0);
|
||||
llast = last_line(list);
|
||||
llast->l_next = l->l_next;
|
||||
if (l->l_next != (line_p) 0) {
|
||||
PREV(l->l_next) = llast;
|
||||
}
|
||||
l->l_next = list;
|
||||
PREV(list) = l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
rem_line(l)
|
||||
line_p l;
|
||||
{
|
||||
/* Remove a line from the list */
|
||||
|
||||
if (PREV(l) != (line_p) 0) {
|
||||
PREV(l)->l_next = l->l_next;
|
||||
}
|
||||
if (l->l_next != (line_p) 0) {
|
||||
PREV(l->l_next) = PREV(l);
|
||||
}
|
||||
oldline(l);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 3 _ A U X . H
|
||||
*/
|
||||
|
||||
extern line_p last_line(); /* (line_p list)
|
||||
* Find the last line of a list.
|
||||
*/
|
||||
extern app_list(); /* (line_p list,l)
|
||||
* Put list after l
|
||||
*/
|
||||
extern rem_line(); /* (line_p l)
|
||||
* Remove a line from a (doubly linked)
|
||||
* list.
|
||||
*/
|
||||
@@ -1,584 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 3 _ C H A N G E . C
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "il.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/def.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_mes.h"
|
||||
#include "../share/get.h"
|
||||
#include "../share/put.h"
|
||||
#include "il_aux.h"
|
||||
#include "il3_change.h"
|
||||
#include "il3_aux.h"
|
||||
|
||||
/* chg_callseq */
|
||||
|
||||
|
||||
|
||||
|
||||
STATIC line_p par_expr(l,expr)
|
||||
line_p l, expr;
|
||||
{
|
||||
/* Find the first line of the expression of which
|
||||
* l is the last line; expr contains a pointer
|
||||
* to a copy of that expression; effectively we
|
||||
* just have to tally lines.
|
||||
*/
|
||||
|
||||
line_p lnp;
|
||||
|
||||
for (lnp = expr->l_next; lnp != (line_p) 0; lnp = lnp->l_next) {
|
||||
assert(l != (line_p) 0);
|
||||
l = PREV(l);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC rem_text(l1,l2)
|
||||
line_p l1,l2;
|
||||
{
|
||||
/* Remove the lines from l1 to l2 (inclusive) */
|
||||
|
||||
line_p l, lstop;
|
||||
l = PREV(l1);
|
||||
lstop = l2->l_next;
|
||||
while (l->l_next != lstop) {
|
||||
rem_line(l->l_next);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC store_tmp(p,l,size)
|
||||
proc_p p;
|
||||
line_p l;
|
||||
offset size;
|
||||
{
|
||||
/* Emit code to store a 'size'-byte value in a new
|
||||
* temporary local variable in the stack frame of p.
|
||||
* Put this code after line l.
|
||||
*/
|
||||
|
||||
line_p lnp;
|
||||
|
||||
lnp = int_line(tmplocal(p,size)); /* line with operand temp. */
|
||||
if (size == ws) {
|
||||
lnp->l_instr = op_stl; /* STL temp. */
|
||||
} else {
|
||||
if (size == 2*ws) {
|
||||
lnp->l_instr = op_sdl; /* SDL temp. */
|
||||
} else {
|
||||
/* emit 'LAL temp; STI size' */
|
||||
lnp->l_instr = op_lal;
|
||||
appnd_line(lnp,l);
|
||||
l = lnp;
|
||||
assert ((short) size == size);
|
||||
lnp = newline(OPSHORT);
|
||||
SHORT(lnp) = size;
|
||||
lnp->l_instr = op_sti;
|
||||
}
|
||||
}
|
||||
appnd_line(lnp,l);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC chg_actuals(c,cal)
|
||||
call_p c;
|
||||
line_p cal;
|
||||
{
|
||||
/* Change the actual parameter expressions of the call. */
|
||||
|
||||
actual_p act;
|
||||
line_p llast,lfirst,l;
|
||||
|
||||
llast = PREV(cal);
|
||||
for (act = c->cl_actuals; act != (actual_p) 0; act = act->ac_next) {
|
||||
lfirst = par_expr(llast,act->ac_exp);
|
||||
/* the code from lfirst to llast is a parameter expression */
|
||||
if (act->ac_inl) {
|
||||
/* in line parameter; remove it */
|
||||
l = llast;
|
||||
llast = PREV(lfirst);
|
||||
rem_text(lfirst,l);
|
||||
} else {
|
||||
store_tmp(curproc,llast,act->ac_size);
|
||||
/* put a "STL tmp" -like instruction after the code */
|
||||
llast = PREV(lfirst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC rm_callpart(c,cal)
|
||||
call_p c;
|
||||
line_p cal;
|
||||
{
|
||||
/* Remove the call part, consisting of a CAL,
|
||||
* an optional ASP and an optional LFR.
|
||||
*/
|
||||
|
||||
line_p l;
|
||||
|
||||
l= PREV(cal);
|
||||
rem_line(cal);
|
||||
if (c->cl_proc->p_nrformals > 0) {
|
||||
/* called procedure has parameters */
|
||||
assert (INSTR(l->l_next) == op_asp);
|
||||
rem_line(l->l_next);
|
||||
}
|
||||
if (INSTR(l->l_next) == op_lfr) {
|
||||
rem_line(l->l_next);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
chg_callseq(c,cal,l_out)
|
||||
call_p c;
|
||||
line_p cal,*l_out;
|
||||
{
|
||||
/* Change the calling sequence. The actual parameter
|
||||
* expressions are changed (in line parameters are
|
||||
* removed, all other ones now store their result
|
||||
* in a temporary local of the caller);
|
||||
* the sequence "CAL ; ASP ; LFR" is removed.
|
||||
*/
|
||||
|
||||
|
||||
chg_actuals(c,cal);
|
||||
*l_out = PREV(cal); /* last instr. of new parameter part */
|
||||
rm_callpart(c,cal);
|
||||
}
|
||||
|
||||
|
||||
/* make_label */
|
||||
|
||||
line_p make_label(l,p)
|
||||
line_p l;
|
||||
proc_p p;
|
||||
{
|
||||
/* Make sure that the instruction after l
|
||||
* contains an instruction label. If this is
|
||||
* not already the case, create a new label.
|
||||
*/
|
||||
|
||||
line_p lab;
|
||||
|
||||
if (l->l_next != (line_p) 0 && INSTR(l->l_next) == op_lab) {
|
||||
return l->l_next;
|
||||
}
|
||||
lab = newline(OPINSTRLAB);
|
||||
lab->l_instr = op_lab;
|
||||
p->p_nrlabels++;
|
||||
INSTRLAB(lab) = p->p_nrlabels;
|
||||
appnd_line(lab,l);
|
||||
return lab;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* modify */
|
||||
|
||||
STATIC act_info(off,acts,ab_off,act_out,off_out)
|
||||
offset off, ab_off, *off_out;
|
||||
actual_p acts, *act_out;
|
||||
{
|
||||
/* Find the actual parameter that corresponds to
|
||||
* the formal parameter with the given offset.
|
||||
* Return it via act_out. If the actual is not
|
||||
* an in-line actual, determine which temporary
|
||||
* local is used for it; return the offset of that
|
||||
* local via off_out.
|
||||
*/
|
||||
|
||||
offset sum = 0, tmp = 0;
|
||||
actual_p act;
|
||||
|
||||
for (act = acts; act != (actual_p) 0; act = act->ac_next) {
|
||||
if (!act->ac_inl) {
|
||||
tmp -= act->ac_size;
|
||||
}
|
||||
if (sum >= off) {
|
||||
/* found */
|
||||
*act_out = act;
|
||||
if (!act->ac_inl) {
|
||||
*off_out = tmp + sum - off + ab_off;
|
||||
} else {
|
||||
assert (sum == off);
|
||||
}
|
||||
return;
|
||||
}
|
||||
sum += act->ac_size;
|
||||
}
|
||||
assert(FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC store_off(off,l)
|
||||
offset off;
|
||||
line_p l;
|
||||
{
|
||||
if (TYPE(l) == OPSHORT) {
|
||||
assert ((short) off == off);
|
||||
SHORT(l) = (short) off;
|
||||
} else {
|
||||
OFFSET(l) = off;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC inl_actual(l,expr)
|
||||
line_p l, expr;
|
||||
{
|
||||
/* Expand an actual parameter in line.
|
||||
* A LOL or LDL instruction is replaced
|
||||
* by an expression.
|
||||
* A SIL or LIL is replaced by the expression
|
||||
* followed by a STI or LOI.
|
||||
*/
|
||||
|
||||
line_p e, lnp, s;
|
||||
short instr;
|
||||
|
||||
instr = INSTR(l);
|
||||
assert(expr != (line_p) 0);
|
||||
e = copy_expr(expr); /* make a copy of expr. */
|
||||
if (instr == op_sil || instr == op_lil) {
|
||||
s = int_line((offset) ws);
|
||||
s->l_instr = (instr == op_sil ? op_sti : op_loi);
|
||||
appnd_line(s,last_line(e));
|
||||
} else {
|
||||
assert(instr == op_lol || instr == op_ldl);
|
||||
}
|
||||
lnp = PREV(l);
|
||||
rem_line(l);
|
||||
app_list(e,lnp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC localref(l,c,ab_off,lb_off)
|
||||
line_p l;
|
||||
call_p c;
|
||||
offset ab_off, lb_off;
|
||||
{
|
||||
/* Change a reference to a local variable or parameter
|
||||
* of the called procedure.
|
||||
*/
|
||||
|
||||
offset off, tmpoff;
|
||||
actual_p act;
|
||||
|
||||
off = off_set(l);
|
||||
if (off < 0) {
|
||||
/* local variable, only the offset changes */
|
||||
store_off(lb_off + off,l);
|
||||
} else {
|
||||
act_info(off,c->cl_actuals,ab_off,&act,&tmpoff); /* find actual */
|
||||
if (act->ac_inl) {
|
||||
/* inline actual parameter */
|
||||
inl_actual(l,act->ac_exp);
|
||||
} else {
|
||||
/* parameter stored in temporary local */
|
||||
store_off(tmpoff,l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC chg_mes(l,c,ab_off,lb_off)
|
||||
line_p l;
|
||||
call_p c;
|
||||
offset ab_off, lb_off;
|
||||
{
|
||||
/* The register messages of the called procedure
|
||||
* must be changed. If the message applies to a
|
||||
* local variable or to a parameter that is not
|
||||
* expanded in line, the offset of the variable
|
||||
* is changed; else the entire message is deleted.
|
||||
*/
|
||||
|
||||
offset off, tmpoff;
|
||||
actual_p act;
|
||||
arg_p arg;
|
||||
|
||||
arg = ARG(l);
|
||||
switch ((int) arg->a_a.a_offset) {
|
||||
case ms_reg:
|
||||
if ((arg = arg->a_next) != (arg_p) 0) {
|
||||
/* "mes 3" without further argument is not changed */
|
||||
off = arg->a_a.a_offset;
|
||||
if (off < 0) {
|
||||
/* local variable */
|
||||
arg->a_a.a_offset += lb_off;
|
||||
} else {
|
||||
act_info(off,c->cl_actuals,ab_off,&act,&tmpoff);
|
||||
if (act->ac_inl) {
|
||||
/* in line actual */
|
||||
rem_line(l);
|
||||
} else {
|
||||
arg->a_a.a_offset = tmpoff;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ms_par:
|
||||
rem_line(l);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC chg_ret(l,c,lab)
|
||||
line_p l,lab;
|
||||
call_p c;
|
||||
{
|
||||
/* Change the RET instruction appearing in the
|
||||
* expanded text of a call. If the called procedure
|
||||
* falls through, the RET is just deleted; else it
|
||||
* is replaced by a branch.
|
||||
*/
|
||||
|
||||
line_p lnp, bra;
|
||||
|
||||
lnp = PREV(l);
|
||||
rem_line(l);
|
||||
if (!FALLTHROUGH(c->cl_proc)) {
|
||||
bra = newline(OPINSTRLAB);
|
||||
bra->l_instr = op_bra;
|
||||
INSTRLAB(bra) = INSTRLAB(lab);
|
||||
appnd_line(bra,lnp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC mod_instr(l,c,lab,ab_off,lb_off,lab_off)
|
||||
line_p l,lab;
|
||||
call_p c;
|
||||
offset ab_off,lb_off;
|
||||
int lab_off;
|
||||
{
|
||||
if (TYPE(l) == OPINSTRLAB) {
|
||||
INSTRLAB(l) += lab_off;
|
||||
} else {
|
||||
switch(INSTR(l)) {
|
||||
case op_stl:
|
||||
case op_inl:
|
||||
case op_del:
|
||||
case op_zrl:
|
||||
case op_sdl:
|
||||
case op_lol:
|
||||
case op_ldl:
|
||||
case op_sil:
|
||||
case op_lil:
|
||||
case op_lal:
|
||||
localref(l,c,ab_off,lb_off);
|
||||
break;
|
||||
case op_ret:
|
||||
chg_ret(l,c,lab);
|
||||
break;
|
||||
case ps_pro:
|
||||
case ps_end:
|
||||
case ps_sym:
|
||||
case ps_hol:
|
||||
case ps_bss:
|
||||
case ps_con:
|
||||
case ps_rom:
|
||||
rem_line(l);
|
||||
break;
|
||||
case ps_mes:
|
||||
chg_mes(l,c,ab_off,lb_off);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
modify(text,c,lab,ab_off,lb_off,lab_off)
|
||||
line_p text,lab;
|
||||
call_p c;
|
||||
offset ab_off,lb_off;
|
||||
int lab_off;
|
||||
{
|
||||
/* Modify the EM text of the called procedure.
|
||||
* References to locals and parameters are
|
||||
* changed; RETs are either deleted or replaced
|
||||
* by a BRA to the given label; PRO and END pseudos
|
||||
* are removed; instruction labels are changed, in
|
||||
* order to make them different from any label used
|
||||
* by the caller; some messages need to be changed too.
|
||||
* Note that the first line of the text is a dummy instruction.
|
||||
*/
|
||||
|
||||
register line_p l;
|
||||
line_p next;
|
||||
|
||||
for (l = text->l_next; l != (line_p) 0; l = next) {
|
||||
next = l->l_next;
|
||||
/* This is rather tricky. An instruction like
|
||||
* LOL 2 may be replaced by a number of instructions
|
||||
* (if the parameter is expanded in line). This inserted
|
||||
* code, however, should not be modified!
|
||||
*/
|
||||
mod_instr(l,c,lab,ab_off,lb_off,lab_off);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
mod_actuals(nc,c,lab,ab_off,lb_off,lab_off)
|
||||
call_p nc,c;
|
||||
line_p lab;
|
||||
offset ab_off,lb_off;
|
||||
int lab_off;
|
||||
{
|
||||
actual_p act;
|
||||
line_p l, next, dum;
|
||||
|
||||
dum = newline(OPNO);
|
||||
PREV(dum) = (line_p) 0;
|
||||
for (act = nc->cl_actuals; act != (actual_p) 0; act = act->ac_next) {
|
||||
l = act->ac_exp;
|
||||
assert(l != (line_p) 0);
|
||||
/* Insert a dummy instruction before l */
|
||||
dum->l_next = l;
|
||||
PREV(l) = dum;
|
||||
while(l != (line_p) 0) {
|
||||
next = l->l_next;
|
||||
mod_instr(l,c,lab,ab_off,lb_off,lab_off);
|
||||
l = next;
|
||||
}
|
||||
act->ac_exp = dum->l_next;
|
||||
PREV(dum->l_next) = (line_p) 0;
|
||||
}
|
||||
oldline(dum);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* insert */
|
||||
|
||||
STATIC line_p first_nonpseudo(l)
|
||||
line_p l;
|
||||
{
|
||||
/* Find the first non-pseudo instruction of
|
||||
* a list of instructions.
|
||||
*/
|
||||
|
||||
while (l != (line_p) 0 && INSTR(l) >= sp_fpseu &&
|
||||
INSTR(l) <= ps_last) l = l->l_next;
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
insert(text,l,firstline)
|
||||
line_p text,l,firstline;
|
||||
{
|
||||
/* Insert the modified EM text of the called
|
||||
* routine in the calling routine. Pseudos are
|
||||
* put after the pseudos of the caller; all
|
||||
* normal instructions are put at the place
|
||||
* where the CAL originally was.
|
||||
*/
|
||||
|
||||
line_p l1,l2,lastpseu;
|
||||
|
||||
l1 = text->l_next;
|
||||
oldline(text); /* remove dummy head instruction */
|
||||
if (l1 == (line_p) 0) return; /* no text at all! */
|
||||
l2 = first_nonpseudo(l1);
|
||||
if (l2 == (line_p) 0) {
|
||||
/* modified code consists only of pseudos */
|
||||
app_list(l1,PREV(first_nonpseudo(firstline)));
|
||||
} else {
|
||||
if (l1 == l2) {
|
||||
/* no pseudos */
|
||||
app_list(l2,l);
|
||||
} else {
|
||||
lastpseu = PREV(first_nonpseudo(firstline));
|
||||
PREV(l2)->l_next = (line_p) 0; /* cut link */
|
||||
app_list(l2,l); /* insert normal instructions */
|
||||
app_list(l1,lastpseu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
liquidate(p,text)
|
||||
proc_p p;
|
||||
line_p text;
|
||||
{
|
||||
/* All calls to procedure p were expanded in line, so
|
||||
* p is no longer needed. However, we must not throw away
|
||||
* any data declarations appearing in p.
|
||||
* The proctable entry of p is not removed, as we do not
|
||||
* want to create holes in this table; however the PF_BODYSEEN
|
||||
* flag is cleared, so p gets the same status as a procedure
|
||||
* whose body is unmkown.
|
||||
*/
|
||||
|
||||
line_p l, nextl, lastkept = (line_p) 0;
|
||||
call_p c, nextc;
|
||||
|
||||
for (l = text; l != (line_p) 0; l = nextl) {
|
||||
nextl = l->l_next;
|
||||
switch(INSTR(l)) {
|
||||
case ps_sym:
|
||||
case ps_hol:
|
||||
case ps_bss:
|
||||
case ps_con:
|
||||
case ps_rom:
|
||||
lastkept = l;
|
||||
break;
|
||||
default:
|
||||
rem_line(l);
|
||||
}
|
||||
}
|
||||
if (lastkept != (line_p) 0) {
|
||||
/* There were some data declarations in p,
|
||||
* so we'll turn p into a data-unit; we'll
|
||||
* have to append an end-pseudo for this
|
||||
* purpose.
|
||||
*/
|
||||
lastkept->l_next = newline(OPNO);
|
||||
lastkept->l_next->l_instr = (byte) ps_end;
|
||||
}
|
||||
/* There may be some calls in the body of p that
|
||||
* ought to be expanded in line. As p is removed
|
||||
* anyway, there is no use in really performing
|
||||
* these substitutions, so the call-descriptors
|
||||
* are just thrown away.
|
||||
*/
|
||||
|
||||
for (c = p->P_CALS; c != (call_p) 0; c = nextc) {
|
||||
nextc = c->cl_cdr;
|
||||
rem_call(c);
|
||||
}
|
||||
/* change the proctable entry */
|
||||
p->p_flags1 &= (byte) ~PF_BODYSEEN;
|
||||
oldchange(p->p_change);
|
||||
olduse(p->p_use);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 3 _ C H A N G E . C
|
||||
*/
|
||||
|
||||
|
||||
extern chg_callseq(); /* (call_p c; line_p cal, *l_out)
|
||||
* Change the calling sequence of
|
||||
* the call c. The parameters are
|
||||
* changed and the sequence
|
||||
* CAL - ASP - LFR is removed.
|
||||
* cal points to the CAL instruction
|
||||
* l_out indicates where the expanded
|
||||
* text of the called routine must
|
||||
* be put.
|
||||
*/
|
||||
extern line_p make_label(); /* (line_p l; proc_p p)
|
||||
* Make sure that the instruction after
|
||||
* l contains a label. If this is not
|
||||
* already the case, create a new label.
|
||||
*/
|
||||
extern modify(); /* (line_p text; call_p c; line_p lab;
|
||||
* offset ab_off, lb_off; int lab_off)
|
||||
* Modify the EM text of the called
|
||||
* procedure.
|
||||
*/
|
||||
extern mod_actuals(); /* (call_p nc,c; line_p lab;
|
||||
* offset ab_off, lb_off; int lab_off)
|
||||
* Modify the actual parameters of the
|
||||
* call nc the same way as the text of
|
||||
* call c would be modified.
|
||||
*/
|
||||
extern insert(); /* (line_p text,l,firstline)
|
||||
* Insert the modified EM text.
|
||||
* Pseudos are put after the pseudos
|
||||
* of the caller.
|
||||
*/
|
||||
extern liquidate(); /* (proc_p p; line_p text)
|
||||
* All calls to p were expanded in line,
|
||||
* so p is no longer needed.
|
||||
*/
|
||||
@@ -1,122 +0,0 @@
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 3 _ S U B S T . C
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "il.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/get.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "il_aux.h"
|
||||
#include "il3_aux.h"
|
||||
#include "il3_change.h"
|
||||
#include "il3_subst.h"
|
||||
|
||||
STATIC line_p fetch_text(lf,c)
|
||||
FILE *lf;
|
||||
call_p c;
|
||||
{
|
||||
/* Read the EM text of the called procedure.
|
||||
* We use random access I/O here.
|
||||
*/
|
||||
|
||||
line_p l;
|
||||
proc_p p;
|
||||
lset savmes;
|
||||
|
||||
savmes = mesregs;
|
||||
mesregs = Lempty_set();
|
||||
fseek(lf,c->cl_proc->P_LADDR,0);
|
||||
l = get_text(lf,&p);
|
||||
assert (p == c->cl_proc);
|
||||
Ldeleteset(mesregs);
|
||||
mesregs = savmes;
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
line_p scan_to_cal(lines,n)
|
||||
line_p lines;
|
||||
short n;
|
||||
{
|
||||
/* Find the n-th CAL instruction */
|
||||
|
||||
register line_p l;
|
||||
|
||||
for (l = lines; l != (line_p) 0; l = l->l_next) {
|
||||
if (INSTR(l) == op_cal) {
|
||||
if (--n == 0) return l;
|
||||
}
|
||||
}
|
||||
return (line_p) 0; /* CAL not found */
|
||||
}
|
||||
|
||||
|
||||
|
||||
substitute(lf,c,cal,firstline)
|
||||
FILE *lf;
|
||||
call_p c;
|
||||
line_p cal,firstline;
|
||||
{
|
||||
/* Perform in line substitution of the call described
|
||||
* by c. The EM text of the called routine is fetched
|
||||
* and modified, the calling sequence is changed,
|
||||
* the modified routine is put at the place of the call
|
||||
* and all global information (proctable etc.) is kept
|
||||
* up to date.
|
||||
*/
|
||||
|
||||
line_p l, text, lab;
|
||||
offset ab_off, lb_off;
|
||||
line_p startscan, ncal;
|
||||
short lastcid;
|
||||
call_p nc;
|
||||
|
||||
Ssubst++;
|
||||
ab_off = - curproc->p_localbytes;
|
||||
/* offset of temporaries for parameters
|
||||
* that are not expanded in line.
|
||||
*/
|
||||
chg_callseq(c,cal,&l);
|
||||
/* Change the calling sequence; l points to the place
|
||||
* where the expanded text must be put
|
||||
*/
|
||||
text = fetch_text(lf,c); /* fetch EM text of called routine */
|
||||
lb_off = - curproc->p_localbytes;
|
||||
/* offset of temps. for locals of called proc. */
|
||||
curproc->p_localbytes += c->cl_proc->P_ORGLOCALS;
|
||||
/* locals of called routine are put in stack frame of caller */
|
||||
if (!FALLTHROUGH(c->cl_proc)) {
|
||||
/* The called proc contains one or more RETurns
|
||||
* somewhere in the middle of its text; these
|
||||
* should be changed into a jump to the end
|
||||
* of the text. We create a label for this
|
||||
* purpose (if there was no one already).
|
||||
*/
|
||||
lab = make_label(l,curproc);
|
||||
}
|
||||
modify(text,c,lab,ab_off,lb_off,curproc->p_nrlabels);
|
||||
curproc->p_nrlabels += c->cl_proc->P_ORGLABELS;
|
||||
insert(text,l,firstline);
|
||||
/* insert text; instructions are put after l, pseudos
|
||||
* are put at beginning of caller.
|
||||
*/
|
||||
/* Now take care of the nested calls */
|
||||
startscan = l->l_next;
|
||||
lastcid = 0;
|
||||
for (nc = c->cl_car; nc != (call_p) 0; nc = nc->cl_cdr) {
|
||||
mod_actuals(nc,c,lab,ab_off,lb_off,curproc->p_nrlabels);
|
||||
ncal = scan_to_cal(startscan,nc->cl_id - lastcid);
|
||||
assert(ncal != (line_p) 0);
|
||||
startscan = scan_to_cal(ncal->l_next,1);
|
||||
lastcid = nc->cl_id;
|
||||
substitute(lf,nc,ncal,firstline);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L 3 _ S U B S T . H
|
||||
*/
|
||||
|
||||
extern line_p scan_to_cal(); /* (line_p lines; short n)
|
||||
* Find the n-th cal instruction.
|
||||
*/
|
||||
extern substitute(); /* (FILE *lf;call_p c; line_ pcal,firstline)
|
||||
* Perform in line substitution of the call described
|
||||
* by c. The EM text of the called routine is fetched
|
||||
* and modified, the calling sequence is changed,
|
||||
* the modified routine is put at the place of the call
|
||||
* and all global information (proctable etc.) is kept
|
||||
* up to date.
|
||||
*/
|
||||
@@ -1,383 +0,0 @@
|
||||
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L _ A U X . C
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "il.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/get.h"
|
||||
#include "../share/put.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/map.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "il_aux.h"
|
||||
|
||||
|
||||
int tsize(type)
|
||||
int type;
|
||||
{
|
||||
/* Determine the size of a variable of the
|
||||
* given type.
|
||||
*/
|
||||
|
||||
switch(type) {
|
||||
case SINGLE: return ws;
|
||||
case DOUBLE: return 2*ws;
|
||||
case POINTER: return ps;
|
||||
default: assert(FALSE);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
|
||||
line_p duplicate(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* Make a duplicate of an EM instruction.
|
||||
* Pseudos may not be passed as argument.
|
||||
*/
|
||||
|
||||
line_p l;
|
||||
|
||||
l = newline(TYPE(lnp));
|
||||
l->l_instr = INSTR(lnp);
|
||||
switch(TYPE(l)) {
|
||||
case OPNO:
|
||||
break;
|
||||
case OPSHORT:
|
||||
SHORT(l) = SHORT(lnp);
|
||||
break;
|
||||
case OPOFFSET:
|
||||
OFFSET(l) = OFFSET(lnp);
|
||||
break;
|
||||
case OPINSTRLAB:
|
||||
INSTRLAB(l) = INSTRLAB(lnp);
|
||||
break;
|
||||
case OPOBJECT:
|
||||
OBJ(l) = OBJ(lnp);
|
||||
break;
|
||||
case OPPROC:
|
||||
PROC(l) = PROC(lnp);
|
||||
break;
|
||||
default:
|
||||
assert(FALSE); /* cannot copy pseudo */
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
line_p copy_expr(l1)
|
||||
line_p l1;
|
||||
{
|
||||
/* copy the expression */
|
||||
|
||||
line_p head, tail, l, lnp;
|
||||
|
||||
head = (line_p) 0;
|
||||
for (lnp = l1; lnp != (line_p) 0; lnp = lnp->l_next) {
|
||||
l = duplicate(lnp);
|
||||
if (head == (line_p) 0) {
|
||||
head = tail = l;
|
||||
PREV(l) = (line_p) 0;
|
||||
} else {
|
||||
tail->l_next = l;
|
||||
PREV(l) = tail;
|
||||
tail = l;
|
||||
}
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
|
||||
rem_call(c)
|
||||
call_p c;
|
||||
{
|
||||
actual_p act, nexta;
|
||||
call_p nc,nextc;
|
||||
line_p l, nextl;
|
||||
|
||||
for (act = c->cl_actuals; act != (actual_p) 0; act = nexta) {
|
||||
nexta = act->ac_next;
|
||||
for (l = act->ac_exp; l != (line_p) 0; l = nextl) {
|
||||
nextl = l->l_next;
|
||||
oldline(l);
|
||||
}
|
||||
oldactual(act);
|
||||
}
|
||||
nc = c->cl_car;
|
||||
oldcall(c);
|
||||
for (; nc != (call_p) 0; nc = nextc) {
|
||||
/* Take care of nested calls */
|
||||
nextc = nc->cl_cdr;
|
||||
rem_call(nc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* rem_graph */
|
||||
|
||||
STATIC short remlines(l)
|
||||
line_p l;
|
||||
{
|
||||
|
||||
register line_p lnp;
|
||||
line_p next;
|
||||
|
||||
for (lnp = l; lnp != (line_p) 0; lnp = next) {
|
||||
next = lnp->l_next;
|
||||
oldline(lnp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
remunit(kind,p,l)
|
||||
short kind;
|
||||
proc_p p;
|
||||
line_p l;
|
||||
{
|
||||
register bblock_p b;
|
||||
bblock_p next;
|
||||
Lindex pi;
|
||||
loop_p lp;
|
||||
|
||||
if (kind == LDATA) {
|
||||
remlines(l);
|
||||
return;
|
||||
}
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = next) {
|
||||
next = b->b_next;
|
||||
remlines(b->b_start);
|
||||
Ldeleteset(b->b_loops);
|
||||
Ldeleteset(b->b_succ);
|
||||
Ldeleteset(b->b_pred);
|
||||
oldbblock(b);
|
||||
}
|
||||
for (pi = Lfirst(p->p_loops); pi != (Lindex) 0;
|
||||
pi = Lnext(pi,p->p_loops)) {
|
||||
oldloop(Lelem(pi));
|
||||
}
|
||||
Ldeleteset(p->p_loops);
|
||||
oldmap(lmap,llength);
|
||||
oldmap(lbmap,llength);
|
||||
oldmap(bmap,blength);
|
||||
oldmap(lpmap,lplength);
|
||||
}
|
||||
remcc(head)
|
||||
calcnt_p head;
|
||||
{
|
||||
calcnt_p cc, next;
|
||||
|
||||
for (cc = head; cc != (calcnt_p) 0; cc = next) {
|
||||
next = cc->cc_next;
|
||||
oldcalcnt(cc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Extra I/O routines */
|
||||
|
||||
call_p getcall(cf)
|
||||
FILE *cf;
|
||||
{
|
||||
/* read a call from the call-file */
|
||||
|
||||
call_p c;
|
||||
proc_p voided;
|
||||
actual_p act,*app;
|
||||
short n,m;
|
||||
|
||||
curinp = cf;
|
||||
c = newcall();
|
||||
n = getshort(); /* void nesting level */
|
||||
if (feof(curinp)) return (call_p) 0;
|
||||
c->cl_caller = pmap[getshort()];
|
||||
c->cl_id = getshort();
|
||||
c->cl_proc = pmap[getshort()];
|
||||
c->cl_looplevel = getbyte();
|
||||
c->cl_flags = getbyte();
|
||||
c->cl_ratio = getshort();
|
||||
app = &c->cl_actuals;
|
||||
n = getshort();
|
||||
while(n--) {
|
||||
act = newactual();
|
||||
m = getshort();
|
||||
act->ac_size = getoff();
|
||||
act->ac_inl = getbyte();
|
||||
act->ac_exp = getlines(cf,m,&voided);
|
||||
*app = act;
|
||||
app = &act->ac_next;
|
||||
}
|
||||
*app = (actual_p) 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
line_p get_text(lf,p_out)
|
||||
FILE *lf;
|
||||
proc_p *p_out;
|
||||
{
|
||||
/* Read the EM text of one unit
|
||||
* If it is a procedure, set p_out to
|
||||
* the proc. just read. Else set p_out
|
||||
* to 0.
|
||||
*/
|
||||
|
||||
line_p dumhead, l, lprev;
|
||||
loop_p *oldlpmap = lpmap;
|
||||
line_p *oldlmap = lmap;
|
||||
short oldllength = llength;
|
||||
short oldlastlabid = lastlabid;
|
||||
|
||||
curinp = lf;
|
||||
*p_out = (proc_p) 0;
|
||||
dumhead = newline(OPNO);
|
||||
/* The list of instructions is preceeded by a dummy
|
||||
* line, to simplify list manipulation
|
||||
*/
|
||||
dumhead->l_instr = op_nop; /* just for fun */
|
||||
lprev = dumhead;
|
||||
for (;;) {
|
||||
l = read_line(p_out);
|
||||
if (feof(curinp)) return (line_p) 0;
|
||||
lprev->l_next = l;
|
||||
PREV(l) = lprev;
|
||||
if (INSTR(l) == ps_end) break;
|
||||
if (INSTR(l) == ps_mes) {
|
||||
message(l);
|
||||
}
|
||||
lprev = l;
|
||||
}
|
||||
/* The tables that map labels to instructions
|
||||
* and labels to basic blocks are not used.
|
||||
*/
|
||||
if (*p_out != (proc_p) 0) {
|
||||
oldmap(lmap,llength);
|
||||
oldmap(lbmap,llength);
|
||||
lmap = oldlmap;
|
||||
lpmap = oldlpmap;
|
||||
}
|
||||
llength = oldllength;
|
||||
lastlabid = oldlastlabid;
|
||||
return dumhead;
|
||||
}
|
||||
|
||||
|
||||
|
||||
calcnt_p getcc(ccf,p)
|
||||
FILE *ccf;
|
||||
proc_p p;
|
||||
{
|
||||
/* Get call-count info of procedure p */
|
||||
|
||||
calcnt_p head,cc,*ccp;
|
||||
short i;
|
||||
|
||||
fseek(ccf,p->p_extend->px_il.p_ccaddr,0);
|
||||
curinp = ccf;
|
||||
head = (calcnt_p) 0;
|
||||
ccp = &head;
|
||||
for (i = getshort(); i != (short) 0; i--) {
|
||||
cc = *ccp = newcalcnt();
|
||||
cc->cc_proc = pmap[getshort()];
|
||||
cc->cc_count = getshort();
|
||||
ccp = &cc->cc_next;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
/* The following routines are only used by the Inline Substitution phase */
|
||||
|
||||
|
||||
STATIC putactuals(alist,cfile)
|
||||
actual_p alist;
|
||||
FILE *cfile;
|
||||
{
|
||||
/* output a list of actual parameters */
|
||||
|
||||
actual_p a,next;
|
||||
line_p l;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
for (a = alist; a != (actual_p) 0; a = a->ac_next) count++;
|
||||
outshort(count); /* number of actuals */
|
||||
for (a = alist; a != (actual_p) 0; a = next) {
|
||||
next = a->ac_next;
|
||||
count = 0;
|
||||
for (l = a->ac_exp; l != (line_p) 0; l= l->l_next) count++;
|
||||
outshort(count); /* length of actual */
|
||||
outoff(a->ac_size);
|
||||
outbyte(a->ac_inl);
|
||||
count = putlines(a->ac_exp,cfile);
|
||||
oldactual(a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
putcall(c,cfile,level)
|
||||
call_p c;
|
||||
FILE *cfile;
|
||||
short level;
|
||||
{
|
||||
/* output a call */
|
||||
|
||||
call_p nc,nextc;
|
||||
|
||||
|
||||
curoutp = cfile;
|
||||
outshort(level); /* nesting level */
|
||||
outshort(c->cl_caller->p_id); /* calling proc */
|
||||
outshort(c->cl_id);
|
||||
outshort(c->cl_proc->p_id); /* called proc */
|
||||
outbyte(c->cl_looplevel);
|
||||
outbyte(c->cl_flags);
|
||||
outshort(c->cl_ratio);
|
||||
putactuals(c->cl_actuals,cfile);
|
||||
nc = c->cl_car;
|
||||
oldcall(c);
|
||||
for (; nc != (call_p) 0; nc = nextc) {
|
||||
/* take care of nested calls */
|
||||
nextc = nc->cl_cdr;
|
||||
putcall(nc,cfile,level+1);
|
||||
}
|
||||
}
|
||||
|
||||
long putcc(head,ccf)
|
||||
calcnt_p head;
|
||||
FILE *ccf;
|
||||
{
|
||||
/* Write call-count information to file ccf.
|
||||
* Return the disk address of the info written.
|
||||
*/
|
||||
|
||||
calcnt_p cc;
|
||||
long addr;
|
||||
short cnt;
|
||||
|
||||
addr = ftell(ccf);
|
||||
curoutp = ccf;
|
||||
cnt = 0;
|
||||
for (cc = head; cc != (calcnt_p) 0;cc = cc->cc_next) cnt++;
|
||||
outshort(cnt);
|
||||
for (cc = head; cc != (calcnt_p) 0; cc = cc->cc_next) {
|
||||
outproc(cc->cc_proc);
|
||||
outshort(cc->cc_count);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
|
||||
/* I N L I N E S U B S T I T U T I O N
|
||||
*
|
||||
* I L _ A U X . H
|
||||
*/
|
||||
|
||||
extern int tsize(); /* (int type)
|
||||
* Determine the size of a variable of
|
||||
* the given type.
|
||||
*/
|
||||
extern line_p duplicate(); /* (line_p lnp)
|
||||
* Make a duplicate of the given EM
|
||||
* instruction. Pseudos may not be
|
||||
* passed as argumnets.
|
||||
*/
|
||||
extern line_p copy_expr(); /* (line_p l1)
|
||||
* copy the expression l1.
|
||||
* Pseudos may not be contained in
|
||||
* the list of instructions.
|
||||
*/
|
||||
extern rem_call(); /* (call_p c)
|
||||
* Remove a call from main memory.
|
||||
*/
|
||||
extern rem_graph(); /* (proc_p p)
|
||||
* Remove the CFG and EM text of
|
||||
* a procedure from core.
|
||||
*/
|
||||
extern remcc(); /* (calcnt_p head)
|
||||
* Remove call-count info from core.
|
||||
*/
|
||||
extern call_p getcall(); /* (FILE *cf)
|
||||
* Read a call from the call-file
|
||||
*/
|
||||
extern line_p get_text(); /* (FILE *lf; proc_p *p_out)
|
||||
* Read the EM text of one procedure.
|
||||
* The procedure read is returned via
|
||||
* p_out.
|
||||
*/
|
||||
extern calcnt_p getcc(); /* (FILE *ccf; proc_p p)
|
||||
* Read the call-count information
|
||||
* of procedure p.
|
||||
*/
|
||||
extern putcall(); /* (call_p call; FILE *cfile; short level)
|
||||
* Write the call
|
||||
* with the given id to the given file.
|
||||
* The level is the nesting level, used by
|
||||
* putcall when it calls itself recurively.
|
||||
* It should be 0 on outer levels.
|
||||
*/
|
||||
extern long putcc(); /* (calcnt_p head; FILE *ccf)
|
||||
* Write call-count information to
|
||||
* file ccf.
|
||||
*/
|
||||
@@ -1,66 +0,0 @@
|
||||
EMH=../../../h
|
||||
EMLIB=../../../lib
|
||||
SHR=../share
|
||||
|
||||
CFILES=\
|
||||
lv.c
|
||||
|
||||
OFILES=\
|
||||
lv.o
|
||||
|
||||
HFILES=\
|
||||
lv.h
|
||||
|
||||
PRFILES=\
|
||||
$(CFILES) $(HFILES) Makefile
|
||||
|
||||
SHARE_OFILES=\
|
||||
$(SHR)/get.o $(SHR)/aux.o $(SHR)/put.o $(SHR)/map.o $(SHR)/alloc.o \
|
||||
$(SHR)/global.o $(SHR)/debug.o $(SHR)/lset.o $(SHR)/cset.o $(SHR)/parser.o \
|
||||
$(SHR)/files.o $(SHR)/locals.o $(SHR)/init_glob.o $(SHR)/go.o
|
||||
|
||||
SHARE_MFILES=\
|
||||
$(SHR)/get.m $(SHR)/aux.m $(SHR)/put.m $(SHR)/map.m $(SHR)/alloc.m \
|
||||
$(SHR)/global.m $(SHR)/debug.m $(SHR)/lset.m $(SHR)/cset.m $(SHR)/parser.m \
|
||||
$(SHR)/files.m $(SHR)/locals.m $(SHR)/init_glob.m $(SHR)/go.m
|
||||
|
||||
lv: $(OFILES)
|
||||
$(CC) -o lv $(LDFLAGS) $(OFILES) $(SHARE_OFILES) $(EMLIB)/em_data.a
|
||||
|
||||
lv_ack: $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -c.o $(CFLAGS) $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -o lv -.c $(LDFLAGS) lv.o $(EMLIB)/em_data.a
|
||||
|
||||
lint:
|
||||
lint $(LINTFLAGS) $(CPPFLAGS) $(CFILES)
|
||||
|
||||
pr: $(PRFILES)
|
||||
@pr $?
|
||||
@touch pr
|
||||
|
||||
depend:
|
||||
$(SHR)/makedepend
|
||||
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
|
||||
lv.o: ../../../h/em_mnem.h
|
||||
lv.o: ../../../h/em_pseu.h
|
||||
lv.o: ../../../h/em_spec.h
|
||||
lv.o: ../share/alloc.h
|
||||
lv.o: ../share/aux.h
|
||||
lv.o: ../share/cset.h
|
||||
lv.o: ../share/debug.h
|
||||
lv.o: ../share/def.h
|
||||
lv.o: ../share/files.h
|
||||
lv.o: ../share/get.h
|
||||
lv.o: ../share/global.h
|
||||
lv.o: ../share/go.h
|
||||
lv.o: ../share/init_glob.h
|
||||
lv.o: ../share/locals.h
|
||||
lv.o: ../share/lset.h
|
||||
lv.o: ../share/map.h
|
||||
lv.o: ../share/parser.h
|
||||
lv.o: ../share/put.h
|
||||
lv.o: ../share/types.h
|
||||
lv.o: lv.h
|
||||
588
util/ego/lv/lv.c
588
util/ego/lv/lv.c
@@ -1,588 +0,0 @@
|
||||
|
||||
/* L I V E V A R I A B L E S A N A L Y S I S */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "lv.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/cset.h"
|
||||
#include "../share/def.h"
|
||||
#include "../share/files.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/map.h"
|
||||
#include "../share/get.h"
|
||||
#include "../share/put.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/init_glob.h"
|
||||
#include "../share/locals.h"
|
||||
#include "../share/go.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../share/parser.h"
|
||||
|
||||
#define newlvbx() (bext_p) newstruct(bext_lv)
|
||||
#define oldlvbx(x) oldstruct(bext_lv,x)
|
||||
|
||||
|
||||
/* TEMPORARY: should be put in ../../../h/em_mes.h: */
|
||||
#define ms_liv 9
|
||||
#define ms_ded 10
|
||||
|
||||
short nrglobals;
|
||||
short nrvars;
|
||||
|
||||
STATIC int Slv;
|
||||
STATIC bool mesgflag = FALSE; /* Suppress generation of live/dead info */
|
||||
|
||||
|
||||
STATIC clean_up()
|
||||
{
|
||||
local_p *p;
|
||||
|
||||
for (p = &locals[1]; p <= &locals[nrlocals]; p++) {
|
||||
oldlocal(*p);
|
||||
}
|
||||
oldmap(locals,nrlocals);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool is_dir_use(l)
|
||||
line_p l;
|
||||
{
|
||||
/* See if l is a direct use of some variable
|
||||
* (i.e. not through a pointer). A LIL is a
|
||||
* direct use of some pointer variable
|
||||
* (and an indirect use of some other variable).
|
||||
* A SIL is also a direct use.
|
||||
* A LOI, however, is not an direct use of a variable.
|
||||
* An an increment/decrement instruction is regarded
|
||||
* as a use here, and not as a definition, as the
|
||||
* variable is first used and than defined.
|
||||
*/
|
||||
|
||||
switch(INSTR(l)) {
|
||||
case op_dee:
|
||||
case op_del:
|
||||
case op_ine:
|
||||
case op_inl:
|
||||
case op_lde:
|
||||
case op_ldl:
|
||||
case op_lil:
|
||||
case op_loe:
|
||||
case op_lol:
|
||||
case op_sil:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool is_indir_use(l)
|
||||
line_p l;
|
||||
{
|
||||
/* See if instruction l uses some variable(s) indirectly,
|
||||
* i.e. through a pointer or via a procedure call.
|
||||
*/
|
||||
|
||||
switch(INSTR(l)) {
|
||||
case op_blm:
|
||||
case op_bls:
|
||||
case op_cai:
|
||||
case op_cal:
|
||||
case op_lar:
|
||||
case op_ldf:
|
||||
case op_lil:
|
||||
case op_lof:
|
||||
case op_loi:
|
||||
case op_los:
|
||||
case op_mon:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool is_def(l)
|
||||
line_p l;
|
||||
{
|
||||
/* See if l does a direct definition */
|
||||
|
||||
switch(INSTR(l)) {
|
||||
case op_sde:
|
||||
case op_sdl:
|
||||
case op_ste:
|
||||
case op_stl:
|
||||
case op_zre:
|
||||
case op_zrl:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
STATIC def_use(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Compute DEF(b) and USE(b), for every basic block b
|
||||
* of procedure p. DEF(b) contains the variables that
|
||||
* are certain to be defined (assigned) in b
|
||||
* before being used. USE(b) contains the variables
|
||||
* that may be used in b, before being defined.
|
||||
* (Note that uncertainty arises in the presence of
|
||||
* pointers and procedure calls).
|
||||
* We compute these sets, by scanning the text of
|
||||
* the basic block from beginning till end.
|
||||
*/
|
||||
|
||||
register bblock_p b;
|
||||
register line_p l;
|
||||
short v;
|
||||
bool found;
|
||||
cset all_ind_uses;
|
||||
|
||||
all_ind_uses = Cempty_set(nrvars);
|
||||
for (v = 1; v < nrlocals; v++) {
|
||||
if (!IS_REGVAR(locals[v])) {
|
||||
Cadd(LOC_TO_VARNR(v),&all_ind_uses);
|
||||
}
|
||||
}
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
USE(b) = Cempty_set(nrvars);
|
||||
DEF(b) = Cempty_set(nrvars);
|
||||
for (l = b->b_start; l != (line_p) 0; l = l->l_next) {
|
||||
if (is_def(l)) {
|
||||
/* An direct definition (i.e. not
|
||||
* through a pointer).
|
||||
*/
|
||||
var_nr(l,&v,&found);
|
||||
if (found && !Cis_elem(v,USE(b))) {
|
||||
/* We do maintain live-dead info
|
||||
* for this variable, and it was
|
||||
* not used earlier in b.
|
||||
*/
|
||||
Cadd(v, &DEF(b));
|
||||
}
|
||||
} else {
|
||||
if (is_dir_use(l)) {
|
||||
var_nr(l,&v,&found);
|
||||
if (found && !Cis_elem(v,DEF(b))) {
|
||||
Cadd(v, &USE(b));
|
||||
}
|
||||
}
|
||||
if (is_indir_use(l)) {
|
||||
/* Add variable that may be used
|
||||
* by l to USE(b).
|
||||
*/
|
||||
Cjoin(all_ind_uses,&USE(b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Cdeleteset(all_ind_uses);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC unite_ins(bbset,setp)
|
||||
lset bbset;
|
||||
cset *setp;
|
||||
{
|
||||
/* Take the union of L_IN(b), for all b in bbset,
|
||||
* and put the result in setp.
|
||||
*/
|
||||
|
||||
Lindex i;
|
||||
|
||||
Cclear_set(setp);
|
||||
for (i = Lfirst(bbset); i != (Lindex) 0; i = Lnext(i,bbset)) {
|
||||
Cjoin(L_IN((bblock_p) Lelem(i)), setp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC solve_lv(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Solve the data flow equations for Live Variables,
|
||||
* for procedure p. These equations are:
|
||||
* (1) IN[b] = OUT[b] - DEF[b] + USE[b]
|
||||
* (2) OUT(b) = IN(s1) + ... + IN(sn) ;
|
||||
* where SUCC(b) = {s1, ... , sn}
|
||||
*/
|
||||
|
||||
register bblock_p b;
|
||||
cset newout = Cempty_set(nrvars);
|
||||
bool change = TRUE;
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
L_IN(b) = Cempty_set(nrvars);
|
||||
Ccopy_set(USE(b), &L_IN(b));
|
||||
L_OUT(b) = Cempty_set(nrvars);
|
||||
}
|
||||
while (change) {
|
||||
change = FALSE;
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
unite_ins(b->b_succ,&newout);
|
||||
if (!Cequal(newout,L_OUT(b))) {
|
||||
change = TRUE;
|
||||
Ccopy_set(newout, &L_OUT(b));
|
||||
Ccopy_set(newout, &L_IN(b));
|
||||
Csubtract(DEF(b), &L_IN(b));
|
||||
Cjoin(USE(b), &L_IN(b));
|
||||
}
|
||||
}
|
||||
}
|
||||
Cdeleteset(newout);
|
||||
}
|
||||
|
||||
|
||||
STATIC live_variables_analysis(p)
|
||||
proc_p p;
|
||||
{
|
||||
make_localtab(p);
|
||||
nrvars = nrglobals + nrlocals;
|
||||
def_use(p);
|
||||
solve_lv(p);
|
||||
}
|
||||
|
||||
|
||||
STATIC init_live_dead(b)
|
||||
bblock_p b;
|
||||
{
|
||||
/* For every register variable, see if it is
|
||||
* live or dead at the end of b.
|
||||
*/
|
||||
|
||||
register short v;
|
||||
local_p loc;
|
||||
|
||||
for (v = 1; v <= nrlocals; v++) {
|
||||
loc = locals[v];
|
||||
if (IS_REGVAR(loc) && Cis_elem(LOC_TO_VARNR(v),L_OUT(b))) {
|
||||
LIVE(loc);
|
||||
} else {
|
||||
DEAD(loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC line_p make_mesg(mesg,loc)
|
||||
short mesg;
|
||||
local_p loc;
|
||||
{
|
||||
/* Create a line for a message stating that
|
||||
* local variable loc is live/dead. This message
|
||||
* looks like: "mes ms_liv,off,size" or
|
||||
* "mes ms_ded,off,size".
|
||||
*/
|
||||
|
||||
line_p l = newline(OPLIST);
|
||||
register arg_p ap;
|
||||
|
||||
l->l_instr = ps_mes;
|
||||
ap = ARG(l) = newarg(ARGOFF);
|
||||
ap->a_a.a_offset = mesg;
|
||||
ap = ap->a_next = newarg(ARGOFF);
|
||||
ap->a_a.a_offset = loc->lc_off;
|
||||
ap = ap->a_next = newarg(ARGOFF);
|
||||
ap->a_a.a_offset = loc->lc_size;
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC block_entry(b,prev)
|
||||
bblock_p b,prev;
|
||||
{
|
||||
short v,vn;
|
||||
local_p loc;
|
||||
bool was_live, is_live;
|
||||
|
||||
/* Generate a live/dead message for every register variable that
|
||||
* was live at the end of prev, but dead at the beginning of b,
|
||||
* or v.v. If prev = 0 (i.e. begin of procedure), parameters were
|
||||
* live, normal local variables were dead.
|
||||
*/
|
||||
|
||||
for (v = 1; v <= nrlocals; v++) {
|
||||
loc = locals[v];
|
||||
vn = LOC_TO_VARNR(v);
|
||||
if (prev == (bblock_p) 0) {
|
||||
was_live = loc->lc_off >= 0;
|
||||
} else {
|
||||
was_live = Cis_elem(vn,L_OUT(prev));
|
||||
}
|
||||
is_live = Cis_elem(vn,L_IN(b));
|
||||
if (was_live != is_live) {
|
||||
app_block(make_mesg((is_live?ms_liv:ms_ded),loc),b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC app_block(l,b)
|
||||
line_p l;
|
||||
bblock_p b;
|
||||
{
|
||||
line_p x = b->b_start;
|
||||
|
||||
if (x != (line_p) 0 && INSTR(x) == ps_pro) {
|
||||
/* start of procedure; append after pro pseudo ! */
|
||||
if ((l->l_next = x->l_next) != (line_p) 0) {
|
||||
PREV(l->l_next) = l;
|
||||
}
|
||||
x->l_next = l;
|
||||
PREV(l) = x;
|
||||
} else {
|
||||
if ((l->l_next = x) != (line_p) 0) {
|
||||
PREV(l->l_next) = l;
|
||||
}
|
||||
b->b_start = l;
|
||||
PREV(l) = (line_p) 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC definition(l,useless_out,v_out,mesgflag)
|
||||
line_p l;
|
||||
bool *useless_out;
|
||||
short *v_out;
|
||||
bool mesgflag;
|
||||
{
|
||||
/* Process a definition. If the defined (register-) variable
|
||||
* is live after 'l', then create a live-message and put
|
||||
* it after 'l'.
|
||||
*/
|
||||
|
||||
short v;
|
||||
bool found;
|
||||
local_p loc;
|
||||
|
||||
*useless_out = FALSE;
|
||||
var_nr(l,&v,&found);
|
||||
if (found && IS_LOCAL(v)) {
|
||||
*v_out = v;
|
||||
loc = locals[TO_LOCAL(v)];
|
||||
if (IS_REGVAR(loc)) {
|
||||
if (IS_LIVE(loc)) {
|
||||
if (!mesgflag) {
|
||||
appnd_line(make_mesg(ms_liv,loc), l);
|
||||
}
|
||||
DEAD(loc);
|
||||
} else {
|
||||
*useless_out = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
STATIC use(l,mesgflag)
|
||||
line_p l;
|
||||
bool mesgflag;
|
||||
{
|
||||
/* Process a use. If the defined (register-) variable
|
||||
* is dead after 'l', then create a dead-message and put
|
||||
* it after 'l'.
|
||||
*/
|
||||
|
||||
short v;
|
||||
bool found;
|
||||
local_p loc;
|
||||
|
||||
var_nr(l,&v,&found);
|
||||
if (found && IS_LOCAL(v)) {
|
||||
loc = locals[TO_LOCAL(v)];
|
||||
if (IS_REGVAR(loc) && IS_DEAD(loc)) {
|
||||
if (!mesgflag) {
|
||||
appnd_line(make_mesg(ms_ded,loc), l);
|
||||
}
|
||||
LIVE(loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC nothing() { } /* No action to be undertaken at level 0 of parser */
|
||||
|
||||
STATIC rem_code(l1,l2,b)
|
||||
line_p l1,l2;
|
||||
bblock_p b;
|
||||
{
|
||||
line_p l,x,y;
|
||||
|
||||
x = PREV(l1);
|
||||
y = l2->l_next;
|
||||
for (l = l1; l != l2; l = l->l_next) {
|
||||
oldline(l);
|
||||
}
|
||||
if (x == (line_p) 0) {
|
||||
b->b_start = y;
|
||||
} else {
|
||||
x->l_next = y;
|
||||
}
|
||||
if (y != (line_p) 0) {
|
||||
PREV(y) = x;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define SIZE(v) ((offset) locals[TO_LOCAL(v)]->lc_size)
|
||||
|
||||
|
||||
|
||||
|
||||
lv_mesg(p,mesgflag)
|
||||
proc_p p;
|
||||
bool mesgflag;
|
||||
{
|
||||
/* Create live/dead messages for every possible register
|
||||
* variable of p. A dead-message is put after a "use" of
|
||||
* such a variable, if the variable becomes dead just
|
||||
* after the use (i.e. this was its last use).
|
||||
* A live message is put after a "definition" of such
|
||||
* a variable, if the variable becomes live just
|
||||
* after the definition (which will usually be the case).
|
||||
* We traverse every basic block b of p from the last
|
||||
* instruction of b backwards to the beginning of b.
|
||||
* Initially, all variables that are dead at the end
|
||||
* of b are marked dead. All others are marked live.
|
||||
* If we come accross a definition of a variable X that
|
||||
* was marked live, we put a live-message after the
|
||||
* definition and mark X dead.
|
||||
* If we come accross a use of a variable X that
|
||||
* was marked dead, we put a dead-message after the
|
||||
* use and mark X live.
|
||||
* So at any point, the mark of X tells whether X is
|
||||
* live or dead immediately before (!) that point.
|
||||
* We also generate a message at the start of a basic block
|
||||
* for every variable that was live at the end of the (textually)
|
||||
* previous block, but dead at the entry of this block, or v.v.
|
||||
* On the fly, useless assignments are removed.
|
||||
*/
|
||||
|
||||
register bblock_p b;
|
||||
register line_p l;
|
||||
line_p lnp, prev;
|
||||
bblock_p prevb = (bblock_p) 0;
|
||||
short v;
|
||||
bool useless;
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
block_entry(b,prevb); /* generate message at head of block */
|
||||
prevb = b;
|
||||
if (!mesgflag) {
|
||||
init_live_dead(b);
|
||||
}
|
||||
for (l = last_instr(b); l != (line_p) 0; l = prev) {
|
||||
/* traverse backwards! */
|
||||
prev = PREV(l);
|
||||
if (is_def(l)) {
|
||||
definition(l,&useless,&v,mesgflag);
|
||||
if (useless && /* assignment to dead var. */
|
||||
parse(prev,SIZE(v),&lnp,0,nothing)) {
|
||||
/* The code "VAR := expression" can
|
||||
* be removed. 'l' is the "STL VAR",
|
||||
* lnp is the beginning of the EM code
|
||||
* for the expression.
|
||||
*/
|
||||
prev = PREV(lnp);
|
||||
rem_code(lnp,l,b);
|
||||
OUTVERBOSE("useless assignment ,proc %d,local %d", curproc->p_id,
|
||||
(int) locals[TO_LOCAL(v)]->lc_off);
|
||||
Slv++;
|
||||
}
|
||||
} else {
|
||||
if (is_dir_use(l)) {
|
||||
use(l,mesgflag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC lv_extend(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Allocate extended data structures for Use Definition analysis */
|
||||
|
||||
register bblock_p b;
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
b->b_extend = newlvbx();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC lv_cleanup(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Deallocate extended data structures for Use Definition analysis */
|
||||
|
||||
register bblock_p b;
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
Cdeleteset(USE(b));
|
||||
Cdeleteset(DEF(b));
|
||||
Cdeleteset(L_IN(b));
|
||||
Cdeleteset(L_OUT(b));
|
||||
oldlvbx(b->b_extend);
|
||||
}
|
||||
}
|
||||
|
||||
lv_flags(p)
|
||||
char *p;
|
||||
{
|
||||
switch(*p) {
|
||||
case 'N':
|
||||
mesgflag = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lv_optimize(p)
|
||||
proc_p p;
|
||||
{
|
||||
locals = (local_p *) 0;
|
||||
lv_extend(p);
|
||||
live_variables_analysis(p);
|
||||
lv_mesg(p,mesgflag);
|
||||
/* generate live-dead messages for regvars */
|
||||
lv_cleanup(p);
|
||||
clean_up();
|
||||
}
|
||||
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
go(argc,argv,init_globals,lv_optimize,no_action,lv_flags);
|
||||
report("useless assignments deleted",Slv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/* L I V E V A R I A B L E S A N A L Y S I S
|
||||
*
|
||||
* L V . H
|
||||
*/
|
||||
|
||||
|
||||
#define USE(b) (b)->b_extend->bx_lv.bx_use
|
||||
#define DEF(b) (b)->b_extend->bx_lv.bx_def
|
||||
#define L_IN(b) (b)->b_extend->bx_lv.bx_lin
|
||||
#define L_OUT(b) (b)->b_extend->bx_lv.bx_lout
|
||||
|
||||
extern short nrglobals; /* number of global variables for which
|
||||
* ud-info is maintained.
|
||||
*/
|
||||
extern short nrvars; /* total number of variables (global + local)
|
||||
* for which ud-info is maintained.
|
||||
*/
|
||||
|
||||
/* Every global variable for which ud-info is maintained has
|
||||
* a 'global variable number' (o_globnr). Every useful local
|
||||
* has a 'local variable number', which is its index in the
|
||||
* 'locals' table. All these variables also have a
|
||||
* 'variable number'. Conversions exist between these numbers.
|
||||
*/
|
||||
|
||||
#define TO_GLOBAL(v) (v)
|
||||
#define TO_LOCAL(v) (v - nrglobals)
|
||||
#define GLOB_TO_VARNR(v) (v)
|
||||
#define LOC_TO_VARNR(v) (v + nrglobals)
|
||||
#define IS_GLOBAL(v) (v <= nrglobals)
|
||||
#define IS_LOCAL(v) (v > nrglobals)
|
||||
|
||||
#define REGVAR(lc) lc->lc_flags |= LCF_REG
|
||||
#define IS_REGVAR(lc) (lc->lc_flags & LCF_REG)
|
||||
#define BADLC(lc) lc->lc_flags |= LCF_BAD
|
||||
#define IS_BADLC(lc) (lc->lc_flags & LCF_BAD)
|
||||
#define LIVE(lc) lc->lc_flags |= LCF_LIVE
|
||||
#define DEAD(lc) lc->lc_flags &= ~LCF_LIVE
|
||||
#define IS_LIVE(lc) (lc->lc_flags & LCF_LIVE)
|
||||
#define IS_DEAD(lc) (!(lc->lc_flags & LCF_LIVE))
|
||||
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
EMH=../../../h
|
||||
EMLIB=../../../lib
|
||||
SHR=../share
|
||||
|
||||
CFILES=\
|
||||
ra.c ra_items.c ra_lifet.c ra_allocl.c ra_profits.c \
|
||||
ra_interv.c ra_pack.c ra_xform.c ra_aux.c
|
||||
|
||||
OFILES=\
|
||||
ra.o ra_items.o ra_lifet.o ra_allocl.o ra_profits.o \
|
||||
ra_interv.o ra_pack.o ra_xform.o ra_aux.o
|
||||
|
||||
HFILES=\
|
||||
ra.h ra_items.h ra_lifet.h ra_allocl.h ra_profits.h \
|
||||
ra_interv.h ra_pack.h ra_xform.h ra_aux.h
|
||||
|
||||
PRFILES=\
|
||||
$(CFILES) $(HFILES) Makefile
|
||||
|
||||
SHARE_OFILES=\
|
||||
$(SHR)/aux.o $(SHR)/get.o $(SHR)/put.o $(SHR)/alloc.o $(SHR)/global.o \
|
||||
$(SHR)/debug.o $(SHR)/files.o $(SHR)/map.o $(SHR)/lset.o $(SHR)/cset.o \
|
||||
$(SHR)/go.o
|
||||
|
||||
SHARE_MFILES=\
|
||||
$(SHR)/aux.m $(SHR)/get.m $(SHR)/put.m $(SHR)/alloc.m $(SHR)/global.m \
|
||||
$(SHR)/debug.m $(SHR)/files.m $(SHR)/map.m $(SHR)/lset.m $(SHR)/cset.m \
|
||||
$(SHR)/go.m
|
||||
|
||||
ra: $(OFILES)
|
||||
$(CC) -o ra $(LDFLAGS) $(OFILES) $(SHARE_OFILES) $(EMLIB)/em_data.a
|
||||
|
||||
ra_ack: $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -c.o $(CFLAGS) $(CFILES) $(SHARE_MFILES)
|
||||
$(CC) -o ra -.c $(LDFLAGS) ra.o $(EMLIB)/em_data.a
|
||||
|
||||
itemtab.h: itemtab.src makeitems $(EMH)/em_mnem.h
|
||||
makeitems $(EMH)/em_mnem.h itemtab.src > itemtab.h
|
||||
|
||||
makeitems: makeitems.c
|
||||
$(CC) -o makeitems makeitems.c
|
||||
|
||||
lint:
|
||||
lint $(LINTFLAGS) $(CPPFLAGS) $(CFILES)
|
||||
|
||||
pr: $(PRFILES)
|
||||
@pr $?
|
||||
@touch pr
|
||||
|
||||
depend:
|
||||
$(SHR)/makedepend
|
||||
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
|
||||
ra.o: ../../../h/em_reg.h
|
||||
ra.o: ../share/alloc.h
|
||||
ra.o: ../share/debug.h
|
||||
ra.o: ../share/files.h
|
||||
ra.o: ../share/get.h
|
||||
ra.o: ../share/global.h
|
||||
ra.o: ../share/go.h
|
||||
ra.o: ../share/lset.h
|
||||
ra.o: ../share/map.h
|
||||
ra.o: ../share/put.h
|
||||
ra.o: ../share/types.h
|
||||
ra.o: ra.h
|
||||
ra.o: ra_allocl.h
|
||||
ra.o: ra_items.h
|
||||
ra.o: ra_pack.h
|
||||
ra.o: ra_profits.h
|
||||
ra.o: ra_xform.h
|
||||
ra_allocl.o: ../../../h/em_mnem.h
|
||||
ra_allocl.o: ../../../h/em_pseu.h
|
||||
ra_allocl.o: ../../../h/em_reg.h
|
||||
ra_allocl.o: ../../../h/em_spec.h
|
||||
ra_allocl.o: ../share/alloc.h
|
||||
ra_allocl.o: ../share/aux.h
|
||||
ra_allocl.o: ../share/cset.h
|
||||
ra_allocl.o: ../share/debug.h
|
||||
ra_allocl.o: ../share/def.h
|
||||
ra_allocl.o: ../share/global.h
|
||||
ra_allocl.o: ../share/lset.h
|
||||
ra_allocl.o: ../share/map.h
|
||||
ra_allocl.o: ../share/types.h
|
||||
ra_allocl.o: ra.h
|
||||
ra_allocl.o: ra_allocl.h
|
||||
ra_allocl.o: ra_aux.h
|
||||
ra_allocl.o: ra_interv.h
|
||||
ra_allocl.o: ra_items.h
|
||||
ra_aux.o: ../../../h/em_mnem.h
|
||||
ra_aux.o: ../../../h/em_pseu.h
|
||||
ra_aux.o: ../../../h/em_reg.h
|
||||
ra_aux.o: ../../../h/em_spec.h
|
||||
ra_aux.o: ../share/alloc.h
|
||||
ra_aux.o: ../share/debug.h
|
||||
ra_aux.o: ../share/def.h
|
||||
ra_aux.o: ../share/global.h
|
||||
ra_aux.o: ../share/lset.h
|
||||
ra_aux.o: ../share/types.h
|
||||
ra_aux.o: ra.h
|
||||
ra_aux.o: ra_aux.h
|
||||
ra_interv.o: ../share/alloc.h
|
||||
ra_interv.o: ../share/debug.h
|
||||
ra_interv.o: ../share/global.h
|
||||
ra_interv.o: ../share/lset.h
|
||||
ra_interv.o: ../share/types.h
|
||||
ra_interv.o: ../../../h/em_reg.h
|
||||
ra_interv.o: ra.h
|
||||
ra_interv.o: ra_interv.h
|
||||
ra_items.o: ../../../h/em_mnem.h
|
||||
ra_items.o: ../../../h/em_pseu.h
|
||||
ra_items.o: ../../../h/em_reg.h
|
||||
ra_items.o: ../../../h/em_spec.h
|
||||
ra_items.o: ../share/alloc.h
|
||||
ra_items.o: ../share/aux.h
|
||||
ra_items.o: ../share/debug.h
|
||||
ra_items.o: ../share/def.h
|
||||
ra_items.o: ../share/global.h
|
||||
ra_items.o: ../share/lset.h
|
||||
ra_items.o: ../share/types.h
|
||||
ra_items.o: itemtab.h
|
||||
ra_items.o: ra.h
|
||||
ra_items.o: ra_aux.h
|
||||
ra_items.o: ra_items.h
|
||||
ra_lifet.o: ../../../h/em_mnem.h
|
||||
ra_lifet.o: ../../../h/em_pseu.h
|
||||
ra_lifet.o: ../../../h/em_reg.h
|
||||
ra_lifet.o: ../../../h/em_spec.h
|
||||
ra_lifet.o: ../share/alloc.h
|
||||
ra_lifet.o: ../share/aux.h
|
||||
ra_lifet.o: ../share/debug.h
|
||||
ra_lifet.o: ../share/def.h
|
||||
ra_lifet.o: ../share/global.h
|
||||
ra_lifet.o: ../share/lset.h
|
||||
ra_lifet.o: ../share/types.h
|
||||
ra_lifet.o: ra.h
|
||||
ra_lifet.o: ra_aux.h
|
||||
ra_lifet.o: ra_items.h
|
||||
ra_lifet.o: ra_lifet.h
|
||||
ra_pack.o: ../../../h/em_reg.h
|
||||
ra_pack.o: ../share/alloc.h
|
||||
ra_pack.o: ../share/aux.h
|
||||
ra_pack.o: ../share/cset.h
|
||||
ra_pack.o: ../share/debug.h
|
||||
ra_pack.o: ../share/def.h
|
||||
ra_pack.o: ../share/global.h
|
||||
ra_pack.o: ../share/lset.h
|
||||
ra_pack.o: ../share/types.h
|
||||
ra_pack.o: ra.h
|
||||
ra_pack.o: ra_aux.h
|
||||
ra_pack.o: ra_interv.h
|
||||
ra_profits.o: ../../../h/em_reg.h
|
||||
ra_profits.o: ../share/debug.h
|
||||
ra_profits.o: ../share/global.h
|
||||
ra_profits.o: ../share/lset.h
|
||||
ra_profits.o: ../share/types.h
|
||||
ra_profits.o: ra.h
|
||||
ra_profits.o: ra_aux.h
|
||||
ra_profits.o: ra_profits.h
|
||||
ra_xform.o: ../../../h/em_mes.h
|
||||
ra_xform.o: ../../../h/em_mnem.h
|
||||
ra_xform.o: ../../../h/em_pseu.h
|
||||
ra_xform.o: ../../../h/em_reg.h
|
||||
ra_xform.o: ../../../h/em_spec.h
|
||||
ra_xform.o: ../share/alloc.h
|
||||
ra_xform.o: ../share/aux.h
|
||||
ra_xform.o: ../share/debug.h
|
||||
ra_xform.o: ../share/def.h
|
||||
ra_xform.o: ../share/global.h
|
||||
ra_xform.o: ../share/lset.h
|
||||
ra_xform.o: ../share/types.h
|
||||
ra_xform.o: ra.h
|
||||
ra_xform.o: ra_interv.h
|
||||
ra_xform.o: ra_items.h
|
||||
ra_xform.o: ra_xform.h
|
||||
@@ -1,21 +0,0 @@
|
||||
op_cal PROC_ADDR 12
|
||||
op_dee GLOBL_ADDR 8
|
||||
op_del LOCALVAR 8
|
||||
op_ine GLOBL_ADDR 7
|
||||
op_inl LOCALVAR 7
|
||||
op_lae GLOBL_ADDR 2
|
||||
op_lal LOCAL_ADDR 2
|
||||
op_ldc DCONST 11
|
||||
op_lde GLOBL_ADDR 3
|
||||
op_ldl LOCALVAR 3
|
||||
op_lil LOCALVAR 1
|
||||
op_loc CONST 10
|
||||
op_loe GLOBL_ADDR 0
|
||||
op_lol LOCALVAR 0
|
||||
op_sde GLOBL_ADDR 6
|
||||
op_sdl LOCALVAR 6
|
||||
op_sil LOCALVAR 5
|
||||
op_ste GLOBL_ADDR 4
|
||||
op_stl LOCALVAR 4
|
||||
op_zre GLOBL_ADDR 9
|
||||
op_zrl LOCALVAR 9
|
||||
@@ -1,77 +0,0 @@
|
||||
#include <stdio.h>
|
||||
|
||||
/* MAKE ITEMS TABLE
|
||||
*
|
||||
* This program is used by the register allocation phase of the optimizer
|
||||
* to make the file itemtab.h. It reads two files:
|
||||
* - the em_mnem.h file, containing the definitions of the
|
||||
* EM mnemonics
|
||||
* - the item-file, containing tuples:
|
||||
* (mnemonic, item_type)
|
||||
* The output (standard output) is a C array.
|
||||
*/
|
||||
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
convert(mnemfile,itemfile)
|
||||
FILE *mnemfile, *itemfile;
|
||||
{
|
||||
char mnem1[20], mnem2[20],def[20],itemtype[20];
|
||||
int newcl,opc,index;
|
||||
|
||||
newcl = TRUE;
|
||||
printf("struct item_descr itemtab[] = {\n");
|
||||
for (;;) {
|
||||
fscanf(mnemfile,"%s%s%d",def,mnem1,&opc);
|
||||
/* read a line like "#define op_aar 1" */
|
||||
if (feof(mnemfile)) break;
|
||||
if (strcmp(def,"#define") != 0) {
|
||||
error("bad mnemonic file, #define expected");
|
||||
}
|
||||
if (newcl) {
|
||||
fscanf(itemfile,"%s%s%d",mnem2,itemtype,&index);
|
||||
/* read a line like "op_loc CONST 4" */
|
||||
}
|
||||
if (feof(itemfile) || strcmp(mnem1,mnem2) != 0) {
|
||||
/* there is no line for this mnemonic, so
|
||||
* it has no type.
|
||||
*/
|
||||
printf("{NO_ITEM,0},\n");
|
||||
newcl = FALSE;
|
||||
} else {
|
||||
printf("{%s,%d},\n",itemtype,index);
|
||||
newcl = TRUE;
|
||||
}
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
error(s)
|
||||
char *s;
|
||||
{
|
||||
fprintf(stderr,"%s\n",s);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
FILE *f1,*f2;
|
||||
|
||||
if (argc != 3) {
|
||||
error("usage: makeitems mnemfile itemfile");
|
||||
}
|
||||
if ((f1 = fopen(argv[1],"r")) == NULL) {
|
||||
error("cannot open mnemonic file");
|
||||
}
|
||||
if ((f2 = fopen(argv[2],"r")) == NULL) {
|
||||
error("cannot open item file");
|
||||
}
|
||||
convert(f1,f2);
|
||||
}
|
||||
548
util/ego/ra/ra.c
548
util/ego/ra/ra.c
@@ -1,548 +0,0 @@
|
||||
/*
|
||||
* R E G I S T E R A L L O C A T I O N
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/files.h"
|
||||
#include "../share/get.h"
|
||||
#include "../share/put.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/map.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/go.h"
|
||||
#include "../../../h/em_reg.h"
|
||||
#include "ra.h"
|
||||
#include "ra_items.h"
|
||||
#include "ra_allocl.h"
|
||||
#include "ra_profits.h"
|
||||
#include "ra_pack.h"
|
||||
#include "ra_xform.h"
|
||||
|
||||
|
||||
#define newrabx() (bext_p) newstruct(bext_ra)
|
||||
#define newralpx() (lpext_p) newstruct(lpext_ra)
|
||||
#define oldrabx(x) oldstruct(bext_ra,x)
|
||||
#define oldralpx(x) oldstruct(lpext_ra,x)
|
||||
|
||||
short alloc_id;
|
||||
static item_p items[NRITEMTYPES];
|
||||
int nrinstrs;
|
||||
line_p *instrmap;
|
||||
|
||||
cond_p alocaltab[NRREGTYPES][NRREGTYPES],alocaddrtab[NRREGTYPES][NRREGTYPES],
|
||||
aconsttab,adconsttab,aglobaltab,aproctab;
|
||||
cond_p olocaltab[NRREGTYPES],olocaddrtab[NRREGTYPES],
|
||||
oconsttab,odconsttab,oglobaltab,oproctab;
|
||||
cond_p regsav_cost;
|
||||
|
||||
short regs_available[] = {
|
||||
/* Actually machine dependent; this is for vax2 */
|
||||
3, /* reg_any i.e. data regs */
|
||||
0, /* reg_loop */
|
||||
3, /* reg_pointer i.e. address reg. */
|
||||
0 /* reg_float */
|
||||
} ;
|
||||
|
||||
STATIC cond_p getcondtab(f)
|
||||
FILE *f;
|
||||
{
|
||||
int l,i;
|
||||
cond_p tab;
|
||||
|
||||
fscanf(f,"%d",&l);
|
||||
tab = newcondtab(l);
|
||||
for (i = 0; i < l; i++) {
|
||||
fscanf(f,"%hd %hd %hd",&tab[i].mc_cond,&tab[i].mc_tval,
|
||||
&tab[i].mc_sval);
|
||||
}
|
||||
assert(tab[l-1].mc_cond == DEFAULT);
|
||||
return tab;
|
||||
}
|
||||
|
||||
get_atab(f,tab)
|
||||
FILE *f;
|
||||
cond_p tab[NRREGTYPES][NRREGTYPES];
|
||||
{
|
||||
int i,cnt,totyp,regtyp;
|
||||
|
||||
fscanf(f,"%d",&cnt);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
fscanf(f,"%d %d",®typ,&totyp);
|
||||
assert(regtyp >= 0 && regtyp < NRREGTYPES);
|
||||
assert(totyp >= 0 && totyp < NRREGTYPES);
|
||||
tab[regtyp][totyp] = getcondtab(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
get_otab(f,tab)
|
||||
FILE *f;
|
||||
cond_p tab[NRREGTYPES];
|
||||
{
|
||||
int i,cnt,regtyp;
|
||||
|
||||
fscanf(f,"%d",&cnt);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
fscanf(f,"%d",®typ);
|
||||
assert(regtyp >= 0 && regtyp < NRREGTYPES);
|
||||
tab[regtyp] = getcondtab(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC ra_machinit(f)
|
||||
FILE *f;
|
||||
{
|
||||
/* Read target machine dependent information for this phase */
|
||||
char s[100];
|
||||
|
||||
for (;;) {
|
||||
while(getc(f) != '\n');
|
||||
fscanf(f,"%s",s);
|
||||
if (strcmp(s,"%%RA") == 0)break;
|
||||
}
|
||||
fscanf(f,"%hd",®s_available[reg_any]);
|
||||
fscanf(f,"%hd",®s_available[reg_pointer]);
|
||||
fscanf(f,"%hd",®s_available[reg_float]);
|
||||
get_atab(f,alocaltab);
|
||||
get_atab(f,alocaddrtab);
|
||||
aconsttab = getcondtab(f);
|
||||
adconsttab = getcondtab(f);
|
||||
aglobaltab = getcondtab(f);
|
||||
aproctab = getcondtab(f);
|
||||
get_otab(f,olocaltab);
|
||||
get_otab(f,olocaddrtab);
|
||||
oconsttab = getcondtab(f);
|
||||
odconsttab = getcondtab(f);
|
||||
oglobaltab = getcondtab(f);
|
||||
oproctab = getcondtab(f);
|
||||
regsav_cost = getcondtab(f);
|
||||
}
|
||||
|
||||
|
||||
STATIC bblock_p header(lp)
|
||||
loop_p lp;
|
||||
{
|
||||
/* Try to determine the 'header' block of loop lp.
|
||||
* If 'e' is the entry block of loop L, then block 'b' is
|
||||
* called the header block of L, iff:
|
||||
* SUCC(b) = {e} & PRED(e) = {b}
|
||||
* If lp has no header block, 0 is returned.
|
||||
*/
|
||||
|
||||
bblock_p x = lp->lp_entry->b_idom;
|
||||
|
||||
if (x != (bblock_p) 0 && Lnrelems(x->b_succ) == 1 &&
|
||||
(bblock_p) Lelem(Lfirst(x->b_succ)) == lp->lp_entry) {
|
||||
return x;
|
||||
}
|
||||
return (bblock_p) 0;
|
||||
}
|
||||
|
||||
|
||||
STATIC ra_extproc(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Allocate the extended data structures for procedure p */
|
||||
|
||||
register loop_p lp;
|
||||
register Lindex pi;
|
||||
register bblock_p b;
|
||||
|
||||
for (pi = Lfirst(p->p_loops); pi != (Lindex) 0;
|
||||
pi = Lnext(pi,p->p_loops)) {
|
||||
lp = (loop_p) Lelem(pi);
|
||||
lp->lp_extend = newralpx();
|
||||
lp->LP_HEADER = header(lp);
|
||||
}
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
b->b_extend = newrabx();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
STATIC ra_cleanproc(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Allocate the extended data structures for procedure p */
|
||||
|
||||
register loop_p lp;
|
||||
register Lindex pi;
|
||||
register bblock_p b;
|
||||
|
||||
for (pi = Lfirst(p->p_loops); pi != (Lindex) 0;
|
||||
pi = Lnext(pi,p->p_loops)) {
|
||||
lp = (loop_p) Lelem(pi);
|
||||
oldralpx(lp->lp_extend);
|
||||
}
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
oldrabx(b->b_extend);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC loop_blocks(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Compute the LP_BLOCKS sets for all loops of p */
|
||||
|
||||
register bblock_p b;
|
||||
register Lindex i;
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
for (i = Lfirst(b->b_loops); i != (Lindex) 0;
|
||||
i = Lnext(i,b->b_loops)) {
|
||||
Ladd(b,&(((loop_p) Lelem(i))->LP_BLOCKS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
STATIC make_instrmap(p,map)
|
||||
proc_p p;
|
||||
line_p map[];
|
||||
{
|
||||
/* make the instructions map of procedure p */
|
||||
|
||||
register bblock_p b;
|
||||
register line_p l;
|
||||
register int i = 0;
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
b->B_BEGIN = i; /* number of first instruction */
|
||||
for (l = b->b_start; l != (line_p) 0; l = l->l_next) {
|
||||
map[i++] = l;
|
||||
}
|
||||
b->B_END = i-1; /* number of last instruction */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool useful_item(item)
|
||||
item_p item;
|
||||
{
|
||||
/* See if it may be useful to put the item in a register.
|
||||
* A local variable that is not a parameter may always be put
|
||||
* in a register (as it need not be initialized).
|
||||
* Other items must be used at least twice.
|
||||
*/
|
||||
|
||||
int nruses = Lnrelems(item->it_usage);
|
||||
assert (nruses > 0); /* otherwise it would not be an item! */
|
||||
return nruses > 1 || (item->it_type == LOCALVAR &&
|
||||
item->i_t.it_off < 0);
|
||||
}
|
||||
|
||||
|
||||
STATIC item_p cat_items(items)
|
||||
item_p items[];
|
||||
{
|
||||
/* Make one item list out of an array of itemlists.
|
||||
* Remove items that are used only once.
|
||||
*/
|
||||
|
||||
register item_p it;
|
||||
item_p *ip,head,next;
|
||||
int t;
|
||||
|
||||
|
||||
ip = &head;
|
||||
for (t = 0; t < NRITEMTYPES;t++) {
|
||||
for ( it = items[t]; it != (item_p) 0; it = next) {
|
||||
next = it->it_next;
|
||||
if (!it->it_desirable || !useful_item(it)) {
|
||||
cleantimeset(it->it_usage);
|
||||
olditem(it);
|
||||
} else {
|
||||
*ip = it;
|
||||
ip = &it->it_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
*ip = (item_p) 0;
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
STATIC clean_interval(list)
|
||||
interv_p list;
|
||||
{
|
||||
register interv_p x,next;
|
||||
|
||||
for (x = list; x != (interv_p) 0; x = next) {
|
||||
next = x->i_next;
|
||||
oldinterval(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC cleantimeset(s)
|
||||
lset s;
|
||||
{
|
||||
register Lindex i;
|
||||
register time_p t;
|
||||
|
||||
for (i = Lfirst(s); i != (Lindex) 0; i = Lnext(i,s)) {
|
||||
t = (time_p) Lelem(i);
|
||||
oldtime(t);
|
||||
}
|
||||
Ldeleteset(s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC clean_allocs(list)
|
||||
alloc_p list;
|
||||
{
|
||||
register alloc_p x,next;
|
||||
|
||||
for (x = list; x != (alloc_p) 0; x = next) {
|
||||
next = x->al_next;
|
||||
clean_interval(x->al_timespan);
|
||||
Cdeleteset(x->al_rivals);
|
||||
Ldeleteset(x->al_inits);
|
||||
clean_interval(x->al_busy);
|
||||
clean_allocs(x->al_mates);
|
||||
oldalloc(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC cleanitems(list)
|
||||
item_p list;
|
||||
{
|
||||
register item_p x,next;
|
||||
|
||||
for (x = list; x != (item_p) 0; x = next ) {
|
||||
next = x->it_next;
|
||||
cleantimeset(x->it_usage);
|
||||
olditem(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ra_initialize()
|
||||
{
|
||||
init_replacements(ps,ws);
|
||||
}
|
||||
|
||||
|
||||
ra_optimize(p)
|
||||
proc_p p;
|
||||
{
|
||||
item_p itemlist;
|
||||
alloc_p alloclist,packed,unpacked;
|
||||
offset locls;
|
||||
bool time_opt = (time_space_ratio == 100);
|
||||
|
||||
ra_extproc(p);
|
||||
loop_blocks(p);
|
||||
alloc_id =0;
|
||||
locls = p->p_localbytes;
|
||||
build_itemlist(p,items,&nrinstrs);
|
||||
instrmap = (line_p *) newmap(nrinstrs-1); /* map starts counting at 0 */
|
||||
make_instrmap(p,instrmap);
|
||||
build_lifetimes(items);
|
||||
/* print_items(items,p); */
|
||||
/* statistics(items); */
|
||||
itemlist = cat_items(items); /* make one list */
|
||||
alloclist = build_alloc_list(p,Lnrelems(p->p_loops),
|
||||
itemlist);
|
||||
build_rivals_graph(alloclist);
|
||||
compute_profits(alloclist,time_opt);
|
||||
/* print_allocs(alloclist); */
|
||||
pack(alloclist,time_opt,&packed,&unpacked,p);
|
||||
stat_regusage(packed);
|
||||
xform_proc(p,packed,nrinstrs,instrmap);
|
||||
/* print_allocs(packed); */
|
||||
p->p_localbytes = locls;
|
||||
/* don't really allocate dummy local variables! */
|
||||
rem_locals(p,packed);
|
||||
rem_formals(p,packed);
|
||||
/* remove storage for real locals that
|
||||
*are always put in register .
|
||||
*/
|
||||
clean_allocs(unpacked);
|
||||
clean_allocs(packed);
|
||||
cleanitems(itemlist);
|
||||
oldmap(instrmap,nrinstrs-1);
|
||||
ra_cleanproc(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
go(argc,argv,ra_initialize,ra_optimize,ra_machinit,no_action);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
/***************************************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
/* debugging stuff */
|
||||
|
||||
|
||||
|
||||
char *str_types[] = {
|
||||
"local variable",
|
||||
"addr. of local",
|
||||
"addr. of external",
|
||||
"addr. of procedure",
|
||||
"constant",
|
||||
"double constant"
|
||||
};
|
||||
|
||||
char *str_regtypes[] = {
|
||||
"any",
|
||||
"loop",
|
||||
"pointer",
|
||||
"float"
|
||||
};
|
||||
|
||||
|
||||
print_items(items,p)
|
||||
item_p items[];
|
||||
proc_p p;
|
||||
{
|
||||
int t;
|
||||
item_p item;
|
||||
interv_p iv;
|
||||
|
||||
printf("BEGIN PROCEDURE %d\n",p->p_id);
|
||||
for (t = 0; t < NRITEMTYPES;t++) {
|
||||
for (item = items[t]; item != (item_p) 0;item = item->it_next) {
|
||||
printf("\nitemtype = %s\n",str_types[t]);
|
||||
if (t == GLOBL_ADDR) {
|
||||
printf("id of external = %d\n",
|
||||
item->i_t.it_obj->o_id);
|
||||
} else {
|
||||
printf("offset = %D\n",
|
||||
item->i_t.it_off);
|
||||
}
|
||||
printf("regtype = %s\n",str_regtypes[item->it_regtype]);
|
||||
printf("size = %d\n",item->it_size);
|
||||
printf("#usages = %d\n", Lnrelems(item->it_usage));
|
||||
printf("lifetime = {");
|
||||
for (iv = item->it_lives; iv != (interv_p) 0;
|
||||
iv = iv->i_next) {
|
||||
printf("(%d,%d) ",iv->i_start,iv->i_stop);
|
||||
}
|
||||
printf("} \n");
|
||||
}
|
||||
}
|
||||
printf("END PROCEDURE %d\n\n",p->p_id);
|
||||
}
|
||||
|
||||
|
||||
print_allocs(list)
|
||||
alloc_p list;
|
||||
{
|
||||
alloc_p al,m;
|
||||
item_p item;
|
||||
short t;
|
||||
interv_p iv;
|
||||
|
||||
fprintf(stderr,"BEGIN ALLOCLIST of proc %d\n",curproc->p_id);
|
||||
for (m = list ; m != (alloc_p) 0; m = m->al_next) {
|
||||
for (al = m; al != (alloc_p) 0; al = al->al_mates) {
|
||||
item = al->al_item;
|
||||
t = item->it_type;
|
||||
fprintf(stderr,"\nitem: [type = %s, ",str_types[t]);
|
||||
switch(t) {
|
||||
case GLOBL_ADDR:
|
||||
fprintf(stderr,"id = %d]\n", item->i_t.it_obj->o_id);
|
||||
break;
|
||||
case PROC_ADDR:
|
||||
fprintf(stderr,"id = %d]\n", item->i_t.it_proc->p_id);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"offset = %D]\n", item->i_t.it_off);
|
||||
}
|
||||
fprintf(stderr,"#usages(static) = %d\n",al->al_susecount);
|
||||
fprintf(stderr,"#usages(dyn) = %d\n",al->al_dusecount);
|
||||
fprintf(stderr,"#inits = %d\n",Lnrelems(al->al_inits));
|
||||
fprintf(stderr,"timespan = {");
|
||||
for (iv = al->al_timespan; iv != (interv_p) 0;
|
||||
iv = iv->i_next) {
|
||||
fprintf(stderr,"(%d,%d) ",iv->i_start,iv->i_stop);
|
||||
}
|
||||
fprintf(stderr,"} \n");
|
||||
fprintf(stderr,"busy = {");
|
||||
for (iv = al->al_busy; iv != (interv_p) 0;
|
||||
iv = iv->i_next) {
|
||||
fprintf(stderr,"(%d,%d) ",iv->i_start,iv->i_stop);
|
||||
}
|
||||
fprintf(stderr,"} \n");
|
||||
fprintf(stderr,"profits = %d\n",al->al_profits);
|
||||
fprintf(stderr,"dummy local = %D\n",al->al_dummy);
|
||||
fprintf(stderr,"regnr = %d\n",al->al_regnr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
short regs_needed[4];
|
||||
stat_regusage(list)
|
||||
alloc_p list;
|
||||
{
|
||||
int i;
|
||||
alloc_p x;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
regs_needed[i] = 0;
|
||||
}
|
||||
for (x = list; x != (alloc_p) 0; x = x->al_next) {
|
||||
regs_needed[x->al_regtype]++;
|
||||
}
|
||||
/* printf("data regs:%d\n",regs_needed[reg_any]); */
|
||||
/* printf("address regs:%d\n",regs_needed[reg_pointer]); */
|
||||
}
|
||||
|
||||
|
||||
|
||||
int cnt_regtypes[reg_float+1];
|
||||
|
||||
statistics(items)
|
||||
item_p items[];
|
||||
{
|
||||
register item_p item,next;
|
||||
int t,r;
|
||||
int cnt;
|
||||
|
||||
printf("\nSTATISTICS\n");
|
||||
for (r = 0; r <= reg_float; r++) cnt_regtypes[r] = 0;
|
||||
for (t = 0; t < NRITEMTYPES;t++) {
|
||||
cnt = 0;
|
||||
for (item = items[t]; item != (item_p) 0;item = next) {
|
||||
if (useful_item(item)) {
|
||||
cnt++;
|
||||
cnt_regtypes[item->it_regtype]++;
|
||||
}
|
||||
next = item->it_next;
|
||||
}
|
||||
printf("#%s = %d\n",str_types[t],cnt);
|
||||
}
|
||||
for (r = 0; r <= reg_float; r++) {
|
||||
printf("#%s = %d\n",str_regtypes[r],cnt_regtypes[r]);
|
||||
}
|
||||
}
|
||||
136
util/ego/ra/ra.h
136
util/ego/ra/ra.h
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* R E G I S T E R A L L O C A T I O N
|
||||
*
|
||||
*/
|
||||
|
||||
/* TEMPORARY: should be put in ../../../h/em_mes.h: */
|
||||
#define ms_liv 9
|
||||
#define ms_ded 10
|
||||
|
||||
#define INFINITE 10000
|
||||
#define NRREGTYPES (reg_float+1)
|
||||
|
||||
extern int nrinstrs; /* number of instructions of current procedure */
|
||||
extern line_p *instrmap;
|
||||
/* Dynamic array: instrmap[i] points to i'th instruction */
|
||||
|
||||
extern cond_p alocaltab[NRREGTYPES][NRREGTYPES],
|
||||
alocaddrtab[NRREGTYPES][NRREGTYPES], aconsttab,
|
||||
adconsttab,aglobaltab,aproctab;
|
||||
extern cond_p olocaltab[NRREGTYPES],olocaddrtab[NRREGTYPES],
|
||||
oconsttab,odconsttab,oglobaltab,oproctab;
|
||||
extern cond_p regsav_cost;
|
||||
|
||||
/* Register Allocation */
|
||||
typedef struct item *item_p;
|
||||
typedef struct allocation *alloc_p;
|
||||
typedef struct interval *interv_p;
|
||||
typedef struct time *time_p;
|
||||
|
||||
|
||||
|
||||
|
||||
extern short regs_available[]; /* contains #registers of every type */
|
||||
|
||||
|
||||
/* A thing that can be put in a register is called an "item". The are several
|
||||
* types of items: a local variable, the address of a local variable,
|
||||
* the address of a global variable, the address of a procedure,
|
||||
* a word-size constant and a doubleword- size constant.
|
||||
*/
|
||||
|
||||
#define LOCALVAR 0
|
||||
#define LOCAL_ADDR 1
|
||||
#define GLOBL_ADDR 2
|
||||
#define PROC_ADDR 3
|
||||
#define CONST 4
|
||||
#define DCONST 5
|
||||
|
||||
#define NO_ITEM 6
|
||||
#define NRITEMTYPES 6
|
||||
|
||||
struct item {
|
||||
item_p it_next; /* link to next item is list */
|
||||
short it_type; /* its type; see above */
|
||||
short it_regtype; /* preferred type of register */
|
||||
short it_size; /* its size (in bytes) */
|
||||
short it_lastlive; /* temporary, used to build livetime */
|
||||
lset it_usage; /* all points in text where item is used*/
|
||||
interv_p it_lives; /* intervals during which item is live */
|
||||
bool it_desirable; /* should this item be put in reg.? */
|
||||
union {
|
||||
obj_p it_obj; /* for GLOBL_ADDR */
|
||||
proc_p it_proc; /* for PROC_ADDR */
|
||||
offset it_off; /* for others */
|
||||
} i_t;
|
||||
};
|
||||
|
||||
|
||||
/* A 'point in time' is defined by a (line,basic block) pair */
|
||||
|
||||
struct time {
|
||||
line_p t_line; /* point in EM text */
|
||||
bblock_p t_bblock; /* its basic block */
|
||||
};
|
||||
|
||||
|
||||
struct interval {
|
||||
short i_start; /* number of first instruction */
|
||||
short i_stop; /* number of last instruction */
|
||||
interv_p i_next;
|
||||
};
|
||||
|
||||
|
||||
/* An item may be put in a register for the duration of a whole procedure
|
||||
* or part of a procedure (e.g. a loop). So a possible "allocation" looks
|
||||
* like: put item X in a register during the timespan T (which is a subset
|
||||
* of the timespan of the entire procedure). The packing process deals
|
||||
* with allocations, rather than items. One item may be part of several
|
||||
* possible allocations.
|
||||
*/
|
||||
|
||||
struct allocation {
|
||||
item_p al_item; /* the item to be put in a register */
|
||||
short al_id; /* unique identifying number */
|
||||
short al_regtype; /* the register type to be used */
|
||||
interv_p al_timespan; /* timespan during which item is in reg. */
|
||||
short al_profits; /* gains of putting item in register */
|
||||
cset al_rivals; /* set of allocations competing with it */
|
||||
short al_susecount; /* #usages during timespan (statically) */
|
||||
short al_dusecount; /* #usages (dynamically, estimate) */
|
||||
lset al_inits; /* points where reg. must be initialized */
|
||||
interv_p al_busy; /* used to compute rivals */
|
||||
short al_regnr; /* register nr.,if it is granted a reg. */
|
||||
offset al_dummy; /* dummy local variable,if granted a reg */
|
||||
alloc_p al_mates; /* link to allocations packed in same reg */
|
||||
alloc_p al_wholeproc; /* alloc. for whole proc as timespan */
|
||||
short al_cntrivals; /* # unpacked rivals ; used for cost estim. */
|
||||
bool al_isloop; /* true if timespan consists of loop */
|
||||
bool al_iswholeproc;/*true if timespan consists of whole proc*/
|
||||
alloc_p al_next; /* link to next one in a list */
|
||||
};
|
||||
|
||||
extern short alloc_id; /* last al_id used for current procedure */
|
||||
|
||||
#define LP_BLOCKS lp_extend->lpx_ra.lpx_blocks
|
||||
#define LP_HEADER lp_extend->lpx_ra.lpx_header
|
||||
#define B_BEGIN b_extend->bx_ra.bx_begin
|
||||
#define B_END b_extend->bx_ra.bx_end
|
||||
|
||||
#define DLINK(l1,l2) l1->l_next=l2; l2->l_prev=l1
|
||||
|
||||
struct item_descr {
|
||||
int id_type;
|
||||
int id_replindex;
|
||||
} ;
|
||||
|
||||
extern struct item_descr itemtab[];
|
||||
|
||||
#define newalloc() (alloc_p) newstruct(allocation)
|
||||
#define oldalloc(a) oldstruct(allocation,a)
|
||||
#define newitem() (item_p) newstruct(item)
|
||||
#define olditem(i) oldstruct(item,i)
|
||||
#define newtime() (time_p) newstruct(time)
|
||||
#define oldtime(t) oldstruct(time,t)
|
||||
#define newinterval() (interv_p) newstruct(interval)
|
||||
#define oldinterval(i) oldstruct(interval,i)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user