124038Ssam /* 224038Ssam * Copyright (c) 1984 Regents of the University of California. 324038Ssam * All rights reserved. The Berkeley software License Agreement 424038Ssam * specifies the terms and conditions for redistribution. 524038Ssam */ 624038Ssam 724038Ssam #ifndef lint 824038Ssam char copyright[] = 924038Ssam "@(#) Copyright (c) 1984 Regents of the University of California.\n\ 1024038Ssam All rights reserved.\n"; 1125692Ssam #endif 1224038Ssam 1324038Ssam #ifndef lint 14*26405Ssam static char sccsid[] = "@(#)main.c 1.3 (Berkeley) 02/24/86"; 1525692Ssam #endif 1624038Ssam 1724038Ssam #include <stdio.h> 1824038Ssam #include <ctype.h> 1924038Ssam #include "inline.h" 2024038Ssam 2124038Ssam /* 2224038Ssam * These are the pattern tables to be loaded 2324038Ssam */ 2424038Ssam struct pats *inittables[] = { 2524038Ssam language_ptab, 2624038Ssam libc_ptab, 2724038Ssam machine_ptab, 2824038Ssam 0 2924038Ssam }; 3024038Ssam 3124038Ssam /* 3224038Ssam * Statistics collection 3324038Ssam */ 3424038Ssam struct stats { 3524038Ssam int attempted; /* number of expansion attempts */ 3624038Ssam int finished; /* expansions done before end of basic block */ 3724038Ssam int lostmodified; /* mergers inhibited by intervening mod */ 3824038Ssam int savedpush; /* successful push/pop merger */ 3924038Ssam } stats; 4024038Ssam 41*26405Ssam extern char *strcpy(); 42*26405Ssam 43*26405Ssam char *whoami; 44*26405Ssam int lineno = 0; 45*26405Ssam int dflag; 46*26405Ssam 4724038Ssam main(argc, argv) 4824038Ssam int argc; 4924038Ssam char *argv[]; 5024038Ssam { 5124038Ssam register char *cp, *lp; 5224038Ssam register char *bufp; 5324038Ssam register struct pats *pp, **php; 5424038Ssam struct pats **tablep; 5524038Ssam register struct inststoptbl *itp, **ithp; 5624038Ssam int size; 5724038Ssam extern char *index(); 5824038Ssam 59*26405Ssam whoami = argv[0]; 6024038Ssam if (argc > 1 && bcmp(argv[1], "-d", 3) == 0) 6124038Ssam dflag++, argc--, argv++; 6224038Ssam if (argc > 1) 6324038Ssam freopen(argv[1], "r", stdin); 6424038Ssam if (argc > 2) 6524038Ssam freopen(argv[2], "w", stdout); 6624038Ssam /* 6724038Ssam * Set up the hash table for the patterns. 6824038Ssam */ 6924038Ssam for (tablep = inittables; *tablep; tablep++) { 7024038Ssam for (pp = *tablep; pp->name[0] != '\0'; pp++) { 7124038Ssam php = &patshdr[hash(pp->name, &size)]; 7224038Ssam pp->size = size; 7324038Ssam pp->next = *php; 7424038Ssam *php = pp; 7524038Ssam } 7624038Ssam } 7724038Ssam /* 7824038Ssam * Set up the hash table for the instruction stop table. 7924038Ssam */ 8024038Ssam for (itp = inststoptable; itp->name[0] != '\0'; itp++) { 8124038Ssam ithp = &inststoptblhdr[hash(itp->name, &size)]; 8224038Ssam itp->size = size; 8324038Ssam itp->next = *ithp; 8424038Ssam *ithp = itp; 8524038Ssam } 8624038Ssam /* 8724038Ssam * check each line and replace as appropriate 8824038Ssam */ 8924038Ssam buftail = bufhead = 0; 9024038Ssam bufp = line[0]; 9124038Ssam while (fgets(bufp, MAXLINELEN, stdin)) { 92*26405Ssam lineno++; 9324038Ssam lp = index(bufp, LABELCHAR); 9424038Ssam if (lp != NULL) { 9524038Ssam for (cp = bufp; cp < lp; cp++) 9624038Ssam if (!isalnum(*cp)) 9724038Ssam break; 9824038Ssam if (cp == lp) { 9924038Ssam bufp = newline(); 10024038Ssam if (*++lp == '\n') { 10124038Ssam emptyqueue(); 10224038Ssam continue; 10324038Ssam } 104*26405Ssam (void) strcpy(bufp, lp); 10524038Ssam *lp++ = '\n'; 10624038Ssam *lp = '\0'; 10724038Ssam emptyqueue(); 10824038Ssam } 10924038Ssam } 11024038Ssam for (cp = bufp; isspace(*cp); cp++) 11124038Ssam /* void */; 11224038Ssam if ((cp = doreplaceon(cp)) == 0) { 11324038Ssam bufp = newline(); 11424038Ssam continue; 11524038Ssam } 11624038Ssam for (pp = patshdr[hash(cp, &size)]; pp; pp = pp->next) { 11724038Ssam if (pp->size == size && bcmp(pp->name, cp, size) == 0) { 118*26405Ssam if (argcounterr(pp->args, countargs(bufp), 119*26405Ssam pp->name)) { 120*26405Ssam pp = NULL; 121*26405Ssam break; 122*26405Ssam } 12324038Ssam expand(pp->replace); 12424038Ssam bufp = line[bufhead]; 12524038Ssam break; 12624038Ssam } 12724038Ssam } 12824038Ssam if (!pp) { 12924038Ssam emptyqueue(); 13024038Ssam fputs(bufp, stdout); 13124038Ssam } 13224038Ssam } 13324038Ssam emptyqueue(); 13424038Ssam if (dflag) 135*26405Ssam fprintf(stderr, "%s: %s %d, %s %d, %s %d, %s %d\n", 136*26405Ssam whoami, 13724038Ssam "attempts", stats.attempted, 13824038Ssam "finished", stats.finished, 13924038Ssam "inhibited", stats.lostmodified, 14024038Ssam "merged", stats.savedpush); 14124038Ssam exit(0); 14224038Ssam } 14324038Ssam 14424038Ssam /* 14524038Ssam * Integrate an expansion into the assembly stream 14624038Ssam */ 14724038Ssam expand(replace) 14824038Ssam char *replace; 14924038Ssam { 15024038Ssam register int curptr; 15124038Ssam char *nextreplace, *argv[MAXARGS]; 15224038Ssam int argc, argreg, foundarg, mod = 0, args = 0; 15324038Ssam char parsebuf[BUFSIZ]; 15424038Ssam 15524038Ssam stats.attempted++; 15624038Ssam for (curptr = bufhead; ; ) { 15724038Ssam nextreplace = copyline(replace, line[bufhead]); 15824038Ssam argc = parseline(line[bufhead], argv, parsebuf); 15924038Ssam argreg = nextarg(argc, argv); 16024038Ssam if (argreg == -1) 16124038Ssam break; 16224038Ssam args++; 16324038Ssam for (foundarg = 0; curptr != buftail; ) { 16424038Ssam curptr = PRED(curptr); 16524038Ssam argc = parseline(line[curptr], argv, parsebuf); 16624038Ssam if (isendofblock(argc, argv)) 16724038Ssam break; 16824038Ssam if (foundarg = ispusharg(argc, argv)) 16924038Ssam break; 17024038Ssam mod |= 1 << modifies(argc, argv); 17124038Ssam } 17224038Ssam if (!foundarg) 17324038Ssam break; 17424038Ssam replace = nextreplace; 17524038Ssam if (mod & (1 << argreg)) { 17624038Ssam stats.lostmodified++; 17724038Ssam if (curptr == buftail) { 17824038Ssam (void)newline(); 17924038Ssam break; 18024038Ssam } 18124038Ssam (void)newline(); 18224038Ssam } else { 18324038Ssam stats.savedpush++; 18424038Ssam rewrite(line[curptr], argc, argv, argreg); 18524038Ssam mod |= 1 << argreg; 18624038Ssam } 18724038Ssam } 18824038Ssam if (argreg == -1) 18924038Ssam stats.finished++; 19024038Ssam emptyqueue(); 19124038Ssam fputs(replace, stdout); 19224038Ssam cleanup(args); 19324038Ssam } 19424038Ssam 19524038Ssam /* 19624038Ssam * Parse a line of assembly language into opcode and arguments. 19724038Ssam */ 19824038Ssam parseline(linep, argv, linebuf) 19924038Ssam char *linep; 20024038Ssam char *argv[]; 20124038Ssam char *linebuf; 20224038Ssam { 20324038Ssam register char *bufp = linebuf, *cp = linep; 20424038Ssam register int argc = 0; 20524038Ssam 20624038Ssam for (;;) { 20724038Ssam /* 20824038Ssam * skip over white space 20924038Ssam */ 21024038Ssam while (isspace(*cp)) 21124038Ssam cp++; 21224038Ssam if (*cp == '\0') 21324038Ssam return (argc); 21424038Ssam /* 21524038Ssam * copy argument 21624038Ssam */ 21724038Ssam if (argc == MAXARGS - 1) { 21824038Ssam fprintf(stderr, "instruction too long->%s", linep); 21924038Ssam return (argc); 22024038Ssam } 22124038Ssam argv[argc++] = bufp; 22224038Ssam while (!isspace(*cp) && *cp != ARGSEPCHAR && *cp != COMMENTCHAR) 22324038Ssam *bufp++ = *cp++; 22424038Ssam *bufp++ = '\0'; 22524038Ssam if (*cp == COMMENTCHAR) 22624038Ssam return (argc); 22724038Ssam if (*cp == ARGSEPCHAR) 22824038Ssam cp++; 22924038Ssam } 23024038Ssam } 23124038Ssam 23224038Ssam /* 23324038Ssam * Check for instructions that end a basic block. 23424038Ssam */ 23524038Ssam isendofblock(argc, argv) 23624038Ssam int argc; 23724038Ssam char *argv[]; 23824038Ssam { 23924038Ssam register struct inststoptbl *itp; 24024038Ssam int size; 24124038Ssam 24224038Ssam if (argc == 0) 24324038Ssam return (0); 24424038Ssam for (itp = inststoptblhdr[hash(argv[0], &size)]; itp; itp = itp->next) 24524038Ssam if (itp->size == size && bcmp(argv[0], itp->name, size) == 0) 24624038Ssam return (1); 24724038Ssam return (0); 24824038Ssam } 24924038Ssam 25024038Ssam /* 25124038Ssam * Copy a newline terminated string. 25224038Ssam * Return pointer to character following last character copied. 25324038Ssam */ 25424038Ssam char * 25524038Ssam copyline(from, to) 25624038Ssam register char *from, *to; 25724038Ssam { 25824038Ssam 25924038Ssam while (*from != '\n') 26024038Ssam *to++ = *from++; 26124038Ssam *to++ = *from++; 26224038Ssam *to = '\0'; 26324038Ssam return (from); 26424038Ssam } 26524038Ssam 26624038Ssam /* 267*26405Ssam * Check for a disparity between the number of arguments a function 268*26405Ssam * is called with and the number which we expect to see. 269*26405Ssam * If the error is unrecoverable, return 1, otherwise 0. 270*26405Ssam */ 271*26405Ssam argcounterr(args, callargs, name) 272*26405Ssam int args, callargs; 273*26405Ssam char *name; 274*26405Ssam { 275*26405Ssam register char *cp; 276*26405Ssam char namebuf[MAXLINELEN]; 277*26405Ssam 278*26405Ssam if (args == callargs) 279*26405Ssam return (0); 280*26405Ssam cp = strcpy(namebuf, name); 281*26405Ssam while (*cp != '\0' && *cp != '\n') 282*26405Ssam ++cp; 283*26405Ssam if (*cp == '\n') 284*26405Ssam *cp = '\0'; 285*26405Ssam if (callargs >= 0) { 286*26405Ssam fprintf(stderr, 287*26405Ssam "%s: error: arg count mismatch, %d != %d for '%s' at line %d\n", 288*26405Ssam whoami, callargs, args, namebuf, lineno); 289*26405Ssam return (1); 290*26405Ssam } 291*26405Ssam fprintf(stderr, 292*26405Ssam "%s: warning: can't verify arg count for '%s' at line %d\n", 293*26405Ssam whoami, namebuf, lineno); 294*26405Ssam return (0); 295*26405Ssam } 296*26405Ssam 297*26405Ssam /* 29824038Ssam * open space for next line in the queue 29924038Ssam */ 30024038Ssam char * 30124038Ssam newline() 30224038Ssam { 30324038Ssam bufhead = SUCC(bufhead); 30424038Ssam if (bufhead == buftail) { 30524038Ssam fputs(line[buftail], stdout); 30624038Ssam buftail = SUCC(buftail); 30724038Ssam } 30824038Ssam return (line[bufhead]); 30924038Ssam } 31024038Ssam 31124038Ssam /* 31224038Ssam * empty the queue by printing out all its lines. 31324038Ssam */ 31424038Ssam emptyqueue() 31524038Ssam { 31624038Ssam while (buftail != bufhead) { 31724038Ssam fputs(line[buftail], stdout); 31824038Ssam buftail = SUCC(buftail); 31924038Ssam } 32024038Ssam } 32124038Ssam 32224038Ssam /* 32324038Ssam * Compute the hash of a string. 32424038Ssam * Return the hash and the size of the item hashed 32524038Ssam */ 32624038Ssam hash(cp, size) 32724038Ssam char *cp; 32824038Ssam int *size; 32924038Ssam { 33024038Ssam register char *cp1 = cp; 33124038Ssam register int hash = 0; 33224038Ssam 33324038Ssam while (*cp1 && *cp1 != '\n') 33424038Ssam hash += (int)*cp1++; 33524038Ssam *size = cp1 - cp + 1; 33624038Ssam hash &= HSHSIZ - 1; 33724038Ssam return (hash); 33824038Ssam } 339