Logo Search packages:      
Sourcecode: pcc version File versions  Download package

local2.c

/*    $Id: local2.c,v 1.102 2008/11/22 16:12:25 ragge Exp $ */
/*
 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


# include "pass2.h"
# include <ctype.h>

# define putstr(s)      fputs((s), stdout)

void acon(FILE *, NODE *p);
int argsize(NODE *p);
void genargs(NODE *p);

static int offlab;
int offarg;
static int addto;
static int regoff[16];

void
deflab(int label)
{
      printf(LABFMT ":\n", label);
}

void
prologue(struct interpass_prolog *ipp)
{
      int i, j;

      if (ipp->ipp_vis)
            printf("    .globl %s\n", ipp->ipp_name);
      printf("%s:\n", ipp->ipp_name);
      addto = p2maxautooff;
      if (addto >= AUTOINIT/SZCHAR)
            addto -= AUTOINIT/SZCHAR;
      addto /= SZINT/SZCHAR;  /* use words here */
      printf("    push %s,%s\n",rnames[STKREG], rnames[FPREG]);
      printf("    move %s,%s\n", rnames[FPREG],rnames[STKREG]);

      for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
            if (i & 1)
                  regoff[j] = addto++;
      }
      if (addto)
            printf("    addi %s,0%o\n", rnames[STKREG], addto);

      for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
            if (i & 1)
                  printf("    movem %s,%d(%s)\n",
                      rnames[j], regoff[j], rnames[STKREG]);
      }
}

void
eoftn(struct interpass_prolog *ipp)
{
      int i, j;

      if (ipp->ipp_ip.ip_lbl == 0)
            return; /* no code needs to be generated */
      for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
            if (i & 1)
                  printf("    move %s,%d(%s)\n",
                      rnames[j], regoff[j], rnames[STKREG]);
      }
      printf("    move %s,%s\n", rnames[STKREG], rnames[FPREG]);
      printf("    pop %s,%s\n", rnames[STKREG], rnames[FPREG]);
      printf("    popj %s,\n", rnames[STKREG]);
}

#if 0
void
prologue(int regs, int autos)
{
      int i, addto;

      offlab = getlab2();
      if (regs < 0 || autos < 0) {
            /*
             * non-optimized code, jump to epilogue for code generation.
             */
            ftlab1 = getlab2();
            ftlab2 = getlab2();
            printf("    jrst L%d\n", ftlab1);
            printf("L%d:\n", ftlab2);
      } else {
            /*
             * We here know what register to save and how much to 
             * add to the stack.
             */
            autos = autos + (SZINT-1);
            addto = (autos - AUTOINIT)/SZINT + (MAXRVAR-regs);
            if (addto || gflag) {
                  printf("    push %s,%s\n",rnames[017], rnames[016]);
                  printf("    move %s,%s\n", rnames[016],rnames[017]);
                  for (i = regs; i < MAXRVAR; i++) {
                        int db = ((i+1) < MAXRVAR);
                        printf("    %smovem %s,0%o(%s)\n",
                            db ? "d" : "",
                            rnames[i+1], i+1-regs, rnames[016]);
                        if (db)
                              i++;
                  }
                  if (addto)
                        printf("    addi %s,0%o\n", rnames[017], addto);
            } else
                  offarg = 1;
      }
}

/*
 * End of block.
 */
void
eoftn(int regs, int autos, int retlab)
{
      register OFFSZ spoff;   /* offset from stack pointer */
      int i;

      spoff = autos + (SZINT-1);
      if (spoff >= AUTOINIT)
            spoff -= AUTOINIT;
      spoff /= SZINT;
      /* return from function code */
      printf("L%d:\n", retlab);
      if (gflag || isoptim == 0 || autos != AUTOINIT || regs != MAXRVAR) {
            for (i = regs; i < MAXRVAR; i++) {
                  int db = ((i+1) < MAXRVAR);
                  printf("    %smove %s,0%o(%s)\n", db ? "d" : "",
                      rnames[i+1], i+1-regs, rnames[016]);
                  if (db)
                        i++;
            }
            printf("    move %s,%s\n", rnames[017], rnames[016]);
            printf("    pop %s,%s\n", rnames[017], rnames[016]);
      }
      printf("    popj %s,\n", rnames[017]);

      /* Prolog code */
      if (isoptim == 0) {
            printf("L%d:\n", ftlab1);
            printf("    push %s,%s\n", rnames[017], rnames[016]);
            printf("    move %s,%s\n", rnames[016], rnames[017]);
            for (i = regs; i < MAXRVAR; i++) {
                  int db = ((i+1) < MAXRVAR);
                  printf("    %smovem %s,0%o(%s)\n", db ? "d" : "",
                      rnames[i+1], i+1-regs, rnames[016]);
                  spoff++;
                  if (db)
                        i++, spoff++;
            }
            if (spoff)
                  printf("    addi %s,0%llo\n", rnames[017], spoff);
            printf("    jrst L%d\n", ftlab2);
      }
      printf("    .set " LABFMT ",0%o\n", offlab, MAXRVAR-regs);
      offarg = isoptim = 0;
}
#endif

