123350Smckusick /* 223350Smckusick * Copyright (c) 1984 Regents of the University of California. 323350Smckusick * All rights reserved. The Berkeley software License Agreement 423350Smckusick * specifies the terms and conditions for redistribution. 523350Smckusick */ 616962Smckusick 716962Smckusick #ifndef lint 823350Smckusick char copyright[] = 923350Smckusick "@(#) Copyright (c) 1984 Regents of the University of California.\n\ 1023350Smckusick All rights reserved.\n"; 1116962Smckusick #endif not lint 1216962Smckusick 1323350Smckusick #ifndef lint 14*27462Skarels static char sccsid[] = "@(#)main.c 1.10 (Berkeley) 04/27/86"; 1523350Smckusick #endif not lint 1623350Smckusick 1716962Smckusick #include <stdio.h> 1816962Smckusick #include <ctype.h> 1916963Smckusick #include "inline.h" 2016962Smckusick 2116975Smckusick /* 2216975Smckusick * These are the pattern tables to be loaded 2316975Smckusick */ 24*27462Skarels struct pats *vax_inittables[] = { 2516975Smckusick language_ptab, 2616975Smckusick libc_ptab, 27*27462Skarels vax_libc_ptab, 2816975Smckusick machine_ptab, 29*27462Skarels vax_ptab, 3016975Smckusick 0 3116975Smckusick }; 3216975Smckusick 33*27462Skarels struct pats *vaxsubset_inittables[] = { 34*27462Skarels language_ptab, 35*27462Skarels libc_ptab, 36*27462Skarels vaxsubset_libc_ptab, 37*27462Skarels machine_ptab, 38*27462Skarels vaxsubset_ptab, 39*27462Skarels 0 40*27462Skarels }; 41*27462Skarels 4216980Smckusick /* 4316980Smckusick * Statistics collection 4416980Smckusick */ 4516980Smckusick struct stats { 4616980Smckusick int attempted; /* number of expansion attempts */ 4716980Smckusick int finished; /* expansions done before end of basic block */ 4816980Smckusick int lostmodified; /* mergers inhibited by intervening mod */ 4916980Smckusick int savedpush; /* successful push/pop merger */ 5016980Smckusick } stats; 5124395Smckusick 5224395Smckusick extern char *strcpy(); 5324395Smckusick 5424395Smckusick char *whoami; 5524395Smckusick int lineno = 0; 5616980Smckusick int dflag; 5716980Smckusick 5816962Smckusick main(argc, argv) 5916962Smckusick int argc; 6016962Smckusick char *argv[]; 6116962Smckusick { 6216962Smckusick register char *cp, *lp; 6316962Smckusick register char *bufp; 6416978Smckusick register struct pats *pp, **php; 6516978Smckusick struct pats **tablep; 6616978Smckusick register struct inststoptbl *itp, **ithp; 6716962Smckusick int size; 6816962Smckusick extern char *index(); 69*27462Skarels int subset = 0; 7016962Smckusick 7124395Smckusick whoami = argv[0]; 72*27462Skarels while (argc > 0 && argv[0][0] == '-') { 73*27462Skarels switch(argv[0][1]) { 74*27462Skarels 75*27462Skarels case 's': 76*27462Skarels subset++; 77*27462Skarels break; 78*27462Skarels 79*27462Skarels case 'd': 80*27462Skarels dflag++; 81*27462Skarels break; 82*27462Skarels 83*27462Skarels default: 84*27462Skarels break; 85*27462Skarels } 86*27462Skarels argc--, argv++; 87*27462Skarels } 8816962Smckusick if (argc > 1) 8916962Smckusick freopen(argv[1], "r", stdin); 9016962Smckusick if (argc > 2) 9116962Smckusick freopen(argv[2], "w", stdout); 9216962Smckusick /* 9316978Smckusick * Set up the hash table for the patterns. 9416962Smckusick */ 95*27462Skarels if (subset) 96*27462Skarels tablep = vaxsubset_inittables; 97*27462Skarels else 98*27462Skarels tablep = vax_inittables; 99*27462Skarels for ( ; *tablep; tablep++) { 10016975Smckusick for (pp = *tablep; pp->name[0] != '\0'; pp++) { 10116978Smckusick php = &patshdr[hash(pp->name, &size)]; 10216975Smckusick pp->size = size; 10316978Smckusick pp->next = *php; 10416978Smckusick *php = pp; 10516975Smckusick } 10616962Smckusick } 10716962Smckusick /* 10816978Smckusick * Set up the hash table for the instruction stop table. 10916978Smckusick */ 11016978Smckusick for (itp = inststoptable; itp->name[0] != '\0'; itp++) { 11116978Smckusick ithp = &inststoptblhdr[hash(itp->name, &size)]; 11216978Smckusick itp->size = size; 11316978Smckusick itp->next = *ithp; 11416978Smckusick *ithp = itp; 11516978Smckusick } 11616978Smckusick /* 11716962Smckusick * check each line and replace as appropriate 11816962Smckusick */ 11916962Smckusick buftail = bufhead = 0; 12016962Smckusick bufp = line[0]; 12116962Smckusick while (fgets(bufp, MAXLINELEN, stdin)) { 12224395Smckusick lineno++; 12316962Smckusick lp = index(bufp, LABELCHAR); 12416962Smckusick if (lp != NULL) { 12518448Smckusick for (cp = bufp; cp < lp; cp++) 12618448Smckusick if (!isalnum(*cp)) 12718448Smckusick break; 12818448Smckusick if (cp == lp) { 12918448Smckusick bufp = newline(); 13018448Smckusick if (*++lp == '\n') { 13118448Smckusick emptyqueue(); 13218448Smckusick continue; 13318448Smckusick } 13424395Smckusick (void) strcpy(bufp, lp); 13518448Smckusick *lp++ = '\n'; 13618448Smckusick *lp = '\0'; 13716962Smckusick emptyqueue(); 13816962Smckusick } 13916962Smckusick } 14016962Smckusick for (cp = bufp; isspace(*cp); cp++) 14116962Smckusick /* void */; 14216962Smckusick if ((cp = doreplaceon(cp)) == 0) { 14316962Smckusick bufp = newline(); 14416962Smckusick continue; 14516962Smckusick } 14616978Smckusick for (pp = patshdr[hash(cp, &size)]; pp; pp = pp->next) { 14716962Smckusick if (pp->size == size && bcmp(pp->name, cp, size) == 0) { 14824395Smckusick if (argcounterr(pp->args, countargs(bufp), pp->name)) { 14924395Smckusick pp = NULL; 15024395Smckusick break; 15124395Smckusick } 15216962Smckusick expand(pp->replace); 15316962Smckusick bufp = line[bufhead]; 15416962Smckusick break; 15516962Smckusick } 15616962Smckusick } 15716962Smckusick if (!pp) { 15816962Smckusick emptyqueue(); 15916962Smckusick fputs(bufp, stdout); 16016962Smckusick } 16116962Smckusick } 16216962Smckusick emptyqueue(); 16316980Smckusick if (dflag) 16424395Smckusick fprintf(stderr, "%s: %s %d, %s %d, %s %d, %s %d\n", 16524395Smckusick whoami, 16616980Smckusick "attempts", stats.attempted, 16716980Smckusick "finished", stats.finished, 16816980Smckusick "inhibited", stats.lostmodified, 16916980Smckusick "merged", stats.savedpush); 17016962Smckusick exit(0); 17116962Smckusick } 17216962Smckusick 17316962Smckusick /* 17416962Smckusick * Integrate an expansion into the assembly stream 17516962Smckusick */ 17616962Smckusick expand(replace) 17716962Smckusick char *replace; 17816962Smckusick { 17916962Smckusick register int curptr; 18016962Smckusick char *nextreplace, *argv[MAXARGS]; 18117202Smckusick int argc, argreg, foundarg, mod = 0, args = 0; 18216962Smckusick char parsebuf[BUFSIZ]; 18316962Smckusick 18416980Smckusick stats.attempted++; 18516980Smckusick for (curptr = bufhead; ; ) { 18616962Smckusick nextreplace = copyline(replace, line[bufhead]); 18716962Smckusick argc = parseline(line[bufhead], argv, parsebuf); 18816962Smckusick argreg = nextarg(argc, argv); 18916962Smckusick if (argreg == -1) 19016962Smckusick break; 19117202Smckusick args++; 19216978Smckusick for (foundarg = 0; curptr != buftail; ) { 19316978Smckusick curptr = PRED(curptr); 19416962Smckusick argc = parseline(line[curptr], argv, parsebuf); 19516978Smckusick if (isendofblock(argc, argv)) 19616962Smckusick break; 19716978Smckusick if (foundarg = ispusharg(argc, argv)) 19816978Smckusick break; 19916962Smckusick mod |= 1 << modifies(argc, argv); 20016962Smckusick } 20116978Smckusick if (!foundarg) 20216962Smckusick break; 20316962Smckusick replace = nextreplace; 20416962Smckusick if (mod & (1 << argreg)) { 20516980Smckusick stats.lostmodified++; 20616978Smckusick if (curptr == buftail) { 20716978Smckusick (void)newline(); 20816978Smckusick break; 20916978Smckusick } 21016962Smckusick (void)newline(); 21116962Smckusick } else { 21216980Smckusick stats.savedpush++; 21316962Smckusick rewrite(line[curptr], argc, argv, argreg); 21416962Smckusick mod |= 1 << argreg; 21516962Smckusick } 21616962Smckusick } 21716980Smckusick if (argreg == -1) 21816980Smckusick stats.finished++; 21916962Smckusick emptyqueue(); 22016962Smckusick fputs(replace, stdout); 22117202Smckusick cleanup(args); 22216962Smckusick } 22316962Smckusick 22416962Smckusick /* 22516962Smckusick * Parse a line of assembly language into opcode and arguments. 22616962Smckusick */ 22716962Smckusick parseline(linep, argv, linebuf) 22816962Smckusick char *linep; 22916962Smckusick char *argv[]; 23016962Smckusick char *linebuf; 23116962Smckusick { 23216962Smckusick register char *bufp = linebuf, *cp = linep; 23316962Smckusick register int argc = 0; 23416962Smckusick 23516962Smckusick for (;;) { 23616962Smckusick /* 23716962Smckusick * skip over white space 23816962Smckusick */ 23916962Smckusick while (isspace(*cp)) 24016962Smckusick cp++; 24116962Smckusick if (*cp == '\0') 24216962Smckusick return (argc); 24316962Smckusick /* 24416962Smckusick * copy argument 24516962Smckusick */ 24616962Smckusick if (argc == MAXARGS - 1) { 24716962Smckusick fprintf(stderr, "instruction too long->%s", linep); 24816962Smckusick return (argc); 24916962Smckusick } 25016962Smckusick argv[argc++] = bufp; 25116978Smckusick while (!isspace(*cp) && *cp != ARGSEPCHAR && *cp != COMMENTCHAR) 25216962Smckusick *bufp++ = *cp++; 25316962Smckusick *bufp++ = '\0'; 25416962Smckusick if (*cp == COMMENTCHAR) 25516962Smckusick return (argc); 25616978Smckusick if (*cp == ARGSEPCHAR) 25716962Smckusick cp++; 25816962Smckusick } 25916962Smckusick } 26016962Smckusick 26116962Smckusick /* 26216978Smckusick * Check for instructions that end a basic block. 26316978Smckusick */ 26416978Smckusick isendofblock(argc, argv) 26516978Smckusick int argc; 26616978Smckusick char *argv[]; 26716978Smckusick { 26816978Smckusick register struct inststoptbl *itp; 26916978Smckusick int size; 27016978Smckusick 27116978Smckusick if (argc == 0) 27216978Smckusick return (0); 27316978Smckusick for (itp = inststoptblhdr[hash(argv[0], &size)]; itp; itp = itp->next) 27416978Smckusick if (itp->size == size && bcmp(argv[0], itp->name, size) == 0) 27516978Smckusick return (1); 27616978Smckusick return (0); 27716978Smckusick } 27816978Smckusick 27916978Smckusick /* 28016962Smckusick * Copy a newline terminated string. 28116962Smckusick * Return pointer to character following last character copied. 28216962Smckusick */ 28316962Smckusick char * 28416962Smckusick copyline(from, to) 28516962Smckusick register char *from, *to; 28616962Smckusick { 28716962Smckusick 28816962Smckusick while (*from != '\n') 28916962Smckusick *to++ = *from++; 29016962Smckusick *to++ = *from++; 29116962Smckusick *to = '\0'; 29216962Smckusick return (from); 29316962Smckusick } 29416962Smckusick 29516962Smckusick /* 29624395Smckusick * Check for a disparity between the number of arguments a function 29724395Smckusick * is called with and the number which we expect to see. 29824395Smckusick * If the error is unrecoverable, return 1, otherwise 0. 29924395Smckusick */ 30024395Smckusick argcounterr(args, callargs, name) 30124395Smckusick int args, callargs; 30224395Smckusick char *name; 30324395Smckusick { 30424395Smckusick register char *cp; 30524395Smckusick char namebuf[MAXLINELEN]; 30624395Smckusick 30724395Smckusick if (args == callargs) 30824395Smckusick return (0); 30924395Smckusick cp = strcpy(namebuf, name); 31024395Smckusick while (*cp != '\0' && *cp != '\n') 31124395Smckusick ++cp; 31224395Smckusick if (*cp == '\n') 31324395Smckusick *cp = '\0'; 31424395Smckusick if (callargs >= 0) { 31524395Smckusick fprintf(stderr, 31624395Smckusick "%s: error: arg count mismatch, %d != %d for '%s' at line %d\n", 31724395Smckusick whoami, callargs, args, namebuf, lineno); 31824395Smckusick return (1); 31924395Smckusick } 32024395Smckusick fprintf(stderr, 32124395Smckusick "%s: warning: can't verify arg count for '%s' at line %d\n", 32224395Smckusick whoami, namebuf, lineno); 32324395Smckusick return (0); 32424395Smckusick } 32524395Smckusick 32624395Smckusick /* 32716962Smckusick * open space for next line in the queue 32816962Smckusick */ 32916962Smckusick char * 33016962Smckusick newline() 33116962Smckusick { 33216962Smckusick bufhead = SUCC(bufhead); 33316962Smckusick if (bufhead == buftail) { 33416962Smckusick fputs(line[buftail], stdout); 33516962Smckusick buftail = SUCC(buftail); 33616962Smckusick } 33716962Smckusick return (line[bufhead]); 33816962Smckusick } 33916962Smckusick 34016962Smckusick /* 34116962Smckusick * empty the queue by printing out all its lines. 34216962Smckusick */ 34316962Smckusick emptyqueue() 34416962Smckusick { 34516962Smckusick while (buftail != bufhead) { 34616962Smckusick fputs(line[buftail], stdout); 34716962Smckusick buftail = SUCC(buftail); 34816962Smckusick } 34916962Smckusick } 35016962Smckusick 35116962Smckusick /* 35216962Smckusick * Compute the hash of a string. 35316962Smckusick * Return the hash and the size of the item hashed 35416962Smckusick */ 35516962Smckusick hash(cp, size) 35616962Smckusick char *cp; 35716962Smckusick int *size; 35816962Smckusick { 35916962Smckusick register char *cp1 = cp; 36016978Smckusick register int hash = 0; 36116962Smckusick 36216962Smckusick while (*cp1 && *cp1 != '\n') 36316962Smckusick hash += (int)*cp1++; 36416962Smckusick *size = cp1 - cp + 1; 36516962Smckusick hash &= HSHSIZ - 1; 36616978Smckusick return (hash); 36716962Smckusick } 368