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

code.c

/*
 * Copyright (c) 2008 David Crawshaw <david@zentus.com>
 * 
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "pass1.h"

void
defloc(struct symtab *sp)
{
      static char *loctbl[] = { "text", "data", "rodata" };
      static int lastloc = -1;
      TWORD t;
      char *n;
      int s;

      if (sp == NULL)
            return;

      t = sp->stype;
      s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
      if (s != lastloc)
            printf("\n\t.section \".%s\"\n", loctbl[s]);
      lastloc = s;
      if (s == PROG)
            return;

      switch (DEUNSIGN(sp->stype)) {
            case CHAR:  s = 1;
            case SHORT: s = 2;
            case INT:
            case UNSIGNED:    s = 4;
            default:    s = 8;
      }
      printf("\t.align %d\n", s);

      n = sp->soname ? sp->soname : sp->sname;
      if (sp->sclass == EXTDEF)
            printf("\t.global %s\n", n);
      if (sp->slevel == 0) {
            printf("\t.type %s,#object\n", n);
            printf("\t.size %s," CONFMT "\n", n,
                  tsize(sp->stype, sp->sdf, sp->sap) / SZCHAR);
            printf("%s:\n", n);
      } else
            printf(LABFMT ":\n", sp->soffset);
}

void
efcode()
{
      /* XXX */
}

void
bfcode(struct symtab **sp, int cnt)
{
      int i, off;
      NODE *p, *q;
      struct symtab *sym;

      /* Process the first six arguments. */
      for (i=0; i < cnt && i < 6; i++) {
            sym = sp[i];
            q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
            q->n_rval = RETREG_PRE(sym->stype) + i;
            p = tempnode(0, sym->stype, sym->sdf, sym->sap);
            sym->soffset = regno(p);
            sym->sflags |= STNODE;
            p = buildtree(ASSIGN, p, q);
            ecomp(p);
      }

      /* Process the remaining arguments. */
      for (off = V9RESERVE; i < cnt; i++) {
            sym = sp[i];
            p = tempnode(0, sym->stype, sym->sdf, sym->sap);
            off = ALIGN(off, (tlen(p) - 1));
            sym->soffset = off * SZCHAR;
            off += tlen(p);
            p = buildtree(ASSIGN, p, nametree(sym));
            sym->soffset = regno(p->n_left);
            sym->sflags |= STNODE;
            ecomp(p);
      }
}

void
bccode()
{
      SETOFF(autooff, SZINT);
}

void
ejobcode(int flag)
{
}

void
bjobcode()
{
}

/*
 * The first six 64-bit arguments are saved in the registers O0 to O5,
 * which become I0 to I5 after the "save" instruction moves the register
 * window. Arguments 7 and up must be saved on the stack to %sp+BIAS+176.
 *
 * For a pretty picture, see Figure 3-16 in the SPARC Compliance Def 2.4.
 */
static NODE *
moveargs(NODE *p, int *regp, int *stacksize)
{
      NODE *r, *q;

      if (p->n_op == CM) {
            p->n_left = moveargs(p->n_left, regp, stacksize);
            r = p->n_right;
      } else {
            r = p;
      }

      /* XXX more than six FP args can and should be passed in registers. */
      if (*regp > 5 && r->n_op != STARG) {
            /* We are storing the stack offset in n_rval. */
            r = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap);
            /* Make sure we are appropriately aligned. */
            *stacksize = ALIGN(*stacksize, (tlen(r) - 1));
            r->n_rval = *stacksize;
            *stacksize += tlen(r);
      } else if (r->n_op == STARG)
            cerror("op STARG in moveargs");
      else {
            q = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_ap);

            /*
             * The first six non-FP arguments go in the registers O0 - O5.
             * Float arguments are stored in %fp1, %fp3, ..., %fp29, %fp31.
             * Double arguments are stored in %fp0, %fp2, ..., %fp28, %fp30.
             * A non-fp argument still increments register, eg.
             *     test(int a, int b, float b)
             * takes %o0, %o1, %fp5.
             */
            if (q->n_type == FLOAT)
                  q->n_rval = F0 + (*regp++ * 2) + 1;
            else if (q->n_type == DOUBLE)
                  q->n_rval = D0 + *regp++;
            else if (q->n_type == LDOUBLE)
                  cerror("long double support incomplete");
            else
                  q->n_rval = O0 + (*regp)++;

            r = buildtree(ASSIGN, q, r);
      }

      if (p->n_op == CM) {
            p->n_right = r;
            return p;
      }

      return r;
}

NODE *
funcode(NODE *p)
{
      NODE *r, *l;
      int reg = 0, stacksize = 0;

      r = l = 0;

      p->n_right = moveargs(p->n_right, &reg, &stacksize);

      /*
       * This is a particularly gross and inefficient way to handle
       * argument overflows. First, we calculate how much stack space
       * we need in moveargs(). Then we assign it by moving %sp, make
       * the function call, and then move %sp back.
       *
       * What we should be doing is getting the maximum of all the needed
       * stacksize values to the prologue and doing it all in the "save"
       * instruction.
       */
      if (stacksize != 0) {
            stacksize = V9STEP(stacksize); /* 16-bit alignment. */

            r = block(REG, NIL, NIL, INT, 0, 0);
            r->n_lval = 0;
            r->n_rval = SP;
            r = block(MINUS, r, bcon(stacksize), INT, 0, 0);

            l = block(REG, NIL, NIL, INT, 0, 0);
            l->n_lval = 0;
            l->n_rval = SP;
            r = buildtree(ASSIGN, l, r);

            p = buildtree(COMOP, r, p);

            r = block(REG, NIL, NIL, INT, 0, 0);
            r->n_lval = 0;
            r->n_rval = SP;
            r = block(PLUS, r, bcon(stacksize), INT, 0, 0);

            l = block(REG, NIL, NIL, INT, 0, 0);
            l->n_lval = 0;
            l->n_rval = SP;
            r = buildtree(ASSIGN, l, r);

            p = buildtree(COMOP, p, r);

      }
      return p;
}

int
fldal(unsigned int t)
{
      uerror("illegal field type");
      return ALINT;
}

void
fldty(struct symtab *p)
{
}

int
mygenswitch(int num, TWORD type, struct swents **p, int n)
{
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index