/*
 * add/sub/...
 *
 * Param given:
 *    R - Register
 *    M - Memory
 *    C - Constant
 */
void
hopcode(int f, int o)
{
      cerror("hopcode: f %d %d", f, o);
}

char *
rnames[] = {  /* keyed to register number tokens */
      "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7",
      "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
      "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7",
      "%10", "%11", "%12", "%13", "%14", "%15",
};

int
tlen(p) NODE *p;
{
      switch(p->n_type) {
            case CHAR:
            case UCHAR:
                  return(1);

            case SHORT:
            case USHORT:
                  return(SZSHORT/SZCHAR);

            case DOUBLE:
                  return(SZDOUBLE/SZCHAR);

            case INT:
            case UNSIGNED:
            case LONG:
            case ULONG:
                  return(SZINT/SZCHAR);

            case LONGLONG:
            case ULONGLONG:
                  return SZLONGLONG/SZCHAR;

            default:
                  if (!ISPTR(p->n_type))
                        cerror("tlen type %d not pointer");
                  return SZPOINT(0)/SZCHAR;
            }
}

static char *
binskip[] = {
      "e",  /* jumpe */
      "n",  /* jumpn */
      "le", /* jumple */
      "l",  /* jumpl */
      "ge", /* jumpge */
      "g",  /* jumpg */
};

/*
 * Extract the higher 36 bits from a longlong.
 */
static CONSZ
gethval(CONSZ lval)
{
      CONSZ hval = (lval >> 35) & 03777777777LL;

      if ((hval & 03000000000LL) == 03000000000LL) {
            hval |= 0777000000000LL;
      } else if ((hval & 03000000000LL) == 02000000000LL) {
            hval &= 01777777777LL;
            hval |= 0400000000000LL;
      }
      return hval;
}

/*
 * Do a binary comparision, and jump accordingly.
 */
static void
twocomp(NODE *p)
{
      int o = p->n_op;
      extern int negrel[];
      int isscon = 0, iscon = p->n_right->n_op == ICON;

      if (o < EQ || o > GT)
            cerror("bad binary conditional branch: %s", opst[o]);

      if (iscon && p->n_right->n_name[0] != 0) {
            printf("    cam%s ", binskip[negrel[o-EQ]-EQ]);
            adrput(stdout, getlr(p, 'L'));
            putchar(',');
            printf("[ .long ");
            adrput(stdout, getlr(p, 'R'));
            putchar(']');
            printf("\n  jrst L%d\n", p->n_label);
            return;
      }
      if (iscon)
            isscon = p->n_right->n_lval >= 0 &&
                p->n_right->n_lval < 01000000;

      printf("    ca%c%s ", iscon && isscon ? 'i' : 'm',
          binskip[negrel[o-EQ]-EQ]);
      adrput(stdout, getlr(p, 'L'));
      putchar(',');
      if (iscon && (isscon == 0)) {
            printf("[ .long ");
            adrput(stdout, getlr(p, 'R'));
            putchar(']');
      } else
            adrput(stdout, getlr(p, 'R'));
      printf("\n  jrst L%d\n", p->n_label);
}

/*
 * Compare byte/word pointers.
 * XXX - do not work for highest bit set in address
 */
static void
ptrcomp(NODE *p)
{
      printf("    rot "); adrput(stdout, getlr(p, 'L')); printf(",6\n");
      printf("    rot "); adrput(stdout, getlr(p, 'R')); printf(",6\n");
      twocomp(p);
}

/*
 * Do a binary comparision of two long long, and jump accordingly.
 * XXX - can optimize for constants.
 */
static void     
twollcomp(NODE *p)
{       
      int o = p->n_op;
      int iscon = p->n_right->n_op == ICON;
      int m = 0; /* XXX gcc */

      if (o < EQ || o > GT)
            cerror("bad long long conditional branch: %s", opst[o]);

      /* Special strategy for equal/not equal */
      if (o == EQ || o == NE) {
            if (o == EQ)
                  m = getlab2();
            printf("    came ");
            upput(getlr(p, 'L'), SZLONG);
            putchar(',');
            if (iscon)
                  printf("[ .long ");
            upput(getlr(p, 'R'), SZLONG);
            if (iscon)
                  putchar(']');
            printf("\n  jrst L%d\n", o == EQ ? m : p->n_label);
            printf("    cam%c ", o == EQ ? 'n' : 'e');
            adrput(stdout, getlr(p, 'L'));
            putchar(',');
            if (iscon)
                  printf("[ .long ");
            adrput(stdout, getlr(p, 'R'));
            if (iscon)
                  putchar(']');
            printf("\n  jrst L%d\n", p->n_label);
            if (o == EQ)
                  printf("L%d:\n", m);
            return;
      }
      /* First test highword */
      printf("    cam%ce ", o == GT || o == GE ? 'l' : 'g');
      adrput(stdout, getlr(p, 'L'));
      putchar(',');
      if (iscon)
            printf("[ .long ");
      adrput(stdout, getlr(p, 'R'));
      if (iscon)
            putchar(']');
      printf("\n  jrst L%d\n", p->n_label);

      /* Test equality */
      printf("    came ");
      adrput(stdout, getlr(p, 'L'));
      putchar(',');
      if (iscon)
            printf("[ .long ");
      adrput(stdout, getlr(p, 'R'));
      if (iscon)
            putchar(']');
      printf("\n  jrst L%d\n", m = getlab2());

      /* Test lowword. Only works with pdp10 format for longlongs */
      printf("    cam%c%c ", o == GT || o == GE ? 'l' : 'g',
          o == LT || o == GT ? 'e' : ' ');
      upput(getlr(p, 'L'), SZLONG);
      putchar(',');
      if (iscon)  
            printf("[ .long ");
      upput(getlr(p, 'R'), SZLONG);
      if (iscon)
            putchar(']');
      printf("\n  jrst L%d\n", p->n_label);
      printf("L%d:\n", m);
}

/*
 * Print the correct instruction for constants.
 */
static void
constput(NODE *p)
{
      CONSZ val = p->n_right->n_lval;
      int reg = p->n_left->n_rval;

      /* Only numeric constant */
      if (p->n_right->n_name[0] == '\0') {
            if (val == 0) {
                  printf("movei %s,0", rnames[reg]);
            } else if ((val & 0777777000000LL) == 0) {
                  printf("movei %s,0%llo", rnames[reg], val);
            } else if ((val & 0777777) == 0) {
                  printf("hrlzi %s,0%llo", rnames[reg], val >> 18);
            } else {
                  printf("move %s,[ .long 0%llo]", rnames[reg],
                      szty(p->n_right->n_type) > 1 ? val :
                      val & 0777777777777LL);
            }
            /* Can have more tests here, hrloi etc */
            return;
      } else {
            printf("xmovei %s,%s", rnames[reg], p->n_right->n_name);
            if (val)
                  printf("+" CONFMT, val);
      }
}

/*
 * Return true if the constant can be bundled in an instruction (immediate).
 */
static int
oneinstr(NODE *p)
{
      if (p->n_name[0] != '\0')
            return 0;
      if ((p->n_lval & 0777777000000ULL) != 0)
            return 0;
      return 1;
}

/*
 * Emit a halfword or byte instruction, from OREG to REG.
 * Sign extension must also be done here.
 */
