home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / program / compiler / sozobon / scsrc20 / top / inst.c < prev    next >
C/C++ Source or Header  |  1991-02-22  |  8KB  |  417 lines

  1. /* Copyright (c) 1988,1991 by Sozobon, Limited.  Author: Tony Andrews
  2.  *
  3.  * Permission is granted to anyone to use this software for any purpose
  4.  * on any computer system, and to redistribute it freely, with the
  5.  * following restrictions:
  6.  * 1) No charge may be made other than reasonable charges for reproduction.
  7.  * 2) Modified versions must be clearly marked as such.
  8.  * 3) The authors are not responsible for any harmful consequences
  9.  *    of using this software, even if they result from defects in it.
  10.  */
  11.  
  12. /*
  13.  * Routines dealing with the parsing and output of instructions.
  14.  */
  15.  
  16. #include "top.h"
  17.  
  18. static    void    getarg();
  19. static    int    isreg();
  20.  
  21. /*
  22.  * addinst(bp, op, args) - add an instruction to block 'bp'
  23.  */
  24. void
  25. addinst(bp, op, args)
  26. register BLOCK    *bp;
  27. char    *op, *args;
  28. {
  29.     register INST    *ni;
  30.     register int    i;
  31.     register char    *s;
  32.     char    *arg2 = "";
  33.  
  34.     if (*op == '\0')    /* no instruction there */
  35.         return;
  36.  
  37.     ni = (INST *) alloc(sizeof(INST));
  38.  
  39.     ni->flags = 0;
  40.     ni->opcode = -1;
  41.     ni->next = NULL;
  42.     ni->prev = NULL;
  43.     ni->live = 0;
  44.     ni->rref = ni->rset = 0;
  45.  
  46.     ni->src.areg = ni->dst.areg = 0;
  47.     ni->src.ireg = ni->dst.ireg = 0;
  48.     ni->src.disp = ni->dst.disp = 0;
  49.     ni->src.amode = ni->dst.amode = NONE;
  50.  
  51.     /*
  52.      * Link into the block appropriately
  53.      */
  54.     if (bp->first == NULL) {
  55.         bp->first = bp->last = ni;
  56.     } else {
  57.         bp->last->next = ni;
  58.         ni->prev = bp->last;
  59.  
  60.         bp->last = ni;
  61.     }
  62.  
  63.     for (s = op; *s ;s++) {
  64.         /*
  65.          * Pseudo-ops start with a period, so the length
  66.          * specifier can't be the first character.
  67.          */
  68.         if (*s == '.' && s != op) {    /* length specifier */
  69.             *s++ = '\0';
  70.             switch (*s) {
  71.             case 'b':
  72.                 ni->flags |= LENB;
  73.                 break;
  74.             case 'w':
  75.                 ni->flags |= LENW;
  76.                 break;
  77.             case 'l':
  78.                 ni->flags |= LENL;
  79.                 break;
  80.             default:
  81.                 fprintf(stderr, "Bad length spec '%c'\n", *s);
  82.                 exit(1);
  83.             }
  84.         }
  85.     }
  86.  
  87.     for (i=0; opnames[i] ;i++) {
  88.         if (strcmp(op, opnames[i]) == 0) {
  89.             ni->opcode = i;
  90.             break;
  91.         }
  92.     }
  93.  
  94.     if (ni->opcode < 0) {
  95.         fprintf(stderr, "Unknown op '%s'\n", op);
  96.         exit(1);
  97.     }
  98.  
  99.     /*
  100.      * Look for the split between the first and second operands.
  101.      */
  102.     for (s = args; *s ;s++) {
  103.         /*
  104.          * skip chars in parens, since an operand split can't
  105.          * occur within.
  106.          */
  107.         if (*s == '(') {
  108.             while (*s != ')')
  109.                 s++;
  110.         }
  111.         if (*s == ',') {
  112.             *s++ = '\0';
  113.             arg2 = s;
  114.             break;
  115.         }
  116.     }
  117.  
  118.     getarg(&ni->src, args);
  119.     getarg(&ni->dst, arg2);
  120. }
  121.  
  122. /*
  123.  * delinst(bp, ip) - delete instruction 'ip' in block 'bp'
  124.  */
  125. void
  126. delinst(bp, ip)
  127. BLOCK    *bp;
  128. register INST    *ip;
  129. {
  130.     register INST    *pi, *ni;    /* previous and next instructions */
  131.  
  132.     pi = ip->prev;
  133.     ni = ip->next;
  134.  
  135.     if (pi != NULL)
  136.         pi->next = ni;
  137.     else
  138.         bp->first = ni;
  139.  
  140.     if (ni != NULL)
  141.         ni->prev = pi;
  142.     else
  143.         bp->last = pi;
  144.  
  145.     /*
  146.      * Free space used by the instruction.
  147.      */
  148.     freeop(&ip->src);
  149.     freeop(&ip->dst);
  150.     free(ip);
  151.  
  152.     s_idel++;
  153. }
  154.  
  155. /*
  156.  * getarg(op, s) - parse string 's' into the operand structure 'op'
  157.  *
  158.  * Hack alert!! The following code parses the operands only to the
  159.  * extent needed by the optimizer. We're primarily interested in
  160.  * details about addressing modes used, not in any expressions that
  161.  * might be present. This code is highly tuned to the output of the
  162.  * compiler.
  163.  */
  164. static    void
  165. getarg(op, s)
  166. register struct    opnd    *op;
  167. register char    *s;
  168. {
  169.     extern    long    atol();
  170.     register int    reg;
  171.     register char    *p;
  172.  
  173.     if (*s == '\0') {
  174.         op->amode = NONE;
  175.         return;
  176.     }
  177.  
  178.     if (*s == '#') {                /* immediate data */
  179.         op->amode = IMM;
  180.         s += 1;
  181.         if (isdigit(s[0]) || s[0] == '-')
  182.             op->disp  = atol(s);
  183.         else {
  184.             op->amode |= SYMB;
  185.             op->astr = strsave(s);
  186.         }
  187.         return;
  188.     } else if ((reg = isreg(s)) >= 0) {        /* reg. direct */
  189.         op->amode = REG;
  190.         op->areg = reg;
  191.     } else if (s[0] == '(' || (s[0] == '-' && s[1] == '(')) {
  192.         op->amode = REGI;
  193.         if (s[0] == '-') {
  194.             op->amode |= DEC;
  195.             s++;
  196.         }
  197.         s++;        /* skip the left paren */
  198.         if ((op->areg = isreg(s)) < 0) {
  199.             fprintf(stderr, "bad reg. '%s'\n", s);
  200.             exit(1);
  201.         }
  202.         s += 3;        /* skip the register and right paren */
  203.  
  204.         if (s[0] == '+')
  205.             op->amode |= INC;
  206.     } else if (!isdigit(s[0]) && (s[0] != '-')) {
  207.         op->amode = ABS;
  208.         op->astr = strsave(s);
  209.     } else {
  210.         for (p=s; isdigit(*p) || *p == '-' ;p++)
  211.             ;
  212.         if (*p != '(') {
  213.             /*
  214.              * Must have been absolute, but with an
  215.              * address instead of a symbol.
  216.              */
  217.             op->amode = ABS;
  218.             op->astr = strsave(s);
  219.             return;
  220.         }
  221.         *p++ = '\0';
  222.         op->disp = atol(s);
  223.         s = p;
  224.         if (s[0] == 'p' && s[1] == 'c') {    /* PC relative */
  225.             if (s[2] == ')') {
  226.                 op->amode = PCD;
  227.                 return;
  228.             }
  229.             op->amode = PCDX;
  230.             op->ireg = isreg(s+3);
  231.             if (s[6] == 'l')
  232.                 op->amode |= XLONG;
  233.         } else if ((reg = isreg(s)) >= 0) {
  234.             op->areg = reg;
  235.             if (s[2] == ')') {
  236.                 op->amode = REGID;
  237.                 return;
  238.             }
  239.             op->amode = REGIDX;
  240.             op->ireg = isreg(s+3);
  241.             if (s[6] == 'l')
  242.                 op->amode |= XLONG;
  243.         } else {
  244.             fprintf(stderr, "bad reg. '%s' after disp\n", s);
  245.             exit(1);
  246.         }
  247.     }
  248. }
  249.  
  250. /*
  251.  * characters that can terminate a register name
  252.  */
  253. #define    isterm(c) ((c) == '\0' || (c) == ')' || (c) == ',' || (c) == '.')
  254.  
  255. static    int
  256. isreg(s)
  257. register char    *s;
  258. {
  259.     if (s[0] == 'd' && isdigit(s[1]) && isterm(s[2]))
  260.         return D0 + (s[1] - '0');
  261.     if (s[0] == 'a' && isdigit(s[1]) && isterm(s[2]))
  262.         return A0 + (s[1] - '0');
  263.     if (s[0] == 's' && s[1] == 'p' && isterm(s[2]))
  264.         return SP;
  265.  
  266.     return -1;
  267. }
  268.  
  269.  
  270. /*
  271.  * Routines for printing out instructions
  272.  */
  273.  
  274. static    char    *rstr();
  275. static    void    putop();
  276.  
  277. void
  278. putinst(ip)
  279. register INST    *ip;
  280. {
  281.     char    c;
  282.  
  283.     fprintf(ofp, "\t%s", opnames[ip->opcode]);
  284.  
  285.     switch (ip->flags) {
  286.     case LENB:
  287.         c = 'b';
  288.         break;
  289.     case LENW:
  290.         c = 'w';
  291.         break;
  292.     case LENL:
  293.         c = 'l';
  294.         break;
  295.     default:
  296.         c = '\0';
  297.         break;
  298.     }
  299.     if (c)
  300.         fprintf(ofp, ".%c", c);
  301.  
  302.     if (ip->src.amode != NONE) {
  303.         fprintf(ofp, "\t");
  304.         putop(&ip->src);
  305.     }
  306.  
  307.     if (ip->dst.amode != NONE) {
  308.         fprintf(ofp, ",");
  309.         putop(&ip->dst);
  310.     }
  311. #ifdef    DEBUG
  312.     if (debug)
  313.         fprintf(ofp, "\t\t* ref(%04x), set(%04x), live(%04x)",
  314.             reg_ref(ip), reg_set(ip), ip->live);
  315. #endif
  316.     fprintf(ofp, "\n");
  317. }
  318.  
  319. static    void
  320. putop(op)
  321. register struct    opnd    *op;
  322. {
  323.     switch (op->amode & MMASK) {
  324.     case NONE:
  325.         break;
  326.     case REG:
  327.         fprintf(ofp, "%s", rstr(op->areg));
  328.         break;
  329.     case IMM:
  330.         if (op->amode & SYMB)
  331.             fprintf(ofp, "#%s", op->astr);
  332.         else
  333.             fprintf(ofp, "#%ld", op->disp);
  334.         break;
  335.     case ABS:
  336.         fprintf(ofp, "%s", op->astr);
  337.         break;
  338.     case REGI:
  339.         if (op->amode & DEC)
  340.             fprintf(ofp, "-");
  341.         fprintf(ofp, "(%s)", rstr(op->areg));
  342.         if (op->amode & INC)
  343.             fprintf(ofp, "+");
  344.         break;
  345.     case REGID:
  346.         fprintf(ofp, "%ld(%s)", op->disp, rstr(op->areg));
  347.         break;
  348.     case REGIDX:
  349.         fprintf(ofp, "%ld(%s,", op->disp, rstr(op->areg));
  350.         fprintf(ofp, "%s.%c)", rstr(op->ireg),
  351.             (op->amode & XLONG) ? 'l' : 'w');
  352.         break;
  353.     case PCD:
  354.         fprintf(ofp, "%ld(pc)", op->disp);
  355.         break;
  356.     case PCDX:
  357.         fprintf(ofp, "%ld(pc,%s.%c)", op->disp, rstr(op->ireg),
  358.             (op->amode & XLONG) ? 'l' : 'w');
  359.         break;
  360.     default:
  361.         fprintf(stderr, "bad addr. mode in putop: %d\n", op->amode);
  362.         exit(1);
  363.     }
  364. }
  365.  
  366. static    char *
  367. rstr(r)
  368. register char    r;
  369. {
  370.     static    char    buf[3];
  371.  
  372.     if (r == SP) {
  373.         buf[0] = 's';
  374.         buf[1] = 'p';
  375.     } else if (r >= A0 && r <= A6) {
  376.         buf[0] = 'a';
  377.         buf[1] = '0' + (r - A0);
  378.     } else {
  379.         buf[0] = 'd';
  380.         buf[1] = '0' + (r - D0);
  381.     }
  382.     buf[2] = '\0';
  383.  
  384.     return buf;
  385. }
  386.  
  387. /*
  388.  * opeq(op1, op2) - test equality of the two instruction operands
  389.  */
  390. bool
  391. opeq(op1, op2)
  392. register struct    opnd    *op1, *op2;
  393. {
  394.     if (op1->amode != op2->amode || op1->areg != op2->areg ||
  395.         op1->ireg  != op2->ireg)
  396.         return FALSE;
  397.  
  398.     /*
  399.      * Depending on the addressing mode, we either need to
  400.      * compare the "astr" strings, or the displacements.
  401.      */
  402.     if ((op1->amode == ABS) || (op1->amode == (IMM|SYMB))) {
  403.         /* compare strings */
  404.         if (op1->astr == NULL)
  405.             return (op2->astr == NULL);
  406.         else {
  407.             if (op2->astr == NULL)
  408.                 return FALSE;
  409.     
  410.             return (strcmp(op1->astr, op2->astr) == 0);
  411.         }
  412.     } else {
  413.         /* compare displacements */
  414.         return (op1->disp == op2->disp);
  415.     }
  416. }
  417.