|
|
1.1 root 1: /* @(#) local.c: 1.5 6/26/84 */
2:
3: /* # include <ctype.h> -- optim.h takes care of this */
4: # include "optim.h"
5: # include "sgs.h"
6: # include "paths.h"
7:
8: # define ASDATE ""
9: # define LINELEN 400
10:
11: # define FATAL(S) fatal((S), (char *) 0)
12:
13: char fixstr[256];
14: char line[LINELEN];
15: char * linptr; /* pointer to current line */
16: int fixlen;
17: char * deflab;
18: int opn;
19: int m;
20: int numauto; /* number of bytes of automatic vars. */
21: int numnreg; /* number of registers */
22: boolean indata;
23: int lineno = IDVAL;
24: int nusel = 0; /* semantically useless instructions */
25: int nspinc = 0; /* useless sp increments */
26: int nmc = 0; /* move followed by compare */
27: int nmal = 0; /* move followed by arithmetic or logical */
28: int nredcmp = 0; /* redundant compares */
29: int nadpsh = 0; /* addw3 or subw3 followed by push */
30: int nadmsh = 0; /* addw3 or subw3 followed by mov */
31: int nadmv = 0; /* replace addw3 or subw3 by mov */
32: extern int ndisc;
33:
34: #ifdef IMPIL
35: zflag = false; /* debug flag for in--line expansion */
36: #endif /* IMPIL */
37:
38: # define numops 151
39:
40: char *optbl[numops] = {
41: "acjl","acjle","acjleu","acjlu",
42: "addb2","addb3","addh2","addh3","addw2",
43: "addw3","alsw2","alsw3","andb2","andb3",
44: "andh2","andh3","andw2","andw3","arsw2",
45: "arsw3","atjnzb","atjnzh","atjnzw","bitw",
46: "call","cmpb","cmph","cmpw",
47: "decpth","decptw","divw2",
48: "divw3","extzv","faddd2","faddd3","fadds2",
49: "fadds3","fcmpd","fdivd2","fdivd3","fdivs2",
50: "fdivs3","fmuld2","fmuld3","fmuls2","fmuls3",
51: "fsubd2","fsubd3","fsubs2","fsubs3",
52: "incpth","incptw","inctst","insv",
53: "jbc","jbs","je","jg","jge",
54: "jgeu","jgu","jl","jle","jleu",
55: "jlu","jmp","jne","jneg","jnneg",
56: "jnpos","jnz","jpos","jsb","jz",
57: "llsw2","llsw3","lrsw2","lrsw3","mcomb",
58: "mcomh","mcomw","mnegb","mnegh","mnegw",
59: "modw2","modw3","movab","movah","movaw",
60: "movb","movbbh","movbbw","movbhw","movblb",
61: "movblh","movblw","movd","movdd","movds","movdw","movh",
62: "movsd","movsw","movtdw","movthb","movtsw",
63: "movtwb","movtwh","movw","movwd","movws",
64: "movzbh","movzbw","movzhw","mulw2","mulw3",
65: "orb2","orb3","orh2","orh3","orw2",
66: "orw3","pushaw","pushbb","pushbh",
67: "pushd","pushw","pushzb","pushzh","ret","save","subb2",
68: "subb3","subh2","subh3","subw2","subw3",
69: "switch","switcht",
70: "udivw2","udivw3","umodw2","umodw3","umulw2",
71: "umulw3","xorb2","xorb3","xorh2","xorh3",
72: "xorw2","xorw3"
73: };
74:
75: FILE *stmpfile; /* Temporary storage for strings which are in the text
76: * section. The strings are collected and printed at
77: * the end of a function. Requirement for field update */
78: extern char *mktemp();
79: FILE *tmpopen();
80: char tmpname[50]; /* name of file for storing string */
81: FILE *atmpfile; /* Temporary storage for input while scanning for presence of
82: * #ASM in function */
83: char atmpname[50];
84: int asmflag = false; /* indicates whether an 'asm' has been encountered */
85: long asmotell; /* location in the output file where the last function ended */
86: int oaflag = false; /* indicates whether -OA flag was entered */
87: boolean instring = false;
88: boolean inswitch = false;
89: #ifdef IMPIL
90: boolean swflag = false; /* switch table appears in function */
91: NODE *lblnode = NULL; /* pointer to last label node */
92: char *pcdecode();
93: #endif /* IMPIL */
94:
95: yylex()
96: {
97: extern char * strchr();
98:
99: register char * s; /* temporary string ptr */
100: register char * start; /* another temporary string ptr */
101: register int i; /* temporary int */
102:
103: #ifdef IMPIL
104: ilinit();
105: #endif /* IMPIL */
106:
107: asmopen(); /* open temp file for asm treatment */
108: linptr = NULL; /* start off with no line */
109:
110: while (linptr != NULL ||
111: ((linptr = fgets(line,LINELEN,stdin)) != NULL && putasm(line)))
112: {
113: switch (*linptr) /* dispatch on first char in line */
114: {
115: case '\n': /* ignore new line */
116: break;
117:
118: case '#': /* check for special comments */
119: s = linptr + 1; /* look at comment only, not # */
120:
121: if (strncmp(s,"STRBEG",6) == 0)
122: instring = true; /* declare we're in a string */
123: else if (strncmp(s,"STREND",6) == 0)
124: instring = false; /* now out of string-ness */
125: else if (strncmp(s,"SWBEG",5) == 0)
126: inswitch = swflag = true; /* now in a switch table */
127: else if (strncmp(s,"SWEND",5) == 0)
128: inswitch = false; /* out of switch table */
129: else if (strncmp(s,"ASM",3) == 0)
130: asmflag = true; /* 'asm' appears in function */
131: #ifdef IMPREGAL
132: else if (strncmp(s,"REGAL",5) == 0)
133: ratable( line ); /* register allocation opt */
134: #endif /* IMPREGAL */
135:
136: break; /* in any case, ignore line further */
137:
138: case '.': /* compiler label */
139: default: /* ordinary label */
140: if (indata) /* in data section, just print */
141: {
142: printf("%s",linptr);
143: break;
144: }
145:
146: /* reach here on labels in text space */
147:
148: s = strchr(linptr,':'); /* find : */
149: if (s == NULL) /* error if not found */
150: { FATAL("Bad input format\n"); }
151:
152: *s++ = '\0'; /* change : to null, skip past */
153:
154: /* for N3B (DMERT), switch code and jump tables are in text space,
155: ** but SWBEG, SWEND bracket just the table. For m32 and u3b, jump tables are
156: ** always in data space.
157: ** Write labels found when "inswitch" to special file for N3B only.
158: */
159:
160: #ifdef N3B
161: if (instring || inswitch) /* inside special string or switch... */
162: #else
163: if (instring) /* inside special string?... */
164: #endif /* def N3B */
165: {
166: putstr(linptr); /* write label to special file */
167: putstr(":\n"); /* put : back in */
168: }
169: else /* normal text space label */
170: {
171: applbl(linptr,s-linptr); /* append label node */
172: lastnode->uniqid = IDVAL;
173: }
174: linptr = s; /* continue processing past label */
175: continue; /* next iteration */
176: /* handle more usual case of line beginning with space/tab */
177: case ' ':
178: case '\t':
179: for (s = linptr; isspace(*s); s++) /* skip white space */
180: ;
181:
182: switch(*s) /* dispatch on next character */
183: {
184: case '\0': /* line of white space */
185: case '#': /* comment */
186: case '\n': /* new line */
187: break; /* ignore */
188:
189: case '.': /* start of pseudo-op */
190: pseudo(s); /* do pseudo-ops */
191: break;
192:
193: default: /* normal instruction */
194: if (indata) /* in data section this is weird case */
195: printf("%s",linptr); /* just write line */
196: else /* normal instruction in text */
197: {
198: for (start = s; ! isspace(*s); s++)
199: ; /* skip over instruction mnemonic */
200:
201: *s++ = '\0'; /* demarcate with null */
202:
203: if ((opn = lookup(start)) == OTHER)
204: saveop(0,start,s-start,opn);
205: /* save funny instruction */
206: else
207: saveop(0,optbl[m],0,opn);
208: /* save normal inst. (m set by
209: ** lookup)
210: */
211: for ( ; isspace(*s); s++ )
212: ; /* span white space */
213: opn = 1; /* now save operands */
214: op(s); /* skip intervening spaces/tabs */
215: }
216: /* remember program name */
217: #ifdef IMPIL
218: if( ntail.back->op == SAVE ) lblnode = ntail.back->back;
219: #endif /* IMPIL */
220: break;
221: } /* end space/tab case */
222: break;
223: } /* end first character switch */
224:
225: linptr = NULL; /* indicate we're done with line */
226: } /* end while */
227: return; /* just exit */
228: }
229: op (s)
230: register char *s;
231: {
232: register char *t;
233:
234: while (*s)
235: {
236: /* scan over leading space/tabs */
237: while (*s == ' ' || *s == '\t')
238: s++;
239:
240: t = s; /* remember effective operand start */
241: while(*s != ',' && *s != '\n') /* find end of operand */
242: s++;
243: *s++ = '\0';
244: saveop(opn++, t, s-t, 0);
245: if (*t == '.') /* operand is a label */
246: if (inswitch)
247: addref(t, s-t);
248: }
249: lastnode->uniqid = lineno;
250: lineno = IDVAL;
251: }
252:
253:
254: pseudo (s)
255: register char *s; /* points at pseudo-op */
256: {
257: void peep(); /* peephole improver */
258: extern int cflag; /* independent part -c flag:
259: ** enable/disable common tail
260: */
261: register int pop; /* pseudo-op code */
262: char savechar; /* saved char that follows pseudo */
263: char * word = s; /* pointer to beginning of pseudo */
264:
265: /* The idea here is to stick in a NUL after the pseudo-op, then replace
266: ** the character we clobbered, rather than copy the pseudo-op somewhere else.
267: */
268:
269: for ( ; ! isspace(*s); s++ )
270: ; /* scan to white space char */
271: savechar = *s; /* mark end of pseudo-op */
272: *s = '\0';
273:
274: /* if we're in a data section, we write all pseudo-ops to output,
275: ** except for .word's, which we must examine, and .text .
276: */
277:
278: pop = plookup(word); /* identify pseudo-op */
279: *s = savechar; /* restore saved character */
280: if (indata) { /* check pseudo-op possibilities */
281: if (pop == TEXT) {
282: indata = false; /* not in data section anymore */
283: return;
284: }
285: else if (pop != WORD) {
286: printf("%s",linptr); /* output the line */
287: return;
288: }
289: }
290:
291: switch (pop) { /* dispatch on pseudo-op in text */
292: case BYTE:
293: putstr(linptr);
294: break;
295: case GLOBL:
296: case TV:
297: line[(m=length(line))-2] = '\0'; /* remove newline */
298: appfl(line, m-1);
299: break;
300: case TEXT:
301: indata = false;
302: break;
303: case FIL:
304: case BSS:
305: printf("%s", line);
306: break;
307: case LN:
308: getln(line);
309: break;
310: case ALIGN:
311: line[(m=length(line))-2] = '\0'; /* remove NL */
312: if (inswitch) {
313: #ifdef N3B /* for DMERT, put aligns in switch to special
314: ** output file with switch table
315: */
316: line[m-2] = '\n'; /* restore new line */
317: putstr(linptr);
318: #else
319: saveop(0, line+1, m-2, OTHER);
320: opn = 1;
321: lastnode->uniqid = lineno;
322: lineno = IDVAL;
323: #endif /* def N3B */
324: }
325: else
326: appfl(line, m-1);
327: break;
328: case SET:
329: if (*++s == '.' && *++s == 'F') {
330: printf("\t.text\n");
331: setauto(line);
332: printf("%s", line);
333: }
334: else if (s--, *s == '.' && *++s == 'R') {
335: setnreg(line);
336: line[(m=length(line))-2] = '\0';
337: appfl(line,m-1);
338: }
339: else {
340: line[(m=length(line))-2] = '\0';
341: appfl(line, m-1);
342: }
343: break;
344: case DATA:
345: printf("%s", line);
346: indata = true;
347: break;
348: case DEF: {
349: int found;
350:
351: line[(m=length(line))-2] = '\0'; /* remove newline */
352: #ifdef IMPIL
353: while( isspace( *s ) ) s++;
354: if (*s++ == '.' && *s++ == 'e' &&
355: *s++ == 'f') { /* .ef */
356: appfl( "*", 2 );
357: if( lblnode == NULL )
358: { FATAL( "No label preceeding .bf pseudo op, file may already be optimized\n" ); }
359: appfl( lblnode->ops[0],
360: length( lblnode->ops[0]));
361: }
362: s--;
363: #endif /* IMPIL */
364: found = 0;
365: while (true) {
366: while (*s++ != ';');
367: if (*(s += 2) == 'e') /* endef */
368: break;
369: /* There are two special cases for ".val". The first is
370: ** ".val ." . Since we're going to move the .def line, we need
371: ** to replace the '.' with a real label (which we make a hard label)
372: ** first. The second special case is ".val .Lxxx" (a local label).
373: ** This arises in the compiler from a user-defined label. The
374: ** problem here is that if the optimizer discards the local label,
375: ** there will be a reference to a non-existent label which will only
376: ** show up at link time. To avoid this, we delete (ignore) the whole
377: ** line.
378: */
379: else if (*s++ == 'v') { /* .val */
380: if (s[3] == '.')
381: {
382: if (s[4] == ';') /* first case */
383: found = 1;
384: else if (s[4] == 'L')
385: found = 3; /* second */
386: }
387: }
388: else if (*s == 'c') /* .scl */
389: if (*(s+3) == '-' && *(s+4) == '1') {
390: found = 2;
391: break;
392: }
393: }
394: switch(found)
395: {
396: case 1: /* .val . */
397: deflab = (char *) newlab();
398: deffix(line, deflab);
399: appfl(fixstr, fixlen+1);
400: fixlbl(deflab);
401: applbl(deflab, length(deflab));
402: lastnode->op = HLABEL;
403: lastnode-> uniqid = IDVAL;
404: break;
405: case 2: /* end of function */
406: cflag = -1; /* turn off common tail
407: ** merging: improve speed,
408: ** not space.
409: */
410: if( !asmflag || oaflag ) {
411: #ifdef IMPREGAL
412: numnreg = raoptim(numnreg, numauto);
413: numauto = raautos(numauto);
414: #endif /* IMPREGAL */
415: #ifdef IMPIL
416: ilmark();
417: #endif /* IMPIL */
418: filter();
419: optim();
420: peep(); /* do peephole improvements */
421: #ifdef IMPIL
422: ilstat(numnreg, numauto);
423: #endif /* IMPIL */
424: chkauto();
425: }
426: prtext();
427: prstr();
428: printf("%s", line);
429: printf("\n");
430: asmchk();
431: init();
432: break;
433: case 3: /* .val .Lxxx */
434: break; /* ignore line */
435: default: /* other .defs */
436: appfl(line, m-1);
437: break;
438: }
439: }
440: break;
441: case WORD:
442: s++; /* point past tab/nl */
443:
444: /* we have to deal with whether .word is within a switch (SWBEG/SWEND) or
445: ** not, and whether or not it appears in a data section.
446: */
447:
448: if (inswitch) { /* always add reference */
449: register char * t = strchr(s,'\n');
450:
451: *t = '\0'; /* change NL to null */
452: addref(s,t+1-s); /* add the reference */
453: *t = '\n'; /* restore NL */
454: }
455:
456: if (indata) /* in data, flush to output */
457: printf("%s",linptr); /* print line */
458: else if (inswitch) /* text (implicit) and switch */
459: putstr(linptr); /* flush to special file */
460: else { /* text, not in switch */
461: saveop(0,".word",6,OTHER);
462: opn = 1; /* doing first operand */
463: op(s);
464: }
465: break;
466:
467: default: /* all unrecognized text
468: ** pseudo-ops
469: */
470: if (! (instring || inswitch))
471: printf("%s", linptr); /* flush to output */
472: else
473: putstr(linptr); /* in(switch|string): to
474: ** special file
475: */
476: break;
477: }
478: }
479:
480: int
481: plookup(s) /* look up pseudo op code */
482: char *s;
483:
484: {
485: /* Note: to improve the linear search speed, these pseudo-ops
486: ** are ordered by frequency of occurrence in a sample of C programs.
487: */
488:
489: static char *pops[numpops] =
490: {
491: ".word", ".byte", ".set", ".def", ".align",
492: ".data", ".text", ".globl", ".ln", ".bss",
493: ".file", ".tv"
494: };
495:
496: static int popcode[numpops] =
497: {
498: WORD, BYTE, SET, DEF, ALIGN,
499: DATA, TEXT, GLOBL, LN, BSS,
500: FIL, TV
501: };
502:
503: register int i;
504:
505: for (i = 0; i < numpops; i++)
506: if (!strcmp(s, pops[i]))
507: return(popcode[i]);
508: return(POTHER);
509: }
510:
511:
512: yyinit(flags) char * flags; {
513:
514: indata = false;
515: for (; *flags != '\0'; flags++) {
516: switch( *flags ) {
517: case 'V':
518: fprintf(stderr,"%s: optimizer - %s %s\n",
519: SGSNAME,RELEASE,ASDATE);
520: break;
521: case 'A':
522: oaflag = true;
523: break;
524: #ifdef IMPIL
525: case 'z':
526: zflag = true;
527: break;
528: #endif /* IMPIL */
529: default:
530: fprintf(stderr,"Optimizer: invalid flag '%c'\n",*flags);
531: }
532: }
533: }
534:
535: char *
536: yysflgs( p ) char *p; { /* parse flags with sub fields */
537:
538: switch( *p ) {
539: #ifdef IMPIL
540: case 'y':
541: p++; /* skip over 'y' to sub option */
542: p = pcdecode( p );
543: return( p );
544: #endif /* IMPIL */
545: default:
546: return( p );
547: }
548: }
549:
550: int
551: lookup(op) char *op; { /* look up op code ordinal */
552:
553: register int f,l,om,x;
554: static unsigned char ocode[numops] = {
555: ACJL,ACJLE,ACJLEU,ACJLU,
556: ADDB2,ADDB3,ADDH2,ADDH3,ADDW2,
557: ADDW3,ALSW2,ALSW3,ANDB2,ANDB3,
558: ANDH2,ANDH3,ANDW2,ANDW3,ARSW2,
559: ARSW3,ATJNZB,ATJNZH,ATJNZW,BITW,
560: CALL,CMPB,CMPH,CMPW,
561: DECPTH,DECPTW,DIVW2,
562: DIVW3,EXTZV,FADDD2,FADDD3,FADDS2,
563: FADDS3,FCMPD,FDIVD2,FDIVD3,FDIVS2,
564: FDIVS3,FMULD2,FMULD3,FMULS2,FMULS3,
565: FSUBD2,FSUBD3,FSUBS2,FSUBS3,
566: INCPTH,INCPTW,INCTST,INSV,
567: JBC,JBS,JE,JG,JGE,
568: JGEU,JGU,JL,JLE,JLEU,
569: JLU,JMP,JNE,JNEG,JNNEG,
570: JNPOS,JNZ,JPOS,JSB,JZ,
571: LLSW2,LLSW3,LRSW2,LRSW3,MCOMB,
572: MCOMH,MCOMW,MNEGB,MNEGH,MNEGW,
573: MODW2,MODW3,MOVAB,MOVAH,MOVAW,
574: MOVB,MOVBBH,MOVBBW,MOVBHW,MOVBLB,
575: MOVBLH,MOVBLW,MOVD,MOVDD,MOVDS,MOVDW,MOVH,
576: MOVSD,MOVSW,MOVTDW,MOVTHB,MOVTSW,
577: MOVTWB,MOVTWH,MOVW,MOVWD,MOVWS,
578: MOVZBH,MOVZBW,MOVZHW,MULW2,MULW3,
579: ORB2,ORB3,ORH2,ORH3,ORW2,
580: ORW3,PUSHAW,PUSHBB,PUSHBH,
581: PUSHD,PUSHW,PUSHZB,PUSHZH,RET,SAVE,SUBB2,
582: SUBB3,SUBH2,SUBH3,SUBW2,SUBW3,
583: SWITCH,SWITCHT,
584: UDIVW2,UDIVW3,UMODW2,UMODW3,UMULW2,
585: UMULW3,XORB2,XORB3,XORH2,XORH3,
586: XORW2,XORW3
587: };
588:
589: f = 0;
590: l = numops;
591: om = 0;
592: m = (f+l)/2;
593: while (m != om) {
594: x = strcmp(op,optbl[m]);
595: if (x == 0)
596: return((int) ocode[m]);
597: else if (x < 0)
598: l = m-1;
599: else
600: f = m+1;
601: om = m;
602: m = (f+l)/2;
603: }
604: return(OTHER);
605: }
606:
607: deffix(str,lbl) register char * str, * lbl; { /*change "val .;" to "val ..n;"*/
608:
609: register char * nc;
610: register boolean scanning;
611:
612: scanning = true;
613: nc = fixstr;
614: fixlen = 0;
615: while (scanning)
616: if (*str == '.' && *(str+1) == ';') {
617: str++;
618: scanning = false;
619: }
620: else {
621: *nc++ = *str++;
622: fixlen++;
623: }
624: while (*nc++ = *lbl++)
625: fixlen++;
626: nc--;
627: while (*nc++ = *str++)
628: fixlen++;
629: }
630:
631: fixlbl(str) register char * str; { /* add colon to end of label */
632:
633: while (*str++);
634: *--str = ':';
635: *++str = '\0';
636: }
637:
638: int
639: length(str) register char * str; { /* return length of string (including \0) */
640:
641: register int l;
642:
643: l = 1;
644: while (*str++)
645: l++;
646: return (l);
647: }
648:
649: getln(str) register char * str; { /* extract line number */
650:
651: while (!isdigit(*str))
652: str++;
653: lineno = 0;
654: while (isdigit(*str)) {
655: lineno = lineno * 10 + *str - '0';
656: str++;
657: }
658: }
659:
660: prinst(p) register NODE *p; { /* print instruction */
661: if (p->uniqid != IDVAL)
662: printf(" .ln %d\n", p->uniqid);
663: #ifdef IMPIL
664: if (p->op == CALL ) {
665: printf("@ %d %s %s\n",
666: numauto + ( int ) p->ops[MAXOPS], p->op1 + 1, p->op2 );
667: p->ops[MAXOPS] = NULL;
668: }
669: #endif /* IMPIL */
670: switch (p->op) {
671: case LABEL:
672: printf("%s:\n", p->opcode);
673: break;
674: case HLABEL:
675: printf("%s\n", p->opcode);
676: break;
677: case MISC:
678: printf(" %s\n", p->opcode);
679: break;
680: case RET:
681: if (*(p->op1 + 1) == '-') {
682: printf(" RET\n");
683: break;
684: }
685: default:
686: printf(" %s ", p->opcode);
687: if (p->op1 != NULL)
688: printf("%s", p->op1);
689: if (p->op2 != NULL)
690: printf(",%s", p->op2);
691: if (p->op3 != NULL)
692: printf(",%s", p->op3);
693: if (p->op4 != NULL)
694: printf(",%s", p->op4);
695: printf("\n");
696: break;
697: }
698: }
699:
700: boolean
701: ishlp(p) register NODE *p; { /* return true if a fixed label present */
702:
703: for (; (p->op == LABEL || p->op == HLABEL); p=p->forw)
704: if (ishl(p))
705: return(true);
706: return(false);
707: }
708:
709: FILE *
710: tmpopen() {
711: strcpy( tmpname, TMPDIR );
712: strcat( tmpname, "/25ccXXXXXX" );
713: return( fopen( mktemp( tmpname ), "w" ) );
714: }
715:
716: putstr(string) char *string; {
717: /* Place string from the text section into a temporary file
718: * to be output at the end of the function */
719:
720: if( stmpfile == NULL )
721: stmpfile = tmpopen();
722: fprintf(stmpfile,"%s",string);
723: }
724:
725: prstr() {
726: /* print the strings stored in stmpfile at the end of the function */
727:
728: if( stmpfile != NULL ) {
729: register int c;
730:
731: stmpfile = freopen( tmpname, "r", stmpfile );
732: if( stmpfile != NULL )
733: while( (c=getc(stmpfile)) != EOF )
734: putchar( c );
735: else
736: {
737: fprintf( stderr, "optimizer error: ");
738: fprintf( stderr, "lost temp file\n");
739: }
740: (void) fclose( stmpfile ); /* close and delete file */
741: unlink( tmpname );
742: stmpfile = NULL;
743: }
744: }
745:
746: /* opens the temp file for storing input while looking for 'asm' */
747: asmopen() {
748: strcpy( atmpname, TMPDIR );
749: strcat( atmpname, "/asmXXXXXX" );
750: atmpfile = fopen( mktemp( atmpname ), "w" );
751: asmotell = ftell( stdout );
752: }
753:
754: /* writes to temp file for 'asm' processing */
755: int
756: putasm( line )
757: char *line;
758: {
759: return( fputs( line, atmpfile ) != EOF );
760: }
761:
762: /* checks for 'asm' in files and undoes code movement */
763: asmchk()
764: {
765: register c;
766: long endotell;
767: extern int vars;
768:
769: if( asmflag && !oaflag ) {
770: if( freopen( atmpname, "r", atmpfile ) != NULL ) {
771: endotell = ftell( stdout );
772: fseek( stdout, asmotell, 0 ); /* This is okay as long
773: as IMPIL is defined because it
774: is not really stdout, it is the file used by
775: in-line expansion. That file is still used,
776: even when in-line expansion is suppressed.
777: If IMPIL is not defined, optim will not work
778: correctly to a terminal, but it will work
779: correctly to a file.
780: This should be fixed. (fbw) */
781: while( ( c = getc( atmpfile ) ) != EOF ) putchar( c );
782: while( ftell( stdout ) < endotell ) printf( "!\n" );
783: }
784: else fprintf( stderr, "optimizer error: asm temp file lost\n" );
785: }
786: freopen( atmpname, "w", atmpfile );
787: asmotell = ftell( stdout );
788: asmflag = false;
789: vars=0; /* reinitialize for global reg allocation */
790: }
791:
792: putp(p,c) register NODE *p; char *c; { /* insert pointer into jump node */
793:
794: if (p->op == CALL)
795: p->op2 = c;
796: else if (p->op == JBC || p->op == JBS)
797: p->op3 = c;
798: else if (p->op == RET) {
799: p->op1 = NULL;
800: p->op2 = c;
801: }
802: else
803: p->op1 = c;
804: }
805:
806: revbr(p) NODE *p; { /* reverse jump in node p */
807:
808: switch (p->op) {
809: case JZ: p->op = JNZ; p->opcode = "jnz"; break;
810: case JNZ: p->op = JZ; p->opcode = "jz"; break;
811: case JPOS: p->op = JNPOS; p->opcode = "jnpos"; break;
812: case JNPOS: p->op = JPOS; p->opcode = "jpos"; break;
813: case JNEG: p->op = JNNEG; p->opcode = "jnneg"; break;
814: case JNNEG: p->op = JNEG; p->opcode = "jneg"; break;
815: case JE: p->op = JNE; p->opcode = "jne"; break;
816: case JNE: p->op = JE; p->opcode = "je"; break;
817: case JL: p->op = JGE; p->opcode = "jge"; break;
818: case JLE: p->op = JG; p->opcode = "jg"; break;
819: case JG: p->op = JLE; p->opcode = "jle"; break;
820: case JGE: p->op = JL; p->opcode = "jl"; break;
821: case JLU: p->op = JGEU; p->opcode = "jgeu"; break;
822: case JLEU: p->op = JGU; p->opcode = "jgu"; break;
823: case JGU: p->op = JLEU; p->opcode = "jleu"; break;
824: case JGEU: p->op = JLU; p->opcode = "jlu"; break;
825: case JBC: p->op = JBS; p->opcode = "jbs"; break;
826: case JBS: p->op = JBC; p->opcode = "jbc"; break;
827: }
828: }
829:
830: char *
831: dst(p) NODE *p; { /* return pointer to dst operand string */
832:
833: switch (p->op) {
834: case ACJL: case ACJLU: case ACJLEU: case ATJNZB: case ATJNZH:
835: case ATJNZW: case INCTST:
836: case INCPTH: case INCPTW: case DECPTH: case DECPTW:
837: return (p->op1);
838: case MCOMB: case MCOMH: case MCOMW: case MOVZBH: case MOVZBW:
839: case MOVZHW: case MOVAB: case MOVAH: case MOVAW: case ANDB2:
840: case ANDH2: case ANDW2: case ORB2: case ORH2: case ORW2:
841: case XORB2: case XORH2: case XORW2: case MOVB: case MOVH:
842: case MOVW: case MOVBBH: case MOVBBW: case MOVBHW: case MOVTHB:
843: case MOVTWB: case MOVTWH: case MNEGB: case MNEGH: case MNEGW:
844: case ADDB2: case ADDH2: case ADDW2: case SUBB2: case SUBH2:
845: case SUBW2: case MULW2: case UMULW2: case DIVW2: case UDIVW2:
846: case MODW2: case UMODW2: case LLSW2: case LRSW2: case ALSW2:
847: case ARSW2: case FADDD2: case FSUBD2: case FMULD2: case FDIVD2:
848: case FADDS2: case FSUBS2: case FMULS2: case FDIVS2:
849: case MOVWS: case MOVWD: case MOVTSW: case MOVTDW:
850: case MOVSW: case MOVDW: case MOVSD: case MOVDS: case MOVDD:
851: case MOVD:
852: return(p->op2);
853: case ANDB3: case ANDH3: case ANDW3: case ORB3: case ORH3:
854: case ORW3: case XORB3: case XORH3: case XORW3: case LLSW3:
855: case LRSW3: case ADDB3: case ADDH3: case ADDW3: case SUBB3:
856: case SUBH3: case SUBW3: case MULW3: case UMULW3: case DIVW3:
857: case UDIVW3: case MODW3: case UMODW3: case ALSW3: case ARSW3:
858: case FADDD3: case FSUBD3: case FMULD3: case FDIVD3:
859: case FADDS3: case FSUBS3: case FMULS3: case FDIVS3:
860: return(p->op3);
861: case INSV: case EXTZV:
862: return(p->op4);
863: default:
864: return (NULL);
865: }
866: }
867:
868: int
869: stype(cop) int cop; { /* return implied type of op code */
870:
871: switch (cop) {
872: case MCOMB: case ANDB2: case ANDB3: case ORB2: case ORB3:
873: case XORB2: case XORB3: case MOVB: case MOVTHB: case MOVTWB:
874: case MNEGB: case ADDB2: case ADDB3: case SUBB2: case SUBB3:
875: case CMPB:
876: return (1);
877: case MCOMH: case MOVZBH: case ANDH2: case ANDH3: case ORH2:
878: case ORH3: case XORH2: case XORH3: case MOVH: case MOVBBH:
879: case MOVTWH: case MNEGH: case ADDH2: case ADDH3: case SUBH2:
880: case SUBH3: case CMPH:
881: return (2);
882: default:
883: return (4);
884:
885: case FADDD2: case FSUBD2: case FMULD2: case FDIVD2:
886: case FADDD3: case FSUBD3: case FMULD3: case FDIVD3:
887: case FCMPD: case MOVSD: case MOVWD: case MOVDD:
888: return(8);
889: }
890: }
891:
892: boolean
893: samereg(cp1,cp2) char *cp1, *cp2; { /* return true if same register */
894:
895: if (*cp1 == '%' && *cp1 == *cp2 && *++cp1 == *++cp2 && *++cp1 == *++cp2)
896: return(true);
897: else
898: return(false);
899: }
900:
901: boolean
902: usesreg(cp1,cp2) register char *cp1, *cp2; { /*return true if cp2 used in cp1*/
903:
904: while(*cp1 != '\0') {
905: if (*cp1 == *cp2 && *(cp1+1) == *(cp2+1) &&
906: *(cp1+2) == *(cp2+2))
907: return(true);
908: cp1++;
909: }
910: return(false);
911: }
912:
913: dstats() { /* print stats on machine dependent optimizations */
914:
915: fprintf(stderr,"%d semantically useless instructions(s)\n", nusel);
916: fprintf(stderr,"%d useless move(s) before compare(s)\n", nmc);
917: fprintf(stderr,"%d merged move-arithmetic/logical(s)\n", nmal);
918: fprintf(stderr,"%d useless sp increment(s)\n", nspinc);
919: fprintf(stderr,"%d redundant compare(s)\n", nredcmp);
920: }
921:
922: wrapup() { /* print unprocessed text and update statistics file */
923:
924: FILE *fopen(), *sp;
925: int mc,mal,usel,spinc,redcmp,disc,inst;
926:
927: if (n0.forw != NULL) {
928: printf(" .text\n");
929: filter();
930: prtext();
931: prstr();
932: }
933: #ifdef IMPIL
934: ilfile();
935: #endif /* IMPIL */
936:
937: (void) fclose( atmpfile ); /* close and delete file */
938: unlink( atmpname );
939:
940: sp = fopen("/g1/dap/optim/stats/statfile","r");
941: if (sp != NULL) {
942: fscanf(sp, "%d %d %d %d %d %d %d",
943: &mc,&mal,&usel,&spinc,&redcmp,&disc,&inst);
944: fclose(sp);
945: mc += nmc;
946: mal += nmal;
947: usel += nusel;
948: spinc += nspinc;
949: redcmp += nredcmp;
950: disc += ndisc;
951: inst += ninst;
952: sp = fopen("/g1/dap/optim/stats/statfile","w");
953: if (sp != NULL) {
954: fprintf(sp, "%d %d %d %d %d %d %d \n",
955: mc,mal,usel,spinc,redcmp,disc,inst);
956: fclose(sp);
957: }
958: }
959: }
960:
961: setauto(str) char *str; { /* set indicator for number of autos */
962:
963: while (*str++ != ',')
964: ;
965: numauto = atoi(str); /* remember # of bytes */
966: return;
967: }
968:
969: setnreg(str) char *str; { /* set indicator for number of registers */
970:
971: while (*str++ != ',')
972: ;
973: numnreg = atoi(str); /* remember number of registers */
974: return;
975: }
976: chkauto() /* delete sp increment if no autos, or fewer than 15 words */
977: {
978: NODE *p;
979:
980: /* 5.0 UNIX microcode on the 3B20 supports a "save" instruction that
981: ** can also allocate temporary space on the stack (up to 15 words).
982: ** Standard IS25 "save" does not do the stack allocation.
983: */
984:
985: #ifndef IMPREGAL
986: #ifdef UCODE50
987: if (numauto <= 4*15) /* save handles up to 15 words */
988: #else
989: if (numauto == 0) /* if no auto's allocated */
990: #endif /* def UCODE50 */
991: {
992: p = n0.forw;
993: while (islabel( p ))
994: p = p->forw;
995: if ( strcmp(p->opcode,"save") == 0
996: && p->forw->op == ADDW2
997: ) /* save followed by addw2 */
998: {
999: #ifdef UCODE50 /* must add second operand to save */
1000: p->op2 = getspace(1+2+1); /* for "&dd\0" */
1001: (void) sprintf(p->op2,"&%d",numauto/4);
1002: /* append operand with # of autos */
1003: #endif /* def UCODE50 */
1004: p = p->forw; /* point at ADDW2 */
1005: DELNODE( p ); /* delete it */
1006: nspinc++; /* discarded sp increment */
1007: ndisc++; /* discarded instruction */
1008: }
1009: }
1010: #endif /* der IMPREGAL */
1011: #ifndef IMPIL
1012: numauto = 0; /* reset for next routine */
1013: #endif /* IMPIL */
1014: return;
1015: }
1016:
1017: uses(p) NODE *p; { /* set register use bits */
1018:
1019: switch (p->op) {
1020: case MOVBLB: case MOVBLH: case MOVBLW:
1021: return (0x7);
1022: case MCOMB: case MCOMH: case MCOMW: case MOVZBH: case MOVZBW:
1023: case MOVZHW: case MOVAB: case MOVAH: case MOVAW: case MOVB:
1024: case MOVH: case MOVW: case MOVBBH: case MOVBBW: case MOVBHW:
1025: case MOVTHB: case MOVTWB: case MOVTWH: case MNEGB: case MNEGH:
1026: case MNEGW:
1027: case MOVWS: case MOVTSW: case MOVSW:
1028: return (scanreg(p->op1,false) | scanreg(p->op2,true) |
1029: scanreg(p->op3,false) | scanreg(p->op4,false));
1030: case ANDB3: case ANDH3: case ANDW3: case ORB3: case ORH3:
1031: case ORW3: case XORB3: case XORH3: case XORW3: case LLSW3:
1032: case LRSW3: case ADDB3: case ADDH3: case ADDW3: case SUBB3:
1033: case SUBH3: case SUBW3: case MULW3: case UMULW3: case DIVW3:
1034: case UDIVW3: case MODW3: case UMODW3: case ALSW3: case ARSW3:
1035: return (scanreg(p->op1,false) | scanreg(p->op2,false) |
1036: scanreg(p->op3,true) | scanreg(p->op4,false));
1037: case INSV: case EXTZV:
1038: return (scanreg(p->op1,false) | scanreg(p->op2,false) |
1039: scanreg(p->op3,false) | scanreg(p->op4,true));
1040: case CALL:
1041: return (scanreg(p->op1,false) | scanreg(p->op2,false) |
1042: scanreg(p->op3,false) | scanreg(p->op4,false) |
1043: ( 1 << 2 )); /* call must preserve %r2;
1044: ptr to returned structure */
1045: case RET:
1046: return (scanreg(p->op1,false) | scanreg(p->op2,false) |
1047: scanreg(p->op3,false) | scanreg(p->op4,false) |
1048: RETREG); /* function return values */
1049: case JSB:
1050: return (scanreg(p->op1,false) | scanreg(p->op2,false) |
1051: scanreg(p->op3,false) | scanreg(p->op4,false) |
1052: 1 ); /* cludge for profiler: %r0 is used to pass
1053: an argument to _mcount */
1054: case FADDD2: case FSUBD2: case FMULD2: case FDIVD2:
1055: case FCMPD:
1056: return( dscanreg(p->op1,false) | dscanreg(p->op2,false) |
1057: scanreg(p->op3,false) | scanreg(p->op4,false) );
1058:
1059: case FADDD3: case FSUBD3: case FMULD3: case FDIVD3:
1060: return( dscanreg(p->op1,false) | dscanreg(p->op2,false) |
1061: dscanreg(p->op3,true) | scanreg(p->op4,false) );
1062:
1063: case MOVWD: case MOVSD:
1064: return( scanreg(p->op1,false) | dscanreg(p->op2,true) |
1065: scanreg(p->op3,false) | scanreg(p->op4,false) );
1066:
1067: case MOVDW: case MOVTDW: case MOVDS:
1068: return( dscanreg(p->op1,false) | scanreg(p->op2,true) |
1069: scanreg(p->op3,false) | scanreg(p->op4,false) );
1070:
1071: case MOVDD: case MOVD:
1072: return( dscanreg(p->op1,false) | dscanreg(p->op2,true) |
1073: scanreg(p->op3,false) | scanreg(p->op4,false) );
1074:
1075: default:
1076: return (scanreg(p->op1,false) | scanreg(p->op2,false) |
1077: scanreg(p->op3,false) | scanreg(p->op4,false) |
1078: ( iscbr( p ) ? CONCODES : 0 ) );
1079: }
1080: }
1081:
1082: scanreg(cp,flag) register char *cp; int flag; { /* determine registers
1083: referenced in operand */
1084:
1085: int reg,set;
1086:
1087: if (cp == NULL)
1088: return (0);
1089: if (flag && *cp == '%')
1090: return (0);
1091: set = 0;
1092: while (*cp != '\0') {
1093: if (*cp == '%') {
1094: cp++;
1095: switch (*cp) {
1096: case 'r':
1097: cp++;
1098: reg = *cp - '0';
1099: break;
1100: case 'a':
1101: cp++;
1102: reg = 9;
1103: break;
1104: case 'f':
1105: cp++;
1106: reg = 10;
1107: break;
1108: case 's':
1109: cp++;
1110: reg = 11;
1111: break;
1112: }
1113: set = set | 1 << reg;
1114: }
1115: cp++;
1116: }
1117: return(set);
1118: }
1119:
1120: /* determine registers used for double operand */
1121:
1122: int
1123: dscanreg(cp,flag)
1124: char * cp; /* operand string */
1125: boolean flag; /* true if register is destination */
1126: {
1127: int temp = scanreg(cp,flag); /* do normal scan */
1128:
1129: if (*cp == '%') /* if direct register reference... */
1130: temp = 3*temp; /* set bit and its left neighbor (reg+1) */
1131:
1132: return(temp);
1133: }
1134:
1135: sets(p) NODE *p; { /* set register destination bits */
1136:
1137: char *cp, *dst();
1138: int o;
1139: boolean dblflag = false; /* true if register double operand */
1140:
1141: switch (o = p->op) {
1142: case MOVBLB: case MOVBLH: case MOVBLW:
1143: return (0x0007);
1144:
1145: /* Procedure calls could potentially clobber all of the scratch registers.
1146: ** We would like call to "kill" all of them, but we can only be reasonably
1147: ** safe by saying it kills those registers in which it returns values.
1148: */
1149:
1150: case CALL:
1151: return(RETREG | CONCODES);
1152:
1153: /* Register doubles set two registers at a time: r and r+1 */
1154:
1155: case FADDD2: case FSUBD2: case FMULD2: case FDIVD2:
1156: case FADDD3: case FSUBD3: case FMULD3: case FDIVD3:
1157: case MOVWD: case MOVSD: case MOVDD: case MOVD:
1158: dblflag = true;
1159:
1160: default:
1161: cp = dst(p);
1162: if (cp != NULL)
1163: return((dblflag ? 3*setreg(cp) : setreg(cp)) | CONCODES );
1164: /* return reg bit and its left
1165: ** neighbor on double
1166: */
1167: else
1168: return ( ( ( o == RET )
1169: || ( CMPB <= o && o <= ATJNZW )
1170: || ( PUSHAW <= o && o <= PUSHBH ) ) ? CONCODES : 0 );
1171: }
1172: }
1173:
1174: setreg(cp) char *cp; { /* set index of register destination (if one) */
1175:
1176: if (*cp == '%')
1177: switch (*++cp) {
1178: case 'r':
1179: cp++;
1180: return (1 << (*cp - '0'));
1181: case 'a':
1182: return (1 << 9);
1183: case 'f':
1184: return (1 << 10);
1185: case 's':
1186: return (1 << 11);
1187: default: /* unrecognized name */
1188: break;
1189: }
1190: return(0); /* for non-register or unrecognized */
1191: }
1192:
1193: boolean
1194: isdead(cp,p) char *cp; NODE *p; { /* true iff *cp is dead after p */
1195:
1196: int reg;
1197:
1198: if (*cp != '%')
1199: return(false);
1200: switch(*++cp) {
1201: case 'r':
1202: reg = *++cp - '0';
1203: break;
1204: case 'a':
1205: reg = 9;
1206: break;
1207: case 'f':
1208: reg = 10;
1209: break;
1210: case 's':
1211: reg = 11;
1212: break;
1213: default: /* unrecognized name */
1214: return(false);
1215: }
1216: if ((p->nlive & (1 << reg)) == 0)
1217: return(true);
1218: else
1219: return(false);
1220: }
1221: char *
1222: getp(p) NODE *p; { /* return pointer to jump destination operand */
1223:
1224: switch (p->op) {
1225: case JMP: case JSB: case JZ: case JNZ:
1226: case JPOS: case JNPOS: case JNEG: case JNNEG: case JE:
1227: case JNE: case JL: case JLE: case JG: case JGE:
1228: case JLU: case JLEU: case JGU: case JGEU:
1229: return(p->op1);
1230: case RET:
1231: case SWITCH:
1232: case SWITCHT:
1233: return(NULL);
1234: case JBC: case JBS:
1235: return(p->op3);
1236: }
1237: }
1238:
1239: char *
1240: newlab() { /* generate a new label */
1241:
1242: static int lbn = 0;
1243: char *c;
1244:
1245: c = (char *)getspace(lbn < 100 ? 6 : (lbn < 1000 ? 7 : 8));
1246: sprintf(c, "..%d\0", lbn);
1247: lbn++;
1248: return(c);
1249: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.