142fa1082Ssam /* 242fa1082Ssam * Copyright (c) 1984 Regents of the University of California. 342fa1082Ssam * All rights reserved. The Berkeley software License Agreement 442fa1082Ssam * specifies the terms and conditions for redistribution. 542fa1082Ssam */ 642fa1082Ssam 742fa1082Ssam #ifndef lint 842fa1082Ssam char copyright[] = 942fa1082Ssam "@(#) Copyright (c) 1984 Regents of the University of California.\n\ 1042fa1082Ssam All rights reserved.\n"; 11b679c950Ssam #endif 1242fa1082Ssam 1342fa1082Ssam #ifndef lint 14*54094f50Ssam static char sccsid[] = "@(#)main.c 1.3 (Berkeley) 02/24/86"; 15b679c950Ssam #endif 1642fa1082Ssam 1742fa1082Ssam #include <stdio.h> 1842fa1082Ssam #include <ctype.h> 1942fa1082Ssam #include "inline.h" 2042fa1082Ssam 2142fa1082Ssam /* 2242fa1082Ssam * These are the pattern tables to be loaded 2342fa1082Ssam */ 2442fa1082Ssam struct pats *inittables[] = { 2542fa1082Ssam language_ptab, 2642fa1082Ssam libc_ptab, 2742fa1082Ssam machine_ptab, 2842fa1082Ssam 0 2942fa1082Ssam }; 3042fa1082Ssam 3142fa1082Ssam /* 3242fa1082Ssam * Statistics collection 3342fa1082Ssam */ 3442fa1082Ssam struct stats { 3542fa1082Ssam int attempted; /* number of expansion attempts */ 3642fa1082Ssam int finished; /* expansions done before end of basic block */ 3742fa1082Ssam int lostmodified; /* mergers inhibited by intervening mod */ 3842fa1082Ssam int savedpush; /* successful push/pop merger */ 3942fa1082Ssam } stats; 40*54094f50Ssam 41*54094f50Ssam extern char *strcpy(); 42*54094f50Ssam 43*54094f50Ssam char *whoami; 44*54094f50Ssam int lineno = 0; 4542fa1082Ssam int dflag; 4642fa1082Ssam 4742fa1082Ssam main(argc, argv) 4842fa1082Ssam int argc; 4942fa1082Ssam char *argv[]; 5042fa1082Ssam { 5142fa1082Ssam register char *cp, *lp; 5242fa1082Ssam register char *bufp; 5342fa1082Ssam register struct pats *pp, **php; 5442fa1082Ssam struct pats **tablep; 5542fa1082Ssam register struct inststoptbl *itp, **ithp; 5642fa1082Ssam int size; 5742fa1082Ssam extern char *index(); 5842fa1082Ssam 59*54094f50Ssam whoami = argv[0]; 6042fa1082Ssam if (argc > 1 && bcmp(argv[1], "-d", 3) == 0) 6142fa1082Ssam dflag++, argc--, argv++; 6242fa1082Ssam if (argc > 1) 6342fa1082Ssam freopen(argv[1], "r", stdin); 6442fa1082Ssam if (argc > 2) 6542fa1082Ssam freopen(argv[2], "w", stdout); 6642fa1082Ssam /* 6742fa1082Ssam * Set up the hash table for the patterns. 6842fa1082Ssam */ 6942fa1082Ssam for (tablep = inittables; *tablep; tablep++) { 7042fa1082Ssam for (pp = *tablep; pp->name[0] != '\0'; pp++) { 7142fa1082Ssam php = &patshdr[hash(pp->name, &size)]; 7242fa1082Ssam pp->size = size; 7342fa1082Ssam pp->next = *php; 7442fa1082Ssam *php = pp; 7542fa1082Ssam } 7642fa1082Ssam } 7742fa1082Ssam /* 7842fa1082Ssam * Set up the hash table for the instruction stop table. 7942fa1082Ssam */ 8042fa1082Ssam for (itp = inststoptable; itp->name[0] != '\0'; itp++) { 8142fa1082Ssam ithp = &inststoptblhdr[hash(itp->name, &size)]; 8242fa1082Ssam itp->size = size; 8342fa1082Ssam itp->next = *ithp; 8442fa1082Ssam *ithp = itp; 8542fa1082Ssam } 8642fa1082Ssam /* 8742fa1082Ssam * check each line and replace as appropriate 8842fa1082Ssam */ 8942fa1082Ssam buftail = bufhead = 0; 9042fa1082Ssam bufp = line[0]; 9142fa1082Ssam while (fgets(bufp, MAXLINELEN, stdin)) { 92*54094f50Ssam lineno++; 9342fa1082Ssam lp = index(bufp, LABELCHAR); 9442fa1082Ssam if (lp != NULL) { 9542fa1082Ssam for (cp = bufp; cp < lp; cp++) 9642fa1082Ssam if (!isalnum(*cp)) 9742fa1082Ssam break; 9842fa1082Ssam if (cp == lp) { 9942fa1082Ssam bufp = newline(); 10042fa1082Ssam if (*++lp == '\n') { 10142fa1082Ssam emptyqueue(); 10242fa1082Ssam continue; 10342fa1082Ssam } 104*54094f50Ssam (void) strcpy(bufp, lp); 10542fa1082Ssam *lp++ = '\n'; 10642fa1082Ssam *lp = '\0'; 10742fa1082Ssam emptyqueue(); 10842fa1082Ssam } 10942fa1082Ssam } 11042fa1082Ssam for (cp = bufp; isspace(*cp); cp++) 11142fa1082Ssam /* void */; 11242fa1082Ssam if ((cp = doreplaceon(cp)) == 0) { 11342fa1082Ssam bufp = newline(); 11442fa1082Ssam continue; 11542fa1082Ssam } 11642fa1082Ssam for (pp = patshdr[hash(cp, &size)]; pp; pp = pp->next) { 11742fa1082Ssam if (pp->size == size && bcmp(pp->name, cp, size) == 0) { 118*54094f50Ssam if (argcounterr(pp->args, countargs(bufp), 119*54094f50Ssam pp->name)) { 120*54094f50Ssam pp = NULL; 121*54094f50Ssam break; 122*54094f50Ssam } 12342fa1082Ssam expand(pp->replace); 12442fa1082Ssam bufp = line[bufhead]; 12542fa1082Ssam break; 12642fa1082Ssam } 12742fa1082Ssam } 12842fa1082Ssam if (!pp) { 12942fa1082Ssam emptyqueue(); 13042fa1082Ssam fputs(bufp, stdout); 13142fa1082Ssam } 13242fa1082Ssam } 13342fa1082Ssam emptyqueue(); 13442fa1082Ssam if (dflag) 135*54094f50Ssam fprintf(stderr, "%s: %s %d, %s %d, %s %d, %s %d\n", 136*54094f50Ssam whoami, 13742fa1082Ssam "attempts", stats.attempted, 13842fa1082Ssam "finished", stats.finished, 13942fa1082Ssam "inhibited", stats.lostmodified, 14042fa1082Ssam "merged", stats.savedpush); 14142fa1082Ssam exit(0); 14242fa1082Ssam } 14342fa1082Ssam 14442fa1082Ssam /* 14542fa1082Ssam * Integrate an expansion into the assembly stream 14642fa1082Ssam */ 14742fa1082Ssam expand(replace) 14842fa1082Ssam char *replace; 14942fa1082Ssam { 15042fa1082Ssam register int curptr; 15142fa1082Ssam char *nextreplace, *argv[MAXARGS]; 15242fa1082Ssam int argc, argreg, foundarg, mod = 0, args = 0; 15342fa1082Ssam char parsebuf[BUFSIZ]; 15442fa1082Ssam 15542fa1082Ssam stats.attempted++; 15642fa1082Ssam for (curptr = bufhead; ; ) { 15742fa1082Ssam nextreplace = copyline(replace, line[bufhead]); 15842fa1082Ssam argc = parseline(line[bufhead], argv, parsebuf); 15942fa1082Ssam argreg = nextarg(argc, argv); 16042fa1082Ssam if (argreg == -1) 16142fa1082Ssam break; 16242fa1082Ssam args++; 16342fa1082Ssam for (foundarg = 0; curptr != buftail; ) { 16442fa1082Ssam curptr = PRED(curptr); 16542fa1082Ssam argc = parseline(line[curptr], argv, parsebuf); 16642fa1082Ssam if (isendofblock(argc, argv)) 16742fa1082Ssam break; 16842fa1082Ssam if (foundarg = ispusharg(argc, argv)) 16942fa1082Ssam break; 17042fa1082Ssam mod |= 1 << modifies(argc, argv); 17142fa1082Ssam } 17242fa1082Ssam if (!foundarg) 17342fa1082Ssam break; 17442fa1082Ssam replace = nextreplace; 17542fa1082Ssam if (mod & (1 << argreg)) { 17642fa1082Ssam stats.lostmodified++; 17742fa1082Ssam if (curptr == buftail) { 17842fa1082Ssam (void)newline(); 17942fa1082Ssam break; 18042fa1082Ssam } 18142fa1082Ssam (void)newline(); 18242fa1082Ssam } else { 18342fa1082Ssam stats.savedpush++; 18442fa1082Ssam rewrite(line[curptr], argc, argv, argreg); 18542fa1082Ssam mod |= 1 << argreg; 18642fa1082Ssam } 18742fa1082Ssam } 18842fa1082Ssam if (argreg == -1) 18942fa1082Ssam stats.finished++; 19042fa1082Ssam emptyqueue(); 19142fa1082Ssam fputs(replace, stdout); 19242fa1082Ssam cleanup(args); 19342fa1082Ssam } 19442fa1082Ssam 19542fa1082Ssam /* 19642fa1082Ssam * Parse a line of assembly language into opcode and arguments. 19742fa1082Ssam */ 19842fa1082Ssam parseline(linep, argv, linebuf) 19942fa1082Ssam char *linep; 20042fa1082Ssam char *argv[]; 20142fa1082Ssam char *linebuf; 20242fa1082Ssam { 20342fa1082Ssam register char *bufp = linebuf, *cp = linep; 20442fa1082Ssam register int argc = 0; 20542fa1082Ssam 20642fa1082Ssam for (;;) { 20742fa1082Ssam /* 20842fa1082Ssam * skip over white space 20942fa1082Ssam */ 21042fa1082Ssam while (isspace(*cp)) 21142fa1082Ssam cp++; 21242fa1082Ssam if (*cp == '\0') 21342fa1082Ssam return (argc); 21442fa1082Ssam /* 21542fa1082Ssam * copy argument 21642fa1082Ssam */ 21742fa1082Ssam if (argc == MAXARGS - 1) { 21842fa1082Ssam fprintf(stderr, "instruction too long->%s", linep); 21942fa1082Ssam return (argc); 22042fa1082Ssam } 22142fa1082Ssam argv[argc++] = bufp; 22242fa1082Ssam while (!isspace(*cp) && *cp != ARGSEPCHAR && *cp != COMMENTCHAR) 22342fa1082Ssam *bufp++ = *cp++; 22442fa1082Ssam *bufp++ = '\0'; 22542fa1082Ssam if (*cp == COMMENTCHAR) 22642fa1082Ssam return (argc); 22742fa1082Ssam if (*cp == ARGSEPCHAR) 22842fa1082Ssam cp++; 22942fa1082Ssam } 23042fa1082Ssam } 23142fa1082Ssam 23242fa1082Ssam /* 23342fa1082Ssam * Check for instructions that end a basic block. 23442fa1082Ssam */ 23542fa1082Ssam isendofblock(argc, argv) 23642fa1082Ssam int argc; 23742fa1082Ssam char *argv[]; 23842fa1082Ssam { 23942fa1082Ssam register struct inststoptbl *itp; 24042fa1082Ssam int size; 24142fa1082Ssam 24242fa1082Ssam if (argc == 0) 24342fa1082Ssam return (0); 24442fa1082Ssam for (itp = inststoptblhdr[hash(argv[0], &size)]; itp; itp = itp->next) 24542fa1082Ssam if (itp->size == size && bcmp(argv[0], itp->name, size) == 0) 24642fa1082Ssam return (1); 24742fa1082Ssam return (0); 24842fa1082Ssam } 24942fa1082Ssam 25042fa1082Ssam /* 25142fa1082Ssam * Copy a newline terminated string. 25242fa1082Ssam * Return pointer to character following last character copied. 25342fa1082Ssam */ 25442fa1082Ssam char * 25542fa1082Ssam copyline(from, to) 25642fa1082Ssam register char *from, *to; 25742fa1082Ssam { 25842fa1082Ssam 25942fa1082Ssam while (*from != '\n') 26042fa1082Ssam *to++ = *from++; 26142fa1082Ssam *to++ = *from++; 26242fa1082Ssam *to = '\0'; 26342fa1082Ssam return (from); 26442fa1082Ssam } 26542fa1082Ssam 26642fa1082Ssam /* 267*54094f50Ssam * Check for a disparity between the number of arguments a function 268*54094f50Ssam * is called with and the number which we expect to see. 269*54094f50Ssam * If the error is unrecoverable, return 1, otherwise 0. 270*54094f50Ssam */ 271*54094f50Ssam argcounterr(args, callargs, name) 272*54094f50Ssam int args, callargs; 273*54094f50Ssam char *name; 274*54094f50Ssam { 275*54094f50Ssam register char *cp; 276*54094f50Ssam char namebuf[MAXLINELEN]; 277*54094f50Ssam 278*54094f50Ssam if (args == callargs) 279*54094f50Ssam return (0); 280*54094f50Ssam cp = strcpy(namebuf, name); 281*54094f50Ssam while (*cp != '\0' && *cp != '\n') 282*54094f50Ssam ++cp; 283*54094f50Ssam if (*cp == '\n') 284*54094f50Ssam *cp = '\0'; 285*54094f50Ssam if (callargs >= 0) { 286*54094f50Ssam fprintf(stderr, 287*54094f50Ssam "%s: error: arg count mismatch, %d != %d for '%s' at line %d\n", 288*54094f50Ssam whoami, callargs, args, namebuf, lineno); 289*54094f50Ssam return (1); 290*54094f50Ssam } 291*54094f50Ssam fprintf(stderr, 292*54094f50Ssam "%s: warning: can't verify arg count for '%s' at line %d\n", 293*54094f50Ssam whoami, namebuf, lineno); 294*54094f50Ssam return (0); 295*54094f50Ssam } 296*54094f50Ssam 297*54094f50Ssam /* 29842fa1082Ssam * open space for next line in the queue 29942fa1082Ssam */ 30042fa1082Ssam char * 30142fa1082Ssam newline() 30242fa1082Ssam { 30342fa1082Ssam bufhead = SUCC(bufhead); 30442fa1082Ssam if (bufhead == buftail) { 30542fa1082Ssam fputs(line[buftail], stdout); 30642fa1082Ssam buftail = SUCC(buftail); 30742fa1082Ssam } 30842fa1082Ssam return (line[bufhead]); 30942fa1082Ssam } 31042fa1082Ssam 31142fa1082Ssam /* 31242fa1082Ssam * empty the queue by printing out all its lines. 31342fa1082Ssam */ 31442fa1082Ssam emptyqueue() 31542fa1082Ssam { 31642fa1082Ssam while (buftail != bufhead) { 31742fa1082Ssam fputs(line[buftail], stdout); 31842fa1082Ssam buftail = SUCC(buftail); 31942fa1082Ssam } 32042fa1082Ssam } 32142fa1082Ssam 32242fa1082Ssam /* 32342fa1082Ssam * Compute the hash of a string. 32442fa1082Ssam * Return the hash and the size of the item hashed 32542fa1082Ssam */ 32642fa1082Ssam hash(cp, size) 32742fa1082Ssam char *cp; 32842fa1082Ssam int *size; 32942fa1082Ssam { 33042fa1082Ssam register char *cp1 = cp; 33142fa1082Ssam register int hash = 0; 33242fa1082Ssam 33342fa1082Ssam while (*cp1 && *cp1 != '\n') 33442fa1082Ssam hash += (int)*cp1++; 33542fa1082Ssam *size = cp1 - cp + 1; 33642fa1082Ssam hash &= HSHSIZ - 1; 33742fa1082Ssam return (hash); 33842fa1082Ssam } 339