📄 c20.c
字号:
#ifndef lintstatic char *sccsid = "@(#)c20.c 4.1 ULTRIX 11/23/87";#endif lint/************************************************************************ * * * Copyright (c) 1985 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * Modification History * * 006 Victoria Holt, 26-Aug-86 * Bug fix in remove_branch_to_return() to fix an infinite loop. * * 005 David Metsky, 13-May-1986 * Added code to ignore the -f flag that came from the new fortran * compiler. Incorperated the code that resulted from the -f flag, * which uses the correct move length. * * 004 Victoria Holt, 08-May-86 * Added support for .stab directives (see STAB). Modified * getline() so that it does not interpret a string containing * a colon as a label. * * 003 David L Ballenger, 06-Mar-1986 * Add code to remove_branch_to_return() to detect empty inifinite * loops, i.e. unconditional branch which branches to itself as in * "for (;;);". * * 002 David L Ballenger, 25-Feb-1986 * Add code to align labels under the appropriate conditions, * remove branches to returns, and uneccessary branches. * * David L Ballenger, 3-Jul-1985 * 001 Allocate optimal size buffers for stdin and stdout. This can * make c2 run faster and also fixes problems with interactions * between c2's allocation routine and stdio's use of malloc(). * * Based on: c20.c 4.6 (Berkeley) 8/11/83 * ************************************************************************//* * C object code improver */#include "c2.h"#include <stdio.h>#include <ctype.h>#include <sys/types.h>#include <sys/stat.h>int ioflag;long isn = 2000000;struct optab *oplook();struct optab *getline();long lgensym[10] = {100000L,200000L,300000L,400000L,500000L,600000L,700000L,800000L,900000L,1000000L};static int n_aligns = 0; /* # of alignments inserted */static void remove_branch_to_return(), align_labels();#define STDERR_BUFSIZ 132 /* Make stderr line buffered with a buffer * this size. Which should be large enough for * most error messages. *//* get_buffer() * * Routine to allocate optimal size buffers for files. */static voidget_buffer(file) FILE *file;{ struct stat stat; /* Call fstat() to get optimal buffer size for file. BUFSIZE is * the default. */ if ( (fstat(fileno(file),&stat) != 0) || (stat.st_blksize <= 0) ) stat.st_blksize = BUFSIZ; /* Call setvbuf() to set up buffer. Pass a NULL buffer pointer * so setvbuf will dynamically allocate the buffer. */ if (setvbuf(file,NULL,_IOFBF,stat.st_blksize) != 0) { fprintf(stderr, "Optimizer: out of space\n"); exit(1); }}#define ALLOCSIZE 4096struct node *alloc(an){ register int n; register char *p; n = an; n+=sizeof(char *)-1; n &= ~(sizeof(char *)-1); if (lasta+n >= lastr) { if (sbrk(ALLOCSIZE) == -1) { fprintf(stderr, "Optimizer: out of space\n"); exit(1); } lastr += ALLOCSIZE; } p = lasta; lasta += n; return(p);}main(argc, argv)char **argv;{ register int niter, maxiter, isend; int nflag,infound; nflag = 0; infound=0; argc--; argv++; /* Make stderr line buffered, so that error messages from * concurrent processes don't get mixed in with ours. */ setvbuf(stderr,NULL,_IOLBF,STDERR_BUFSIZ); while (argc>0) {/* get flags */ if (**argv=='+') debug++; else if (**argv=='-') { switch((*argv)[1]) { case 'i': ioflag++; break; case 'n': nflag++; break; case 'f': /* ignore -f 005 */ break; case '\000': /* Place holder for input file spec */ infound++; break; default: fprintf(stderr, "C2: invalid option %s\n", *argv); break; } } else if (infound==0) { if (freopen(*argv, "r", stdin) ==NULL) { fprintf(stderr,"C2: can't find %s\n", *argv); exit(1); } ++infound; } else if (freopen(*argv, "w", stdout) ==NULL) { fprintf(stderr,"C2: can't create %s\n", *argv); exit(1); } argc--; argv++; } /* Set up buffers for stdin and stdout. Note that this must * be done before setting up the information for c2's own memory * allocation routine. Stdin and stdout will be fully buffered with * an "optimal" buffer size. */ get_buffer(stdin); get_buffer(stdout); /* Set up information for c2's memory allocation scheme. */ lasta = lastr = sbrk(2); opsetup(); lasta = firstr = lastr = alloc(0); maxiter = 0; do { isend = input(); niter = 0; bmove(); do { refcount(); do { iterate(); clearreg(); niter++; } while (nchange); comjump(); rmove(); } while (nchange || jumpsw()); /* * Do some final optimizations: * - remove branches to returns * - align certain labels. * - use ACBx, AOBxxx, and SOBxxx instructions * where appopriate * - get rid of unused labels. */ remove_branch_to_return(); align_labels(); addsob(); refcount(); /* * Output the code */ output(); if (niter > maxiter) maxiter = niter; lasta = firstr; } while (isend); if (nflag) { fprintf(stderr,"%d labels aligned\n",n_aligns); fprintf(stderr,"%d iterations\n", maxiter); fprintf(stderr,"%d jumps to jumps\n", nbrbr); fprintf(stderr,"%d inst. after jumps\n", iaftbr); fprintf(stderr,"%d jumps to .+1\n", njp1); fprintf(stderr,"%d redundant labels\n", nrlab); fprintf(stderr,"%d cross-jumps\n", nxjump); fprintf(stderr,"%d code motions\n", ncmot); fprintf(stderr,"%d branches reversed\n", nrevbr); fprintf(stderr,"%d redundant moves\n", redunm); fprintf(stderr,"%d simplified addresses\n", nsaddr); fprintf(stderr,"%d loops inverted\n", loopiv); fprintf(stderr,"%d redundant jumps\n", nredunj); fprintf(stderr,"%d common seqs before jmp's\n", ncomj); fprintf(stderr,"%d skips over jumps\n", nskip); fprintf(stderr,"%d sob's added\n", nsob); fprintf(stderr,"%d redundant tst's\n", nrtst); fprintf(stderr,"%d jump on bit\n", nbj); fprintf(stderr,"%d field operations\n", nfield); fprintf(stderr,"%dK core\n", ((unsigned)lastr+01777) >> 10); } putc('\n',stdout); fflush(stdout); exit(0);}input(){ register struct node *p, *lastp; struct optab *op; register char *cp1; static struct optab F77JSW = {".long", T(JSW,1)}; lastp = &first; for (;;) { top: op = getline(); if (debug && op==0) fprintf(stderr,"? %s\n",line); switch (op->opcode&0377) { case LABEL: p = alloc(sizeof first); if (isdigit(line[0]) && (p->labno=locdef(line)) || (line[0] == 'L') && (p->labno=getnum(line+1))) { p->combop = LABEL; if (p->labno<100000L && isn<=p->labno) isn=1+p->labno; p->code = 0; } else { p->combop = DLABEL; p->labno = 0; p->code = copy(line); } break; case LGEN: if (*curlp!='L' && !locuse(curlp)) goto std; op= &F77JSW; case JBR: if (op->opcode==T(JBR,RET) || op->opcode==T(JBR,RSB)) goto std; case CBR: case JMP: case JSW: case SOBGEQ: case SOBGTR: case AOBLEQ: case AOBLSS: case ACB: p = alloc(sizeof first); p->combop = op->opcode; p->code=0; cp1=curlp; if ((!isdigit(*cp1) || 0==(p->labno=locuse(cp1))) && (*cp1!='L' || 0==(p->labno = getnum(cp1+1)))) {/* jbs, etc.? */ while (*cp1++); while (*--cp1!=',' && cp1!=curlp); if (cp1==curlp || (!isdigit(*++cp1) || 0==(p->labno=locuse(cp1))) && (*cp1!='L' || 0==(p->labno=getnum(cp1+1)))) p->labno = 0; else *--cp1=0; p->code = copy(curlp); } if (isn<=p->labno) isn=1+p->labno; break; case MOVA: p=alloc(sizeof first); p->combop=op->opcode; p->code=0; cp1=curlp+1; if (cp1[-1]=='L' || isdigit(cp1[-1])) { while (*cp1++!=','); *--cp1=0; if (0!=(p->labno=locuse(curlp)) || 0!=(p->labno=getnum(curlp+1))) p->code=copy(cp1+1); else {*cp1=','; p->code=copy(curlp);} } else {p->code=copy(--cp1); p->labno=0;} break; case SET: case COMM: case LCOMM: case STAB: printf("%s\n",line); goto top; case BSS: case DATA: for (;;) { printf("%s%c",line,(op->opcode==LABEL ? ':' : '\n')); if (op->opcode==TEXT) goto top; if (END==(op=getline())->opcode) {/* dangling .data is bad for you */ printf(".text\n"); break; } } std: default: p = alloc(sizeof first); p->combop = op->opcode; p->labno = 0; p->code = copy(curlp); break; } p->forw = 0; p->back = lastp; p->pop = op; lastp->forw = p; lastp = p; p->ref = 0; if (p->op==CASE) { char *lp; int ncase; lp=curlp; while (*lp++); while (*--lp!='$'); ncase=getnum(lp+1); if (LABEL!=(getline())->opcode) abort(-2); do { if (WGEN!=(getline())->opcode) abort(-3); p = alloc(sizeof first); p->combop = JSW; p->code = 0; lp=curlp; while(*lp++!='-'); *--lp=0; p->labno=getnum(curlp+1); if (isn<=p->labno) isn=1+p->labno; p->forw = 0; p->back = lastp; lastp->forw = p; lastp = p; p->ref = 0; p->pop=0; } while (--ncase>=0); } if (op->opcode==EROU) return(1); if (op->opcode==END) return(0); }}struct optab *getline(){ register char *lp; register c; Boolean instring; static struct optab OPLABEL={"",LABEL}; static struct optab OPEND={"",END}; lp = line; instring = false; while (EOF!=(c=getchar()) && isspace(c)); while (EOF!=c) { if (c == '"') { instring = (instring == true) ? false : true; } if (c==':' && !instring) { *lp++ = 0; return(&OPLABEL); } if (c=='\n') { *lp++ = 0; return(oplook()); } *lp++ = c; c = getchar(); } *lp++ = 0; return(&OPEND);}longgetnum(p)register char *p;{ register c; int neg; register long n; n = 0; neg=0; if (*p=='-') {++neg; ++p;} while (isdigit(c = *p++)) { c -= '0'; n *= 10; if (neg) n -= c; else n += c; } if (*--p != 0) return(0); return(n);}locuse(p)register char *p;{ register c; int neg; register long n; if (!isdigit(p[0]) || p[1] != 'f' && p[1] != 'b' || p[2]) return(0); return (lgensym[p[0] - '0'] - (p[1] == 'b'));}locdef(p)register char *p;{ if (!isdigit(p[0]) || p[1]) return(0); return (lgensym[p[0] - '0']++);}/* isloop * * Routine to determine if a label node is the top of a loop. It does this * by searching forward from the label node, and if it finds a branch * statement that refers to it then it assumes that it is a loop. */static struct node *isloop(label) register struct node *label;{ register struct node *next = label; register int branch_seen = 0; while (next = next->forw) { if ((next->op == CBR) || (next->combop == JBR)) { if (next->ref == label) { /* * This looks like a loop. */ return(1); } else { /* Remember that we saw a branch */ branch_seen = 1; } } else if ((next->op == JBR) && (branch_seen == 0)) { /* * We've hit a RET or RSB, and there is no way * to branch around it. This can't be a loop, * at least not an iterative one. There may be * a back reference to label somewhere ahead of * this point due to comjump(), but that isn't * the kind of loop we're looking for. */ return(0); } } return(0);}/* align_labels * * Routine to align labels in what is hoped is a optimal manner, i.e.: * * - labels which have a high enough reference count, i.e. the * first statement after a series of: * * if () {} * else if () {} * else if () {} * * - labels which are the tops of loops * * Labels following unconditional branches are not handled here. The * assembler handles them when it decides what do to with jbr and jxxx * instructions. Labels after RETs and RSBs are handled here. */static voidalign_labels(){ register struct node *prev; register struct node *label; /* Loop through all the statements looking for labels. */ prev = &first; while (label = prev->forw) { if ( (label->op == LABEL) && (prev->combop != JBR) ) { /* * Align this label? */ if ((prev->op == JBR) /* after RET/RSB */ || (label->refc > 2) /* if else if seq */ || (isloop(label)) /* loop */ ) { /* Insert an .align 2 between the * previous statement and the label. * This will longword align the label. */ register struct node *align; align = alloc(sizeof(*align)); prev->forw = align; align->back = prev; align->forw = label; label->back = align; align->combop = ALIGN; if (prev->op == JBR) { /* Pad with HALTs */ align->code = "2"; } else { /* Pad with NOPs since we might * drop through. */ align->code = "2,1";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -