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

local2.c

/*    $OpenBSD$   */

/*
 * Copyright (c) 2007 Michael Shalayeff
 * 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>
# include <string.h>

void acon(NODE *p);
void prtprolog(struct interpass_prolog *, int);
int countargs(NODE *p, int *);
void fixcalls(NODE *p, void *);

static int stkpos;
int p2calls;

static const int rl[] =
  { R0, R1, R1, R1, R1, R1, R31, R31, R31, R31,
    R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18,
    T1, T4, T3, T2, ARG3, ARG1, RET1 };
static const int rh[] =
  { R0, R31, T4, T3, T2, T1, T4, T3, T2, T1,
    R18, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17,
    T4, T3, T2, T1, ARG2, ARG0, RET0 };

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

static int regoff[MAXREGS];
static TWORD ftype;

/*
 * Print out the prolog assembler.
 * addto and regoff are already calculated.
 */
void
prtprolog(struct interpass_prolog *ipp, int addto)
{
      int i;

      /* if this functions calls nothing -- no frame is needed */
      if (p2calls || p2maxautooff > 4) {
            printf("\tcopy\t%%r3,%%r1\n\tcopy\t%%sp,%%r3\n");
            if (addto < 0x2000)
                  printf("\tstw,ma\t%%r1,%d(%%sp)\n", addto);
            else if (addto < 0x802000)
                  printf("\tstw,ma\t%%r1,8192(%%sp)\n"
                      "\taddil\t%d-8192,%%sp\n"
                      "\tcopy\t%%r1,%%sp\n", addto);
            else
                  comperr("too much local allocation");
            if (p2calls)
                  printf("\tstw\t%%rp,-20(%%r3)\n");
      }

      for (i = 0; i < MAXREGS; i++)
            if (TESTBIT(ipp->ipp_regs, i)) {
                  if (i <= R31)
                        printf("\tstw\t%s,%d(%%r3)\n",
                            rnames[i], regoff[i]);
                  else if (i <= RETD0)
                        printf("\tstw\t%s,%d(%%r3)\n"
                            "\tstw\t%s,%d(%%r3)\n",
                            rnames[rl[i - RD0]], regoff[i] + 0,
                            rnames[rh[i - RD0]], regoff[i] + 4);
                  else if (i <= FR31)
                        printf("\tfstws\t%s,%d(%%r3)\n",
                            rnames[i], regoff[i]);
                  else
                        printf("\tfstds\t%s,%d(%%r3)\n",
                            rnames[i], regoff[i]);
            }
}

/*
 * calculate stack size and offsets
 */
static int
offcalc(struct interpass_prolog *ipp)
{
      int i, addto, off;

      addto = 32;
      if (p2calls) {
            i = p2calls - 1;
            /* round up to 4 args */
            if (i < 4)
                  i = 4;
            addto += i * 4;
      }

      for (off = 4, i = 0; i < MAXREGS; i++)
            if (TESTBIT(ipp->ipp_regs, i)) {
                  regoff[i] = off;
                  off += szty(PERMTYPE(i)) * SZINT/SZCHAR;
            }
      addto += off + p2maxautooff;
      return (addto + 63) & ~63;
}