static void
emitshort(NODE *p)
{
      CONSZ off = p->n_lval;
      TWORD type = p->n_type;
      int reg = p->n_rval;
      int issigned = !ISUNSIGNED(type);
      int ischar = type == CHAR || type == UCHAR;
      int reg1 = getlr(p, '1')->n_rval;

      if (off < 0) { /* argument, use move instead */
            printf("    move ");
      } else if (off == 0 && p->n_name[0] == 0) {
            printf("    ldb %s,%s\n", rnames[reg1], rnames[reg]);
            /* XXX must sign extend here even if not necessary */
            switch (type) {
            case CHAR:
                  printf("    lsh %s,033\n", rnames[reg1]);
                  printf("    ash %s,-033\n", rnames[reg1]);
                  break;
            case SHORT:
                  printf("    hrre %s,%s\n",
                      rnames[reg1], rnames[reg1]);
                  break;
            }
            return;
      } else if (ischar) {
            if (off >= 0700000000000LL && p->n_name[0] != '\0') {
                  cerror("emitsh");
                  /* reg contains index integer */
//                if (!istreg(reg))
//                      cerror("emitshort !istreg");
                  printf("    adjbp %s,[ .long 0%llo+%s ]\n",
                      rnames[reg], off, p->n_name);
                  printf("    ldb ");
                  adrput(stdout, getlr(p, '1'));
                  printf(",%s\n", rnames[reg]);
                  goto signe;
            }
            printf("    ldb ");
            adrput(stdout, getlr(p, '1'));
            if (off)
                  printf(",[ .long 0%02o11%02o%06o ]\n",
                      (int)(27-(9*(off&3))), reg, (int)off/4);
            else
                  printf(",%s\n", rnames[reg]);
signe:            if (issigned) {
                  printf("    lsh ");
                  adrput(stdout, getlr(p, '1'));
                  printf(",033\n    ash ");
                  adrput(stdout, getlr(p, '1'));
                  printf(",-033\n");
            }
            return;
      } else {
            printf("    h%cr%c ", off & 1 ? 'r' : 'l',
                issigned ? 'e' : 'z');
      }
      p->n_lval /= (ischar ? 4 : 2);
      adrput(stdout, getlr(p, '1'));
      putchar(',');
      adrput(stdout, getlr(p, 'L'));
      putchar('\n');
}

/*
 * Store a short from a register. Destination is a OREG.
 */
static void
storeshort(NODE *p)
{
      NODE *l = p->n_left;
      CONSZ off = l->n_lval;
      int reg = l->n_rval;
      int ischar = BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR;

      if (l->n_op == NAME) {
            if (ischar) {
                  printf("    dpb ");
                  adrput(stdout, getlr(p, 'R'));
                  printf(",[ .long 0%02o%010o+%s ]\n",
                      070+((int)off&3), (int)(off/4), l->n_name);
                  return;
            }
            printf("    hr%cm ", off & 1 ? 'r' : 'l');
            l->n_lval /= 2;
            adrput(stdout, getlr(p, 'R'));
            putchar(',');   
            adrput(stdout, getlr(p, 'L'));
            putchar('\n');
            return;
      }

      if (off || reg == FPREG) { /* Can emit halfword instructions */
            if (off < 0) { /* argument, use move instead */
                  printf("    movem ");
            } else if (ischar) {
                  printf("    dpb ");
                  adrput(stdout, getlr(p, '1'));
                  printf(",[ .long 0%02o11%02o%06o ]\n",
                      (int)(27-(9*(off&3))), reg, (int)off/4);
                  return;
            } else {
                  printf("    hr%cm ", off & 1 ? 'r' : 'l');
            }
            l->n_lval /= 2;
            adrput(stdout, getlr(p, 'R'));
            putchar(',');
            adrput(stdout, getlr(p, 'L'));
      } else {
            printf("    dpb ");
            adrput(stdout, getlr(p, 'R'));
            putchar(',');
            l = getlr(p, 'L');
            l->n_op = REG;
            adrput(stdout, l);
            l->n_op = OREG;
      }
      putchar('\n');
}

/*
 * Multiply a register with a constant.
 */
static void     
imuli(NODE *p)
{
      NODE *r = p->n_right;

      if (r->n_lval >= 0 && r->n_lval <= 0777777) {
            printf("    imuli ");
            adrput(stdout, getlr(p, 'L'));
            printf(",0%llo\n", r->n_lval);
      } else {
            printf("    imul ");
            adrput(stdout, getlr(p, 'L'));
            printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL);
      }
}

/*
 * Divide a register with a constant.
 */
static void     
idivi(NODE *p)
{
      NODE *r = p->n_right;

      if (r->n_lval >= 0 && r->n_lval <= 0777777) {
            printf("    idivi ");
            adrput(stdout, getlr(p, '1'));
            printf(",0%llo\n", r->n_lval);
      } else {
            printf("    idiv ");
            adrput(stdout, getlr(p, '1'));
            printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL);
      }
}

/*
 * move a constant into a register.
 */
static void
xmovei(NODE *p)
{
      /*
       * Trick: If this is an unnamed constant, just move it directly,
       * otherwise use xmovei to get section number.
       */
      if (p->n_name[0] == '\0' || p->n_lval > 0777777) {
            printf("    ");
            zzzcode(p, 'D');
            putchar(' ');
            adrput(stdout, getlr(p, '1'));
            putchar(',');
            zzzcode(p, 'E');
      } else {
            printf("    xmovei ");
            adrput(stdout, getlr(p, '1'));
            printf(",%s", p->n_name);
            if (p->n_lval != 0)
                  printf("+0%llo", p->n_lval);
      }
      putchar('\n');
}

