633 lines
12 KiB
C
633 lines
12 KiB
C
/* $Id: local2.c,v 1.1.1.2 2007/10/27 14:43:32 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 = getlab();
|
|
ftlab2 = getlab();
|
|
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 = getlab();
|
|
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) == SRDIR))
|
|
return(1);
|
|
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))
|
|
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 MOVE:
|
|
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);
|
|
}
|
|
|
|
#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);
|
|
}
|