void
prologue(struct interpass_prolog *ipp)
{
      int addto;

      ftype = ipp->ipp_type;

      /*
       * We here know what registers to save and how much to 
       * add to the stack.
       */
      addto = offcalc(ipp);
      printf("\t.proc\ncallinfo frame=%d, save_rp, save_sp\n\t.entry\n",
          addto);
      prtprolog(ipp, addto);
}

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

      if (ipp->ipp_ip.ip_lbl == 0)
            return; /* no code needs to be generated */

      /* return from function code */
      for (i = 0; i < MAXREGS; i++)
            if (TESTBIT(ipp->ipp_regs, i)) {
                  if (i <= R31)
                        printf("\tldw\t%d(%%r3),%s\n",
                            regoff[i], rnames[i]);
                  else if (i <= RETD0)
                        printf("\tldw\t%d(%%r3),%s\n"
                            "\tldw\t%d(%%r3),%s\n",
                            regoff[i] + 0, rnames[rl[i - RD0]],
                            regoff[i] + 4, rnames[rh[i - RD0]]);
                  else if (i <= FR31)
                        printf("\tfldws\t%d(%%r3),%s\n",
                            regoff[i], rnames[i]);
                  else
                        printf("\tfldds\t%d(%%r3),%s\n",
                            regoff[i], rnames[i]);
            }

      if (p2calls || p2maxautooff > 4) {
            if (p2calls)
                  printf("\tldw\t-20(%%r3),%%rp\n");
            printf("\tcopy\t%%r3,%%r1\n"
                "\tldw\t0(%%r3),%%r3\n"
                "\tbv\t%%r0(%%rp)\n"
                "\tcopy\t%%r1,%%sp\n");
      } else
            printf("\tbv\t%%r0(%%rp)\n\tnop\n");

      printf("\t.exit\n\t.procend\n\t.size\t%s, .-%s\n",
          ipp->ipp_name, ipp->ipp_name);
}

/*
 * add/sub/...
 *
 * Param given:
 */
void
hopcode(int f, int o)
{
      char *str;

      switch (o) {
      case PLUS:
            str = "add";
            break;
      case MINUS:
            str = "sub";
            break;
      case AND:
            str = "and";
            break;
      case OR:
            str = "or";
            break;
      case ER:
            str = "xor";
            break;
      case EQ:
            str = "=";
            break;
      case NE:
            str = "<>";
            break;
      case LE:
            str = "<";
            break;
      case LT:
            str = "<=";
            break;
      case ULE:
            str = "<<";
            break;
      case ULT:
            str = "<<=";
            break;
      case GE:
            str = ">=";
            break;
      case GT:
            str = ">";
            break;
      case UGE:
            str = ">>";
            break;
      case UGT:
            str = ">>=";
            break;
      default:
            comperr("hopcode2: %d", o);
            str = 0; /* XXX gcc */
      }
      printf("%s%c", str, f);
}

/*
 * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
 */
int
tlen(p) NODE *p;
{
      switch(p->n_type) {
            case CHAR:
            case UCHAR:
                  return(1);

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

            case FLOAT:
                  return(SZFLOAT/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))
                        comperr("tlen type %d not pointer", p->n_type);
                  return SZPOINT(p->n_type)/SZCHAR;
            }
}

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

      if (t < LONGLONG || t == FLOAT || t > BTMASK)
            return 4;
      if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
            return 8;
      if (t == LDOUBLE)
            return 8;   /* LDOUBLE is 16 */
      if ((t == STRTY || t == UNIONTY) && p->n_right->n_op == STARG)
            return 4 + p->n_right->n_stsize;
        /* perhaps it's down there somewhere -- let me take another look! */
      if ((t == STRTY || t == UNIONTY) && p->n_right->n_op == CALL) {
            q = p->n_right->n_right->n_left->n_left->n_right;
            if (q->n_op == STARG)
                  return 4 + q->n_stsize;
      }
      comperr("argsiz %p", p);
      return 0;
}

/*
 * Emit code to compare two longlong numbers.
 */
static void
twollcomp(NODE *p)
{
      int o = p->n_op;
      int s = getlab2();
      int e = p->n_label;
      int cb1, cb2;

      if (o >= ULE)
            o -= (ULE-LE);
      switch (o) {
      case NE:
            cb1 = 0;
            cb2 = NE;
            break;
      case EQ:
            cb1 = NE;
            cb2 = 0;
            break;
      case LE:
      case LT:
            cb1 = GT;
            cb2 = LT;
            break;
      case GE:
      case GT:
            cb1 = LT;
            cb2 = GT;
            break;
      
      default:
            cb1 = cb2 = 0; /* XXX gcc */
      }
      if (p->n_op >= ULE)
            cb1 += 4, cb2 += 4;
      if (cb1) {
            p->n_op = cb1;
            p->n_label = s;
            expand(p, 0, "\tcomb,O\tUR,UL,LC\n\tnop\n");
            p->n_label = e;
            p->n_op = o;
      }
      if (cb2) {
            p->n_op = cb2;
            expand(p, 0, "\tcomb,O\tUR,UL,LC\n\tnop\n");
            p->n_op = o;
      }
      expand(p, 0, "\tcomb,O\tAR,AL,LC\n\tnop\n");
      deflab(s);
}

