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

local2.c

/*    $Id: local2.c,v 1.40 2008/11/22 16:12:24 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>

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

static int ftlab1, ftlab2;

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

static TWORD ftype;
static int addto;

void
prologue(struct interpass_prolog *ipp)
{
    ftype = ipp->ipp_type;

#if 0
    if (ipp->ipp_regs > 0 && ipp->ipp_regs != MINRVAR)
      comperr("fix prologue register savings", ipp->ipp_regs);
#endif
    
    printf("      RSEG CODE:CODE:REORDER:NOROOT(0)\n");
    if (ipp->ipp_vis)   
      printf("    PUBLIC %s\n", ipp->ipp_name);
    printf("%s:\n", ipp->ipp_name);
    
#if 0 
    if (xsaveip) {
      /* Optimizer running, save space on stack */
      addto = (p2maxautooff - AUTOINIT)/SZCHAR;
      printf("    enter #%d\n", addto);
    } else {
#endif

      /* non-optimized code, jump to epilogue for code generation */
      ftlab1 = getlab2();
      ftlab2 = getlab2();
      printf("    jmp.w " LABFMT "\n", ftlab1);
      deflab(ftlab2);
}

/*
 * End of block.
 */
void
eoftn(struct interpass_prolog *ipp)
{
#if 0
      if (ipp->ipp_regs != MINRVAR)
            comperr("fix eoftn register savings %x", ipp->ipp_regs);
#endif

      //    if (xsaveip == 0)
      addto = (p2maxautooff - AUTOINIT)/SZCHAR;

      /* return from function code */
      //deflab(ipp->ipp_ip.ip_lbl);   //XXX - is this necessary?
      
      /* If retval is a pointer and not a function pointer, put in A0 */
      if (ISPTR(DECREF(ipp->ipp_type)) &&
          !ISFTN(DECREF(DECREF(ipp->ipp_type))))
          printf("      mov.w r0,a0\n");
      
      /* struct return needs special treatment */
      if (ftype == STRTY || ftype == UNIONTY) {
            comperr("fix struct return in eoftn");
      } else
            printf("    exitd\n");

      /* Prolog code */
      //    if (xsaveip == 0) {
            deflab(ftlab1);
            printf("    enter #%d\n", addto);
            printf("    jmp.w " LABFMT "\n", ftlab2);
            //}
}

/*
 * 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;
      default:
            comperr("hopcode2: %d", o);
            str = 0; /* XXX gcc */
      }
      printf("%s.%c", str, f);
}

char *
rnames[] = {  /* keyed to register number tokens */
    "r0", "r2", "r1", "r3", "a0", "a1", "fb", "sp", "r0h", "r0l",
    "r1h", "r1l",
};

/*
 * Return the size (in bytes) of some types.
 */