static void
printcon(NODE *p) 
{
      CONSZ cz;

      p = p->n_left;
      if (p->n_lval >= 0700000000000LL) {
            /* converted to pointer in clocal() */
            conput(0, p);
            return;
      }
      if (p->n_lval == 0 && p->n_name[0] == '\0') {
            putchar('0');
            return;
      }
      if (BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR)
            cz = (p->n_lval/4) | ((p->n_lval & 3) << 30);
      else
            cz = (p->n_lval/2) | (((p->n_lval & 1) + 5) << 30);
      cz |= 0700000000000LL;
      printf("0%llo", cz);
      if (p->n_name[0] != '\0')
            printf("+%s", p->n_name);
}

static void
putcond(NODE *p)
{               
      char *c = 0; /* XXX gcc */

      switch (p->n_op) {
      case EQ: c = "e"; break;
      case NE: c = "n"; break;
      case LE: c = "le"; break;
      case LT: c = "l"; break;
      case GT: c = "g"; break;
      case GE: c = "ge"; break;
      default:
            cerror("putcond");
      }
      printf("%s", c);
}

void
zzzcode(NODE *p, int c)
{
      NODE *l;
      CONSZ hval;

      switch (c) {
      case 'A': /* ildb right arg */
            adrput(stdout, p->n_left->n_left);
            break;

      case 'B': /* remove from stack after subroutine call */
            if (p->n_qual)
                  printf("    subi %%17,0%o\n", p->n_qual);
            break;

      case 'C':
            constput(p);
            break;

      case 'D': /* Find out which type of const load insn to use */
            if (p->n_op != ICON)
                  cerror("zzzcode not ICON");
            if (p->n_name[0] == '\0') {
                  if ((p->n_lval <= 0777777) && (p->n_lval > 0))
                        printf("movei");
                  else if ((p->n_lval & 0777777) == 0)
                        printf("hrlzi");
                  else
                        printf("move");
            } else
                  printf("move");
            break;

      case 'E': /* Print correct constant expression */
            if (p->n_name[0] == '\0') {
                  if ((p->n_lval <= 0777777) && (p->n_lval > 0)){
                        printf("0%llo", p->n_lval);
                  } else if ((p->n_lval & 0777777) == 0) {
                        printf("0%llo", p->n_lval >> 18);
                  } else {
                        if (p->n_lval < 0)
                              printf("[ .long -0%llo]", -p->n_lval);
                        else
                              printf("[ .long 0%llo]", p->n_lval);
                  }
            } else {
                  if (p->n_lval == 0)
                        printf("[ .long %s]", p->n_name);
                  else
                        printf("[ .long %s+0%llo]",
                            p->n_name, p->n_lval);
            }
            break;

      case 'G': /* structure argument */
            printf("    addl %%17,0%o\n", p->n_stsize/(SZINT/SZCHAR));
            printf("    foo...\n");
            break;

      case 'P':
            p = getlr(p, 'R');
            /* FALLTHROUGH */
      case 'O':
            /*
             * Print long long expression.
             */
            hval = gethval(p->n_lval);
            printf("[ .long 0%llo,0%llo", hval,
                (p->n_lval & 0377777777777LL) | (hval & 0400000000000LL));
            if (p->n_name[0] != '\0')
                  printf("+%s", p->n_name);
            printf(" ]");
            break;

      case 'F': /* Print an "opsimp" instruction based on its const type */
            hopcode(oneinstr(p->n_right) ? 'C' : 'R', p->n_op);
            break;

      case 'H': /* Print a small constant */
            p = p->n_right;
            printf("0%llo", p->n_lval & 0777777);
            break;

      case 'Q': /* two-param long long comparisions */
            twollcomp(p);
            break;

      case 'R': /* two-param conditionals */
            twocomp(p);
            break;

      case 'U':
            emitshort(p);
            break;
            
      case 'V':
            storeshort(p);
            break;

      case 'Z':
            ptrcomp(p);
            break;

      case 'a':
            imuli(p);
            break;

      case 'b':
            idivi(p);
            break;

      case 'c':
            xmovei(p);
            break;

      case 'd':
            printcon(p);
            break;

      case 'e':
            putcond(p);
            break;

      case 'g':
            if (p->n_right->n_op != OREG || p->n_right->n_lval != 0)
                  comperr("bad Zg oreg");
            printf("%s", rnames[p->n_right->n_rval]);
            break;

#if 0
      case '1': /* double upput */
            p = getlr(p, '1');
            p->n_rval += 2;
            adrput(stdout, p);
            p->n_rval -= 2;
            break;
#endif

      case 'i': /* Write instruction for short load from name */
            l = getlr(p, 'L');
            printf("    h%cr%c %s,%s+" CONFMT "\n",
                l->n_lval & 1 ? 'r' : 'l',
                ISUNSIGNED(p->n_type) ? 'z' : 'e',
                rnames[getlr(p, '1')->n_rval],
                l->n_name, l->n_lval >> 1);
            break;

      default:
            cerror("zzzcode %c", c);
      }
}