void
zzzcode(NODE *p, int c)
{
      int n;

      switch (c) {

      case 'C':   /* after-call fixup */
            n = p->n_qual;    /* args */
            break;

      case 'P':   /* returning struct-call setup */
            n = p->n_qual;    /* args */
            break;

      case 'D':   /* Long long comparision */
            twollcomp(p);
            break;

      case 'F':   /* struct as an arg */

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

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

      if (o == NAME || o == REG || o == ICON || o == OREG ||
          (o == UMUL && shumul(p->n_left, SOREG)))
            return(1);
      return(0);
}

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

/*
 * Does the bitfield shape match?
 */
int
flshape(NODE *p)
{
      if (isreg(p))
            return SRDIR; /* Direct match */

      return SRREG; /* put it into a register */
}

/* INTEMP shapes must not contain any temporary registers */
/* XXX should this go away now? */
int
shtemp(NODE *p)
{
      return 0;
#if 0
      int r;

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

      switch (p->n_op) {
      case REG:
            return (!istreg(p->n_rval));

      case OREG:
            r = p->n_rval;
            if (R2TEST(r)) {
                  if (istreg(R2UPK1(r)))
                        return(0);
                  r = R2UPK2(r);
            }
            return (!istreg(r));

      case UMUL:
            p = p->n_left;
            return (p->n_op != UMUL && shtemp(p));
      }

      if (optype(p->n_op) != LTYPE)
            return(0);
      return(1);
#endif
}

void
adrcon(CONSZ val)
{
      /* fix for L% and R% */
      printf(CONFMT, val);
}

void
conput(FILE *fp, NODE *p)
{
      CONSZ val = p->n_lval;

      switch (p->n_op) {
      case ICON:
            if (p->n_name[0] != '\0') {
                  fprintf(fp, "RR'%s-$global$", p->n_name);
                  if (val)
                        fprintf(fp, "+" CONFMT, val);
            } else
                  fprintf(fp, CONFMT, val);
            return;

      default:
            comperr("illegal conput, p %p", p);
      }
}

/*ARGSUSED*/
void
insput(NODE *p)
{
      comperr("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 /= SZCHAR;
      switch (p->n_op) {
      case REG:
            printf("%s", rnames[rh[p->n_rval - RD0]]);
            break;

      case OREG:
            p->n_lval += size;
            adrput(stdout, p);
            p->n_lval -= size;
            break;

      case ICON:
      case NAME:
            if (p->n_name[0] != '\0') {
                  printf("LR'%s-$global$", p->n_name);
                  if (p->n_lval != 0)
                        printf("+" CONFMT, p->n_lval);
            } else
                  printf("L%%" CONFMT, p->n_lval >> 32);
            break;
      default:
            comperr("upput bad op %d size %d", p->n_op, size);
      }
}

void
adrput(FILE *io, 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 ICON:
      case NAME:
            if (p->n_name[0] != '\0') {
                  fprintf(io, "RR'%s-$global$", p->n_name);
                  if (p->n_lval != 0)
                        fprintf(io, "+" CONFMT, p->n_lval);
            } else
                  fprintf(io, "R%%" CONFMT, p->n_lval);
            return;

      case OREG:
            r = p->n_rval;
            if (p->n_name[0] != '\0') {
                  fprintf(io, "RR'%s-$global$", p->n_name);
                  if (p->n_lval != 0)
                        fprintf(io, "+" CONFMT, p->n_lval);
            } else
                  fprintf(io, "%d", (int)p->n_lval);
            if (R2TEST(r)) {
                  fprintf(io, "%s(%s)", rnames[R2UPK1(r)],
                      rnames[R2UPK2(r)]);
            } else
                  fprintf(io, "(%s)", rnames[p->n_rval]);
            return;
      case REG:
            if (RD0 <= p->n_rval && p->n_rval <= RETD0)
                  fprintf(io, "%s", rnames[rl[p->n_rval - RD0]]);
            else
                  fprintf(io, "%s", rnames[p->n_rval]);
            return;

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

      }
}

/* not used */
void
cbgen(int o, int lab)
{
}

int
countargs(NODE *p, int *n)
{
      int sz;
      
      if (p->n_op == CM) {
            countargs(p->n_left, n);
            countargs(p->n_right, n);
            return *n;
      }

      sz = argsiz(p) / 4;
      if (*n % (sz > 4? 4 : sz))
            (*n)++; /* XXX */

      return *n += sz;
}

void
fixcalls(NODE *p, void *arg)
{
      int n, o;

      /* Prepare for struct return by allocating bounce space on stack */
      switch (o = p->n_op) {
      case STCALL:
      case USTCALL:
            if (p->n_stsize + p2autooff > stkpos)
                  stkpos = p->n_stsize + p2autooff;
            /* FALLTHROGH */
      case CALL:
      case UCALL:
            n = 0;
            n = 1 + countargs(p->n_right, &n);
            if (n > p2calls)
                  p2calls = n;
            break;
      }
}

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

      stkpos = p2autooff;
      DLIST_FOREACH(ip, ipole, qelem) {
            switch (ip->type) {
            case IP_PROLOG:
                  p2calls = 0;
                  break;

            case IP_NODE:
                  walkf(ip->ip_node, fixcalls, 0);
                  break;
            }
      }
      if (stkpos > p2autooff)
            p2autooff = stkpos;
      if (stkpos > p2maxautooff)
            p2maxautooff = stkpos;
      if (x2debug)
            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);
}