int
tlen(p) NODE *p;
{
      switch(p->n_type) {
            case CHAR:
            case UCHAR:
                  return(1);

            case INT:
            case UNSIGNED:
            case FLOAT:
                  return 2;

            case DOUBLE:
            case LONG:
            case ULONG:
                  return 4;

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

/*
 * 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;
      expand(p, 0, "    cmp.w UR,UL\n");
      if (cb1) cbgen(cb1, s);
      if (cb2) cbgen(cb2, e);
      expand(p, 0, "    cmp.w AR,AL\n");
      cbgen(p->n_op, e);
      deflab(s);
}


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

      switch (c) {
      case 'A': /* print negative shift constant */
            p = getlr(p, 'R');
            if (p->n_op != ICON)
                  comperr("ZA bad use");
            p->n_lval = -p->n_lval;
            adrput(stdout, p);
            p->n_lval = -p->n_lval;
            break;

      case 'B':
            if (p->n_rval)
                  printf("    add.b #%d,%s\n",
                      p->n_rval, rnames[STKREG]);
            break;

      case 'C': /* Print label address */
            p = p->n_left;
            if (p->n_lval)
                  printf(LABFMT, (int)p->n_lval);
            else
                  printf("%s", p->n_name);
            break;

      case 'D': /* copy function pointers */
            l = p->n_left;
            printf("\tmov.w #HWRD(%s),%s\n\tmov.w #LWRD(%s),%s\n",
                p->n_right->n_name, rnames[l->n_rval+1],
                p->n_right->n_name, rnames[l->n_rval]);
            break;

      case 'E': /* double-reg printout */
            /* XXX - always r0r2 here */
            printf("%s%s", rnames[R0], rnames[R2]);
            break;

      case 'F': /* long comparisions */
            twollcomp(p);
            break;

      case 'G':
            printf("R0R2");
            break;

      case 'H': /* push 32-bit address (for functions) */
            printf("\tpush.w #HWRD(%s)\n\tpush.w #LWRD(%s)\n",
                p->n_left->n_name, p->n_left->n_name);
            break;

      case 'I': /* push 32-bit address (for functions) */
            l = p->n_left;
            printf("\tpush.w %d[%s]\n\tpush.w %d[%s]\n",
                (int)l->n_lval, rnames[l->n_rval],
                (int)l->n_lval+2, rnames[l->n_rval]);
            break;

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

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

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) == SRDIR))
            return(1);
      return(0);
}

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

/*
 * Does the bitfield shape match?
 */
int
flshape(NODE *p)
{
      int o = p->n_op;

      if (o == OREG || o == REG || o == NAME)
            return SRDIR; /* Direct match */
      if (o == UMUL && shumul(p->n_left, SOREG))
            return SROREG; /* Convert into oreg */
      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;
}

void
adrcon(CONSZ val)
{
      printf("$" CONFMT, val);
}

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

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

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

/*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 /= SZINT;
      switch (p->n_op) {
      case REG:
            fputs(rnames[p->n_rval + 1], stdout);
            break;

      case NAME:
      case OREG:
            p->n_lval += size;
            adrput(stdout, p);
            p->n_lval -= size;
            break;
      case ICON:
            fprintf(stdout, "#" CONFMT, p->n_lval >> 16);
            break;
      default:
            comperr("upput bad op %d size %d", p->n_op, size);
      }
}

void
adrput(FILE *io, NODE *p)
{
      /* 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, io);
            if (p->n_lval != 0)
                  fprintf(io, "+" CONFMT, p->n_lval);
            return;

      case OREG:
            if (p->n_lval)
                  fprintf(io, "%d", (int)p->n_lval);
            fprintf(io, "[%s]", rnames[p->n_rval]);
            return;
      case ICON:
            /* addressable value of the constant */
            fputc('#', io);
            conput(io, p);
            return;

      case REG:
          /*if (DEUNSIGN(p->n_type) == CHAR) {
                  fprintf(io, "R%c%c", p->n_rval < 2 ? '0' : '1',
                      (p->n_rval & 1) ? 'H' : 'L');
                      } else*/
          fprintf(io, "%s", rnames[p->n_rval]);
          return;

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

      }
}

static char *
ccbranches[] = {
      "jeq",            /* jumpe */
      "jne",            /* jumpn */
      "jle",            /* jumple */
      "jlt",            /* jumpl */
      "jge",            /* jumpge */
      "jgt",            /* jumpg */
      "jleu",           /* jumple (jlequ) */
      "jltu",           /* jumpl (jlssu) */
      "jgeu",           /* jumpge (jgequ) */
      "jgtu",           /* jumpg (jgtru) */
};


/*   printf conditional and unconditional branches */
void
cbgen(int o, int lab)
{
      if (o < EQ || o > UGT)
            comperr("bad conditional branch: %s", opst[o]);
      printf("    %s " LABFMT "\n", ccbranches[o-EQ], lab);
}

void
mycanon(NODE *p)
{
}

void
myoptim(struct interpass *ip)
{
}

