/* $Id: local2.c,v 1.8 2007/11/26 00:26:46 gmcgarry Exp $ */
/*
* Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
* 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 <assert.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "pass1.h"
#include "pass2.h"
/*
* these mnemonics match the order of the preprocessor decls
* EQ, NE, LE, LT, GE, GT, ULE, ULT, UGE, UGT
*/
static char *
ccbranches[] = {
"beq", /* branch if equal */
"bne", /* branch if not-equal */
"ble", /* branch if less-than-or-equal */
"blt", /* branch if less-than */
"bge", /* branch if greater-than-or-equal */
"bgt", /* branch if greater-than */
/* what should these be ? */
"bls", /* branch if lower-than-or-same */
"blo", /* branch if lower-than */
"bhs", /* branch if higher-than-or-same */
"bhi", /* branch if higher-than */
};
/*
* 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 = "orr";
break;
case ER:
str = "eor";
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(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))
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, "\tcmp UR,UL\t@ compare 64-bit values (upper)\n");
if (cb1) cbgen(cb1, s);
if (cb2) cbgen(cb2, e);
expand(p, 0, "\tcmp AR,AL\t@ (and lower)\n");
cbgen(p->n_op, e);
deflab(s);
}
#if 0
/*
* Assign to a bitfield.
* Clumsy at least, but what to do?
*/
static void
bfasg(NODE *p)
{
NODE *fn = p->n_left;
int shift = UPKFOFF(fn->n_rval);
int fsz = UPKFSZ(fn->n_rval);
int andval, tch = 0;
/* get instruction size */
switch (p->n_type) {
case CHAR: case UCHAR: tch = 'b'; break;
case SHORT: case USHORT: tch = 'w'; break;
case INT: case UNSIGNED: tch = 'l'; break;
default: comperr("bfasg");
}
/* put src into a temporary reg */
fprintf(stdout, " mov%c ", tch);
adrput(stdout, getlr(p, 'R'));
fprintf(stdout, ",");
adrput(stdout, getlr(p, '1'));
fprintf(stdout, "\n");
/* AND away the bits from dest */
andval = ~(((1 << fsz) - 1) << shift);
fprintf(stdout, " and%c $%d,", tch, andval);
adrput(stdout, fn->n_left);
fprintf(stdout, "\n");
/* AND away unwanted bits from src */
andval = ((1 << fsz) - 1);
fprintf(stdout, " and%c $%d,", tch, andval);
adrput(stdout, getlr(p, '1'));
fprintf(stdout, "\n");
/* SHIFT left src number of bits */
if (shift) {
fprintf(stdout, " sal%c $%d,", tch, shift);
adrput(stdout, getlr(p, '1'));
fprintf(stdout, "\n");
}
/* OR in src to dest */
fprintf(stdout, " or%c ", tch);
adrput(stdout, getlr(p, '1'));
fprintf(stdout, ",");
adrput(stdout, fn->n_left);
fprintf(stdout, "\n");
}
#endif
/*
* Push a structure on stack as argument.
* the scratch registers are already free here
*/
static void
stasg(NODE *p)
{
NODE *l = p->n_left;
printf("\tldr %s,=%d\n", rnames[R2], p->n_stsize);
if (l->n_rval != R0 || l->n_lval != 0)
printf("\tadd %s,%s," CONFMT "\n", rnames[R0],
rnames[l->n_rval], l->n_lval);
printf("\tbl %s\n", exname("memcpy"));
}
static void
shiftop(NODE *p)
{
NODE *r = p->n_right;
TWORD ty = p->n_type;
if (p->n_op == LS && r->n_op == ICON && r->n_lval < 32) {
expand(p, INBREG, "\tmov A1,AL,lsr ");
printf(CONFMT "\t@ 64-bit left-shift\n", 32 - r->n_lval);
expand(p, INBREG, "\tmov U1,UL,asl AR\n");
expand(p, INBREG, "\torr U1,U1,A1\n");
expand(p, INBREG, "\tmov A1,AL,asl AR\n");
} else if (p->n_op == LS && r->n_op == ICON && r->n_lval < 64) {
expand(p, INBREG, "\tldr A1,=0\t@ 64-bit left-shift\n");
expand(p, INBREG, "\tmov U1,AL,asl ");
printf(CONFMT "\n", r->n_lval - 32);
} else if (p->n_op == LS && r->n_op == ICON) {
expand(p, INBREG, "\tldr A1,=0\t@ 64-bit left-shift\n");
expand(p, INBREG, "\tldr U1,=0\n");
} else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 32) {
expand(p, INBREG, "\tmov U1,UL,asl ");
printf(CONFMT "\t@ 64-bit right-shift\n", 32 - r->n_lval);
expand(p, INBREG, "\tmov A1,AL,lsr AR\n");
expand(p, INBREG, "\torr A1,A1,U1\n");
if (ty == LONGLONG)
expand(p, INBREG, "\tmov U1,UL,asr AR\n");
else
expand(p, INBREG, "\tmov U1,UL,lsr AR\n");
} else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 64) {
if (ty == LONGLONG) {
expand(p, INBREG, "\tldr U1,=-1\t@ 64-bit right-shift\n");
expand(p, INBREG, "\tmov A1,UL,asr ");
}else {
expand(p, INBREG, "\tldr U1,=0\t@ 64-bit right-shift\n");
expand(p, INBREG, "\tmov A1,UL,lsr ");
}
printf(CONFMT "\n", r->n_lval - 32);
} else if (p->n_op == LS && r->n_op == ICON) {
expand(p, INBREG, "\tldr A1,=0\t@ 64-bit right-shift\n");
expand(p, INBREG, "\tldr U1,=0\n");
}
}
/*
* http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
*/
static void
fpemul(NODE *p)
{
NODE *l = p->n_left;
char *ch = NULL;
if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3";
else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3";
else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3";
else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3";
else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3";
else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3";
else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3";
else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3";
else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3";
else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3";
else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3";
else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3";
else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2";
else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2";
else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2";
else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2";
else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2";
else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2";
else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2";
else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2";
else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2";
else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2";
else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2";
else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2";
else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2";
else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2";
else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2";
else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2";
else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2";
else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2";
else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2";
else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2";
else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2";
else if (p->n_op == SCONV && p->n_type == FLOAT) {
if (l->n_type == DOUBLE) ch = "truncdfsf2";
else if (l->n_type == LDOUBLE) ch = "trunctfsf2";
else if (l->n_type == ULONGLONG) ch = "floatuntisf";
else if (l->n_type == LONGLONG) ch = "floattisf";
else if (l->n_type == LONG) ch = "floatdisf";
else if (l->n_type == ULONG) ch = "floatundisf";
else if (l->n_type == INT) ch = "floatsisf";
else if (l->n_type == UNSIGNED) ch = "floatunsisf";
} else if (p->n_op == SCONV && p->n_type == DOUBLE) {
if (l->n_type == FLOAT) ch = "extendsfdf2";
else if (l->n_type == LDOUBLE) ch = "trunctfdf2";
else if (l->n_type == ULONGLONG) ch = "floatuntidf";
else if (l->n_type == LONGLONG) ch = "floattidf";
else if (l->n_type == LONG) ch = "floatdidf";
else if (l->n_type == ULONG) ch = "floatundidf";
else if (l->n_type == INT) ch = "floatsidf";
else if (l->n_type == UNSIGNED) ch = "floatunsidf";
} else if (p->n_op == SCONV && p->n_type == LDOUBLE) {
if (l->n_type == FLOAT) ch = "extendsftf2";
else if (l->n_type == DOUBLE) ch = "extenddftf2";
else if (l->n_type == ULONGLONG) ch = "floatuntitf";
else if (l->n_type == LONGLONG) ch = "floattitf";
else if (l->n_type == LONG) ch = "floatditf";
else if (l->n_type == ULONG) ch = "floatunsditf";
else if (l->n_type == INT) ch = "floatsitf";
else if (l->n_type == UNSIGNED) ch = "floatunsitf";
} else if (p->n_op == SCONV && p->n_type == ULONGLONG) {
if (l->n_type == FLOAT) ch = "fixunssfti";
else if (l->n_type == DOUBLE) ch = "fixunsdfti";
else if (l->n_type == LDOUBLE) ch = "fixunstfti";
} else if (p->n_op == SCONV && p->n_type == LONGLONG) {
if (l->n_type == FLOAT) ch = "fixsfti";
else if (l->n_type == DOUBLE) ch = "fixdfti";
else if (l->n_type == LDOUBLE) ch = "fixtfti";
} else if (p->n_op == SCONV && p->n_type == LONG) {
if (l->n_type == FLOAT) ch = "fixsfdi";
else if (l->n_type == DOUBLE) ch = "fixdfdi";
else if (l->n_type == LDOUBLE) ch = "fixtfdi";
} else if (p->n_op == SCONV && p->n_type == ULONG) {
if (l->n_type == FLOAT) ch = "fixunssfdi";
else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
else if (l->n_type == LDOUBLE) ch = "fixunstfdi";
} else if (p->n_op == SCONV && p->n_type == INT) {
if (l->n_type == FLOAT) ch = "fixsfsi";
else if (l->n_type == DOUBLE) ch = "fixdfsi";
else if (l->n_type == LDOUBLE) ch = "fixtfsi";
} else if (p->n_op == SCONV && p->n_type == UNSIGNED) {
if (l->n_type == FLOAT) ch = "fixunssfsi";
else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
else if (l->n_type == LDOUBLE) ch = "fixunstfsi";
}
if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op);
printf("\tbl __%s\t@ softfloat operation\n", exname(ch));
if (p->n_op >= EQ && p->n_op <= GT)
printf("\tcmp %s,#0\n", rnames[R0]);
}
/*
* http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
*/
static void
emul(NODE *p)
{
char *ch = NULL;
/**/ if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashlti3";
else if (p->n_op == LS && DEUNSIGN(p->n_type) == LONG) ch = "ashldi3";
else if (p->n_op == LS && DEUNSIGN(p->n_type) == INT) ch = "ashlsi3";
/**/ else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrti3";
else if (p->n_op == RS && p->n_type == ULONG) ch = "lshrdi3";
else if (p->n_op == RS && p->n_type == UNSIGNED) ch = "lshrsi3";
/**/ else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrti3";
else if (p->n_op == RS && p->n_type == LONG) ch = "ashrdi3";
else if (p->n_op == RS && p->n_type == INT) ch = "ashrsi3";
else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divti3";
else if (p->n_op == DIV && p->n_type == LONG) ch = "divdi3";
else if (p->n_op == DIV && p->n_type == INT) ch = "divsi3";
else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivti3";
else if (p->n_op == DIV && p->n_type == ULONG) ch = "udivdi3";
else if (p->n_op == DIV && p->n_type == UNSIGNED) ch = "udivsi3";
else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "modti3";
else if (p->n_op == MOD && p->n_type == LONG) ch = "moddi3";
else if (p->n_op == MOD && p->n_type == INT) ch = "modsi3";
else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umodti3";
else if (p->n_op == MOD && p->n_type == ULONG) ch = "umoddi3";
else if (p->n_op == MOD && p->n_type == UNSIGNED) ch = "umodsi3";
else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "multi3";
else if (p->n_op == MUL && p->n_type == LONG) ch = "muldi3";
else if (p->n_op == MUL && p->n_type == INT) ch = "mulsi3";
else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negti2";
else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negdi2";
else ch = 0, comperr("ZE");
printf("\tbl __%s\t@ emulated operation\n", exname(ch));
}
static int
argsiz(NODE *p)
{
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 12;
if (t == STRTY || t == UNIONTY)
return p->n_stsize;
comperr("argsiz");
return 0;
}
void
zzzcode(NODE *p, int c)
{
int pr;
switch (c) {
#if 0
case 'B': /* Assign to bitfield */
bfasg(p);
break;
#endif
case 'C': /* remove from stack after subroutine call */
pr = p->n_qual;
#if 0
if (p->n_op == STCALL || p->n_op == USTCALL)
pr += 4;
#endif
if (p->n_op == UCALL)
return; /* XXX remove ZC from UCALL */
if (pr > 0)
printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], pr);
break;
case 'D': /* Long long comparision */
twollcomp(p);
break;
case 'E': /* print out emulated ops */
emul(p);
break;
case 'F': /* print out emulated floating-point ops */
fpemul(p);
break;
case 'I': /* init constant */
if (p->n_name[0] != '\0')
comperr("named init");
fprintf(stdout, "=%lld", p->n_lval & 0xffffffff);
break;
case 'J': /* init longlong constant */
expand(p, INBREG, "\tldr A1,");
fprintf(stdout, "=%lld\t@ load 64-bit constant\n",
p->n_lval & 0xffffffff);
expand(p, INBREG, "\tldr U1,");
fprintf(stdout, "=%lld\n", (p->n_lval >> 32));
break;
case 'O': /* 64-bit left and right shift operators */
shiftop(p);
break;
case 'Q': /* emit struct assign */
stasg(p);
break;
default:
comperr("zzzcode %c", c);
}
}
/*ARGSUSED*/
int
rewfld(NODE *p)
{
return(1);
}
/*
* 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;
#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)
{
printf(CONFMT, val);
}
void
conput(FILE *fp, NODE *p)
{
char *s;
int val = p->n_lval;
switch (p->n_op) {
case ICON:
#if 0
if (p->n_sp)
printf(" [class=%d,level=%d] ", p->n_sp->sclass, p->n_sp->slevel);
#endif
if (p->n_sp == NULL || (p->n_sp->sclass == ILABEL ||
(p->n_sp->sclass == STATIC && p->n_sp->slevel > 0)))
s = p->n_name;
else
s = exname(p->n_name);
if (*s != '\0') {
fprintf(fp, "%s", s);
if (val > 0)
fprintf(fp, "+%d", val);
else if (val < 0)
fprintf(fp, "-%d", -val);
} else
fprintf(fp, CONFMT, (CONSZ)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:
fprintf(stdout, "%s", rnames[p->n_rval-R0R1+1]);
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 >> 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 NAME:
if (p->n_name[0] != '\0') {
fputs(p->n_name, io);
if (p->n_lval != 0)
fprintf(io, "+%lld", p->n_lval);
} else
fprintf(io, CONFMT, p->n_lval);
return;
case OREG:
r = p->n_rval;
fprintf(io, "[%s,#%d]", rnames[p->n_rval], (int)p->n_lval);
return;
case ICON:
/* addressable value of the constant */
conput(io, p);
return;
case MOVE:
case REG:
switch (p->n_type) {
#if !defined(ARM_HAS_FPA) && !defined(ARM_HAS_VFP)
case DOUBLE:
case LDOUBLE:
#endif
case LONGLONG:
case ULONGLONG:
fprintf(stdout, "%s", rnames[p->n_rval-R0R1]);
break;
default:
fprintf(io, "%s", rnames[p->n_rval]);
}
return;
default:
comperr("illegal address, op %d, node %p", p->n_op, p);
return;
}
}
/* printf conditional and unconditional branches */
void
cbgen(int o, int lab)
{
if (o < EQ || o > UGT)
comperr("bad conditional branch: %s", opst[o]);
printf("\t%s " LABFMT "\t@ conditional branch\n",
ccbranches[o-EQ], lab);
}
struct addrsymb {
DLIST_ENTRY(addrsymb) link;
struct symtab *orig;
struct symtab *new;
};
struct addrsymb addrsymblist;
static void
prtaddr(NODE *p)
{
NODE *l = p->n_left;
struct addrsymb *el;
int found = 0;
int lab;
if (p->n_op != ADDROF || l->n_op != NAME)
return;
/* write address to byte stream */
DLIST_FOREACH(el, &addrsymblist, link) {
if (el->orig == l->n_sp) {
found = 1;
break;
}
}
if (!found) {
setloc1(PROG);
defalign(SZPOINT(l->n_type));
deflab1(lab = getlab());
printf("\t.word ");
adrput(stdout, l);
printf("\n");
el = tmpalloc(sizeof(struct addrsymb));
el->orig = l->n_sp;
el->new = tmpalloc(sizeof(struct symtab_hdr));
el->new->sclass = ILABEL;
el->new->soffset = lab;
el->new->sflags = 0;
DLIST_INSERT_BEFORE(&addrsymblist, el, link);
}
nfree(l);
p->n_op = NAME;
p->n_lval = 0;
p->n_sp = el->new;
p2tree(p);
}
void
myreader(struct interpass *ipole)
{
struct interpass *ip;
DLIST_INIT(&addrsymblist, link);
DLIST_FOREACH(ip, ipole, qelem) {
if (ip->type != IP_NODE)
continue;
walkf(ip->ip_node, prtaddr);
}
if (x2debug)
printip(ipole);
}
/*
* Remove some PCONVs after OREGs are created.
*/
static void
pconv2(NODE *p)
{
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);
}
void
myoptim(struct interpass *ipp)
{
}
/*
* Register move: move contents of register 's' to register 'r'.
*/
void
rmove(int s, int d, TWORD t)
{
switch (t) {
#if !defined(ARM_HAS_FPU) && !defined(ARM_HAS_VFP)
case DOUBLE:
case LDOUBLE:
#endif
case LONGLONG:
case ULONGLONG:
#define LONGREG(x, y) rnames[(x)-(R0R1-(y))]
if (s == d+1) {
/* dh = sl, copy low word first */
printf("\tmov %s,%s @ rmove\n",
LONGREG(d,0), LONGREG(s,0));
printf("\tmov %s,%s\n",
LONGREG(d,1), LONGREG(s,1));
} else {
/* copy high word first */
printf("\tmov %s,%s @ rmove\n",
LONGREG(d,1), LONGREG(s,1));
printf("\tmov %s,%s\n",
LONGREG(d,0), LONGREG(s,0));
}
#undef LONGREG
break;
default:
printf("\tmov %s,%s @ rmove\n", rnames[d], rnames[s]);
}
}
/*
* Can we assign a register from class 'c', given the set
* of number of assigned registers in each class 'r'.
*
* On ARM, we have:
* 11 CLASSA registers (32-bit hard registers)
* 10 CLASSB registers (64-bit composite registers)
* 8 or 32 CLASSC registers (floating-point)
*
* There is a problem calculating the available composite registers
* (ie CLASSB). The algorithm below assumes that given any two
* registers, we can make a composite register. But this isn't true
* here (or with other targets), since the number of combinations
* of register pairs could become very large. Additionally,
* having so many combinations really isn't so practical, since
* most register pairs cannot be used to pass function arguments.
* Consequently, when there is pressure composite registers,
* "beenhere" compilation failures are common.
*
* [We need to know which registers are allocated, not simply
* the number in each class]
*/
int
COLORMAP(int c, int *r)
{
int num = 0; /* number of registers used */
#if 0
static const char classes[] = { 'X', 'A', 'B', 'C', 'D' };
printf("COLORMAP: requested class %c\n", classes[c]);
printf("COLORMAP: class A: %d\n", r[CLASSA]);
printf("COLORMAP: class B: %d\n", r[CLASSB]);
#endif
switch (c) {
case CLASSA:
num += r[CLASSA];
num += 2*r[CLASSB];
return num < 11;
case CLASSB:
num += 2*r[CLASSB];
num += r[CLASSA];
return num < 6; /* XXX see comments above */
case CLASSC:
num += r[CLASSC];
return num < 8;
}
assert(0);
return 0; /* XXX gcc */
}
/*
* Return a class suitable for a specific type.
*/
int
gclass(TWORD t)
{
#if defined(ARM_HAS_FPA) || defined(ARM_HAS_VFP)
if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
return CLASSC;
#endif
if (t == DOUBLE || t == LDOUBLE || t == LONGLONG || t == ULONGLONG)
return CLASSB;
return CLASSA;
}
/*
* 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)
size += argsiz(p->n_right);
size += argsiz(p);
op->n_qual = size - 16; /* XXX */
}
/*
* Special shapes.
*/
int
special(NODE *p, int shape)
{
return SRNOPE;
}
/*
* Target-dependent command-line options.
*/
void
mflags(char *str)
{
}
syntax highlighted by Code2HTML, v. 0.9.1