void
myoptim(struct interpass *ipole)
{
}

void
rmove(int s, int d, TWORD t)
{
      int sl, sh, dl, dh;

      switch (t) {
      case LONGLONG:
      case ULONGLONG:
            sl = rl[s-RD0];
            sh = rh[s-RD0];
            dl = rl[d-RD0];
            dh = rh[d-RD0];

#define     SW(x,y) { int i = x; x = y; y = i; }
            if (sl == dh || sh == dl) {
                  /* Swap if moving to itself */
                  SW(sl, sh);
                  SW(dl, dh);
            }
            if (sl != dl)
                  printf("\tcopy\t%s,%s\n", rnames[sl], rnames[dl]);
            if (sh != dh)
                  printf("\tcopy\t%s,%s\n", rnames[sh], rnames[dh]);
            break;
      case FLOAT:
            printf("\tfcpy,sgl\t%s,%s\n", rnames[s], rnames[d]);
            break;
      case DOUBLE:
      case LDOUBLE:
            printf("\tfcpy,dbl\t%s,%s\n", rnames[s], rnames[d]);
            break;
      default:
            printf("\tcopy\t%s,%s\n", rnames[s], rnames[d]);
      }
}

/*
 * 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:
            num = 2 * r[CLASSB];
            num += r[CLASSA];
            return num < 28;
      case CLASSB:
            num = r[CLASSA];
            num += r[CLASSB] * 2;
            return num < 28;
      case CLASSC:
            num = (r[CLASSD] > 8? 8 : r[CLASSD]) * 2;
            num += r[CLASSC];
            return num < 28;
      case CLASSD:
            num = (r[CLASSC] + 1) / 2;
            num += r[CLASSD];
            return num < 28;
      }
      return 0; /* XXX gcc */
}