#if 0
void
mygenregs(NODE *p)
{

      if (p->n_op == MINUS && p->n_type == DOUBLE &&
          (p->n_su & (LMASK|RMASK)) == (LREG|RREG)) {
            p->n_su |= DORIGHT;
      }
      /* Must walk down correct node first for logops to work */
      if (p->n_op != CBRANCH)
            return;
      p = p->n_left;
      if ((p->n_su & (LMASK|RMASK)) != (LREG|RREG))
            return;
      p->n_su &= ~DORIGHT;

}
#endif

struct hardops hardops[] = {
      { PLUS, FLOAT, "?F_ADD_L04" },
      { MUL, LONG, "?L_MUL_L03" },
      { MUL, ULONG, "?L_MUL_L03" },
      { DIV, LONG, "?SL_DIV_L03" },
      { DIV, ULONG, "?UL_DIV_L03" },
      { MOD, LONG, "?SL_MOD_L03" },
      { MOD, ULONG, "?UL_MOD_L03" },
      { RS, LONGLONG, "__ashrdi3" },
      { RS, ULONGLONG, "__lshrdi3" },
      { LS, LONGLONG, "__ashldi3" },
      { LS, ULONGLONG, "__ashldi3" },
      { 0 },
};

int
special(NODE *p, int shape)
{
      switch (shape) {
      case SFTN:
            if (ISPTR(p->n_type) && ISFTN(DECREF(p->n_type))) {
                  if (p->n_op == NAME || p->n_op == OREG)
                        return SRDIR;
                  else
                        return SRREG;
            }
            break;
      }
      return SRNOPE;
}

void    
myreader(NODE *p)
{
      NODE *q, *r, *s, *right;

      if (optype(p->n_op) == LTYPE)
            return;
      if (optype(p->n_op) != UTYPE)
            myreader(p->n_right);
      myreader(p->n_left);

      switch (p->n_op) {
      case PLUS:
      case MINUS:
            if (p->n_type != LONG && p->n_type != ULONG)
                  break;
            if (p->n_right->n_op == NAME || p->n_right->n_op == OREG)
                  break;
            /* Must convert right into OREG */
            right = p->n_right;
            q = mklnode(OREG, BITOOR(freetemp(szty(right->n_type))),
                FPREG, right->n_type);
            s = mkbinode(ASSIGN, q, right, right->n_type);
            r = talloc(); 
            *r = *q;
            p->n_right = r;
            pass2_compile(ipnode(s));
            break;
      }
}


void
rmove(int s, int d, TWORD t)
{
      switch (t) {
      case CHAR:
      case UCHAR:
          printf("      mov.b %s,%s\n", rnames[s], rnames[d]);
          break;
      default:
          printf("      mov.w %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 = r[CLASSA];
            num += r[CLASSC];
            return num < 4;
      case CLASSB:
            num = r[CLASSB];
            return num < 2;
      case CLASSC:
            num = 2*r[CLASSA];
            num += r[CLASSC];
            return num < 4;
      }
      return 0; /* XXX gcc */
}

/*
 * Return a class suitable for a specific type.
 */
int
gclass(TWORD t)
{
      if (t == CHAR || t == UCHAR)
            return CLASSC;
      
      if(ISPTR(t))
            return CLASSB;
      
      return CLASSA;
}

static int sizen;

/* XXX: Fix this. */
static int
argsiz(NODE *p)
{
        TWORD t = p->n_type;

        if (t < LONGLONG || t > MAXTYPES)
                return 4;
        if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
                return 8;
        if (t == LDOUBLE)
                return 12;
        if (t == STRTY)
                return p->n_stsize;
        comperr("argsiz");
        return 0;
}

/*
 * Calculate argument sizes.
 * XXX: Fix this.
 */
void
lastcall(NODE *p)
{
        sizen = 0;
        for (p = p->n_right; p->n_op == CM; p = p->n_left)
                sizen += argsiz(p->n_right);
        sizen += argsiz(p);
}

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