/* set up temporary registers */
void
setregs()
{
      fregs = 7;  /* 7 free regs on PDP10 (1-7) */
}

/*ARGSUSED*/
int
rewfld(NODE *p)
{
      return(1);
}

int
fldexpand(NODE *p, int cookie, char **cp)
{
      return 0;
}

int
flshape(NODE *p)
{
      register int o = p->n_op;

      return (o == REG || o == NAME || o == ICON ||
            (o == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1)));
}

/* INTEMP shapes must not contain any temporary registers */
int
shtemp(NODE *p)
{
      return(0);
}

int
shumul(NODE *p, int order)
{
      register int o;

      if (x2debug) {
            int val;
            printf("shumul(%p)\n", p);
            eprint(p, 0, &val, &val);
      }

      o = p->n_op;
#if 0
      if (o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON)
            return(STARNM);
#endif

#if 0
      if ((o == INCR) &&
          (p->n_left->n_op == REG && p->n_right->n_op == ICON) &&
          p->n_right->n_name[0] == '\0') {
            switch (p->n_type) {
                  case CHAR|PTR:
                  case UCHAR|PTR:
                        o = 1;
                        break;

                  case SHORT|PTR:
                  case USHORT|PTR:
                        o = 2;
                        break;

                  case INT|PTR:
                  case UNSIGNED|PTR:
                  case LONG|PTR:
                  case ULONG|PTR:
                  case FLOAT|PTR:
                        o = 4;
                        break;

                  case DOUBLE|PTR:
                  case LONGLONG|PTR:
                  case ULONGLONG|PTR:
                        o = 8;
                        break;

                  default:
                        if (ISPTR(p->n_type) &&
                             ISPTR(DECREF(p->n_type))) {
                              o = 4;
                              break;
                        } else
                              return(0);
            }
            return( 0);
      }
#endif
      return( SRNOPE );
}

void
adrcon(CONSZ val)
{
      cerror("adrcon: val %llo\n", val);
}

void
conput(FILE *fp, NODE *p)
{
      switch (p->n_op) {
      case ICON:
            if (p->n_lval != 0) {
                  acon(stdout, p);
                  if (p->n_name[0] != '\0')
                        putchar('+');
            }
            if (p->n_name[0] != '\0')
                  printf("%s", p->n_name);
            if (p->n_name[0] == '\0' && p->n_lval == 0)
                  putchar('0');
            return;

      case REG:
            putstr(rnames[p->n_rval]);
            return;

      default:
            cerror("illegal conput");
      }
}

/*ARGSUSED*/
void
insput(NODE *p)
{
      cerror("insput");
}

/*
 * Write out the upper address, like the upper register of a 2-register
 * reference, or the next memory location.
 */
void
upput(NODE *p, int size)
{

      size /= SZLONG;
      switch (p->n_op) {
      case REG:
            putstr(rnames[p->n_rval + size]);
            break;

      case NAME:
      case OREG:
            p->n_lval += size;
            adrput(stdout, p);
            p->n_lval -= size;
            break;
      case ICON:
            printf(CONFMT, p->n_lval >> (36 * size));
            break;
      default:
            cerror("upput bad op %d size %d", p->n_op, size);
      }
}

