home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1988 by Sozobon, Limited. Author: Tony Andrews
- *
- * Permission is granted to anyone to use this software for any purpose
- * on any computer system, and to redistribute it freely, with the
- * following restrictions:
- * 1) No charge may be made other than reasonable charges for reproduction.
- * 2) Modified versions must be clearly marked as such.
- * 3) The authors are not responsible for any harmful consequences
- * of using this software, even if they result from defects in it.
- */
-
- /*
- * Routines dealing with the parsing and output of instructions.
- */
-
- #include "top.h"
-
- static void getarg();
- static int isreg();
-
- /*
- * addinst(bp, op, args) - add an instruction to block 'bp'
- */
- void
- addinst(bp, op, args)
- register BLOCK *bp;
- char *op, *args;
- {
- register INST *ni;
- register int i;
- register char *s;
- char *arg2 = "";
-
- if (*op == '\0') /* no instruction there */
- return;
-
- ni = (INST *) alloc(sizeof(INST));
-
- ni->flags = 0;
- ni->opcode = -1;
- ni->next = NULL;
- ni->prev = NULL;
- ni->live = 0;
- ni->rref = ni->rset = 0;
-
- ni->src.areg = ni->dst.areg = 0;
- ni->src.ireg = ni->dst.ireg = 0;
- ni->src.disp = ni->dst.disp = 0;
- ni->src.amode = ni->dst.amode = NONE;
-
- /*
- * Link into the block appropriately
- */
- if (bp->first == NULL) {
- bp->first = bp->last = ni;
- } else {
- bp->last->next = ni;
- ni->prev = bp->last;
-
- bp->last = ni;
- }
-
- for (s = op; *s ;s++) {
- /*
- * Pseudo-ops start with a period, so the length
- * specifier can't be the first character.
- */
- if (*s == '.' && s != op) { /* length specifier */
- *s++ = '\0';
- switch (*s) {
- case 'b':
- ni->flags |= LENB;
- break;
- case 'w':
- ni->flags |= LENW;
- break;
- case 'l':
- ni->flags |= LENL;
- break;
- default:
- fprintf(stderr, "Bad length spec '%c'\n", *s);
- exit(1);
- }
- }
- }
-
- for (i=0; opnames[i] ;i++) {
- if (strcmp(op, opnames[i]) == 0) {
- ni->opcode = i;
- break;
- }
- }
-
- if (ni->opcode < 0) {
- fprintf(stderr, "Unknown op '%s'\n", op);
- exit(1);
- }
-
- /*
- * Look for the split between the first and second operands.
- */
- for (s = args; *s ;s++) {
- /*
- * skip chars in parens, since an operand split can't
- * occur within.
- */
- if (*s == '(') {
- while (*s != ')')
- s++;
- }
- if (*s == ',') {
- *s++ = '\0';
- arg2 = s;
- break;
- }
- }
-
- getarg(&ni->src, args);
- getarg(&ni->dst, arg2);
- }
-
- /*
- * delinst(bp, ip) - delete instruction 'ip' in block 'bp'
- */
- void
- delinst(bp, ip)
- BLOCK *bp;
- register INST *ip;
- {
- register INST *pi, *ni; /* previous and next instructions */
-
- pi = ip->prev;
- ni = ip->next;
-
- if (pi != NULL)
- pi->next = ni;
- else
- bp->first = ni;
-
- if (ni != NULL)
- ni->prev = pi;
- else
- bp->last = pi;
-
- /*
- * Free space used by the instruction.
- */
- freeop(&ip->src);
- freeop(&ip->dst);
- free(ip);
-
- s_idel++;
- }
-
- /*
- * getarg(op, s) - parse string 's' into the operand structure 'op'
- *
- * Hack alert!! The following code parses the operands only to the
- * extent needed by the optimizer. We're primarily interested in
- * details about addressing modes used, not in any expressions that
- * might be present. This code is highly tuned to the output of the
- * compiler.
- */
- static void
- getarg(op, s)
- register struct opnd *op;
- register char *s;
- {
- extern long atol();
- register int reg;
- register char *p;
-
- if (*s == '\0') {
- op->amode = NONE;
- return;
- }
-
- if (*s == '#') { /* immediate data */
- op->amode = IMM;
- s += 1;
- if (isdigit(s[0]) || s[0] == '-')
- op->disp = atol(s);
- else {
- op->amode |= SYMB;
- op->astr = strsave(s);
- }
- return;
- } else if ((reg = isreg(s)) >= 0) { /* reg. direct */
- op->amode = REG;
- op->areg = reg;
- } else if (s[0] == '(' || (s[0] == '-' && s[1] == '(')) {
- op->amode = REGI;
- if (s[0] == '-') {
- op->amode |= DEC;
- s++;
- }
- s++; /* skip the left paren */
- if ((op->areg = isreg(s)) < 0) {
- fprintf(stderr, "bad reg. '%s'\n", s);
- exit(1);
- }
- s += 3; /* skip the register and right paren */
-
- if (s[0] == '+')
- op->amode |= INC;
- } else if (!isdigit(s[0]) && (s[0] != '-')) {
- op->amode = ABS;
- op->astr = strsave(s);
- } else {
- for (p=s; isdigit(*p) || *p == '-' ;p++)
- ;
- if (*p != '(') {
- /*
- * Must have been absolute, but with an
- * address instead of a symbol.
- */
- op->amode = ABS;
- op->astr = strsave(s);
- return;
- }
- *p++ = '\0';
- op->disp = atol(s);
- s = p;
- if (s[0] == 'p' && s[1] == 'c') { /* PC relative */
- if (s[2] == ')') {
- op->amode = PCD;
- return;
- }
- op->amode = PCDX;
- op->ireg = isreg(s+3);
- if (s[6] == 'l')
- op->amode |= XLONG;
- } else if ((reg = isreg(s)) >= 0) {
- op->areg = reg;
- if (s[2] == ')') {
- op->amode = REGID;
- return;
- }
- op->amode = REGIDX;
- op->ireg = isreg(s+3);
- if (s[6] == 'l')
- op->amode |= XLONG;
- } else {
- fprintf(stderr, "bad reg. '%s' after disp\n", s);
- exit(1);
- }
- }
- }
-
- /*
- * characters that can terminate a register name
- */
- #define isterm(c) ((c) == '\0' || (c) == ')' || (c) == ',' || (c) == '.')
-
- static int
- isreg(s)
- register char *s;
- {
- if (s[0] == 'd' && isdigit(s[1]) && isterm(s[2]))
- return D0 + (s[1] - '0');
- if (s[0] == 'a' && isdigit(s[1]) && isterm(s[2]))
- return A0 + (s[1] - '0');
- if (s[0] == 's' && s[1] == 'p' && isterm(s[2]))
- return SP;
-
- return -1;
- }
-
-
- /*
- * Routines for printing out instructions
- */
-
- static char *rstr();
- static void putop();
-
- void
- putinst(ip)
- register INST *ip;
- {
- char c;
-
- fprintf(ofp, "\t%s", opnames[ip->opcode]);
-
- switch (ip->flags) {
- case LENB:
- c = 'b';
- break;
- case LENW:
- c = 'w';
- break;
- case LENL:
- c = 'l';
- break;
- default:
- c = '\0';
- break;
- }
- if (c)
- fprintf(ofp, ".%c", c);
-
- if (ip->src.amode != NONE) {
- fprintf(ofp, "\t");
- putop(&ip->src);
- }
-
- if (ip->dst.amode != NONE) {
- fprintf(ofp, ",");
- putop(&ip->dst);
- }
- #ifdef DEBUG
- if (debug)
- fprintf(ofp, "\t\t* ref(%04x), set(%04x), live(%04x)",
- reg_ref(ip), reg_set(ip), ip->live);
- #endif
- fprintf(ofp, "\n");
- }
-
- static void
- putop(op)
- register struct opnd *op;
- {
- switch (op->amode & MMASK) {
- case NONE:
- break;
- case REG:
- fprintf(ofp, "%s", rstr(op->areg));
- break;
- case IMM:
- if (op->amode & SYMB)
- fprintf(ofp, "#%s", op->astr);
- else
- fprintf(ofp, "#%ld", op->disp);
- break;
- case ABS:
- fprintf(ofp, "%s", op->astr);
- break;
- case REGI:
- if (op->amode & DEC)
- fprintf(ofp, "-");
- fprintf(ofp, "(%s)", rstr(op->areg));
- if (op->amode & INC)
- fprintf(ofp, "+");
- break;
- case REGID:
- fprintf(ofp, "%ld(%s)", op->disp, rstr(op->areg));
- break;
- case REGIDX:
- fprintf(ofp, "%ld(%s,", op->disp, rstr(op->areg));
- fprintf(ofp, "%s.%c)", rstr(op->ireg),
- (op->amode & XLONG) ? 'l' : 'w');
- break;
- case PCD:
- fprintf(ofp, "%ld(pc)", op->disp);
- break;
- case PCDX:
- fprintf(ofp, "%ld(pc,%s.%c)", op->disp, rstr(op->ireg),
- (op->amode & XLONG) ? 'l' : 'w');
- break;
- default:
- fprintf(stderr, "bad addr. mode in putop: %d\n", op->amode);
- exit(1);
- }
- }
-
- static char *
- rstr(r)
- register char r;
- {
- static char buf[3];
-
- if (r == SP) {
- buf[0] = 's';
- buf[1] = 'p';
- } else if (r >= A0 && r <= A6) {
- buf[0] = 'a';
- buf[1] = '0' + (r - A0);
- } else {
- buf[0] = 'd';
- buf[1] = '0' + (r - D0);
- }
- buf[2] = '\0';
-
- return buf;
- }
-
- /*
- * opeq(op1, op2) - test equality of the two instruction operands
- */
- bool
- opeq(op1, op2)
- register struct opnd *op1, *op2;
- {
- if (op1->amode != op2->amode || op1->areg != op2->areg ||
- op1->ireg != op2->ireg)
- return FALSE;
-
- /*
- * Depending on the addressing mode, we either need to
- * compare the "astr" strings, or the displacements.
- */
- if ((op1->amode == ABS) || (op1->amode == (IMM|SYMB))) {
- /* compare strings */
- if (op1->astr == NULL)
- return (op2->astr == NULL);
- else {
- if (op2->astr == NULL)
- return FALSE;
-
- return (strcmp(op1->astr, op2->astr) == 0);
- }
- } else {
- /* compare displacements */
- return (op1->disp == op2->disp);
- }
- }
-