char * rnames[MAXREGS] = {
      "%r0", "%r1", "%rp", "%r3", "%r4", "%r5", "%r6", "%r7", "%r8", "%r9",
      "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "%r16", "%r17", "%r18",
      "%t4", "%t3", "%t2", "%t1", "%arg3", "%arg2", "%arg1", "%arg0", "%dp",
      "%ret0", "%ret1", "%sp", "%r31",
      "%rd0", "%rd1", "%rd2", "%rd3", "%rd4", "%rd5", "%rd6", "%rd7",
      "%rd8", "%rd9", "%rd10", "%rd11", "%rd12", "%rd13", "%rd14", "%rd15",
      "%rd16", "%rd17", "%rd18", "%rd19", "%rd20", "%rd21", "%rd22", "%rd23",
      "%rd24", "%td4", "%td3", "%td2", "%td1", "%ad1", "%ad0", "%retd0",
      "%fr0", "%fr4", "%fr5", "%fr6", "%fr7", "%fr8", "%fr9", "%fr10",
      "%fr11", "%fr12", "%fr13", "%fr14", "%fr15", "%fr16", "%fr17", "%fr18",
      "%fr19", "%fr20", "%fr21", "%fr22", "%fr23", "%fr24", "%fr25", "%fr26",
      "%fr27", "%fr28", "%fr29", "%fr30", "%fr31",
      "%fr0l", "%fr0r", "%fr4l", "%fr4r", "%fr5l", "%fr5r", "%fr6l", "%fr6r",
      "%fr7l", "%fr7r", "%fr8l", "%fr8r", "%fr9l", "%fr9r",
      "%fr10l", "%fr10r", "%fr11l", "%fr11r", "%fr12l", "%fr12r",
      "%fr13l", "%fr13r", "%fr14l", "%fr14r", "%fr15l", "%fr15r",
      "%fr16l", "%fr16r", "%fr17l", "%fr17r", "%fr18l", "%fr18r",
#ifdef __hppa64__
      "%fr19l", "%fr19r",
      "%fr20l", "%fr20r", "%fr21l", "%fr21r", "%fr22l", "%fr22r",
      "%fr23l", "%fr23r", "%fr24l", "%fr24r", "%fr25l", "%fr25r",
      "%fr26l", "%fr26r", "%fr27l", "%fr27r", "%fr28l", "%fr28r",
      "%fr29l", "%fr29r", "%fr30l", "%fr30r", "%fr31l", "%fr31r",
#endif
};

/*
 * Return a class suitable for a specific type.
 */
int
gclass(TWORD t)
{
      switch (t) {
      case LONGLONG:
      case ULONGLONG:
            return CLASSB;
      case FLOAT:
            return CLASSC;
      case DOUBLE:
      case LDOUBLE:
            return CLASSD;
      default:
            return CLASSA;
      }
}

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

      p->n_qual = size;
      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)
            size += argsiz(p->n_right);
      size += argsiz(p);
      op->n_qual = size; /* XXX */
}

/*
 * Special shapes.
 */
int
special(NODE *p, int shape)
{
      int o = p->n_op;

      switch (shape) {
      case SFUNCALL:
            if (o == STCALL || o == USTCALL)
                  return SRREG;
            break;
      case SPIMM:
            if (o != ICON || p->n_name[0] ||
                p->n_lval < -31 || p->n_lval >= 32)
                  break;
            return SRDIR;
      case SPICON:
            if (o != ICON || p->n_name[0] ||
                p->n_lval < -1024 || p->n_lval >= 1024)
                  break;
            return SRDIR;
      case SPCNHW:
            if (o != ICON || p->n_name[0] || (p->n_lval & 0xffffffffLL))
                  break;
            return SRDIR;
      case SPCNLW:
            if (o != ICON || p->n_name[0] || (p->n_lval & ~0xffffffffLL))
                  break;
            return SRDIR;
      case SPCNHI:
            if (o != ICON || p->n_name[0] || (p->n_lval & ~0xfffff800LL))
                  break;
            return SRDIR;
      case SPCON:
            if (o != ICON || p->n_name[0] ||
                p->n_lval < -8192 || p->n_lval >= 8192)
                  break;
            return SRDIR;
      case SPNAME:
            if (o != ICON || !p->n_name[0])
                  break;
            return SRDIR;
      }
      return SRNOPE;
}

/*
 * 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