void
adrput(FILE *fp, NODE *p)
{
      int r;
      /* output an address, with offsets, from p */

      if (p->n_op == FLD)
            p = p->n_left;

      switch (p->n_op) {

      case NAME:
            if (p->n_name[0] != '\0')
                  fputs(p->n_name, fp);
            if (p->n_lval != 0)
                  fprintf(fp, "+" CONFMT, p->n_lval & 0777777777777LL);
            return;

      case OREG:
            r = p->n_rval;
#if 0
            if (R2TEST(r)) { /* double indexing */
                  register int flags;

                  flags = R2UPK3(r);
                  if (flags & 1)
                        putc('*', fp);
                  if (flags & 4)
                        putc('-', fp);
                  if (p->n_lval != 0 || p->n_name[0] != '\0')
                        acon(p);
                  if (R2UPK1(r) != 100)
                        printf("(%s)", rnames[R2UPK1(r)]);
                  if (flags & 2)
                        putchar('+');
                  printf("[%s]", rnames[R2UPK2(r)]);
                  return;
            }
#endif
            if (R2TEST(r))
                  cerror("adrput: unwanted double indexing: r %o", r);
            if (p->n_rval != FPREG && p->n_lval < 0 && p->n_name[0]) {
                  fprintf(fp, "%s", p->n_name);
                  acon(fp, p);
                  fprintf(fp, "(%s)", rnames[p->n_rval]);
                  return;
            }
            if (p->n_lval < 0 && p->n_rval == FPREG && offarg) {
                  p->n_lval -= offarg-2; acon(fp, p); p->n_lval += offarg-2;
            } else if (p->n_lval != 0)
                  acon(fp, p);
            if (p->n_name[0] != '\0')
                  fprintf(fp, "%s%s", p->n_lval ? "+" : "", p->n_name);
            if (p->n_lval > 0 && p->n_rval == FPREG && offlab)
                  fprintf(fp, "+" LABFMT, offlab);
            if (p->n_lval < 0 && p->n_rval == FPREG && offarg)
                  fprintf(fp, "(017)");
            else
                  fprintf(fp, "(%s)", rnames[p->n_rval]);
            return;
      case ICON:
            /* addressable value of the constant */
            if (p->n_lval > 0) {
                  acon(fp, p);
                  if (p->n_name[0] != '\0')
                        putc('+', fp);
            }
            if (p->n_name[0] != '\0')
                  fprintf(fp, "%s", p->n_name);
            if (p->n_lval < 0) 
                  acon(fp, p);
            if (p->n_name[0] == '\0' && p->n_lval == 0)
                  putc('0', fp);
            return;

      case REG:
            fputs(rnames[p->n_rval], fp);
            return;

      default:
            cerror("illegal address, op %d", p->n_op);
            return;

      }
}

/*
 * print out a constant
*/
void
acon(FILE *fp, NODE *p)
{
      if (p->n_lval < 0 && p->n_lval > -0777777777777ULL)
            fprintf(fp, "-" CONFMT, -p->n_lval);
      else
            fprintf(fp, CONFMT, p->n_lval);
}

/*   printf conditional and unconditional branches */
void
cbgen(int o,int lab)
{
}

/*
 * Do some local optimizations that must be done after optim is called.
 */
static void
optim2(NODE *p, void *arg)
{
      int op = p->n_op;
      int m, ml;
      NODE *l;

      /* Remove redundant PCONV's */
      if (op == PCONV) {
            l = p->n_left;
            m = BTYPE(p->n_type);
            ml = BTYPE(l->n_type);
            if ((m == INT || m == LONG || m == LONGLONG || m == FLOAT ||
                m == DOUBLE || m == STRTY || m == UNIONTY ||
                m == UNSIGNED || m == ULONG || m == ULONGLONG) &&
                (ml == INT || ml == LONG || ml == LONGLONG || ml == FLOAT ||
                ml == DOUBLE || ml == STRTY || ml == UNIONTY || 
                ml == UNSIGNED || ml == ULONG ||
                ml == ULONGLONG) && ISPTR(l->n_type)) {
                  *p = *l;
                  nfree(l);
                  op = p->n_op;
            } else
            if (ISPTR(DECREF(p->n_type)) &&
                (l->n_type == INCREF(STRTY))) {
                  *p = *l;
                  nfree(l);
                  op = p->n_op;
            } else
            if (ISPTR(DECREF(l->n_type)) &&
                (p->n_type == INCREF(INT) ||
                p->n_type == INCREF(STRTY) ||
                p->n_type == INCREF(UNSIGNED))) {
                  *p = *l;
                  nfree(l);
                  op = p->n_op;
            }

      }
      /* Add constands, similar to the one in optim() */
      if (op == PLUS && p->n_right->n_op == ICON) {
            l = p->n_left;
            if (l->n_op == PLUS && l->n_right->n_op == ICON &&
                (p->n_right->n_name[0] == '\0' ||
                 l->n_right->n_name[0] == '\0')) {
                  l->n_right->n_lval += p->n_right->n_lval;
                  if (l->n_right->n_name[0] == '\0')
                        l->n_right->n_name = p->n_right->n_name;
                  nfree(p->n_right);
                  *p = *l;
                  nfree(l);
            }
      }

      /* Convert "PTR undef" (void *) to "PTR uchar" */
      /* XXX - should be done in MI code */
      if (BTYPE(p->n_type) == VOID)
            p->n_type = (p->n_type & ~BTMASK) | UCHAR;
      if (op == ICON) {
            if ((p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR))
                && p->n_lval == 0 && p->n_name[0] != '\0')
                  p->n_lval = 0700000000000LL;
            if ((p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT))
                && p->n_lval == 0 && p->n_name[0] != '\0')
                  p->n_lval = 0750000000000LL;
      }
      if (op == MINUS) {
            if ((p->n_left->n_type == (PTR|CHAR) ||
                p->n_left->n_type == (PTR|UCHAR)) &&
                (p->n_right->n_type == (PTR|CHAR) ||
                p->n_right->n_type == (PTR|UCHAR))) {
                  l = talloc();
                  l->n_op = SCONV;
                  l->n_type = INT;
                  l->n_left = p->n_right;
                  p->n_right = l;
                  l = talloc();
                  l->n_op = SCONV;
                  l->n_type = INT;
                  l->n_left = p->n_left;
                  p->n_left = l;
            }
      }
}

