diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-11-25 18:45:07 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-11-25 18:45:07 +0000 |
commit | 3c2f541d3e23df847b1c1a21f4b872d9dbf7a77f (patch) | |
tree | a76920c888f85b6fb1f9f4468c2e490081c15d20 /usr.bin/pcc | |
parent | 65aba424613ac0024be70850b638392a82317dba (diff) |
arm backend from Gregory McGarry, untested
Diffstat (limited to 'usr.bin/pcc')
-rw-r--r-- | usr.bin/pcc/arm/code.c | 451 | ||||
-rw-r--r-- | usr.bin/pcc/arm/local.c | 640 | ||||
-rw-r--r-- | usr.bin/pcc/arm/local2.c | 954 | ||||
-rw-r--r-- | usr.bin/pcc/arm/macdefs.h | 229 | ||||
-rw-r--r-- | usr.bin/pcc/arm/order.c | 293 | ||||
-rw-r--r-- | usr.bin/pcc/arm/table.c | 1501 |
6 files changed, 4068 insertions, 0 deletions
diff --git a/usr.bin/pcc/arm/code.c b/usr.bin/pcc/arm/code.c new file mode 100644 index 00000000000..76004e533e9 --- /dev/null +++ b/usr.bin/pcc/arm/code.c @@ -0,0 +1,451 @@ +/* $OpenBSD: code.c,v 1.1 2007/11/25 18:45:06 otto 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. + */ + +/* + * Stuff for pass1. + */ + +#include <assert.h> + +#include "pass1.h" +#include "pass2.h" + +/* + * Modify the alignment in the data section to become a multiple of n. + */ +void +defalign(int n) +{ + n /= SZCHAR; + if (n == 1) + return; + printf("\t.align %d\n", n); +} + +/* + * Define the current location as an internal label. + */ +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +/* + * Define the current location in the data section to be the name p->sname + */ +void +defnam(struct symtab *p) +{ + char *c = p->sname; + +#ifdef GCC_COMPAT + c = gcc_findname(p); +#endif + if (p->sclass == EXTDEF) + printf("\t.global %s\n", exname(c)); + printf("%s:\n", exname(c)); +} + +int rvnr; + +/* + * End-of-Function code: + */ +void +efcode() +{ + NODE *p, *q; + int tempnr; + + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; + + /* + * At this point, the address of the return structure on + * has been FORCEd to RETREG, which is R0. + * We want to copy the contents from there to the address + * we placed into the tempnode "rvnr". + */ + + /* move the pointer out of R0 to a tempnode */ + q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue); + q->n_rval = R0; + p = tempnode(0, PTR+STRTY, 0, cftnsp->ssue); + tempnr = p->n_lval; + p = buildtree(ASSIGN, p, q); + ecomp(p); + + /* get the address from the tempnode */ + q = tempnode(tempnr, PTR+STRTY, 0, cftnsp->ssue); + q = buildtree(UMUL, q, NIL); + + /* now, get the structure destination */ + p = tempnode(rvnr, PTR+STRTY, 0, cftnsp->ssue); + p = buildtree(UMUL, p, NIL); + + /* struct assignment */ + p = buildtree(ASSIGN, p, q); + ecomp(p); +} + +/* + * Beginning-of-function code: + * + * 'a' is an array of indices in symtab for the arguments + * 'n' is the number of arguments + */ +void +bfcode(struct symtab **sp, int cnt) +{ + NODE *p, *q; + int i, n, start = 0; + + /* if returning a structure, more the hidden argument into a TEMP */ + if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { + p = tempnode(0, PTR+STRTY, 0, cftnsp->ssue); + rvnr = p->n_lval; + q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue); + q->n_rval = start++; + p = buildtree(ASSIGN, p, q); + ecomp(p); + } + + /* recalculate the arg offset and create TEMP moves */ + for (n = start, i = 0; i < cnt; i++) { + int sz = szty(sp[i]->stype); + if (n + sz <= 4) { + /* put stack args in temps */ + p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->ssue); + spname = sp[i]; + q = block(REG, NIL, NIL, + sp[i]->stype, sp[i]->sdf, sp[i]->ssue); + q->n_rval = (sz == 2 ? R0R1 + n : R0+n); + p = buildtree(ASSIGN, p, q); + sp[i]->soffset = p->n_left->n_lval; + sp[i]->sflags |= STNODE; + ecomp(p); + } else { + sp[i]->soffset -= SZINT * 4; + if (xtemps) { + /* put stack args in temps if optimizing */ + spname = sp[i]; + p = tempnode(0, sp[i]->stype, + sp[i]->sdf, sp[i]->ssue); + p = buildtree(ASSIGN, p, buildtree(NAME, 0, 0)); + sp[i]->soffset = p->n_left->n_lval; + sp[i]->sflags |= STNODE; + ecomp(p); + } + + } + n += szty(sp[i]->stype); + } +} + + +/* + * Beginning-of-code: finished generating function prologue + * + * by now, the automatics and register variables are allocated + */ +void +bccode() +{ + SETOFF(autooff, SZINT); +} + +/* + * End-of-job: called just before final exit. + */ +void +ejobcode(int flag ) +{ +#define OSB(x) __STRING(x) +#define OS OSB(TARGOS) + printf("\t.ident \"%s (%s)\"\n", PACKAGE_STRING, OS); +} + +/* + * Beginning-of-job: called before compilation starts + * + * Initialise data structures specific for the local machine. + */ +void +bjobcode() +{ +} + +/* + * Output ascii string: print character 't' at position 'i' until 't' == -1. + */ +void +bycode(int t, int i) +{ + static int lastoctal = 0; + + /* put byte i+1 in a string */ + + if (t < 0) { + if (i != 0) + puts("\""); + } else { + if (i == 0) + printf("\t.ascii \""); + if (t == '\\' || t == '"') { + lastoctal = 0; + putchar('\\'); + putchar(t); + } else if (t < 040 || t >= 0177) { + lastoctal++; + printf("\\%o",t); + } else if (lastoctal && '0' <= t && t <= '9') { + lastoctal = 0; + printf("\"\n\t.ascii \"%c", t); + } else { + lastoctal = 0; + putchar(t); + } + } +} + +/* + * Compute the alignment of object with type 't'. + */ +int +fldal(unsigned int t) +{ + uerror("illegal field type"); + return(ALINT); +} + +/* + * fix up type of field p + */ +void +fldty(struct symtab *p) +{ +} + +/* + * Build target-dependent switch tree/table. + * + * Return 1 if successfull, otherwise return 0 and the + * target-independent tree will be used. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} + +static int regoff[7]; +static TWORD ftype; + +/* + * calculate stack size and offsets + */ +static int +offcalc(struct interpass_prolog *ipp) +{ + int i, j, addto; + +#ifdef PCC_DEBUG + if (x2debug) + printf("offcalc: p2maxautooff=%d\n", p2maxautooff); +#endif + + addto = p2maxautooff; + + // space is always allocated on the stack to save the permanents + for (i = ipp->ipp_regs, j = 0; i ; i >>= 1, j++) { + if (i & 1) { + addto += SZINT/SZCHAR; + regoff[j] = addto; + } + } + +#if 0 + addto += 7; + addto &= ~7; +#endif + +#ifdef PCC_DEBUG + if (x2debug) + printf("offcalc: addto=%d\n", addto); +#endif + + addto -= AUTOINIT / SZCHAR; + + return addto; +} + +void +prologue(struct interpass_prolog *ipp) +{ + int i, j; + int addto; + +#ifdef PCC_DEBUG + if (x2debug) + printf("prologue: type=%d, lineno=%d, name=%s, vis=%d, ipptype=%d, regs=0x%x, autos=%d, tmpnum=%d, lblnum=%d\n", + ipp->ipp_ip.type, + ipp->ipp_ip.lineno, + ipp->ipp_name, + ipp->ipp_vis, + ipp->ipp_type, + ipp->ipp_regs, + ipp->ipp_autos, + ipp->ip_tmpnum, + ipp->ip_lblnum); +#endif + + ftype = ipp->ipp_type; + + printf("\t.align 2\n"); + if (ipp->ipp_vis) + printf("\t.global %s\n", exname(ipp->ipp_name)); + printf("\t.type %s,%%function\n", exname(ipp->ipp_name)); + printf("%s:\n", exname(ipp->ipp_name)); + + /* + * We here know what register to save and how much to + * add to the stack. + */ + addto = offcalc(ipp); + + printf("\tmov %s,%s\n", rnames[IP], rnames[SP]); + printf("\tstmfd %s!,{%s,%s,%s,%s}\n", rnames[SP], rnames[FP], + rnames[IP], rnames[LR], rnames[PC]); + printf("\tsub %s,%s,#4\n", rnames[FP], rnames[IP]); + if (addto) + printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], addto); + + for (i = ipp->ipp_regs, j = 0; i; i >>= 1, j++) { + if (i & 1) { + printf("\tstr %s,[%s,#-%d]\n", + rnames[j], rnames[FP], regoff[j]); + } + } + +} + +void +eoftn(struct interpass_prolog *ipp) +{ + int i, j; + + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + + /* return from function code */ + for (i = ipp->ipp_regs, j = 0; i ; i >>= 1, j++) { + if (i & 1) + printf("\tldr %s,[%s,#-%d]\n", + rnames[j], rnames[FP], regoff[j]); + + } + + /* struct return needs special treatment */ + if (ftype == STRTY || ftype == UNIONTY) { + assert(0); + } else { + printf("\tldmea %s,{%s,%s,%s}\n", rnames[FP], rnames[FP], + rnames[SP], rnames[PC]); + } + printf("\t.size %s,.-%s\n", exname(ipp->ipp_name), + exname(ipp->ipp_name)); +} + +char *rnames[] = { + "r0", "r1", "r2", "r3","r4","r5", "r6", "r7", "r8", + "r9", "r10", "fp", "ip", "sp", "lr", "pc", + "r0r1", "r1r2", "r2r3", "r3r4", "r4r5", "r5r6", + "r6r7", "r7r8", "r8r9", "r9r10", +}; + +static void +moveargs(NODE **n, int *regp) +{ + NODE *r = *n; + NODE *t; + int sz; + int regnum; + + if (r->n_op == CM) { + moveargs(&r->n_left, regp); + n = &r->n_right; + r = r->n_right; + } + + regnum = *regp; + sz = szty(r->n_type); + + if (regnum + sz <= R4) { + t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_sue); + switch (r->n_type) { + case DOUBLE: + case LDOUBLE: +#if defined(ARM_HAS_FPA) || defined(ARM_HAS_VFP) + t->n_rval = regnum + F0; + break; +#endif + case LONGLONG: + case ULONGLONG: + t->n_rval = regnum + R0R1; + break; + default: + t->n_rval = regnum; + } + t = buildtree(ASSIGN, t, r); + } else { + t = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_sue); + } + + *n = t; + *regp += sz; +} + +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + */ +NODE * +funcode(NODE *p) +{ + int regnum = R0; + int ty; + + ty = DECREF(p->n_left->n_type); + if (ty == STRTY+FTN || ty == UNIONTY+FTN) + regnum = R1; + + moveargs(&p->n_right, ®num); + return p; +} diff --git a/usr.bin/pcc/arm/local.c b/usr.bin/pcc/arm/local.c new file mode 100644 index 00000000000..70e9bfb4419 --- /dev/null +++ b/usr.bin/pcc/arm/local.c @@ -0,0 +1,640 @@ +/* $OpenBSD: local.c,v 1.1 2007/11/25 18:45:06 otto 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. + */ + +/* + * We define location operations which operate on the expression tree + * during the first pass (before sending to the backend for code generation.) + */ + +#include <assert.h> + +#include "pass1.h" + +/* + * clocal() is called to do local transformations on + * an expression tree before being sent to the backend. + */ +NODE * +clocal(NODE *p) +{ + struct symtab *q; + NODE *l, *r, *t; + int o; + int ty; + + o = p->n_op; + switch (o) { + + case STASG: + + l = p->n_left; + r = p->n_right; + if (r->n_op == STCALL || r->n_op == USTCALL) { + /* assign left node as first argument to function */ + nfree(p); + t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_sue); + l->n_rval = R0; + l = buildtree(ADDROF, l, NIL); + l = buildtree(ASSIGN, t, l); + ecomp(l); + t = tempnode(0, r->n_type, r->n_df, r->n_sue); + r = buildtree(ASSIGN, t, r); + ecomp(r); + t = tempnode(t->n_lval, r->n_type, r->n_df, r->n_sue); + return t; + } + break; + +#if 0 + case CALL: + r = tempnode(0, p->n_type, p->n_df, p->n_sue); + ecomp(buildtree(ASSIGN, r, p)); + return r; +#endif + + case NAME: + if ((q = p->n_sp) == NULL) + return p; + if (blevel == 0) + return p; + + switch (q->sclass) { + case PARAM: + case AUTO: + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + r->n_lval = 0; + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + case REGISTER: + p->n_op = REG; + p->n_lval = 0; + p->n_rval = q->soffset; + break; + case STATIC: + if (q->slevel > 0) { + p->n_lval = 0; + p->n_sp = q; + } + break; + default: + ty = p->n_type; + p = block(ADDROF, p, NIL, INCREF(ty), p->n_df, p->n_sue); + p = block(UMUL, p, NIL, ty, p->n_df, p->n_sue); + break; + } + break; + + case STNAME: + if ((q = p->n_sp) == NULL) + return p; + if (q->sclass != STNAME) + return p; + ty = p->n_type; + p = block(ADDROF, p, NIL, INCREF(ty), + p->n_df, p->n_sue); + p = block(UMUL, p, NIL, ty, p->n_df, p->n_sue); + break; + + case FORCE: + /* put return value in return reg */ + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT)); + p->n_left->n_rval = p->n_left->n_type == BOOL ? + RETREG(BOOL_TYPE) : RETREG(p->n_type); + break; + + case PMCONV: + case PVCONV: + nfree(p); + return buildtree(o == PMCONV ? MUL : DIV, p->n_left, p->n_right); + + case SCONV: + l = p->n_left; + if (p->n_type == l->n_type) { + nfree(p); + return l; + } + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + btdims[p->n_type].suesize == btdims[l->n_type].suesize) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE && + l->n_type != LDOUBLE && p->n_type != LDOUBLE) { + if (l->n_op == NAME || l->n_op == UMUL || + l->n_op == TEMP) { + l->n_type = p->n_type; + nfree(p); + return l; + } + } + } + +#if 0 // table.c will handle these okay + if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && + coptype(l->n_op) == BITYPE) { + l->n_type = p->n_type; + nfree(p); + return l; + } +#endif + + if (l->n_op == ICON) { + CONSZ val = l->n_lval; + + if (!ISPTR(p->n_type)) /* Pointers don't need to be conv'd */ + switch (p->n_type) { + case BOOL: + l->n_lval = l->n_lval != 0; + break; + case CHAR: + l->n_lval = (char)val; + break; + case UCHAR: + l->n_lval = val & 0377; + break; + case SHORT: + l->n_lval = (short)val; + break; + case USHORT: + l->n_lval = val & 0177777; + break; + case ULONG: + case UNSIGNED: + l->n_lval = val & 0xffffffff; + break; + case LONG: + case INT: + l->n_lval = (int)val; + break; + case LONGLONG: + l->n_lval = (long long)val; + break; + case ULONGLONG: + l->n_lval = val; + break; + case VOID: + break; + case LDOUBLE: + case DOUBLE: + case FLOAT: + l->n_op = FCON; + l->n_dcon = val; + break; + default: + cerror("unknown type %d", l->n_type); + } + l->n_type = p->n_type; + l->n_sue = MKSUE(p->n_type); + nfree(p); + return l; + } +#if 0 // table.c will handle these okay + if (DEUNSIGN(p->n_type) == SHORT && + DEUNSIGN(l->n_type) == SHORT) { + nfree(p); + p = l; + } +#endif + if ((DEUNSIGN(p->n_type) == CHAR || + DEUNSIGN(p->n_type) == SHORT) && + (l->n_type == FLOAT || l->n_type == DOUBLE || + l->n_type == LDOUBLE)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue); + p->n_left->n_type = INT; + return p; + } + break; + + case PCONV: + l = p->n_left; + if (l->n_op == ICON) { + l->n_lval = (unsigned)l->n_lval; + goto delp; + } + if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) { + p->n_left = block(SCONV, l, NIL, + UNSIGNED, 0, MKSUE(UNSIGNED)); + break; + } + if (l->n_op == SCONV) + break; + if (l->n_op == ADDROF && l->n_left->n_op == TEMP) + goto delp; + if (p->n_type > BTMASK && l->n_type > BTMASK) + goto delp; + break; + + delp: + l->n_type = p->n_type; + l->n_qual = p->n_qual; + l->n_df = p->n_df; + l->n_sue = p->n_sue; + nfree(p); + p = l; + break; + } + + return p; +} + +/* + * Called before sending the tree to the backend. + */ +void +myp2tree(NODE *p) +{ +} + +/* + * Called during the first pass to determine if a NAME can be addressed. + * + * Return nonzero if supported, otherwise return 0. + */ +int +andable(NODE *p) +{ + if (blevel == 0) + return 1; + if (ISFTN(p->n_type)) + return 1; + return 0; +} + +/* + * Called just after function arguments are built. Re-initialize the + * offset of the arguments on the stack. + * Is this necessary anymore? bfcode() is called immediately after. + */ +void +cendarg() +{ + autooff = AUTOINIT; +} + +/* + * Return 1 if a variable of type 't' is OK to put in register. + */ +int +cisreg(TWORD t) +{ + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) + return 0; /* not yet */ + return 1; +} + +/* + * Used for generating pointer offsets into structures and arrays. + * + * For a pointer of type 't', generate an the offset 'off'. + */ +NODE * +offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue) +{ + return bcon(off/SZCHAR); +} + +/* + * Allocate bits from the stack for dynamic-sized arrays. + * + * 'p' is the tree which represents the type being allocated. + * 'off' is the number of 'p's to be allocated. + * 't' is the storeable node where the address is written. + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + + p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ + + /* sub the size from sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT)); + sp->n_lval = 0; + sp->n_rval = SP; + ecomp(buildtree(MINUSEQ, sp, p)); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue); + sp->n_lval = 0; + sp->n_rval = SP; + t->n_type = sp->n_type; + ecomp(buildtree(ASSIGN, t, sp)); +} + +static int inbits = 0, inval = 0; + +/* + * set 'fsz' bits in sequence to zero. + */ +void +zbits(OFFSZ off, int fsz) +{ + int m; + + if (idebug) + printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits); + if ((m = (inbits % SZCHAR))) { + m = SZCHAR - m; + if (fsz < m) { + inbits += fsz; + return; + } else { + fsz -= m; + printf("\t.byte %d\n", inval); + inval = inbits = 0; + } + } + if (fsz >= SZCHAR) { + printf("\t.space %d\n", fsz/SZCHAR); + fsz -= (fsz/SZCHAR) * SZCHAR; + } + if (fsz) { + inval = 0; + inbits = fsz; + } +} + +/* + * Initialize a bitfield. + */ +void +infld(CONSZ off, int fsz, CONSZ val) +{ + if (idebug) + printf("infld off %lld, fsz %d, val %lld inbits %d\n", + off, fsz, val, inbits); + val &= (1 << fsz)-1; + while (fsz + inbits >= SZCHAR) { + inval |= (val << inbits); + printf("\t.byte %d\n", inval & 255); + fsz -= (SZCHAR - inbits); + val >>= (SZCHAR - inbits); + inval = inbits = 0; + } + if (fsz) { + inval |= (val << inbits); + inbits += fsz; + } +} + +/* + * Print an integer constant node, may be associated with a label. + * Do not free the node after use. + * 'off' is bit offset from the beginning of the aggregate + * 'fsz' is the number of bits this is referring to + */ +void +ninval(CONSZ off, int fsz, NODE *p) +{ + union { float f; double d; int i[2]; } u; + struct symtab *q; + TWORD t; + int i, j; + + t = p->n_type; + if (t > BTMASK) + t = INT; /* pointer */ + + if (p->n_op != ICON && p->n_op != FCON) + cerror("ninval: init node not constant"); + + if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) + uerror("element not constant"); + + switch (t) { + case LONGLONG: + case ULONGLONG: + i = (p->n_lval >> 32); + j = (p->n_lval & 0xffffffff); + p->n_type = INT; +#ifdef TARGET_BIG_ENDIAN + p->n_lval = i; + ninval(off+32, 32, p); + p->n_lval = j; + ninval(off, 32, p); +#else + p->n_lval = j; + ninval(off, 32, p); + p->n_lval = i; + ninval(off+32, 32, p); +#endif + break; + case INT: + case UNSIGNED: + printf("\t.word 0x%x", (int)p->n_lval); + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0) || + q->sclass == ILABEL) { + printf("+" LABFMT, q->soffset); + } else + printf("+%s", exname(q->sname)); + } + printf("\n"); + break; + case SHORT: + case USHORT: + printf("\t.short 0x%x\n", (int)p->n_lval & 0xffff); + break; + case BOOL: + if (p->n_lval > 1) + p->n_lval = p->n_lval != 0; + /* FALLTHROUGH */ + case CHAR: + case UCHAR: + printf("\t.byte %d\n", (int)p->n_lval & 0xff); + break; + case LDOUBLE: + case DOUBLE: + u.d = (double)p->n_dcon; +#if (defined(TARGET_BIG_ENDIAN) && defined(HOST_LITTLE_ENDIAN)) || \ + (defined(TARGET_LITTLE_ENDIAN) && defined(HOST_BIG_ENDIAN)) + printf("\t.word\t0x%x\n\t.word\t0x%x\n", u.i[0], u.i[1]); +#else + printf("\t.word\t0x%x\n\t.word\t0x%x\n", u.i[1], u.i[0]); +#endif + break; + case FLOAT: + u.f = (float)p->n_dcon; + printf("\t.word\t0x%x\n", u.i[0]); + break; + default: + cerror("ninval"); + } +} + +/* + * Prefix a leading underscore to a global variable (if necessary). + */ +char * +exname(char *p) +{ + return (p == NULL ? "" : p); +} + +/* + * Map types which are not defined on the local machine. + */ +TWORD +ctype(TWORD type) +{ + switch (BTYPE(type)) { + case LONG: + MODTYPE(type,INT); + break; + case ULONG: + MODTYPE(type,UNSIGNED); + break; + } + return (type); +} + +/* + * Before calling a function do any tree re-writing for the local machine. + * + * 'p' is the function tree (NAME) + * 'q' is the CM-separated list of arguments. + */ +void +calldec(NODE *p, NODE *q) +{ +} + +/* + * While handling uninitialised variables, handle variables marked extern. + */ +void +extdec(struct symtab *q) +{ +} + +/* + * make a common declaration for 'id', if reasonable + */ +void +commdec(struct symtab *q) +{ + int off; + + off = tsize(q->stype, q->sdf, q->ssue); + off = (off+(SZCHAR-1))/SZCHAR; +#ifdef GCC_COMPAT + printf("\t.comm %s,%d,%d\n", exname(gcc_findname(q)), off, 4); +#else + printf("\t.comm %s,%,%d\n", exname(q->sname), off, 4); +#endif +} + +/* + * make a local common declaration for 'id', if reasonable + */ +void +lcommdec(struct symtab *q) +{ + int off; + + off = tsize(q->stype, q->sdf, q->ssue); + off = (off+(SZCHAR-1))/SZCHAR; + if (q->slevel == 0) +#ifdef GCC_COMPAT + printf("\t.lcomm %s,%d\n", exname(gcc_findname(q)), off); +#else + printf("\t.lcomm %s,%d\n", exname(q->sname), off); +#endif + else + printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off); +} + +/* + * Print a (non-prog) label. + */ +void +deflab1(int label) +{ + printf(LABFMT ":\n", label); +} + +static char *loctbl[] = { "text", "data", "text", "section .rodata" }; + +void +setloc1(int locc) +{ + if (locc == lastloc) + return; + lastloc = locc; + printf("\t.%s\n", loctbl[locc]); +} + +/* + * va_start(ap, last) implementation. + * + * f is the NAME node for this builtin function. + * a is the argument list containing: + * CM + * ap last + */ +NODE * +arm_builtin_stdarg_start(NODE *f, NODE *a) +{ + NODE *p; + int sz = 1; + + /* check num args and type */ + if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || + !ISPTR(a->n_left->n_type)) + goto bad; + + /* must first deal with argument size; use int size */ + p = a->n_right; + if (p->n_type < INT) + sz = SZINT / tsize(p->n_type, p->n_df, p->n_sue); + +bad: + return bcon(0); +} + +NODE * +arm_builtin_va_arg(NODE *f, NODE *a) +{ + return bcon(0); +} + +NODE * +arm_builtin_va_end(NODE *f, NODE *a) +{ + return bcon(0); +} + +NODE * +arm_builtin_va_copy(NODE *f, NODE *a) +{ + return bcon(0); +} + diff --git a/usr.bin/pcc/arm/local2.c b/usr.bin/pcc/arm/local2.c new file mode 100644 index 00000000000..b278573efb1 --- /dev/null +++ b/usr.bin/pcc/arm/local2.c @@ -0,0 +1,954 @@ +/* $OpenBSD: local2.c,v 1.1 2007/11/25 18:45:06 otto 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; +} diff --git a/usr.bin/pcc/arm/macdefs.h b/usr.bin/pcc/arm/macdefs.h new file mode 100644 index 00000000000..c125945eb43 --- /dev/null +++ b/usr.bin/pcc/arm/macdefs.h @@ -0,0 +1,229 @@ +/* $Id: macdefs.h,v 1.1 2007/11/25 18:45:06 otto 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. + */ + +/* + * Machine-dependent defines for both passes. + */ + +/* + * Convert (multi-)character constant to integer. + */ +#define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZBOOL 32 +#define SZINT 32 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#define SZLDOUBLE 64 +#define SZLONG 32 +#define SZSHORT 16 +#define SZLONGLONG 64 +#define SZPOINT(t) 32 + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALBOOL 32 +#define ALINT 32 +#define ALFLOAT 32 +#define ALDOUBLE 32 +#define ALLDOUBLE 32 +#define ALLONG 32 +#define ALLONGLONG 32 +#define ALSHORT 16 +#define ALPOINT 32 +#define ALSTRUCT 32 +#define ALSTACK 32 + +/* + * Min/max values. + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT -1 +#define MAX_INT 0x7fffffff +#define MAX_UNSIGNED 0xffffffff +#define MIN_LONG MIN_INT +#define MAX_LONG MAX_INT +#define MAX_ULONG MAX_UNSIGNED +#define MIN_LONGLONG 0x8000000000000000LL +#define MAX_LONGLONG 0x7fffffffffffffffLL +#define MAX_ULONGLONG 0xffffffffffffffffULL + +#define BOOL_TYPE INT /* what used to store _Bool */ +#define WCHAR_TYPE INT /* what used to store wchar_t */ + +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "#%lld" /* format for printing constants */ +#define LABFMT ".L%d" /* format for printing labels */ +#define STABLBL "LL%d" /* format for stab (debugging) labels */ +#define STAB_LINE_ABSOLUTE /* S_LINE fields use absolute addresses */ + +#undef FIELDOPS /* no bit-field instructions */ + +#define ENUMSIZE(high,low) INT /* enums are always stored in full int */ + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) ((x)&03) +#define wdal(k) (BYTEOFF(k)==0) +#define BITOOR(x) (x) /* bit offset to oreg offset XXX die! */ + +#define STOARG(p) +#define STOFARG(p) +#define STOSTARG(p) + +#define szty(t) (((t) == DOUBLE || (t) == LDOUBLE || \ + (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1) + +#define R0 0 +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 + +#define FP 11 +#define IP 12 +#define SP 13 +#define LR 14 +#define PC 15 + +#define R0R1 16 +#define R1R2 17 +#define R2R3 18 +#define R3R4 19 +#define R4R5 20 +#define R5R6 21 +#define R6R7 22 +#define R7R8 23 +#define R8R9 24 +#define R9R10 25 + +#define NUMCLASS 2 +#define MAXREGS 26 + +#define RSTATUS \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + 0, 0, 0, 0, 0, \ + SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG, \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + +#define ROVERLAP \ + { R0R1, -1 }, \ + { R0R1, R1R2, -1 }, \ + { R1R2, R2R3, -1 }, \ + { R2R3, R3R4, -1 }, \ + { R3R4, R4R5, -1 }, \ + { R4R5, R5R6, -1 }, \ + { R5R6, R6R7, -1 }, \ + { R6R7, R7R8, -1 }, \ + { R7R8, R8R9, -1 }, \ + { R8R9, R9R10, -1 }, \ + { R9R10, -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { R0, R1, R1R2, -1 }, \ + { R1, R2, R0R1, R2R3, -1 }, \ + { R2, R3, R1R2, R3R4, -1 }, \ + { R3, R4, R2R3, R4R5, -1 }, \ + { R4, R5, R3R4, R5R6, -1 }, \ + { R5, R6, R4R5, R6R7, -1 }, \ + { R6, R7, R5R6, R7R8, -1 }, \ + { R7, R8, R6R7, R8R9, -1 }, \ + { R8, R9, R7R8, R9R10, -1 }, \ + { R9, R10, R8R9, -1 }, \ + +#define BACKTEMP /* stack grows negatively for temporaries */ +#define BACKAUTO /* stack grows negatively for automatics */ + +#define ARGINIT (4*8) /* # bits above fp where arguments start */ +#define AUTOINIT (12*8) /* # bits above fp where automatics start */ + +/* XXX - to die */ +#define FPREG FP /* frame pointer */ + +/* Return a register class based on the type of the node */ +#define PCLASS(p) (1 << gclass((p)->n_type)) + +#define GCLASS(x) (x < 16 ? CLASSA : CLASSB) +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 6) /* A1 */ +#define ENCRA2(x) ((x) << 12) /* A2 */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ + +#if defined(ARM_HAS_FPA) || defined(ARM_HAS_VFP) +#define RETREG(x) (DEUNSIGN(x) == LONGLONG ? R0R1 : \ + (x) == DOUBLE || (x) == LDOUBLE || (x) == FLOAT ? \ + F0 : R0) +#else +#define RETREG(x) (DEUNSIGN(x) == LONGLONG || \ + (x) == DOUBLE || (x) == LDOUBLE ? R0R1 : R0) +#endif + +int COLORMAP(int c, int *r); + +#define TARGET_STDARGS \ + { "__builtin_stdarg_start, arm_builtin_stdarg_start }, \ + { "__builtin_va_arg, arm_builtin_va_arg }, \ + { "__builtin_va_end, arm_builtin_va_end }, \ + { "__builtin_va_copy, arm_builtin_va_copy }, + +#define NODE struct node +struct node; +NODE *arm_builtin_stdarg_start(NODE *f, NODE *a); +NODE *arm_builtin_va_arg(NODE *f, NODE *a); +NODE *arm_builtin_va_end(NODE *f, NODE *a); +NODE *arm_builtin_va_copy(NODE *f, NODE *a); +#undef NODE diff --git a/usr.bin/pcc/arm/order.c b/usr.bin/pcc/arm/order.c new file mode 100644 index 00000000000..09f4bbcde60 --- /dev/null +++ b/usr.bin/pcc/arm/order.c @@ -0,0 +1,293 @@ +/* $OpenBSD: order.c,v 1.1 2007/11/25 18:45:06 otto 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. + */ + +/* + * Machine-dependent code-generation strategy (pass 2). + */ + +#include <assert.h> +#include <string.h> + +#include "pass2.h" + +/* + * Check size of offset in OREG. Called by oregok() to see if an + * OREG can be generated. + */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + if (cp && cp[0]) return 1; + return !(off < 32768 && off > -32769); /* YES */ +} + +/* + * Generate instructions for an OREG. Why is this routine MD? + * Called by swmatch(). + */ +void +offstar(NODE *p, int shape) +{ + NODE *r; + + if (isreg(p)) + return; /* Is already OREG */ + + r = p->n_right; + if( p->n_op == PLUS || p->n_op == MINUS ){ + if( r->n_op == ICON ){ + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + /* Converted in ormake() */ + return; + } + /* usually for arraying indexing: */ + if (r->n_op == LS && r->n_right->n_op == ICON && + r->n_right->n_lval == 2 && p->n_op == PLUS) { + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + if (isreg(r->n_left) == 0) + (void)geninsn(r->n_left, INAREG); + return; + } + } + (void)geninsn(p, INAREG); +} + +/* + * It is OK to do an OREG - Modify the expression tree to be an OREG. + */ +void +myormake(NODE *q) +{ +} + +/* + * Check to if the UMUL node can be converted into an OREG. + */ +int +shumul(NODE *p) +{ + /* Turns currently anything into OREG */ + return SOREG; +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of a failed table lookup. + * + * Return nonzero to retry table search on new tree, or zero to fail. + */ +int +setbin(NODE *p) +{ + return 0; + +} + +/* + * Rewrite assignment operations. + * Called as a result of a failed table lookup. + * + * Return nonzero to retry table search on new tree, or zero to fail. + */ +int +setasg(NODE *p, int cookie) +{ + return 0; +} + +/* + * Rewrite UMUL operation. + * Called as a result of a failed table lookup. + * + * Return nonzero to retry table search on new tree, or zero to fail. + */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +/* + * Special handling of some instruction register allocation. + * + * Called as a result of specifying NSPECIAL in the table. + */ +struct rspecial * +nspecial(struct optab *q) +{ + + switch (q->op) { + +#if !defined(ARM_HAS_FPA) && !defined(ARM_HAS_VFP) + case UMINUS: + case SCONV: + if (q->lshape == SBREG && q->rshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R0R1 }, + { NRES, R0 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG && q->rshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R0 }, + { NRES, R0R1 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG && q->rshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R0 }, + { NRES, R0 }, + { 0 } + }; + return s; + } else if (q->lshape == SBREG && q->rshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R0R1 }, + { NRES, R0R1 }, + { 0 } + }; + return s; + } + + case OPLOG: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R0R1 }, + { NRIGHT, R2R3 }, + { NRES, R0 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R0 }, + { NRIGHT, R1 }, + { NRES, R0 }, + { 0 } + }; + return s; + } + case PLUS: + case MINUS: + case MUL: +#endif + case MOD: + case DIV: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R0R1 }, + { NRIGHT, R2R3 }, + { NRES, R0R1 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R0 }, + { NRIGHT, R1 }, + { NRES, R0 }, + { 0 } + }; + return s; + } + case LS: + case RS: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R0R1 }, + { NRIGHT, R2 }, + { NRES, R0R1 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R0 }, + { NRIGHT, R1 }, + { NRES, R0 }, + { 0 } + }; + return s; + } + case STASG: + { + static struct rspecial s[] = { + { NEVER, R0 }, + { NRIGHT, R1 }, + { NEVER, R2 }, + { 0 } }; + return s; + } + break; + + default: + break; + } + +#ifdef PCC_DEBUG + comperr("nspecial entry %d [0x%x]: %s", q - table, q->op, q->cstring); +#endif + return 0; /* XXX gcc */ +} + +/* + * Set evaluation order of a binary node ('+','-', '*', '/', etc) if it + * differs from default. + */ +int +setorder(NODE *p) +{ + return 0; +} + +/* + * Set registers "live" at function calls (like arguments in registers). + * This is for liveness analysis of registers. + */ +int * +livecall(NODE *p) +{ + static int r[] = { R3, R2, R1, R0, -1 }; + int num = 1; + + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return &r[4-0]; + + for (p = p->n_right; p->n_op == CM; p = p->n_left) + num += szty(p->n_right->n_type); + num += szty(p->n_right->n_type); + + num = (num > 4 ? 4 : num); + + return &r[4 - num]; +} diff --git a/usr.bin/pcc/arm/table.c b/usr.bin/pcc/arm/table.c new file mode 100644 index 00000000000..fcf715dbc09 --- /dev/null +++ b/usr.bin/pcc/arm/table.c @@ -0,0 +1,1501 @@ +/* $OpenBSD: table.c,v 1.1 2007/11/25 18:45:06 otto Exp $ */ +/*- + * Copyright (c) 2007 Gregory McGarry <g.mcgarry@ieee.org> + * + * Permission to use, copy, modify, and 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. + */ + +/* + * A template has five logical sections: + * + * 1) subtree (operator); goal to achieve (cookie) + * 2) left node descendent of operator (node class; type) + * 3) right node descendent of operator (node class; type) + * 4) resource requirements (number of scratch registers); + * subtree rewriting rule + * 5) emitted instructions + */ + +#include "pass2.h" + +#define TUWORD TUNSIGNED|TULONG +#define TSWORD TINT|TLONG +#define TWORD TUWORD|TSWORD + +#if defined(ARM_HAS_FPA) || defined(ARM_HAS_VFP) +#define INFREG INCREG +#define NFREG NCREG +#define SFREG SCREG +#define NFSL NCSL +#define NFSR NCSR +#define INXREG INCREG +#define NXREG NCREG +#define SXREG SCREG +#define NXSL NCSL +#define NXSR NCSR +#else +#define INFREG INAREG +#define NFREG NAREG +#define SFREG SAREG +#define NFSL NASL +#define NFSR NASR +#define INXREG INBREG +#define NXREG NBREG +#define SXREG SBREG +#define NXSL NBSL +#define NXSR NBSR +#endif + +#define COM " @ " + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* PCONVs are not necessary */ +{ PCONV, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + COM "pointer conversion\n", }, + +/* + * Conversions of integral types + * + * For each deunsigned type, they look something like this: + * + * signed -> bigger signed - nothing to do + * signed -> bigger unsigned - clear the top bits (of source type) + * + * signed -> smaller signed - sign-extend the bits (to dest type) + * signed -> smaller unsigned - clear the top bits (of dest type) + * unsigned -> smaller signed - sign-extend top bits (to dest type) + * unsigned -> smaller unsigned - clear the top bits (of dest type) + * + * unsigned -> bigger - nothing to do + */ + +{ SCONV, INAREG, + INAREG, TCHAR, + INAREG, TSWORD|TSHORT, + NAREG|NASL, RESC1, + COM "convert char to short/int\n", }, + +{ SCONV, INAREG, + INAREG, TCHAR, + INAREG, TUWORD|TUSHORT|TUCHAR, + NAREG|NASL, RESC1, + " and A1,AL,#255" COM "convert char to uchar/ushort/uint\n", }, + +{ SCONV, INAREG, + INAREG, TUCHAR, + INAREG, TCHAR, + NAREG|NASL, RESC1, + " mov A1,AL,asl #24" COM "convert uchar to char\n" + " mov A1,A1,asr #24\n", }, + +{ SCONV, INAREG, + INAREG, TUCHAR, + INAREG, TWORD|TSHORT|TUSHORT, + 0, RLEFT, + COM "convert uchar to (u)short/(u)int\n", }, + +{ SCONV, INAREG, + INAREG, TSHORT, + INAREG, TSWORD, + 0, RLEFT, + COM "convert short to int\n", }, + +{ SCONV, INAREG, + INAREG, TSHORT, + INAREG, TUWORD, + NAREG|NASL, RESC1, + " mov A1,AL,asl #16" COM "convert short to uint\n" + " mov A1,AL,lsr #16\n", }, + +{ SCONV, INAREG, + INAREG, TUSHORT, + INAREG, TSHORT, + NAREG|NASL, RESC1, + " mov A1,AL,asl #16" COM "convert ushort to short\n" + " mov A1,A1,asr #16\n", }, + +{ SCONV, INAREG, + INAREG, TSHORT|TUSHORT, + INAREG, TCHAR, + NAREG|NASL, RESC1, + " mov A1,AL,asl #24" COM "convert (u)short to char\n" + " mov A1,A1,asr #24\n", }, + +{ SCONV, INAREG, + INAREG, TSHORT|TUSHORT, + INAREG, TUCHAR, + NAREG|NASL, RESC1, + " and A1,AL,#255" COM "convert (u)short to uchar\n", }, + +{ SCONV, INAREG, + INAREG, TUSHORT, + INAREG, TWORD, + NAREG|NASL, RESC1, + COM "convert ushort to (u)int\n", }, + +{ SCONV, INAREG, + INAREG, TWORD, + INAREG, TCHAR, + NAREG|NASL, RESC1, + " mov A1,AL,asl #24" COM "convert (u)int to char\n" + " mov A1,A1,asr #24\n", }, + +{ SCONV, INAREG, + INAREG, TWORD, + INAREG, TSHORT, + NAREG|NASL, RESC1, + " mov A1,AL,asl #16" COM "convert (u)int to short\n" + " mov A1,A1,asr #16\n", }, + +{ SCONV, INAREG, + INAREG, TWORD, + INAREG, TUCHAR, + NAREG|NASL, RESC1, + " and A1,AL,#255" COM "convert uchar to char\n", }, + +{ SCONV, INAREG, + INAREG, TWORD, + INAREG, TUSHORT, + NAREG|NASL, RESC1, + " mov A1,AL,asl #16" COM "convert int to ushort\n" + " mov A1,AL,lsr #16\n", }, + +{ SCONV, INAREG, + SAREG, TPOINT|TWORD, + SAREG, TWORD|TPOINT, + 0, RLEFT, + COM "convert between pointers and words\n", }, + +{ SCONV, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RLEFT, + COM "convert (u)longlong to (u)longlong\n", }, + +/* convert (u)char/(u)short/(u)int to longlong */ +{ SCONV, INBREG, + SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " mov A1,AL" COM "convert (u)char/(u)short/(u)int to (u)longlong\n" + " mov U1,AL,asr #31\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TCHAR, + NAREG, RESC1, + " mov A1,AL,asl #24" COM "convert (u)longlong to char\n" + " mov A1,A1,asr #24\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TSHORT, + NAREG, RESC1, + " mov A1,AL,asl #16" COM "convert (u)longlong to short\n" + " mov A1,A1,asr #16\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TWORD, + NAREG, RESC1, + " mov A1,AL" COM "convert (u)longlong to (u)int\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TUCHAR, + NAREG, RESC1, + " and A1,AL,#255" COM "convert (u)longlong to uchar\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TUSHORT, + NAREG, RESC1, + " mov A1,AL,asl #16" COM "convert (u)longlong to ushort\n" + " mov A1,A1,lsr #16\n", }, + +/* conversions on load from memory */ + +/* char */ +{ SCONV, INAREG, + SOREG, TCHAR, + SAREG, TWORD, + NASL|NAREG, RESC1, + " ldrsb A1,AL" COM "convert char to int/long\n", }, + +/* uchar */ +{ SCONV, INAREG, + SOREG, TUCHAR, + SAREG, TWORD, + NASL|NAREG, RESC1, + " ldrb A1,AL" COM "convert uchar to int/long\n", }, + +/* short */ +{ SCONV, INAREG, + SOREG, TSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " ldrsh A1,AL" COM "convert short to int/long\n", }, + +/* ushort */ +{ SCONV, INAREG, + SOREG, TSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " ldrh A1,AL" COM "convert ushort to int/long\n", }, + +{ SCONV, INAREG, + SFREG, TFLOAT, + SAREG, TSWORD, + NSPECIAL|NAREG, RESC1, +#ifdef ARM_HAS_FPA + " fix AL,AR" COM "convert float to int\n", }, +#elifdef ARM_HAS_VFP + " ftosis AL,AR" COM "convert float to int\n", }, +#else + "ZF", }, +#endif + +{ SCONV, INAREG, + SFREG, TFLOAT, + SAREG, TUWORD, + NSPECIAL|NAREG, RESC1, +#ifdef ARM_HAS_FPA + " fix AL,AR" COM "convert float to int\n", }, +#elifdef ARM_HAS_VFP + " ftouis AL,AR" COM "convert float to int\n", }, +#else + "ZF", }, +#endif + +{ SCONV, INBREG, + SFREG, TFLOAT, + SBREG, TULONGLONG, + NSPECIAL|NAREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP +#else + "ZF", }, +#endif + +{ SCONV, INBREG, + SFREG, TFLOAT, + SBREG, TLONGLONG, + NSPECIAL|NAREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP +#else + "ZF", }, +#endif + +{ SCONV, INAREG, + SXREG, TDOUBLE|TLDOUBLE, + SAREG, TSWORD, + NSPECIAL|NAREG, RESC1, +#ifdef ARM_HAS_FPA + " fix AL,AR" COM "convert double/ldouble to int\n", }, +#elifdef ARM_HAS_VFP + " ftosid AL,AR" COM "convert double/ldouble to int\n", }, +#else + "ZF", }, +#endif + +{ SCONV, INAREG, + SXREG, TDOUBLE|TLDOUBLE, + SAREG, TUWORD, + NSPECIAL|NAREG, RESC1, +#ifdef ARM_HAS_FPA + " fix AL,AR" COM "convert double/ldouble to int\n", }, +#elifdef ARM_HAS_VFP + " ftouid AL,AR" COM "convert double/ldouble to int\n", }, +#else + "ZF", }, +#endif + +{ SCONV, INBREG, + SXREG, TDOUBLE|TLDOUBLE, + SBREG, TULONGLONG, + NSPECIAL|NAREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP +#else + "ZF", }, +#endif + +{ SCONV, INBREG, + SXREG, TDOUBLE|TLDOUBLE, + SBREG, TLONGLONG, + NSPECIAL|NAREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP +#else + "ZF", }, +#endif + +{ SCONV, INFREG, + SAREG, TSWORD, + SFREG, TFLOAT, + NSPECIAL|NFREG, RESC1, +#ifdef ARM_HAS_FPA + " flts AL,AR" COM "convert int to float\n" }, +#elifdef ARM_HAS_VFP + " fsitos AL,AR" COM "convert int to float\n" }, +#else + "ZF", }, +#endif + +{ SCONV, INFREG, + SAREG, TUWORD, + SFREG, TFLOAT, + NSPECIAL|NFREG, RESC1, +#ifdef ARM_HAS_FPA + " flts AL,AR" COM "convert int to float\n" }, +#elifdef ARM_HAS_VFP + " fuitos AL,AR" COM "convert int to float\n" }, +#else + "ZF", }, +#endif + +{ SCONV, INFREG, + SBREG, TLONGLONG, + SFREG, TFLOAT, + NSPECIAL|NFREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP +#else + "ZF", }, +#endif + +{ SCONV, INFREG, + SBREG, TULONGLONG, + SFREG, TFLOAT, + NSPECIAL|NFREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP +#else + "ZF", }, +#endif + +{ SCONV, INXREG, + SAREG, TSWORD, + SXREG, TDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA + " fltd AL,AR" COM "convert int to double\n" }, +#elifdef ARM_HAS_VFP + " fsitod AL,AR" COM "convert int to double\n" }, +#else + "ZF", }, +#endif + +{ SCONV, INXREG, + SAREG, TUWORD, + SXREG, TDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA + " fltd AL,AR" COM "convert int to double\n" }, +#elifdef ARM_HAS_VFP + " fuitod AL,AR" COM "convert int to double\n" }, +#else + "ZF", }, +#endif + +{ SCONV, INXREG, + SBREG, TLONGLONG, + SXREG, TDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP +#else + "ZF", }, +#endif + +{ SCONV, INXREG, + SBREG, TULONGLONG, + SXREG, TDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP +#else + "ZF", }, +#endif + +{ SCONV, INXREG, + SAREG, TSWORD, + SXREG, TLDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA + " flte AL,AR" COM "convert int to ldouble\n" }, +#elifdef ARM_HAS_VFP + " fsitod AL,AR" COM "convert int to ldouble\n" }, +#else + "ZF", }, +#endif + +{ SCONV, INXREG, + SAREG, TUWORD, + SXREG, TLDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA + " flte AL,AR" COM "convert int to ldouble\n" }, +#elifdef ARM_HAS_VFP + " fuitod AL,AR" COM "convert int to ldouble\n" }, +#else + "ZF", }, +#endif + + +{ SCONV, INXREG, + SBREG, TLONGLONG, + SXREG, TLDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP +#else + "ZF", }, +#endif + +{ SCONV, INXREG, + SBREG, TULONGLONG, + SXREG, TLDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP +#else + "ZF", }, +#endif + +{ SCONV, INFREG, + SXREG, TDOUBLE, + SFREG, TFLOAT, + NSPECIAL|NFREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP + " fcvtds AL,AR" COM "convert float to double\n" }, +#else + "ZF", }, +#endif + +{ SCONV, INFREG, + SXREG, TLDOUBLE, + SFREG, TFLOAT, + NSPECIAL|NFREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP + " fcvtds AL,AR" COM "convert float to double\n" }, +#else + "ZF", }, +#endif + +{ SCONV, INXREG, + SFREG, TFLOAT, + SXREG, TDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP + " fcvtsd AL,AR" COM "convert float to double\n" }, +#else + "ZF", }, +#endif + +{ SCONV, INXREG, + SFREG, TFLOAT, + SXREG, TLDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA +#elifdef ARM_HAS_VFP + " fcvtsd AL,AR" COM "convert float to double\n" }, +#else + "ZF", }, +#endif + +{ SCONV, INXREG, + SXREG, TDOUBLE|TLDOUBLE, + SXREG, TDOUBLE|TLDOUBLE, + 0, RLEFT, + COM "convert (l)double to (l)double", }, + +/* + * Subroutine calls. + */ + +{ CALL, FOREFF, + SCON|SNAME, TANY, + SANY, TANY, + 0, 0, + " bl CL" COM "call (args, no result) to scon/sname (CL)\n" + "ZC", }, + +{ UCALL, FOREFF, + SCON|SNAME, TANY, + SANY, TANY, + 0, 0, + " bl CL" COM "call (no args, no result) to scon/sname (CL)\n", }, + +{ CALL, INAREG, + SCON|SNAME, TANY, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result in r0) to scon/sname (CL)\n" + "ZC", }, + +{ CALL, INBREG, + SCON|SNAME, TANY, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n" + "ZC", }, + +{ CALL, INFREG, + SCON|SNAME, TANY, + SFREG, TFLOAT, + NFREG|NASL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result r0) to scon/sname (CL)\n" + "ZC", }, + +{ CALL, INXREG, + SCON|SNAME, TANY, + SXREG, TDOUBLE|TLDOUBLE, + NXREG|NXSL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n" + "ZC", }, + +{ UCALL, INAREG, + SCON|SNAME, TANY, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", }, + +{ UCALL, INBREG, + SCON|SNAME, TANY, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", }, + +{ UCALL, INFREG, + SCON|SNAME, TANY, + SFREG, TFLOAT, + NFREG|NFSL, RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", }, + +{ UCALL, INXREG, + SCON|SNAME, TANY, + SXREG, TDOUBLE|TLDOUBLE, + NXREG|NXSL, RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", }, + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " mov lr,pc\n" + " mov pc,AL\n" + "ZC", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " mov lr,pc\n" + " mov pc,AL\n", }, + +/* struct return */ +{ USTCALL, FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, 0, + " bl CL\n", }, + +{ USTCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL\n", }, + +{ USTCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " mov lr,pc\n" + " mov pc,AL\n", }, + +{ STCALL, FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, 0, + " bl CL\n" + "ZC", }, + +{ STCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL\n" + "ZC", }, + +{ STCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " mov lr,pc\n" + " mov pc,AL\n" + "ZC", }, + +/* + * The next rules handle all binop-style operators. + */ + +{ PLUS, INAREG, + SAREG, TWORD|TPOINT, + SCCON, TANY, + NAREG, RESC1, + " add A1,AL,AR" COM "addition of constant\n", }, + +{ PLUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SSCON, TANY, + NBREG|NBSL, RESC1, + " adds A1,AL,AR" COM "64-bit addition of constant\n" + " adc U1,UL,UR\n", }, + +{ PLUS, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + " add A1,AL,AR" COM "addition\n", }, + +{ PLUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " adds A1,AL,AR" COM "64-bit addition\n" + " adc U1,UL,UR\n", }, + +{ PLUS, INFREG, + SFREG, TFLOAT, + SFREG, TFLOAT, + NSPECIAL|NFREG, RESC1, +#ifdef ARM_HAS_FPA + " adfs A1,AL,AR" COM "float add\n", }, +#elifdef ARM_HAS_VFP + " fadds A1,AL,AR" COM "float add\n", }, +#else + "ZF", }, +#endif + +{ PLUS, INXREG, + SXREG, TDOUBLE, + SXREG, TDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA + " adfd A1,AL,AR" COM "double add\n", }, +#elifdef ARM_HAS_VFP + " faddd A1,AL,AR" COM "double add\n", }, +#else + "ZF", }, +#endif + +{ PLUS, INXREG, + SXREG, TLDOUBLE, + SXREG, TLDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA + " adfe A1,AL,AR" COM "ldouble add\n", }, +#elifdef ARM_HAS_VFP + " faddd A1,AL,AR" COM "ldouble add\n", }, +#else + "ZF", }, +#endif + +{ MINUS, INAREG, + SAREG, TWORD|TPOINT, + SCCON, TANY, + NAREG|NASL, RESC1, + " sub A1,AL,AR" COM "subtraction of constant\n", }, + +{ MINUS, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + " sub A1,AR,AL" COM "subtraction\n", }, + +{ MINUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SCCON, TANY, + NBREG|NBSL, RESC1, + " subs A1,AL,AR" COM "64-bit subtraction of constant\n" + " rsc U1,UL,AR\n", }, + +{ MINUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " subs A1,AL,AR" COM "64-bit subtraction\n" + " sbc U1,UL,AR\n", }, + +{ MINUS, INFREG, + SFREG, TFLOAT, + SFREG, TFLOAT, + NSPECIAL|NFREG, RESC1, +#ifdef ARM_HAS_FPA + " sufs A1,AL,AR" COM "float subtraction\n", }, +#elifdef ARM_HAS_VFP + " fsubs A1,AL,AR" COM "float subtraction\n", }, +#else + "ZF", }, +#endif + +{ MINUS, INXREG, + SXREG, TDOUBLE, + SXREG, TDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA + " sufd A1,AL,AR" COM "double subtraction\n", }, +#elifdef ARM_HAS_VFP + " fsubd A1,AL,AR" COM "double subtraction\n", }, +#else + "ZF", }, +#endif + +{ MINUS, INXREG, + SXREG, TLDOUBLE, + SXREG, TLDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA + " sufe A1,AL,AR" COM "ldouble subtraction\n", }, +#elifdef ARM_HAS_VFP + " fsubd A1,AL,AR" COM "double subtraction\n", }, +#else + "ZF", }, +#endif + +/* + * The next rules handle all shift operators. + */ + +{ LS, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " mov A1,AL,asl AR" COM "left shift\n", }, + +{ LS, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SCCON, TANY, + NAREG|NASL, RESC1, + " mov A1,AL,asl AR" COM "left shift by constant\n", }, + +{ LS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SCON, TANY, + NBREG, RESC1, + "ZO" }, + +{ RS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + NAREG|NASL, RESC1, + " mov A1,AL,asr AR" COM "right shift\n", }, + +{ RS, INAREG, + SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TUWORD|TUSHORT|TUCHAR, + NAREG|NASL, RESC1, + " mov A1,AL,lsr AR" COM "right shift\n", }, + +{ RS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SCCON, TANY, + NAREG|NASL, RESC1, + " mov A1,AL,asr AR" COM "right shift by constant\n", }, + +{ RS, INAREG, + SAREG, TUWORD|TUSHORT|TUCHAR, + SCCON, TANY, + NAREG|NASL, RESC1, + " mov A1,AL,lsr AR" COM "right shift by constant\n", }, + +{ RS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SCON, TANY, + NBREG, RESC1, + "ZO" }, + +/* + * The next rules takes care of assignments. "=". + */ + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RDEST, + " str AR,AL" COM "assign word\n", }, + +{ ASSIGN, FOREFF|INBREG, + SOREG|SNAME, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RDEST, + " str AR,AL" COM "assign 64-bit value\n" + " str UR,UL\n", }, + +/* XXX don't know if this works */ +{ ASSIGN, FOREFF|INBREG, + SAREG, TPTRTO|TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RDEST, + " stmdb AL,{AR-UR}" COM "assign 64-bit value\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + 0, RDEST, + " strb AR,AL" COM "assign (u)char\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RDEST, + " strh AR,AL" COM "assign (u)short\n", }, + +{ ASSIGN, FOREFF|INFREG, + SOREG|SNAME, TFLOAT, + SFREG, TFLOAT, + 0, RDEST, +#ifdef ARM_HAS_FPA + " stfs AR,AL" COM "assign float\n", }, +#elifdef ARM_HAS_VFP +#else + " str AR,AL" COM "assign float\n", }, +#endif + +{ ASSIGN, FOREFF|INXREG, + SOREG|SNAME, TDOUBLE, + SXREG, TDOUBLE, + 0, RDEST, +#ifdef ARM_HAS_FPA + " stfd AR,AL" COM "assign double\n", }, +#elifdef ARM_HAS_VFP +#else + " str AR,AL" COM "assign double\n" + " str UR,UL\n", }, +#endif + +{ ASSIGN, FOREFF|INXREG, + SOREG|SNAME, TLDOUBLE, + SXREG, TLDOUBLE, + 0, RDEST, +#ifdef ARM_HAS_FPA + " stfe AR,AL" COM "assign ldouble\n", }, +#elifdef ARM_HAS_VFP +#else + " str AR,AL" COM "assign ldouble\n" + " str UR,UL\n", }, +#endif + +/* assign register to register */ +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + 0, RDEST, + " mov AL,AR" COM "assign AR to AL\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RDEST, + " mov AL,AR" COM "assign UR:AR to UL:AL\n" + " mov UL,UR\n", }, + +{ ASSIGN, FOREFF|INFREG, + SFREG, TFLOAT, + SFREG, TFLOAT, + 0, RDEST, +#ifdef ARM_HAS_FPA + " mvf AL,AR" COM "assign float reg to float reg\n", }, +#elifdef ARM_HAS_VFP + " fcpys AL,AR" COM "assign float reg to float reg\n", }, +#else + " mov AL,AR" COM "assign float reg to float reg\n", }, +#endif + +{ ASSIGN, FOREFF|INXREG, + SXREG, TDOUBLE|TLDOUBLE, + SXREG, TDOUBLE|TLDOUBLE, + 0, RDEST, +#ifdef ARM_HAS_FPA + " mvf AL,AR" COM "assign float reg to float reg\n", }, +#elifdef ARM_HAS_VFP + " fcpyd AL,AR" COM "assign float reg to float reg\n", }, +#else + " mov AL,AR" COM "assign (l)double reg to (l)double reg\n" + " mov UL,UR\n", }, +#endif + +#if 0 +{ ASSIGN, FOREFF|INAREG, + SFLD, TANY, + SAREG, TANY, + NAREG, RDEST, + "ZE", }, + +{ ASSIGN, FOREFF, + SFLD, TANY, + SAREG, TANY, + NAREG, 0, + "ZE", }, +#endif + +{ STASG, INAREG|FOREFF, + SOREG|SNAME, TANY, + SAREG, TPTRTO|TANY, + NSPECIAL, RRIGHT, + "ZQ", }, + +/* + * DIV/MOD/MUL + */ + +{ DIV, INAREG, + SAREG, TWORD, + SAREG, TWORD, + NSPECIAL|NAREG|NASL, RESC1, + "ZE", }, + +{ DIV, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG|NBSL, RESC1, + "ZE", }, + +{ DIV, INFREG, + SFREG, TFLOAT, + SFREG, TFLOAT, + NSPECIAL|NFREG, RESC1, +#ifdef ARM_HAS_FPA + " dvfs A1,AL,AL" COM "fast (float) divide\n", }, +#elifdef ARM_HAS_VFP + " fdivs A1,AL,AL" COM "fast (float) divide\n", }, +#else + "ZF", }, +#endif + +{ DIV, INXREG, + SXREG, TDOUBLE, + SXREG, TDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA + " dvfd A1,AL,AL" COM "double divide\n", }, +#elifdef ARM_HAS_VFP + " fdivd A1,AL,AL" COM "double divide\n", }, +#else + "ZF", }, +#endif + +{ DIV, INXREG, + SXREG, TLDOUBLE, + SXREG, TLDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA + " dvfe A1,AL,AL" COM "ldouble divide\n", }, +#elifdef ARM_HAS_VFP + " fdivd A1,AL,AL" COM "double divide\n", }, +#else + "ZF", }, +#endif + +{ MOD, INAREG, + SAREG, TWORD, + SAREG, TWORD, + NSPECIAL|NAREG, RESC1, + "ZE", }, + +{ MOD, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +{ MUL, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NSPECIAL|NAREG, RESC1, + " mul A1,AL,AR\n", }, + +{ MUL, INBREG, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + NSPECIAL|NBREG, RESC1, +#ifdef ARM_HAS_MULL + " smull U1,A1,AL,AR\n", }, +#else + " mul A1,AL,AR\n" + " mul U1,AL,AR\n", }, +#endif + +{ MUL, INBREG, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + NSPECIAL|NBREG, RESC1, +#ifdef ARM_HAS_MULL + " umull U1,A1,AL,AR\n", }, +#else + " mul A1,AL,AR\n" + " mul U1,AL,AR\n", }, +#endif + +{ MUL, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG, RESC1, +#ifdef ARM_HAS_MULL + " umull U1,A1,AL,AR\n", }, +#else + " mul A1,AL,AR\n" + " mul U1,AL,AR\n", }, +#endif + +{ MUL, INFREG, + SFREG, TFLOAT, + SFREG, TFLOAT, + NSPECIAL|NFREG, RESC1, +#ifdef ARM_HAS_FPA + " fmls A1,AL,AL" COM "fast (float) multiply\n", }, +#elifdef ARM_HAS_VFP + " fmuls A1,AL,AL" COM "float multiply\n", }, +#else + "ZF", }, +#endif + +{ MUL, INXREG, + SXREG, TDOUBLE|TLDOUBLE, + SXREG, TDOUBLE|TLDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA + " mufd A1,AL,AL" COM "fast (l)double multiply\n", }, +#elifdef ARM_HAS_VFP + " muld A1,AL,AL" COM "(l)double multiply\n", }, +#else + "ZF", }, +#endif + +/* + * Indirection operators. + */ + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TWORD|TPOINT, + NAREG, RESC1, + " ldr A1,AL" COM "word load\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TCHAR, + NAREG, RESC1, + " ldrsb A1,AL" COM "char load\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TUCHAR, + NAREG, RESC1, + " ldrb A1,AL" COM "uchar load\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TUSHORT, + NAREG, RESC1, + " ldrh A1,AL" COM "short load\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TSHORT, + NAREG, RESC1, + " ldrsh A1,AL" COM "short load\n", }, + +{ UMUL, INBREG, + SANY, TANY, + SOREG|SNAME, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " ldr A1,AL" COM "64-bit load\n" + " ldr U1,UL\n", }, + +{ UMUL, INFREG, + SANY, TANY, + SOREG|SNAME, TFLOAT, + NFREG, RESC1, +#ifdef ARM_HAS_FPA + " ldfs A1,AL" COM "float load\n", }, +#elifdef ARM_HAS_VFP +#else + " ldr A1,AL" COM "float load\n", }, +#endif + +{ UMUL, INXREG, + SANY, TANY, + SOREG|SNAME, TDOUBLE, + NXREG, RESC1, +#ifdef ARM_HAS_FPA + " ldfd AL" COM "double load\n", }, +#elifdef ARM_HAS_VFP +#else + " ldr A1,AL" COM "double load\n" + " ldr U1,UL\n", }, +#endif + +{ UMUL, INXREG, + SANY, TANY, + SOREG|SNAME, TLDOUBLE, + NXREG, RESC1, +#ifdef ARM_HAS_FPA + " ldfe AL" COM "long double load\n", }, +#elifdef ARM_HAS_VFP +#else + " ldr A1,AL" COM "long double load\n" + " ldr U1,UL\n", }, +#endif + +/* + * Logical/branching operators + */ + +/* compare with register */ +{ OPLOG, FORCC, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + 0, RESCC, + " cmp AL,AR" COM "AR-AL (sets flags)\n", }, + +/* compare with register */ +{ OPLOG, FORCC, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + 0, RESCC, + " cmp AL,AR" COM "AR-AL (sets flags)\n", }, + +/* compare with register */ +{ OPLOG, FORCC, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RESCC, + "ZD", }, + +{ OPLOG, FORCC, + SFREG, TFLOAT, + SFREG, TFLOAT, + NSPECIAL, RESCC, +#ifdef ARM_HAS_FPA + " cmfs AL,AR" COM "float compare\n", }, +#elifdef ARM_HAS_VFP + " fcmps AL,AR" COM "float compare\n", }, +#else + "ZF", }, +#endif + +{ OPLOG, FORCC, + SXREG, TDOUBLE, + SXREG, TDOUBLE, + NSPECIAL, RESCC, +#ifdef ARM_HAS_FPA + " cmfd AL,AR" COM "double compare\n", }, +#elifdef ARM_HAS_VFP + " fcmpd AL,AR" COM "double compare\n", }, +#else + "ZF", }, +#endif + +{ OPLOG, FORCC, + SXREG, TLDOUBLE, + SXREG, TLDOUBLE, + NSPECIAL, RESCC, +#ifdef ARM_HAS_FPA + " cmfe AL,AR" COM "ldouble compare\n", }, +#elifdef ARM_HAS_VFP + " fcmpd AL,AR" COM "double compare\n", }, +#else + "ZF", }, +#endif + +/* AND/OR/ER */ +{ AND, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1|RESCC, + " and A1,AL,AR" COM "64-bit and\n" + " and U1,UL,UR\n", }, + +{ OR, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " orr A1,AL,AR" COM "64-bit or\n" + " orr U1,UL,UR\n" }, + +{ ER, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " eor A1,AL,AR" COM "64-bit xor\n" + " eor U1,UL,UR\n" }, + +{ OPSIMP, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1|RESCC, + " O A1,AL,AR\n", }, + +{ OPSIMP, INAREG|FORCC, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " Os A1,AL,AR\n", }, + + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " b LL\n", }, + +#if 0 +{ GOTO, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, RNOP, + " mov pc,AL\n", }, +#endif + +/* + * Convert LTYPE to reg. + */ + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TWORD|TPOINT, + NAREG, RESC1, + " ldr A1,AL" COM "load word from memory\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SOREG|SNAME, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " ldr A1,AL" COM "load long long from memory\n" + " ldr U1,UL\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TCHAR, + NAREG, RESC1, + " ldrsb A1,AL" COM "load char from memory\n" }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TUCHAR, + NAREG, RESC1, + " ldrb A1,AL" COM "load uchar from memory\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TSHORT, + NAREG, RESC1, + " ldrsh A1,AL" COM "load short from memory\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TUSHORT, + NAREG, RESC1, + " ldrh A1,AL" COM "load ushort from memory\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SCON, TANY, + NAREG, RESC1, + " ldr A1,ZI" COM "load integer constant\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SCON, TANY, + NBREG, RESC1, + "ZJ", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG, TANY, + NAREG, RESC1, + " mov A1,AL" COM "load AL into A1\n" }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SBREG, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " mov A1,AL" COM "load UL:AL into U1:A1\n" + " mov U1,UL\n", }, + +{ OPLTYPE, INFREG, + SANY, TANY, + SOREG|SNAME, TFLOAT, + NFREG, RESC1, +#ifdef ARM_HAS_FPA + " ldfs A1,AL" COM "load float\n", }, +#elifdef ARM_HAS_VFP +#else + " ldr A1,AL" COM "load float\n", }, +#endif + +{ OPLTYPE, INXREG, + SANY, TANY, + SOREG|SNAME, TDOUBLE, + NXREG, RESC1, +#ifdef ARM_HAS_FPA + " ldfd A1,AL" COM "load double\n", }, +#elifdef ARM_HAS_VFP +#else + " ldr A1,AL" COM "load double\n" + " ldr U1,UL\n", }, +#endif + +{ OPLTYPE, INXREG, + SANY, TANY, + SOREG|SNAME, TLDOUBLE, + NXREG, RESC1, +#ifdef ARM_HAS_FPA + " ldfe A1,AL" COM "load ldouble\n", }, +#elifdef ARM_HAS_VFP +#else + " ldr A1,AL" COM "load ldouble\n" + " ldr U1,UL\n", }, +#endif + +/* + * Negate a word. + */ + +{ UMINUS, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " neg A1,AL" COM "negation\n", }, + +{ UMINUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " rsbs A1,AL,#0" COM "64-bit negation\n" + " rsc U1,UL,#0\n", }, + +{ UMINUS, INFREG, + SFREG, TFLOAT, + SFREG, TFLOAT, + NSPECIAL|NFREG, RESC1, +#ifdef ARM_HAS_FPA + " mvfs A1,AL" COM "float negation\n", }, +#elifdef ARM_HAS_VFP + " negs A1,AL" COM "float negation\n", }, +#else + "ZF", }, +#endif + +{ UMINUS, INXREG, + SXREG, TDOUBLE, + SXREG, TDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA + " mvfd A1,AL" COM "double negation\n", }, +#elifdef ARM_HAS_VFP + " negd A1,AL" COM "double negation\n", }, +#else + "ZF", }, +#endif + +{ UMINUS, INXREG, + SXREG, TLDOUBLE, + SXREG, TLDOUBLE, + NSPECIAL|NXREG, RESC1, +#ifdef ARM_HAS_FPA + " mvfe A1,AL" COM "ldouble negation\n", }, +#elifdef ARM_HAS_VFP + " negd A1,AL" COM "ldouble negation\n", }, +#else + "ZF", }, +#endif + +{ COMPL, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TANY, + NAREG|NASL, RESC1, + " mvn A1,AL" COM "complement\n", }, + +{ COMPL, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SANY, TANY, + NBREG|NBSL, RESC1, + " mvn A1,AL" COM "64-bit complement\n" + " mvn U1,UL\n", }, + +/* + * Arguments to functions. + */ + +{ FUNARG, FOREFF, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + 0, 0, + " stmfd sp!,{AL}" COM "save function arg to stack\n", }, + +{ FUNARG, FOREFF, + SBREG, TLONGLONG|TULONGLONG, + SANY, TLONGLONG|TULONGLONG, + 0, 0, + " stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", }, + +{ FUNARG, FOREFF, + SFREG, TFLOAT, + SANY, TFLOAT, + 0, 0, + " stmfd sp!,{AL}" COM "save function arg to stack\n", }, + +{ FUNARG, FOREFF, + SXREG, TDOUBLE|TLDOUBLE, + SANY, TDOUBLE|TLDOUBLE, + 0, 0, + " stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", }, + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ STASG, DF(STASG), }, + +{ FLD, DF(FLD), }, + +{ OPLEAF, DF(NAME), }, + +/* { INIT, DF(INIT), }, */ + +{ OPUNARY, DF(UMINUS), }, + +{ OPANY, DF(BITYPE), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); |