|
|
researchv9-SUN3(old)
/* @(#) local.c: 1.5 6/26/84 */
/* # include <ctype.h> -- optim.h takes care of this */
# include "optim.h"
# include "sgs.h"
# include "paths.h"
# define ASDATE ""
# define LINELEN 400
# define FATAL(S) fatal((S), (char *) 0)
char fixstr[256];
char line[LINELEN];
char * linptr; /* pointer to current line */
int fixlen;
char * deflab;
int opn;
int m;
int numauto; /* number of bytes of automatic vars. */
int numnreg; /* number of registers */
boolean indata;
int lineno = IDVAL;
int nusel = 0; /* semantically useless instructions */
int nspinc = 0; /* useless sp increments */
int nmc = 0; /* move followed by compare */
int nmal = 0; /* move followed by arithmetic or logical */
int nredcmp = 0; /* redundant compares */
int nadpsh = 0; /* addw3 or subw3 followed by push */
int nadmsh = 0; /* addw3 or subw3 followed by mov */
int nadmv = 0; /* replace addw3 or subw3 by mov */
extern int ndisc;
#ifdef IMPIL
zflag = false; /* debug flag for in--line expansion */
#endif /* IMPIL */
# define numops 151
char *optbl[numops] = {
"acjl","acjle","acjleu","acjlu",
"addb2","addb3","addh2","addh3","addw2",
"addw3","alsw2","alsw3","andb2","andb3",
"andh2","andh3","andw2","andw3","arsw2",
"arsw3","atjnzb","atjnzh","atjnzw","bitw",
"call","cmpb","cmph","cmpw",
"decpth","decptw","divw2",
"divw3","extzv","faddd2","faddd3","fadds2",
"fadds3","fcmpd","fdivd2","fdivd3","fdivs2",
"fdivs3","fmuld2","fmuld3","fmuls2","fmuls3",
"fsubd2","fsubd3","fsubs2","fsubs3",
"incpth","incptw","inctst","insv",
"jbc","jbs","je","jg","jge",
"jgeu","jgu","jl","jle","jleu",
"jlu","jmp","jne","jneg","jnneg",
"jnpos","jnz","jpos","jsb","jz",
"llsw2","llsw3","lrsw2","lrsw3","mcomb",
"mcomh","mcomw","mnegb","mnegh","mnegw",
"modw2","modw3","movab","movah","movaw",
"movb","movbbh","movbbw","movbhw","movblb",
"movblh","movblw","movd","movdd","movds","movdw","movh",
"movsd","movsw","movtdw","movthb","movtsw",
"movtwb","movtwh","movw","movwd","movws",
"movzbh","movzbw","movzhw","mulw2","mulw3",
"orb2","orb3","orh2","orh3","orw2",
"orw3","pushaw","pushbb","pushbh",
"pushd","pushw","pushzb","pushzh","ret","save","subb2",
"subb3","subh2","subh3","subw2","subw3",
"switch","switcht",
"udivw2","udivw3","umodw2","umodw3","umulw2",
"umulw3","xorb2","xorb3","xorh2","xorh3",
"xorw2","xorw3"
};
FILE *stmpfile; /* Temporary storage for strings which are in the text
* section. The strings are collected and printed at
* the end of a function. Requirement for field update */
extern char *mktemp();
FILE *tmpopen();
char tmpname[50]; /* name of file for storing string */
FILE *atmpfile; /* Temporary storage for input while scanning for presence of
* #ASM in function */
char atmpname[50];
int asmflag = false; /* indicates whether an 'asm' has been encountered */
long asmotell; /* location in the output file where the last function ended */
int oaflag = false; /* indicates whether -OA flag was entered */
boolean instring = false;
boolean inswitch = false;
#ifdef IMPIL
boolean swflag = false; /* switch table appears in function */
NODE *lblnode = NULL; /* pointer to last label node */
char *pcdecode();
#endif /* IMPIL */
yylex()
{
extern char * strchr();
register char * s; /* temporary string ptr */
register char * start; /* another temporary string ptr */
register int i; /* temporary int */
#ifdef IMPIL
ilinit();
#endif /* IMPIL */
asmopen(); /* open temp file for asm treatment */
linptr = NULL; /* start off with no line */
while (linptr != NULL ||
((linptr = fgets(line,LINELEN,stdin)) != NULL && putasm(line)))
{
switch (*linptr) /* dispatch on first char in line */
{
case '\n': /* ignore new line */
break;
case '#': /* check for special comments */
s = linptr + 1; /* look at comment only, not # */
if (strncmp(s,"STRBEG",6) == 0)
instring = true; /* declare we're in a string */
else if (strncmp(s,"STREND",6) == 0)
instring = false; /* now out of string-ness */
else if (strncmp(s,"SWBEG",5) == 0)
inswitch = swflag = true; /* now in a switch table */
else if (strncmp(s,"SWEND",5) == 0)
inswitch = false; /* out of switch table */
else if (strncmp(s,"ASM",3) == 0)
asmflag = true; /* 'asm' appears in function */
#ifdef IMPREGAL
else if (strncmp(s,"REGAL",5) == 0)
ratable( line ); /* register allocation opt */
#endif /* IMPREGAL */
break; /* in any case, ignore line further */
case '.': /* compiler label */
default: /* ordinary label */
if (indata) /* in data section, just print */
{
printf("%s",linptr);
break;
}
/* reach here on labels in text space */
s = strchr(linptr,':'); /* find : */
if (s == NULL) /* error if not found */
{ FATAL("Bad input format\n"); }
*s++ = '\0'; /* change : to null, skip past */
/* for N3B (DMERT), switch code and jump tables are in text space,
** but SWBEG, SWEND bracket just the table. For m32 and u3b, jump tables are
** always in data space.
** Write labels found when "inswitch" to special file for N3B only.
*/
#ifdef N3B
if (instring || inswitch) /* inside special string or switch... */
#else
if (instring) /* inside special string?... */
#endif /* def N3B */
{
putstr(linptr); /* write label to special file */
putstr(":\n"); /* put : back in */
}
else /* normal text space label */
{
applbl(linptr,s-linptr); /* append label node */
lastnode->uniqid = IDVAL;
}
linptr = s; /* continue processing past label */
continue; /* next iteration */
/* handle more usual case of line beginning with space/tab */
case ' ':
case '\t':
for (s = linptr; isspace(*s); s++) /* skip white space */
;
switch(*s) /* dispatch on next character */
{
case '\0': /* line of white space */
case '#': /* comment */
case '\n': /* new line */
break; /* ignore */
case '.': /* start of pseudo-op */
pseudo(s); /* do pseudo-ops */
break;
default: /* normal instruction */
if (indata) /* in data section this is weird case */
printf("%s",linptr); /* just write line */
else /* normal instruction in text */
{
for (start = s; ! isspace(*s); s++)
; /* skip over instruction mnemonic */
*s++ = '\0'; /* demarcate with null */
if ((opn = lookup(start)) == OTHER)
saveop(0,start,s-start,opn);
/* save funny instruction */
else
saveop(0,optbl[m],0,opn);
/* save normal inst. (m set by
** lookup)
*/
for ( ; isspace(*s); s++ )
; /* span white space */
opn = 1; /* now save operands */
op(s); /* skip intervening spaces/tabs */
}
/* remember program name */
#ifdef IMPIL
if( ntail.back->op == SAVE ) lblnode = ntail.back->back;
#endif /* IMPIL */
break;
} /* end space/tab case */
break;
} /* end first character switch */
linptr = NULL; /* indicate we're done with line */
} /* end while */
return; /* just exit */
}
op (s)
register char *s;
{
register char *t;
while (*s)
{
/* scan over leading space/tabs */
while (*s == ' ' || *s == '\t')
s++;
t = s; /* remember effective operand start */
while(*s != ',' && *s != '\n') /* find end of operand */
s++;
*s++ = '\0';
saveop(opn++, t, s-t, 0);
if (*t == '.') /* operand is a label */
if (inswitch)
addref(t, s-t);
}
lastnode->uniqid = lineno;
lineno = IDVAL;
}
pseudo (s)
register char *s; /* points at pseudo-op */
{
void peep(); /* peephole improver */
extern int cflag; /* independent part -c flag:
** enable/disable common tail
*/
register int pop; /* pseudo-op code */
char savechar; /* saved char that follows pseudo */
char * word = s; /* pointer to beginning of pseudo */
/* The idea here is to stick in a NUL after the pseudo-op, then replace
** the character we clobbered, rather than copy the pseudo-op somewhere else.
*/
for ( ; ! isspace(*s); s++ )
; /* scan to white space char */
savechar = *s; /* mark end of pseudo-op */
*s = '\0';
/* if we're in a data section, we write all pseudo-ops to output,
** except for .word's, which we must examine, and .text .
*/
pop = plookup(word); /* identify pseudo-op */
*s = savechar; /* restore saved character */
if (indata) { /* check pseudo-op possibilities */
if (pop == TEXT) {
indata = false; /* not in data section anymore */
return;
}
else if (pop != WORD) {
printf("%s",linptr); /* output the line */
return;
}
}
switch (pop) { /* dispatch on pseudo-op in text */
case BYTE:
putstr(linptr);
break;
case GLOBL:
case TV:
line[(m=length(line))-2] = '\0'; /* remove newline */
appfl(line, m-1);
break;
case TEXT:
indata = false;
break;
case FIL:
case BSS:
printf("%s", line);
break;
case LN:
getln(line);
break;
case ALIGN:
line[(m=length(line))-2] = '\0'; /* remove NL */
if (inswitch) {
#ifdef N3B /* for DMERT, put aligns in switch to special
** output file with switch table
*/
line[m-2] = '\n'; /* restore new line */
putstr(linptr);
#else
saveop(0, line+1, m-2, OTHER);
opn = 1;
lastnode->uniqid = lineno;
lineno = IDVAL;
#endif /* def N3B */
}
else
appfl(line, m-1);
break;
case SET:
if (*++s == '.' && *++s == 'F') {
printf("\t.text\n");
setauto(line);
printf("%s", line);
}
else if (s--, *s == '.' && *++s == 'R') {
setnreg(line);
line[(m=length(line))-2] = '\0';
appfl(line,m-1);
}
else {
line[(m=length(line))-2] = '\0';
appfl(line, m-1);
}
break;
case DATA:
printf("%s", line);
indata = true;
break;
case DEF: {
int found;
line[(m=length(line))-2] = '\0'; /* remove newline */
#ifdef IMPIL
while( isspace( *s ) ) s++;
if (*s++ == '.' && *s++ == 'e' &&
*s++ == 'f') { /* .ef */
appfl( "*", 2 );
if( lblnode == NULL )
{ FATAL( "No label preceeding .bf pseudo op, file may already be optimized\n" ); }
appfl( lblnode->ops[0],
length( lblnode->ops[0]));
}
s--;
#endif /* IMPIL */
found = 0;
while (true) {
while (*s++ != ';');
if (*(s += 2) == 'e') /* endef */
break;
/* There are two special cases for ".val". The first is
** ".val ." . Since we're going to move the .def line, we need
** to replace the '.' with a real label (which we make a hard label)
** first. The second special case is ".val .Lxxx" (a local label).
** This arises in the compiler from a user-defined label. The
** problem here is that if the optimizer discards the local label,
** there will be a reference to a non-existent label which will only
** show up at link time. To avoid this, we delete (ignore) the whole
** line.
*/
else if (*s++ == 'v') { /* .val */
if (s[3] == '.')
{
if (s[4] == ';') /* first case */
found = 1;
else if (s[4] == 'L')
found = 3; /* second */
}
}
else if (*s == 'c') /* .scl */
if (*(s+3) == '-' && *(s+4) == '1') {
found = 2;
break;
}
}
switch(found)
{
case 1: /* .val . */
deflab = (char *) newlab();
deffix(line, deflab);
appfl(fixstr, fixlen+1);
fixlbl(deflab);
applbl(deflab, length(deflab));
lastnode->op = HLABEL;
lastnode-> uniqid = IDVAL;
break;
case 2: /* end of function */
cflag = -1; /* turn off common tail
** merging: improve speed,
** not space.
*/
if( !asmflag || oaflag ) {
#ifdef IMPREGAL
numnreg = raoptim(numnreg, numauto);
numauto = raautos(numauto);
#endif /* IMPREGAL */
#ifdef IMPIL
ilmark();
#endif /* IMPIL */
filter();
optim();
peep(); /* do peephole improvements */
#ifdef IMPIL
ilstat(numnreg, numauto);
#endif /* IMPIL */
chkauto();
}
prtext();
prstr();
printf("%s", line);
printf("\n");
asmchk();
init();
break;
case 3: /* .val .Lxxx */
break; /* ignore line */
default: /* other .defs */
appfl(line, m-1);
break;
}
}
break;
case WORD:
s++; /* point past tab/nl */
/* we have to deal with whether .word is within a switch (SWBEG/SWEND) or
** not, and whether or not it appears in a data section.
*/
if (inswitch) { /* always add reference */
register char * t = strchr(s,'\n');
*t = '\0'; /* change NL to null */
addref(s,t+1-s); /* add the reference */
*t = '\n'; /* restore NL */
}
if (indata) /* in data, flush to output */
printf("%s",linptr); /* print line */
else if (inswitch) /* text (implicit) and switch */
putstr(linptr); /* flush to special file */
else { /* text, not in switch */
saveop(0,".word",6,OTHER);
opn = 1; /* doing first operand */
op(s);
}
break;
default: /* all unrecognized text
** pseudo-ops
*/
if (! (instring || inswitch))
printf("%s", linptr); /* flush to output */
else
putstr(linptr); /* in(switch|string): to
** special file
*/
break;
}
}
int
plookup(s) /* look up pseudo op code */
char *s;
{
/* Note: to improve the linear search speed, these pseudo-ops
** are ordered by frequency of occurrence in a sample of C programs.
*/
static char *pops[numpops] =
{
".word", ".byte", ".set", ".def", ".align",
".data", ".text", ".globl", ".ln", ".bss",
".file", ".tv"
};
static int popcode[numpops] =
{
WORD, BYTE, SET, DEF, ALIGN,
DATA, TEXT, GLOBL, LN, BSS,
FIL, TV
};
register int i;
for (i = 0; i < numpops; i++)
if (!strcmp(s, pops[i]))
return(popcode[i]);
return(POTHER);
}
yyinit(flags) char * flags; {
indata = false;
for (; *flags != '\0'; flags++) {
switch( *flags ) {
case 'V':
fprintf(stderr,"%s: optimizer - %s %s\n",
SGSNAME,RELEASE,ASDATE);
break;
case 'A':
oaflag = true;
break;
#ifdef IMPIL
case 'z':
zflag = true;
break;
#endif /* IMPIL */
default:
fprintf(stderr,"Optimizer: invalid flag '%c'\n",*flags);
}
}
}
char *
yysflgs( p ) char *p; { /* parse flags with sub fields */
switch( *p ) {
#ifdef IMPIL
case 'y':
p++; /* skip over 'y' to sub option */
p = pcdecode( p );
return( p );
#endif /* IMPIL */
default:
return( p );
}
}
int
lookup(op) char *op; { /* look up op code ordinal */
register int f,l,om,x;
static unsigned char ocode[numops] = {
ACJL,ACJLE,ACJLEU,ACJLU,
ADDB2,ADDB3,ADDH2,ADDH3,ADDW2,
ADDW3,ALSW2,ALSW3,ANDB2,ANDB3,
ANDH2,ANDH3,ANDW2,ANDW3,ARSW2,
ARSW3,ATJNZB,ATJNZH,ATJNZW,BITW,
CALL,CMPB,CMPH,CMPW,
DECPTH,DECPTW,DIVW2,
DIVW3,EXTZV,FADDD2,FADDD3,FADDS2,
FADDS3,FCMPD,FDIVD2,FDIVD3,FDIVS2,
FDIVS3,FMULD2,FMULD3,FMULS2,FMULS3,
FSUBD2,FSUBD3,FSUBS2,FSUBS3,
INCPTH,INCPTW,INCTST,INSV,
JBC,JBS,JE,JG,JGE,
JGEU,JGU,JL,JLE,JLEU,
JLU,JMP,JNE,JNEG,JNNEG,
JNPOS,JNZ,JPOS,JSB,JZ,
LLSW2,LLSW3,LRSW2,LRSW3,MCOMB,
MCOMH,MCOMW,MNEGB,MNEGH,MNEGW,
MODW2,MODW3,MOVAB,MOVAH,MOVAW,
MOVB,MOVBBH,MOVBBW,MOVBHW,MOVBLB,
MOVBLH,MOVBLW,MOVD,MOVDD,MOVDS,MOVDW,MOVH,
MOVSD,MOVSW,MOVTDW,MOVTHB,MOVTSW,
MOVTWB,MOVTWH,MOVW,MOVWD,MOVWS,
MOVZBH,MOVZBW,MOVZHW,MULW2,MULW3,
ORB2,ORB3,ORH2,ORH3,ORW2,
ORW3,PUSHAW,PUSHBB,PUSHBH,
PUSHD,PUSHW,PUSHZB,PUSHZH,RET,SAVE,SUBB2,
SUBB3,SUBH2,SUBH3,SUBW2,SUBW3,
SWITCH,SWITCHT,
UDIVW2,UDIVW3,UMODW2,UMODW3,UMULW2,
UMULW3,XORB2,XORB3,XORH2,XORH3,
XORW2,XORW3
};
f = 0;
l = numops;
om = 0;
m = (f+l)/2;
while (m != om) {
x = strcmp(op,optbl[m]);
if (x == 0)
return((int) ocode[m]);
else if (x < 0)
l = m-1;
else
f = m+1;
om = m;
m = (f+l)/2;
}
return(OTHER);
}
deffix(str,lbl) register char * str, * lbl; { /*change "val .;" to "val ..n;"*/
register char * nc;
register boolean scanning;
scanning = true;
nc = fixstr;
fixlen = 0;
while (scanning)
if (*str == '.' && *(str+1) == ';') {
str++;
scanning = false;
}
else {
*nc++ = *str++;
fixlen++;
}
while (*nc++ = *lbl++)
fixlen++;
nc--;
while (*nc++ = *str++)
fixlen++;
}
fixlbl(str) register char * str; { /* add colon to end of label */
while (*str++);
*--str = ':';
*++str = '\0';
}
int
length(str) register char * str; { /* return length of string (including \0) */
register int l;
l = 1;
while (*str++)
l++;
return (l);
}
getln(str) register char * str; { /* extract line number */
while (!isdigit(*str))
str++;
lineno = 0;
while (isdigit(*str)) {
lineno = lineno * 10 + *str - '0';
str++;
}
}
prinst(p) register NODE *p; { /* print instruction */
if (p->uniqid != IDVAL)
printf(" .ln %d\n", p->uniqid);
#ifdef IMPIL
if (p->op == CALL ) {
printf("@ %d %s %s\n",
numauto + ( int ) p->ops[MAXOPS], p->op1 + 1, p->op2 );
p->ops[MAXOPS] = NULL;
}
#endif /* IMPIL */
switch (p->op) {
case LABEL:
printf("%s:\n", p->opcode);
break;
case HLABEL:
printf("%s\n", p->opcode);
break;
case MISC:
printf(" %s\n", p->opcode);
break;
case RET:
if (*(p->op1 + 1) == '-') {
printf(" RET\n");
break;
}
default:
printf(" %s ", p->opcode);
if (p->op1 != NULL)
printf("%s", p->op1);
if (p->op2 != NULL)
printf(",%s", p->op2);
if (p->op3 != NULL)
printf(",%s", p->op3);
if (p->op4 != NULL)
printf(",%s", p->op4);
printf("\n");
break;
}
}
boolean
ishlp(p) register NODE *p; { /* return true if a fixed label present */
for (; (p->op == LABEL || p->op == HLABEL); p=p->forw)
if (ishl(p))
return(true);
return(false);
}
FILE *
tmpopen() {
strcpy( tmpname, TMPDIR );
strcat( tmpname, "/25ccXXXXXX" );
return( fopen( mktemp( tmpname ), "w" ) );
}
putstr(string) char *string; {
/* Place string from the text section into a temporary file
* to be output at the end of the function */
if( stmpfile == NULL )
stmpfile = tmpopen();
fprintf(stmpfile,"%s",string);
}
prstr() {
/* print the strings stored in stmpfile at the end of the function */
if( stmpfile != NULL ) {
register int c;
stmpfile = freopen( tmpname, "r", stmpfile );
if( stmpfile != NULL )
while( (c=getc(stmpfile)) != EOF )
putchar( c );
else
{
fprintf( stderr, "optimizer error: ");
fprintf( stderr, "lost temp file\n");
}
(void) fclose( stmpfile ); /* close and delete file */
unlink( tmpname );
stmpfile = NULL;
}
}
/* opens the temp file for storing input while looking for 'asm' */
asmopen() {
strcpy( atmpname, TMPDIR );
strcat( atmpname, "/asmXXXXXX" );
atmpfile = fopen( mktemp( atmpname ), "w" );
asmotell = ftell( stdout );
}
/* writes to temp file for 'asm' processing */
int
putasm( line )
char *line;
{
return( fputs( line, atmpfile ) != EOF );
}
/* checks for 'asm' in files and undoes code movement */
asmchk()
{
register c;
long endotell;
extern int vars;
if( asmflag && !oaflag ) {
if( freopen( atmpname, "r", atmpfile ) != NULL ) {
endotell = ftell( stdout );
fseek( stdout, asmotell, 0 ); /* This is okay as long
as IMPIL is defined because it
is not really stdout, it is the file used by
in-line expansion. That file is still used,
even when in-line expansion is suppressed.
If IMPIL is not defined, optim will not work
correctly to a terminal, but it will work
correctly to a file.
This should be fixed. (fbw) */
while( ( c = getc( atmpfile ) ) != EOF ) putchar( c );
while( ftell( stdout ) < endotell ) printf( "!\n" );
}
else fprintf( stderr, "optimizer error: asm temp file lost\n" );
}
freopen( atmpname, "w", atmpfile );
asmotell = ftell( stdout );
asmflag = false;
vars=0; /* reinitialize for global reg allocation */
}
putp(p,c) register NODE *p; char *c; { /* insert pointer into jump node */
if (p->op == CALL)
p->op2 = c;
else if (p->op == JBC || p->op == JBS)
p->op3 = c;
else if (p->op == RET) {
p->op1 = NULL;
p->op2 = c;
}
else
p->op1 = c;
}
revbr(p) NODE *p; { /* reverse jump in node p */
switch (p->op) {
case JZ: p->op = JNZ; p->opcode = "jnz"; break;
case JNZ: p->op = JZ; p->opcode = "jz"; break;
case JPOS: p->op = JNPOS; p->opcode = "jnpos"; break;
case JNPOS: p->op = JPOS; p->opcode = "jpos"; break;
case JNEG: p->op = JNNEG; p->opcode = "jnneg"; break;
case JNNEG: p->op = JNEG; p->opcode = "jneg"; break;
case JE: p->op = JNE; p->opcode = "jne"; break;
case JNE: p->op = JE; p->opcode = "je"; break;
case JL: p->op = JGE; p->opcode = "jge"; break;
case JLE: p->op = JG; p->opcode = "jg"; break;
case JG: p->op = JLE; p->opcode = "jle"; break;
case JGE: p->op = JL; p->opcode = "jl"; break;
case JLU: p->op = JGEU; p->opcode = "jgeu"; break;
case JLEU: p->op = JGU; p->opcode = "jgu"; break;
case JGU: p->op = JLEU; p->opcode = "jleu"; break;
case JGEU: p->op = JLU; p->opcode = "jlu"; break;
case JBC: p->op = JBS; p->opcode = "jbs"; break;
case JBS: p->op = JBC; p->opcode = "jbc"; break;
}
}
char *
dst(p) NODE *p; { /* return pointer to dst operand string */
switch (p->op) {
case ACJL: case ACJLU: case ACJLEU: case ATJNZB: case ATJNZH:
case ATJNZW: case INCTST:
case INCPTH: case INCPTW: case DECPTH: case DECPTW:
return (p->op1);
case MCOMB: case MCOMH: case MCOMW: case MOVZBH: case MOVZBW:
case MOVZHW: case MOVAB: case MOVAH: case MOVAW: case ANDB2:
case ANDH2: case ANDW2: case ORB2: case ORH2: case ORW2:
case XORB2: case XORH2: case XORW2: case MOVB: case MOVH:
case MOVW: case MOVBBH: case MOVBBW: case MOVBHW: case MOVTHB:
case MOVTWB: case MOVTWH: case MNEGB: case MNEGH: case MNEGW:
case ADDB2: case ADDH2: case ADDW2: case SUBB2: case SUBH2:
case SUBW2: case MULW2: case UMULW2: case DIVW2: case UDIVW2:
case MODW2: case UMODW2: case LLSW2: case LRSW2: case ALSW2:
case ARSW2: case FADDD2: case FSUBD2: case FMULD2: case FDIVD2:
case FADDS2: case FSUBS2: case FMULS2: case FDIVS2:
case MOVWS: case MOVWD: case MOVTSW: case MOVTDW:
case MOVSW: case MOVDW: case MOVSD: case MOVDS: case MOVDD:
case MOVD:
return(p->op2);
case ANDB3: case ANDH3: case ANDW3: case ORB3: case ORH3:
case ORW3: case XORB3: case XORH3: case XORW3: case LLSW3:
case LRSW3: case ADDB3: case ADDH3: case ADDW3: case SUBB3:
case SUBH3: case SUBW3: case MULW3: case UMULW3: case DIVW3:
case UDIVW3: case MODW3: case UMODW3: case ALSW3: case ARSW3:
case FADDD3: case FSUBD3: case FMULD3: case FDIVD3:
case FADDS3: case FSUBS3: case FMULS3: case FDIVS3:
return(p->op3);
case INSV: case EXTZV:
return(p->op4);
default:
return (NULL);
}
}
int
stype(cop) int cop; { /* return implied type of op code */
switch (cop) {
case MCOMB: case ANDB2: case ANDB3: case ORB2: case ORB3:
case XORB2: case XORB3: case MOVB: case MOVTHB: case MOVTWB:
case MNEGB: case ADDB2: case ADDB3: case SUBB2: case SUBB3:
case CMPB:
return (1);
case MCOMH: case MOVZBH: case ANDH2: case ANDH3: case ORH2:
case ORH3: case XORH2: case XORH3: case MOVH: case MOVBBH:
case MOVTWH: case MNEGH: case ADDH2: case ADDH3: case SUBH2:
case SUBH3: case CMPH:
return (2);
default:
return (4);
case FADDD2: case FSUBD2: case FMULD2: case FDIVD2:
case FADDD3: case FSUBD3: case FMULD3: case FDIVD3:
case FCMPD: case MOVSD: case MOVWD: case MOVDD:
return(8);
}
}
boolean
samereg(cp1,cp2) char *cp1, *cp2; { /* return true if same register */
if (*cp1 == '%' && *cp1 == *cp2 && *++cp1 == *++cp2 && *++cp1 == *++cp2)
return(true);
else
return(false);
}
boolean
usesreg(cp1,cp2) register char *cp1, *cp2; { /*return true if cp2 used in cp1*/
while(*cp1 != '\0') {
if (*cp1 == *cp2 && *(cp1+1) == *(cp2+1) &&
*(cp1+2) == *(cp2+2))
return(true);
cp1++;
}
return(false);
}
dstats() { /* print stats on machine dependent optimizations */
fprintf(stderr,"%d semantically useless instructions(s)\n", nusel);
fprintf(stderr,"%d useless move(s) before compare(s)\n", nmc);
fprintf(stderr,"%d merged move-arithmetic/logical(s)\n", nmal);
fprintf(stderr,"%d useless sp increment(s)\n", nspinc);
fprintf(stderr,"%d redundant compare(s)\n", nredcmp);
}
wrapup() { /* print unprocessed text and update statistics file */
FILE *fopen(), *sp;
int mc,mal,usel,spinc,redcmp,disc,inst;
if (n0.forw != NULL) {
printf(" .text\n");
filter();
prtext();
prstr();
}
#ifdef IMPIL
ilfile();
#endif /* IMPIL */
(void) fclose( atmpfile ); /* close and delete file */
unlink( atmpname );
sp = fopen("/g1/dap/optim/stats/statfile","r");
if (sp != NULL) {
fscanf(sp, "%d %d %d %d %d %d %d",
&mc,&mal,&usel,&spinc,&redcmp,&disc,&inst);
fclose(sp);
mc += nmc;
mal += nmal;
usel += nusel;
spinc += nspinc;
redcmp += nredcmp;
disc += ndisc;
inst += ninst;
sp = fopen("/g1/dap/optim/stats/statfile","w");
if (sp != NULL) {
fprintf(sp, "%d %d %d %d %d %d %d \n",
mc,mal,usel,spinc,redcmp,disc,inst);
fclose(sp);
}
}
}
setauto(str) char *str; { /* set indicator for number of autos */
while (*str++ != ',')
;
numauto = atoi(str); /* remember # of bytes */
return;
}
setnreg(str) char *str; { /* set indicator for number of registers */
while (*str++ != ',')
;
numnreg = atoi(str); /* remember number of registers */
return;
}
chkauto() /* delete sp increment if no autos, or fewer than 15 words */
{
NODE *p;
/* 5.0 UNIX microcode on the 3B20 supports a "save" instruction that
** can also allocate temporary space on the stack (up to 15 words).
** Standard IS25 "save" does not do the stack allocation.
*/
#ifndef IMPREGAL
#ifdef UCODE50
if (numauto <= 4*15) /* save handles up to 15 words */
#else
if (numauto == 0) /* if no auto's allocated */
#endif /* def UCODE50 */
{
p = n0.forw;
while (islabel( p ))
p = p->forw;
if ( strcmp(p->opcode,"save") == 0
&& p->forw->op == ADDW2
) /* save followed by addw2 */
{
#ifdef UCODE50 /* must add second operand to save */
p->op2 = getspace(1+2+1); /* for "&dd\0" */
(void) sprintf(p->op2,"&%d",numauto/4);
/* append operand with # of autos */
#endif /* def UCODE50 */
p = p->forw; /* point at ADDW2 */
DELNODE( p ); /* delete it */
nspinc++; /* discarded sp increment */
ndisc++; /* discarded instruction */
}
}
#endif /* der IMPREGAL */
#ifndef IMPIL
numauto = 0; /* reset for next routine */
#endif /* IMPIL */
return;
}
uses(p) NODE *p; { /* set register use bits */
switch (p->op) {
case MOVBLB: case MOVBLH: case MOVBLW:
return (0x7);
case MCOMB: case MCOMH: case MCOMW: case MOVZBH: case MOVZBW:
case MOVZHW: case MOVAB: case MOVAH: case MOVAW: case MOVB:
case MOVH: case MOVW: case MOVBBH: case MOVBBW: case MOVBHW:
case MOVTHB: case MOVTWB: case MOVTWH: case MNEGB: case MNEGH:
case MNEGW:
case MOVWS: case MOVTSW: case MOVSW:
return (scanreg(p->op1,false) | scanreg(p->op2,true) |
scanreg(p->op3,false) | scanreg(p->op4,false));
case ANDB3: case ANDH3: case ANDW3: case ORB3: case ORH3:
case ORW3: case XORB3: case XORH3: case XORW3: case LLSW3:
case LRSW3: case ADDB3: case ADDH3: case ADDW3: case SUBB3:
case SUBH3: case SUBW3: case MULW3: case UMULW3: case DIVW3:
case UDIVW3: case MODW3: case UMODW3: case ALSW3: case ARSW3:
return (scanreg(p->op1,false) | scanreg(p->op2,false) |
scanreg(p->op3,true) | scanreg(p->op4,false));
case INSV: case EXTZV:
return (scanreg(p->op1,false) | scanreg(p->op2,false) |
scanreg(p->op3,false) | scanreg(p->op4,true));
case CALL:
return (scanreg(p->op1,false) | scanreg(p->op2,false) |
scanreg(p->op3,false) | scanreg(p->op4,false) |
( 1 << 2 )); /* call must preserve %r2;
ptr to returned structure */
case RET:
return (scanreg(p->op1,false) | scanreg(p->op2,false) |
scanreg(p->op3,false) | scanreg(p->op4,false) |
RETREG); /* function return values */
case JSB:
return (scanreg(p->op1,false) | scanreg(p->op2,false) |
scanreg(p->op3,false) | scanreg(p->op4,false) |
1 ); /* cludge for profiler: %r0 is used to pass
an argument to _mcount */
case FADDD2: case FSUBD2: case FMULD2: case FDIVD2:
case FCMPD:
return( dscanreg(p->op1,false) | dscanreg(p->op2,false) |
scanreg(p->op3,false) | scanreg(p->op4,false) );
case FADDD3: case FSUBD3: case FMULD3: case FDIVD3:
return( dscanreg(p->op1,false) | dscanreg(p->op2,false) |
dscanreg(p->op3,true) | scanreg(p->op4,false) );
case MOVWD: case MOVSD:
return( scanreg(p->op1,false) | dscanreg(p->op2,true) |
scanreg(p->op3,false) | scanreg(p->op4,false) );
case MOVDW: case MOVTDW: case MOVDS:
return( dscanreg(p->op1,false) | scanreg(p->op2,true) |
scanreg(p->op3,false) | scanreg(p->op4,false) );
case MOVDD: case MOVD:
return( dscanreg(p->op1,false) | dscanreg(p->op2,true) |
scanreg(p->op3,false) | scanreg(p->op4,false) );
default:
return (scanreg(p->op1,false) | scanreg(p->op2,false) |
scanreg(p->op3,false) | scanreg(p->op4,false) |
( iscbr( p ) ? CONCODES : 0 ) );
}
}
scanreg(cp,flag) register char *cp; int flag; { /* determine registers
referenced in operand */
int reg,set;
if (cp == NULL)
return (0);
if (flag && *cp == '%')
return (0);
set = 0;
while (*cp != '\0') {
if (*cp == '%') {
cp++;
switch (*cp) {
case 'r':
cp++;
reg = *cp - '0';
break;
case 'a':
cp++;
reg = 9;
break;
case 'f':
cp++;
reg = 10;
break;
case 's':
cp++;
reg = 11;
break;
}
set = set | 1 << reg;
}
cp++;
}
return(set);
}
/* determine registers used for double operand */
int
dscanreg(cp,flag)
char * cp; /* operand string */
boolean flag; /* true if register is destination */
{
int temp = scanreg(cp,flag); /* do normal scan */
if (*cp == '%') /* if direct register reference... */
temp = 3*temp; /* set bit and its left neighbor (reg+1) */
return(temp);
}
sets(p) NODE *p; { /* set register destination bits */
char *cp, *dst();
int o;
boolean dblflag = false; /* true if register double operand */
switch (o = p->op) {
case MOVBLB: case MOVBLH: case MOVBLW:
return (0x0007);
/* Procedure calls could potentially clobber all of the scratch registers.
** We would like call to "kill" all of them, but we can only be reasonably
** safe by saying it kills those registers in which it returns values.
*/
case CALL:
return(RETREG | CONCODES);
/* Register doubles set two registers at a time: r and r+1 */
case FADDD2: case FSUBD2: case FMULD2: case FDIVD2:
case FADDD3: case FSUBD3: case FMULD3: case FDIVD3:
case MOVWD: case MOVSD: case MOVDD: case MOVD:
dblflag = true;
default:
cp = dst(p);
if (cp != NULL)
return((dblflag ? 3*setreg(cp) : setreg(cp)) | CONCODES );
/* return reg bit and its left
** neighbor on double
*/
else
return ( ( ( o == RET )
|| ( CMPB <= o && o <= ATJNZW )
|| ( PUSHAW <= o && o <= PUSHBH ) ) ? CONCODES : 0 );
}
}
setreg(cp) char *cp; { /* set index of register destination (if one) */
if (*cp == '%')
switch (*++cp) {
case 'r':
cp++;
return (1 << (*cp - '0'));
case 'a':
return (1 << 9);
case 'f':
return (1 << 10);
case 's':
return (1 << 11);
default: /* unrecognized name */
break;
}
return(0); /* for non-register or unrecognized */
}
boolean
isdead(cp,p) char *cp; NODE *p; { /* true iff *cp is dead after p */
int reg;
if (*cp != '%')
return(false);
switch(*++cp) {
case 'r':
reg = *++cp - '0';
break;
case 'a':
reg = 9;
break;
case 'f':
reg = 10;
break;
case 's':
reg = 11;
break;
default: /* unrecognized name */
return(false);
}
if ((p->nlive & (1 << reg)) == 0)
return(true);
else
return(false);
}
char *
getp(p) NODE *p; { /* return pointer to jump destination operand */
switch (p->op) {
case JMP: case JSB: case JZ: case JNZ:
case JPOS: case JNPOS: case JNEG: case JNNEG: case JE:
case JNE: case JL: case JLE: case JG: case JGE:
case JLU: case JLEU: case JGU: case JGEU:
return(p->op1);
case RET:
case SWITCH:
case SWITCHT:
return(NULL);
case JBC: case JBS:
return(p->op3);
}
}
char *
newlab() { /* generate a new label */
static int lbn = 0;
char *c;
c = (char *)getspace(lbn < 100 ? 6 : (lbn < 1000 ? 7 : 8));
sprintf(c, "..%d\0", lbn);
lbn++;
return(c);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.