void
myreader(struct interpass *ipole)
{
      struct interpass *ip;

      DLIST_FOREACH(ip, ipole, qelem) {
            if (ip->type != IP_NODE)
                  continue;
            walkf(ip->ip_node, optim2, 0);
      }

      if (x2debug) {
            printf("myreader final tree:\n");
            printip(ipole);
      }
}

/*
 * Remove some PCONVs after OREGs are created.
 */
static void
pconv2(NODE *p, void *arg)
{
      NODE *q;

      if (p->n_op == PLUS) {
            if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
                  if (p->n_right->n_op != ICON)
                        return;
                  if (p->n_left->n_op != PCONV)
                        return;
                  if (p->n_left->n_left->n_op != OREG)
                        return;
                  q = p->n_left->n_left;
                  nfree(p->n_left);
                  p->n_left = q;
                  /*
                   * This will be converted to another OREG later.
                   */
            }
      }
}

void
mycanon(NODE *p)
{
      walkf(p, pconv2, 0);
}

/*
 * Remove last goto.
 */
void
myoptim(struct interpass *ip)
{
}

/*
 * Return a class suitable for a specific type.
 */
int
gclass(TWORD t)
{
      return (szty(t) == 2 ? CLASSB : CLASSA);
}

static int
argsiz(NODE *p)
{
      TWORD t = p->n_type;

      if (t == STRTY || t == UNIONTY)
            return p->n_stsize/(SZINT/SZCHAR);
      return szty(t);
}

/*
 * Calculate argument sizes.
 */
void
lastcall(NODE *p)
{
        NODE *op = p;
        int size = 0;

        p->n_qual = 0;
        if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
                return;
        for (p = p->n_right; p->n_op == CM; p = p->n_left)
            if (p->n_right->n_op != ASSIGN)
                  size += argsiz(p->n_right);
      if (p->n_op != ASSIGN)
            size += argsiz(p);
        op->n_qual = size; /* XXX */
}

void
rmove(int s, int d, TWORD t)
{
      printf("    %smove %s,%s\n",
          (s > 017 ? "d" : ""), rnames[d], rnames[s]);
}

/*
 * For class c, find worst-case displacement of the number of
 * registers in the array r[] indexed by class.
 */
int
COLORMAP(int c, int *r)
{
      int num;

      switch (c) {
      case CLASSA:
            /* there are 13 classa, so min 6 classb are needed to block */
            num = r[CLASSB] * 2;
            num += r[CLASSA];
            return num < 13;
      case CLASSB:
            /* 7 classa may block all classb */
            num = r[CLASSB] + r[CLASSA];
            return num < 7;
      }
      comperr("COLORMAP");
      return 0; /* XXX gcc */
}

/*
 * Target-dependent command-line options.
 */
void
mflags(char *str)
{
}
/*
 * Do something target-dependent for xasm arguments.
 * Supposed to find target-specific constraints and rewrite them.
 */
int
myxasm(struct interpass *ip, NODE *p)
{
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index